Repository navigation
Sync master from upstream - #144
Merged
Merged
Conversation
Master to Dev 2.12.8
Dev to Next Release 2.12.8
…licated deleteOption() was calling options.splice() which mutated the original array in-place. When a block is duplicated in Gutenberg the new block's attributes initially share the same array reference, so the mutation affected both blocks simultaneously. Additionally, setAttributes received `deleteOptions` as the key instead of `options`, making the update a no-op and leaving the shared reference intact. Fixes by replacing splice/map with filter (immutable) and correcting the setAttributes key to `options`. Fixes #3174 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…vigates handleFormSubmission() re-enabled the submit button and hid the loader right after redirectToUrl(), while the old page was still on screen. A second tap in that window resubmitted into a request the unload then cancelled (Safari: "TypeError: Load failed"). submitFormData() logged it as type 'error', which is_fault() counts, so one tap sent the site owner the "form submissions are failing" alert, and the visitor saw the raw browser text. - After a redirect that leaves the page, keep the button disabled and the loader on. Release them on a back/forward cache restore, or after 15s for a redirect that never unloads the page (e.g. a file download). A hash-only URL on the same page does not unload, so it releases at once. - Track navigatingAway (set by redirectToUrl() and pagehide, cleared on a bfcache restore). A request that fails while it is set is logged as 'network' with no status, which is_fault() does not count. - Do not pass native TypeError / SyntaxError text to showErrorMessage(); the empty message falls back to the translated generic error, as Pro's login handler already does. - Test: pin that a status-less 'network' entry is not a fault. Fixes #3173
…llback From the self-review of #3175: - mailto:, tel: and other non-http(s) URLs hand off to another app and never unload the page, so they release the button at once instead of after 15s. - A URL ending in an empty "#" is a same-page fragment navigation too. - The 15s fallback proves the page did not leave, so it clears navigatingAway. Otherwise a later real failure on that page would be logged as a non-fault. If the navigation commits later, pagehide sets the flag again before the unload. - release() removes its pageshow listener, so repeated non-unloading redirects do not stack listeners. - Reword the raw-error comment as the rule it enforces.
…nerate with AI screen - Four free-safe starter cards (Contact, Quote request, Event registration, Feedback) that prefill the prompt; clicking again clears an untouched prompt. - Pick / Customize / Generate progress steps and event-driven Learn tips. - Generate stays aria-disabled until the prompt has text, with a hint. - Inline Undo when a card replaces the user's own prompt. - 0/2000 character counter; voice input adds a separator and respects the limit. - Layout uses max-width and scrolls on short or narrow screens. - Replace the resume-upload example prompt with free-supported wording. - New srfm.aiFormScreen.starterPrompts filter with jest coverage.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ated
Gutenberg's cloneBlock() does a shallow spread of block attributes, so
duplicated blocks share the same array references as the original (e.g.
the options array in multi-choice). Any in-place mutation on one block's
array would silently affect the other.
On duplicate detection, iterate all attributes and shallow-clone any
array values (one level deep is sufficient since option objects contain
only primitives) so each block immediately owns its own independent copy.
This is the root-cause fix. The deleteOption immutability fix in
multi-choice/edit.js is still correct and prevents future regressions,
but without this change the shared reference persists until the first
setAttributes({ options }) call.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a narrow lifecycle hook right after Entries::add() succeeds, before notification mail is sent, and on the compliance "do not store entries" accepted path (entry id 0). It carries the parsed request data, so a listener can correlate the submission with non-field keys the client sent. Pro's Form Abandonment & Recovery (sureforms-pro#1519) uses it to mark an unfinished capture submitted and stop its pending reminder without waiting behind a slow mail transport. srfm_form_submit is unchanged.
- Send the selected starter card id and an edited flag with create-new-form. - Store the card id on the form as _srfm_ai_starter. - New ai_starter_usage event (forced, cumulative): total AI forms, forms per starter card and edited count, so card share is queryable in ClickHouse. - Add ai_starter to the first_form_published event properties. - handleAddNewPost() accepts optional extra request data. - PHPUnit coverage for the counters, key cap and pending-event overwrite.
…for the coverage check
Forces healthy AI usage details before boot (local/CI domains fail middleware verification) and stubs generate-form, then checks each card sends its prompt, the inactive Generate hint, deselect and Undo.
The starter cards and Learn tips already guide the flow; the indicator added visual noise without semantics for assistive tech.
…fter the step indicator removal
- New AI_Helper::has_ai_generated_forms() (one-row lookup), localized as srfm_admin.has_ai_generated_forms on the Generate with AI screen only. - After the first AI form the cards collapse to "Need ideas? Show examples"; expanding moves focus to the first card. The Learn flow always shows them. - PHPUnit + Playwright coverage.
… it replaced Edited prompts are still kept on deselect. Adds Playwright coverage for both.
Starter usage is counted at creation time, so the per-form meta only fed a one-time first_form_published property. Remove it (and its export/duplicate side effects) and sanitize the starter id inside track_ai_starter_usage() instead of relying on the caller.
… box It sat below the credits/upgrade banner, so the blank-form option was pushed down the page.
- Learn / generate tips open above their target, so they no longer overflow the scroll container at ~1280px (clipped tip + horizontal scrollbar). - Clicking Generate with an empty prompt also opens collapsed examples, since the hint tells the user to pick one. - Collapsed state uses its own subtitle. - Deselecting an edited example announces that the edits were kept. - Drop the always-false aria-expanded on "Show examples". - has_ai_generated_forms(): skip the sort (orderby none), accurate docblock.
…t doesn't cover the examples
Stubs generate-form and map-fields as successful and captures the create-new-form body for an untouched card, an edited card and free text. Also type $starter_id as mixed in the tracker docblock.
… fix (#3150) Review: sureforms#3214 (optional)
…-review Email delivery: review fixes for #3214 (stale SureMail status, lost-submission count)
Email delivery: SureMail + SureContact onboarding, delivery status and honest failures (#3150)
feat: fire srfm_submission_accepted as soon as a submission is accepted
…-submit-disabled fix: keep the submit button disabled while a redirect confirmation navigates
feat(analytics): track AI forms created from starter cards
# Conflicts: # tests/unit/admin/test-analytics.php
feat(ai-builder): starter prompt cards on Generate with AI
…t, and always clean up its cap filter WordPress trunk (7.2-alpha) wp_kses_post() drops a <script>'s contents as well as its tags, so the exact-output assertion failed. It failed before its own cleanup, leaking the "no unfiltered_html" filter into every later test: the WPForms importer and page-search tests then saved through kses and failed too. Both outputs are accepted now, and the filter and user are removed in a finally block.
- Smart tags now resolve only in SureForms form content: get_form_markup()
marks its whole render as form content, the srfm/form block resolves for a
real form, and a form post's own page still resolves. check_form_by_id() is
true only for a sureforms_form post.
- {get_input:name} and {get_cookie:name} must match in full.
- get_input / get_cookie values with a javascript:, vbscript: or data: scheme
are dropped (numeric character references decoded at any code point), and
braces in values are returned as character references so a later pass
cannot resolve a tag inside a value.
- get_form_markup() body moved to render_form_markup() so the render context
is restored on every return path.
…eckbox-fields fix: keep an unticked checkbox in the entry and in notification emails
…by-error-ref fix: only reference the field error message while it is shown (#3080)
…to dev-nr-2.12.9 # Conflicts: # tests/unit/admin/test-admin.php
Dev to Next Release 2.12.9
…ng post title (#3219)
Round 2 review.
H1 The form-post fallback in get_block_form_id() read the global post, which a
query loop sets to each form it renders while another post is on screen. A
block in that post then resolved its own tags, including {get_cookie:} for
the viewer's session. The fallback is now tied to the queried object, so it
only fires on the form's own page. WordPress' own cookie names are refused
outright as defence in depth.
H2 {embed_post_title} returned the raw title into a field default that had
already been escaped as the literal tag, so a quote in the title reached the
value attribute. It is escaped now, as {form_title} already was.
M1 @SInCE 2.12.9 -> x.x.x in 9 places; the release PR fills these in.
M2 Only leading whitespace and in-scheme tab/CR/LF are collapsed before the
scheme check, so ordinary values keep their interior spaces.
M3 Changelog lines for the security fix and the behaviour change.
L1 Combining marks in request tag names, for Indic and Thai parameters.
L3 blockId is reduced to CSS-safe characters before it reaches a selector.
L4 The cheap brace test runs before get_block_form_id() on every block.
L5 Smart_Tags::get_instance() instead of a new render_block filter per call.
Not done: L2. Making render_form_markup() private trips PHP Insights' ordered
class elements rule, which wants the ~700-line body moved.
Version Bump 2.12.9
Resolve the readme.txt conflict: fold this PR's smart tags Improvement and security Fix lines into the 2.12.9 entry, and set the PR's @SInCE x.x.x placeholders to 2.12.9 since it ships in 2.12.9.
…m-scope fix(security): resolve smart tags only in form content (#3219)
Auto-generated by /i18n command on PR #3225
chore: update i18n translations
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.
Syncs private
masterup to4153a5d38(SureForms 2.12.9, released 2026-10-13) into the public mirror.master→4153a5d38. 212 commits are new to the mirror; the rest re-signed to SHAs already on the mirror..claude,internal-docs,docs, allCLAUDE.md, analysis docs, internal release workflows andbinscripts).README.mdis the only markdown file in this diff.master, so this diff only shows real upstream changes (155 files), with no internal-file deletions.Highlights (2.12.9 changelog)
srfm_submission_accepteddeveloper action, fired as soon as a submission is accepted.srfm_allow_php_mail_fallbackfilter to restore it.🤖 Generated with Claude Code