Skip to content

Let plugins add font sources through the gfpdf_font_sources filter - #2013

Closed
gravitypdf-bot wants to merge 4 commits into
developmentfrom
feature/font-sources-filter
Closed

gravitypdf-bot wants to merge 4 commits into
developmentfrom
feature/font-sources-filter

Conversation

@gravitypdf-bot

@gravitypdf-bot gravitypdf-bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Plugins can now add their own font sources through a new gfpdf_font_sources filter. This is how Gravity PDF Pro will serve the premium template fonts. A source's families register with mPDF and can be listed in their own font list group. Their files download from the source's manifest through the same verified downloader as the core fonts, and when the source is required, the background sync keeps them on disk. When a source is added or its version changes, the next admin request adopts any matching custom font records and schedules a sync. Stacked on #2016.

  • Model_Font_Sources::get_sources() applies the filter once per request. It validates each added source, logs and drops any that are invalid, then runs Save a core font under a hashed name when another font's file holds its name #2016's rename_colliding_files() over the valid ones. The bundled and core IDs are reserved.
  • An added source's manifest is all-or-nothing, and is read when the sources are built (see below). One bad entry (for example an http:// URL), or a family file missing from the manifest, rejects the whole file and logs it.
  • check_added_sources() runs on admin_init and stores each source's version in the per-site option gfpdf_font_sources. When a source is new or its version changed, it adopts the source's records and fires gfpdf_font_sources_changed, which Controller_Font_Downloader hooks to schedule_sync().
  • GPDFAPI::add_pdf_font() needed no changes: it's a no-op for any family key a registered source provides. The required set also counts added required sources.
  • Uninstall deletes the new option.
  • No template data, manifest or external dependency ships. The tests use a fixture source.

Try it

  1. Add a mu-plugin that registers a source through gfpdf_font_sources. Give it a families entry such as 'lato' => [ 'name' => 'Lato', 'R' => 'Lato-Regular.ttf' ], a manifest PHP file returning [ 'Lato-Regular.ttf' => [ 'url' => 'https://…', 'size' => …, 'sha' => '<git blob SHA-1>' ] ], plus 'group' => 'Template Fonts', 'required' => true and 'version' => '1.0.0'.
  2. Load any admin page. wp option get gfpdf_font_sources shows {"…": "1.0.0"}, and wp cron event list shows gfpdf_core_font_sync.
  3. Run cron. The file appears in wp-content/uploads/PDF_EXTENDED_TEMPLATES/fonts/.
  4. Open a PDF's settings. Lato is listed under "Template Fonts" only.
  5. Change the manifest URL to http://, bump version and reload an admin page. The log shows "Font manifest rejected: an entry is invalid" and nothing downloads.

Test plan

  • Test_Added_Font_Sources (new) covers these cases:
    • a fixture source is registered and listed only in its own group, or unlisted without a group
      • an added file that collides with a core file with a different hash gets the hashed name end to end: font data, manifest, required set and download path
      • an added file with the same bytes as a core file shares the one file and one download
      • malformed sources and rejected manifests are dropped or emptied before the rename, and a valid source is still renamed
      • the filter runs once, a callback inside it gets the core sources, and nothing it caches outlives it
    • an invalid source is dropped and logged: missing manifest, bad families, bad ID, reserved ID, non-array source
    • a manifest with an http:// URL or a missing family file is rejected whole
    • mpdf_font_data registers the source before custom records, so a custom record still overrides it
    • only the bundled dir is appended to fontDir
    • adding or re-versioning a source adopts its records and schedules a sync once
    • a removed source is forgotten
    • add_pdf_font() is a no-op only while the source is registered
    • a required source's files are in the required set, and a non-required source's files aren't
  • Neighbouring classes pass on the rebased tip, single site (521 tests) and multisite (494): Test_Model_Font_Sources, Test_Model_Required_Fonts, Test_Model_Font_Downloader, Test_Downloaded_Fonts, Test_Api, Test_Controller_Upgrade_Routines, Test_Public_Api_Contract, Uninstall, Test_Controller_System_Report, Test_Controller_Actions, Test_On_Demand_Font_File_Finder, Test_Font_Rendering. The only failures are environment-only: test_an_unwritable_folder_fails_without_a_request ×2 (the container runs as root) and test_the_kill_switch_constant_turns_downloads_off (the parallel-harness constant warning).
  • PHPCS and PHPStan clean
  • CI is green
More info

Validation. An added source is checked once, when the sources are built, and must have:

  • a sanitize_key()-clean ID
  • non-empty families, each keyed by a lowercase string, with a Regular file, and every R/B/I/BI value a plain file name
  • a readable manifest

If set, group must be a non-empty string, version a scalar, and legacy a map of git blob SHA-1 => positive int.

Only families, manifest, group, required, legacy and version are kept, so an added source can't set a dir or legacy_manifest.

A filter that rewrites or unsets bundled/core gets the originals back; a rewrite is also logged.

Rebased onto #2016. The sources now always read the manifests of the downloadable sources when they are built (an added source plus core is two), because file names two sources share have to be told apart. Validation runs first, so rename_colliding_files() only sees well-formed sources, and it reads each manifest through the same all-or-nothing check, so a rejected manifest takes no file name. After the filter, get_sources() clears the manifest, family-file and record-collision caches, in case a callback read them from the core sources alone, and get_manifest(), get_record_collisions() and get_record_file_names() build the sources before touching those caches.

Manifest rejection, not drop. The plan's test list says a source with a bad manifest is "dropped". Dropping it when the manifest is first read would make get_sources() change partway through a request, depending on whether anything had read that manifest yet. Instead, read_source_manifest() rejects the whole file, and checks that every family file is on it. A rejected source keeps its families registered, but none of its files are downloadable, required, or adoptable. Its PDFs render through the on-demand finder's fallback. A source whose manifest was rejected isn't recorded in gfpdf_font_sources, so it's adopted and synced once fixed. Core manifests keep the existing skip-and-warn behaviour.

Version option. Plan §2 had superseded the stored-version design for bundled/core, which still adopt in the 6.19 upgrade routine. Added sources need it, since a plugin activated by any route has no upgrade routine of ours to run, so only added sources are tracked. The option is per site because custom font records are. It is stored even when empty, autoloaded, so later reads come from the alloptions cache instead of a query per admin request. check_added_sources() returns early when the stored value is [] and nothing hooks the filter.

Refactors. adopt_records() now reuses the cached get_source_manifest() instead of re-including the file. is_blob() and is_file_name() are shared by manifest entries, legacy hashes and family files. The tests' manifest writer moved into CopiesFontFixtures::write_manifest_file().

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Coverage report for commit: bbc0ca5
File: ./tmp/jest-coverage/clover.xml

Cover ┌─────────────────────────┐ Freq.
   0% │ ░░░░░░░░░░░░░░░░░░░░░░░ │  0.0%
  10% │ ░░░░░░░░░░░░░░░░░░░░░░░ │  0.0%
  20% │ ░░░░░░░░░░░░░░░░░░░░░░░ │  0.0%
  30% │ ░░░░░░░░░░░░░░░░░░░░░░░ │  0.0%
  40% │ ░░░░░░░░░░░░░░░░░░░░░░░ │  0.0%
  50% │ ░░░░░░░░░░░░░░░░░░░░░░░ │  0.0%
  60% │ ░░░░░░░░░░░░░░░░░░░░░░░ │  0.0%
  70% │ █░░░░░░░░░░░░░░░░░░░░░░ │  1.6%
  80% │ ███░░░░░░░░░░░░░░░░░░░░ │  7.9%
  90% │ ██████░░░░░░░░░░░░░░░░░ │ 17.5%
 100% │ ███████████████████████ │ 73.0%
      └─────────────────────────┘
 *Legend:* █ = Current Distribution 
Summary - Lines: 93.26% | Methods: 87.50% | Branches: 83.03%
FilesLinesMethodsBranches
src/assets/js/react/actions
   downloadedFonts.js100.00%-100.00%
   fontManager.js100.00%100.00%100.00%
   templates.js100.00%100.00%100.00%
src/assets/js/react/components/Alert
   Alert.js100.00%100.00%100.00%
src/assets/js/react/components
   CustomHashRouter.js100.00%100.00%100.00%
   Empty.js100.00%100.00%100.00%
   ShowMessage.js80.65%80.00%72.22%
   Spinner.js100.00%100.00%100.00%
src/assets/js/react/components/FontManager
   AddFont.js100.00%100.00%100.00%
   AddUpdateFontFooter.js85.00%50.00%88.71%
   AdvancedButton.js100.00%100.00%100.00%
   DownloadedFonts.js100.00%91.67%100.00%
   FontList.js100.00%50.00%65.22%
   FontListAlertMessage.js100.00%100.00%100.00%
   FontListHeader.js100.00%100.00%100.00%
   FontListIcon.js100.00%100.00%100.00%
   FontListItems.js84.15%62.50%65.57%
   FontListSkeleton.js100.00%100.00%100.00%
   FontManager.js76.47%57.14%50.00%
   FontManagerBody.js96.30%96.43%90.29%
   FontManagerHeader.js100.00%100.00%100.00%
   FontVariant.js90.00%60.00%70.00%
   FontVariantLabel.js100.00%100.00%100.00%
   InitialAddUpdateState.js100.00%100.00%100.00%
   SearchBox.js90.00%66.67%69.23%
   TemplateTooltip.js100.00%75.00%100.00%
   UpdateFont.js75.00%50.00%75.00%
src/assets/js/react/components/Modal
   CloseDialog.js93.33%66.67%70.59%
src/assets/js/react/components/Template
   TemplateActivateButton.js100.00%100.00%100.00%
   TemplateButton.js85.71%66.67%100.00%
   TemplateContainer.js71.43%66.67%25.00%
   TemplateDeleteButton.js100.00%100.00%70.00%
   TemplateDocsLink.js100.00%100.00%100.00%
   TemplateFooterActions.js100.00%100.00%100.00%
   TemplateHeaderNavigation.js82.35%85.71%70.00%
   TemplateHeaderTitle.js100.00%100.00%100.00%
   TemplateList.js100.00%100.00%100.00%
   TemplateListItem.js100.00%100.00%92.86%
   TemplateListItemComponents.js100.00%100.00%100.00%
   TemplateManagerClosed.js100.00%100.00%100.00%
   TemplateScreenshot.js100.00%100.00%100.00%
   TemplateScreenshots.js100.00%100.00%50.00%
   TemplateSearch.js93.75%88.89%50.00%
   TemplateSingle.js100.00%100.00%100.00%
   TemplateSingleComponents.js100.00%100.00%75.00%
   TemplateUploader.js100.00%100.00%95.00%
   TemplateUploaderContext.js100.00%100.00%100.00%
   TemplateUploaderTile.js100.00%100.00%100.00%
src/assets/js/react/reducers
   downloadedFontsReducer.js100.00%100.00%100.00%
   fontManagerReducer.js86.25%75.00%75.71%
   index.js100.00%100.00%100.00%
   templateReducer.js100.00%100.00%100.00%
src/assets/js/react/sagas
   downloadedFonts.js100.00%100.00%100.00%
   fontManager.js86.96%90.00%83.33%
   index.js100.00%100.00%100.00%
   templates.js91.30%100.00%100.00%
src/assets/js/react/selectors
   getTemplates.js91.11%100.00%83.33%
src/assets/js/react/utilities/FontManager
   adjustFontListHeight.js100.00%100.00%100.00%
   associatedFontManagerSelectBox.js94.44%100.00%66.67%
   fontManagerReducer.js100.00%100.00%100.00%
   toggleUpdateFont.js100.00%100.00%100.00%
src/assets/js/react/utilities/Template
   hasPendingUpload.js100.00%100.00%100.00%
src/assets/js/react/utilities
   withRouterHooks.js100.00%100.00%100.00%

🤖 Jest coverage report

On-demand downloading makes deleting a core font safe, as one a PDF needs comes back on its own, but the Font Manager
only listed custom fonts, so a downloaded font could only be removed by hand from the fonts folder.

The Font Manager gets a "Downloaded Fonts" section listing each family of a downloadable source with files on disk:
its styles, size and why it's in use (default font, site language, PDF count, a required source, another site, or a
file another required font shares). In-use families can't be deleted; the server re-checks and returns 409, and 404
for a bundled, unknown or absent family. Delete removes the family's manifest files whatever their hash (an explicit
action, unlike the upgrade prune), keeps the licence files, clears the files' failure and back-off entries, flushes the
family's metrics and logs what it removed. With downloads turned off the confirm says the font won't come back.

The in-use reasons come from Model_Required_Fonts::get_font_reasons(), which get_required_font_files() is now built
on, so the list and the background sync share one walk of the forms. On Multisite the fonts folder is shared, so only
super admins can delete, and "in use" also counts every other site's default font, locale font and PDF fonts. Those come
from Model_Required_Fonts::get_site_font_keys(), which reads a site's tables by prefix rather than switch_to_blog() so no
other site's plugins or filters run. One options query per site also says whether Gravity Forms has run there
(gf_db_version), so no site pays a separate table check.

Routes live in Controller_Font_Downloader, beside the font sync it already wires up,
rather than Controller_Custom_Fonts, which the multisite-safe CRUD work also changes.

The E2E test copies a core font no other spec uses into the fonts folder, as downloads are off on the E2E site, and
puts one in use with an X-GPDF-E2E-Default-Font header rather than a PDF selecting it, which would count it as required
in the other specs' system reports.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gravitypdf-bot and others added 2 commits November 6, 2026 10:48
…nts in the 6.19 cleanup

Every site shares the fonts folder, so the font state about it is now stored the same way on single site and
Multisite: the failed downloads record and the 6.19 cleanup's progress are main network options, the language font
cache is a site transient, and the failed fonts notice's dismissal lives in the record rather than in each site's
settings. The 6.19 cleanup keeps the fonts any site needs, reading each site's settings, locale and PDFs directly through the same
reader the Font Manager uses for other sites' fonts. It
runs in a cron event that reads the sites in batches within the sync's time budget, so no upgrade request pays for a
large network's scan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ts name

download() returned true for any file at a manifest name, so a family could silently use another font's file, and
merging two sources' manifests with += gave the later source the first's file for a name they use for different files.

A file at a manifest name is another font's when its size matches no build the sources know (the manifest's, the
legacy manifest's or a source's `legacy` hashes). The family's font is then saved as {stem}-{first 8 of the sha}{ext},
derived from the manifest with nothing stored, and mPDF looks for that name first. The file at the name is never
touched. A size mismatch is a stat call, so it is also found while rendering; a file of a known size that is not the
manifest's is found by the background sync, the only place a file already on disk is hashed. With downloads off, or a
download failing or backing off, the file at the name stays in use, so a conflict never renders worse than before.

Two sources that use one name for different files get it at merge time: the later source's manifest entry and family
file references take the hashed name, so nothing downstream sees a duplicate.

