Search code examples
ajaxwordpresswoocommerceproductcart

Count cart content VS term count in WooCommerce cart and show the difference using AJAX (Fragments)


I got four giftboxes. The customer can only put products tagged with fits-in-giftbox into them. The boxes have space for 4, 9, 16 or 24 pieces. All other products will be packed separately.

I need to count how many times each of these boxes have been added to cart and calculate the total number of pieces they can fit.

I then need to calculate how many fits-in-giftbox tagged products the customer adds to their cart and match that number with how many pieces all giftboxes can hold.

Example: Customer puts one box-4 (holds 4 products) and one box-24 (holds 24 products) in the cart. In total, the customer can now add 28 products tagged with fits-in-giftbox.

Customer adds 18 products tagged with fits-in-giftbox. There are now 10 pieces left.

Expected output: "You have added three (3) giftboxes to your cart. Please add an additional XX products to fill your boxes."

OR: "You have added two (2) giftboxes which can hold 8 pieces. You have added 12 products to your cart. The exceeding four (4) products will be packed separately unless you add another giftbox to your cart."

OR: "You have added one giftbox to your cart but no giftbox products. Unless you do, these products will be packed separately."

I hope this makes sense. Feels like I am going in circles here..

This is the code I need help with:

function product_tag_count( $term ) {
    $tag_count = 0;
    foreach( WC()->cart->get_cart() as $cart_item ) {
        if ( has_term( $term, 'product_tag', $cart_item['product_id'] ) )
            $tag_count += $cart_item['quantity'];
    }
    return $tag_count == 0 ? false : $tag_count;
}

function display_cart_counters() {

    ob_start();

    $link  = wc_get_checkout_url();
    $title = __( 'Checkout and Pay', 'woocommerce' );
    $tag_count = __( '0 products', 'woocommerce');

    echo '<a class="product-cart-count" href="' . $link . '" title="' . $title . '">' . $tag_count . '</a>';

    return ob_get_clean();

}

add_filter( 'woocommerce_add_to_cart_fragments', 'counters_add_to_cart_fragment', 30, 1 );
function counters_add_to_cart_fragment( $fragments ) {
    
    ob_start();

    // count the number of giftboxes
    $giftbox4 = 'giftbox-4';
    $fits_in_giftbox4 = '4';
    $count_giftbox4 = product_tag_count( $giftbox4 );

    $giftbox9 = 'giftbox-9';
    $fits_in_giftbox9 = '9';
    $count_giftbox9 = product_tag_count( $giftbox9 );

    $giftbox16 = 'giftbox-16';
    $fits_in_giftbox16 = '16';
    $count_giftbox16 = product_tag_count( $giftbox16 );

    $giftbox24 = 'giftbox-24';
    $fits_in_giftbox24 = '24';
    $count_giftbox24 = product_tag_count( $giftbox24 );
    
    // get the total number of giftboxes
    $count_giftboxes_total = ( $count_giftbox4 + $count_giftbox9 + $count_giftbox16 + $count_giftbox24 );

    // count how many products that fits into giftboxes
    $fits_in_giftbox = 'goes-into-box';
    $count_fits_in_giftbox = product_tag_count( $fits_in_giftbox );

    // count the cart as a whole
    $cart_count = WC()->cart->get_cart_contents_count();

    // calculate the difference between cart as a whole and giftbox products
    $difference_between_cart_and_giftbox_products = ( $cart_count - $count_fits_in_giftbox );

    // calculate boxes VS giftbox products
    $fits_into_boxes_vs_giftbox_products = ( $count_giftboxes_total - $count_fits_in_giftbox );


    // this is what I need help with.. how do I get the total pieces of all boxes added to cart?
    
    // first check, is there space left or not?
    if ( $count_giftboxes_total < $count_fits_in_giftbox ) {
    $output = sprintf (_n( 'You have %d product to much. This will be packed separately unless you add another giftbox.', 'You have %d products to many. These will be packed separately unless you add another giftbox.' ), 'woocommerce');
    } elseif () {
        $output = sprintf (_n( 'You have %d product to much. This will be packed separately unless you add another giftbox.', 'You have %d products to many. These will be packed separately unless you add another giftbox.' ), 'woocommerce');
    } elseif () {
        $output = sprintf (_n( 'You have %d product to much. This will be packed separately unless you add another giftbox.', 'You have %d products to many. These will be packed separately unless you add another giftbox.' ), 'woocommerce');
    } else {
        $output = sprintf (_n( 'You have %d product to much. This will be packed separately unless you add another giftbox.', 'You have %d products to many. These will be packed separately unless you add another giftbox.' ), 'woocommerce');
    }
    
    $checkout_link = wc_get_checkout_url();
    $link_title = __( 'Go to Checkout', 'woocommerce' );

    ?>
    <div class="product-wrapper">
    <?php echo $output; ?>
    <br>
    <a class="product-cart-count" href="<?php echo $link; ?>"
    title="<?php echo $title ?>">Go to Checkout &amp; Pay</a>
    </div>
    
    <?php 
    
        $fragments['a.product-cart-count'] = ob_get_clean();

        return $fragments;
}

add_action( 'woocommerce_before_shop_loop', 'count_products_and_boxes');
add_action( 'woocommerce_before_add_to_cart_form', 'count_products_and_boxes');
function count_products_and_boxes() {
    echo display_cart_counters();
}

Solution

  • This will adjust the message based on the number of giftboxes in cart and the number of products they can contain. Messages are changed:

    • When the cart contains products, but no giftbox(es)
    • When the cart contains giftbox(es), but no products
    • When there are more products in cart than giftboxes can contain
    • When there are less products in cart than giftboxes can contain

    Note that I used the product ID for the 4 giftboxes, otherwise you'll make it unnecessarily complicated.

    function display_cart_counters() {
        // Settings
        $term = 'fits-in-giftbox';
        $taxonomy = 'product_tag';
        
        // Giftbox IDs. Important, these should not contain the term 'fits-in-giftbox' !!
        // Contents => Product ID
        $giftbox_ids = array( 
            4  => 218,
            9  => 220,
            16 => 813,
            24 => 815 
        );
        
        // Initialize
        $count_fits_in_giftbox = 0;
        $count_giftboxes = 0;
        $count_giftboxes_total = 0;
        $count_not_term = 0;
        $message = '';
        
        // True
        if ( WC()->cart ) { 
            // Loop trough cart items quantities
            foreach( WC()->cart->get_cart_item_quantities() as $product_id => $cart_item_quantity ) {
                // Contains the definite term
                if ( has_term( $term, $taxonomy, $product_id ) ) {
                    // Add the cart item quantity from this certain product to the counter
                    $count_fits_in_giftbox += $cart_item_quantity;
                // The box ID is in the cart
                } elseif( in_array( $product_id, $giftbox_ids ) ) {
                    // Add 1 * cart item quantity to counter
                    $count_giftboxes += 1 * $cart_item_quantity;
                    
                    // Add contens * the cart item quantity to the counter
                    $count_giftboxes_total  += ( array_search ( $product_id, $giftbox_ids ) * $cart_item_quantity );
                // Does not contain the particular term and is not a gift box
                } else {
                    // Add the cart item quantity from this certain product to the counter
                    $count_not_term += $cart_item_quantity;
                }
            }
        }
        
        // Singular or plural
        $s_o_p_giftbox = _n( '%d giftbox', '%d giftboxes', $count_giftboxes, 'woocommerce' );
        $s_o_p_product = _n( '%d product', '%d products', $count_fits_in_giftbox, 'woocommerce' );
        
        // Additional message for untagged products
        if ( $count_not_term >= 1 ) { 
            $untagged_product_message = ' You also added %s untagged products, these will be packaged separately.';
        } else {
            $untagged_product_message = '';
            $count_not_term = '';
        }
        
        // When the cart contains products, but no giftbox(es)
        if ( $count_giftboxes == 0 && $count_fits_in_giftbox >= 1 ) {
            $message = sprintf( 
                __( 'You have added ' . $s_o_p_giftbox . ' to your cart but ' . $s_o_p_product . '. Unless you do, these products will be packed separately.' . $untagged_product_message . '', 'woocommerce' ), 
                $count_giftboxes, 
                $count_fits_in_giftbox,
                $count_not_term
            );      
        // When the cart contains giftbox(es), but no products
        } elseif ( $count_giftboxes >= 1 && $count_fits_in_giftbox == 0 ) {
            $message = sprintf( 
                __( 'You have added ' . $s_o_p_giftbox . ' to your cart but no giftbox products. Unless you do, these products will be packed separately.' . $untagged_product_message . '', 'woocommerce' ), 
                $count_giftboxes,
                $count_not_term
            );
        // When there are more products in cart than giftboxes can contain
        } elseif( $count_giftboxes_total < $count_fits_in_giftbox ) {
            $message = sprintf( 
                __( 'You have added ' . $s_o_p_giftbox . ' which can hold %d pieces. You have added ' . $s_o_p_product . ' to your cart. The exceeding %d products will be packed separately unless you add another giftbox to your cart.' . $untagged_product_message . '', 'woocommerce' ),
                $count_giftboxes, 
                $count_giftboxes_total, 
                $count_fits_in_giftbox, 
                $count_fits_in_giftbox - $count_giftboxes_total,
                $count_not_term
            );
        // When there are less products in cart than giftboxes can contain
        } elseif( $count_giftboxes_total > $count_fits_in_giftbox ) {
            $message = sprintf( 
                __( 'You have added ' . $s_o_p_giftbox . ' which can hold %d pieces. You have added ' . $s_o_p_product . ' to your cart. Please add an additional %d products to fill your boxes.' . $untagged_product_message . '', 'woocommerce' ), 
                $count_giftboxes, 
                $count_giftboxes_total, 
                $count_fits_in_giftbox, 
                $count_giftboxes_total - $count_fits_in_giftbox,
                $count_not_term
            );
        }
        
        return $message;
    }
    
    // Refreshing on cart ajax events
    function filter_woocommerce_add_to_cart_fragments( $fragments ) {    
        $fragments['div.display-cart-counters'] = '<div class="display-cart-counters">' . display_cart_counters() . '</div>';
        
        return $fragments;        
    }
    add_filter( 'woocommerce_add_to_cart_fragments', 'filter_woocommerce_add_to_cart_fragments', 10, 1 );
    
    // Display message via the desired hooks
    function display_message() {
        echo '<div class="display-cart-counters">' . display_cart_counters() . '</div>';
    }
    add_action( 'woocommerce_before_shop_loop', 'display_message', 10, 0 );
    add_action( 'woocommerce_before_add_to_cart_form', 'display_message', 10, 0 );