Changing the WooCommerce Added to Cart Notice
The value handed to this filter is already HTML, and it already contains the View cart button. Escaping it the way you would escape a plain string deletes the only link on the notice.
The first argument is markup, not a sentence. woocommerce_add_to_cart_message_html passes a string that already contains an anchor to the cart wrapped around a button class. Treat it as text — run it through a plain escaping function, or replace it wholesale with your own wording — and the notice keeps working while quietly losing the only link on it.
The arguments
add_filter( 'woocommerce_add_to_cart_message_html', 'ti_cart_message', 10, 3 );
function ti_cart_message( $message, $products, $show_qty ) {
return $message;
}
| Argument | Type | What it holds |
|---|---|---|
$message |
string | The full notice, including the cart link markup |
$products |
array | Product ID mapped to quantity, for everything added in this request |
$show_qty |
bool | Whether quantities should be named in the wording |
Declaring three arguments is required to receive the second and third. Omitting the count leaves $products undefined, and the resulting warning is easy to miss because the notice still renders.
Changing the wording without losing the link
The safe shape keeps the original markup and adds to it, rather than rebuilding it:
add_filter( 'woocommerce_add_to_cart_message_html', 'ti_cart_message', 10, 2 );
function ti_cart_message( $message, $products ) {
if ( ! is_array( $products ) || count( $products ) !== 1 ) {
return $message;
}
$id = absint( array_key_first( $products ) );
$product = wc_get_product( $id );
if ( ! $product instanceof WC_Product ) {
return $message;
}
$added = sprintf(
/* translators: %s: product name */
esc_html__( '%s is in your basket.', 'your-textdomain' ),
esc_html( $product->get_name() )
);
return '<span class="ti-added">' . $added . '</span> ' . $message;
}
Two habits are doing the work here. The product name is escaped, because it comes from the database and a store with user-submitted product data cannot assume it is clean. The original $message is concatenated rather than discarded, so the cart link survives.
If you must replace the message entirely, rebuild the link yourself with wc_get_cart_url() and run the assembled string through wp_kses_post rather than esc_html, which strips every tag.
Why the notice sometimes never appears
The filter running and the notice displaying are separate events:
- AJAX add to cart on archives. With the option enabled, adding from a product grid updates cart fragments without a reload. There is no notice render on that request, so nothing is shown even though the message was built. This is the single most common reason the wording appears to be ignored.
- A redirect straight to the cart. The "redirect to cart after adding" option sends the shopper to the cart page, where the notice is displayed by a different template than the one they came from.
- A theme that does not print notices. A template missing the notices call renders no messages at all, anywhere. The tell is that error messages are missing too, not just this one.
- A page cache serving the previous HTML. Notices are per-session, and a cached page has none. Confirm the exclusion rules following clearing the WordPress cache.
Multiple products in one request
A grouped product submits several children at once, and $products then holds more than one entry. A callback written for a single item will either name the wrong product or produce wording that reads oddly for four. The guard in the snippet above handles this by returning the default for anything that is not exactly one product, which is a better outcome than a confidently wrong sentence.
The third argument, $show_qty, is true when quantities should appear. Honouring it matters most in the multi-item case, where "added to your basket" without counts leaves the shopper unsure what actually happened.
Verify in four places
Notices surface differently depending on where the add came from, so test all of these:
- The single product page with AJAX off, which is the classic full-reload path.
- A product grid with AJAX on, where you should expect no notice and the cart count to change instead — the same behaviour that governs product shortcodes.
- A grouped product with two children selected, checking the wording holds up.
- A second add of the same product, confirming the quantity wording is right.
If the notice renders but the cart total does not move, the message is not the problem and the trail starts at products not showing in the cart instead.
Frequently asked
- Because the filter receives HTML and your callback returned a plain string. The button is part of the message markup, not a separate element, so replacing the whole value with text removes it along with the wording.
- With AJAX add to cart enabled on archives there is no page reload, so there is no notice render. WooCommerce updates the cart fragments instead and the message is queued rather than shown.
- It is an array of product IDs mapped to quantities for everything added in that request. It lets one message describe a multi-item add, which is what happens when a grouped product is submitted.