Best practices for the use of the “cart fragments” API

Beginning with WooCommerce 7.8, we implemented a change that disables the cart fragments script from being enqueued on all page routes of a WooCommerce store by default. Responsible for updating the cart widget after a successful add-to-cart event, the script can cause performance issues on stores not using that functionality. Going forward the script will now only be enqueued if the Cart Widget is rendered in a view. Keep in mind that some themes (like Storefront) hard-code the widget into the theme’s templates so it is not always user-added.

This article provides a deeper overview of why this change was necessary and some suggested best practices (or recommendations) going forward.

What is the get_refreshed_fragments API or “cart fragments”?

WooCommerce cart fragments is a script that uses the WordPress admin-ajax API to update the cart without refreshing the page. The term get_refreshed_fragments refers to the handle the AJAX request is registered to as well as the callback that is invoked by the AJAX request triggered whenever there is a change to the Cart on the front end of the store (or on regular intervals).

If you look at the cart-fragments.js file, you can search for the string get_refreshed_fragments and discover that there are a few places where this script is invoked:

As you can see, there are a number of places where this AJAX call is invoked by the cart fragments script to keep the mini cart widget up to date.

Addressing Performance Issues

Prior to the change introduced in WooCommerce 7.8, the cart fragments script was enqueued on every page load in a WooCommerce even if the mini-cart widget wasn’t present on the page. This was less than ideal leading to unnecessary additional AJAX requests to the server. On heavily trafficked stores, this could severely impact the load on the server and the responsiveness of a site.

With the changes applied via WooCommerce 7.8, this impact is minimized to pages that have the Cart widget active, when third party scripts register cart-fragments as a dependency, or when explicitly enqueued in code. We’re still investigating safe ways we can reduce this performance hit for usage of cart-fragments across all stores while preserving backward compatibility but in the meantime, here are some suggested best practices for further reducing the impact of using this API.

Limit Cart Sync functionality to specific WooCommerce pages

Using the snippet below, you can limit the execution of the cart-fragments script to specific pages. Note, the cart-fragments.js file will still load, however, it won’t execute:

add_filter( 'woocommerce_get_script_data', function( $script_data, $handle ) {

     if ( 'wc-cart-fragments' === $handle ) {

         if ( is_woocommerce() || is_cart() || is_checkout() ) {

             return $script_data;

         }

        return null;

      } 

      return $script_data;

 }, 10, 2 );

Caveats:

  • If you have non-standard custom pages that have cart behaviour not satisfying the conditions for is_woocommerce(), the mini-cart widget won’t update as expected.
  • If you expose the mini-cart widget on every page of your site and also have server/page caching enabled for your store, it’s likely the mini-cart widget will not update to show the active cart contents for the shopper session on those cached pages.

Replace usage of the Mini-Cart Widget with the Mini-Cart Block

The Mini-Cart block has a number of built-in performance measures to optimize the scalability of the live cart functionality and does not use the cart fragments API. As a result, we definitely recommend developers of themes and plugins switch to using and implementing the Mini-Cart block for this functionality.

For block themes

If the store is using a block theme, this is as easy as either using one of the available WooCommerce header patterns from WooCommerce core as a replacement for the current theme’s header template part content or adding the Mini-Cart block to your theme’s active header template part.

For classic themes with widget areas

If your classic theme does not hard code the Mini-Cart widget in the theme file, and instead implements it via a widget area, you can replace the Mini-Cart widget with the Mini-Cart block. 

For classic themes with hardcoded mini-cart widget use.

The good news is that it’s possible to programmatically inject the Mini-Cart block into your theme to replace the Mini-Cart widget. While we’re still internally discussing our approach to rolling this out, I’ve done a proof of concept pull request for the Storefront classic theme that demonstrates replacing the Mini-Cart widget with the Mini-Cart block. 

Note, implementing something like this for a classic theme also exposes to users (via add_theme_support( ‘block-template-parts’ ) ) the ability to edit the Mini-Cart style and layout, which is an added feature/advantage over using the Mini-Cart widget.

Caveats

  • The Mini-Cart template part being exposed for classic themes that register support will only be available once this pull request in WooCommerce Blocks is merged (which is something we will be doing).
  • If you hardcode the Mini-Cart block into a classic theme template using do_blocks( '<!-- wp:woocommerce/mini-cart /-->' ), the block styling might need some additional tweaking via CSS. You can also pass in accepted attributes via the block syntax to modify its behaviour and styles. The best way to discover which attributes are available is to use modify the block configuration in a block theme and switch to the code view in the editor to copy and paste the block syntax.

Keep yourself in the loop!

This field is hidden when viewing the form
This field is hidden when viewing the form
This field is hidden when viewing the form


6 responses to “Best practices for the use of the “cart fragments” API”

  1. Dimitrios Avatar
    Dimitrios

    I would suggest not to drop mini-cart widget and try to improve its performance as well, as its still more extendable and easier to customise (via hooks or overrides) than mini cart block

    And also, a vast amount of e-commerce stores, has the mini cart on upper right. Not much of an improve on performance, as most WooCommerce pages would need a mini cart icon and functionality there.

    1. This is already on our radar. As I mentioned in the post:

      We’re still investigating safe ways we can reduce this performance hit for usage of cart-fragments across all stores while preserving backward compatibility

      So there are currently no plans to remove widgets or the cart-fragments API and we’re still looking at ways to make it more performant while still preserving its extensibility surface.

  2. Dave Loodts Avatar
    Dave Loodts

    It would be more awesome to see real live examples and screencast explanations of those switches instead of theoretical examples. All the proposed solutions aren’t working as we test it out.

    The most common issue after 7.8 is on the cart page itself. (yes, also in Storefront). Changing the content of the cart on a cart page has no influence on the mini-cart. However enqueing cart fragments fixes that, it results in these errors:

    Function wp_enqueue_script was called incorrectly. Scripts and styles should not be registered or enqueued until the wp_enqueue_scripts, admin_enqueue_scripts, or login_enqueue_scripts hooks. This notice was triggered by the wc-cart-fragments handle

    The other suggestion of dropping the widget in another place (for example footer) does not work on the cart page (for example on storefront themes).

    Although this is not a giant functionality issue (it’s no order blocking thing), i probably won’t update our customers stores untill i really have a proper solution for this. So, i hope WooCommerce is communicating more practical and hands-on about this cart-fragment change.

    1. The most common issue after 7.8 is on the cart page itself. (yes, also in Storefront). Changing the content of the cart on a cart page has no influence on the mini-cart

      This appears to be something that is intentional behaviour given these lines in WooCommerce core for the widget. As far as I can tell WooCommerce 7.8 didn’t change that behaviour at all.

      If you want the widget to show contents on Cart or Checkout pages, you can utilize the filter on that link to always return true.

      However enqueing cart fragments fixes that, it results in these errors:

      Function wp_enqueue_script was called incorrectly. Scripts and styles should not be registered or enqueued until the wp_enqueue_scripts, admin_enqueue_scripts, or login_enqueue_scripts hooks. This notice was triggered by the wc-cart-fragments handle

      That warning is expected if the wp_enqueue_script is invoked too early in the WordPress loading call stack. Assuming you’re trying to address the mini-widget behaviour you mentioned earlier, you could just use the filter I linked to instead.

      The other suggestion of dropping the widget in another place (for example footer) does not work on the cart page (for example on storefront themes).

      It does if the filter I linked to is used to include the cart page as a place where the widget is rendered (and in WC 7.8 where the cart-fragments script is enqueued).

  3. andreigoa Avatar
    andreigoa

    Hello! Don’t know for sure, if this is the right place to ask about the issue I met, but I’ll try…
    The Mini-Cart Block I used in the block theme is not refreshing its contents after I add the product to the cart using StoreAPI from the custom block I made using @wordpress/create-block. Googled deep to the bottom of the internet and can’t find any info about the possibility to fire some event after a product is added via AP to reload the mini-cart contents. Anyone can help me with this issue and point to the right direction?

  4. Hi

    Could you please provide a code or explanation to how to invoke this update programmatically for a custom plugin ( satisfying is_woocommerce() ) that manipulates cart data?

    The only way would be to add a REST api endpoint to the Store API?

    Thanks

Leave a Reply

Your email address will not be published. Required fields are marked *