Premium add-on for Bricks Builder

Adding Quantity Input Field to Bricks Mini Cart element

The bricks builder has a native side cart element (Mini Cart) for the WooCommerce site. In this tutorial, I shall show how we can add the quantity field with the ‘+’ and ‘-‘ buttons there. So the customer can easily update the cart item’s quantity from there without any page refresh.

Quantity Input Field in Mini Cart
Quantity Input Field in Mini Cart

Step 1: Adding the Quantity Input Field

Add the following PHP code to your site. You can use the Bricks Child theme’s function.php file or any 3rd party snippets plugin like WPCodex.[edd_restrict id=”12,14,2474,3068,96772,98850,98847,98844,98841″ message=”Customers of BricksUltimate addon can view this content after login to the site. Non-BricksUltimate addon’s users will buy this tutorial separately. See the BUY NOW button below.”]

/**
 * Add quantity field to bricks mini cart element
 */
add_filter( 'woocommerce_widget_cart_item_quantity', 'buwoo_mini_cart_quantity', 10, 3 );
function buwoo_mini_cart_quantity( $price, $cart_item, $cart_item_key ) {
	$product_price = apply_filters( 'woocommerce_cart_item_price', WC()->cart->get_product_price( $cart_item['data'] ), $cart_item, $cart_item_key );

	if ( WC()->cart->display_prices_including_tax() ) {
		$product_price = wc_get_price_including_tax( $cart_item['data'] );
	} else {
		$product_price = wc_get_price_excluding_tax( $cart_item['data'] );
	}

	/* WPC Product Bundles */
	if ( ( isset( $cart_item['woosb_ids'], $cart_item['woosb_price'], $cart_item['woosb_fixed_price'] ) && ! $cart_item['woosb_fixed_price'] ) 
		|| ( isset( $cart_item['woosb_parent_id'], $cart_item['woosb_price'], $cart_item['woosb_fixed_price'] ) && $cart_item['woosb_fixed_price'] ) ) {
	    $product_price = $cart_item['woosb_price'];
	}

	$product = $cart_item['data'];
	$quantity = $cart_item['quantity'];

	$args = array(
		'input_id'     => uniqid( 'quantity_' ),
		'input_name'   => 'quantity',
		'input_value'  => $quantity,
		'classes'      => apply_filters( 'woocommerce_quantity_input_classes', array( 'input-text', 'qty', 'text' ), $product ),
		'max_value'    => apply_filters( 'woocommerce_quantity_input_max', $product->get_max_purchase_quantity(), $product ),
		'min_value'    => apply_filters( 'woocommerce_quantity_input_min', $product->get_min_purchase_quantity(), $product ),
		'step'         => apply_filters( 'woocommerce_quantity_input_step', 1, $product ),
		'pattern'      => apply_filters( 'woocommerce_quantity_input_pattern', has_filter( 'woocommerce_stock_amount', 'intval' ) ? '[0-9]*' : '' ),
		'inputmode'    => apply_filters( 'woocommerce_quantity_input_inputmode', has_filter( 'woocommerce_stock_amount', 'intval' ) ? 'numeric' : '' ),
		'product_name' => $product ? $product->get_title() : '',
		'placeholder'  => apply_filters( 'woocommerce_quantity_input_placeholder', '', $product ),
		'autocomplete' => apply_filters( 'woocommerce_quantity_input_autocomplete', 'off', $product ),
	);

	// Apply sanity to min/max args - min cannot be lower than 0.
	$args['min_value'] = max( $args['min_value'], 0 );
	$args['max_value'] = 0 < $args['max_value'] ? $args['max_value'] : '';

	// Max cannot be lower than min if defined.
	if ( '' !== $args['max_value'] && $args['max_value'] < $args['min_value'] ) {
		$args['max_value'] = $args['min_value'];
	}

	if( class_exists( 'Morningtrain\WooAdvancedQTY\Plugin\Controllers\InputArgsController' ) ) {
					$advnargs = Morningtrain\WooAdvancedQTY\Plugin\Controllers\InputArgsController::applyArgs(array(), $cart_item['product_id'], true);
					if( isset( $advnargs['min_value'] ) && $advnargs['min_value'] > $args['min_value'] )
						$args['min_value'] = $advnargs['min_value'];
					
					if( isset( $advnargs['max_value'] ) && $advnargs['max_value'] > $args['max_value'] )
						$args['max_value'] = $advnargs['max_value'];
				}
	
	ob_start();

		/* translators: %s: Quantity. */
		$label = ! empty( $args['product_name'] ) ? sprintf( esc_html__( '%s quantity', 'woocommerce' ), wp_strip_all_tags( $args['product_name'] ) ) : esc_html__( 'Quantity', 'woocommerce' );
		?>
		<div class="quantity">
			<?php do_action( 'woocommerce_before_quantity_input_field' ); ?>
			<label class="screen-reader-text" for="<?php echo esc_attr( $args['input_id'] ); ?>"><?php echo esc_attr( $label ); ?></label>
			<input
				type="number"
				id="<?php echo esc_attr( $args['input_id'] ); ?>"
				class="<?php echo esc_attr( join( ' ', (array) $args['classes'] ) ); ?>"
				step="<?php echo esc_attr( $args['step'] ); ?>"
				min="<?php echo esc_attr( $args['min_value'] ); ?>"
				max="<?php echo esc_attr( 0 < $args['max_value'] ? $args['max_value'] : '' ); ?>"
				name="<?php echo esc_attr( $args['input_name'] ); ?>"
				value="<?php echo esc_attr( $args['input_value'] ); ?>"
				title="<?php echo esc_attr_x( 'Qty', 'Product quantity input tooltip', 'woocommerce' ); ?>"
				size="4"
				placeholder="<?php echo esc_attr( $args['placeholder'] ); ?>"
				inputmode="<?php echo esc_attr( $args['inputmode'] ); ?>"
				autocomplete="<?php echo esc_attr( isset( $args['autocomplete'] ) ? $args['autocomplete'] : 'on' ); ?>"
			/>
			<?php do_action( 'woocommerce_after_quantity_input_field' ); ?>
		</div>
		<?php

	$price .= sprintf( 
		'<div class="qty-price-wrap" data-product_id="%d" data-cart_item_key="%s">
				%s
			<div class="item-total-price">%s</div>
		</div>',
		$cart_item['product_id'],
		$cart_item_key,
		ob_get_clean(),
		wc_price( $cart_item['quantity'] * $product_price )
	);
	
	return $price;
}

Step 2: CSS Code

Adding the following CSS code into the Bricks Child theme’s style.css file or any 3rd party plugin.

.qty-price-wrap {
	--bricks-woo-input-height: 20px;
	display: flex;
	width: auto;
	justify-content: space-between;
	margin-top: 7px;
}

.brxe-woocommerce-mini-cart .cart-detail li .qty-price-wrap .quantity {
	border-style: solid;
	border-width: 1px;
	display: flex;
	height: 22px;
	margin-bottom: 0;
	overflow: hidden;
	width: 77px;
	border-color: var( --bricks-border-color );
}

.qty-price-wrap input::-webkit-outer-spin-button,
.qty-price-wrap input::-webkit-inner-spin-button{
	-webkit-appearance: none;
	margin: 0;
	display: none;
}

.qty-price-wrap .quantity .qty {
	-moz-appearance: textfield;
	-webkit-appearance: textfield;
	appearance: textfield;
	background-color: transparent;
	border: none;
	flex: 1;
	font-size: 10px;
	line-height: 1;
	padding: 0;
	text-align: center;
	width: 25px;
	order: 1;
}

.qty-price-wrap .quantity svg {
	fill: currentColor;
	height: 13px;
	width: 13px;
}

.qty-price-wrap .quantity .minus,
.qty-price-wrap .quantity .plus {
	align-items: center;
	cursor: pointer;
	display: flex;
	justify-content: center;
}

.qty-price-wrap .quantity .action {
	width: 25px;
}

.qty-price-wrap .quantity .minus {
	border-right: 1px solid var( --bricks-border-color );
	order: 0;
}

.qty-price-wrap .quantity .plus {
	border-left: 1px solid var( --bricks-border-color );
	order: 2;
}

Step 3: AJAX Action

We shall update the quantity value with AJAX and avoid the page refresh. Drop the following PHP snippets.

add_action( 'wp_ajax_buwoo_update_cart_item_quantity', 'buwoo_update_cart_item_quantity' );
add_action( 'wp_ajax_nopriv_buwoo_update_cart_item_quantity', 'buwoo_update_cart_item_quantity' );

function buwoo_update_cart_item_quantity() {
	check_ajax_referer( 'bricks-nonce', 'security' );

	$cart_key 	= sanitize_text_field( $_POST['cart_key'] );
	$new_qty 	= wc_stock_amount(absint( $_POST['qty'] ));
	$cart_item_data = WC()->cart->get_cart_item( $cart_key );
	$product_id = apply_filters('woocommerce_add_to_cart_product_id', absint($_POST['product_id']));
	$passed_validation = apply_filters('woocommerce_add_to_cart_validation', true, $product_id, $new_qty);	

	if( $passed_validation && $cart_key && ! empty( $cart_item_data ) ) {
		$updated = $new_qty == 0 ? WC()->cart->remove_cart_item( $cart_key ) : WC()->cart->set_quantity( $cart_key, $new_qty );
		if( $updated ){
			
			wc_clear_notices();

			\WC_AJAX::get_refreshed_fragments();
		}
	} else {
		$data = array(
			'error' => __( 'Failed. Something went wrong', 'bricksultimate' ),
		);
		
		wp_send_json($data);
	}
}

JS snippets:

You can add this JS code at Dashboard->Bricks->Settings->Custom Code->Body(Footer) scripts or any 3rd party plugin.

<script type="text/javascript">
jQuery(document).ready(function($){

	let itemBaseQty = 1;
	let updateTimer;

	$(document.body).on( 'focusin', '.qty-price-wrap .qty', function (e) {
		itemBaseQty = $(e.currentTarget).val();
	});

	$(document.body).on('pointerdown', '.qty-price-wrap .action', function (e) {
		var $toggler 	= $(e.currentTarget),
			$input 		= $toggler.siblings('.qty');

		if( !$input.length ) return;

		var baseQty = itemBaseQty = parseFloat( $input.val() ),
			step 	= parseFloat( $input.attr('step') ),
			min 	= parseFloat( $input.attr('min') ),
			max 	= parseFloat( $input.attr('max') ),
			newQty 	= $toggler.hasClass( 'plus' ) ? baseQty + step : baseQty - step;
		
		$input.val(newQty).trigger('change');
	});
        
        $(document.body).on('change', '.qty-price-wrap .qty', function(e) {

		if ( typeof wc_cart_fragments_params === 'undefined' ) {
			return false;
		}

		e.preventDefault();

		var $input 	= $(e.currentTarget),
			newQty 	= parseFloat( $input.val() ),
			step 	= parseFloat( $input.attr('step') ),
			min 	= parseFloat( $input.attr('min') ),
			max 	= parseFloat( $input.attr('max') ),
			invalid = false;

		if( isNaN( newQty )  || newQty < 0 || newQty < min  ) {
			invalid = true;
		}
		else if( newQty > max ){
			invalid = true;
		}
		else if( ( newQty % step ) !== 0 ) {
			invalid = true;
		}

		if( invalid ){
			$input.val( itemBaseQty );

			return;
		}

		clearTimeout(updateTimer);

        updateTimer = setTimeout(function () {

			$row = $input.closest( '.woocommerce-mini-cart-item' );

			$row.block({
				message: null,
				overlayCSS: {
					opacity: 0.6
				}
			});

			$.ajax({
				url: wc_cart_fragments_params.ajax_url.toString(),
				type: 'POST',
				data: {
					"action": 'buwoo_update_cart_item_quantity',
					"cart_key": $input.closest('.qty-price-wrap').attr('data-cart_item_key'),
					"product_id": $input.closest('.qty-price-wrap').attr('data-product_id'),
					"qty": newQty,
					"security": bricksData.nonce
				},
				dataType: 'json',
				success: function(response){
					if (response.error) {
						$input.val( itemBaseQty );
						return;
					} else {
						$(document.body).trigger('wc_fragment_refresh', [response.fragments, response.cart_hash, $input]);
					}
				},
				complete: function() {
					$row.unblock();
					$(document.body).trigger("wc_update_cart");
					$( document.body ).trigger( 'update_checkout' );
				}
			});
		}, 2000);
	});
});
</script>

All are done here. Now go to your frontend and check the mini cart after adding a product.[/edd_restrict]

– OR –