How to Customize WooCommerce Add to Cart Button Text Dynamically and add “Already in cart” text.

Are you running a WooCommerce store and want to make your “Add to Cart” buttons more informative and user-friendly? In this tutorial, I’ll show you how to enhance your WooCommerce shop with dynamic cart button text that updates automatically based on the product’s status in the cart.

What Does This Enhancement Do?

This code adds the following helpful features to your WooCommerce store:

  1. Shows different button text when a product is already in the cart (including quantity)
  2. Custom text for variable products before and after selecting options
  3. Allows you to set custom button text for individual products
  4. Updates button text automatically without page refresh
  5. Includes an easy-to-use settings page in WooCommerce admin

Benefits for Your Customers

  • Clear indication when a product is already in their cart
  • Shows the current quantity right on the button
  • Better guidance for variable products
  • Improved shopping experience with real-time updates
  • Reduces confusion and potential duplicate purchases

How to Implement It?

There are two ways to add this functionality to your store. I’ll explain both, but strongly recommend the first method:

Method 1: Using Code Snippets Plugin (Recommended)

  1. Install and activate the “Code Snippets” plugin from WordPress repository
  2. Go to Snippets → Add New
  3. Give your snippet a title like “WooCommerce Enhanced Cart Buttons”
  4. Copy the entire code from above and paste it into the snippet editor
  5. Check the “Only run in administration area” option
  6. Click “Save Changes and Activate”

Method 2: Using functions.php (Not Recommended)

Add the code to your child theme’s functions.php file.

⚠️ Warning: This method requires more technical knowledge and can break your site if not done carefully!

  1. Connect to your site via FTP or file manager
  2. Navigate to your theme folder (wp-content/themes/your-theme)
  3. Open functions.php
  4. Add the code at the bottom of the file
  5. Save and upload the file

Why Code Snippets is Better

  1. Safety: If there’s an error in the code, Code Snippets will deactivate just that snippet instead of breaking your entire site
  2. Organization: Keeps your custom code separate and easy to manage
  3. Portability: Easy to export/import between sites
  4. No FTP needed: All done through WordPress admin
  5. Version control: Track changes and revert if needed

Method 3: Download and install it as a regular WordPress plugin

If you don’t feel comfortable messing with the code, you can download this as a WordPress plugin. Just install it like any other plugin (Plugins >> Add New), and it works similarly to the code below after activating it.

Video: How to Customize WooCommerce Add to Cart Button Text Dynamically and add “Already in cart” text

How to Customize WooCommerce Add to Cart Button Text Dynamically and add “Already in cart” text – The Code

if (!defined('ABSPATH')) {
    exit;
}

class WC_Enhanced_Cart_Button {
    private static $instance = null;
    private $cart_items_cache = [];

    // Settings keys
    private $settings_keys = [
        'default_text' => 'wc_cart_default_text',
        'already_added_text' => 'wc_cart_already_added_text',
        'select_options_text' => 'wc_cart_select_options_text',
        'per_product_prefix' => '_custom_cart_button_'
    ];

    public static function get_instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct() {
        // Cart button text filters
        add_filter('woocommerce_product_single_add_to_cart_text', [$this, 'modify_single_product_button'], 10, 2);
        add_filter('woocommerce_product_add_to_cart_text', [$this, 'modify_archive_product_button'], 20, 2);

        // Cart initialization
        add_action('woocommerce_cart_loaded_from_session', [$this, 'init_cart_cache']);

        // Admin settings
        if (is_admin()) {
            add_action('admin_menu', [$this, 'add_admin_menu']);
            add_action('admin_init', [$this, 'init_settings']);
            
            // Product meta box
            add_action('woocommerce_product_data_tabs', [$this, 'add_product_data_tab']);
            add_action('woocommerce_product_data_panels', [$this, 'add_product_data_panel']);
            add_action('woocommerce_process_product_meta', [$this, 'save_product_meta']);
        }

        // AJAX handlers
        add_action('wp_ajax_update_cart_button_text', [$this, 'ajax_update_button_text']);
        add_action('wp_ajax_nopriv_update_cart_button_text', [$this, 'ajax_update_button_text']);
        
        // Add AJAX scripts
        add_action('wp_footer', [$this, 'add_ajax_script']);
    }

    // Cart Cache Methods
    public function init_cart_cache() {
        if (!WC()->cart) {
            return;
        }

        $this->cart_items_cache = [];
        foreach (WC()->cart->get_cart() as $cart_item) {
            $product_id = $cart_item['product_id'];
            if (!isset($this->cart_items_cache[$product_id])) {
                $this->cart_items_cache[$product_id] = [
                    'quantity' => 0,
                    'data' => $cart_item['data']
                ];
            }
            $this->cart_items_cache[$product_id]['quantity'] += $cart_item['quantity'];
        }
    }

    private function get_product_cart_status($product_id) {
        return isset($this->cart_items_cache[$product_id]) ? $this->cart_items_cache[$product_id] : false;
    }

    // Button Text Methods
private function get_button_text($product) {
    $product_id = $product->get_id();
    $type = $product->get_type();
    $variations_selected = isset($_POST['variations_selected']) ? (bool)$_POST['variations_selected'] : false;
    $cart_status = $this->get_product_cart_status($product_id);
    
    // Check if product has custom text
    $custom_text = '';
    
    if ($type === 'variable') {
        // First check if product is in cart
        if ($cart_status) {
            $custom_text = get_post_meta($product_id, $this->settings_keys['per_product_prefix'] . 'already_added', true);
            if (!$custom_text) {
                $custom_text = get_option($this->settings_keys['already_added_text'], __('Already in cart (%qty%) - Add again?', 'woocommerce'));
            }
            $custom_text = str_replace('%qty%', $cart_status['quantity'], $custom_text);
        } else {
            if ($variations_selected) {
                // When variations are selected
                $custom_text = get_post_meta($product_id, $this->settings_keys['per_product_prefix'] . 'default', true);
                if (empty($custom_text)) {
                    $custom_text = get_option($this->settings_keys['default_text'], __('Add to cart', 'woocommerce'));
                }
            } else {
                // When variations aren't selected
                $custom_text = get_post_meta($product_id, $this->settings_keys['per_product_prefix'] . 'select_options', true);
                if (empty($custom_text)) {
                    $custom_text = get_option($this->settings_keys['select_options_text'], __('Select options', 'woocommerce'));
                }
            }
        }
    } else {
        if ($cart_status) {
            $custom_text = get_post_meta($product_id, $this->settings_keys['per_product_prefix'] . 'already_added', true);
            if (!$custom_text) {
                $custom_text = get_option($this->settings_keys['already_added_text'], __('Already in cart (%qty%) - Add again?', 'woocommerce'));
            }
            $custom_text = str_replace('%qty%', $cart_status['quantity'], $custom_text);
        } else {
            $custom_text = get_post_meta($product_id, $this->settings_keys['per_product_prefix'] . 'default', true);
            if (!$custom_text) {
                $custom_text = get_option($this->settings_keys['default_text'], __('Add to cart', 'woocommerce'));
            }
        }
    }

    return $custom_text;
}

    public function modify_single_product_button($text, $product = null) {
        if (!$product) {
            global $product;
        }
        if (!$product) {
            return $text;
        }

        return $this->get_button_text($product);
    }

    public function modify_archive_product_button($text, $product) {
        if (!$product) {
            return $text;
        }

        return $this->get_button_text($product);
    }

    // Admin Settings Methods
    public function add_admin_menu() {
        add_submenu_page(
            'woocommerce',
            __('Cart Button Settings', 'woocommerce'),
            __('Cart Button', 'woocommerce'),
            'manage_woocommerce',
            'wc-cart-button-settings',
            [$this, 'render_settings_page']
        );
    }

    public function init_settings() {
        register_setting('wc_cart_button_settings', $this->settings_keys['default_text']);
        register_setting('wc_cart_button_settings', $this->settings_keys['already_added_text']);
        register_setting('wc_cart_button_settings', $this->settings_keys['select_options_text']);
    }

