Skip to content

Experimental iAPI Mini Cart - Finish up features: min/max steppers, discount badges, empty mini cart contents, open drawer when add to cart #58716

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Jun 23, 2025

Conversation

samueljseay
Copy link
Contributor

@samueljseay samueljseay commented Jun 11, 2025

Changes proposed in this Pull Request:

Closes:

#58523
#58521
#58179
#58196

and has a workaround to solve #58673

Includes:

  • Min/max threshold when using steppers to inc/decrement quantities
  • Display discount badges for individual item and line item total discount
  • Support removing items entirely from cart via "remove item" link
  • Supprot block setting to open cart when items are added to cart (via event)
  • Support block setting to show total price alongside mini cart badge
  • Render "Start Shopping" button in empty mini cart contents block
  • Edit quantity via text input (also respect min/max)

How to test the changes in this Pull Request:

Test min/max threshold

  • Have a product with minimum quantity or maximum quantity set (The WooCommerce sample products has some products that fulfill this).
  • Add one of those products to cart via shop page
  • Open mini cart, use steppers to increase or decrease quantity to maximum.
  • Try to increment beyond maximum, note stepper is disabled
  • Also for minimum try the same thing

Test discount badge display

  • Have a product with a discount price set
  • Add some to cart
  • Open mini cart, see that there is a discount badge shown for the item's discount and also a discount badge shown for the total line item discount

Test removing item from cart entirely

  • Have multiple items of one kind in cart
  • Open mini cart
  • Click "Remove item" link
  • Item should be completely removed from mini cart

Test "open cart when adding" block setting

  • Go to theme/appearance > edit
  • Find and click on mini cart badge in the editor layout
  • In the block settings enable "open cart drawer when adding" setting
  • As shopper add a product to cart via shop page or other
  • See that the mini cart opens when the item is added

Test "display total price" block setting

  • Go to theme/appearance > edit
  • Find and click on mini cart badge in the editor layout
  • In the block settings enable "display total price" setting
  • As shopper add some items to cart, note that the total price is now displayed beside the mini cart badge

Test empty cart state

  • As shopper with empty cart open mini cart by clicking the badge
  • See correctly styled "no items in cart" and "continue shopping" button.
  • Click the button
  • see that it navigates to shop page

Changelog entry

  • Automatically create a changelog entry from the details below.
  • This Pull Request does not require a changelog entry. (Comment required below)
Changelog Entry Details

Significance

  • Patch
  • Minor
  • Major

Type

  • Fix - Fixes an existing bug
  • Add - Adds functionality
  • Update - Update existing functionality
  • Dev - Development related task
  • Tweak - A minor adjustment to the codebase
  • Performance - Address performance issues
  • Enhancement - Improvement to existing functionality

Message

Changelog Entry Comment

Comment

Add min/max, discount badge support to experimental interactivity API mini cart.

@github-actions github-actions bot added the plugin: woocommerce Issues related to the WooCommerce Core plugin. label Jun 11, 2025
@samueljseay samueljseay changed the title Experimental iAPI Mini Cart: Support min, max steppers. Display badges with total discounts. Experimental iAPI Mini Cart - Finish up features: min/max steppers, discount badges, empty mini cart contents, open drawer when add to cart Jun 13, 2025
@samueljseay samueljseay marked this pull request as ready for review June 13, 2025 09:14
Copy link
Contributor

github-actions bot commented Jun 13, 2025

Size Change: +3.52 kB (+0.06%)

Total Size: 5.84 MB

Filename Size Change
./plugins/woocommerce/client/blocks/build/woocommerce/mini-cart.js 5.98 kB +3.32 kB (+124.88%) 🆘

compressed-size-action

Copy link
Contributor

github-actions bot commented Jun 13, 2025

Test using WordPress Playground

The changes in this pull request can be previewed and tested using a WordPress Playground instance.
WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Test this pull request with WordPress Playground.

Note that this URL is valid for 30 days from when this comment was last updated. You can update it by closing/reopening the PR or pushing a new commit.

Copy link
Contributor

coderabbitai bot commented Jun 17, 2025

📝 Walkthrough

Walkthrough

This update enhances the WooCommerce mini-cart feature by introducing support for minimum and maximum values, discount badges, improved subtotal formatting, and refined interactivity. It includes new and refactored store actions and getters, updates to markup for accessibility and discount display, CSS for conditional visibility, and feature-flagged rendering logic.

Changes

