June 15, 2025
4 min read

Are you looking to add quantity increment and decrement buttons (+/-) to your WooCommerce checkout page? By default, WooCommerce shows a simple quantity number on the checkout page without any option to change it. This can be frustrating for customers who want to adjust their order quantities before completing their purchase.

In this tutorial, we’ll show you how to add working quantity controls to your WooCommerce checkout page without using any paid plugins. The solution is completely free and uses simple WordPress hooks.

Why Add Quantity Controls to Checkout Page?

Before diving into the code, let’s understand why this feature is important:

  • Better User Experience: Customers can easily adjust quantities without going back to the cart page
  • Reduced Cart Abandonment: Smoother checkout process keeps customers engaged
  • Mobile Friendly: Plus and minus buttons are easier to use on mobile devices than typing numbers
  • Professional Look: Makes your store look more polished and user-friendly

What You’ll Need

  • Access to your WordPress admin area
  • Basic knowledge of copying and pasting code
  • A child theme (recommended) or ability to edit your theme’s functions.php file
  • Active WooCommerce plugin

Step-by-Step Implementation

Step 1: Access Your Theme Files

You can add the code in two ways:

Option 1: Using Theme Editor (Quick Method)

  1. Go to WordPress Admin → Appearance → Theme Editor
  2. Select your active theme
  3. Open the functions.php file

Option 2: Using FTP/cPanel (Recommended)

  1. Access your website files via FTP or cPanel File Manager
  2. Navigate to /wp-content/themes/your-theme-name/
  3. Download and edit the functions.php file

Step 2: Add the Complete Code

Copy and paste this complete code at the end of your functions.php file (before the closing ?> tag if it exists):

functions.php
<?php
// Add quantity input field to checkout page
add_filter('woocommerce_checkout_cart_item_quantity', 'add_quantity_input_checkout', 10, 3);

function add_quantity_input_checkout($product_quantity, $cart_item, $cart_item_key) {
    // Check if product is sold individually
    if ($cart_item['data']->is_sold_individually()) {
        return $product_quantity;
    }
    
    $product_id = $cart_item['product_id'];
    $quantity = $cart_item['quantity'];
    
    // Create quantity input with +/- buttons
    $quantity_input = '<div class="quantity-wrapper">';
    $quantity_input .= '<button type="button" class="qty-btn minus" data-cart-key="' . $cart_item_key . '">-</button>';
    $quantity_input .= '<input type="number" class="input-text qty text" name="cart[' . $cart_item_key . '][qty]" value="' . $quantity . '" min="1" max="99" step="1">';
    $quantity_input .= '<button type="button" class="qty-btn plus" data-cart-key="' . $cart_item_key . '">+</button>';
    $quantity_input .= '</div>';
    
    return $quantity_input;
}

// Add CSS for styling
add_action('wp_head', 'checkout_quantity_styles');

function checkout_quantity_styles() {
    if (is_checkout()) {
        ?>
        <style>
        .quantity-wrapper {
            display: flex;
            align-items: center;
            justify-content: center;
            max-width: 120px;
        }
        
        .qty-btn {
            background: #333;
            color: white;
            border: none;
            width: 30px;
            height: 30px;
            cursor: pointer;
            font-size: 16px;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        
        .qty-btn:hover {
            background: #555;
        }
        
        .qty-btn.minus {
            border-radius: 3px 0 0 3px;
        }
        
        .qty-btn.plus {
            border-radius: 0 3px 3px 0;
        }
        
        .quantity-wrapper .qty {
            width: 60px;
            text-align: center;
            border: 1px solid #ddd;
            border-left: none;
            border-right: none;
            height: 30px;
            margin: 0;
            padding: 0;
        }
        
        /* Remove spinner arrows */
        .quantity-wrapper .qty::-webkit-outer-spin-button,
        .quantity-wrapper .qty::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
        
        .quantity-wrapper .qty[type=number] {
            -moz-appearance: textfield;
        }
        </style>
        <?php
    }
}

// Add JavaScript for quantity controls
add_action('wp_footer', 'checkout_quantity_scripts');

function checkout_quantity_scripts() {
    if (is_checkout()) {
        ?>
        <script>
        jQuery(document).ready(function($) {
            var isUpdating = false;
            
            // Handle plus button click
            $(document).on('click', '.qty-btn.plus', function(e) {
                e.preventDefault();
                if (isUpdating) return;
                
                var input = $(this).siblings('.qty');
                var cartKey = $(this).data('cart-key');
                var currentVal = parseInt(input.val());
                var max = parseInt(input.attr('max')) || 99;
                
                if (currentVal < max) {
                    var newVal = currentVal + 1;
                    input.val(newVal);
                    updateCartQuantity(cartKey, newVal);
                }
            });
            
            // Handle minus button click
            $(document).on('click', '.qty-btn.minus', function(e) {
                e.preventDefault();
                if (isUpdating) return;
                
                var input = $(this).siblings('.qty');
                var cartKey = $(this).data('cart-key');
                var currentVal = parseInt(input.val());
                var min = parseInt(input.attr('min')) || 1;
                
                if (currentVal > min) {
                    var newVal = currentVal - 1;
                    input.val(newVal);
                    updateCartQuantity(cartKey, newVal);
                }
            });
            
            // Handle direct input change
            $(document).on('change', '.quantity-wrapper .qty', function() {
                if (isUpdating) return;
                
                var cartKey = $(this).attr('name').match(/cart\[(.*?)\]/)[1];
                var newVal = parseInt($(this).val()) || 1;
                updateCartQuantity(cartKey, newVal);
            });
            
            function updateCartQuantity(cartKey, quantity) {
                if (isUpdating) return;
                isUpdating = true;
                
                // Show loading state
                $('.woocommerce-checkout-review-order-table').addClass('processing');
                
                $.ajax({
                    type: 'POST',
                    url: wc_checkout_params.ajax_url,
                    data: {
                        action: 'update_checkout_quantity',
                        cart_item_key: cartKey,
                        quantity: quantity,
                        security: wc_checkout_params.update_order_review_nonce
                    },
                    success: function(response) {
                        // Refresh the checkout fragments
                        $('body').trigger('update_checkout');
                        
                        // Update cart widget if exists
                        $(document.body).trigger('wc_fragment_refresh');
                    },
                    error: function() {
                        console.log('Error updating quantity');
                    },
                    complete: function() {
                        isUpdating = false;
                        $('.woocommerce-checkout-review-order-table').removeClass('processing');
                    }
                });
            }
        });
        </script>
        <?php
    }
}

// Handle AJAX quantity updates
add_action('wp_ajax_update_checkout_quantity', 'handle_checkout_quantity_update');
add_action('wp_ajax_nopriv_update_checkout_quantity', 'handle_checkout_quantity_update');

function handle_checkout_quantity_update() {
    // Verify nonce for security
    if (!wp_verify_nonce($_POST['security'], 'update-order-review')) {
        wp_die('Security check failed');
    }
    
    if (isset($_POST['cart_item_key']) && isset($_POST['quantity'])) {
        $cart_item_key = sanitize_text_field($_POST['cart_item_key']);
        $quantity = intval($_POST['quantity']);
        
        // Ensure minimum quantity of 1
        if ($quantity < 1) {
            $quantity = 1;
        }
        
        // Update cart quantity
        WC()->cart->set_quantity($cart_item_key, $quantity);
        
        // Calculate totals
        WC()->cart->calculate_totals();
        
        // Return success response
        wp_send_json_success(array(
            'message' => 'Quantity updated successfully',
            'cart_hash' => WC()->cart->get_cart_hash()
        ));
    } else {
        wp_send_json_error('Invalid data');
    }
    
    wp_die();
}

// Add loading styles for better UX
add_action('wp_head', 'checkout_loading_styles');

function checkout_loading_styles() {
    if (is_checkout()) {
        ?>
        <style>
        .woocommerce-checkout-review-order-table.processing {
            opacity: 0.6;
            pointer-events: none;
        }
        
        .woocommerce-checkout-review-order-table.processing::after {
            content: '';
            position: absolute;
            top: 50%;
            left: 50%;
            width: 20px;
            height: 20px;
            margin: -10px 0 0 -10px;
            border: 2px solid #f3f3f3;
            border-top: 2px solid #333;
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }
        
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        </style>
        <?php
    }
}
?>

Step 3: Save and Test

  1. Save the functions.php file
  2. Upload it back to your server (if using FTP)
  3. Clear any caching plugins
  4. Test the checkout page with items in your cart

How the Code Works

Let’s break down what each part of the code does:

1. HTML Structure

The code creates a wrapper with plus/minus buttons and a number input field for each product in the checkout.

2. CSS Styling

The CSS styles the buttons to look professional and work well on both desktop and mobile devices.

3. JavaScript Functionality

The JavaScript handles button clicks and updates the cart quantities using AJAX without refreshing the page.

4. AJAX Handler

The PHP AJAX handler securely processes quantity updates and recalculates cart totals.

Troubleshooting Common Issues

Issue 1: Buttons Not Appearing

  • Check if you saved the file correctly
  • Clear your website cache
  • Make sure WooCommerce is active

Issue 2: Quantities Not Updating

  • Check browser console for JavaScript errors
  • Ensure your theme includes jQuery
  • Try disabling other plugins temporarily

Issue 3: Styling Issues

  • Your theme might have conflicting CSS
  • Try adding !important to critical CSS rules
  • Check if your theme overrides WooCommerce templates

Best Practices and Tips

  1. Use a Child Theme: Always add custom code to a child theme to prevent losing changes during theme updates
  2. Backup First: Always backup your website before making changes
  3. Test Thoroughly: Test the functionality on different devices and browsers
  4. Monitor Performance: Check if the code affects your site’s loading speed
  5. Keep it Updated: Make sure the code works with WooCommerce updates

Conclusion

Adding quantity plus minus buttons to your WooCommerce checkout page is a simple but effective way to improve your customers’ shopping experience. The code we’ve provided is secure, mobile-friendly, and integrates seamlessly with WooCommerce’s existing functionality.

This solution works with most WordPress themes and WooCommerce versions. It automatically handles cart updates, price calculations, and provides visual feedback to users during the update process.

Remember to test the functionality thoroughly after implementation and consider your specific theme’s styling requirements for the best results.

Have you implemented this feature on your WooCommerce store? Share your experience in the comments below!

Leave a Reply

Your email address will not be published. Required fields are marked *

Allow Only Business Email Addresses in the Email Field of Elementor Forms

Find out how to restrict email fields in Elementor forms to business emails only. Improve form data quality by blocking free email domains like Gmail and Yahoo.

Create a new WordPress administrator via functions.php & FTP

Sometimes, you might need to create an administrator account in WordPress without being able to access the admin dashboard. This could be because you have lost access to your site’s admin panel or when troubleshooting a client’s website. In this tutorial, we will show you how to programmatically add a WordPress administrator account using the […]

Conditional statement to show pagination

Conditional statement to show pagination on WordPress archive or blog page

JS set interval for an event until element show

Sometimes we need to active an event when a specific element loads on-page or part of an element change.

Web Development Project in mind?

if you looking for a web developer for paid contribution to your project I am available for work.

Mukto
Mukto

Click the button below to chat with me.