Search code examples
phpdatewoocommercecart

How to sort cart items by date (the last modified cart item will be the first)?


I am trying to order the cart contents by date, the last one added or modified must be displayed first. I tried reversing the order of the cart but its not working as expected. This is the code I tried:

//reorder cart
add_action('woocommerce_cart_loaded_from_session', 'wh_cartOrderItemsbyNewest');

function wh_cartOrderItemsbyNewest() {

    //if the cart is empty do nothing
    if (WC()->cart->get_cart_contents_count() == 0) {
        return;
    }

    //array to collect cart items
    $cart_sort = [];

    //add cart item inside the array
    foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item) { print_r(WC()->cart->cart_contents[$cart_item_key][0]);
        $cart_sort[$cart_item_key] = WC()->cart->cart_contents[$cart_item_key];
    }

    //replace the cart contents with in the reverse order
    WC()->cart->cart_contents = array_reverse($cart_sort);
}

Solution

  • Cart items are already shown in cart by date added.

    Then the last one added to the cart will be the first in the list.

    The problem arises when you change the quantity of a product in the cart. In this case he would remain in his same position.

    I thought of using a custom cart item data with the date of addition/modification but in this case it would create more lines of the same product.

    I solved it with the Options API.

    I thought about creating/updating a realtime date option when:

    • woocommerce_add_to_cart the product is added to the cart
    • woocommerce_cart_item_removed the product is removed from the cart
    • woocommerce_after_cart_item_quantity_update the cart item quantity is updated (increased or decreased)

    While the option is deleted when:

    • woocommerce_cart_emptied the cart is emptied

    The sort will also be applied to the mini cart.

    The following function will create custom ordering of cart items based on the last_update_cart_item option:

    // sorts cart items by modification date
    add_action( 'woocommerce_cart_loaded_from_session', 'sorts_cart_items_by_modification_date' );
    function sorts_cart_items_by_modification_date() {
    
        // only if the cart is not empty
        if ( WC()->cart->get_cart_contents_count() == 0 ) {
            return;
        }
    
        // only if the "last_update_cart_item" option exists
        if ( ! $last_update = get_option( 'last_update_cart_item' ) ) {
            return;
        }
    
        $cart_sort = array();
        $cart_item_content = array();
    
        foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
            // gets the update date of the cart item
            $cart_sort[$cart_item_key] = $last_update[$cart_item_key];
            // gets the contents of the cart item
            $cart_item_content[$cart_item_key] = WC()->cart->cart_contents[$cart_item_key];
        }
    
        // sorts the cart items by descending date (the last modified will be the first)
        array_multisort( $cart_sort, SORT_DESC, WC()->cart->get_cart() );
    
        // creates the new sorting with the contents of the cart items
        foreach ( $cart_sort as $key => $value ) {
            $sorted[$key] = $cart_item_content[$key];
        }
    
        // update cart contents with custom sorting
        WC()->cart->cart_contents = $sorted;
        
    }
    

    While the following functions will update the last_update_cart_item option when the product is added, changed or removed from the cart:

    // update the "last_update_cart_item" option with the date the product was added to the cart
    add_action( 'woocommerce_add_to_cart', 'after_woocommerce_add_to_cart', 10, 6 );
    function after_woocommerce_add_to_cart( $cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data ) {
        $last_update = array();
        if ( get_option( 'last_update_cart_item' ) ) {
            $last_update = get_option( 'last_update_cart_item' );
        }
        // set the updated date of the cart item
        $last_update[$cart_item_key] = date("Y-m-d H:i:s");
        update_option( 'last_update_cart_item', $last_update );
    
        return $cart_item_data;
    }
    
    // when the cart item is removed, it also removes the cart item key from the "last_update_cart_item" option
    add_action( 'woocommerce_cart_item_removed', 'after_woocommerce_cart_item_removed', 10, 2 );
    function after_woocommerce_cart_item_removed( $cart_item_key, $cart ) {
        if ( $last_update = get_option( 'last_update_cart_item' ) ) {
            if ( array_key_exists( $cart_item_key, $last_update ) ) {
                // removes the cart item key from the "last_update_cart_item" option
                unset( $last_update[$cart_item_key] );
                update_option( 'last_update_cart_item', $last_update );
            }
        }
    }
    
    // when the quantity of the cart item updates, sets or updates the date
    add_action( 'woocommerce_after_cart_item_quantity_update', 'update_cart_item_data_after_cart_item_quantity_update', 10, 4 );
    function update_cart_item_data_after_cart_item_quantity_update( $cart_item_key, $quantity, $old_quantity, $cart ) {
        $last_update = array();
        if ( get_option( 'last_update_cart_item' ) ) {
            $last_update = get_option( 'last_update_cart_item' );
        }
        // updates the date of the cart item whose quantity has been changed
        $last_update[$cart_item_key] = date("Y-m-d H:i:s");
        update_option( 'last_update_cart_item', $last_update );
    
    }
    
    // when the cart is empty delete the "last_update_cart_item" option
    add_action( 'woocommerce_cart_emptied', 'after_woocommerce_cart_emptied', 10, 1 );
    function after_woocommerce_cart_emptied( $cart ) {
        // delete the "last_update_cart_item" option
        delete_option( 'last_update_cart_item' );
    }
    

    The code has been tested and works. Add it to your active theme's functions.php.