Files/Paths Change Summary
plugins/woocommerce/changelog/58716-dev-min-max-discount Added changelog entry documenting support for min/max values and discount badges in the experimental mini-cart feature.
plugins/woocommerce/client/blocks/assets/js/base/components/cart-checkout/product-badge/style.scss
plugins/woocommerce/client/blocks/assets/js/base/components/product-price/style.scss
Added CSS rules to hide product badge and price elements when the hidden attribute is present.
plugins/woocommerce/client/blocks/assets/js/base/stores/woocommerce/cart.ts Introduced a new removeCartItem action for optimistic UI updates and server sync when removing cart items.
plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts Refactored and extended mini-cart frontend store: added subtotal formatting, discount handling, min/max logic, new actions for quantity and removal, consolidated subtotal logic, and improved event-driven UI.
plugins/woocommerce/src/Blocks/BlockTypes/EmptyMiniCartContentsBlock.php Renamed and updated method for rendering empty mini-cart contents; added a wrapper div and new data attributes for interactivity.
plugins/woocommerce/src/Blocks/BlockTypes/MiniCart.php Updated rendering to extract and bind plain subtotal text, conditionally render subtotal and tax label, and register interactivity config. Returns empty string if no cart instance exists.
plugins/woocommerce/src/Blocks/BlockTypes/MiniCartFooterBlock.php Changed subtotal binding key to a fully qualified state reference for interactivity.
plugins/woocommerce/src/Blocks/BlockTypes/MiniCartItemsBlock.php Enhanced markup for discount display, added "Save" badge, improved quantity handling with min/max, and updated event bindings for item actions.
plugins/woocommerce/src/Blocks/BlockTypes/MiniCartShoppingButtonBlock.php Added feature-flagged rendering for the shopping button block, with a new method for experimental markup and dependency on feature detection.

Poem

Hop, hop, hooray! The mini-cart’s new,
Discounts and limits, all shiny and true.
Badges that sparkle, prices that hide,
With Dinero’s math, we take the ride.
From empty carts to shopping delight,
This bunny’s coding through day and night! 🐇✨


📜 Recent review details

Configuration used: .coderabbit.yml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f612ec8 and f52cd24.

📒 Files selected for processing (1)
  • plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts (7 hunks)
🧰 Additional context used
🧠 Learnings (1)
plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts (4)
Learnt from: samueljseay
PR: woocommerce/woocommerce#58716
File: plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts:83-101
Timestamp: 2025-06-17T07:07:53.443Z
Learning: In WooCommerce blocks, when porting existing code patterns that have known issues (like parseInt truncating decimal money values), maintain consistency with existing implementation rather than making isolated fixes. The preference is for systematic refactoring approaches (like broader Dinero adoption) over piecemeal changes.
Learnt from: samueljseay
PR: woocommerce/woocommerce#58716
File: plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts:132-149
Timestamp: 2025-06-17T07:07:01.287Z
Learning: The WordPress Interactivity API's wp-init directive automatically handles cleanup by calling any function returned from the init callback when the element is removed from the DOM. HTML directives cannot take complex JavaScript expressions.
Learnt from: samueljseay
PR: woocommerce/woocommerce#58716
File: plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts:132-149
Timestamp: 2025-06-17T07:07:01.287Z
Learning: The WordPress Interactivity API's wp-init directive automatically handles cleanup by calling any function returned from the init callback when the DOM element is removed from the DOM. The callback function can optionally return a cleanup function, and if it does, wp-init will automatically execute it during element removal. HTML directives in the Interactivity API cannot take complex JavaScript expressions.
Learnt from: samueljseay
PR: woocommerce/woocommerce#58716
File: plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts:78-96
Timestamp: 2025-06-18T06:05:25.472Z
Learning: In WooCommerce mini cart implementation, the cart state is server-populated before JavaScript initialization, so wooStoreState.cart and wooStoreState.cart.totals will be available on first render without requiring null-safe guards.
⏰ Context from checks skipped due to timeout of 90000ms (27)
  • GitHub Check: Blocks e2e tests 10/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 7/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 9/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 4/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 8/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 5/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 3/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 6/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 1/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 2/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Metrics - @woocommerce/plugin-woocommerce [performance]
  • GitHub Check: Core e2e tests 4/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core API tests - @woocommerce/plugin-woocommerce [api]
  • GitHub Check: Core e2e tests 1/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 2/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 6/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 5/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 3/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: PHP: 7.4 WP: latest - 1 [WP 6.7.2] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: JavaScript - @woocommerce/block-library [unit]
  • GitHub Check: PHP: 7.4 WP: latest - 1 [WP 6.7.2] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: PHP: 8.4 WP: latest [WP latest] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: PHP: 8.4 WP: latest [WP latest] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: Lint - @woocommerce/block-library
  • GitHub Check: Lint - @woocommerce/plugin-woocommerce
  • GitHub Check: Check Asset Sizes
  • GitHub Check: build
🔇 Additional comments (6)
plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts (6)

1-38: Well-organized imports and configuration setup

The consolidation of all configuration extraction at the top of the file is a good architectural improvement. The addition of Dinero.js for precise monetary calculations and the clean separation of imports by category makes the code more maintainable.


43-66: Comprehensive type definitions

The type definitions are well-structured and properly capture the store state and context interfaces. The addition of CartItemContext appropriately supports the new reactive cart item pattern.


80-172: Solid main store implementation with proper cleanup

The main mini-cart store is well-implemented. Key highlights:

  • The formattedSubtotal getter properly consolidates subtotal formatting logic that was previously duplicated
  • The setupOpenDrawerListener correctly returns a cleanup function as required by the WordPress Interactivity API
  • All getters follow consistent patterns and proper reactivity principles

Previous review concerns about memory leaks and decimal precision have been appropriately addressed.


174-415: Excellent reactive store implementation with robust cart item handling

This store implementation showcases several strengths:

  • Reactive cart item pattern: The cartItem getter properly addresses the wp-each reactivity issues mentioned in previous reviews
  • Precise monetary calculations: Consistent use of Dinero.js for discount calculations ensures accuracy
  • Robust input validation: The overrideInvalidQuantity action includes proper NaN handling as requested in previous reviews
  • Comprehensive getters: Well-structured getters for limits, discounts, and formatting with appropriate fallbacks
  • Proper async patterns: Actions correctly use generator syntax for cart operations

The implementation effectively balances functionality with maintainability.


417-432: Clean and focused counter store implementation

Simple, effective implementation for cart item counter text with proper singular/plural handling. The focused, single-purpose design is exactly what's needed here.


1-433: Excellent overall implementation of the mini-cart interactivity API

This file represents a high-quality implementation that successfully addresses the experimental mini-cart requirements. Key strengths include:

  • Comprehensive functionality: Supports min/max quantity limits, discount badges, and cart manipulation
  • Architectural soundness: Well-organized store separation with clear responsibilities
  • Best practices adherence: Proper WordPress Interactivity API patterns, including cleanup functions
  • Responsive to feedback: Previous review concerns have been thoughtfully addressed
  • Maintainable code: Consistent patterns, good TypeScript typing, and clear organization

The implementation effectively balances experimental feature requirements with production-ready code quality.

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🔭 Outside diff range comments (2)
plugins/woocommerce/src/Blocks/BlockTypes/MiniCartFooterBlock.php (2)

28-34: Subtotal calculation is wrong – get_subtotal_tax() returns tax, not “subtotal including tax”.

get_subtotal_tax() yields only the tax amount. To output the subtotal including tax you must add both values:

-        $subtotal                         = $display_cart_price_including_tax ? $cart->get_subtotal_tax() : $cart->get_subtotal();
+        $subtotal = $cart->get_subtotal();
+        if ( $display_cart_price_including_tax ) {
+            $subtotal += $cart->get_subtotal_tax();
+        }

Current code under-reports the subtotal (shows only tax!) whenever the “incl” option is active.


51-66: State namespace mismatch – formattedSubtotal is stored under the footer block but read from the mini-cart store.

wp_interactivity_state(
    $this->get_full_block_name(), // → woocommerce/mini-cart-footer-block
    [ 'formattedSubtotal' => $formatted_subtotal ]
);

Yet the markup binds to:

<span data-wp-text="woocommerce/mini-cart::state.formattedSubtotal">

Unless another component also puts formattedSubtotal into woocommerce/mini-cart::state, the span will render empty. Either:

  1. Move the state to the woocommerce/mini-cart namespace, or
  2. Revert the attribute back to woocommerce/mini-cart-footer-block::state.formattedSubtotal.

Please align the two to avoid broken UI.

🧹 Nitpick comments (6)
plugins/woocommerce/src/Blocks/Utils/BlocksSharedState.php (1)

