Skip to content

Accept internationalized domain names in Website/URL fields - #3256

Open
NathanaelJonesIreland wants to merge 2 commits into
masterfrom
fix/url-field-idn-support
Open

Accept internationalized domain names in Website/URL fields#3256
NathanaelJonesIreland wants to merge 2 commits into
masterfrom
fix/url-field-idn-support

Conversation

@NathanaelJonesIreland

@NathanaelJonesIreland NathanaelJonesIreland commented Aug 19, 2026

Copy link
Copy Markdown

What

The Website/URL field rejects valid internationalized domain names (IDNs) whose hostname contains
accented characters. Reported by an Elite customer in Help Scout ticket 257002 for a .ch domain
spelled with an umlaut. .ch explicitly permits accented vowels, so the domain is legitimately
registrable.

The cause is a single host-matching regex, duplicated in PHP and JS. Its host character class
[\da-z\.-] is ASCII-only:

  • classes/models/fields/FrmFieldUrl.php in FrmFieldUrl::validate()
  • js/formidable.js in checkUrlField()
  • js/formidable.min.js (the literal survives verbatim, since npm run minimize compiles at
    WHITESPACE level)

Formidable Pro has zero copies of this pattern.

Why this is safe rather than a loosening

Three things make this a consistency fix rather than a new capability:

  1. The punycode spelling of the same domain already passes. xn---encoded hosts have always
    validated, and they resolve to the identical host. Accepting the Unicode spelling adds nothing
    a submitter could not already do.
  2. Non-ASCII in the path, query and fragment already passes. The regex only constrains the
    host, so the field already stored accented characters happily. Only the hostname was rejected.
  3. esc_url_raw() already preserves the bytes. WordPress's URL sanitizer explicitly allows the
    high byte range, so sanitizing was never the thing rejecting these values.

Sanitizing, escaping, storage and the scheme allowlist are all untouched. Chrome's native
type="url" constraint already accepts every IDN form here, so the browser was not the blocker
either.

Verification

  • Exhaustive ASCII equivalence. The old and new patterns were compared across 1408 ASCII
    byte/position combinations and are byte-for-byte identical. No previously accepted or rejected
    ASCII url changes behaviour. This was brute-forced, not sampled.
  • Injection set unchanged. javascript:, data:, vbscript:, <script> and CRLF-header
    inputs all still fail exactly as before. The only behavioural delta across the whole matrix is
    the IDN cases.
  • Pattern read back from the edited file (rather than a copy) accepts 10 IDN forms, including
    Cyrillic and CJK, and rejects 8 malformed hosts.

The trap worth knowing about in review

The two regexes deliberately do not use the same character range:

  • PHP matches UTF-8 bytes (no /u modifier), so the raw byte range covers all non-ASCII.
  • JS matches UTF-16 code units, so it needs \u0080-\uFFFF. The PHP byte range would cover an
    umlaut but not Cyrillic or CJK.

Copying one literal into both would accept those hosts server side while silently rejecting them in
the browser, which is the same class of split this ticket is about. test_url_field_js_regex_parity()
asserts the two JS files carry the code unit form and never the PHP one.

/u is also deliberately absent from the PHP pattern: preg_match() returns false on invalid
UTF-8, and because the result is negated that would report valid Latin-1 input as invalid.
test_url_non_utf8_host_byte() guards this, with a precondition so it cannot pass vacuously.

One more subtlety, confirmed empirically: appending the range after the trailing hyphen
([\da-z\.-\x80-\xff]) is not a syntax error. PCRE reads it as the range 0x2E-0x80, which
silently admits / ? : @ < > [ inside the hostname. The negative rows https://a/b.com and
https://a?b.com exist to fail if anyone ever reorders the class that way.

Tests

  • test_url_idn_validation() - 11 must-pass values (accented Latin, Cyrillic, CJK, uppercase
    non-ASCII, punycode, ASCII baseline, localhost, non-ASCII in path/query/fragment, and the
    no-scheme form) and 4 must-fail values.
  • test_url_non_utf8_host_byte() - the /u guard.
  • test_url_field_js_regex_parity() - asserts the rule rather than pinning the literal, and checks
    the minified artifact carries the same host class as its source. Mutation-proven: green on the
    real files, red when formidable.min.js is reverted alone, red when the PHP range is copied into
    the JS source.
  • 3 rows appended to the shared expected_format_errors() table.
  • One Cypress it() with "Validate this form with javascript" enabled, so it exercises the
    committed minified artifact through a real browser rather than passing via the server-side path.

php -l and node --check are clean. phpcs, phpstan, phpunit and eslint need composer install
plus a WordPress test database, which is not set up on this machine, so they run here in CI under
the labels below. Reviewer note: core CI is label-gated, so this PR carries run tests,
run analysis and run e2e tests. Without them only typos and psalm would run.

Manual QA note

The front end serves the combined js/frm.min.js, which is rebuilt from js/formidable.min.js
only by FrmAppHelper::save_combined_js() (called from FrmMigrate and FrmAddon). When testing
this by hand, delete js/frm.min.js or set SCRIPT_DEBUG, otherwise a stale combined file will
serve the old regex and the fix will look like it did nothing.

Deliberately not fixed here

These are pre-existing and adjacent, left out to keep the change narrow. Each is a separate
behaviour decision, and they are grouped into a follow-up issue rather than lost:

  • Underscore in the host is rejected.
  • IPv6 literals are rejected.
  • ftp:, mailto:, news:, feed: and telnet: are rejected by the format check even though the
    scheme allowlist a few lines above explicitly admits them - a real internal contradiction.
  • Garbage such as https://-.- and https://.... passes, so this check was never a strong quality
    gate in the first place.

Help Scout ticket 257002.

Summary by CodeRabbit

  • Bug Fixes

    • URL fields now accept valid internationalized domain names, including domains containing accented or other non-ASCII characters.
    • Existing HTTP, HTTPS, and localhost validation rules remain supported.
    • Improved validation continues to reject malformed domains, dotless hostnames, invalid paths, and unsupported URL formats.
  • Tests

    • Added coverage for internationalized domains and consistency between browser and server-side URL validation.

The host pattern in FrmFieldUrl::validate() and its twin in checkUrlField()
allowed ASCII only, so valid internationalized domains were rejected. The
punycode spelling of the same domain already passed, and non-ASCII in the
path, query and fragment already passed, so this removes an inconsistency
rather than granting anything new.

The two character ranges differ by design. PHP matches UTF-8 bytes, so it
uses the raw byte range; JS matches UTF-16 code units, so it needs the code
unit range. Copying one literal into both would accept Cyrillic and CJK hosts
server side while silently rejecting them in the browser, so a test asserts
the two JS files carry the code unit form and never the PHP one.

The /u modifier is deliberately not added to the PHP pattern: preg_match()
returns false on invalid UTF-8, and because the result is negated that would
report valid Latin-1 input as invalid.

Sanitizing, escaping, storage and the scheme allowlist are untouched. The new
pattern was compared byte for byte with the old one across 1408 ASCII inputs
with no difference, so no ASCII url changes behaviour.

Help Scout ticket 257002.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@NathanaelJonesIreland, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 7 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ab00dd25-b73c-44c6-b216-8475e97534a9

📥 Commits

Reviewing files that changed from the base of the PR and between cf3f6c8 and df88b2d.

⛔ Files ignored due to path filters (1)
  • js/formidable.min.js is excluded by !**/*.min.js
📒 Files selected for processing (3)
  • js/formidable.js
  • tests/cypress/e2e/Forms/fieldsInFormBuilder.cy.js
  • tests/phpunit/fields/test_FrmFieldValidate.php

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a26a14d5-a247-4d76-b851-e35d56d60d64

📥 Commits

Reviewing files that changed from the base of the PR and between 3b3bf52 and cf3f6c8.

⛔ Files ignored due to path filters (1)
  • js/formidable.min.js is excluded by !**/*.min.js
📒 Files selected for processing (4)
  • classes/models/fields/FrmFieldUrl.php
  • js/formidable.js
  • tests/cypress/e2e/Forms/fieldsInFormBuilder.cy.js
  • tests/phpunit/fields/test_FrmFieldValidate.php

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

URL validation now accepts non-ASCII characters in hostnames in PHP and JavaScript. Tests cover internationalized domains, malformed URLs, raw Latin-1 host bytes, regex parity, and form-builder validation behavior.

Changes

Internationalized URL validation

Layer / File(s) Summary
URL validation rules and unit coverage
classes/models/fields/FrmFieldUrl.php, js/formidable.js, tests/phpunit/fields/test_FrmFieldValidate.php
PHP and JavaScript hostname patterns accept non-ASCII characters. PHPUnit coverage validates internationalized domains, malformed URLs, raw Latin-1 host bytes, and parity between JavaScript artifacts.
Form builder validation flow
tests/cypress/e2e/Forms/fieldsInFormBuilder.cy.js
The Cypress test rejects a dotless internationalized hostname and accepts https://ernährung.ch with JavaScript validation enabled.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to cf3f6

This localized change expands URL validation to support internationalized domain names while preserving existing sanitization and scheme checks; no actionable merge-blocking risk remains beyond normal checks and review.

Suggested reviewers: crabcyborg

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: accepting internationalized domain names in Website/URL fields.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/url-field-idn-support

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@NathanaelJonesIreland NathanaelJonesIreland added run tests run analysis run e2e tests Run the Cypress end-to-end suite on this PR labels Aug 19, 2026
@deepsource-io

deepsource-io Bot commented Aug 19, 2026

Copy link
Copy Markdown

DeepSource Code Review

We reviewed changes in 3b3bf52...df88b2d on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

Important

Some issues found as part of this review are outside of the diff in this pull request and aren't shown in the inline review comments due to GitHub's API limitations. You can see those issues on the DeepSource dashboard.

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
PHP Aug 19, 2026 9:27a.m. Review ↗
JavaScript Aug 19, 2026 9:27a.m. Review ↗

Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.

Comment thread js/formidable.js Outdated
Comment thread tests/cypress/e2e/Forms/fieldsInFormBuilder.cy.js Outdated
Comment thread tests/cypress/e2e/Forms/fieldsInFormBuilder.cy.js Outdated
Comment thread tests/cypress/e2e/Forms/fieldsInFormBuilder.cy.js Outdated
Comment thread tests/cypress/e2e/Forms/fieldsInFormBuilder.cy.js Outdated
// Byte range by design, and no /u modifier: with /u, preg_match() returns false on invalid UTF-8.
if ( $value && ! preg_match( '/^http(s)?:\/\/(?:localhost|(?:[\da-z\x80-\xff\.-]+\.[\da-z\x80-\xff\.-]+))/i', $value ) ) {
$errors[ 'field' . $args['id'] ] = FrmFieldsHelper::get_error_msg( $this->field, 'invalid' );
} elseif ( $this->field->required == '1' && ! $value ) { // phpcs:ignore Universal.Operators.StrictComparisons

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cannot access property $required on array|int|object


The property you are trying to access is not defined and will cause unexpected behavior when used.

@@ -183,6 +198,108 @@ public function test_url_value() {
$this->assertArrayHasKey( 'field' . $field->id, $errors, 'http:// passed required validation ' . print_r( $errors, 1 ) );

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call to an undefined method test_FrmFieldValidate::assertArrayHasKey()


The method you are trying to call is not defined, which can result in a fatal error.

* @covers FrmFieldUrl::validate
*/
public function test_url_idn_validation() {
$field = $this->factory->field->get_object_by_id( $this->get_field_key( 'url' ) );

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Access to an undefined property test_FrmFieldValidate::$factory


The property you are trying to access is not defined and will cause unexpected behavior when used.

*/
public function test_url_idn_validation() {
$field = $this->factory->field->get_object_by_id( $this->get_field_key( 'url' ) );
$this->assertNotEmpty( $field );

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call to an undefined method test_FrmFieldValidate::assertNotEmpty()


The method you are trying to call is not defined, which can result in a fatal error.


foreach ( $should_pass as $url ) {
$errors = $this->check_single_value( array( $field->id => $url ) );
$this->assertArrayNotHasKey( 'field' . $field->id, $errors, 'A valid url failed validation: ' . $url );

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call to an undefined method test_FrmFieldValidate::assertArrayNotHasKey()


The method you are trying to call is not defined, which can result in a fatal error.

$contents = file_get_contents( $file );
$name = basename( $file );

$this->assertStringContainsString( '\u0080-\uFFFF', $contents, 'The JS host pattern is missing the code unit range in ' . $name );

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call to an undefined method test_FrmFieldValidate::assertStringContainsString()


The method you are trying to call is not defined, which can result in a fatal error.

$name = basename( $file );

$this->assertStringContainsString( '\u0080-\uFFFF', $contents, 'The JS host pattern is missing the code unit range in ' . $name );
$this->assertStringNotContainsString( '\x80-\xff', $contents, 'The PHP byte range was copied into ' . $name . '. JS matches UTF-16 code units, so that would reject the Cyrillic and CJK hosts the server accepts.' );

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call to an undefined method test_FrmFieldValidate::assertStringNotContainsString()


The method you are trying to call is not defined, which can result in a fatal error.


$this->assertStringContainsString( '\u0080-\uFFFF', $contents, 'The JS host pattern is missing the code unit range in ' . $name );
$this->assertStringNotContainsString( '\x80-\xff', $contents, 'The PHP byte range was copied into ' . $name . '. JS matches UTF-16 code units, so that would reject the Cyrillic and CJK hosts the server accepts.' );
$this->assertStringNotContainsString( '[\da-z\.-]', $contents, 'The old ASCII-only host class is still present in ' . $name );

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call to an undefined method test_FrmFieldValidate::assertStringNotContainsString()


The method you are trying to call is not defined, which can result in a fatal error.


// The host class in the source must appear verbatim in the minified artifact.
$matched = preg_match( '/\[\\\\da-z[^\]]*\]/', file_get_contents( $source ), $matches );
$this->assertSame( 1, $matched, 'Could not find the url host class in js/formidable.js' );

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call to an undefined method test_FrmFieldValidate::assertSame()


The method you are trying to call is not defined, which can result in a fatal error.

// The host class in the source must appear verbatim in the minified artifact.
$matched = preg_match( '/\[\\\\da-z[^\]]*\]/', file_get_contents( $source ), $matches );
$this->assertSame( 1, $matched, 'Could not find the url host class in js/formidable.js' );
$this->assertStringContainsString( $matches[0], file_get_contents( $minified ), 'js/formidable.min.js is stale. Rebuild it so it carries the same url host class as js/formidable.js.' );

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call to an undefined method test_FrmFieldValidate::assertStringContainsString()


The method you are trying to call is not defined, which can result in a fatal error.

PHPCS: two assertion messages in test_FrmFieldValidate.php exceeded the
180 character limit (SlevomatCodingStandard.Files.LineLength). Shortened
them; the detail they carried is already in the method docblocks.

DeepSource JS-0117 wanted the u flag on the JS host pattern, which uses
unicode escapes. Adding it required widening the class to a code point
range, since under the u flag the old code unit range would no longer
match astral characters that the PHP side accepts as bytes. Verified in
node: the u variant is identical to the previous one on all 15 sample
urls and across 640 generated ASCII cases, and an astral host still
matches, so PHP and JS stay in step.

DeepSource JS-R1004: four backtick strings in the new Cypress block had
no interpolation. Converted to plain strings.

The parity test needle and the explanatory comment were updated to match
the new JS form. The PHP pattern deliberately still has no u modifier,
because preg_match() returns false on malformed UTF-8 and the negated
result would report valid Latin-1 input as invalid.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@NathanaelJonesIreland

Copy link
Copy Markdown
Author

CI status: 18 green, 2 red, and neither red one comes from this PR

Green, including the parts that matter here: PHPUnit on PHP 7.4/WP 6.9 and PHP 8/WP 6.9, PHPCS,
PHPStan, Psalm, Mago, ESLint, Oxlint, PHP CS Fixer, Rector, Stylelint, Spell Check, DeepSource:
JavaScript, DeepScan, Scrutinizer, CodeRabbit.

The new Cypress case passed:

✓ should accept an internationalized domain name in a Website/URL field (8398ms)
Spec Ran: Forms/fieldsInFormBuilder.cy.js  (green)

That is the end-to-end proof that the committed js/formidable.min.js was actually rebuilt, since
wp-env activation regenerates js/frm.min.js from it.


Red 1 — Cypress admin-html-validation.cy.js: no-dup-id, Duplicate ID "frm_connect_with_oauth" at #frm_strp_settings_container > div:nth-child(2) > a, on the global
settings page.

That ID lives in stripe/views/settings/connect.php:30 and stripe/js/connect_settings.js:5, both
untouched here — this PR changes five files, none of them under stripe/.

Worth flagging separately: Cypress has never actually run on master. Every historical run shows
skipped, because the gate added in #3254 reads
github.event.pull_request.labels, which is null on push events, and the run e2e tests label
did not exist in this repo at all until I created it to label this PR. So there is no green baseline
to compare against, and this appears to be the first Cypress execution on any PR since the gate
landed. The duplicate ID looks like a genuine pre-existing HTML-validity and accessibility bug in
the Stripe Connect settings view (the anchor is rendered in two sibling containers) rather than
anything to do with URL fields. Happy to open a separate issue for it if useful — flagging rather
than silently folding it into this PR.

Red 2 — DeepSource: PHP. All of the reported findings are pre-existing lines that DeepSource
cannot resolve, not defects introduced here. Checked individually against origin/master:

  • Call to an undefined method assertEmpty()/assertNotEmpty()/assertArrayHasKey() at lines 58, 76,
    78, 183, 198 — every one of those lines is unchanged master code. DeepSource is not resolving
    PHPUnit's TestCase base class.
  • Access to an undefined property $factory at lines 16, 20, 145, 155, 170 — also unchanged master
    code; $factory comes from the WP test-case base class.
  • Cannot access property $required on array|int|object at FrmFieldUrl.php:89 — this is the
    pre-existing } elseif ( $this->field->required == '1' ... line, byte-identical to master's line
    88. It only moved down one line because the fix adds a comment above it.

DeepSource: JavaScript went green after this PR's second commit, which addressed the two findings
that genuinely were mine (JS-0117 wanted the u flag; JS-R1004 flagged four backtick strings
with no interpolation).

@NathanaelJonesIreland

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@NathanaelJonesIreland

Copy link
Copy Markdown
Author

Housekeeping so the review queue reflects reality.

Resolved 5 DeepSource threads — all raised against the first commit (cf3f6c8) and all genuinely
fixed in df88b2d. GitHub already marked each of them outdated, and DeepSource: JavaScript is
now success on the head commit. For the record, rather than just taking the check's word for it:

Thread Finding Current state
js/formidable.js:546 JS-0117, use the u flag Pattern is now …/iu with a code point range
fieldsInFormBuilder.cy.js:258 JS-R1004, needless template string now 'li[id="text"] a[title="Text"]'
fieldsInFormBuilder.cy.js:259 JS-R1004 now 'li[id="url"] a[title="Website/URL"]'
fieldsInFormBuilder.cy.js:280 JS-R1004 now '[id^="frm_error_field_"]'
fieldsInFormBuilder.cy.js:290 JS-R1004 now '[id^="frm_error_field_"]'

Worth noting on JS-0117 specifically: adding u was not purely cosmetic. Under the u flag the
previous code unit range would have stopped matching astral-plane characters that the PHP side
accepts as bytes, which would have introduced a fresh server-accepts / client-rejects split — the
exact bug class this PR fixes. So the range was widened to a code point range at the same time,
and verified in node as identical to the previous behaviour across 640 generated ASCII cases with
astral hosts still matching.

Left the 16 DeepSource PHP threads open deliberately. They are false positives, but they are not
mine to dismiss and a reviewer should see them. The decisive evidence is that PHP 7.4 tests in WP 6.9 and PHP 8 tests in WP 6.9 both pass: a suite cannot pass while calling undefined methods,
so Call to an undefined method assertNotEmpty() cannot be true. DeepSource is not resolving
PHPUnit's TestCase, which is also why it reports the same error on line 198 — untouched master
code. Similarly FrmFieldUrl.php:89 is master's line 88 verbatim, moved down one line by the added
comment.

If the team wants those silenced repo-wide, excluding tests/** from the PHP analyzer in
.deepsource.toml would do it, but that is a policy call rather than something to fold into this PR.

Filed Strategy11/formidable-pro#6568 for the pre-existing duplicate-ID failure in the Stripe Connect settings view that
this PR's Cypress run surfaced. It includes the root cause (the view is rendered once per mode with
hardcoded IDs) and a note that current behaviour is not broken, since the click handlers use
jQuery delegated events and derive mode from the [data-test-mode] ancestor.

@NathanaelJonesIreland

Copy link
Copy Markdown
Author

Babysit pass — nothing pushed, and no re-litigating the two triage comments above. One addition
only, because it answers the question a reviewer actually has to decide: can this merge with
DeepSource: PHP red?

The repo has already answered that twice, this month. Both of these merged on 2026-08-13 with
DeepSource: PHP failing and inline DeepSource threads open on the phpunit files they added:

PR DeepSource: PHP Open phpunit threads at merge
#3234 — Import nulls without fatal errors fail 6, on tests/phpunit/xml/test_FrmXMLHelper.php
#3235 — Make field create handle invalid input better fail 9, on tests/phpunit/fields/test_FrmField.php

Same finding class in both — Call to an undefined method assertX() and
Access to an undefined property $factory. So this is not a new judgement call about this PR; it is
what happens to every core PR that adds a phpunit test.

I also found the mechanical cause, which makes it unfixable from inside this diff rather than merely
a false positive. .deepsource.toml excludes **/vendor/**, so PHPUnit\Framework\TestCase is
invisible to the PHP analyzer. stubs.php does declare
WP_UnitTestCase extends WP_UnitTestCase_Base extends PHPUnit\Framework\TestCase, and phpstan.neon
and psalm.xml both load that file explicitly — which is exactly why PHPStan and Psalm are green
here while DeepSource is not. DeepSource has no equivalent stub setting, so every assert*() call in
all 78 phpunit test files is unresolvable to it. Nothing this PR can change; the fix is either a
stub path or a tests/** exclusion in .deepsource.toml, and that is a repo policy call.

Cypress is unchanged from the triage above: the sole failure is the pre-existing duplicate
frm_connect_with_oauth ID, now tracked as Strategy11/formidable-pro#6568. I re-read the log on the current head to confirm
it is byte-for-byte the same failure #3242 hits on an unrelated diff, which is the cleanest proof
available that it is master-side and not either PR's doing.

Still waiting on a human review — the only reviews on record are deepsource-io[bot] and
coderabbitai[bot], so this is not merging itself.

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

Labels

run analysis run e2e tests Run the Cypress end-to-end suite on this PR run tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants