How to Update the WooCommerce Header Cart Count With AJAX

Quick Summary

  • Return your counter's span from the woocommerce_add_to_cart_fragments filter, keyed by its CSS selector, and print the same span in header.php.
  • Since WooCommerce 7.8, wc-cart-fragments only loads with the Cart widget; enqueue it to refresh the count on cached pages and after cart page updates.
  • Block add to cart buttons don't send fragments, so listen for wc-blocks_added_to_cart; in block themes, the Mini-Cart block updates its own count.

A cart counter in your header should change as soon as a customer adds a product, without a page reload. In a classic theme, register the counter’s HTML with the woocommerce_add_to_cart_fragments filter and print the same element in header.php: after every AJAX add to cart, WooCommerce sends that HTML back with the new count and swaps it into the page. Since WooCommerce 7.8, the wc-cart-fragments script that also refreshes the count on page load and on the cart page is only loaded where the Cart widget is shown, so enqueue it yourself. In a block theme, use the Mini-Cart block instead; it updates its own count and doesn’t use fragments.

Step 1: register the fragment

Add this code to your child theme’s functions.php file:

PHP
add_filter( 'woocommerce_add_to_cart_fragments', 'wc_refresh_mini_cart_count' );
function wc_refresh_mini_cart_count( $fragments ) {
    ob_start();
    ?>
    <span class="number-of-product-in-store"><?php echo esc_html( WC()->cart->get_cart_contents_count() ); ?></span>
    <?php
    $fragments['.number-of-product-in-store'] = ob_get_clean();
    return $fragments;
}
  • The woocommerce_add_to_cart_fragments filter receives an array of fragments. Each key is a CSS selector, and each value is the HTML that replaces the matching element. WooCommerce’s own mini cart is already in the array as div.widget_shopping_cart_content; the function adds the counter next to it.
  • ob_start() and ob_get_clean() capture the span markup as a string instead of printing it.
  • WC()->cart->get_cart_contents_count() returns the total quantity of items in the cart. esc_html() escapes it, because other plugins can change the number through the woocommerce_cart_contents_count filter.

WooCommerce runs this filter when it answers an AJAX add to cart or remove from cart request, and when the fragments script asks for fresh fragments.

Step 2: print the counter in your header

Add this where the count should appear, usually in your theme’s header.php:

PHP
<?php if ( function_exists( 'WC' ) && WC()->cart ) : ?>
<span class="number-of-product-in-store"><?php echo esc_html( WC()->cart->get_cart_contents_count() ); ?></span>
<?php endif; ?>

This prints the current count when the page loads. The class must match the selector from step 1 (.number-of-product-in-store), because WooCommerce replaces the whole element, not just the number. If you rename the class, change it in both places. The function_exists() check keeps the header from breaking with a fatal error if WooCommerce is ever deactivated.

Step 3: load the cart fragments script

Two WooCommerce scripts swap fragments into the page:

  • wc-add-to-cart handles the AJAX add to cart buttons on shop and category pages. The add to cart request already returns the fragments, and this script replaces them, so the counter updates after those clicks with no extra code.
  • wc-cart-fragments fetches fresh fragments when the page loads (from the browser’s session storage when the cart hasn’t changed, otherwise with a request to ?wc-ajax=get_refreshed_fragments), after quantities change on the classic cart page, when the cart changes in another tab, and when a page comes back from the browser’s back button.

Until WooCommerce 7.8, wc-cart-fragments was loaded on every page. As WooCommerce explains in its post on the cart fragments API, it now loads only where the Cart widget is shown, because of the extra request it makes. Without it, a page served from a page cache shows whatever count was cached, and the counter doesn’t change when a customer updates the cart page. If your header counter needs those updates, enqueue the script from your theme:

PHP
add_action( 'wp_enqueue_scripts', 'nmh47_enqueue_cart_fragments' );
function nmh47_enqueue_cart_fragments() {
    wp_enqueue_script( 'wc-cart-fragments' );
}

WooCommerce registers wc-cart-fragments itself, so you only enqueue the handle; don’t copy the file into your theme.

What if products are added with block buttons?

The Product Button block and the Add to Cart + Options block add products through WooCommerce’s Store API. They don’t return fragments or trigger the jQuery added_to_cart event, so a fragments counter doesn’t notice. After a successful add, they dispatch a wc-blocks_added_to_cart event on the page. You can listen for it and ask the fragments script to refresh:

PHP
add_action( 'wp_enqueue_scripts', 'nmh47_enqueue_cart_fragments' );
function nmh47_enqueue_cart_fragments() {
    wp_enqueue_script( 'wc-cart-fragments' );
    wp_add_inline_script(
        'wc-cart-fragments',
        "document.addEventListener( 'wc-blocks_added_to_cart', function () {
            jQuery( document.body ).trigger( 'wc_fragment_refresh' );
        } );",
        'before'
    );
}

This replaces the function from step 3. wc_fragment_refresh is the event wc-cart-fragments listens to. The inline script goes 'before' the fragments script on purpose: WordPress won’t defer a script that has an inline script after it, and WooCommerce loads wc-cart-fragments with defer.

Block themes: use the Mini-Cart block

In a block theme you don’t edit header.php. Many block themes already have the Mini-Cart block in their header; if yours doesn’t, add it to the Header template part in Appearance > Editor. It shows a cart icon with the item count, updates without a page reload, and doesn’t use cart fragments at all. WooCommerce recommends it over the fragments API for this reason. See the Mini-Cart block documentation for its settings.

Why isn’t the cart count updating?

  • The selectors don’t match. The array key in step 1 and the class in step 2 must match, or WooCommerce has nothing to replace.
  • The add to cart button reloads the page. On shop and category pages the count only updates in place when Enable AJAX add to cart buttons on archives is on under WooCommerce > Settings > Products. In your own product loops, print the button with WooCommerce’s markup, as in adding AJAX add to cart buttons to a custom loop. On a classic single product page, the add to cart form submits and reloads the page, and step 2 prints the new count.
  • The count is right after adding but wrong on the next page. The page came from a page cache and the fragments script isn’t loaded. Add step 3.
  • Old fragments stay after you change the code. The fragments script keeps fragments in the browser’s session storage and reuses them while the cart is unchanged. Clear your page cache and test in a private window.
  • Products added with block buttons don’t change the count. Add the listener from the block buttons section.

Frequently asked questions

Does the counter show products or units?

Units. get_cart_contents_count() adds up quantities, so two of the same product count as 2. To count cart lines instead, use count( WC()->cart->get_cart() ) in both snippets.

Can I update the cart total the same way?

Yes. Add a second entry to $fragments with its own selector, and print WC()->cart->get_cart_subtotal() inside that element, both in the filter and in your header. It returns the subtotal as price HTML, so don’t wrap it in esc_html().

Share on X (opens in a new tab) Share on LinkedIn (opens in a new tab) Share on Facebook (opens in a new tab)

ChatGPT (opens in a new tab) Claude (opens in a new tab) Gemini (opens in a new tab) Perplexity (opens in a new tab) Grok (opens in a new tab)

More Insights

See More