Skip to content

Sync master from upstream - #121

Merged
vanshk141999 merged 86 commits into
masterfrom
sync/master-20260819
Aug 19, 2026
Merged

vanshk141999 merged 86 commits into
masterfrom
sync/master-20260819

Conversation

@vanshk141999

Copy link
Copy Markdown
Collaborator

Sync master from upstream.

Upstream range: dc4caf48..c043bea3 (647 commits since the last sync merge-base)
Strip applied: yes — internal-only paths removed in a dedicated commit before the merge cap.

The branch is capped with a merge commit whose first parent is master on this repo, so the diff below shows only real upstream changes — no internal-file deletions. 61 files changed, +4510 / −1428.

Highlights

  • Release 2.12.4 (#3050, #3049) — version bump, changelog, README, translations
  • Add a "Finish setting up" dashboard card guiding new forms to completion (#3041)
  • Add a dashboard prompt to personalise a new form's Thank You message (#3040)
  • Add a "Form" option to the admin bar's "+ New" menu (#3047)
  • Add an admin-only "Edit Form" shortcut on embedded forms (#3039)
  • Upload email notification images to the Media Library instead of embedding base64 (#3037)
  • WordPress 7.1 compatibility: iframed block editor (#3043), form block preview modal (#3055), deprecated defaultProps removal (#3044)
  • Post-release review fixes and unit test coverage (#3054)
  • Updated translations (#3051)

vanshk141999 and others added 30 commits August 5, 2026 14:12
Adds a copy-only skill that rewrites the three readme.txt fields WordPress.org
search actually scores — title, short description, and Tags — grounded in the
plugin-directory ranking code. Dry-run by default; --apply writes changes after
title confirmation. Never touches versions, Stable tag, or quality signals, and
enforces wp.org limits (150-char short desc, 5 tags, no competitor trademarks).
… reference

Adds the two factors the ranking artifacts prove but the first draft missed:
- multi-word targets must be adjacent and early in the title (the factor that
  lets a 20k-install 2.7-star plugin outrank a 500k-install 4.9-star one for
  'contact form'), reflected in the analysis and title-rewrite steps
- verbatim function_score params for all six quality multipliers, so the skill
  can explain why a readme edit cannot move quality
Also documents slug hyphen-tokenization and the title.engram substring match.
feat: /sureforms:optimize-readme — wp.org search-ranking readme optimizer
…s base64

Images inserted via the Quill toolbar were stored as base64 data URLs
(data:image/...) which get stripped by wp_kses_post() on save, causing
the image to permanently disappear from the editor and sent emails.

Replace FileReader.readAsDataURL() with a POST to /wp/v2/media so the
image is uploaded to the WordPress Media Library and inserted as a real
https:// URL that survives wp_kses_post() sanitization.

Fixes #3036

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Renders a pill link into the form container that opens the block editor for
the form, shown only to users who can edit_post that form. It is absent from
the DOM (and its styles) for everyone else, so the layout and submission are
untouched for visitors. Works across block, shortcode, widget and single
embeds since all render through get_form_markup(); the scoped style prints
once per request.
…le (#3029)

Moves the admin Edit Form button from a top-right hover overlay to a centered, always-visible control below the form, per review feedback.
…ble (#3029)

Per the issue's UI spec: an Elementor/Beaver-Builder-style edit overlay at the top-right corner of the form container, always visible. Absolutely positioned so it never affects the form layout; still fully absent from the DOM for non-editing users.
…corner (#3029)

Per feedback: the pill fades in on form hover (and keyboard focus) and sits on the top-right corner of the container.
… (#3030)

Adds a dismissible dashboard prompt for the latest form still using the shipped default Thank You message, nudging the admin to customise it. Detection compares tag-stripped confirmation text against the default (robust to the icon-URL difference); the CTA deep-links into the editor with srfm_focus=thankyou; a per-form REST dismissal (edit_post re-checked) persists via _srfm_thankyou_prompt_dismissed, and the server only lists forms whose message is still default so it auto-clears once customised.
…tion (#3031)

Surfaces the latest form the user can edit that still has an unfinished setup step — no reply destination, the default thank-you message, or not embedded on a page — with a contextual sentence and a CTA per incomplete step (Edit form, Set where replies go, Edit the thank-you message, Add to a page). Dismiss and a 14-day snooze persist per form via post meta; the card auto-clears once every step is done since the server only lists incomplete forms. Embed detection is a bounded LIKE over published content.
… (#3030)

Restyles the prompt to the shared card treatment — a tinted icon square, title, description, and primary CTA — inside the dashboard's existing white-box card (rounded-xl, subtle border, soft shadow).
…card (#3030)

Adds Edit form + per-step CTAs (Set where replies go, Edit the thank-you
message, Add to a page) and the setup-context copy, showing only the steps a
form still needs (no reply destination, default thank-you, not embedded). Same
icon/white-box treatment as before.
… go" (#3030)

Removes the page-embed step (and its detection) and un-gates the reply-destination and thank-you links so both always appear beside Edit form.
…-link

The dashboard 'Finish setting up' card's 'Set where replies go' CTA now points
the editor at ?srfm_focus=ottokit so it lands on the OttoKit (Automations)
settings screen instead of Email Notification.

GeneralSettings snapshots the srfm_focus target at bundle-eval time because the
block editor strips unrecognised query args from the URL before a mount effect
can read them; a load-window poll then opens the form-settings dialog on the
target tab and forces the Force UI dialog overlay visible (its fade-in can stall
when toggled amid the editor's initial render churn).
The load-window poll re-dispatched the open event whenever the dialog panel was
absent, so closing it (✕ / Esc / backdrop) within that window immediately
reopened it. Track the dialog's own `isOpen` state via a ref: once it has
opened, halt the poll the moment it goes back to false — a deliberate close
flips state on the same live mount, whereas a load-time remount tears the effect
down and re-runs it fresh, so churn still reopens while a user close stays
closed.
Render the 'Finish setting up' checklist as a server-side widget on the main
WordPress dashboard instead of a React card on the SureForms dashboard, following
the existing AI-widget convention (markup in the render callback, CSS + behaviour
via wp_add_inline_style/script on empty-src handles, server values through
wp_localize_script) so it stays Plugin-Check clean.

- get_form_setup_card() now reports each step's completion (created, published,
  email, page) plus counts; includes drafts so 'publish' can be outstanding, and
  skips forms that are already fully set up.
- The email step is driven by is_default_email_notification(): a form ships with
  a default admin notification that get_post_meta returns even when untouched, so
  the step is done only once the recipient, subject or body is customised (or a
  second notification is added, or it is disabled).
- 'Set up email' deep-links to the Email Notification tab via GeneralSettings'
  srfm_focus handler (ported from #3030).
- 'Get embed code' reveals the [sureforms id] shortcode inline with copy.
- 'Remind me in two weeks' is a per-user snooze that hides the whole widget for
  14 days, not just the current form.
- Removes the superseded React FormSetupCard and its localization.
Render the 'Finish setting up' prompt as a native admin notice on the main
WordPress dashboard instead of a React card on the SureForms dashboard, matching
the plugin's dashboard-asset convention: markup in the render callback, CSS and
the dismiss handler via wp_add_inline_style/script on empty-src handles, and the
REST URL, nonce and form id passed through wp_localize_script.

- render_thankyou_prompt_notice() prints the notice (title, contextual sentence,
  Edit form / Set where replies go / Edit the thank-you message actions, and a ✕)
  only on the dashboard screen, for the newest editable form still needing setup.
- enqueue_thankyou_prompt_assets() styles it in the SureForms brand orange
  (#D54407): orange accent bar and primary button, borderless orange text actions.
- The ✕ reuses the existing dismiss-thankyou-prompt REST endpoint (per-form).
- get_thankyou_prompt_forms() is memoized so the enqueue and render passes share
  one query.
- Removes the superseded React ThankYouPrompt, its dashboard mount and its
  localization.
Drop the opacity:0 default and the container-hover / focus-visible reveal so the
admin-only Edit Form shortcut is always visible at the form's top-right corner.
The server-side current_user_can('edit_post') gate is unchanged, so the pill
stays absent from the DOM for non-editors.
…(#3029)

Review follow-ups for the admin-only Edit Form pill:

- Keep it out of shared full-page caches: the response now signals DONOTCACHEPAGE
  and nocache_headers() when the pill renders, and an explicit is_user_logged_in()
  guard pairs with it. get_form_markup() output is cache-friendly, so baking
  admin-only markup into it could otherwise be served to visitors by an
  auth-unaware cache. Docblock corrected to state the real invariant.
- Do not render on the single-form / Instant Form page (is_singular) or inside the
  block-editor REST preview (REST_REQUEST) — the form is the whole page / already
  being edited there, so the overlay is redundant.
- Add extensibility filters: srfm_show_edit_form_button (short-circuit) and
  srfm_edit_form_button_link (retarget).
- Accessibility: aria-label now contains the visible 'Edit Form' text (WCAG 2.5.3).
- Add test_render_edit_form_button covering capability gating (absent for anon /
  subscriber, present for admin), the once-per-request style dedup, and the
  suppression filter — restores the check-test-coverage gate.
…e forms (#3030)

- Render the 'Finish setting up' prompt through the bundled Astra Notices library
  (Astra_Notices::add_notice) instead of hand-rolled admin_notices markup + a
  custom REST dismiss endpoint. The per-form notice id gives per-form dismissal
  via the library's own dismiss control, so the dismiss REST route, its handler,
  the _srfm_thankyou_prompt_dismissed meta and the enqueue helper are removed.
- Show on every admin screen EXCEPT the main dashboard.
- Only for forms created from an Astra Sites starter template - gated on the
  _astra_sites_imported_post marker Astra Sites stamps on imported posts.
- Brand-orange styling (#D54407) printed via the astra_notice_before_markup_{id}
  hook, since the message is wp_kses_post'd; override the library's flex container
  so the title/text/actions stack, with tuned action spacing.
- Track clicks on all four actions (Edit form, Set where replies go, Edit the
  thank-you message, dismiss) through the shared srfm_notice_response endpoint +
  Analytics::events()->track, with a per-form-id prefix branch. Beacons use
  fetch keepalive so they survive the CTA navigation.
…rage (#3030)

Covers the seven admin.php functions the coverage gate flagged: the notice
registrar/styles/tracking methods and the reply-destination, default-confirmation,
prompt-query and first-form-created helpers.
- Strengthen the tests with real fixtures instead of type-only smoke assertions:
  is_default_confirmation_message (default message -> true, edited -> false),
  form_has_reply_destination (enabled+recipient -> true, disabled -> false), and
  get_thankyou_prompt_forms (an Astra Sites imported form is targeted, a
  non-imported one is not). These now fail if the detect/auto-clear/targeting
  logic is reverted.
- Bound the deep-link poll: once the dialog is open it holds the overlay painted
  for ~2s (the fade settles by then) instead of polling for the dialog's whole
  lifetime; pin the Force UI overlay-selector assumption in a comment.
- Make the notice sentence translator-friendly: use complete phrases per
  combination and drop the fragment-gluing join_clauses helper (its 3-clause
  branch was unreachable with only two steps).
- Add extensibility filters: srfm_show_thankyou_prompt (short-circuit) and
  srfm_thankyou_prompt_forms (re-scope the candidates).
- Correct the memoization docblock (only the render pass reads the cache).
- Relocate the two new private methods into the class's private-method cluster
  so PHP Insights' ordered-class-elements style check passes.
A starter-template import stores the default confirmation with a literal
apostrophe, while Global_Settings::get_default_confirmation_message() generates
it with the encoded &#39;. is_default_confirmation_message() only stripped tags,
so the two normalised strings differed and a genuinely-default imported form was
never detected — the notice never showed. Decode HTML entities during
normalisation so encoded and literal forms compare equal. Adds a regression test
covering the decoded-default case.
Style/dedup (H2): move the CSS off the function-static + inline <style> onto a
registered inline-only handle (wp_register_style false + wp_add_inline_style +
wp_enqueue_style). WP_Styles dedupes by handle, survives a discarded the_content
pass (e.g. an SEO plugin building og:description during wp_head, which used to
flip the static and throw the style away, leaving an unstyled pill), and passes a
strict style-src CSP.

Cache (H1): drop the DONOTCACHEPAGE / nocache_headers block — inert on the normal
headers-already-sent path and an irreversible process-global side effect from a
fragment renderer, for a payload an anonymous visitor cannot act on.

Contexts (H3): also skip page-builder editor canvases (Elementor edit mode,
Bricks builder), plus is_admin / wp_doing_ajax / wp_is_json_request / is_feed —
Elementor/Bricks call get_form_markup() directly (not over REST), where their own
edit handles collide with the pill.

Container (M3): only render when the .srfm-form-container actually opens (same
block-count guard), so a zero-block form no longer emits an orphaned, unpositioned
pill.

CSS (M4/M5): position the pill inside the box with a positive inset-inline-end
(no mobile horizontal overflow, RTL-correct), and scope the container
position:relative to the srfm-styling-none case so it never overrides a site's
own rule when default styling is on.

Guards & a11y: real-form post-type check (shortcode accepts any ID); capability
check before the suppression filter; coerce the link filter result and bail on
empty; drop the redundant is_user_logged_in and aria-label; add an
"(opens in a new tab)" screen-reader hint and a :focus-visible style.

Docblocks (M7): correct the two wrong claims — the editor preview is an iframe to
the form permalink suppressed by is_singular (not a REST render), and it is
admin-only via manage_options (map_meta_cap false), not per-post.

Tests (M1/M2/M6): assert the href is bound to THIS form and that a second form
links to its own editor; assert the stylesheet is enqueued by handle instead of
the vacuous style-count; add tear_down() to reset the current user and filters.
…(#3031)

- Move the SETUP_WIDGET_SNOOZE_USER_META constant into the class's constant
  section (ordered-class-elements style rule).
- Convert the widget markup's foreach/if alternative syntax to braces (the
  no-alternative-syntax quality rule).
- Add test methods for the nine flagged admin.php functions: the setup-card
  query, embed detection, default email-notification and confirmation detection,
  the REST dismiss handler, the widget register/render/enqueue methods, and the
  first-form-created flag.
Gate get_form_setup_card() on the _astra_sites_imported_post marker Astra Sites
stamps on imported posts, so the dashboard widget targets only forms created from
a starter template — matching the Thank You notice (#3030).
vanshk141999 and others added 29 commits August 18, 2026 19:44
- C-1 (merge fatal): move the #3030 tests into a dedicated Test_Thankyou_Prompt_Notice
  class so they no longer collide with #3041's test_is_first_form_created() in the
  shared Test_Getting_Started_Notice.
- H-1/H-2 (my B2 regression): the deep-link used the wrong getActiveComplementaryArea
  scope ('core/edit-post' instead of 'core'), so it never exited early and never
  switched away from the Block tab. Rewrote the editor-root loop to switch to the
  Document tab (correct 'core' scope) and stop on a direct deepLinkState.consumed
  signal set by GeneralSettings, instead of inferring from churning selectors —
  which also fixes M-1/M-2 (bounded, no preference-fighting). Verified live from the
  Block tab: switches to Document and opens the dialog.
- H-3: notice registers at priority 100 so it can't pre-empt higher-priority
  display-with-other-notices=false notices (e.g. Astra's version warnings).
- H-4/H-5: get_thankyou_prompt_forms() memo is now a resettable static property
  (+ reset_thankyou_prompt_cache()), so the render test asserts real positive and
  negative cases with proper preconditions and restores the shared registry.
- M-5: validate every payload key the markup reads, not just id/edit_url.
- M-7: assert the icon data-URI in the styles test.
- Lows: null screen fails closed; deep-link.js window guard fixed and the focus
  value resolved through the allowlist inside the module.

Deferred (noted on the PR): M-3 (Add-New dirty-on-mount), M-4 (negative query cache),
and the C-2 placement / AC#5 / AC#7 product decisions.
- B1: rename test_is_first_form_created → _reflects_stored_timestamp so it can't
  collide with #3040's same-named test on merge (coverage grep still matches).
- B2: bring the deep-link PHP producer (inc/gutenberg-hooks.php's srfm_focus
  inline script) into this PR so the JS consumer isn't shipped without it; the CTAs
  no longer fall through to the unreliable URL snapshot.
- B3 + testability: get_form_setup_card()'s memo is now a resettable static
  property (keyed per user) with reset_form_setup_card_cache() + an extracted
  private compute_form_setup_card(); the card/render tests now seed the trigger
  meta, reset, and assert the populated path UNCONDITIONALLY (no dead if/else).
- Re-synced all four deep-link JS files + gutenberg-hooks.php byte-identical to
  #3040, which carries the round-3 fixes (correct 'core' getActiveComplementaryArea
  scope, deepLinkState.consumed signal, Document-tab switch) — so the two PRs stop
  drifting and this branch inherits the H-1/H-2/M-1/M-2 fixes.
- Lows: REST 'action' enum paired with validate_callback (+required) so it's
  actually enforced; view_url omitted for draft/pending forms (get_permalink 404s);
  untitled form no longer renders a trailing space.

Deferred / product: completion logic + AC #2/#4/#5/#8, ✕ per-form dismiss (M4/AC#6),
the single-surface question, and target=_blank on the CTAs (kept per explicit
request; Adi suggests same-tab).
…textarea readOnly (TC-003/014), Helpers getBlocks store, quick-bar useSelect deps
…der (render identity), move DEFAULTS above (TDZ), onStatus optional
…age-prompt

Add a dashboard prompt to personalise a new form's Thank You message (#3030)
…eprecation

fix: replace deprecated defaultProps on function components (TC-009, TC-013)
fix: WP 7.1 iframed editor compatibility (TC-003/004/005/014/019/023)
Brings the PR up to date with dev (which now contains #3040). The only
conflict was admin/admin.php, where #3040's and #3041's methods were added at
the same anchors; resolved by keeping both PRs' members verbatim (both add
disjoint members — zero name overlap). test-admin.php and inc/rest-api.php
auto-merged. Verified: php -l, PHPCS, PHP Insights 100/100/100, PHPStan level 9,
and 13 setup-card/thankyou unit tests (49 assertions) all pass; every member
declaration is unique (no Cannot redeclare).
…#3031)

Two changes:

1. Hook registration lost in the dev merge. The merge rebuilt admin.php from
   dev's copy plus #3041's members, but the two constructor lines that wire the
   widget were only in #3041's constructor diff, so register_form_setup_widget()
   and enqueue_form_setup_widget_assets() were defined and never attached — the
   widget never rendered on the dashboard. Re-added next to the AI widget's hooks.

2. Snooze removed. The widget now shows only the fixed optional next-step CTAs;
   the per-user 14-day snooze that hid the whole widget is gone. Drops the button
   markup, its CSS and JS (including removeWidget), the SETUP_WIDGET_SNOOZE_USER_META
   const and its meta write, the compute_form_setup_card() snooze gate, and the
   'snooze' REST enum value. Tests and docblocks updated to match.

Verified: php -l, PHPCS, PHPStan level 9, PHP Insights 100/100/100, 13 unit tests
(46 assertions), and a live render (3 CTAs, no snooze markup).
…ecklist

Add a "Finish setting up" dashboard card to guide new forms to completion (#3031)
Auto-generated by /i18n command on PR #3050
Blocking:
- inc/rest-api.php: resolve Admin at dispatch instead of while get_endpoints()
  builds the route table. That runs on rest_api_init for every REST request, and
  plugin-loader only constructs Admin under is_admin(), so the front-end
  submit-form path was running Admin's constructor (40 hook registrations, an
  option read, the notices library, the wpforms_current_user_can filter).
  Verified: route-table build no longer instantiates Admin; dispatch still 200.
- readme.txt / README.md: add the four undocumented user-visible changes
  (#3026, #3029, #3030, #3031). README.md regenerated via 'grunt readme'.
- EditorToolbar.js: 413, 403, network failure and upload-succeeded-but-no-URL all
  ended at console.error, so an oversized photo looked like nothing happened.
  All four now surface via notify.error, using WP's message when the failure
  reached the REST API and generic copy when it did not.

Follow-ups taken:
- Gate both meta_query builders on ASTRA_SITES_VER. Starter Templates stamps the
  marker, so without it the query can never match; the Thank You one ran on
  every admin pageview.
- orderby tiebreaker [ date DESC, ID DESC ] on both queries — an import creates
  several forms in the same second, leaving 'newest' to MySQL.
- Replace the remaining '_astra_sites_imported_post' literals with
  Admin::ASTRA_SITES_IMPORT_META.
- aria-label now uses the $card_title fallback, so an untitled form no longer
  reads 'View  (opens in a new tab)'.
- Editor.js: check the complementary-area scope under both 'core' and
  'core/edit-post'. The area name is stable but the scope is not, and 6.4 is our
  declared minimum — checking only 'core' meant the early-exit never matched
  there, re-dispatching openGeneralSidebar 20 times over 6s.

PHPStan level 9, PHPCS, PHP Insights 100/100/100 and ESLint clean; build passes;
13/13 affected tests pass. The one wider failure
(Test_Rest_Api::test_forms_manage_args_required_and_enum) reproduces on
unmodified next-release.
Ports #3053 to next-release so these ship in 2.12.4. That PR merged into dev,
but the release ships next-release, so without this the fixes would slip a
release.

Byte-identical to #3053's merged result:
- Edit.js: clear the loader unconditionally (it sat behind the contentDocument
  guard, which is null on 7.1's cross-origin-isolated canvas, so the spinner
  never cleared), plus a 3s fallback, height over the srfm-preview-height
  postMessage, and guarded contentDocument reads.
- preview-styling.js: report height to the embedder, tolerance-guarded so the
  apply -> reflow -> report cycle cannot loop.
- Dialog.js: offset from the measured admin-bar height rather than inferred from
  fullscreen mode, which no longer hides the bar on 7.1.
- header-styles.scss: margin: 0 on .editor-header__back-button.

Verified the four files on next-release were identical to #3053's pre-image, so
this carries only that PR, and each result is byte-identical to a83be1e30.
ESLint and Stylelint clean; build passes with all three fixes in the bundles.

Note: the preview height path is still not fully confirmed on 7.1 — see the PR
description.
…view-modal-nr

fix: WP 7.1 editor regressions — form block preview and settings modal (port of #3053)
…x PHPCS

Addresses the re-review on #3054.

1. PHPCS was red and I reported it green. The inline
   /** @phpstan-ignore-next-line */ parsed as a doc comment with no short
   description (Generic.Commenting.DocComment.MissingShort). Now a line comment,
   which PHPStan honours just the same. My earlier check grepped colour-coded
   PHPCS output, so the ANSI codes between '|' and 'ERROR' meant the pattern
   never matched a real error — checking exit codes from here on.

2. The ASTRA_SITES_VER gate was wrong and I introduced it. Verified against the
   installed Starter Templates 4.7.4: the constant is defined in the main plugin
   file, so it only exists while the plugin is active, and neither uninstall.php
   nor astra_sites_deactivate() removes _astra_sites_imported_post — that hook
   only deletes a handful of options. So import-then-remove-the-importer left the
   marker on every form while both features silently stopped appearing, which is
   precisely the population they target.

   Replaced with the negative cache originally asked for: a transient set only
   when the marker query itself returns zero posts (a site-wide fact, not a
   per-user one), invalidated on added_post_meta/updated_post_meta for the marker
   key so a later import surfaces immediately rather than waiting a week. The
   invalidator narrows to SRFM_FORMS_POST_TYPE, since a full-site import stamps
   the marker on every post it creates. Both misleading comments rewritten.

3. Both cache branches are now testable, which the constant made impossible.
   The four tests no longer define ASTRA_SITES_VER; they clear the transient
   instead. test_negative_cache_short_circuits_the_marker_query covers the bail
   path, the populated path, invalidation on the marker key, and that an
   unrelated key leaves the cache alone. Revert-tested: it fails when the gate is
   disabled and passes when restored.

invalidate_starter_template_cache() reads its arguments via func_get_args()
because the hook passes ( $meta_id, $post_id, $meta_key ) and the meta id is
never used — declaring it tripped the unused-parameter sniff, and Insights runs
at --min-quality=100 in CI.

Verified by exit code this time: PHPCS 0, PHPStan 0, phpinsights -n
--min-quality=100 --min-architecture=100 --min-style=100 returns 0 with
100/100/100 project-wide. 14 affected tests pass (52 assertions).
check-test-coverage flagged invalidate_starter_template_cache(): the gate greps
for a test named after the function, and its behaviour was covered inside
test_negative_cache_short_circuits_the_marker_query() instead.

Split those assertions into test_invalidate_starter_template_cache() rather than
adding a stub to satisfy the grep, and added the case that was missing: the
marker on a non-form post must leave the cache alone, since a full-site import
stamps pages and products too and neither feature queries those.

Revert-tested — stubbing the post-type narrowing to 'if ( false )' fails the
test, and it passes restored. 15 affected tests pass (53 assertions); PHPCS,
PHPStan and phpinsights --min-quality=100 all return 0.
@vanshk141999
vanshk141999 merged commit db0c3aa into master Aug 19, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants