I'm trying to add a 'products per page' dropdown to my woocommerce storefront child theme without using a plugin. I'm adding the below code to my functions.php source
add_action( 'woocommerce_before_shop_loop', 'ps_selectbox', 25 );
function ps_selectbox() {
$per_page = filter_input(INPUT_GET, 'perpage', FILTER_SANITIZE_NUMBER_INT);
echo '<div class="woocommerce-perpage">';
echo '<span>Per Page: </span>';
echo '<select onchange="if (this.value) window.location.href=this.value">';
$orderby_options = array(
'8' => '8',
'16' => '16',
'32' => '32',
'64' => '64'
);
foreach( $orderby_options as $value => $label ) {
echo "<option ".selected( $per_page, $value )." value='?perpage=$value'>$label</option>";
}
echo '</select>';
echo '</div>';
}
add_action( 'pre_get_posts', 'ps_pre_get_products_query' );
function ps_pre_get_products_query( $query ) {
$per_page = filter_input(INPUT_GET, 'perpage', FILTER_SANITIZE_NUMBER_INT);
if( $query->is_main_query() && !is_admin() && is_post_type_archive( 'product' ) ) {
$query->set( 'posts_per_page', $per_page );
}
}
When I do this, the drop down box shows but any option I choose just takes me back to the front page of my theme.
Can anyone help me?
You can add the below codes into functions.php file. Reference:
The first step is to display a select box on the shop archive page. With some basic php we can echo a select box via the woocommerce_before_shop_loop hook.
add_action( 'woocommerce_before_shop_loop', 'ps_selectbox', 25 );
function ps_selectbox() {
$per_page = filter_input(INPUT_GET, 'perpage', FILTER_SANITIZE_NUMBER_INT);
echo '<div class="woocommerce-perpage">';
echo '<span>Per Page: </span>';
echo '<select onchange="if (this.value) window.location.href=this.value">';
$orderby_options = array(
'8' => '8',
'16' => '16',
'32' => '32',
'64' => '64'
);
foreach( $orderby_options as $value => $label ) {
echo "<option ".selected( $per_page, $value )." value='?perpage=$value'>$label</option>";
}
echo '</select>';
echo '</div>';
}
Some inline jQuery has been added so everytime the select box is changed the “products per page” varibale is sent to the browser.
The filter_input() function gets the external variable which in this case is the number of products to show and sanitizes it.
Now everything is in place we can run the pre_get_posts hook with number of products per page via the “get” method.
add_action( 'pre_get_posts', 'ps_pre_get_products_query' );
function ps_pre_get_products_query( $query ) {
$per_page = filter_input(INPUT_GET, 'perpage', FILTER_SANITIZE_NUMBER_INT);
if( $query->is_main_query() && !is_admin() && is_post_type_archive( 'product' ) ){
$query->set( 'posts_per_page', $per_page );
}
}
This is the most simpliest of methods to add a “products per page” dropdown for your WooCommerce store, alternativle you could go about using an ajax method.
I'm using the following code taken from here-
http://designloud.com/how-to-add-products-per-page-dropdown-to-woocommerce/?showmodaldialog=1#comment-1554
// Lets create the function to house our form
remove_action( 'woocommerce_before_shop_loop', 'woocommerce_catalog_ordering', 30 );
function woocommerce_catalog_page_ordering() {
?>
<?php echo '<span class="itemsorder">Items Per Page:' ?>
<form action="" method="POST" name="results" class="woocommerce-ordering">
<select name="woocommerce-sort-by-columns" id="woocommerce-sort-by-columns" class="sortby" onchange="this.form.submit()">
<?php
//Get products on page reload
if (isset($_POST['woocommerce-sort-by-columns']) && (($_COOKIE['shop_pageResults'] <> $_POST['woocommerce-sort-by-columns']))) {
$numberOfProductsPerPage = $_POST['woocommerce-sort-by-columns'];
} else {
$numberOfProductsPerPage = $_COOKIE['shop_pageResults'];
}
// This is where you can change the amounts per page that the user will use feel free to change the numbers and text as you want, in my case we had 4 products per row so I chose to have multiples of four for the user to select.
$shopCatalog_orderby = apply_filters('woocommerce_sortby_page', array(
//Add as many of these as you like, -1 shows all products per page
// '' => __('Results per page', 'woocommerce'),
'20' => __('20', 'woocommerce'),
'-1' => __('All', 'woocommerce'),
));
foreach ( $shopCatalog_orderby as $sort_id => $sort_name )
echo '<option value="' . $sort_id . '" ' . selected( $numberOfProductsPerPage, $sort_id, true ) . ' >' . $sort_name . '</option>';
?>
</select>
</form>
<?php echo ' </span>' ?>
<?php
}
// now we set our cookie if we need to
function dl_sort_by_page($count) {
if (isset($_COOKIE['shop_pageResults'])) { // if normal page load with cookie
$count = $_COOKIE['shop_pageResults'];
}
if (isset($_POST['woocommerce-sort-by-columns'])) { //if form submitted
setcookie('shop_pageResults', $_POST['woocommerce-sort-by-columns'], time()+1209600, '/', 'www.your-domain-goes-here.com', false); //this will fail if any part of page has been output- hope this works!
$count = $_POST['woocommerce-sort-by-columns'];
}
// else normal page load and no cookie
return $count;
}
add_filter('loop_shop_per_page','dl_sort_by_page');
add_action( 'woocommerce_before_shop_loop', 'woocommerce_catalog_page_ordering', 20 );
Related
Based on this (Change the displayed number of products in Woocommerce with Select dropdown) I use the following code to let the visitor display 20, 40 or 60 products on page:
//save and load the chosen option from session
function jc_get_products_per_page(){
global $woocommerce;
$default = 20;
$count = $default;
$options = jc_get_products_per_page_options();
// capture form data and store in session
if(isset($_POST['jc-woocommerce-products-per-page'])){
// set products per page from dropdown
$products_max = intval($_POST['jc-woocommerce-products-per-page']);
if($products_max != 0 && $products_max >= -1){
$woocommerce->session->jc_product_per_page = $products_max;
return $products_max;
}
}
// load product limit from session
if(isset($woocommerce->session->jc_product_per_page)){
// set products per page from woo session
$products_max = intval($woocommerce->session->jc_product_per_page);
if($products_max != 0 && $products_max >= -1){
return $products_max;
}
}
return $count;
}
add_filter('loop_shop_per_page','jc_get_products_per_page', 800);
//set the options for the dropdown
function jc_get_products_per_page_options(){
$options = apply_filters( 'jc_products_per_page', array(
20 => __('20', 'woocommerce'),
30 => __('30', 'woocommerce'),
60 => __('60', 'woocommerce')
));
return $options;
}
//display the dropdown on front-end
function jc_woocommerce_products_per_page(){
$options = jc_get_products_per_page_options();
$current_value = jc_get_products_per_page();
?>
<div id="products-per-page">
<div id="select_kaarten"><form action="" label="denny" method="POST" class="woocommerce-products-per-page">
<label></label>
<select name="jc-woocommerce-products-per-page" class="selectie" onchange="this.form.submit()">
<?php foreach($options as $value => $name): ?>
<option value="<?php echo $value; ?>" <?php selected($value, $current_value); ?>><?php echo $name; ?></option>
<?php endforeach; ?>
</select>
</form></div>
</div>
<?php
}
add_action('woocommerce_before_shop_loop', 'jc_woocommerce_products_per_page', 100);
remove_action( 'woocommerce_before_shop_loop', 'woocommerce_result_count', 20 );
// remove_action( 'woocommerce_before_shop_loop', 'woocommerce_catalog_ordering', 30 );
add_action( 'woocommerce_after_shop_loop', 'woocommerce_result_count', 8 );
This selector is shown on every category page, but I want to only run it on pages where the number of products is more than 20 products.
How can I achieve this?
This was actually quiet simple, just had to put the output in a if {} loop to check the number of products using
wc_get_loop_prop( 'total' ); . In the above code, I needed to output <div id="products-per-page"> only if wc_get_loop_prop( 'total' ) > 20 .
The complete code looks like this:
function jc_get_products_per_page(){
global $woocommerce;
$default = 30;
$count = $default;
$options = jc_get_products_per_page_options();
// capture form data and store in session
if(isset($_POST['jc-woocommerce-products-per-page'])){
// set products per page from dropdown
$products_max = intval($_POST['jc-woocommerce-products-per-page']);
if($products_max != 0 && $products_max >= -1){
$woocommerce->session->jc_product_per_page = $products_max;
return $products_max;
}
}
// load product limit from session
if(isset($woocommerce->session->jc_product_per_page)){
// set products per page from woo session
$products_max = intval($woocommerce->session->jc_product_per_page);
if($products_max != 0 && $products_max >= -1){
return $products_max;
}
}
return $count;
}
add_filter('loop_shop_per_page','jc_get_products_per_page', 800);
//set the options for the dropdown
function jc_get_products_per_page_options(){
$options = apply_filters( 'jc_products_per_page', array(
20 => __('20', 'woocommerce'),
30 => __('30', 'woocommerce'),
60 => __('60', 'woocommerce')
));
return $options;
}
//display the dropdown on front-end
function jc_woocommerce_products_per_page(){
$options = jc_get_products_per_page_options();
$current_value = jc_get_products_per_page();
?>
<?php
// SHOW ONLY IF MORE THAN 20 PRODUCTS
$aantalpr = wc_get_loop_prop( 'total' );
if ($aantalpr > 20) { ?>
<div id="products-per-page">
<div id="select_kaarten"><form action="" label="denny" method="POST" class="woocommerce-products-per-page">
<label></label>
<select name="jc-woocommerce-products-per-page" class="selectie" onchange="this.form.submit()">
<?php foreach($options as $value => $name): ?>
<option value="<?php echo $value; ?>" <?php selected($value, $current_value); ?>><?php echo $name; ?></option>
<?php endforeach; ?>
</select>
</form></div>
</div>
<?php
} else {
echo "";
}
}
add_action('woocommerce_before_shop_loop', 'jc_woocommerce_products_per_page', 100);
remove_action( 'woocommerce_before_shop_loop', 'woocommerce_result_count', 20 );
// remove_action( 'woocommerce_before_shop_loop', 'woocommerce_catalog_ordering', 30 );
add_action( 'woocommerce_after_shop_loop', 'woocommerce_result_count', 8 );
// add_action( 'woocommerce_after_shop_loop', 'woocommerce_catalog_ordering', 9 );
Currently I've got this bit of code to do post-per-page filter to my woocommerce shop
function ps_selectbox() {
$per_page = filter_input(INPUT_GET, 'perpage', FILTER_SANITIZE_NUMBER_INT);
ob_start();
echo '<div class="woocommerce-ordering">';
echo '<select onchange="if (this.value) window.location.href=this.value">';
$orderby_options = array(
'16' => '16 items per page',
'32' => '32 items per page',
'64' => '64 items per page'
);
foreach( $orderby_options as $value => $label ) {
echo "<option ".selected( $per_page, $value )." value='?perpage=$value'>$label</option>";
}
echo '</select>';
echo '</div>';
return ob_get_clean();
}
add_action( 'pre_get_posts', 'ps_pre_get_products_query' );
function ps_pre_get_products_query( $query ) {
$per_page = filter_input(INPUT_GET, 'perpage', FILTER_SANITIZE_NUMBER_INT);
if( $query->is_main_query() && !is_admin() ) {
$query->set( 'posts_per_page', $per_page );
}
}
It will append "?perpage=$value" to the url and change number of items per page in the shop.
But when it comes to search result page, it will clear the current query and replace it with just "?perpage=$value"
EX: "https://aaa.com/?s=C21&post_type=product" to "https://aaa.com/?perpage=16"
If I manually change the url to be ""https://aaa.com/?s=C21&post_type=product&perpage=32" it works.
I tried add_query_arg( $args ) and a condition check but it doesn't seem to work.
EX:
function ps_pre_get_products_query( $query ) {
$per_page = filter_input(INPUT_GET, 'perpage', FILTER_SANITIZE_NUMBER_INT);
if (is_search()) {
add_query_arg( $per_page );
}
elseif( $query->is_main_query() && !is_admin() ) {
$query->set( 'posts_per_page', $per_page );
}
}
But it doesn't seem to work.
Is there anyway I can keep this perpage dropdown feature in search result page?
Thanks in advance. Cheers.
Based on "Add a custom checkbox in WooCommerce checkout which value shows in admin edit order", I am trying to display custom radio buttons fields only if customer state is NewYork to let customer pick a delivery time in checkout page by choosing a delivery time option. Then admin could see the chosen delivery time in admin order edit pages.
This image will explain everything:
Here is my code attempt (with one checkbox for testing):
$user_state = get_user_meta( get_current_user_id(), 'billing_state')
if($user_state=='NY'){
add_action( 'woocommerce_review_order_before_submit', 'my_custom_checkout_field' );
function my_custom_checkout_field() {
echo '<div id="my_custom_checkout_field">';
woocommerce_form_field( 'my_field_name', array(
'type' => 'checkbox',
'class' => array('input-checkbox'),
'label' => __('My custom checkbox'),
'required'
), WC()->checkout->get_value( 'my_field_name' ) );
echo '</div>';
}
// Save the custom checkout field in the order meta, when checkbox has been checked
add_action( 'woocommerce_checkout_update_order_meta', 'custom_checkout_field_update_order_meta', 10, 1 );
function custom_checkout_field_update_order_meta( $order_id ) {
if ( ! empty( $_POST['my_field_name'] ) )
update_post_meta( $order_id, 'my_field_name', $_POST['my_field_name'] );
}
// Display the custom field result on the order edit page (backend) when checkbox has been checked
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_custom_field_on_order_edit_pages', 10, 1 );
function display_custom_field_on_order_edit_pages( $order ){
$my_field_name = get_post_meta( $order->get_id(), 'my_field_name', true );
if( $my_field_name == 1 )
echo '<p><strong>My custom field: </strong> <span style="color:red;">Is enabled</span></p>';
}}
But the custom field value isn't displayed. Any help is appreciated.
First you need to include your state condition (New York) inside the function that display your custom radio buttons on checkout page:
if( WC()->customer->get_shipping_state() == 'NY' ) {
// Do something for customers from "New York"
}
To make this possible Ajax and WC_Session is required, because checkout page is Ajax refreshed and it will not keep the customer choice.
So I have revisited all your existing code:
// Custom setting function: Here define your delivery options for "New york"
function get_newyork_delivery_options(){
return array(
'9am-2pm' => __('9 AM - 2 PM'),
'2pm-6pm' => __('2 PM - 6 PM'),
'6pm-9pm' => __('6 PM - 9 PM'),
);
}
// Display delivery custom radio buttons field in checkout for "New york" state
add_action( 'woocommerce_review_order_after_shipping', 'display_delivery_choice_field', 20 );
function display_delivery_choice_field(){
// Only for "New York" state
if( WC()->customer->get_shipping_state() == 'NY' ) :
$choice = WC()->session->get('delivery_choice');
// Display the radio buttons
echo '<tr class="delivery-options">
<th>' . __("Delivery time") . '<br><em>(' . __("for New York") . ')</em></th>
<td><span class="woocommerce-input-wrapper">';
foreach ( get_newyork_delivery_options() as $key => $label ) {
$checked = $choice == $key ? 'checked="checked"' : '';
$field_id = 'delivery_time' . $key;
echo '<label for="' . $field_id . '" class="radio " style="display:block">
<input type="radio" class="input-radio " id="' . $field_id . '" name="delivery_time" value="' . $key . '" ' . $checked . '> ' . $label;
echo '</label>';
}
echo '</span></td>
<tr>';
endif;
}
// jQuery - Ajax script
add_action( 'wp_footer', 'checkout_delivery_script' );
function checkout_delivery_script() {
// Only on Checkout
if( is_checkout() && ! is_wc_endpoint_url() ) :
if( WC()->session->__isset('delivery_choice') )
WC()->session->__unset('delivery_choice')
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;
$('form.checkout').on('change', 'input[name="delivery_time"]', function(){
var delivery = $(this).val();
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'delivery_choice',
'delivery_choice': delivery,
},
success: function (result) {
$('body').trigger('update_checkout');
},
});
});
});
</script>
<?php
endif;
}
// Get Ajax request and saving to WC session
add_action( 'wp_ajax_delivery_choice', 'get_delivery_choice' );
add_action( 'wp_ajax_nopriv_delivery_choice', 'get_delivery_choice' );
function get_delivery_choice() {
if ( isset($_POST['delivery_choice']) ) {
WC()->session->set('delivery_choice', esc_attr( $_POST['delivery_choice'] ) );
echo WC()->session->get('delivery_choice');
}
die();
}
// Save the chosen delivery time as order meta data
add_action('woocommerce_checkout_create_order', 'custom_checkout_field_added_as_order_meta', 10, 2 );
function custom_checkout_field_added_as_order_meta( $order, $data ) {
if ( isset( $_POST['delivery_option'] ) )
$order->add_meta_data( '_delivery_time', esc_attr( $_POST['delivery_time'] ) );
}
// Display the chosen delivery time on order totals lines everywhere (except admin)
add_action('woocommerce_get_order_item_totals', 'display_bacs_option_on_order_totals', 10, 3 );
function display_bacs_option_on_order_totals( $total_rows, $order, $tax_display ) {
if ( $delivery_time = $order->get_meta('_delivery_time') ) {
$sorted_total_rows = [];
foreach ( $total_rows as $key_row => $total_row ) {
$sorted_total_rows[$key_row] = $total_row;
if( $key_row === 'shipping' ) {
$sorted_total_rows['delivery_time'] = [
'label' => __( "Delivery time", "woocommerce"),
'value' => esc_html( get_newyork_delivery_options()[$delivery_time] ),
];
}
}
$total_rows = $sorted_total_rows;
}
return $total_rows;
}
// Display the chosen delivery option on admin order edit page for new york state
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'display_custom_field_on_order_edit_pages', 10, 1 );
function display_custom_field_on_order_edit_pages( $order ){
if( $key = $order->get_meta( '_delivery_time' ) ) {
$label = get_newyork_delivery_options()[$key];
echo '<p><strong>Delivery <em>(New York)</em>: </strong> <span style="color:green;">' . $label . '</span></p>';
}
}
Code goes in function.php file of the active child theme (or active theme). Tested and works.
I've got these 3 functions in my functions.php (sorry for the newbie code).
There's a submit button, and a dropdown. User selects a country in the list of options and press submit. The custom_product_query_tax_query is then run, and sorts the products by the slug Denmark or Europa. It's working, however, I need to press the submit button twice, or atleast reload the page manually for the changes to be visible.
Do I need to call the woocommerce_product_query before other content, or am I simply doing it all wrong?
//Before shop loop we inject the dropdown form with submit button.
//We also preselect the last option choosen, based on the country in session.
function report_button()
{
// display button only on posts
if ( !is_single() )
{
$retrive_data = WC()->session->get( 'Country' );
$denmark = '';
$europe = '';
if($retrive_data === 'Denmark')
{
$denmark = 'selected';
}
else
{
$europe = 'selected';
}
$content .= '<form action="" method="POST">
<select name="select_name[]" id="">
<option value="Europe" '. $europe .'>Vis alle produkter</option>
<option value="Denmark" '. $denmark .'>Vis kun lovlige i Danmark</option>
</select>
<input type="submit">
</form>';
echo $content;
}
}
add_action( 'woocommerce_before_shop_loop', 'report_button', 10 );
//On submit, we set the selected country in a session variable.
add_action( 'template_redirect', 'wpse149613_form_process' );
function wpse149613_form_process()
{
if(isset($_POST['select_name'])){ // select_name will be replaced with your input filed name
$getInput = $_POST['select_name']; // select_name will be replaced with your input filed name
foreach ($getInput as $option => $value) {
$selectedOption = $value;
WC()->session->set( 'Country' , $selectedOption );
}
}
}
//Custom woocommerce product query, show only products with Slug, Denmark.
function custom_product_query_tax_query( $q )
{
if( is_admin() ) return $q;
$retrive_data = WC()->session->get( 'Country' );
if ( $retrive_data == 'Denmark' )
{
$tax_query = (array) $q->get( 'tax_query' );
$tax_query[] = array(
'taxonomy' => 'product_tag',
'field' => 'slug',
'terms' => array( 'Denmark' ),
'operator' => 'IN'
);
$q->set( 'tax_query', $tax_query );
}
else
{
return $q;
}
}
add_filter( 'woocommerce_product_query', 'custom_product_query_tax_query', 10, 2 );
Alright, I seem to have found the answer elsewhere. The template_redirect function hook, needs somewhere to redirect to. I added this to the buttom of the code, and it works!
$current_url = home_url( add_query_arg( array(), $wp->request ) );
wp_redirect($current_url);
exit;
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>';
}
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;
}
There is an issue where on cart update using Woo 2.6 with AJAX, the select breaks. If you remove the trailing / here:
...', 'woocommerce' ) ?>" class="qty" />
To:
', 'woocommerce' ) ?>" class="qty">
It will now work.