8-8: Remove or use the newly-imported AssetDataRegistry.

AssetDataRegistry is imported but never referenced in this trait. Unused imports trigger PHPCS warnings and needlessly bloat the opcode cache.

-use Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry;

Either remove the line or actually leverage the registry here (e.g. for injecting shared data).

plugins/woocommerce/client/blocks/assets/js/base/components/cart-checkout/product-badge/style.scss (1)

11-13: Optional: add !important to guarantee hiding wins over block styles.

Several components inject inline display:inline rules at runtime. If that happens after this stylesheet loads, the selector loses. Appending !important guarantees the element is hidden whenever [hidden] is present.

-    display: none;
+    display: none !important;

Non-blocking; ignore if all consumers rely solely on the native [hidden] behaviour.

plugins/woocommerce/client/blocks/assets/js/base/components/product-price/style.scss (1)

19-21: Mirror the badge rule – consider !important.

Same reasoning as the badge CSS: a later inline style could override this display:none. Using !important would bullet-proof the hide logic.

-    display: none;
+    display: none !important;

Minor, feel free to skip if you are confident no competing inline styles exist.

plugins/woocommerce/src/Blocks/BlockTypes/EmptyMiniCartContentsBlock.php (1)

44-55: Minor formatting / a11y polish

Consider adding aria-hidden="true" to the outer wrapper when state.cartIsEmpty is false. This keeps assisted tech in sync with the hidden binding and matches the convention used elsewhere in Core blocks.

Purely optional – code functions as-is.

plugins/woocommerce/src/Blocks/BlockTypes/MiniCartShoppingButtonBlock.php (1)

42-60: Escape translated output

$start_shopping_label is user-facing text. Echo it with esc_html() to avoid edge-case XSS when translation files are compromised.

-   echo $start_shopping_label;
+   echo esc_html( $start_shopping_label );
plugins/woocommerce/src/Blocks/BlockTypes/MiniCartItemsBlock.php (1)

128-153: Button glyphs: consider accessible alternatives

The full-width + / - characters can be mis-pronounced by some screen-readers. Prefer SVG icons or a visually-hidden + / – with aria-labels already supplied.

Optional but improves a11y consistency.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 98703fd and 9310787.

📒 Files selected for processing (11)
  • plugins/woocommerce/changelog/58716-dev-min-max-discount (1 hunks)
  • plugins/woocommerce/client/blocks/assets/js/base/components/cart-checkout/product-badge/style.scss (1 hunks)
  • plugins/woocommerce/client/blocks/assets/js/base/components/product-price/style.scss (1 hunks)
  • plugins/woocommerce/client/blocks/assets/js/base/stores/woocommerce/cart.ts (5 hunks)
  • plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts (8 hunks)
  • plugins/woocommerce/src/Blocks/BlockTypes/EmptyMiniCartContentsBlock.php (1 hunks)
  • plugins/woocommerce/src/Blocks/BlockTypes/MiniCart.php (3 hunks)
  • plugins/woocommerce/src/Blocks/BlockTypes/MiniCartFooterBlock.php (1 hunks)
  • plugins/woocommerce/src/Blocks/BlockTypes/MiniCartItemsBlock.php (3 hunks)
  • plugins/woocommerce/src/Blocks/BlockTypes/MiniCartShoppingButtonBlock.php (2 hunks)
  • plugins/woocommerce/src/Blocks/Utils/BlocksSharedState.php (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
plugins/woocommerce/src/Blocks/BlockTypes/MiniCartItemsBlock.php (1)
Learnt from: mreishus
PR: woocommerce/woocommerce#58891
File: plugins/woocommerce/src/Blocks/Utils/BlocksSharedState.php:0-0
Timestamp: 2025-06-16T21:59:26.243Z
Learning: In WooCommerce's CartSchema::get_item_response() method, when called in the context of BlocksSharedState::register_cart_interactivity(), the method returns a plain array rather than a WP_REST_Response object, making it directly suitable for wp_interactivity_state() without needing to call ->get_data().
🧬 Code Graph Analysis (1)
plugins/woocommerce/src/Blocks/BlockTypes/MiniCart.php (2)
plugins/woocommerce/includes/wc-formatting-functions.php (1)
  • wc_price (567-640)
plugins/woocommerce/src/Blocks/BlockTypes/AbstractBlock.php (1)
  • get_full_block_name (79-81)
⏰ Context from checks skipped due to timeout of 90000ms (14)
  • GitHub Check: Blocks e2e tests 9/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core API tests - @woocommerce/plugin-woocommerce [api]
  • GitHub Check: Core e2e tests 1/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 2/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 3/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 4/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: PHP: 7.4 WP: latest - 1 [WP 6.7.2] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: JavaScript - @woocommerce/block-library [unit]
  • GitHub Check: PHP: 8.4 WP: latest [WP latest] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: PHP: 8.4 WP: latest [WP latest] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: Lint - @woocommerce/plugin-woocommerce
  • GitHub Check: Lint - @woocommerce/block-library
  • GitHub Check: Check Asset Sizes
  • GitHub Check: build
🔇 Additional comments (3)
plugins/woocommerce/src/Blocks/Utils/BlocksSharedState.php (1)

126-130: Defensive fallback for missing shop page.

wc_get_page_id( 'shop' ) may return 0, in which case get_permalink() returns false. Down-stream callers expecting a string URL will then receive false, potentially breaking JS that assumes a string.

-            'shopUrl'      => get_permalink( wc_get_page_id( 'shop' ) ),
+            'shopUrl'      => (string) get_permalink( wc_get_page_id( 'shop' ) ) ?: '',

Consider exposing an empty string (or omitting the key) when the shop page is not configured.

plugins/woocommerce/changelog/58716-dev-min-max-discount (1)

1-4: Changelog entry looks good.

Accurately summarises the patch; no action needed.

plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts (1)

178-184: Defensive check for undefined cart item

getCartItemById casts the result of .find() directly to CartItem. If the ID is missing it returns undefined, causing downstream crashes. Consider returning null or throwing early to aid debugging.

-	return wooStoreState.cart.items.find( ( item ) => item.id === id ) as CartItem;
+	return (
+		wooStoreState.cart.items.find( ( item ) => item.id === id ) ?? null
+	);

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts (1)

202-255: parseInt vs decimal amounts and extra convertPrecision calls

The discount calculations reuse the same truncating parseInt pattern and call convertPrecision on every getter access, which is expensive.

  1. Use parseFloat (or keep values in minor units).
  2. Cache the normalizedCurrency.minorUnit outside the getter to avoid repeated convertPrecision in tight loops (wp-each over items).

Example micro-refactor:

const parseAmount = (v:string) => Number.parseFloat(v);
const { precision } = prices.raw_prices;
const regular = Dinero({ amount: parseAmount(prices.raw_prices.regular_price), precision });
…

Not critical but improves correctness and avoids unnecessary CPU on carts with many items.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9310787 and 2624b8f.

📒 Files selected for processing (4)
  • plugins/woocommerce/client/blocks/assets/js/base/stores/woocommerce/cart.ts (5 hunks)
  • plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts (8 hunks)
  • plugins/woocommerce/src/Blocks/BlockTypes/MiniCart.php (1 hunks)
  • plugins/woocommerce/src/Blocks/BlockTypes/MiniCartItemsBlock.php (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • plugins/woocommerce/src/Blocks/BlockTypes/MiniCartItemsBlock.php
  • plugins/woocommerce/client/blocks/assets/js/base/stores/woocommerce/cart.ts
  • plugins/woocommerce/src/Blocks/BlockTypes/MiniCart.php
🔇 Additional comments (2)
plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts (2)

266-269: Good catch – cartItemMaximum now returns the correct limit.

This fixes the previous off-by-one bug and correctly caps the quantity input.


408-414: Guard against NaN – issue resolved.

The extra Number.isNaN check prevents corrupt cart quantities when the user enters non-numeric text.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
plugins/woocommerce/src/Blocks/BlockTypes/EmptyMiniCartContentsBlock.php (2)

18-24: DocBlocks still reference “Filled” rather than “Empty” mini-cart

Both DocBlocks were copied from the previous implementation and no longer describe the current behaviour, which can trip up IDEs and future maintainers.

- * Render the markup for the Filled Mini-Cart Contents block.
+ * Render the markup for the Empty Mini-Cart Contents block.- * Render the experimental interactivity API powered Filled Mini-Cart Contents block.
+ * Render the experimental interactivity-API powered Empty Mini-Cart Contents block.

Also applies to: 34-40


44-50: Consider mirroring the aria-hidden condition with an inert attribute for full accessibility

hidden removes the subtree from the accessibility tree, but focus can still be programmatically moved into it when the element is later shown. Adding inert (or tabindex="-1" on reveal) prevents accidental focus while the drawer is closed.

Not critical for functionality, but worth evaluating against WCAG focus-management guidelines.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2624b8f and 64380ff.

📒 Files selected for processing (4)
  • plugins/woocommerce/src/Blocks/BlockTypes/EmptyMiniCartContentsBlock.php (2 hunks)
  • plugins/woocommerce/src/Blocks/BlockTypes/MiniCartItemsBlock.php (4 hunks)
  • plugins/woocommerce/src/Blocks/BlockTypes/MiniCartShoppingButtonBlock.php (2 hunks)
  • plugins/woocommerce/src/Blocks/Utils/BlocksSharedState.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • plugins/woocommerce/src/Blocks/Utils/BlocksSharedState.php
  • plugins/woocommerce/src/Blocks/BlockTypes/MiniCartItemsBlock.php
  • plugins/woocommerce/src/Blocks/BlockTypes/MiniCartShoppingButtonBlock.php
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: Lint - @woocommerce/plugin-woocommerce
  • GitHub Check: Lint - @woocommerce/block-library
  • GitHub Check: Validate changelog
  • GitHub Check: build
  • GitHub Check: Check Asset Sizes

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts (1)

79-97: Repeated parseInt truncates fractional amounts – acknowledged pattern

The subtotal logic inherits the existing parseInt-based approach that drops decimal parts (e.g. "12.99"12). This is consistent with the rest of the Mini-Cart code and your earlier decision to postpone a Dinero-wide refactor.

No action required here.

🧹 Nitpick comments (1)
plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts (1)

411-417: Redundant branch after early NaN guard

parseInt( '' ) returns NaN, which is already caught by the isNaN check and early return. The additional else if ( qty === '' ) can never be reached.

-} else if ( qty === '' ) {
-    finalQuantity = minimum;
-}

Removing this dead code slightly simplifies the flow without changing behaviour.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 64380ff and 355c29d.

📒 Files selected for processing (3)
  • plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts (8 hunks)
  • plugins/woocommerce/src/Blocks/BlockTypes/MiniCart.php (1 hunks)
  • plugins/woocommerce/src/Blocks/BlockTypes/MiniCartShoppingButtonBlock.php (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • plugins/woocommerce/src/Blocks/BlockTypes/MiniCartShoppingButtonBlock.php
  • plugins/woocommerce/src/Blocks/BlockTypes/MiniCart.php
🧰 Additional context used
🧠 Learnings (1)
plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts (3)
Learnt from: samueljseay
PR: woocommerce/woocommerce#58716
File: plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts:83-101
Timestamp: 2025-06-17T07:07:53.435Z
Learning: In WooCommerce blocks, when porting existing code patterns that have known issues (like parseInt truncating decimal money values), maintain consistency with existing implementation rather than making isolated fixes. The preference is for systematic refactoring approaches (like broader Dinero adoption) over piecemeal changes.
Learnt from: samueljseay
PR: woocommerce/woocommerce#58716
File: plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts:132-149
Timestamp: 2025-06-17T07:07:01.274Z
Learning: The WordPress Interactivity API's wp-init directive automatically handles cleanup by calling any function returned from the init callback when the element is removed from the DOM. HTML directives cannot take complex JavaScript expressions.
Learnt from: samueljseay
PR: woocommerce/woocommerce#58716
File: plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts:132-149
Timestamp: 2025-06-17T07:07:01.274Z
Learning: The WordPress Interactivity API's wp-init directive automatically handles cleanup by calling any function returned from the init callback when the DOM element is removed from the DOM. The callback function can optionally return a cleanup function, and if it does, wp-init will automatically execute it during element removal. HTML directives in the Interactivity API cannot take complex JavaScript expressions.
⏰ Context from checks skipped due to timeout of 90000ms (19)
  • GitHub Check: JavaScript - @woocommerce/block-library [unit]
  • GitHub Check: Blocks e2e tests 10/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 5/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 9/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 3/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 6/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 1/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: PHP: 8.4 WP: latest [WP latest] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: Core e2e tests 2/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 2/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 5/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 3/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: PHP: 7.4 WP: latest - 1 [WP 6.7.2] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: PHP: 8.4 WP: latest [WP latest] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: PHP: 7.4 WP: latest - 1 [WP 6.7.2] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: Lint - @woocommerce/block-library
  • GitHub Check: Lint - @woocommerce/plugin-woocommerce
  • GitHub Check: build
  • GitHub Check: Check Asset Sizes
🔇 Additional comments (2)
plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts (2)

127-145: Listener setup / teardown looks solid

setupOpenDrawerListener now adds the wc-blocks_added_to_cart listener only when needed and correctly returns a cleanup function for automatic teardown by wp-init. Nice job preventing duplicate listeners and leaks.


260-267: Correct maximum limit retrieval

cartItemMaximum now correctly returns quantity_limits.maximum, fixing the earlier bug that exposed the minimum limit.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts (1)

341-352: Potential XSS via short_description innerHTML injection

Although WooCommerce generally filters product descriptions, relying on that sanitisation at this point is brittle.
Inserting HTML directly bypasses React/Interactivity API’s escaping and could open a hole if upstream filtering changes.

Consider:

  1. Whitelisting allowed tags with DOMPurify (already a WC dependency).
  2. Rendering the description server-side and passing the safe markup via block config.

Hardening this now avoids a class of future security bugs.
[security]

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 355c29d and 2a95412.

📒 Files selected for processing (1)
  • plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts (8 hunks)
🧰 Additional context used
🧠 Learnings (1)
plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts (3)
Learnt from: samueljseay
PR: woocommerce/woocommerce#58716
File: plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts:83-101
Timestamp: 2025-06-17T07:07:53.435Z
Learning: In WooCommerce blocks, when porting existing code patterns that have known issues (like parseInt truncating decimal money values), maintain consistency with existing implementation rather than making isolated fixes. The preference is for systematic refactoring approaches (like broader Dinero adoption) over piecemeal changes.
Learnt from: samueljseay
PR: woocommerce/woocommerce#58716
File: plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts:132-149
Timestamp: 2025-06-17T07:07:01.274Z
Learning: The WordPress Interactivity API's wp-init directive automatically handles cleanup by calling any function returned from the init callback when the element is removed from the DOM. HTML directives cannot take complex JavaScript expressions.
Learnt from: samueljseay
PR: woocommerce/woocommerce#58716
File: plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts:132-149
Timestamp: 2025-06-17T07:07:01.274Z
Learning: The WordPress Interactivity API's wp-init directive automatically handles cleanup by calling any function returned from the init callback when the DOM element is removed from the DOM. The callback function can optionally return a cleanup function, and if it does, wp-init will automatically execute it during element removal. HTML directives in the Interactivity API cannot take complex JavaScript expressions.
⏰ Context from checks skipped due to timeout of 90000ms (27)
  • GitHub Check: Blocks e2e tests 10/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 6/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 9/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 4/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Metrics - @woocommerce/plugin-woocommerce [performance]
  • GitHub Check: Blocks e2e tests 3/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 8/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 5/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 7/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core API tests - @woocommerce/plugin-woocommerce [api]
  • GitHub Check: Blocks e2e tests 2/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 4/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 2/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Blocks e2e tests 1/10 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 5/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 6/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 1/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: Core e2e tests 3/6 - @woocommerce/plugin-woocommerce [e2e]
  • GitHub Check: JavaScript - @woocommerce/block-library [unit]
  • GitHub Check: PHP: 8.4 WP: latest [WP latest] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: PHP: 7.4 WP: latest - 1 [WP 6.7.2] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: PHP: 8.4 WP: latest [WP latest] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: PHP: 7.4 WP: latest - 1 [WP 6.7.2] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
  • GitHub Check: Lint - @woocommerce/block-library
  • GitHub Check: Lint - @woocommerce/plugin-woocommerce
  • GitHub Check: Check Asset Sizes
  • GitHub Check: build
🔇 Additional comments (1)
plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts (1)

446-472: incrementQuantity / decrementQuantity bypass min/max limits

The actions blindly add ±1 and rely on the UI to disable the buttons.
Programmatic calls (or a future UI change) could exceed limits, producing 422 responses from the API.

-quantity: cartItem.quantity + 1,
+quantity: Math.min(
+    cartItem.quantity + 1,
+    cartItem.quantity_limits.maximum || Number.MAX_SAFE_INTEGER
+),

…and the symmetrical clamp for decrement.

Defensive coding here removes the need to trust every caller.

@samueljseay
Copy link
Contributor Author

@coderabbitai configuration

This was referenced Jul 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
plugin: woocommerce Issues related to the WooCommerce Core plugin.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants