sisi sisi - 3 months ago 45
PHP Question

How do I make the quantity dropdown work right in cart page?

Since I don't know how to disable the quantity hover. I'm going to use the dropdown quantity. I have the code but the quantity dropdown doesn't update the right number in the cart page. Do you know why? For example if I my quantity is 3, it will say 1 in my cart page.
Also when I choose my quantity 3, and then I click the "add to cart button" , it will say "Please choose product options" because I didn't choose a size. The quantity start from 1 again, it doesn't stay the same what I chose before.
Also this have to work in mobile too. Can you help me with that? Thanks

// override the quantity input with a dropdown
function woocommerce_quantity_input() {
global $product;
global $post;
global $prod_quant_default;



$prod_quant_default = 1; // <----------- Default Amount
$category_ID = '26'; // <----------- Case Category

$terms = get_the_terms( $post->ID, 'product_cat' );
foreach ($terms as $term) {
$product_cat_id = $term->term_id;
break;
}


// Sets QTY for Cases (Cat 26)
if ($product_cat_id == $category_ID){
$prod_quant_default = 1;
//break;
}


$defaults = array(
'input_name' => 'quantity',
'input_value' => '1',
'max_value' => apply_filters( 'woocommerce_quantity_input_max', '', $product ),
'min_value' => apply_filters( 'woocommerce_quantity_input_min', '', $product ),
'step' => apply_filters( 'woocommerce_quantity_input_step', '1', $product ),
'style' => apply_filters( 'woocommerce_quantity_style', 'float:left; margin-right:10px;', $product )
);
if ( ! empty( $defaults['min_value'] ) )
$min = $defaults['min_value'];
else $min = 1;

if ( ! empty( $defaults['max_value'] ) )
$max = $defaults['max_value'];
else $max = 10;

if ( ! empty( $defaults['step'] ) )
$step = $defaults['step'];
else $step = 1;


$options = '';
for ( $count = $min; $count <= $max; $count = $count+$step ) {
global $prod_quant_default;
if ($count == $prod_quant_default) {
$selected = ' selected="selected" ';
}
else {
$selected = null;
}


$options .= '<option' . $selected . ' value="' . $count . '">' . $count . '</option>';

}
echo '<div class="quantity_select" style="' . $defaults['style'] . '"><select name="' . esc_attr( $defaults['input_name'] ) . '" title="' . _x( 'Qty', 'Product quantity input tooltip', 'woocommerce' ) . '" class="qty">' . $options . '</select></div>';


}

Answer

I think the best way is to override the quantity-input.php template that is called by the woocommerce_quantity_input() function.

Your theme's new woocommerce/global/quantity-input.php template override:

<?php
/**
 * Product quantity inputs
 *
 * This template can be overridden by copying it to yourtheme/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         http://docs.woothemes.com/document/template-structure/
 * @author      WooThemes
 * @package     WooCommerce/Templates
 * @version     2.5.0
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}
?>
<div class="quantity">
    <?php
    $options = '';
    for ( $count = $args['min_value']; $count <= $args['max_value']; $count = $count+$args['step'] ) {
        $options .= '<option' . selected( $args['input_value'], $count, false ) . ' value="' . $count . '">' . $count . '</option>';
    } 
    if ( $options ){ ?>
    <select name="<?php echo esc_attr( $args['input_name'] ); ?>" title="<?php echo esc_attr_x( 'Qty', 'Product quantity input tooltip', 'woocommerce' ) ?>" class="qty" /><?php echo $options;?></select>
    <?php } else {
        printf( '%s <input type="hidden" name="%s" value="%s" />', $args['input_value'], $args['input_name'], $args['input_value'] );
    } ?>
</div>

Note: All my local testing is on bleeding-edge WooCommerce, I'm not sure if the 2.5 version listed here will work with current WC2.4.X. But the idea would be similar.

If you need to modify the min/max defaults, you can do so via filter in your theme's functions.php:

add_filter( 'woocommerce_quantity_input_max', 'so_input_max', 20, 2 );
function so_input_max( $max, $product ){
    return 10;
}

add_filter( 'woocommerce_quantity_input_min', 'so_input_min', 20, 2 );
function so_input_min( $min, $product ){
    return 1;
}

Remember, these are just the defaults in the case where no min/max are directly specified when calling the woocommerce_quantity_input() function.

EDIT

I improved the template above to have the right input names/values ( <select> definitely had the wrong name attribute) and to show a hidden quantity input in the case where there are no options (this is what Woo does when a product is sold individually so that so that the quantity is not lost when updating the cart).

There are no options on the cart page because the cart.php template doesn't set a max if the item's stock isn't managed, or if backorders are allowed. A null max kills the for loop in our template. With the min at 0 and the max at null, there's nothing to loop through and no <option> tags are created.

To fix that we can filter the woocommerce_cart_item_quantity in the cart.php template. This would also need to be added to your functions.php.

add_filter( 'woocommerce_cart_item_quantity', 'so_cart_item_quantity', 10, 3 );
function so_cart_item_quantity( $product_quantity, $cart_item_key, $cart_item ){
    $_product = $cart_item['data'];
     if ( ! $_product->is_sold_individually() ) {
        $max_value = $_product->backorders_allowed() ? '' : $_product->get_stock_quantity();
        // set a max of 10 as default if max is null
        $max_value = $max_value != '' ? $max_value : 10;
        $product_quantity = woocommerce_quantity_input( array(
                'input_name'  => "cart[{$cart_item_key}][qty]",
                'input_value' => $cart_item['quantity'],
                'max_value'   => $max_value,
                'min_value'   => '0'
        ), $_product, false );
    }
    return $product_quantity;
}