Add a WooCommerce Cart Icon With Item Count Shortcode

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()->cart and builds a link to wc_get_cart_url(). When the cart is empty, the link gets the class is-empty and no badge.
  • In wp-admin, the block editor preview and REST requests WooCommerce has no cart, and WC()->cart is null. The snippet then shows a count of 0. The older version read the count from null there, which throws a PHP warning on every such request.
  • woocommerce_add_to_cart_fragments sends 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-label tells 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:#000 in the CSS, or style .dpc-cart-button__count in 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() in dpc_cart_button_html(); it returns HTML, so print it with wp_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-contents to dpc-cart-button. Several themes use a.cart-contents for 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.

// newsletter

Three tested WordPress snippets a week

Blocks, security, performance, Tailwind, PHP and React. Copy, paste, ship. You’ll also get DPlugins product updates. No spam, and you can unsubscribe anytime.

// newsletter

Three tested WordPress snippets a week

Blocks, security, performance, Tailwind, PHP and React. Copy, paste, ship. You'll also get DPlugins product updates. No spam, and you can unsubscribe anytime.