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:
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_fragmentsfilter 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 asdiv.widget_shopping_cart_content; the function adds the counter next to it. ob_start()andob_get_clean()capture thespanmarkup 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 thewoocommerce_cart_contents_countfilter.
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 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-carthandles 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-fragmentsfetches 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:
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:
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().
Related articles
- building a full mini cart in the header: the same fragments filter for a complete item list
- adjusting the default mini cart template: when you want item details next to the count
- removing a product from the mini cart with AJAX: keeps the count right when items are removed
