Cherry-pick hot-patch-6.14.3 fixes into development#1657
Open
jakejackson1 wants to merge 20 commits into
Open
Conversation
Hide the select-default-font tick in the AddUpdateFontFooter when the Font Manager is opened from the global Tools tab, matching the existing handleDisableSelectFields() pattern in FontListItems.js — the tick is meaningless without a parent font dropdown to write the selection back into. Also pin font-size: 20px / line-height: 1 on the dashicons trash and tick buttons inside .select-delete-icons-container so they render at ~35px and match the adjacent .gfpdf-button on WordPress 7.0, where the inherited <button> line-height (~33px) was ballooning them to 48px. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Revert the search result list selector from ol back to ul (the React component renders <ul class="search-menu">, so the ol rule was an orphan and stripped row backgrounds, shadows and the flex layout) and re-add the .hit-action rules that were removed in e35add7. Use visibility: hidden / visible instead of display: none / flex on .hit-action so the select-icon slot is always reserved — hovering a result no longer pushes the title and path onto a new line. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add .button to the #gfpdf-template-container and #gfpdf-font-manager-container override so the activate <a class="button"> picks up the same min-height: 32px / line-height: 2.30769231 reset as the <button> elements (without it the broad #tab_PDF .button rule was applying line-height: 2.95, which rendered as 42.48px in a 36px button). Set box-sizing: border-box on .theme .more-details so the WP-core 20% / 60% / 20% positioning includes the 24px horizontal padding — otherwise the hover label sat ~12px right of centre.
…load apiPostTemplateUploadProcessing never throws on HTTP failures, so the saga always dispatched the success action — even when the server returned 400 or a JSON error body. ajaxSuccess then ran response.body.templates.forEach() on a non-array (e.g. the integer 400 parsed from the wp_die response), throwing a TypeError that unmounted the modal. ajaxFailed never ran, and even if it had it was reading error.response.body.error — a shape that no caller produced. Route the saga to templateUploadProcessingFailed when response.ok is false or response.body.templates is missing, and rewrite ajaxFailed to read the new response shape (falling back to genericUploadErrorText when the body is not a JSON error payload). Tests updated to cover the three failure paths: non-ok status, missing templates array, and a thrown fetch.
glob() intermittently returned an empty result immediately after unzip_file() wrote the new entries through WP_Filesystem, even when scandir() on the same directory showed the .php files were present. This surfaced for users as "No valid PDF template found in Zip archive." on otherwise-valid template uploads, and as a ~6% flake rate on Test_Templates::test_unzip_and_verify_templates in the suite. Switch to scandir() + suffix filter for the post-unzip listing so the directory is always re-read from disk, and harden the test itself with a unique archive name per run, a flush of the template transient cache before/after the test, and a try/finally to guarantee cleanup runs even when an assertion mid-test fails. Verified 40/40 consecutive full-suite passes after the change.
Replace the scandir + array_filter dance with a CallbackFilterIterator over a FilesystemIterator, extracted into a small find_template_files() helper, and reuse it from both the validation path and the post-copy header lookup so they share one source of truth. Kept non-recursive to mirror Helper_Templates::get_all_templates_in_folder(): the rest of the template system only discovers top-level .php files in the install folder, so picking up templates from subdirectories at validation time would let zips pass that the system can't actually load post-install.
…im comments
Replace the new Model_Templates::find_template_files() with a direct
call to the existing Helper_Templates::get_all_templates_in_folder(),
which already wraps the same FilesystemIterator + CallbackFilterIterator
pipeline behind a logged try/catch — removes ~30 lines and the
CallbackFilterIterator / FilesystemIterator imports.
Extract the brittle window.location.search.substr(lastIndexOf('=')+1)
pattern used in four Font Manager components into a single
getTabLocation() utility. Preserve the trailing-`=`-value semantics:
the call sites depend on the value of the *final* query parameter
(sometimes 'tab', sometimes 'subview', sometimes the form id), so
URLSearchParams.get('tab') is not a drop-in replacement — it returns
'' on the global PDF settings page (?page=gf_settings&subview=PDF) and
breaks FontListItems.handleSetSelectedFontNameValue.
Drop the redundant pre-test cleanup in test_unzip_and_verify_templates
(the try/finally block already guarantees teardown), and prune
explanatory comments that just restated what the code below them did.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Changing the Template dropdown on a form-level PDF settings page wipes the user's in-progress edits because the entire template-fields section is replaced via AJAX with server-rendered markup based on saved values. Snapshot every input inside the template fieldset before the request fires, then re-apply matching values to the new HTML before TinyMCE and wpColorPicker are re-initialised on top of it. Snapshot entries that no longer match a field in the new template are silently dropped — the new template doesn't surface them. Restored checkbox/radio toggles dispatch `change` so dependent conditional panels driven by setupToggledFields settle into the right state. The snapshot/restore pair lives in its own formValuesSnapshot module so it can be unit-tested against a real jQuery + JSDOM environment. Two non-obvious cases worth flagging: 1. `.gfpdf-input-toggle` checkboxes (the First Page Header / First Page Footer toggles) have no `name` attribute, so a named-input scan silently drops them. They're snapshotted keyed by the name of the textarea inside the container they show/hide — a stable identity across HTML swaps — and restored via the same lookup, firing `change` so setupToggledFields slides the container correctly. 2. When a TinyMCE editor is in Code/Text mode the editor body has stale content and the textarea holds the live edits. The snapshot checks `editor.hidden` and reads the textarea in Code mode. Also fixes a real bug surfaced by the test suite: jQuery's `:button` pseudo doesn't match input[type=submit] or input[type=reset], so the guard spells out `:button, :submit, :reset, [type=file]`. 20 Jest tests cover text/number/select/textarea/radio/checkbox, TinyMCE Visual + Code modes, nameless toggle round-trip, template dropdown exclusion, button/submit/reset/file skipping, and a full snapshot → swap → restore integration case. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The superagent → fetch migration in 890c053 swapped a client that auto-rejected on 4xx/5xx for native fetch, which only sets response.ok = false. The coreFonts saga still only guarded against a falsy parsed body — and getJsonString('{}') returns a truthy empty object, so a 400 from /wp-admin/admin-ajax.php was happily treated as "download succeeded". The E2E "Tools tab - Install core fonts field test failure" expected the .gfpdf-core-font-status-error element to render after the mock returned 400; it never appeared because the saga walked the success branch. Add response.ok to the guards on both saga branches (mirrors the existing pattern in sagas/fontManager.js and sagas/templates.js) and extend the Jest suite to lock in the non-2xx-is-a-failure behaviour. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… round-trip Add a success-path case for the templateUploadProcessing saga (only the two failure branches and the thrown-error case were exercised before), and a round-trip test that snapshots and restores every standard HTML form input type — including multi-select, multi-checkbox groups, and hidden/range/date/time/colour inputs — to lock in formValuesSnapshot's coverage of the field surface it has to handle on a template swap. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rules The form-settings UI exposes two related fields — the `conditional` toggle (user-visible on/off switch) and the `conditionalLogic` rules array — and they can drift out of sync. When that happens (toggle off, rules array still populated from a previous enable), the runtime checks evaluated the stale rules and rejected entries against rules the UI said were disabled, manifesting as a "[gravitypdf] shortcode says conditional logic enabled, entry didn't pass" error on form confirmations. Route all four PDF-level runtime sites — get_pdf_config, middle_conditional, get_active_pdfs, and the [gravitypdf] merge-tag check — through a new Helper_Misc::conditional_logic_passes() that treats the toggle as the source of truth and short-circuits when it's explicitly off. Legacy settings without the toggle key fall back to evaluating the rules. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…plate swap
Switching the PDF template dropdown with the user's last-selected editor
tab set to 'html' was buggy in two ways:
1. switchEditors.go('html') was called immediately after tinyMCE.init()
while the iframe was still being mounted, throwing
"Cannot read properties of undefined (reading 'getSelection')" inside
editor.hide(). The exception unwound the surrounding ajaxCall()
success callback, skipping initialiseCommonElements, merge tags, and
tooltip re-init for the swapped-in fields.
2. switchEditors.go reads the iframe selection and, if a range is set,
schedules textArea.focus() 100ms later (base.js
selectTextInTextArea), which scrolls the page to the editor. TinyMCE
seeds a default cursor on init, so this fires for every editor on
the form — the viewport ends up on the last one, yanking the user
away from the template dropdown they just clicked.
Defer the switchEditors.go call via editor.on('init', ...) when the
editor isn't initialised yet, then clear the iframe selection inside
the deferred apply() so findBookmarkedPosition short-circuits and the
focus/scroll path is skipped. Wrap the call in a try/catch as a final
safety net: if WP can't switch, the editor falls back to Visual mode
silently and the user can flip the tab manually.
Drive-bys from the same area:
- hoist getUserSetting('editor') out of the editors.forEach loop and
drop narrative comments inside loadTinyMCEEditor
- replace stringly-typed class_exists() with
GF_Background_Process::class in bootstrap.php
- reorder/dedupe the 6.14.3 changelog entries
13 Jest tests cover the apply() behaviour — selection-clear, deferred
init via editor.on('init'), missing-getWin/getSelection guards,
switchEditors throwing, switchEditors absent.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## development #1657 +/- ##
===============================================
+ Coverage 92.85% 92.99% +0.14%
===============================================
Files 58 59 +1
Lines 1511 1528 +17
Branches 419 430 +11
===============================================
+ Hits 1403 1421 +18
+ Misses 103 102 -1
Partials 5 5 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
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
Brings the 20 hot-patch-6.14.3 commits onto
development, with conflict resolutions for the regions dev has already refactored. One hot-patch commit (b19ce882settings/view/SCSS WP 7.0 tweaks) was skipped — its content already landed ondevelopmentvia03be1d41.Highlights — conflict resolutions adapted to current dev API
templates.jssaga: hot-patch routes HTTP failures totemplateUploadProcessingFailed; rewired to dev's{ message }payload contract soTemplateUploader.ajaxFailedstill readserror?.message ?? genericUploadErrorText.coreFonts.jssaga: addedresponse.okguards on both branches (mirrorsfontManager.js/templates.jspattern).setupDynamicTemplateFields.js: integratedsnapshotFormValues/restoreFormValueswhile preserving dev'sactionToolbarvariable + import path. ExportedTEMPLATE_SECTION_SELECTOR/TEMPLATE_DROPDOWN_SELECTORfromformValuesSnapshot.jsto collapse the 5x-duplicated selector literals.loadTinyMCEEditor.js: merged hot-patch'srestoreLastEditorTabhelper with dev's earlierswitchEditors.gomigration.getTabLocation()extraction: applied toAddUpdateFontFooter.js,FontListItems.js,FontManager.js.\GFForms::$versionmigration: standardised on unprefixedGFForms::$versioneverywhereuse GFForms;is in scope.Skipped
b19ce882 fix: settings, view, and SCSS tweaks for WP 7.0 / PHP 8.5— content already ondevelopment(commit03be1d41covers it; the cherry-pick produced an empty diff).Test plan
yarn lint:jscleanyarn test:js -- tests/js-unit/react/sagas/coreFonts.test.js— new "non-2xx" test runs inside thegetFilesFromGitHub()describeyarn test:js -- tests/js-unit/react/sagas/templates.test.js— three saga branches (non-ok, missing templates array, fetch throws) all dispatch{ message }payloadsyarn test:js -- tests/js-unit/admin/settings/common/dynamicTemplateFields/formValuesSnapshot.test.js— full round-trip + every standard form-field typeyarn test:js -- tests/js-unit/admin/settings/common/dynamicTemplateFields/loadTinyMCEEditor.test.js— newrestoreLastEditorTabdeferral pathcomposer lintcleanyarn test:php—Helper_Misc,Pre_Checks,Gravity_Forms,Templatessuites green.zip→ modal stays open, inline error appears (noTypeError)/wp-admin/admin-ajax.phpcore-fonts route →.gfpdf-core-font-status-errorappears🤖 Generated with Claude Code