Mastering WooCommerce Hooks: Setting Minimum And Maximum Order Quantities

I’ve been thinking about continuing my Mastering WooCommerce Hooks series here on my personal Website instead of another Website. It has been a long time since I write anything related to WooCommerce and WordPress so hopefully this series will help me do just that, about one post every week or so.

This week’s article we’ll be building a simple interface on the Add New Product page where you’ll be able to set Minimum and Maximum per order quantities. Not only we’ll be implementing these fields, there is going to be a third one which will control the “step” or the amount to be incremented everytime someone clicks on the little up arrow on the product description page.

The image below shows exactly what it will look on the back-end of the site on the Add New Product page.

Building the WordPress/WooCommerce Plugin

We are going to be developing this as a plugin so that we can re-use it if we wanted to. Below is the code for the plugin and the first part of the implementation which happens to be registering the input fields to the Product data section you normally see when setting up a product in WooCommerce.

Registering the Input Fields

<?php
/*
Plugin Name: WC Minimum & Maximum Order Quantities
Plugin URI: https://www.wpsuperstar.com/
Description: Allows you to quickly set minimum and maximum order quantities for products.
Author: Yojance Rabelo
Author URI: https://www.wpsuperstar.com/
Version: 0.0.1
License: GPL version 2 or later - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*/

class WPS_Minimum_Maximum_Order_Quantities {

    public function __construct() {
        $this->init();
    }

    public function init() {
        add_action( 'woocommerce_product_options_inventory_product_data',       array( $this, 'register_min_max_input_fields' ) );
    }

    public function register_min_max_input_fields() {
        echo '<div class="options_group show_if_simple show_if_grouped">';

        woocommerce_wp_text_input( array(
            'id'                => '_product_min_order_qty',
            'label'             => __( 'Minimum Order Qty', 'wps' ),
            'desc_tip'          => true,
            'description'       => __( '', 'wps' ),
            'type'              => 'number',
        ) );

        woocommerce_wp_text_input( array(
            'id'                => '_product_max_order_qty',
            'label'             => __( 'Maximum Order Qty', 'wps' ),
            'desc_tip'          => true,
            'description'       => __( '', 'wps' ),
            'type'              => 'number',
        ) );

        woocommerce_wp_text_input( array(
            'id'                => '_product_incremental_step',
            'label'             => __( 'Incrementing Step', 'wps' ),
            'desc_tip'          => true,
            'description'       => __( '', 'wps' ),
            'type'              => 'number',
        ) );
        echo '</div>';
    }


}

new WPS_Minimum_Maximum_Order_Quantities();

Go ahead and activate the plugin now and navigate to the Add New Product screen or simply try to edit one of your existing products.

Saving These New Product Fields

Add a new method to our class (remember we are building this as a WordPress plugin using PHP classes) so that we can save the data when present or delete it when not needed.

public function init() {
        add_action( 'woocommerce_product_options_inventory_product_data',       array( $this, 'register_min_max_input_fields' ) );
        add_action( 'save_post',                                                array( $this, 'save_custom_product_settings' ), 10, 1 );
    }

public function save_custom_product_settings( $post_id ) {
    if( 'product' == get_post_type( $post_id ) ) {
        // Some ternary operators
        isset( $_POST['_product_min_order_qty'] ) && ! empty( $_POST['_product_min_order_qty'] )
            ? update_post_meta( $post_id, '_product_min_order_qty', $_POST['_product_min_order_qty'] )
            : delete_post_meta( $post_id, '_product_min_order_qty' );

        isset( $_POST['_product_max_order_qty'] ) && ! empty( $_POST['_product_max_order_qty'] )
            ? update_post_meta( $post_id, '_product_max_order_qty', $_POST['_product_max_order_qty'] )
            : delete_post_meta( $post_id, '_product_max_order_qty' );

        isset( $_POST['_product_incremental_step'] ) && ! empty( $_POST['_product_incremental_step'] )
            ? update_post_meta( $post_id, '_product_incremental_step', $_POST['_product_incremental_step'] )
            : delete_post_meta( $post_id, '_product_incremental_step' );
    }
}

Making It All Work

Now here comes the fun part. Making it all work on the front-end through the product description page. Let’s add another hook to the init() method and then implement the function which is going to change the default values on those indivudual products that you have set a minimum, maximum or step value.

public function init() {
        add_action( 'woocommerce_product_options_inventory_product_data',       array( $this, 'register_min_max_input_fields' ) );
        add_action( 'save_post',                                                array( $this, 'save_custom_product_settings' ), 10, 1 );
        add_filter( 'woocommerce_quantity_input_args',                          array( $this, 'set_min_max_step_product_settings' ), 10, 2 );
    }

Fun Part

public function set_min_max_step_product_settings( $prod_defaults, WC_Product $product ) {
        // Check first to make sure the product type is either simple or grouped
        if( in_array( $product->get_type(), array( 'simple', 'grouped' ) ) ) {
            // Check for the minimum order quantity
            $min_order_qty = get_post_meta( $product->id, '_product_min_order_qty', true );
            ! empty( $min_order_qty ) ? $prod_defaults['min_value'] = $min_order_qty : 0;

            // Check for the maximum order quantity
            $max_order_qty = get_post_meta( $product->id, '_product_max_order_qty', true );
            ! empty( $max_order_qty ) ? $prod_defaults['max_value'] = $max_order_qty : 0;

            // Check for incremental step
            $incremental_step = get_post_meta( $product->id, '_product_incremental_step', true );
            ! empty( $incremental_step ) ? $prod_defaults['step'] = $incremental_step : 0;
        }
        // Always return the product defaults
        return $prod_defaults;
    }

Here is the final code with comments and ready to be dropped into the plugins folder.

<?php
/*
Plugin Name: WC Minimum & Maximum Order Quantities
Plugin URI: https://www.wpsuperstar.com/
Description: Allows you to quickly set minimum and maximum order quantities for products.
Author: Yojance Rabelo
Author URI: https://www.wpsuperstar.com/
Version: 0.0.1
License: GPL version 2 or later - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*/

class WPS_Minimum_Maximum_Order_Quantities {

    /**
     * WPS_Minimum_Maximum_Order_Quantities constructor
     */
    public function __construct() {
        $this->init();
    }

    public function init() {
        // Register Minimum, Maximum and Incremental Steps input fields
        add_action( 'woocommerce_product_options_inventory_product_data',       array( $this, 'register_min_max_input_fields' ) );
        // Save the Minimum, Maximum and Incremental Steps when set
        add_action( 'save_post',                                                array( $this, 'save_custom_product_settings' ), 10, 1 );
        // Set the Minimum, Maximum and Incremental Steps for a product when it's clearly specified on the back-end.
        add_filter( 'woocommerce_quantity_input_args',                          array( $this, 'set_min_max_step_product_settings' ), 10, 2 );
    }

    /**
     * Register Minimum, Maximum and Incremental Steps input fields
     */
    public function register_min_max_input_fields() {
        echo '<div class="options_group show_if_simple show_if_grouped">';

        woocommerce_wp_text_input( array(
            'id'                => '_product_min_order_qty',
            'label'             => __( 'Minimum Order Qty', 'wps' ),
            'desc_tip'          => true,
            'description'       => __( '', 'wps' ),
            'type'              => 'number',
        ) );

        woocommerce_wp_text_input( array(
            'id'                => '_product_max_order_qty',
            'label'             => __( 'Maximum Order Qty', 'wps' ),
            'desc_tip'          => true,
            'description'       => __( '', 'wps' ),
            'type'              => 'number',
        ) );

        woocommerce_wp_text_input( array(
            'id'                => '_product_incremental_step',
            'label'             => __( 'Incrementing Step', 'wps' ),
            'desc_tip'          => true,
            'description'       => __( '', 'wps' ),
            'type'              => 'number',
        ) );
        echo '</div>';
    }

    /**
     * Save the Minimum, Maximum and Incremental Steps when set
     * TODO: Turn into a loop to decrease repeated code
     * @param $post_id
     */
    public function save_custom_product_settings( $post_id ) {
        if( 'product' == get_post_type( $post_id ) ) {
            // Some ternary operators
            isset( $_POST['_product_min_order_qty'] ) && ! empty( $_POST['_product_min_order_qty'] )
                ? update_post_meta( $post_id, '_product_min_order_qty', $_POST['_product_min_order_qty'] )
                : delete_post_meta( $post_id, '_product_min_order_qty' );

            isset( $_POST['_product_max_order_qty'] ) && ! empty( $_POST['_product_max_order_qty'] )
                ? update_post_meta( $post_id, '_product_max_order_qty', $_POST['_product_max_order_qty'] )
                : delete_post_meta( $post_id, '_product_max_order_qty' );

            isset( $_POST['_product_incremental_step'] ) && ! empty( $_POST['_product_incremental_step'] )
                ? update_post_meta( $post_id, '_product_incremental_step', $_POST['_product_incremental_step'] )
                : delete_post_meta( $post_id, '_product_incremental_step' );
        }
    }

    /**
     * Set the Minimum, Maximum and Incremental Steps for a product when it's clearly specified on the back-end.
     *
     * @param $prod_defaults
     * @param WC_Product $product
     * @return array
     */
    public function set_min_max_step_product_settings( $prod_defaults, WC_Product $product ) {
        // Check first to make sure the product type is either simple or grouped
        if( in_array( $product->get_type(), array( 'simple', 'grouped' ) ) ) {
            // Check for the minimum order quantity
            $min_order_qty = get_post_meta( $product->id, '_product_min_order_qty', true );
            ! empty( $min_order_qty ) ? $prod_defaults['min_value'] = $min_order_qty : 0;

            // Check for the maximum order quantity
            $max_order_qty = get_post_meta( $product->id, '_product_max_order_qty', true );
            ! empty( $max_order_qty ) ? $prod_defaults['max_value'] = $max_order_qty : 0;

            // Check for incremental step
            $incremental_step = get_post_meta( $product->id, '_product_incremental_step', true );
            ! empty( $incremental_step ) ? $prod_defaults['step'] = $incremental_step : 1;
        }
        // Always return the product defaults
        return $prod_defaults;
    }
}

new WPS_Minimum_Maximum_Order_Quantities();

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s