Release - #2978
Merged
Merged
Conversation
…m() (#2938) CSS_Handler::is_writable() called WP_Filesystem() before its function_exists() fallback, so a frontend request with an active sidebar and no generated widget stylesheet fataled with "Call to undefined function WP_Filesystem()" when the include did not expose the function. Run the guard first so the request degrades to the inline widget CSS fallback, and verify the initialized $wp_filesystem instance before reading its method. Adds an isolated-process PHPUnit regression test and a frontend e2e spec covering the blocked-filesystem fallback and the written-file path. Fixes #2937 Co-authored-by: Luca Dobrescu <luca.dobrescu@vertistudio.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
… context post (#2939) * fix: postContent dynamic tag reads the loop globals instead of its context post get_the_content() takes the post as its third argument; the context post ID was passed as the first one ($more_link_text), so $post stayed null and core fell back to the loop globals. When a theme or plugin leaves those globals clobbered, post-template.php warns "Undefined array key -1" (plus a preg_match() deprecation on PHP 8) and the tag renders empty. Fixes #2929 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test: cover the postContent recursion guard and isolate the e2e fixtures Addresses the Copilot review on #2939. The guard in mark_exceptions() is what the get_the_content() argument fix actually changes: it reads the context post's content to decide whether a nested postContent tag would recurse. Both mismatch cases are now covered - a nested tag in the context post must fire the guard, and a nested tag in the loop-global post must not blank a clean context post. The guard is asserted directly before rendering because an unfired guard makes apply_dynamic_content() recurse until the process dies, so the test has to fail fast instead of hanging. The e2e spec namespaced its Query Loop search token per run and now deletes its own post and page in afterAll. wp-env is persistent and the fixed token had already accumulated twelve records over six local runs, any of which the perPage:1 loop could resolve instead of the run's own post. Teardown is best-effort per record so one failed request cannot orphan the others. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Luca Dobrescu <luca.dobrescu@vertistudio.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…2956) * fix: frontend fatal when a listed class cannot be autoloaded Main::autoload_classes() instantiated every entry of its class list without checking that the class is loadable. On a package with a stale Composer classmap the Atomic Wind entry resolved to nothing and `new $classname()` threw an uncaught Error on `init`, taking down every request (#2954). Skip entries that are not loadable so a packaging or third-party filter problem degrades to a missing feature instead of a site-wide fatal. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: resolve the plugin's own classes when the Composer classmap is stale Composer exposes `inc/` through a generated classmap in `vendor/`, so a map that does not match the files on disk — an interrupted plugin update, an OPcache entry compiled from the previous version — makes a class that is present unloadable. Register a fallback loader for `ThemeIsle\GutenbergBlocks\*` that resolves a class from its file name. It is appended to the SPL stack, so Composer still answers first and the fallback only runs when Composer has no answer. The class then loads and its feature keeps working, instead of being skipped by the guard in Main::autoload_classes(). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: drop the fallback autoloader, log skipped classes instead Per review: a stale Composer classmap is an environment issue (broken or partial update) that fixes itself on reinstall, so keeping the class_exists() guard is enough. Remove inc/class-autoloader.php and its SPL registration — it locked us into the file-naming convention, added a second load path, and could hide a genuinely broken release. When the guard skips an unloadable entry it now logs it, so a lost feature is visible instead of silent. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Luca Dobrescu <luca.dobrescu@vertistudio.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…S parsing (#2958) * fix: fatal when another plugin loads a different php-css-parser release Base_CSS::get_animation_css() parsed the animation stylesheet with the bundled Sabberworm parser even when another plugin had already loaded classes from a different release of it. Mixing the two fatals at class-link time ("Declaration of CSSList::addComments... must be compatible") and that error is not catchable, so a guard now verifies every sentinel class resolves to Otter's own vendor directory before anything parser-related loads — including the transient read, which stores parser objects. When the guard fails, the full stock otter-animation stylesheet is enqueued instead, matching the optimize-off delivery path. Adds an isolated-process PHPUnit regression test and a frontend e2e spec covering both the foreign-parser fallback and the bundled-parser optimized path. Fixes #2942 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: serve the stock animation stylesheet from the frontend loader on parser collision Copilot review: the get_animation_css() fallback enqueue was lost once the generated post CSS was cached — later requests never reach the parser path, and the cached CSS carries no animation rules. Move the fallback delivery into Blocks_Animation::frontend_load(), which runs on every request that renders an animated block, and cover a cached-CSS reload in the e2e spec. Also delete the spec's probe posts in afterAll. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: reject any preloaded foreign Sabberworm symbol, not only the sentinels Copilot review: the parser touches more classes than the three sentinels (OutputFormat, DeclarationBlock, KeyFrame, and the cached object graph), so a foreign copy of any of them slipped past the guard and still mixed releases. has_own_css_parser() now first rejects every already-declared class, interface, or trait under Sabberworm\CSS that does not resolve to the bundled vendor directory — before the sentinel checks can autoload anything — and only then resolves the sentinel entry points. The sandbox gains an outputformat scenario covering a foreign non-sentinel class. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: match foreign Sabberworm declarations case-insensitively Copilot review (suppressed note): PHP class and namespace names are case-insensitive, so a foreign symbol declared with different casing is the same runtime class but slipped past the case-sensitive prefix scan. Use stripos so every colliding declaration is rejected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: trim animation-CSS collision comments to the load-bearing why Cut the verbose guard and preflight comments in Base_CSS and Blocks_Animation down to the constraint a reader cannot infer: the foreign-parser fatal is uncatchable, so the guard must run before any parser class loads. Also correct the has_own_css_parser() docblock to say it checks every loaded Sabberworm\CSS symbol, not only the ones the parser touches. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: log when a foreign php-css-parser release disables animation CSS The parser-collision guard silently served the stock animation stylesheet, so a conflicting Sabberworm release looked like the optimization had stopped working for no reason. Log the skip, mirroring the autoload-skip notice from #2956, so the cause is visible in the debug log. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Luca Dobrescu <luca.dobrescu@vertistudio.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…ducts (#2926) * fix: keep Meta Boxes pane open by default for WooCommerce Builder products Since WP 6.7 the iframed post editor renders meta boxes in a bottom drawer that is collapsed unless the user previously opened it. Otter 3.2.0 bumped all blocks to apiVersion 3, which switched WooCommerce Builder product edit screens to the iframed canvas, hiding the WooCommerce Product data panel (price, inventory, etc.) behind the collapsed drawer. Default the drawer to open on builder-enabled product screens via the preferences setDefaults API, which never overrides an explicit user choice. Closes #2822 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: rescue Product data metabox from the side column + e2e coverage The metabox Move-up/down arrows persist the order instantly and, at the edge of an area, relocate a box into the adjacent area. From the block editor (WooCommerce Builder products) one accidental click can strand woocommerce-product-data in 'side', where it renders inside the ~280px sidebar and its layout breaks. Correct it at read time via the get_user_option_meta-box-order_product filter. Adds Playwright coverage for the builder edit screen: drawer open by default, side-area rescue, classic-editor scoping for non-builder products, and explicit user preference winning over the new default. WooCommerce (latest stable) joins .wp-env.json; the e2e bootstrap gains product-creation and user-meta helpers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: address review, scope the rescue, and keep WooCommerce out of other suites - Add the missing void return type that failed PHPStan. - Scope restore_product_data_location() to builder-enabled products, so a layout saved on a classic product is left as the user arranged it. - Add PHPUnit coverage for both guards: the inline meta-boxes-pane default (present for builder products, absent for plain products and non-product posts) and the metabox-order rescue. - Mount WooCommerce as an inactive wp-env mapping from the copy composer already installs, and activate it only around the WooCommerce spec. Activating it for the whole environment changed editor load behavior and broke the performance suite. - Reset the shared admin user's drawer preference and metabox order in beforeEach as well as afterEach, so the first test is not skewed by state left behind by an earlier run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: load a single WooCommerce copy in the PHPUnit bootstrap Mounting WooCommerce at wp-content/plugins/woocommerce made the existing activate_plugin() call in the bootstrap resolve — it had been a silent no-op while that directory did not exist. activate_plugin() includes the plugin file through plugin_sandbox_scrape(), so WooCommerce was loaded via two different paths and PHP fataled on redeclaring the unguarded WC() and wc_get_container() functions, failing the suite with exit 255 before any test ran. Load the mounted copy when present so both includes resolve to the same path, keeping the vendor copy as a fallback. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: delete the products the WooCommerce spec creates Each test published a product and teardown only reset user metadata, so a reused wp-env gained four products per run and later product suites could run against that residue. Track the ids the spec creates and hard-delete exactly those in afterEach, while WooCommerce is still active so its product lookup tables are cleaned too. The endpoint ignores ids that are not products, so a stale id cannot remove unrelated content. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: restore the script registry after the WooCommerce Builder test Removing the dummy wp-edit-post handle in teardown left the shared $wp_scripts registry without WordPress's own registration, so later tests could fail depending on suite order. Discard the registry instead, which makes the next wp_scripts() call rebuild every default registration. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: run the suites against current WooCommerce The composer constraint is open but the lock still pinned 10.1.2 from a year ago, so mounting the Composer copy meant neither the new regression suite nor the PHPUnit bootstrap exercised current WooCommerce, and the pin also contradicted the php-stubs/woocommerce-stubs ^10.8 requirement. Refresh the lock to 10.9.4, the version the regression was reproduced on. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Marius Cristea <marius.cristea@vertistudio.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: pirate-bot <58979018+pirate-bot@users.noreply.github.com>
Contributor
Author
Bundle Size Diff
|
Contributor
Author
|
Plugin build for b749aa4 is ready 🛎️!
|
Contributor
Author
E2E TestsPlaywright Test Status: See serial and parallel matrix jobs Performance ResultsserverResponse: {"q25":439.31,"q50":474.11,"q75":478.3,"cnt":10}, firstPaint: {"q25":1633.63,"q50":1784.74,"q75":2035.54,"cnt":10}, domContentLoaded: {"q25":4245.71,"q50":4311.11,"q75":4329.22,"cnt":10}, loaded: {"q25":4249.26,"q50":4314.7,"q75":4332.93,"cnt":10}, firstContentfulPaint: {"q25":2813.23,"q50":3233.74,"q75":3253.22,"cnt":10}, firstBlock: {"q25":19869.26,"q50":19985.17,"q75":20097.71,"cnt":10}, type: {"q25":30.85,"q50":34.82,"q75":37.87,"cnt":10}, typeWithoutInspector: {"q25":28.04,"q50":30.54,"q75":32.21,"cnt":10}, typeWithTopToolbar: {"q25":41,"q50":43.78,"q75":48.83,"cnt":10}, typeContainer: {"q25":17.41,"q50":18.27,"q75":19.46,"cnt":10}, focus: {"q25":158.97,"q50":163.15,"q75":172.13,"cnt":10}, inserterOpen: {"q25":50.24,"q50":53.48,"q75":55.13,"cnt":10}, inserterSearch: {"q25":31.92,"q50":33.48,"q75":34.97,"cnt":10}, inserterHover: {"q25":5.48,"q50":5.74,"q75":6.34,"cnt":20}, loadPatterns: {"q25":2098,"q50":2148.82,"q75":2205.52,"cnt":10}, listViewOpen: {"q25":275.55,"q50":278.97,"q75":282.99,"cnt":10} |
Validated Stripe price ID before checkout
Contributor
Author
|
🎉 This PR is included in version 3.2.3 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Linked issues
This release will close the following issues once merged:
WP_Filesystem()is unavailable #2937Public changelog