Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
213 commits
Select commit Hold shift + click to select a range
04ac969
Merge pull request #3171 from brainstormforce/master-dev-2.12.8
vanshk141999 Sep 25, 2026
5eedc51
Merge pull request #3172 from brainstormforce/dev-nr-2.12.8-post
vanshk141999 Sep 25, 2026
ec15341
fix(multi-choice): prevent shared options reference when block is dup…
avi1080p Sep 28, 2026
e638cc3
fix: keep the submit button disabled while a redirect confirmation na…
vanshk141999 Sep 28, 2026
e9771ec
fix: release non-unloading redirects at once and clear the flag on fa…
vanshk141999 Sep 28, 2026
65952e4
feat(ai-builder): add starter prompt cards and guided steps to the Ge…
adi3890 Sep 28, 2026
fe0e9af
chore: update plugin version to 2.12.8
avi1080p Sep 28, 2026
e367429
fix(addInitialAttr): deep-clone array attributes when block is duplic…
avi1080p Sep 28, 2026
243c48f
feat: fire srfm_submission_accepted as soon as a submission is accepted
vanshk141999 Sep 28, 2026
fd48972
feat(analytics): track AI forms created from starter cards
adi3890 Sep 29, 2026
0f4f597
test(analytics): move ai_starter_usage tests into test-analytics.php …
adi3890 Sep 29, 2026
25962dc
test(e2e): cover starter cards on the Generate with AI screen
adi3890 Sep 29, 2026
fb18885
Merge branch 'feat/ai-starter-cards' into feat/ai-starter-tracking
adi3890 Sep 29, 2026
1fdf4c7
docs(e2e): note AI screen testing patterns in the spec guide
adi3890 Sep 29, 2026
3772a3c
Merge branch 'feat/ai-starter-cards' into feat/ai-starter-tracking
adi3890 Sep 29, 2026
585345d
feat(ai-builder): remove the Pick / Customize / Generate step indicator
adi3890 Sep 29, 2026
4858a09
Merge branch 'feat/ai-starter-cards' into feat/ai-starter-tracking
adi3890 Sep 29, 2026
c84bb7b
fix(analytics): keep isUntouchedStarter for the starter edited flag a…
adi3890 Sep 29, 2026
5cb4d86
feat(ai-builder): collapse starter examples once the site has an AI form
adi3890 Sep 29, 2026
c2af078
Merge branch 'feat/ai-starter-cards' into feat/ai-starter-tracking
adi3890 Sep 29, 2026
17f1581
fix(ai-builder): deselecting an untouched example restores the prompt…
adi3890 Sep 29, 2026
39f8dbd
Merge branch 'feat/ai-starter-cards' into feat/ai-starter-tracking
adi3890 Sep 29, 2026
44a4328
refactor(analytics): drop the _srfm_ai_starter form meta
adi3890 Sep 29, 2026
f989139
feat(ai-builder): show "Or create it yourself" right below the prompt…
adi3890 Sep 29, 2026
b0810e5
Merge branch 'feat/ai-starter-cards' into feat/ai-starter-tracking
adi3890 Sep 29, 2026
26ed874
fix(ai-builder): review polish for starter examples
adi3890 Sep 29, 2026
a8f034e
Merge branch 'feat/ai-starter-cards' into feat/ai-starter-tracking
adi3890 Sep 29, 2026
0d024ba
fix(ai-builder): show the Learn tip inside the prompt box corner so i…
adi3890 Sep 29, 2026
63ba761
Merge branch 'feat/ai-starter-cards' into feat/ai-starter-tracking
adi3890 Sep 29, 2026
f748b2d
test(e2e): assert ai_starter / ai_starter_edited reach create-new-form
adi3890 Sep 29, 2026
e140137
fix(ai-builder): ask for a multi-select question for dietary needs in…
adi3890 Sep 29, 2026
f7ffb7c
Merge branch 'feat/ai-starter-cards' into feat/ai-starter-tracking
adi3890 Sep 29, 2026
346a1a2
feat(email-delivery): add an email delivery status service
adi3890 Sep 29, 2026
83c9582
fix(notifications): stop the silent PHP mail() fallback and record se…
adi3890 Sep 29, 2026
c2a975f
fix(notifications): say when a failed notification lost a submission
adi3890 Sep 29, 2026
7d228e8
feat(onboarding): make the email delivery step reflect real sending s…
adi3890 Sep 29, 2026
4abfb6d
feat(email-delivery): show email delivery status on the dashboard, wi…
adi3890 Sep 29, 2026
872da2b
fix(compliance): name the real email delivery state in the never-stor…
adi3890 Sep 30, 2026
1f5c0bd
Merge branch 'feat/email-delivery-gdpr-warning-3150' into feat/email-…
adi3890 Sep 30, 2026
5ccbfa5
fix(editor): space the email delivery status off the notification table
adi3890 Sep 30, 2026
996d36f
fix(form-checks): keep the email setup fix next to a notification fai…
adi3890 Sep 30, 2026
2ebac1d
fix(addInitialAttr): keep inner arrays as arrays when cloning on dupl…
vanshk141999 Sep 30, 2026
935182b
Merge pull request #3176 from brainstormforce/fix/multi-choice-duplic…
vanshk141999 Sep 30, 2026
96a6cc2
fix(email-delivery): ask to connect SureMail when a failure meets no …
adi3890 Sep 30, 2026
0844b51
Merge branch 'feat/email-delivery-status-3150' into feat/email-delive…
adi3890 Sep 30, 2026
4f0c6ab
Merge branch 'feat/email-delivery-send-path-3150' into feat/email-del…
adi3890 Sep 30, 2026
5f6face
Merge branch 'feat/email-delivery-gdpr-warning-3150' into feat/email-…
adi3890 Sep 30, 2026
8c8359c
Merge branch 'feat/email-delivery-status-3150' into feat/email-delive…
adi3890 Sep 30, 2026
796d12f
style(ai-builder): per-card accent colors for starter example icons
adi3890 Sep 30, 2026
693ad99
Merge branch 'feat/ai-starter-cards' into feat/ai-starter-tracking
adi3890 Sep 30, 2026
cbe3f25
style(ai-builder): larger starter icon tiles to match the Figma
adi3890 Sep 30, 2026
db36b72
Merge branch 'feat/ai-starter-cards' into feat/ai-starter-tracking
adi3890 Sep 30, 2026
ff99bc1
style(ai-builder): more breathing room around the starter examples
adi3890 Sep 30, 2026
2f1fee2
Merge branch 'feat/ai-starter-cards' into feat/ai-starter-tracking
adi3890 Sep 30, 2026
2c44275
style(ai-builder): Figma selection style for starter example cards
adi3890 Sep 30, 2026
0e68133
Merge branch 'feat/ai-starter-cards' into feat/ai-starter-tracking
adi3890 Sep 30, 2026
549ad32
feat(onboarding): show the SureContact offer and ask for consent befo…
adi3890 Oct 1, 2026
7970bf5
feat(onboarding): create the SureContact account in one click through…
adi3890 Oct 1, 2026
7d637c2
feat(email-delivery): warn when the SureContact quota is nearly used up
adi3890 Oct 1, 2026
b1fc6d9
fix(email-delivery): a new SureMail connection clears failures from t…
adi3890 Oct 1, 2026
9a4a460
fix(admin): run activation hooks for plugins installed from SureForms
adi3890 Oct 1, 2026
05b5652
feat(email-delivery): advise verifying SureContact when an unverified…
adi3890 Oct 1, 2026
9f78429
test(email-delivery): date the SureContact connection before the failure
adi3890 Oct 1, 2026
44ba512
fix(email-delivery): address review on the status service
adi3890 Oct 1, 2026
3e52063
Merge remote-tracking branch 'origin/feat/email-delivery-status-3150'…
adi3890 Oct 1, 2026
75bef6b
fix(notifications): address review on the send path
adi3890 Oct 1, 2026
e99fe60
Merge remote-tracking branch 'origin/feat/email-delivery-send-path-31…
adi3890 Oct 1, 2026
67a3186
fix(email-delivery): keep lost never-store submissions until the owne…
adi3890 Oct 1, 2026
fac1582
Merge remote-tracking branch 'origin/feat/email-delivery-gdpr-warning…
adi3890 Oct 1, 2026
26d9bd0
perf(email-delivery): page the notifying-form lookup and prime its meta
adi3890 Oct 1, 2026
bd7e560
Merge remote-tracking branch 'origin/feat/email-delivery-dashboard-31…
adi3890 Oct 1, 2026
fbe1c41
fix(email-delivery): recheck a low quota sooner and test the quota fetch
adi3890 Oct 1, 2026
a56a4cc
Merge remote-tracking branch 'origin/feat/email-delivery-quota-notice…
adi3890 Oct 1, 2026
6dd1903
fix(email-delivery): advise verifying only when SureContact confirms …
adi3890 Oct 1, 2026
219c8b2
Merge remote-tracking branch 'origin/feat/email-delivery-status-3150'…
adi3890 Oct 1, 2026
88815a9
fix(onboarding): give failures their own screen in the email step
adi3890 Oct 1, 2026
a39a26c
Merge remote-tracking branch 'origin/feat/email-delivery-onboarding-3…
adi3890 Oct 1, 2026
5384145
fix(onboarding): say everything SureContact receives in the consent box
adi3890 Oct 1, 2026
aad70dd
Merge remote-tracking branch 'origin/feat/email-delivery-onboarding-c…
adi3890 Oct 1, 2026
7d4924b
fix(onboarding): send existing SureContact accounts through SureMail'…
adi3890 Oct 1, 2026
7387b85
Merge remote-tracking branch 'origin/feat/email-delivery-one-click-su…
adi3890 Oct 1, 2026
cc955c2
fix(admin): clear plugin onboarding redirects and tighten the installer
adi3890 Oct 1, 2026
a6958a4
style(admin): drop an extra blank line (PHP Insights)
adi3890 Oct 1, 2026
8679a55
fix(notifications): address round-2 review on the send path
adi3890 Oct 2, 2026
a9bd5b1
Merge remote-tracking branch 'origin/feat/email-delivery-send-path-31…
adi3890 Oct 2, 2026
41fb992
test(email-delivery): a partly sent never-store submission is not lost
adi3890 Oct 2, 2026
daff0ac
Merge remote-tracking branch 'origin/feat/email-delivery-gdpr-warning…
adi3890 Oct 2, 2026
fe27895
fix(email-delivery): stable order for the paged notifying-form lookup
adi3890 Oct 2, 2026
1c215a7
Merge remote-tracking branch 'origin/feat/email-delivery-dashboard-31…
adi3890 Oct 2, 2026
047357b
fix(email-delivery): recheck a used-up daily allowance within 30 minutes
adi3890 Oct 2, 2026
55f193c
Merge remote-tracking branch 'origin/feat/email-delivery-quota-notice…
adi3890 Oct 2, 2026
47cb5bb
fix(email-delivery): keep the cached quota when a failure asks for a …
adi3890 Oct 2, 2026
1384d15
fix(ai-builder): address review on starter examples (#3177)
adi3890 Oct 5, 2026
228c1aa
Merge remote-tracking branch 'origin/feat/ai-starter-cards' into feat…
adi3890 Oct 5, 2026
89201db
fix(analytics): address review on starter card tracking (#3180)
adi3890 Oct 5, 2026
c4c423a
fix(ai-builder): keep the AI screen scrollable and quiet aborted voic…
adi3890 Oct 5, 2026
db3ac23
Merge branch 'feat/ai-starter-cards' into feat/ai-starter-tracking
adi3890 Oct 5, 2026
bd16b74
fix(analytics): count a prompt as a card only if it keeps the card's …
adi3890 Oct 5, 2026
4f28b70
feat(email-delivery): redesign the onboarding email step and SMTP pag…
adi3890 Oct 7, 2026
e4d65f3
feat(email-delivery): lead the notification failure with "Connect Sur…
adi3890 Oct 7, 2026
4d4cfe0
fix(onboarding): open SureContact by default while SureMail is inactive
adi3890 Oct 7, 2026
41226ad
feat(mcp): install the MCP Adapter from WordPress.org in one click
vanshk141999 Oct 7, 2026
72d3b0a
fix(onboarding): address review on the email step and SMTP page (#3150)
adi3890 Oct 7, 2026
0d1d8a4
fix(onboarding): move focus with the selection on arrow keys, after i…
adi3890 Oct 7, 2026
6db8c96
fix(form-checks): offer Connect SureContact on the no-connection remi…
adi3890 Oct 7, 2026
115aa54
feat(onboarding): apply the updated email step design and review copy…
adi3890 Oct 7, 2026
0108813
feat(onboarding): animated 100 Mails Free tile and the You're all set…
adi3890 Oct 7, 2026
4aae1b6
fix(email-delivery): never throttle a failure across a new SureMail c…
adi3890 Oct 7, 2026
6a4f955
fix(onboarding): keep the email step's actions in view on short scree…
adi3890 Oct 7, 2026
1605e3e
fix(onboarding): 24px around the email step's divider, and its sticky…
adi3890 Oct 7, 2026
5bc8367
fix(onboarding): open Other SMTP card keeps the SureMail blue stroke,…
adi3890 Oct 7, 2026
e33b55c
fix(onboarding): keep the consent box and errors with the sticky acti…
adi3890 Oct 7, 2026
995ed31
feat(onboarding): tell SureContact a one-click sign-up came from Sure…
adi3890 Oct 7, 2026
4eaf070
fix(onboarding): consent says the From is replaced and SureContact ge…
adi3890 Oct 7, 2026
312d5ee
Merge remote-tracking branch 'origin/feat/email-delivery-onboarding-c…
adi3890 Oct 7, 2026
e5a8306
fix(onboarding): a fresh status read after install, never a stale in-…
adi3890 Oct 7, 2026
effcc78
Merge remote-tracking branch 'origin/feat/email-delivery-onboarding-3…
adi3890 Oct 7, 2026
5228ebf
Merge remote-tracking branch 'origin/feat/email-delivery-onboarding-c…
adi3890 Oct 7, 2026
bbe9816
fix(onboarding): after a sign-up, read the status afresh and stay bus…
adi3890 Oct 7, 2026
0b0bae4
Merge remote-tracking branch 'origin/feat/email-delivery-one-click-su…
adi3890 Oct 7, 2026
13af056
Merge remote-tracking branch 'origin/fix/email-delivery-new-connectio…
adi3890 Oct 7, 2026
5bfa727
fix(onboarding): consent says every site email is sent from the accou…
adi3890 Oct 7, 2026
7a932c2
fix(mcp): keep Activate for admins who can't install, and retry activ…
vanshk141999 Oct 7, 2026
ab45562
Merge pull request #3207 from brainstormforce/feat/mcp-adapter-one-cl…
vanshk141999 Oct 7, 2026
c249bdf
fix(notifications): judge a refused recipient by where the address ca…
adi3890 Oct 8, 2026
85bdba3
Merge remote-tracking branch 'origin/feat/email-delivery-send-path-31…
adi3890 Oct 8, 2026
d2dbad9
Merge remote-tracking branch 'origin/feat/email-delivery-gdpr-warning…
adi3890 Oct 8, 2026
654431d
Merge remote-tracking branch 'origin/feat/email-delivery-dashboard-31…
adi3890 Oct 8, 2026
bbd7794
Merge remote-tracking branch 'origin/feat/email-delivery-quota-notice…
adi3890 Oct 8, 2026
176fe5c
Merge remote-tracking branch 'origin/feat/email-delivery-verify-advic…
adi3890 Oct 8, 2026
4f2ddd0
Merge remote-tracking branch 'origin/feat/email-delivery-verify-advic…
adi3890 Oct 8, 2026
b5ba993
docs(form-checks): connect docblock no longer assumes #3205, and the …
adi3890 Oct 8, 2026
202aaf6
fix(onboarding): verify hint for new accounts, honest connected state…
adi3890 Oct 8, 2026
2356ead
feat(onboarding): sign in to an existing SureContact account in a pop…
adi3890 Oct 8, 2026
ad1162f
fix(onboarding): show Mailjet instead of Outlook in the provider logo…
adi3890 Oct 8, 2026
dcb2c34
test(notifications): name the visitor-recipient test after the functi…
adi3890 Oct 8, 2026
e51d043
Merge remote-tracking branch 'origin/feat/email-delivery-send-path-31…
adi3890 Oct 8, 2026
97c31fa
Merge remote-tracking branch 'origin/feat/email-delivery-gdpr-warning…
adi3890 Oct 8, 2026
3256dcf
Merge remote-tracking branch 'origin/feat/email-delivery-dashboard-31…
adi3890 Oct 8, 2026
87a4e9b
Merge remote-tracking branch 'origin/feat/email-delivery-quota-notice…
adi3890 Oct 8, 2026
220949a
Merge remote-tracking branch 'origin/feat/email-delivery-verify-advic…
adi3890 Oct 8, 2026
89cd8ed
Merge remote-tracking branch 'origin/feat/email-delivery-verify-advic…
adi3890 Oct 8, 2026
de96015
Merge pull request #3182 from brainstormforce/feat/email-delivery-sta…
adi3890 Oct 8, 2026
1808a8d
Merge pull request #3193 from brainstormforce/fix/recommended-plugin-…
adi3890 Oct 8, 2026
3a30ef3
Merge pull request #3186 from brainstormforce/feat/email-delivery-onb…
adi3890 Oct 8, 2026
87b393a
Merge pull request #3189 from brainstormforce/feat/email-delivery-onb…
adi3890 Oct 8, 2026
b290ecc
fix(notifications): server decides entry_saved; only address-level re…
adi3890 Oct 8, 2026
e6884ec
Merge remote-tracking branch 'origin/feat/email-delivery-send-path-31…
adi3890 Oct 8, 2026
df0d884
Merge remote-tracking branch 'origin/feat/email-delivery-gdpr-warning…
adi3890 Oct 8, 2026
a9197ab
Merge remote-tracking branch 'origin/feat/email-delivery-dashboard-31…
adi3890 Oct 8, 2026
8d1bde3
Merge remote-tracking branch 'origin/feat/email-delivery-quota-notice…
adi3890 Oct 8, 2026
0565cb8
Merge remote-tracking branch 'origin/feat/email-delivery-verify-advic…
adi3890 Oct 8, 2026
6916668
Merge remote-tracking branch 'origin/feat/email-delivery-verify-advic…
adi3890 Oct 8, 2026
8e497e2
Merge remote-tracking branch 'origin/feat/email-delivery-form-checks-…
adi3890 Oct 8, 2026
32af445
Merge remote-tracking branch 'origin/fix/email-delivery-throttle-acro…
adi3890 Oct 8, 2026
da73a57
Merge stack A (#3183…#3206, #3208) and stack B (#3190…#3205) into the…
adi3890 Oct 8, 2026
3e214ad
test(email-delivery): fail, connect, fail again within the throttle r…
adi3890 Oct 8, 2026
43a0287
test: accept WordPress 7.2's script handling in the form detector tes…
adi3890 Oct 8, 2026
8444721
test: also reset the current user in the form detector test's cleanup
adi3890 Oct 8, 2026
e1c0b7d
fix(notifications): judge a refused visitor address by the server's w…
adi3890 Oct 8, 2026
bbe5757
Merge remote-tracking branch 'origin/feat/email-delivery-send-path-31…
adi3890 Oct 8, 2026
de93a91
Merge remote-tracking branch 'origin/feat/email-delivery-gdpr-warning…
adi3890 Oct 8, 2026
b2c89a0
Merge remote-tracking branch 'origin/feat/email-delivery-dashboard-31…
adi3890 Oct 8, 2026
52ca4e2
Merge remote-tracking branch 'origin/feat/email-delivery-quota-notice…
adi3890 Oct 8, 2026
c4d29d7
Merge remote-tracking branch 'origin/feat/email-delivery-verify-advic…
adi3890 Oct 8, 2026
ef9589a
Merge remote-tracking branch 'origin/feat/email-delivery-form-checks-…
adi3890 Oct 8, 2026
a0b2237
Merge pull request #3211 from brainstormforce/fix/tests-wordpress-tru…
adi3890 Oct 8, 2026
1ece235
Merge branch 'dev' into feat/email-delivery-3150
adi3890 Oct 8, 2026
97f878f
test(email-delivery): a new connection is noticed by the failure itse…
adi3890 Oct 8, 2026
7b03a5b
chore: one SureForms-screen block in admin.php, and drop a test's no-…
adi3890 Oct 8, 2026
34776bf
Merge pull request #3190 from brainstormforce/feat/email-delivery-one…
adi3890 Oct 8, 2026
92b4311
Merge pull request #3192 from brainstormforce/fix/email-delivery-new-…
adi3890 Oct 8, 2026
318e948
Merge pull request #3205 from brainstormforce/feat/email-delivery-onb…
adi3890 Oct 8, 2026
d7edad9
Merge pull request #3210 from brainstormforce/feat/email-delivery-315…
adi3890 Oct 8, 2026
62da7cb
fix: keep an unticked checkbox in the entry and in notification emails
vanshk141999 Oct 8, 2026
d2c8a7f
chore(email-delivery): order class members and drop extra blank lines…
adi3890 Oct 9, 2026
68b0c63
fix(notifications): stop excusing "mailbox unavailable" refusals (#3150)
adi3890 Oct 9, 2026
5b43111
Merge pull request #3216 from brainstormforce/fix/email-delivery-3150…
adi3890 Oct 9, 2026
9215510
fix: only reference the field error message while it is shown
vanshk141999 Oct 11, 2026
ca9553e
fix: keep shared email error id linked while still shown; drop empty …
vanshk141999 Oct 11, 2026
d41656e
test: cover set_aria_described_by directly; keep its note in the body
vanshk141999 Oct 11, 2026
f4486f1
fix(email-delivery): read SureMail's install state again before insta…
adi3890 Oct 12, 2026
4f9335f
fix(email-delivery): count a lost submission only when the site faile…
adi3890 Oct 12, 2026
61a16cb
fix(onboarding): offer a link when the SureContact sign-in window is …
adi3890 Oct 12, 2026
939e503
docs(changelog): list the email delivery additions and the activation…
adi3890 Oct 12, 2026
846bcfa
Merge pull request #3218 from brainstormforce/fix/email-delivery-3150…
vanshk141999 Oct 12, 2026
05bcfa5
Merge pull request #3214 from brainstormforce/feat/email-delivery-3150
vanshk141999 Oct 12, 2026
70ea184
Merge pull request #3178 from brainstormforce/feat/1519-form-abandonment
vanshk141999 Oct 12, 2026
b1cd170
Merge pull request #3175 from brainstormforce/fix/3173-redirect-keeps…
vanshk141999 Oct 12, 2026
0f12788
Merge pull request #3180 from brainstormforce/feat/ai-starter-tracking
vanshk141999 Oct 12, 2026
2ae45f7
Merge remote-tracking branch 'origin/dev' into fix-3177-merge
vanshk141999 Oct 12, 2026
274073b
Merge pull request #3177 from brainstormforce/feat/ai-starter-cards
vanshk141999 Oct 12, 2026
3cfcdd1
test: accept WordPress 7.2's script handling in the form detector tes…
adi3890 Oct 8, 2026
5c040e2
test: also reset the current user in the form detector test's cleanup
adi3890 Oct 8, 2026
a07f76c
fix(security): resolve smart tags only in form content (#3219)
vanshk141999 Oct 12, 2026
c10067d
test: cover get_rendering_form_id() and render_form_markup() (#3219)
vanshk141999 Oct 12, 2026
0357879
Merge pull request #3215 from brainstormforce/fix/3213-unsubmitted-ch…
vanshk141999 Oct 12, 2026
ee8e432
Merge pull request #3217 from brainstormforce/fix/3080-aria-described…
vanshk141999 Oct 12, 2026
b09ee78
Merge branch 'dev' of https://github.com/brainstormforce/sureforms in…
vanshk141999 Oct 12, 2026
4939ebd
Merge pull request #3221 from brainstormforce/dev-nr-2.12.9
vanshk141999 Oct 12, 2026
ac4252d
Version Bump 2.12.9
vanshk141999 Oct 12, 2026
ef0ba81
Changelog: add all PRs merged since 2.12.8
vanshk141999 Oct 13, 2026
bf9ef38
Changelog: shorten 2.12.9 lines
vanshk141999 Oct 13, 2026
48f985e
Changelog: trim 2.12.9 entry
vanshk141999 Oct 13, 2026
2bd9a17
fix(security): stop a loop lending form scope, and escape the embeddi…
vanshk141999 Oct 13, 2026
534d8f7
Merge pull request #3222 from brainstormforce/version-bump-2.12.9
vanshk141999 Oct 13, 2026
6a461bf
Merge next-release into fix/3219-smart-tags-form-scope
vanshk141999 Oct 13, 2026
4a163d1
Merge pull request #3220 from brainstormforce/fix/3219-smart-tags-for…
vanshk141999 Oct 13, 2026
4d945f2
chore: update i18n translations
github-actions[bot] Oct 13, 2026
e7763eb
Merge pull request #3226 from brainstormforce/i18n/next-release
vanshk141999 Oct 13, 2026
28cd0cf
Merge pull request #3225 from brainstormforce/next-release
vanshk141999 Oct 14, 2026
b807f01
chore: strip internal-only paths from public mirror sync
vanshk141999 Oct 14, 2026
02b4c1e
Sync master from upstream
vanshk141999 Oct 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
**Contributors:** [brainstormforce](https://profiles.wordpress.org/brainstormforce/)
**Tags:** forms, ai forms, contact form, form builder, payment form
**Requires at least:** 6.4
**Tested up to:** 7.1.2
**Tested up to:** 7.1.3
**Requires PHP:** 7.4
**Stable tag:** 2.12.8
**Stable tag:** 2.12.9
**License:** GPLv2 or later
**License URI:** http://www.gnu.org/licenses/gpl-2.0.html

Expand Down Expand Up @@ -426,6 +426,17 @@ Visit the [SureForms features page](https://sureforms.com/features/?utm_source=w
You can report security issues through our [Bug Bounty Program](https://brainstormforce.com/bug-bounty-program/). We collaborate with Patchstack to validate, triage, and handle security reports.

## Changelog ##
### 2.12.9 - 13th October 2026 ###
* New: Added the `srfm_submission_accepted` developer action, fired as soon as a submission is accepted.
* New: Forms that do not store entries now warn you when a failed notification loses a submission.
* New: MCP Adapter can now be installed and activated in one click.
* Improvement: Failed notifications are no longer silently retried through PHP's mail(); the reason now shows in Entry Logs and Form Checks. Use the `srfm_allow_php_mail_fallback` filter to restore it.
* Improvement: Smart tags such as {get_input:name} now resolve only inside SureForms form content. A tag written in ordinary page or post content is shown as written.
* Fix: Deleting an option in a duplicated Multiple Choice block no longer removes it from the original.
* Fix: Form fields no longer fail accessibility scans for a missing error message reference.
* Fix: The submit button now stays disabled while a form redirects, preventing duplicate submissions.
* Fix: Unticked Checkbox fields now appear in entries and notification emails.
* Fix: This update addressed a security bug. Props to dzaku from Patchstack for reporting it responsibly to our team.
### 2.12.8 - 25th September 2026 ###
* Improvement: The debug log no longer records routine validation stops, such as an empty required field, keeping it focused on real failures.
* Fix: Entry Logs now record the email notification sent when a form is submitted.
Expand All @@ -439,12 +450,6 @@ You can report security issues through our [Bug Bounty Program](https://brainsto
* Fix: The conversion rate no longer counts submissions made by site editors while previewing a form.
* Fix: The Edit Form icon is no longer oversized in Divi.
* Fix: This update addressed a security bug. Props to nh4tvd from Patchstack for reporting it responsibly to our team.
### 2.12.6 - 2nd September 2026 ###
* New: Added an Enable Logs option that records form submission failures to a downloadable file, making it easier to diagnose issues on a live site.
* New: Added Views and Conversion Rate columns to the Forms list, so you can see how each form is performing at a glance.
* New: SureForms now detects a missing entries database table and offers a one-click repair, so submissions start saving again without manual database work.
* Fix: The Edit Form button no longer overlaps form fields on the front end.
* Fix: This update addressed a security bug. Props to Patchstack for reporting it responsibly to our team.
The full changelog is available [here](https://sureforms.com/whats-new/?utm_source=wordpress.org&utm_medium=whats_new).

## Upgrade Notice ##
559 changes: 541 additions & 18 deletions admin/admin.php

Large diffs are not rendered by default.

160 changes: 141 additions & 19 deletions admin/analytics.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@

namespace SRFM\Admin;

use SRFM\Inc\AI_Form_Builder\AI_Helper;
use SRFM\Inc\Database\Register;
use SRFM\Inc\Database\Tables\Entries;
use SRFM\Inc\Email_Delivery\Status as Email_Delivery_Status;
use SRFM\Inc\Form_Views;
use SRFM\Inc\Helper;
use SRFM\Inc\Learn;
Expand Down Expand Up @@ -92,6 +94,7 @@ static function () {
add_action( 'current_screen', [ $this, 'track_first_editor_open' ] );
add_action( 'transition_post_status', [ $this, 'track_first_form_published' ], 10, 3 );
add_action( 'save_post', [ $this, 'track_embed_styling_configured' ], 10, 2 );
add_action( 'admin_init', [ $this, 'track_email_delivery_status' ] );

// Detect state-based events on admin load (dedup prevents repeat tracking).
$this->detect_state_events();
Expand Down Expand Up @@ -736,6 +739,58 @@ public function track_first_form_published( $new_status, $old_status, $post ) {
);
}

/**
* Track AI form creation, broken down by the starter card used (if any).
*
* Keeps cumulative counters in srfm_options and queues the latest totals as
* the `ai_starter_usage` event each time an AI form is created, so the share
* of AI forms started from each card can be read from the warehouse.
*
* @param mixed $starter_id Starter card id (sanitized here), or empty string for a free-text prompt.
* @param bool $edited Whether the starter prompt was edited before generating.
* @since 2.12.9
* @return void
*/
public static function track_ai_starter_usage( $starter_id, $edited ) {
// The id becomes an option key and an event property key, so clean it here
// rather than trusting every caller.
$starter_id = substr( sanitize_key( Helper::get_string_value( $starter_id ) ), 0, 40 );

$usage = Helper::get_srfm_option( 'ai_starter_usage', [] );
$usage = is_array( $usage ) ? $usage : [];

$counts = isset( $usage['starters'] ) && is_array( $usage['starters'] ) ? array_map( 'absint', $usage['starters'] ) : [];

// Counts AI forms created since this tracking shipped, deleted ones included
// (unlike the `ai_generated_forms` stat, which counts forms that exist now).
$usage['ai_forms_created'] = absint( $usage['ai_forms_created'] ?? 0 ) + 1;

// Cap distinct keys so a filtered starter list can't grow the option unbounded.
if ( '' !== $starter_id && ( isset( $counts[ $starter_id ] ) || count( $counts ) < 20 ) ) {
$counts[ $starter_id ] = absint( $counts[ $starter_id ] ?? 0 ) + 1;

if ( $edited ) {
$usage['edited'] = absint( $usage['edited'] ?? 0 ) + 1;
}
}

$usage['starters'] = $counts;
Helper::update_srfm_option( 'ai_starter_usage', $usage );

$properties = [
'ai_forms_created' => (string) $usage['ai_forms_created'],
'edited' => (string) absint( $usage['edited'] ?? 0 ),
];
foreach ( $counts as $id => $count ) {
$properties[ 'starter_' . $id ] = (string) $count;
}

// $force = true: skip the already-sent check and replace any queued copy, so
// the next flush sends these totals. Nothing is re-sent until another AI form
// is created.
self::events()->track( 'ai_starter_usage', (string) array_sum( $counts ), $properties, true );
}

/**
* Track embed styling configuration when a post/page is saved.
*
Expand Down Expand Up @@ -824,6 +879,47 @@ public function track_plugin_activated_event() {
self::events()->track( 'plugin_activated', SRFM_VER, [ 'source' => $source ] );
}

/**
* Track the site's email delivery state.
*
* Whether form notifications have a real mailer behind them. A state, not a
* milestone, so it is re-sent (forced) whenever it changes -- and checked at
* most daily, because admin_init runs on every admin page load and the status
* can scan the plugins directory. Only fixed labels are sent: connection
* titles are owner-entered text.
*
* On admin_init rather than in detect_state_events(), which runs while
* plugins are still loading: pluggable functions do not exist yet, so a
* redefined wp_mail() would be missed and current_user_can() is undefined.
*
* @since 2.12.9
* @return void
*/
public function track_email_delivery_status() {
if ( false !== get_transient( 'srfm_email_delivery_state_checked' ) ) {
return;
}

set_transient( 'srfm_email_delivery_state_checked', 1, DAY_IN_SECONDS );

$email_delivery = Email_Delivery_Status::get_status();
$mailer_slug = Helper::get_string_value( $email_delivery['mailer']['slug'] ?? '' );
$verified = $email_delivery['surecontact']['email_verified'] ?? null;
$delivery_props = [
'mailer' => $mailer_slug,
'mailer_plugin' => 'other' === $mailer_slug ? Helper::get_string_value( $email_delivery['mailer']['label'] ?? '' ) : '',
'surecontact' => ! empty( $email_delivery['surecontact']['connected'] ) ? 'yes' : 'no',
'surecontact_verified' => null === $verified ? 'unknown' : ( $verified ? 'yes' : 'no' ),
];
$delivery_state = Helper::get_string_value( $email_delivery['state'] ?? '' );
$fingerprint = $delivery_state . '|' . implode( '|', $delivery_props );

if ( '' !== $delivery_state && Helper::get_srfm_option( 'email_delivery_state_tracked', '' ) !== $fingerprint ) {
self::events()->track( 'email_delivery_status', $delivery_state, $delivery_props, true );
Helper::update_srfm_option( 'email_delivery_state_tracked', $fingerprint );
}
}

/**
* Extract non-inherit formTheme values from Bricks element data.
*
Expand Down Expand Up @@ -1007,6 +1103,49 @@ private function detect_state_events() {
$onboarding_props['suremail_installed'] = (bool) $onboarding_analytics['suremailInstalled'] ? 'yes' : 'no';
}

// Email delivery step: the delivery state on arrival and on leaving,
// and what the owner did. Closed sets, intersected like the premium
// tabs below, because the blob is whatever the wizard POSTed.
if ( ! empty( $onboarding_analytics['emailDelivery'] ) && is_array( $onboarding_analytics['emailDelivery'] ) ) {
$email_delivery = $onboarding_analytics['emailDelivery'];
$states = [ 'attention', 'not_configured', 'suremail_no_connection', 'limited', 'other_mailer', 'ready' ];
$step_actions = [ 'skip', 'cannot_install', 'install_other_smtp', 'continue_limited', 'continue_other_mailer', 'continue_ready', 'continue_attention', 'continue_not_set_up' ];

$state_props = [
'stateAtStep' => 'email_delivery_state_at_step',
'finalState' => 'email_delivery_state_at_exit',
];

foreach ( $state_props as $key => $prop ) {
if ( isset( $email_delivery[ $key ] ) && in_array( $email_delivery[ $key ], $states, true ) ) {
$onboarding_props[ $prop ] = $email_delivery[ $key ];
}
}

if ( isset( $email_delivery['action'] ) && in_array( $email_delivery['action'], $step_actions, true ) ) {
$onboarding_props['email_delivery_action'] = $email_delivery['action'];
}

if ( isset( $email_delivery['suremailOpened'] ) ) {
$onboarding_props['email_delivery_suremail_opened'] = (bool) $email_delivery['suremailOpened'] ? 'yes' : 'no';
}

if ( isset( $email_delivery['consented'] ) ) {
$onboarding_props['email_delivery_consented'] = (bool) $email_delivery['consented'] ? 'yes' : 'no';
}

// The option card open when the step was left.
if ( isset( $email_delivery['option'] ) && in_array( $email_delivery['option'], [ 'surecontact', 'other_smtp' ], true ) ) {
$onboarding_props['email_delivery_option'] = $email_delivery['option'];
}

// Outcome of the one-click SureContact sign-up, when it was tried.
$provision_outcomes = [ 'created', 'already_registered', 'unavailable', 'failed' ];
if ( isset( $email_delivery['provision'] ) && in_array( $email_delivery['provision'], $provision_outcomes, true ) ) {
$onboarding_props['email_delivery_provision'] = $email_delivery['provision'];
}
}

if ( isset( $onboarding_analytics['accountConnected'] ) ) {
$onboarding_props['account_connected'] = (bool) $onboarding_analytics['accountConnected'] ? 'yes' : 'no';
}
Expand Down Expand Up @@ -1066,25 +1205,8 @@ private function detect_state_events() {

// first_ai_form_generated: detect if any AI-generated form exists.
// Guard with is_tracked() to skip the meta_query after the event is already tracked.
if ( ! self::events()->is_tracked( 'first_ai_form_generated' ) ) {
$ai_forms = get_posts(
[
'post_type' => SRFM_FORMS_POST_TYPE,
'post_status' => 'any',
'posts_per_page' => 1,
'fields' => 'ids',
'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Runs once per lifecycle via is_tracked guard.
[
'key' => '_srfm_is_ai_generated',
'value' => '',
'compare' => '!=',
],
],
]
);
if ( ! empty( $ai_forms ) ) {
self::events()->track( 'first_ai_form_generated' );
}
if ( ! self::events()->is_tracked( 'first_ai_form_generated' ) && AI_Helper::has_ai_generated_forms() ) {
self::events()->track( 'first_ai_form_generated' );
}

// MCP / Abilities API first-enable events.
Expand Down
20 changes: 10 additions & 10 deletions assets/js/unminified/blocks/dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,6 @@ function initializeDropdown() {

let additionalConfig = {};
const inputName = element.getAttribute( 'name' );
const errorContainerID = element
?.closest( '.srfm-dropdown-block' )
?.querySelector( '.srfm-error-message' )
?.getAttribute( 'data-srfm-id' );

if ( element.getAttribute( 'data-multiple' ) === 'true' ) {
additionalConfig = {
maxItems: null, // Enabling multi selection for dropdown.
Expand All @@ -55,17 +50,22 @@ function initializeDropdown() {
plugins: [ 'remove_button', 'clear_button' ], // Adding remove button to the selected options and clear button for the dropdown.
openOnFocus: false, // Stop the dropdown from opening on focus.
/**
* If the error container is present, assign it to the aria-describedby attribute.
* This will ensure that when there is a error, it will be announced by the screen reader
* when the field is in focus state.
* Mirror the select's aria-describedby onto the search input, so the error
* (linked only while shown) and the help text are announced on focus.
*
* If there are selected options, announce them on field focus.
*/
onFocus() {
if ( errorContainerID ) {
const describedBy =
element.getAttribute( 'aria-describedby' );
if ( describedBy ) {
tomInputInstance.control_input.setAttribute(
'aria-describedby',
errorContainerID
describedBy
);
} else {
tomInputInstance.control_input.removeAttribute(
'aria-describedby'
);
}
if (
Expand Down
Loading
Loading