logo
image
Jun 10, 2026 - 07:54 PM

WooCommerce WhatsApp Order Button: Product Questions, Orders, and Abandoned Cart Flow

WooCommerce WhatsApp order button turns product questions, order updates, and abandoned carts into direct WhatsApp conversations. This page contains three real code blocks for your theme functions.php (or a small custom plugin) that work with HPOS-enabled stores and the block-based cart.

1. "Ask on WhatsApp" button on the single-product page

Drop this in your theme's functions.php (or a small must-use plugin). It renders a green button right under the "Add to cart" button with the product name and SKU in the message:

add_action('woocommerce_after_add_to_cart_button', function () {
    global $product;
    if (!$product instanceof WC_Product) return;

    $phone = '966500000000';
    $msg   = sprintf(
        "Hi, I have a question about %s (SKU %s).",
        $product->get_name(),
        $product->get_sku() ?: 'n/a'
    );
    $href  = 'https://wa.me/' . preg_replace('/[^0-9]/', '', $phone)
           . '?text=' . rawurlencode($msg);

    echo ''
         . 'Ask on WhatsApp';
});

add_action('wp_footer', function () { ?>

2. WhatsApp link on each WooCommerce order row in My Account

Useful for "I have a question about order #1234" type messages. Adds a column to the orders table:

add_filter('woocommerce_my_account_my_orders_columns', function ($cols) {
    $cols['wutt_wa'] = 'WhatsApp';
    return $cols;
});

add_action('woocommerce_my_account_my_orders_column_wutt_wa', function ($order) {
    $phone = '966500000000';
    $msg   = sprintf("Hi, I have a question about order #%s.",
                     $order->get_order_number());
    $href  = 'https://wa.me/' . preg_replace('/[^0-9]/', '', $phone)
           . '?text=' . rawurlencode($msg);
    echo 'Chat';
});

3. Abandoned-cart recovery hook

WooCommerce fires cart-abandoned events from plugins like Cartflows. Below is a clean hook you can wire into your custom cron, or trigger from any analytics job that scans old wc_session rows:

add_action('wutt_recover_abandoned_cart', function ($cart_hash) {
    $session = WC()->session;
    if (!$session) return;

    $cart     = $session->get('cart', []);
    $customer = $session->get('customer', []);
    $phone    = $customer['phone'] ?? '';
    if (!$phone || empty($cart)) return;

    $lines = [];
    foreach ($cart as $item) {
        $name = $item['data']->get_name() ?? 'item';
        $lines[] = sprintf("- %dx %s", $item['quantity'] ?? 1, $name);
    }
    $msg  = "Hi, you left items in your cart at " . get_bloginfo('name') . ":\n"
          . implode("\n", $lines) . "\n\nCan I help you finish the order?";
    $href = 'https://wa.me/' . preg_replace('/[^0-9]/', '', $phone)
          . '?text=' . rawurlencode($msg);

    update_post_meta($cart_hash, '_wutt_recovery_link', $href);
    do_action('wutt_recovery_link_ready', $href, $phone, $msg);
});

4. Thank-you page WhatsApp share

On woocommerce_thankyou offer a "Share with a friend on WhatsApp" link. The prefilled text includes the order number, total, and a short thank-you line:

add_action('woocommerce_thankyou', function ($order_id) {
    $order = wc_get_order($order_id);
    if (!$order) return;
    $msg = sprintf("Thanks %s! Your order #%s for %s %s is confirmed.",
        $order->get_billing_first_name() ?: 'there',
        $order->get_order_number(),
        $order->get_total(),
        $order->get_currency());
    $href = 'https://wa.me/?text=' . rawurlencode($msg);
    echo '

Share order on WhatsApp

'; });

Block-themes (Twenty Twenty-Four, etc.)

If your theme is block-based, the cleanest path is a small custom block plugin. The same PHP hooks above still work because WooCommerce fires them on every template render. To put the button next to "Add to cart" in a block theme, wrap the Add-to-cart block in a Group block and inject the button via the woocommerce_after_add_to_cart_button hook using your theme's slot system.

Quick checklist

  • Always strip non-digits before building wa.me/ URLs.
  • Use rawurlencode() for the message so apostrophes, & and emojis survive.
  • Test with a real order in incognito to confirm HPOS and block-based cart compatibility.
  • For automated recovery messages, send through Wutt's template API so you stay on Meta's approved-templates list.

Add Wutt to your site — start $1 trial

Drop the widget in, then keep every reply, click, lead, and order inside Wutt Inbox, Wutt Book, Wutt Reviews, Wutt Loyalty, and the CRM follow-up workspace.

Start $1 trial

Admin order list WhatsApp column

Add a custom column to the WooCommerce admin orders list so the team can jump to a customer chat in one click.

// In your theme functions.php or a small custom plugin
add_filter("manage_edit-shop_order_columns", function ($columns) {
    $new = [];
    foreach ($columns as $k => $v) {
        $new[$k] = $v;
        if ($k === "order_status") {
            $new["wutt_chat"] = "WhatsApp";
        }
    }
    return $new;
});

add_action("manage_shop_order_posts_custom_column", function ($col, $post_id) {
    if ($col !== "wutt_chat") return;
    $phone = get_post_meta($post_id, "_billing_phone", true);
    if (!$phone) { echo "—"; return; }
    $clean = preg_replace("/[^0-9]/", "", $phone);
    $href  = "https://wa.me/" . $clean . "?text=" . rawurlencode("Hi! Regarding your order #" . $post_id);
    echo "<a href=\"" . esc_url($href) . "\" target=\"_blank\" rel=\"noopener\">Chat</a>";
}, 10, 2);

Abandoned cart recovery with Wutt API

For automated abandoned-cart messages, use the Wutt template API so you stay inside Meta’s 24-hour window rules. Trigger from a scheduled cron that checks wc_abandoned_cart rows older than 60 minutes.

// /wp-content/plugins/wutt-cart-recover/wutt-cart-recover.php
add_action("wutt_recover_abandoned_cart", function ($cart_id) {
    $cart = get_post($cart_id);
    if (!$cart) return;
    $phone = get_post_meta($cart_id, "_wutt_phone", true);
    if (!$phone) return;

    $payload = [
        "to" => $phone,
        "template" => [
            "name" => "wutt_cart_recovery",
            "language" => ["code" => "en"],
            "components" => [[
                "type" => "body",
                "parameters" => [
                    ["type" => "text", "text" => get_post_meta($cart_id, "_wutt_name", true)],
                    ["type" => "text", "text" => get_post_meta($cart_id, "_wutt_total", true)],
                    ["type" => "text", "text" => get_post_meta($cart_id, "_wutt_url",  true)],
                ],
            ]],
        ],
    ];

    $resp = wp_remote_post("https://api.wutt.net/v1/messages/send-template", [
        "headers" => [
            "Authorization" => "Bearer " . get_option("wutt_api_key"),
            "Content-Type"  => "application/json",
        ],
        "body"    => wp_json_encode($payload),
        "timeout" => 20,
    ]);

    if (!is_wp_error($resp)) {
        update_post_meta($cart_id, "_wutt_recovery_sent_at", current_time("mysql"));
    }
});
do_action("wutt_recovery_link_ready", $cart_id, $url, $phone);

HPOS, block themes, and what to watch for

WooCommerce 8+ moved orders to High-Performance Order Storage (HPOS). All the get_post_meta calls above still work because HPOS has a compatibility shim, but new code should use $order = wc_get_order($id); $order->get_meta("_billing_phone"); instead.

For block-based themes (Twenty Twenty-Four, Twenty Twenty-Five, custom block themes), the WooCommerce hooks still fire but the rendered cart markup changes. If your "Ask on WhatsApp" button is missing, it is almost always a hook priority issue: bump woocommerce_after_add_to_cart_button from default 10 to 20 so the button renders after the block-based add-to-cart markup.

Tracking and analytics

Fire a GA4 event whenever someone clicks the "Ask about this product" button. This is what powers the ROI numbers in the Wutt dashboard and the blog calculator.

document.addEventListener("click", function (e) {
    const a = e.target.closest("a.wutt-ask, a.wutt-share");
    if (!a) return;
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
        event: "wutt_chat_click",
        product_id: a.dataset.product || null,
        product_name: a.dataset.name || null,
        href: a.href,
    });
});