Every reader of a font file's path now agrees: the finder, the downloaded fonts list and delete (a hashed copy is
deleted alone), the installed counts and needs-download checks, the sync's file list and retries, prune and adoption
(which read the file at the name), and the unregistered fonts auto-loader (which skips hashed copies). Saving a hashed
copy flushes the font metrics and removes a copy left by an older release of the font.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@gravitypdf-bot
gravitypdf-bot force-pushed the feature/font-sources-filter branch from 7d9eed7 to 4d11a67 Compare November 6, 2026 00:35
@gravitypdf-bot
gravitypdf-bot changed the base branch from feature/core-font-upgrade-prune to feature/font-file-conflict-rename November 6, 2026 00:35
A plugin (Gravity PDF Pro's template fonts, for one) can now register a font source: mPDF families whose files
download from the source's own manifest through the same verified downloader as the core fonts, optionally listed in
their own font list group and, when `required`, kept on disk by the background sync.

- Each added source is validated once per request: a lowercase key ID that isn't `bundled` or `core`, families with a
  Regular file and plain file names, a readable manifest, and a label group, scalar version and SHA-1 => size legacy
  if set. An invalid one is logged and dropped; only the known keys are kept, so an added source can't set a `dir`.
- Building the sources reads each downloadable source's manifest, since two sources using one file name for different
  files must be told apart (the later source's file takes its hashed name, as for the core fonts). Only valid sources
  get that far, so a malformed source can't break the rename. An added source's manifest is all or nothing: one malformed entry (e.g. an
  http:// URL) or a family file missing from it rejects the whole file, logged, so a bad build never half-installs.
  Its families stay registered and render through the on-demand finder's fallback; nothing of it downloads.
  Dropping the source instead would have made the sources depend on a manifest's contents.
- On admin_init, each added source that's new or has a new `version` (option `gfpdf_font_sources`, per site, since
  custom font records are per site) adopts its records, then `gfpdf_font_sources_changed` fires and the downloader
  schedules a sync. This covers activation by any route (UI, network, WP-CLI, file copy) and an update shipping new
  fonts. A removed source is forgotten, so adding it back adopts again; one with a rejected manifest stays
  unrecorded until fixed. The option is stored even when empty so later reads come from the autoloaded options, and
  the check returns early when nothing hooks the filter and nothing is stored.
- `GPDFAPI::add_pdf_font()` and the required set already loop over the registered sources, so they cover added
  sources unchanged; adoption now reuses the cached source manifest instead of reading the file again.
- The option is deleted on uninstall.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gravitypdf-bot
gravitypdf-bot force-pushed the feature/font-sources-filter branch from 4d11a67 to bbc0ca5 Compare November 6, 2026 01:50
@github-actions

github-actions Bot commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

Coverage report for commit: bbc0ca5
File: tmp/coverage/report-xml/merged.xml

Cover ┌─────────────────────────┐ Freq.
   0% │ ██████░░░░░░░░░░░░░░░░░ │  7.6%
  10% │ ░░░░░░░░░░░░░░░░░░░░░░░ │  0.0%
  20% │ █░░░░░░░░░░░░░░░░░░░░░░ │  0.4%
  30% │ █░░░░░░░░░░░░░░░░░░░░░░ │  1.3%
  40% │ █░░░░░░░░░░░░░░░░░░░░░░ │  0.4%
  50% │ ███████░░░░░░░░░░░░░░░░ │  9.4%
  60% │ █░░░░░░░░░░░░░░░░░░░░░░ │  0.9%
  70% │ ██░░░░░░░░░░░░░░░░░░░░░ │  2.7%
  80% │ █████████████░░░░░░░░░░ │ 17.0%
  90% │ ███████████████████████ │ 31.7%
 100% │ █████████████████████░░ │ 28.6%
      └─────────────────────────┘
 *Legend:* █ = Current Distribution 
Summary - Lines: 89.48% | Methods: 95.74%
FilesLinesMethodsBranches
/var/www/html/wp-content/plugins/gravity-pdf
   api.php98.14%100.00%100.00%
   gravity-pdf-updater.php53.97%100.00%100.00%
   pdf.php59.82%81.25%100.00%
/var/www/html/wp-content/plugins/gravity-pdf/src/Controller
   Controller_Actions.php99.10%100.00%100.00%
   Controller_Activation.php95.83%100.00%100.00%
   Controller_Custom_Fonts.php95.09%100.00%100.00%
   Controller_Debug.php100.00%100.00%100.00%
   Controller_Export_Entries.php96.77%100.00%100.00%
   Controller_Font_Downloader.php100.00%100.00%100.00%
   Controller_Font_Sources.php100.00%100.00%100.00%
   Controller_Form_Settings.php87.37%90.00%100.00%
   Controller_Install.php100.00%100.00%100.00%
   Controller_Mergetags.php100.00%100.00%100.00%
   Controller_PDF.php81.46%100.00%100.00%
   Controller_Pdf_Cache.php100.00%100.00%100.00%
   Controller_Pdf_Queue.php85.27%87.50%100.00%
   Controller_Save_Core_Fonts.php91.67%100.00%100.00%
   Controller_Settings.php86.90%100.00%100.00%
   Controller_Shortcodes.php100.00%100.00%100.00%
   Controller_System_Report.php100.00%100.00%100.00%
   Controller_Templates.php100.00%100.00%100.00%
   Controller_Uninstaller.php83.33%77.78%100.00%
   Controller_Upgrade_Routines.php95.19%100.00%100.00%
   Controller_Webhooks.php100.00%100.00%100.00%
   Controller_Zapier.php100.00%100.00%100.00%
/var/www/html/wp-content/plugins/gravity-pdf/src/Exceptions
   GravityPdfDatabaseUpdateException.php50.00%100.00%100.00%
   GravityPdfDomainException.php50.00%100.00%100.00%
   GravityPdfException.php50.00%100.00%100.00%
   GravityPdfFontNotFoundException.php50.00%100.00%100.00%
   GravityPdfIdException.php50.00%100.00%100.00%
   GravityPdfModelNotUpdatedException.php50.00%100.00%100.00%
   GravityPdfNotATemplateException.php50.00%100.00%100.00%
   GravityPdfRuntimeException.php50.00%100.00%100.00%
   GravityPdfShortcodeEntryIdException.php50.00%100.00%100.00%
   GravityPdfShortcodePdfConditionalLogicFailedException.php50.00%100.00%100.00%
   GravityPdfShortcodePdfConfigNotFoundException.php50.00%100.00%100.00%
   GravityPdfShortcodePdfInactiveException.php50.00%100.00%100.00%
/var/www/html/wp-content/plugins/gravity-pdf/src/Helper/Fields
   Field_Address.php92.86%100.00%100.00%
   Field_Chainedselect.php66.67%75.00%100.00%
   Field_Checkbox.php94.44%100.00%100.00%
   Field_Consent.php95.00%100.00%100.00%
   Field_Coupon.php--100.00%
   Field_Creditcard.php83.33%100.00%100.00%
   Field_Date.php83.33%100.00%100.00%
   Field_Default.php83.33%100.00%100.00%
   Field_Discount.php44.00%75.00%100.00%
   Field_Email.php83.33%100.00%100.00%
   Field_Fg_Ls_Consent.php92.86%100.00%100.00%
   Field_Fg_Ls_Signature.php73.08%66.67%100.00%
   Field_Fileupload.php95.83%100.00%100.00%
   Field_Form.php90.91%100.00%100.00%
   Field_Hidden.php81.82%100.00%100.00%
   Field_Html.php89.47%100.00%100.00%
   Field_Image_Choice.php86.67%100.00%100.00%
   Field_Likert.php97.22%100.00%100.00%
   Field_List.php92.41%100.00%100.00%
   Field_Multi_Choice.php50.00%100.00%100.00%
   Field_Multiselect.php92.59%100.00%100.00%
   Field_Name.php84.62%100.00%100.00%
   Field_Number.php83.33%100.00%100.00%
   Field_Option.php96.15%100.00%100.00%
   Field_Page.php83.33%100.00%100.00%
   Field_Phone.php94.55%100.00%100.00%
   Field_Poll.php93.75%100.00%100.00%
   Field_Post_Category.php85.00%100.00%100.00%
   Field_Post_Content.php82.35%100.00%100.00%
   Field_Post_Custom_Field.php50.00%100.00%100.00%
   Field_Post_Excerpt.php81.82%100.00%100.00%
   Field_Post_Image.php94.00%100.00%100.00%
   Field_Post_Tags.php90.91%100.00%100.00%
   Field_Post_Title.php81.82%100.00%100.00%
   Field_Product.php92.31%100.00%100.00%
   Field_Products.php84.32%100.00%100.00%
   Field_Quantity.php84.62%100.00%100.00%
   Field_Quiz.php89.74%100.00%100.00%
   Field_Radio.php94.74%100.00%100.00%
   Field_Rank.php95.24%100.00%100.00%
   Field_Rating.php95.24%100.00%100.00%
   Field_Repeater.php97.39%100.00%100.00%
   Field_Section.php90.74%100.00%100.00%
   Field_Select.php94.12%100.00%100.00%
   Field_Shipping.php92.86%100.00%100.00%
   Field_Signature.php71.11%100.00%100.00%
   Field_Slim.php82.35%100.00%100.00%
   Field_Slim_Post.php91.30%100.00%100.00%
   Field_Subtotal.php65.38%75.00%100.00%
   Field_Survey.php95.00%100.00%100.00%
   Field_Tax.php32.00%50.00%100.00%
   Field_Text.php81.82%100.00%100.00%
   Field_Textarea.php91.18%100.00%100.00%
   Field_Time.php81.82%100.00%100.00%
   Field_Tos.php92.86%100.00%100.00%
   Field_Total.php88.00%100.00%100.00%
   Field_Website.php85.71%100.00%100.00%
/var/www/html/wp-content/plugins/gravity-pdf/src/Helper/Fonts
   FlushCache.php92.31%100.00%100.00%
   LocalFile.php88.89%100.00%100.00%
   LocalFilesystem.php66.67%100.00%100.00%
   SupportsOtl.php87.50%100.00%100.00%
   TtfFontValidation.php84.62%100.00%100.00%
/var/www/html/wp-content/plugins/gravity-pdf/src/Helper
   Helper_Abstract_Addon.php94.09%100.00%100.00%
   Helper_Abstract_Config_Settings.php75.00%100.00%100.00%
   Helper_Abstract_Controller.php-100.00%100.00%
   Helper_Abstract_Field_Products.php89.47%66.67%100.00%
   Helper_Abstract_Fields.php96.10%95.83%100.00%
   Helper_Abstract_Fields_Input_Type.php84.00%100.00%100.00%
   Helper_Abstract_Form.php--100.00%
   Helper_Abstract_Model.php100.00%100.00%100.00%
   Helper_Abstract_Options.php77.13%79.66%100.00%
   Helper_Abstract_Pdf_Shortcode.php94.67%95.65%100.00%
   Helper_Abstract_View.php96.77%100.00%100.00%
   Helper_Async_Notifications.php64.29%100.00%100.00%
   Helper_Data.php98.31%100.00%100.00%
   Helper_Field_Container.php92.31%100.00%100.00%
   Helper_Field_Container_Gf25.php92.00%100.00%100.00%
   Helper_Field_Container_Void.php16.67%-100.00%
   Helper_Form.php80.65%64.29%100.00%
   Helper_Interface_Actions.php-100.00%100.00%
   Helper_Interface_Config.php50.00%100.00%100.00%
   Helper_Interface_Config_Settings.php50.00%100.00%100.00%
   Helper_Interface_Deprecated_Features.php50.00%100.00%100.00%
   Helper_Interface_Extension_Settings.php-100.00%100.00%
   Helper_Interface_Extension_Uninstaller.php-100.00%100.00%
   Helper_Interface_Field_Pdf_Config.php50.00%100.00%100.00%
   Helper_Interface_Filters.php-100.00%100.00%
   Helper_Interface_Setup_TearDown.php50.00%100.00%100.00%
   Helper_Interface_Url_Signer.php-100.00%100.00%
   Helper_Logger.php-100.00%100.00%
   Helper_Misc.php89.17%100.00%100.00%
   Helper_Mpdf.php50.00%100.00%100.00%
   Helper_Notices.php92.98%100.00%100.00%
   Helper_Options_Fields.php98.10%100.00%100.00%
   Helper_PDF.php88.61%97.56%100.00%
   Helper_PDF_List_Table.php84.50%92.31%100.00%
   Helper_Pdf_Queue.php84.31%100.00%100.00%
   Helper_QueryPath.php80.00%100.00%100.00%
   Helper_Render_Health.php85.71%100.00%100.00%
   Helper_Sha256_Url_Signer.php90.91%100.00%100.00%
   Helper_Singleton.php100.00%100.00%100.00%
   Helper_Templates.php97.29%100.00%100.00%
   Helper_Trait_Logger.php25.00%-100.00%
   Helper_Trait_Removed_Methods.php100.00%100.00%100.00%
   Helper_Url_Signer.php84.82%100.00%100.00%
/var/www/html/wp-content/plugins/gravity-pdf/src/Helper/Licensing
Table truncated to fit comment

🤖 PHPUnit coverage report

@jakejackson1
jakejackson1 force-pushed the feature/font-file-conflict-rename branch from f7acf3e to 74c3b06 Compare November 6, 2026 03:06
@gravitypdf-bot
gravitypdf-bot force-pushed the feature/font-file-conflict-rename branch 3 times, most recently from 62cbe50 to 38e02af Compare November 9, 2026 06:09
Base automatically changed from feature/font-file-conflict-rename to development November 9, 2026 06:12
@jakejackson1

Copy link
Copy Markdown
Member

Not planned. Include additional fonts in the current manifest.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants