411 lines
16 KiB
PHP
411 lines
16 KiB
PHP
<?php
|
|
/**
|
|
* Booster for WooCommerce - Module - Order Min/Max Quantities
|
|
*
|
|
* @version 3.7.0
|
|
* @since 2.9.0
|
|
* @author Algoritmika Ltd.
|
|
*/
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
if ( ! class_exists( 'WCJ_Order_Quantities' ) ) :
|
|
|
|
class WCJ_Order_Quantities extends WCJ_Module {
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @version 3.7.0
|
|
* @since 2.9.0
|
|
* @todo maybe rename the module to "Order Quantities" or "Order Product Quantities" or "Product Quantities"?
|
|
* @todo loop (`woocommerce_loop_add_to_cart_link`)
|
|
* @todo (maybe) order quantities by user roles
|
|
*/
|
|
function __construct() {
|
|
|
|
$this->id = 'order_quantities';
|
|
$this->short_desc = __( 'Order Min/Max Quantities', 'woocommerce-jetpack' );
|
|
$this->desc = __( 'Set min/max product quantities in WooCommerce order.', 'woocommerce-jetpack' );
|
|
$this->link_slug = 'woocommerce-order-min-max-quantities';
|
|
parent::__construct();
|
|
|
|
if ( $this->is_enabled() ) {
|
|
// Min/max quantities
|
|
if ( 'yes' === get_option( 'wcj_order_quantities_max_section_enabled', 'no' ) || 'yes' === get_option( 'wcj_order_quantities_min_section_enabled', 'no' ) ) {
|
|
add_action( 'woocommerce_checkout_process', array( $this, 'check_order_quantities' ) );
|
|
add_action( 'woocommerce_before_cart', array( $this, 'check_order_quantities' ) );
|
|
if ( 'yes' === get_option( 'wcj_order_quantities_stop_from_seeing_checkout', 'no' ) ) {
|
|
add_action( 'wp', array( $this, 'stop_from_seeing_checkout' ), PHP_INT_MAX );
|
|
}
|
|
add_filter( 'woocommerce_available_variation', array( $this, 'set_quantity_input_min_max_variation' ), PHP_INT_MAX, 3 );
|
|
if ( 'yes' === get_option( 'wcj_order_quantities_min_section_enabled', 'no' ) ) {
|
|
add_filter( 'woocommerce_quantity_input_min', array( $this, 'set_quantity_input_min' ), PHP_INT_MAX, 2 );
|
|
}
|
|
if ( 'yes' === get_option( 'wcj_order_quantities_max_section_enabled', 'no' ) ) {
|
|
add_filter( 'woocommerce_quantity_input_max', array( $this, 'set_quantity_input_max' ), PHP_INT_MAX, 2 );
|
|
}
|
|
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_script' ) );
|
|
}
|
|
// Quantity step
|
|
if ( 'yes' === get_option( 'wcj_order_quantities_step_section_enabled', 'no' ) ) {
|
|
add_filter( 'woocommerce_quantity_input_step', array( $this, 'set_quantity_input_step' ), PHP_INT_MAX, 2 );
|
|
}
|
|
// Meta box
|
|
$this->is_min_per_product_enabled = ( 'yes' === get_option( 'wcj_order_quantities_min_section_enabled', 'no' ) &&
|
|
'yes' === apply_filters( 'booster_option', 'no', get_option( 'wcj_order_quantities_min_per_item_quantity_per_product', 'no' ) ) );
|
|
$this->is_max_per_product_enabled = ( 'yes' === get_option( 'wcj_order_quantities_max_section_enabled', 'no' ) &&
|
|
'yes' === apply_filters( 'booster_option', 'no', get_option( 'wcj_order_quantities_max_per_item_quantity_per_product', 'no' ) ) );
|
|
$this->is_step_per_product_enabled = ( 'yes' === get_option( 'wcj_order_quantities_step_section_enabled', 'no' ) &&
|
|
'yes' === apply_filters( 'booster_option', 'no', get_option( 'wcj_order_quantities_step_per_product', 'no' ) ) );
|
|
if ( $this->is_min_per_product_enabled || $this->is_max_per_product_enabled || $this->is_step_per_product_enabled ) {
|
|
add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ) );
|
|
add_action( 'save_post_product', array( $this, 'save_meta_box' ), PHP_INT_MAX, 2 );
|
|
}
|
|
// Limit cart items (i.e. "Single Item Cart" Mode)
|
|
if ( 'yes' === apply_filters( 'booster_option', 'no', get_option( 'wcj_order_quantities_single_item_cart_enabled', 'no' ) ) ) {
|
|
add_filter( 'woocommerce_add_to_cart_validation', array( $this, 'single_item_cart' ), PHP_INT_MAX, 4 );
|
|
}
|
|
// For cart
|
|
add_filter( 'woocommerce_quantity_input_args', array( $this, 'set_quantity_input_args' ), PHP_INT_MAX, 2 );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* set_quantity_input_args.
|
|
*
|
|
* @version 3.7.0
|
|
* @since 3.7.0
|
|
*/
|
|
function set_quantity_input_args( $args, $product ) {
|
|
if ( 'yes' === get_option( 'wcj_order_quantities_min_section_enabled', 'no' ) ) {
|
|
$args['min_value'] = $this->set_quantity_input_min( $args['min_value'], $product );
|
|
}
|
|
if ( 'yes' === get_option( 'wcj_order_quantities_max_section_enabled', 'no' ) ) {
|
|
$args['max_value'] = $this->set_quantity_input_max( $args['max_value'], $product );
|
|
}
|
|
if ( 'yes' === get_option( 'wcj_order_quantities_step_section_enabled', 'no' ) ) {
|
|
$args['step'] = $this->set_quantity_input_step( $args['step'], $product );
|
|
}
|
|
return $args;
|
|
}
|
|
|
|
/**
|
|
* set_quantity_input_step.
|
|
*
|
|
* @version 3.7.0
|
|
* @since 3.7.0
|
|
*/
|
|
function set_quantity_input_step( $qty, $product ) {
|
|
if ( 'yes' === apply_filters( 'booster_option', 'no', get_option( 'wcj_order_quantities_step_per_product', 'no' ) ) ) {
|
|
if ( '' != ( $step = get_post_meta( wcj_get_product_id_or_variation_parent_id( $product ), '_' . 'wcj_order_quantities_step', true ) ) && 0 != $step ) {
|
|
return $step;
|
|
}
|
|
}
|
|
return ( 0 != ( $step = get_option( 'wcj_order_quantities_step', 1 ) ) ? $step : $qty );
|
|
}
|
|
|
|
/**
|
|
* single_item_cart.
|
|
*
|
|
* @version 3.6.0
|
|
* @since 3.6.0
|
|
*/
|
|
function single_item_cart( $passed, $product_id, $quantity = 0, $variation_id = 0 ) {
|
|
if ( ! WC()->cart->is_empty() ) {
|
|
if ( is_array( WC()->cart->cart_contents ) && 1 == count( WC()->cart->cart_contents ) && wcj_is_product_in_cart( ( 0 != $variation_id ? $variation_id : $product_id ) ) ) {
|
|
return $passed;
|
|
} else {
|
|
wc_add_notice( get_option( 'wcj_order_quantities_single_item_cart_message',
|
|
__( 'Only one item can be added to the cart. Clear the cart or finish the order, before adding another item to the cart.', 'woocommerce-jetpack' ) ), 'error' );
|
|
return false;
|
|
}
|
|
}
|
|
return $passed;
|
|
}
|
|
|
|
/**
|
|
* enqueue_script.
|
|
*
|
|
* @version 3.2.3
|
|
* @since 3.2.2
|
|
* @todo `force_on_add_to_cart` for simple products
|
|
* @todo make this optional?
|
|
*/
|
|
function enqueue_script() {
|
|
$_product = wc_get_product();
|
|
if ( $_product && $_product->is_type( 'variable' ) ) {
|
|
$quantities_options = array(
|
|
'reset_to_min' => ( 'reset_to_min' === get_option( 'wcj_order_quantities_variable_variation_change', 'do_nothing' ) ),
|
|
'reset_to_max' => ( 'reset_to_max' === get_option( 'wcj_order_quantities_variable_variation_change', 'do_nothing' ) ),
|
|
'force_on_add_to_cart' => ( 'yes' === get_option( 'wcj_order_quantities_variable_force_on_add_to_cart', 'no' ) ),
|
|
);
|
|
$product_quantities = array();
|
|
foreach ( $_product->get_available_variations() as $variation ) {
|
|
$product_quantities[ $variation['variation_id'] ] = array(
|
|
'min_qty' => $variation['min_qty'],
|
|
'max_qty' => $variation['max_qty'],
|
|
);
|
|
}
|
|
wp_enqueue_script( 'wcj-order-quantities', trailingslashit( wcj_plugin_url() ) . 'includes/js/wcj-order-quantities.js', array( 'jquery' ), WCJ()->version, true );
|
|
wp_localize_script( 'wcj-order-quantities', 'product_quantities', $product_quantities );
|
|
wp_localize_script( 'wcj-order-quantities', 'quantities_options', $quantities_options );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* get_product_quantity.
|
|
*
|
|
* @version 3.2.2
|
|
* @since 3.2.2
|
|
*/
|
|
function get_product_quantity( $min_or_max, $_product, $default_qty ) {
|
|
if ( 'no' === get_option( 'wcj_order_quantities_' . $min_or_max . '_section_enabled', 'no' ) ) {
|
|
return $default_qty;
|
|
}
|
|
if (
|
|
'yes' === apply_filters( 'booster_option', 'no', get_option( 'wcj_order_quantities_' . $min_or_max . '_per_item_quantity_per_product', 'no' ) ) &&
|
|
0 != ( $max_or_max_per_item_quantity_per_product = get_post_meta( wcj_get_product_id( $_product ), '_' . 'wcj_order_quantities_' . $min_or_max, true ) )
|
|
) {
|
|
return $max_or_max_per_item_quantity_per_product;
|
|
} elseif ( 0 != ( $max_or_max_per_item_quantity = apply_filters( 'booster_option', 0, get_option( 'wcj_order_quantities_' . $min_or_max . '_per_item_quantity', 0 ) ) ) ) {
|
|
return $max_or_max_per_item_quantity;
|
|
} else {
|
|
return $default_qty;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* set_quantity_input_min_max_variation.
|
|
*
|
|
* @version 3.2.2
|
|
* @since 3.2.2
|
|
*/
|
|
function set_quantity_input_min_max_variation( $args, $_product, $_variation ) {
|
|
$args['min_qty'] = $this->get_product_quantity( 'min', $_variation, $args['min_qty'] );
|
|
$args['max_qty'] = $this->get_product_quantity( 'max', $_variation, $args['max_qty'] );
|
|
$_max = $_variation->get_max_purchase_quantity();
|
|
if ( -1 != $_max && $args['max_qty'] > $_max ) {
|
|
$args['max_qty'] = $_max;
|
|
}
|
|
if ( $args['min_qty'] < 0 ) {
|
|
$args['min_qty'] = '';
|
|
}
|
|
if ( $args['max_qty'] < 0 ) {
|
|
$args['max_qty'] = '';
|
|
}
|
|
return $args;
|
|
}
|
|
|
|
/**
|
|
* set_quantity_input_min.
|
|
*
|
|
* @version 3.2.2
|
|
* @since 3.2.2
|
|
*/
|
|
function set_quantity_input_min( $qty, $_product ) {
|
|
if ( ! $_product->is_type( 'variable' ) ) {
|
|
$min = $this->get_product_quantity( 'min', $_product, $qty );
|
|
$_max = $_product->get_max_purchase_quantity();
|
|
return ( -1 == $_max || $min < $_max ? $min : $_max );
|
|
} else {
|
|
return $qty;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* set_quantity_input_max.
|
|
*
|
|
* @version 3.2.2
|
|
* @since 3.2.2
|
|
*/
|
|
function set_quantity_input_max( $qty, $_product ) {
|
|
if ( ! $_product->is_type( 'variable' ) ) {
|
|
$max = $this->get_product_quantity( 'max', $_product, $qty );
|
|
$_max = $_product->get_max_purchase_quantity();
|
|
return ( -1 == $_max || $max < $_max ? $max : $_max );
|
|
} else {
|
|
return $qty;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* stop_from_seeing_checkout.
|
|
*
|
|
* @version 3.2.3
|
|
* @since 2.9.0
|
|
*/
|
|
function stop_from_seeing_checkout() {
|
|
if ( ! isset( WC()->cart ) ) {
|
|
return;
|
|
}
|
|
if ( ! is_checkout() ) {
|
|
return;
|
|
}
|
|
$cart_item_quantities = WC()->cart->get_cart_item_quantities();
|
|
if ( empty( $cart_item_quantities ) || ! is_array( $cart_item_quantities ) ) {
|
|
return;
|
|
}
|
|
$cart_total_quantity = array_sum( $cart_item_quantities );
|
|
if ( 'yes' === get_option( 'wcj_order_quantities_max_section_enabled', 'no' ) ) {
|
|
if ( ! $this->check_quantities( 'max', $cart_item_quantities, $cart_total_quantity, false, true ) ) {
|
|
wp_safe_redirect( wc_get_cart_url() );
|
|
exit;
|
|
}
|
|
}
|
|
if ( 'yes' === get_option( 'wcj_order_quantities_min_section_enabled', 'no' ) ) {
|
|
if ( ! $this->check_quantities( 'min', $cart_item_quantities, $cart_total_quantity, false, true ) ) {
|
|
wp_safe_redirect( wc_get_cart_url() );
|
|
exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* print_message.
|
|
*
|
|
* @version 2.9.0
|
|
* @since 2.9.0
|
|
*/
|
|
function print_message( $message_type, $_is_cart, $required_quantity, $total_quantity, $_product_id = 0 ) {
|
|
if ( $_is_cart ) {
|
|
if ( 'no' === get_option( 'wcj_order_quantities_cart_notice_enabled', 'no' ) ) {
|
|
return;
|
|
}
|
|
}
|
|
switch ( $message_type ) {
|
|
case 'max_cart_total_quantity':
|
|
$replaced_values = array(
|
|
'%max_cart_total_quantity%' => $required_quantity,
|
|
'%cart_total_quantity%' => $total_quantity,
|
|
);
|
|
$message_template = get_option( 'wcj_order_quantities_max_cart_total_message',
|
|
__( 'Maximum allowed order quantity is %max_cart_total_quantity%. Your current order quantity is %cart_total_quantity%.', 'woocommerce-jetpack' ) );
|
|
break;
|
|
case 'min_cart_total_quantity':
|
|
$replaced_values = array(
|
|
'%min_cart_total_quantity%' => $required_quantity,
|
|
'%cart_total_quantity%' => $total_quantity,
|
|
);
|
|
$message_template = get_option( 'wcj_order_quantities_min_cart_total_message',
|
|
__( 'Minimum allowed order quantity is %min_cart_total_quantity%. Your current order quantity is %cart_total_quantity%.', 'woocommerce-jetpack' ) );
|
|
break;
|
|
case 'max_per_item_quantity':
|
|
$_product = wc_get_product( $_product_id );
|
|
$replaced_values = array(
|
|
'%max_per_item_quantity%' => $required_quantity,
|
|
'%item_quantity%' => $total_quantity,
|
|
'%product_title%' => $_product->get_title(),
|
|
);
|
|
$message_template = get_option( 'wcj_order_quantities_max_per_item_message',
|
|
__( 'Maximum allowed quantity for %product_title% is %max_per_item_quantity%. Your current item quantity is %item_quantity%.', 'woocommerce-jetpack' ) );
|
|
break;
|
|
case 'min_per_item_quantity':
|
|
$_product = wc_get_product( $_product_id );
|
|
$replaced_values = array(
|
|
'%min_per_item_quantity%' => $required_quantity,
|
|
'%item_quantity%' => $total_quantity,
|
|
'%product_title%' => $_product->get_title(),
|
|
);
|
|
$message_template = get_option( 'wcj_order_quantities_min_per_item_message',
|
|
__( 'Minimum allowed quantity for %product_title% is %min_per_item_quantity%. Your current item quantity is %item_quantity%.', 'woocommerce-jetpack' ) );
|
|
break;
|
|
}
|
|
$_notice = str_replace( array_keys( $replaced_values ), array_values( $replaced_values ), $message_template );
|
|
if ( $_is_cart ) {
|
|
wc_print_notice( $_notice, 'notice' );
|
|
} else {
|
|
wc_add_notice( $_notice, 'error' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* check_quantities.
|
|
*
|
|
* @version 3.2.2
|
|
* @since 2.9.0
|
|
*/
|
|
function check_quantities( $min_or_max, $cart_item_quantities, $cart_total_quantity, $_is_cart, $_return ) {
|
|
if ( 0 != ( $min_or_max_cart_total_quantity = get_option( 'wcj_order_quantities_' . $min_or_max . '_cart_total_quantity', 0 ) ) ) {
|
|
if (
|
|
( 'max' === $min_or_max && $cart_total_quantity > $min_or_max_cart_total_quantity ) ||
|
|
( 'min' === $min_or_max && $cart_total_quantity < $min_or_max_cart_total_quantity )
|
|
) {
|
|
if ( $_return ) {
|
|
return false;
|
|
} else {
|
|
$this->print_message( $min_or_max . '_cart_total_quantity', $_is_cart, $min_or_max_cart_total_quantity, $cart_total_quantity );
|
|
}
|
|
}
|
|
}
|
|
if ( apply_filters( 'booster_option', 'no', get_option( 'wcj_order_quantities_' . $min_or_max . '_per_item_quantity_per_product', 'no' ) ) ) {
|
|
foreach ( $cart_item_quantities as $_product_id => $cart_item_quantity ) {
|
|
if ( 0 != ( $max_or_max_per_item_quantity = get_post_meta( $_product_id, '_' . 'wcj_order_quantities_' . $min_or_max, true ) ) ) {
|
|
if (
|
|
( 'max' === $min_or_max && $cart_item_quantity > $max_or_max_per_item_quantity ) ||
|
|
( 'min' === $min_or_max && $cart_item_quantity < $max_or_max_per_item_quantity )
|
|
) {
|
|
if ( $_return ) {
|
|
return false;
|
|
} else {
|
|
$this->print_message( $min_or_max . '_per_item_quantity', $_is_cart, $max_or_max_per_item_quantity, $cart_item_quantity, $_product_id );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( 0 != ( $max_or_max_per_item_quantity = apply_filters( 'booster_option', 0, get_option( 'wcj_order_quantities_' . $min_or_max . '_per_item_quantity', 0 ) ) ) ) {
|
|
foreach ( $cart_item_quantities as $_product_id => $cart_item_quantity ) {
|
|
if (
|
|
'yes' === apply_filters( 'booster_option', 'no', get_option( 'wcj_order_quantities_' . $min_or_max . '_per_item_quantity_per_product', 'no' ) ) &&
|
|
0 != get_post_meta( $_product_id, '_' . 'wcj_order_quantities_' . $min_or_max, true )
|
|
) {
|
|
continue;
|
|
}
|
|
if (
|
|
( 'max' === $min_or_max && $cart_item_quantity > $max_or_max_per_item_quantity ) ||
|
|
( 'min' === $min_or_max && $cart_item_quantity < $max_or_max_per_item_quantity )
|
|
) {
|
|
if ( $_return ) {
|
|
return false;
|
|
} else {
|
|
$this->print_message( $min_or_max . '_per_item_quantity', $_is_cart, $max_or_max_per_item_quantity, $cart_item_quantity, $_product_id );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( $_return ) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* check_order_quantities.
|
|
*
|
|
* @version 2.9.0
|
|
* @since 2.9.0
|
|
*/
|
|
function check_order_quantities() {
|
|
if ( ! isset( WC()->cart ) ) {
|
|
return;
|
|
}
|
|
$cart_item_quantities = WC()->cart->get_cart_item_quantities();
|
|
if ( empty( $cart_item_quantities ) || ! is_array( $cart_item_quantities ) ) {
|
|
return;
|
|
}
|
|
$cart_total_quantity = array_sum( $cart_item_quantities );
|
|
$_is_cart = is_cart();
|
|
if ( 'yes' === get_option( 'wcj_order_quantities_max_section_enabled', 'no' ) ) {
|
|
$this->check_quantities( 'max', $cart_item_quantities, $cart_total_quantity, $_is_cart, false );
|
|
}
|
|
if ( 'yes' === get_option( 'wcj_order_quantities_min_section_enabled', 'no' ) ) {
|
|
$this->check_quantities( 'min', $cart_item_quantities, $cart_total_quantity, $_is_cart, false );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
endif;
|
|
|
|
return new WCJ_Order_Quantities();
|