WooCommerce Bulk Purchasing

How to apply discount on bulk purchasing and allow price filtering by the discounted price?
Update the discount percent that each quantity grant (for variable products it will be displayed only after adding to cart, those pages should be excluded in the cache plugin):

add_filter( 'woocommerce_price_filter_widget_step', '__return_zero' );
add_filter( 'woocommerce_price_filter_widget_min_amount' , '__return_zero' );
add_action( 'woocommerce_widget_price_filter_start', 'wc_add_quantity_field' );
add_filter( 'posts_clauses', 'wc_pre_price_filter_post_clauses', 8, 2 );
add_filter( 'posts_clauses', 'wc_price_filter_excluded_products', 20, 2 );
add_filter( 'the_posts', 'wc_handle_get_posts', 10, 2 );
add_action( 'wp_ajax_wc_save_products_quantity', 'wc_save_products_quantity' );
add_action( 'wp_ajax_nopriv_wc_save_products_quantity', 'wc_save_products_quantity' );
add_filter( 'woocommerce_loop_add_to_cart_args', 'wc_set_default_quantity', 10, 2 );
add_filter( 'woocommerce_product_add_to_cart_text', 'wc_set_text_quantity', 10, 2 );
add_filter( 'woocommerce_quantity_input_args', 'wc_quantity_input_args', 10, 2 );
add_action( 'woocommerce_before_calculate_totals', 'wc_quantity_based_pricing' );
add_action( 'woocommerce_after_add_to_cart_button', 'wc_product_price_quantity' );
add_action( 'wp_ajax_wc_display_total', 'wc_display_total' );
add_action( 'wp_ajax_nopriv_wc_display_total', 'wc_display_total' );
add_filter( 'woocommerce_get_price_suffix', 'wc_change_product_suffix', 10, 2 );
if ( ! is_admin() ) {
	add_filter( 'woocommerce_get_price_html', 'wc_adjust_price_display', 10, 2 );
}

function wc_get_discount( $product_id = '', $quantity = '' ) {
	$excluded_cat = [ '36' ];
	$max_discount = '40';
	if ( empty( $quantity ) ) {
		$quantity = WC()->session->get( 'products_quantity' );
	}
	if ( $quantity && ( empty( $product_id ) || ! array_intersect( $excluded_cat, wc_get_product_cat_ids( $product_id ) ) ) ) {
		$quantities = [
			10	=> 0,
			25	=> 10,
			50	=> 12.5,
			80	=> 16,
		];
		foreach ( $quantities as $num => $max ) {
			if ( $quantity < $max ) {
				$percent = $num;
				break;
			}
		}
		return ( isset( $percent ) ? $percent : $max_discount ) / 100;
	}
	return 0;
}

function wc_price_filter_excluded_products( $args, $wp_query ) {
	$excluded_cat = [ '36' ];
	$args['where'] = str_replace( 'wc_product_meta_lookup.max_price', 'wc_product_meta_lookup.max_price AND ( wp_posts.ID NOT IN ( SELECT object_id FROM wp_term_relationships WHERE term_taxonomy_id IN ( ' . implode( ',', $excluded_cat ) . ' ) ) ) OR ( ( wp_posts.ID IN ( SELECT object_id FROM wp_term_relationships WHERE term_taxonomy_id IN ( ' . implode( ',', $excluded_cat ) . ' ) ) ) AND (' . ( isset( $_POST['org_max_price'] ) ? $_POST['org_max_price'] : PHP_INT_MAX ) . '<wc_product_meta_lookup.min_price OR ' . ( isset( $_POST['org_min_price'] ) ? $_POST['org_min_price'] : 0 ) . '>wc_product_meta_lookup.max_price ) )', $args['where'] );
	return $args;
}

function wc_change_product_suffix( $html, $product ) {
	$excluded_cat = [ '36' ];
	return is_product() && is_single( $product->get_id() ) && ! array_intersect( $excluded_cat, wc_get_product_cat_ids( $product->get_id() ) ) ? " Per unit" : $html;
}

function wc_add_quantity_field() {
	woocommerce_form_field( 'products_quantity', [
		'type'		=> 'number',
		'label'		=> __( 'Quantity', 'woocommerce' ),
		'custom_attributes' => [ 'min' => '0' ],
	], WC()->session->get( 'products_quantity' ) ); ?>
	<script type="text/javascript">
	jQuery( function( $ ) {
		$( '#products_quantity' ).on( 'change', function() {
			var data = {
				'action'	: 'wc_save_products_quantity',
				'products_quantity'	: $( this ).val(),
			};
			$.post( '<?php echo admin_url( 'admin-ajax.php' ); ?>', data, function( response ) {
				location.reload();
			} );
		} );
	} );
	</script>
<?php }

function wc_pre_price_filter_post_clauses( $args, $wp_query ) {
	if ( isset( $_GET['min_price'] ) ) {
		$_POST['org_min_price'] = wc_clean( $_GET['min_price'] );
		$_GET['min_price'] = floor( $_GET['min_price'] / ( 1 - wc_get_discount() ) );
	}
	if ( isset( $_GET['max_price'] ) ) {
		$_POST['org_max_price'] = wc_clean( $_GET['max_price'] );
		$_GET['max_price'] = ceil( $_GET['max_price'] / ( 1 - wc_get_discount() ) );
	}
	return $args;
}

function wc_handle_get_posts( $posts, $query ) {
	if ( 'product_query' === $query->get( 'wc_query' ) ) {
		remove_filter( 'posts_clauses', 'wc_pre_price_filter_post_clauses', 8, 2 );
		if ( isset( $_POST['org_min_price'], $_GET['min_price'] ) ) {
			$_GET['min_price'] = $_POST['org_min_price'];
		}
		if ( isset( $_POST['org_max_price'], $_GET['max_price'] ) ) {
			$_GET['max_price'] = $_POST['org_max_price'];
		}
	}
	return $posts;
}

function wc_save_products_quantity() {
	if ( isset( $_POST['products_quantity'] ) ) {
		if ( isset( WC()->session ) && ! WC()->session->has_session() ) {
			WC()->session->set_customer_session_cookie( true );
		}
		WC()->session->set( 'products_quantity', wc_clean( $_POST['products_quantity'] ) );
	}
	wp_send_json( '' );
}

function wc_set_default_quantity( $args, $product ) {
	$quantity = WC()->session->get( 'products_quantity' );
	if ( $quantity ) {
		$args['quantity'] = $quantity;
	}
	return $args;
}

function wc_set_text_quantity( $text, $product ) {
	return $product->is_purchasable() && $product->is_in_stock() ? $text . ' ' . WC()->session->get( 'products_quantity' ) : $text;
}

function wc_quantity_input_args( $args, $product ) {
	$quantity = WC()->session->get( 'products_quantity' );
	if ( $quantity && 'quantity' === $args['input_name'] ) {
		$args['input_value'] = $quantity;
	}
	return $args;
}

function wc_quantity_based_pricing( $cart ) {
	if ( ( ! is_admin() || wp_doing_ajax() ) && 2 > did_action( 'woocommerce_before_calculate_totals' ) ) {
		foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
			$discount = wc_get_discount( $cart_item['data']->get_id(), $cart_item['quantity'] );
			if ( $discount ) {
				$cart_item['data']->set_price( round( $cart_item['data']->get_price() * ( 1 - $discount ), wc_get_price_decimals() ) );
			}
		}
	}
}

function wc_product_price_quantity() {
	global $product;
	if ( $product->is_type( 'simple' ) ) {
		echo '<div id="subtotal" style="display: inline-block;"></div>'; ?>
		<script type="text/javascript">
		jQuery( function( $ ) {
			$( 'input[name=quantity]' ).each( function() { display_prices( $( this ) ) } );
			$( 'input[name=quantity]' ).on( 'change', function() { display_prices( $( this ) ) } );
			function display_prices( field ) {
				var data = {
					'action'	: 'wc_display_total',
					'quantity'	: field.val(),
					'product_id'	: $( '.single_add_to_cart_button' ).val(),
				};
				$.post( '<?php echo admin_url( 'admin-ajax.php' ); ?>', data, function( response ) {
					if ( 'discount' in response ) {
						$( '#subtotal' ).html( '<strong>Total</strong> ' + response.subtotal + '<br><strong>Save</strong> ' + response.discount + '<br><strong>Total after discount</strong> ' + response.total );
					} else {
						$( '#subtotal' ).html( '<strong>Total</strong> ' + response.subtotal );
					}
				} );
			}
		} );
		</script>
	<?php }
}

function wc_display_total() {
	if ( isset( WC()->session ) && ! WC()->session->has_session() ) {
		WC()->session->set_customer_session_cookie( true );
	}
	WC()->session->set( 'products_quantity', wc_clean( $_POST['quantity'] ) );
	$discount_percent = wc_get_discount( $_POST['product_id'], $_POST['quantity'] );
	$product_price = wc_get_price_to_display( wc_get_product( $_POST['product_id'] ) );
	$subtotal = $product_price * $_POST['quantity'];
	if ( $discount_percent ) {
		$total = round( $product_price * ( 1 - $discount_percent ), wc_get_price_decimals() ) * $_POST['quantity'];
		wp_send_json( [ 'subtotal' => wc_price( $subtotal ), 'total' => wc_price( $total ), 'discount' => wc_price( $subtotal - $total ) ] );
	} else {
		wp_send_json( [ 'subtotal' => wc_price( $subtotal ) ] );
	}
}

function wc_adjust_price_display( $price_html, $product ) {
	$quantity = WC()->session->get( 'products_quantity' );
	$discount = wc_get_discount( $product->get_id() );
	return $quantity && $product->is_type( 'simple' ) && is_archive() && $discount ? '<span style="color:red;"><del>price: ' . $price_html . '</del></span><br>discounted price: ' . wc_price( wc_get_price_to_display( $product ) * ( 1 - $discount ) ) : $price_html;
}

Leave a comment

Your email address will not be published. Required fields are marked *