Repository navigation
Keep a font failure a render can't tell is stale - #2035
Merged
jakejackson1 merged 1 commit intoNov 12, 2026
Merged
Conversation
When a download fails while another font's file is at the font's name, the failure record now keeps that file's size and modified time. A render's size-only own-copy check, and the clearing of give-ups for files on disk, no longer count that same unchanged file as the font's own copy. So a same-size file from another font, which only the sync's hash check finds, no longer clears the failure on every render: the retry gives up and the failed fonts notice lists it. A font copied in by hand still clears its failure on the next render, as the copy has a new modified time (or no file was at the name when the download failed). The render path does no hashing. - download() treats the recorded file as another font's on a render. - download_or_queue() queues a large font in that case rather than downloading it during the render. - Give-ups are only cleared for a file that isn't the recorded one. Closes #2021 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
|
Coverage report for commit: 445fa4d Summary - Lines: 93.99% | Methods: 90.78% | Branches: 85.75%
🤖 Jest coverage report |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Contributor
|
Coverage report for commit: 445fa4d Summary - Lines: 90.47% | Methods: 96.03%
🤖 PHPUnit coverage report |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
This was referenced Nov 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A render could clear a recorded font download failure on the strength of a file's size alone. When another font's file sat at a core font's name with the size of a known build, only the background sync's hash check found it. The download to the font's hashed name then failed, and the next render cleared the failure again. So the retry never reached a give-up and the failed fonts notice never showed. A failure now records the size and modified time of the other font's file it found at the name, and nothing counts that unchanged file as the font's own copy.
download()no longer clears a failure for the file the failed download found, while it is unchanged.Try it
DejaVuSans.ttfintowp-content/uploads/PDF_EXTENDED_TEMPLATES/fonts/and change its last byte (printf x | dd of=DejaVuSans.ttf bs=1 seek=$(( $(stat -f%z DejaVuSans.ttf) - 1 )) conv=notrunc).define( 'WP_HTTP_BLOCK_EXTERNAL', true );inwp-config.php.wp cron event run gfpdf_core_font_sync.wp option get gfpdf_core_font_failures --format=jsonlists the font with aconflictvalue.DejaVuSans.ttfover the modified file and generate the PDF again. The failure and the notice are cleared.Test plan
test_an_unwritable_folder_fails_without_a_requestx2 (the container runs as root) andtest_deep_copy_is_deprecatedalso fail ondevelopment.test_delete_item_with_font_reference_gone_successerrored once in the full run but passes alone and in two runs of its class, and it doesn't touch the downloader.unwritable folderfailuresModel_Font_Downloader.phpMore info
The issue listed three options. This is a variant of the mtime one that needs no stored failure time.
record_failure()stamps the file at the font's plain name (size:mtime) into a newconflictfield. A failed download leaves the name as it was, so any file there is another font's: the sync's hash check or a size mismatch found it. With nothing at the name, the stamp is''and the record behaves as before.is_failed_conflict()is true when the own copyget_own_copy()found by size is the plain-name file and its stamp still matches. It is checked indownload()when not verifying, and viahas_own_copy()indownload_or_queue()andclear_installed_give_ups(). A hashed copy on disk is always the font's own, so it isn't affected. The check costs nothing extra on a render unless the failure has a stamp, asdownload()already reads the failure record.A file copied in with its old modified time preserved (
cp -p) and of the same size as the other font's file won't clear on a render. The sync's next verified pass still clears it.Not changed here:
Model_Required_Fonts(Site Health, the System Report and the Font Manager's install state) still goes by size, so while the failure stands it reports the font as installed even though the notice lists it as failed.delete_downloaded_font()can also treat the other font's file as the family's own copy while such a failure stands. Both predate this change and need the downloader's record passed intoModel_Font_SourcesorModel_Required_Fonts, so they're left for #2036.