Search code examples
phpwordpresswoocommercecarthook-woocommerce

Sort products at the bottom of the product list in cart WooCommerce by product ID


In WooCommerce, I use a code that auto adds packaging when adding any dish to the cart.

The functionality is as follows:

  1. dish is in the shopping cart, 1 lunch box is added

  2. dishes are in the shopping cart, 2 lunch boxes are added

  3. dishes are in the shopping cart, 3 lunch boxes are added

There are 3 lunch boxes, so now 1 package is added

function add_delivery_charge_to_cart( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
        return;

    $lunchbox_id  = 5737; // "LunchBox" to be added to cart
    $pakket_id = 5738; // "Pakket" to be added to cart

    // Loop through cart items
    foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
        // Check if "LunchBox" product is already in cart
        if( $cart_item['data']->get_id() == $lunchbox_id ) {
            $lunchbox_key = $cart_item_key;
            $lunchbox_qty = $cart_item['quantity'];
        }

        // Check if "Pakket" product is already in cart
        if( $cart_item['data']->get_id() == $pakket_id ) {
            $pakket_key = $cart_item_key;
            $pakket_qty = $cart_item['quantity'];
        }       
    }

    // Get total items in cart, counts number of products and quantity per product
    $total_items_in_cart = WC()->cart->get_cart_contents_count();

    // If product "LunchBox" is in cart, we check the quantity to update it if needed
    if ( isset($lunchbox_key) && $lunchbox_qty != $total_items_in_cart ) {
        // Lunchbox total = total_items_in_cart 
        $lunchbox_total = $total_items_in_cart;

        // Isset lunchbox qty, lunchbox total - lunchbox qty
        if ( isset($lunchbox_qty) ) {
            $lunchbox_total = $lunchbox_total - $lunchbox_qty;
        }

        // Isset pakket qty, lunchbox total - pakket qty        
        if ( isset($pakket_qty) ) {
            $lunchbox_total = $lunchbox_total - $pakket_qty;
        } 

        // Set quantity, lunchbox
        $cart->set_quantity( $lunchbox_key, $lunchbox_total );

    } elseif ( !isset($lunchbox_key) && $total_items_in_cart > 0 ) {
        // Product "LunchBox" is not in cart, we add it
        $cart->add_to_cart( $lunchbox_id, $total_items_in_cart );
    }

    // Total items in cart greater than or equal to 3
    if ( $total_items_in_cart >= 3 ) {
        // Pakket total = total_items_in_cart 
        $pakket_total = $total_items_in_cart;

        // Isset lunchbox qty, pakket total - lunchbox qty
        if ( isset($lunchbox_qty) ) {
            $pakket_total = $pakket_total - $lunchbox_qty;
        }

        // Isset pakket qty, pakket total - pakket qty      
        if ( isset($pakket_qty) ) {
            $pakket_total = $pakket_total - $pakket_qty;
        }       


        // Pakket total = pakket_total / 3 = floor(result)
        // Floor = round fractions down, rounding result down
        $pakket_total = floor( $pakket_total / 3 );

        // If product "Pakket" is in cart
        if ( isset($pakket_key) ) {         
            $cart->set_quantity( $pakket_key, $pakket_total );
        } elseif ( !isset($pakket_key) ) {
            // Product "Pakket" is not in cart, we add it
            $cart->add_to_cart( $pakket_id, $pakket_total );
        }
    }
}
add_action( 'woocommerce_before_calculate_totals', 'add_delivery_charge_to_cart', 10, 1 );

There is a small problem. All automatically added packaging in the cart is sorted mixed with other products.

How to make packing in the cart always at the bottom of the product list?

Alphabetically sorting A-Z does not fit:

add_action( 'woocommerce_cart_loaded_from_session', 'my_sort_cart_items_alphabetically' ); 
function my_sort_cart_items_alphabetically() {

    // READ CART ITEMS
    $products_in_cart = array();
    foreach ( WC()->cart->get_cart_contents() as $key => $item ) {
        $products_in_cart[ $key ] = $item['data']->get_title();
    }

    // SORT CART ITEMS
    natsort( $products_in_cart );

    // ASSIGN SORTED ITEMS TO CART
    $cart_contents = array();
    foreach ( $products_in_cart as $cart_key => $product_title ) {
        $cart_contents[ $cart_key ] = WC()->cart->cart_contents[ $cart_key ];
    }
    WC()->cart->cart_contents = $cart_contents;
}

I will be happy for your help!


Solution

  • Product IDs added in the array will appear at the bottom of the list

    Related thread:

    function sort_cart_specific_product_at_bottom( $cart ) {    
        // Product id's to to display at tbe bottom of the product list
        $product_ids_last = array( 30, 815 );
    
        // Set empty arrays
        $products_in_cart = array();
        $products_last = array();
        $cart_contents = array();
    
        // Loop through cart items
        foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
            // Get product id
            $product_id = $cart_item['data']->get_id();
    
            // In_array — checks if a value exists in an array
            if ( in_array( $product_id, $product_ids_last) ) {
                // Add to products last array
                $products_last[ $cart_item_key ] = $product_id;
            } else {
                // Add to products in cart array
                $products_in_cart[ $cart_item_key ] = $product_id;
            }
        }
    
        // Merges the elements together so that the values of one are appended to the end of the previous one.
        $products_in_cart = array_merge( $products_in_cart, $products_last );
    
        // Assign sorted items to cart
        foreach ( $products_in_cart as $cart_item_key => $product_id ) {
            $cart_contents[ $cart_item_key ] = $cart->cart_contents[ $cart_item_key ];
        }
    
        // Cart contents
        $cart->cart_contents = $cart_contents;
    
    }
    add_action( 'woocommerce_cart_loaded_from_session', 'sort_cart_specific_product_at_bottom', 10, 1 );