Skip to content

Instantly share code, notes, and snippets.

@helgatheviking
Created February 24, 2017 18:09
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save helgatheviking/6abe7385c23ba4238710ba6d1ccc5181 to your computer and use it in GitHub Desktop.
Save helgatheviking/6abe7385c23ba4238710ba6d1ccc5181 to your computer and use it in GitHub Desktop.
Add plus and minus buttons to WooCommerce quantity inputs
<?php
/**
* Product quantity inputs with plus/minus buttons
*
* Save this template to your theme as woocommerce/global/quantity-input.php.
*
* HOWEVER, on occasion WooCommerce will need to update template files and you
* (the theme developer) will need to copy the new files to your theme to
* maintain compatibility. We try to do this as little as possible, but it does
* happen. When this occurs the version of the template file will be bumped and
* the readme will list any important changes.
*
* @see https://docs.woocommerce.com/document/template-structure/
* @author WooThemes
* @package WooCommerce/Templates
* @version 2.5.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( $max_value && $min_value === $max_value ) {
?>
<input type="hidden" name="<?php echo esc_attr( $input_name ); ?>" value="<?php echo esc_attr( $min_value ); ?>" />
<?php
} else {
?>
<div class="quantity">
<input class="minus" type="button" value="-">
<input type="number" step="<?php echo esc_attr( $step ); ?>" min="<?php echo esc_attr( $min_value ); ?>" max="<?php echo esc_attr( 0 < $max_value ? $max_value : '' ); ?>" name="<?php echo esc_attr( $input_name ); ?>" value="<?php echo esc_attr( $input_value ); ?>" title="<?php echo esc_attr_x( 'Qty', 'Product quantity input tooltip', 'woocommerce' ) ?>" class="input-text qty text" size="4" pattern="<?php echo esc_attr( $pattern ); ?>" inputmode="<?php echo esc_attr( $inputmode ); ?>" />
<input class="plus" type="button" value="+">
</div>
<?php
}
@robizzt
Copy link

robizzt commented Oct 12, 2017

Buttons doesn't work after you press "Update Busket" (if "Update busket" button doesn't refreshs page, it just updates it).

@Adamyus
Copy link

Adamyus commented Oct 16, 2017

true @robzzt is right

@foliopages
Copy link

foliopages commented Jan 10, 2018

Same problem here. Replaced $('.quantity') instances with $(this) problem solved.

@basepack
Copy link

basepack commented Jan 31, 2018

Updated javascript code:

   $('.woocommerce .quantity').on('click', '.minus', function (e) {
        var $inputQty = $(this).parent().find('input.qty');
        var val = parseInt($inputQty.val());
        var step = $inputQty.attr('step');
        step = 'undefined' !== typeof(step) ? parseInt(step) : 1;
        if (val > 0) {
            $inputQty.val(val - step).change();
        }
    });
    $('.woocommerce .quantity').on('click', '.plus', function (e) {
        var $inputQty = $(this).parent().find('input.qty');
        var val = parseInt($inputQty.val());
        var step = $inputQty.attr('step');
        step = 'undefined' !== typeof(step) ? parseInt(step) : 1;
        $inputQty.val(val + step).change();
    });

@MichalCzerwonka
Copy link

MichalCzerwonka commented Feb 16, 2018

Still don't work for me. I make small changes and code work's even after update cart:

$('body').on('click', '.minus', function (e) {
    var $inputQty = $(this).parent().find('input.qty');
    var val = parseInt($inputQty.val());
    var step = $inputQty.attr('step');
    step = 'undefined' !== typeof(step) ? parseInt(step) : 1;
    if (val > 0) {
        $inputQty.val(val - step).change();
    }
});
$('body').on('click', '.plus', function (e) {
    var $inputQty = $(this).parent().find('input.qty');
    var val = parseInt($inputQty.val());
    var step = $inputQty.attr('step');
    step = 'undefined' !== typeof(step) ? parseInt(step) : 1;
    $inputQty.val(val + step).change();
});

@a1iraxa
Copy link

a1iraxa commented Apr 24, 2018

 jQuery(document).ready(function($){

    $(document).on('click', '.plus', function(e) { // replace '.quantity' with document (without single quote)
        $input = $(this).prev('input.qty');
        var val = parseInt($input.val());
        var step = $input.attr('step');
        step = 'undefined' !== typeof(step) ? parseInt(step) : 1;
        $input.val( val + step ).change();
    });
    $(document).on('click', '.minus',  // replace '.quantity' with document (without single quote)
        function(e) {
        $input = $(this).next('input.qty');
        var val = parseInt($input.val());
        var step = $input.attr('step');
        step = 'undefined' !== typeof(step) ? parseInt(step) : 1;
        if (val > 0) {
            $input.val( val - step ).change();
        } 
    });
 });

@taishoDev
Copy link

taishoDev commented May 16, 2019

If you want a more advanced and easily configurable solution working on the product, cart and optionally shop/category pages with styling included to make the buttons correctly positioned and beautifully styled out of the box, you can use my new free plugin:
Qty Increment Buttons for WooCommerce

@deshario
Copy link

it works single time only ... after cart update .. plus minus not working

@taishoDev
Copy link

taishoDev commented Jul 21, 2019

Qty Increment Buttons for WooCommerce has code that solves the issue of quantity not being changeable after cart update and all other AJAX calls. .ready() is not enough. Binding the function to cart update event as well is also not enough. Any other AJAX call can possibly break it, so you need to additionally bind it to ajaxComplete() and use .off for your selector to avoid the function executing multiple times.

@samholguin
Copy link

samholguin commented Apr 12, 2021

Vanilla for those that may need:

const DOM = {
    plusBtns: document.querySelectorAll('.plus'),
    minusBtns: document.querySelectorAll('.minus'),
};

const init = () => {
    if (DOM.plusBtns.length > 0) {
        DOM.plusBtns.forEach((btn) => {
            btn.addEventListener('click', (event) => {
                event.preventDefault();
                const input = btn.nextElementSibling;
                const val = Number(input.value);
                let step = input.getAttribute('step');
                step = (typeof(step) !== 'undefined' ? Number(step) : 1);
                input.value = val + step;
            });
        });
    }

    if (DOM.minusBtns.length > 0) {
        DOM.minusBtns.forEach((btn) => {
            btn.addEventListener('click', (event) => {
                event.preventDefault();
                const input = btn.previousElementSibling;
                const val = Number(input.value);
                let step = input.getAttribute('step');
                step = (typeof(step) !== 'undefined' ? Number(step) : 1);
                if (val > 0) {
                    input.value = val - step;
                }
            });
        });
    }
};

export default init;

@tradesouthwest
Copy link

Thanks for the Vanilla, @samholguin

@SamMed1
Copy link

SamMed1 commented May 17, 2022

@samholguin Thanks for the vanilla!

Based on the html structure above, the plusBtns forEach should have:

const input = btn.previousElementSibling;

and the minusBtns forEach should have:

const input = btn.nextElementSibling;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment