Most WooCommerce themes show a cart icon in the header, but block themes, page builders and custom headers often do not. This snippet adds a WooCommerce cart icon with the cart item count as a shortcode you can put in a menu, a header template part or any block.
The icon links to the cart page, shows a small badge with the number of items, and updates without a page reload when a customer adds a product.
[woo_cart_button](the tag from the older version of this post keeps working)
The snippet
<?php
/**
* [woo_cart_button] - WooCommerce cart icon with the number of items, linked to the cart page.
* The count updates without a page reload when products are added or removed.
*/
add_shortcode( 'woo_cart_button', 'dpc_cart_button_shortcode' );
function dpc_cart_button_shortcode(): string {
if ( ! function_exists( 'WC' ) ) {
return '';
}
dpc_cart_button_assets();
return dpc_cart_button_html();
}
function dpc_cart_button_html(): string {
// WC()->cart is null in wp-admin, the block editor preview and REST requests.
$count = WC()->cart ? (int) WC()->cart->get_cart_contents_count() : 0;
$label = sprintf(
/* translators: %d: number of items in the cart. */
_n( 'Cart, %d item', 'Cart, %d items', $count, 'dpc' ),
$count
);
$badge = $count > 0
? '<span class="dpc-cart-button__count" aria-hidden="true">' . esc_html( number_format_i18n( $count ) ) . '</span>'
: '';
return sprintf(
'<a class="dpc-cart-button%1$s" href="%2$s" aria-label="%3$s">'
. '<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path d="M5.929 1.757a.5.5 0 1 0-.858-.514L2.217 6H.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h.623l1.844 6.456A.75.75 0 0 0 3.69 15h8.622a.75.75 0 0 0 .722-.544L14.877 8h.623a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1.717L10.93 1.243a.5.5 0 1 0-.858.514L12.617 6H3.383L5.93 1.757zM4 10a1 1 0 0 1 2 0v2a1 1 0 1 1-2 0v-2zm3 0a1 1 0 0 1 2 0v2a1 1 0 1 1-2 0v-2zm4-1a1 1 0 0 1 1 1v2a1 1 0 1 1-2 0v-2a1 1 0 0 1 1-1z"/></svg>'
. '%4$s</a>',
$count > 0 ? '' : ' is-empty',
esc_url( wc_get_cart_url() ),
esc_attr( $label ),
$badge
);
}
// Send the new button with every cart update, so the count changes without a reload.
add_filter( 'woocommerce_add_to_cart_fragments', 'dpc_cart_button_fragment' );
function dpc_cart_button_fragment( $fragments ) {
$fragments['a.dpc-cart-button'] = dpc_cart_button_html();
return $fragments;
}
/** CSS once per page, and only on pages that show the button. */
function dpc_cart_button_assets(): void {
if ( wp_style_is( 'dpc-cart-button', 'enqueued' ) ) {
return;
}
// WooCommerce 7.8+ no longer loads the cart fragments script on every page.
wp_enqueue_script( 'wc-cart-fragments' );
wp_register_style( 'dpc-cart-button', false, array(), '1.0' );
wp_enqueue_style( 'dpc-cart-button' );
wp_add_inline_style(
'dpc-cart-button',
'.dpc-cart-button{position:relative;display:inline-flex;align-items:center;justify-content:center;color:inherit;text-decoration:none}'
. '.dpc-cart-button__count{position:absolute;top:-8px;right:-10px;min-width:22px;height:22px;padding:0 4px;box-sizing:border-box;border-radius:11px;color:#fff;background:#000;font:12px/22px Arial,Helvetica,sans-serif;text-align:center}'
);
}
How it works
- The shortcode reads the item count from
WC()->cartand builds a link towc_get_cart_url(). When the cart is empty, the link gets the classis-emptyand no badge. - In wp-admin, the block editor preview and REST requests WooCommerce has no cart, and
WC()->cartisnull. The snippet then shows a count of 0. The older version read the count fromnullthere, which throws a PHP warning on every such request. woocommerce_add_to_cart_fragmentssends a fresh copy of the button with every cart update. WooCommerce swaps it in on the page, so the badge changes without a reload.- Since WooCommerce 7.8 the script that applies those updates (
wc-cart-fragments) is not loaded on every page any more. The shortcode loads it where the button is shown. - The URL, count and label are escaped. The
aria-labeltells screen readers how many items are in the cart, and the icon is hidden from them. - The CSS is added once, only on pages that show the button.
Add it with Scripts Organizer
In Scripts Organizer go to Code Blocks → Add New and give the block a name. Set Trigger location to Everywhere, tick PHP under Script location, paste the code into the PHP editor, edit the config and publish. Leave Action/Hook empty.
PHP, CSS and the fragment filter live in one block on purpose: the CSS is printed by the shortcode, so there is no separate Header part to set conditions for.
The same code also works unchanged in a small plugin or an mu-plugin.
Customise it
- Colours: change
color:#fff;background:#000in the CSS, or style.dpc-cart-button__countin your theme. - Hide the icon when the cart is empty: add
.dpc-cart-button.is-empty{display:none}to the CSS. - Show the total instead of the count: use
WC()->cart->get_cart_total()indpc_cart_button_html(); it returns HTML, so print it withwp_kses_post(). - In a classic menu: add a Custom Link and use a plugin that runs shortcodes in menus, or put the shortcode in a header template part.
Gotchas
- The classes changed from
cart-contentstodpc-cart-button. Several themes usea.cart-contentsfor their own header cart, and the older fragment replaced it. Update your custom CSS if it targeted the old classes. - On fully cached pages the count in the HTML can be out of date. The fragments script corrects it right after the page loads, so the badge may change once.
In the Scripts Organizer library Import it with one click from Scripts Organizer.