    public function render_settings_page() {
        ?>
        <div class="wrap wc-cart-button-settings">
            <h1><?php echo esc_html(get_admin_page_title()); ?></h1>
            
            <form method="post" action="options.php">
                <?php
                settings_fields('wc_cart_button_settings');
                ?>
                
                <table class="form-table">
                    <tr>
                        <th scope="row"><?php _e('Default Add to Cart Text', 'woocommerce'); ?></th>
                        <td>
                            <input type="text" 
                                   name="<?php echo esc_attr($this->settings_keys['default_text']); ?>"
                                   value="<?php echo esc_attr(get_option($this->settings_keys['default_text'], __('Add to cart', 'woocommerce'))); ?>"
                                   class="regular-text">
                        </td>
                    </tr>
                    <tr>
                        <th scope="row"><?php _e('Already in Cart Text', 'woocommerce'); ?></th>
                        <td>
                            <input type="text" 
                                   name="<?php echo esc_attr($this->settings_keys['already_added_text']); ?>"
                                   value="<?php echo esc_attr(get_option($this->settings_keys['already_added_text'], __('Already in cart (%qty%) - Add again?', 'woocommerce'))); ?>"
                                   class="regular-text">
                            <p class="description"><?php _e('Use %qty% to display the quantity', 'woocommerce'); ?></p>
                        </td>
                    </tr>
                    <tr>
                        <th scope="row"><?php _e('Select Options Text', 'woocommerce'); ?></th>
                        <td>
                            <input type="text" 
                                   name="<?php echo esc_attr($this->settings_keys['select_options_text']); ?>"
                                   value="<?php echo esc_attr(get_option($this->settings_keys['select_options_text'], __('Select options', 'woocommerce'))); ?>"
                                   class="regular-text">
                        </td>
                    </tr>
                </table>
                
                <?php submit_button(); ?>
            </form>

            <div class="wc-cart-button-preview" style="margin-top: 30px; padding: 20px; background: #fff; border: 1px solid #ddd;">
                <h2><?php _e('Preview', 'woocommerce'); ?></h2>
                <div style="display: flex; gap: 20px; margin-top: 15px;">
                    <div>
                        <h4><?php _e('Simple Product', 'woocommerce'); ?></h4>
                        <button class="button" style="margin-bottom: 10px;">
                            <?php echo esc_html(get_option($this->settings_keys['default_text'], __('Add to cart', 'woocommerce'))); ?>
                        </button>
                        <button class="button">
                            <?php 
                            $text = get_option($this->settings_keys['already_added_text'], __('Already in cart (%qty%) - Add again?', 'woocommerce'));
                            echo esc_html(str_replace('%qty%', '2', $text));
                            ?>
                        </button>
                    </div>
                    <div>
                        <h4><?php _e('Variable Product', 'woocommerce'); ?></h4>
                        <button class="button">
                            <?php echo esc_html(get_option($this->settings_keys['select_options_text'], __('Select options', 'woocommerce'))); ?>
                        </button>
                    </div>
                </div>
            </div>
        </div>
        <?php
    }

    // Product Data Tab Methods
    public function add_product_data_tab($tabs) {
        $tabs['cart_button'] = [
            'label' => __('Cart Button', 'woocommerce'),
            'target' => 'cart_button_product_data',
            'class' => ['hide_if_grouped'],
        ];
        return $tabs;
    }

    public function add_product_data_panel() {
        global $post;
        ?>
        <div id="cart_button_product_data" class="panel woocommerce_options_panel">
            <?php
            // Default Add to Cart Text
            woocommerce_wp_text_input([
                'id' => $this->settings_keys['per_product_prefix'] . 'default',
                'label' => __('Custom Add to Cart Text', 'woocommerce'),
                'description' => __('Override default Add to Cart button text for this product.', 'woocommerce'),
                'desc_tip' => true,
                'value' => get_post_meta($post->ID, $this->settings_keys['per_product_prefix'] . 'default', true)
            ]);

            // Already in Cart Text
            woocommerce_wp_text_input([
                'id' => $this->settings_keys['per_product_prefix'] . 'already_added',
                'label' => __('Custom Already in Cart Text', 'woocommerce'),
                'description' => __('Override default Already in Cart text for this product. Use %qty% to display the quantity.', 'woocommerce'),
                'desc_tip' => true,
                'value' => get_post_meta($post->ID, $this->settings_keys['per_product_prefix'] . 'already_added', true)
            ]);

            // Select Options Text (show only for variable products)
            ?>
            <div class="show_if_variable">
                <?php
                woocommerce_wp_text_input([
                    'id' => $this->settings_keys['per_product_prefix'] . 'select_options',
                    'label' => __('Custom Select Options Text', 'woocommerce'),
                    'description' => __('Override default Select Options text for this variable product.', 'woocommerce'),
                    'desc_tip' => true,
                    'value' => get_post_meta($post->ID, $this->settings_keys['per_product_prefix'] . 'select_options', true)
                ]);
                ?>
            </div>
        </div>
        <?php
    }

    public function save_product_meta($post_id) {
        $fields = [
            $this->settings_keys['per_product_prefix'] . 'default',
            $this->settings_keys['per_product_prefix'] . 'already_added',
            $this->settings_keys['per_product_prefix'] . 'select_options'
        ];

        foreach ($fields as $field) {
            if (isset($_POST[$field])) {
                update_post_meta($post_id, $field, sanitize_text_field($_POST[$field]));
            }
        }
    }

    // AJAX Methods
public function ajax_update_button_text() {
    check_ajax_referer('update_cart_button', 'nonce');

    $product_id = isset($_POST['product_id']) ? intval($_POST['product_id']) : 0;
    
    if (!$product_id) {
        wp_send_json_error();
    }

    $product = wc_get_product($product_id);
    if (!$product) {
        wp_send_json_error();
    }

    $this->init_cart_cache();
    $button_text = $this->get_button_text($product);
    
    wp_send_json_success([
        'text' => $button_text,
        'product_id' => $product_id
    ]);
}

public function add_ajax_script() {
    if (!is_shop() && !is_product() && !is_product_category()) {
        return;
    }
    ?>
    <script type="text/javascript">
    jQuery(function($) {
        // Make updateButtonText available globally
        window.updateButtonText = function(productId) {
            $.ajax({
                url: '<?php echo admin_url('admin-ajax.php'); ?>',
                type: 'POST',
                data: {
                    action: 'update_cart_button_text',
                    nonce: '<?php echo wp_create_nonce('update_cart_button'); ?>',
                    product_id: productId,
                    variations_selected: $('form.variations_form[data-product_id="' + productId + '"]').length ? 
                        areAllVariationsSelected($('form.variations_form[data-product_id="' + productId + '"]')) : false
                },
                success: function(response) {
                    if (response.success) {
                        $('.single_add_to_cart_button[value="' + response.data.product_id + '"]').text(response.data.text);
                        $('a.add_to_cart_button[data-product_id="' + response.data.product_id + '"]').text(response.data.text);
                    }
                }
            });
        };

        function areAllVariationsSelected($form) {
            var allSelected = true;
            $form.find('.variations select').each(function() {
                if ($(this).val() === '') {
                    allSelected = false;
                    return false;
                }
            });
            return allSelected;
        }

        function updateVariationButtonText($form) {
            var $button = $form.find('.single_add_to_cart_button');
            var productId = $form.find('input[name="product_id"]').val() || $form.find('button[name="add-to-cart"]').val();
            
            if ($form.hasClass('variations_form')) {
                $.ajax({
                    url: '<?php echo admin_url('admin-ajax.php'); ?>',
                    type: 'POST',
                    data: {
                        action: 'update_cart_button_text',
                        nonce: '<?php echo wp_create_nonce('update_cart_button'); ?>',
                        product_id: productId,
                        variations_selected: areAllVariationsSelected($form) ? 1 : 0,
                        in_cart: true // Add this flag to check cart status
                    },
                    success: function(response) {
                        if (response.success) {
                            $button.text(response.data.text);
                        }
                    }
                });
            }
        }

        // Listen for variation changes
        $('form.variations_form').on('woocommerce_variation_has_changed', function() {
            updateVariationButtonText($(this));
        });

        // Initial check on page load
        $('form.variations_form').each(function() {
            updateVariationButtonText($(this));
        });

        // Update on add to cart
        $('body').on('added_to_cart', function(event, fragments, cartHash, button) {
            var productId = $(button).data('product_id');
            if (productId) {
                updateButtonText(productId);
            }
        });

        // Update on cart update
        $('body').on('updated_cart_totals', function() {
            $('.add_to_cart_button').each(function() {
                var productId = $(this).data('product_id');
                if (productId) {
                    updateButtonText(productId);
                }
            });
            
            // Also update single product buttons
            var singleProductId = $('.single_add_to_cart_button').val();
            if (singleProductId) {
                updateButtonText(singleProductId);
            }
        });

        // Handle quantity changes
        $('body').on('change', 'form.cart input.qty', function() {
            var $form = $(this).closest('form.cart');
            var productId = $form.find('button[name="add-to-cart"]').val();
            if (productId) {
                updateButtonText(productId);
            }
        });

        // Handle cart removal
        $('body').on('removed_from_cart', function(event, fragments, cartHash, $button) {
            var productId = $button.data('product_id');
            if (productId) {
                updateButtonText(productId);
            }
        });
    });
    </script>
    <?php
}
} // Class closing brace

// Initialize the enhanced cart button functionality
add_action('init', function() {
    WC_Enhanced_Cart_Button::get_instance();
});

How do I configure the text options?

After activating the code:

  1. Go to WooCommerce → Cart Button in your WordPress admin
  2. You’ll see three customizable text options:
  • Default “Add to Cart” text
  • Text when product is already in cart (use %qty% for quantity)
  • Text for variable products before options are selected

Per-Product Custom Text

You can also set custom button text for individual products:

  1. Edit any product
  2. Look for the “Cart Button” tab in product data
  3. Set custom text for:
  • Add to Cart button
  • Already in Cart message
  • Select Options (for variable products)
How to Customize WooCommerce Add to Cart Button Text Dynamically and add "Already in cart" text.

Troubleshooting

If you’re using Code Snippets and something doesn’t work:

  1. Go to Snippets in your WordPress admin
  2. Deactivate the snippet
  3. Check if your site works normally
  4. Make sure WooCommerce is up to date
  5. Try activating the snippet again

If using functions.php and your site breaks:

  1. Access your site via FTP
  2. Remove the code from functions.php
  3. Switch to using Code Snippets instead

Conclusion

This enhancement makes your WooCommerce store more user-friendly by providing clear, dynamic feedback about cart status right on the buttons. Using the Code Snippets plugin makes it safe and easy to implement, even if you’re not a coding expert.

Remember to always backup your site before making any code changes, and test the functionality on a staging site if possible.

Need help? Leave a comment below, and I’ll be happy to assist you!

Do you want to thank me and buy me a beer?

Every donation is entirely welcome but NEVER required. Enjoy my work for free but if you would like to thank me and buy me a beer or two then you can use this form here below.

Donation Form (#2)

Here are some of my favorite WordPress tools

Thanks for reading this article! I hope it's been useful as you work on your own websites and e-commerce sites. I wanted to share some tools I use as a WordPress developer, and I think you'll find them helpful too.

Just so you know, these are affiliate links. If you decide to use any of them, I'll earn a commission. This helps me create tutorials and YouTube videos. But honestly, I genuinely use and recommend these tools to my friends and family as well. Your support keeps me creating content that benefits everyone.

Themes: Over the past few years, I've consistently relied on two primary themes for all sorts of projects: the Blocksy theme and the Kadence Theme. If you explore this website and my YouTube channel, you'll come across numerous tutorials that delve into these themes. If you're interested in obtaining a 10% discount for both of these themes, then:

Code Snippets Manager: WPCodeBox allows you to add code snippets to your site. Not only that, but it also provides you with the capability to construct and oversee your WordPress Code Snippets library right in the cloud. You can grab it with the 20% discount here (SAVE 20% Coupon: WPSH20).

Contact forms: There are hundreds of contact forms out there but Fluent Forms is the one I like the most. If you need a 20% discount then use this link (save 20% coupon is WPSH20).

Gutenberg add-ons: If I need a good Gutenberg blocks add-on then Kadence Blocks is the one I have used the most. You’ll get a 10% discount with the coupon SIMPLEHACKS here.

Website migration: While building a website you probably need a good plugin that can help you with the migration, backups, restoration, and staging sites. Well, WpVivid is the one I have used for the last couple of years. If you use this link along with the WPSH20 coupon you’ll get a 20% discount.

Woocommerce extensions: There are a bunch of Woocommerce extensions that I like but the one that stands out is Advanced Dynamic Pricing. Once again, you’ll get a 20% discount if you use this link here (save 20% coupon is WPSH20)

Web Hosting: If you would like to have a really fast and easy-to-use managed cloud hosting, then I recommend Verpex Hosting (see my review here). By the way, this site is hosted in Verpex.)

To see all my most up-to-date recommendations, check out this resource that I made for you!

Janek T.
Janek T.

Improve this text: {CLIPBOARD}

- I have been passionate about Wordpress since 2011, creating websites and sharing valuable tips on using Wordpress and Woocommerce on my site.
- Be the first to receive notifications about new tutorials by subscribing to my Youtube channel .
- Follow me on Twitter here

Articles: 134