Search code examples
phpwordpresswoocommercehook-woocommercesku

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


In WooCommerce, I use a code that shows the steak weight selection form, saves the selection data and displays this data in the cart, on the checkout page, when editing the order and in email notifications.

My code is also combined with a code that automatically adds packaging when adding any products to the cart. Adding packaging occurs on SKU.

/**
* Display Custom Checkbox Field
*/
function steak_custom_field_add() {
    global $post;

    // Checkbox
    woocommerce_wp_checkbox(
        array(
            'id' => '_steak_checkbox',
            'label' => __('Steak Weight', 'woocommerce' ),
            'description' => __( 'If necessary, enable steak weight selection', 'woocommerce' )
        )
    );
}
add_action('woocommerce_product_options_general_product_data', 'steak_custom_field_add', 10, 0 );

/**
 * Save Custom Checkbox Field
 */
function steak_custom_field_save( $post_id ) {
    $product = wc_get_product( $post_id );

    // Custom Product Checkbox Field
    $steak_checkbox = isset( $_POST['_steak_checkbox'] ) ? 'yes' : 'no';

    // Update product meta
    $product->update_meta_data( '_steak_checkbox', $steak_checkbox );

    // Save
    $product->save();
}
add_action('woocommerce_process_product_meta', 'steak_custom_field_save', 10, 1 );

/**
 * Display Custom Select Box
 */
function display_steak_custom_field() {
    global $post;

    // Get product
    $product = wc_get_product( $post->ID );

    // If is single product page and have the "steak_checkbox" enabled we display the field
    if ( $product->get_meta( '_steak_checkbox' ) === 'yes' ) {

        echo '<div class="roast_select">';

        $select = woocommerce_form_field( 'steak_custom_options', array(
            'type'          => 'select',
            'class'         => array('my-steak-select-box form-row-wide'),
            'label'         => __('Steak Weight'),
            'required'      => false,
            'return'       => false,
            'options'   => array(
                ''      => 'Please select...',
                '300g'  => '300g',
                '400g'  => '400g',
                '500g'  => '500g',
                '600g'  => '600g',
                '700g'  => '700g',
                '800g'  => '800g',
                '900g'  => '900g',
                '1000g'  => '1000g'
            )
        ), '' );
        echo $select;
        echo '</div>';
        ?>
        <script type="text/javascript">
            jQuery(document).ready(function ($) {
                console.log('it works 1');

                var price = <?php echo $product->get_price(); ?>, currency = '<?php echo get_woocommerce_currency_symbol(); ?>';

                $( '[name=steak_custom_options]' ).change(function(){
                    if (!(this.value < 1)) {
                        var dropdown_val = this.value;
                        var remove_g = dropdown_val.replace( 'g', '' );
                        var remove_double_zero = remove_g.replace( '00', '' );

                        var product_total = parseFloat( price * remove_double_zero );

                        // For single product page
                        $( '.entry-summary .woocommerce-Price-amount' ).html( currency + product_total.toFixed(2));

                        // quick-view-custom-price
                        $( '.quick-view-custom-price .woocommerce-Price-amount' ).html( currency + product_total.toFixed(2));
                    }
                });
            });
        </script>
        <?php
    }
}
add_action( 'woocommerce_before_add_to_cart_button', 'display_steak_custom_field', 10, 0 );

/**
 * Add as custom cart item data
 */
function add_custom_steak_cart_item_data( $cart_item_data, $product_id, $variation_id, $quantity ) {
    // Get product
    $product = wc_get_product( $product_id );

    // Get product sku
    $product_sku = $product->get_sku();

    if ( !empty( $_POST['steak_custom_options'] ) && $product_sku != 'lunchbox' ) {
        $cart_item_data['steak_option'] = $_POST['steak_custom_options'];
    }

    return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'add_custom_steak_cart_item_data', 10, 4 );

/**
 * Add custom fields values under cart item name in cart
 */
function steak_custom_field_add_cart( $item_name, $cart_item, $cart_item_key ) {
    if( is_cart() ) {
        if( isset( $cart_item['steak_option'] ) ) {
            $item_name .= '<div class="my-steak-class"><strong>' . __("Steak Weight", "woocommerce") . ':</strong> ' . $cart_item['steak_option'] . '</div>';
        }
    }

    return $item_name;
}
add_filter( 'woocommerce_cart_item_name', 'steak_custom_field_add_cart', 10, 3 );

/**
 * Calculate the number of lunchboxes and package, based on the number of products in cart.
 */
function add_delivery_charge_to_cart( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

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

    /********** SETTINGS **********/

    $lunchbox_sku  = 'lunchbox'; // "LunchBox SKU" to be added to cart
    $pakket_sku = 'pakket'; // "Pakket SKU" to be added to cart

    $exclude_categories = array( 'drink', 'bread' ); // Exclude these categories

    /********** END SETTINGS **********/

    // Get product ID by SKU
    $lunchbox_id = wc_get_product_id_by_sku( $lunchbox_sku );
    $pakket_id = wc_get_product_id_by_sku( $pakket_sku );

    $category_qty_total = 0; // Total of category quantity items, Don't edit!!

    /********** LOOP THROUGH CART ITEMS **********/

    foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
        // Get product id
        $product_id = $cart_item['data']->get_id();

        // Get product quantity
        $product_qty = $cart_item['quantity'];

        // Check if "LunchBox" product is already in cart
        if( $product_id == $lunchbox_id ) {
            $lunchbox_key = $cart_item_key;
            $lunchbox_qty = $product_qty;
        }

        // Check if "Pakket" product is already in cart
        if( $product_id == $pakket_id ) {
            $pakket_key = $cart_item_key;
            $pakket_qty = $product_qty;
        }

        // Check if product belongs to a certain category
        if( has_term( $exclude_categories, 'product_cat', $product_id ) ) {
            $category_qty_total += $product_qty;
        }

        // Check if product, contains steak weight
        if( isset( $cart_item['steak_option'] ) ) {
            // Remove the last 2 zeros (100g becomes 1, 300g becomes 3, 1000g becomes 10, etc...)
            // Remove 'g' from grams
            // convert string to integer
            $chosen_weight = (int) str_replace( '00', '', str_replace('g', '', $cart_item['steak_option']) );

            // Get current price
            $current_price = $cart_item['data']->get_price();

            // Set new price, price is already known per 100g
            $cart_item['data']->set_price( $current_price * $chosen_weight );
        }
    }

    /********** CALCULATE THE TOTALS, SO "LUNCHBOX", "PAKKET" & CATEGORIES ARE NOT USED IN THE TOTALS **********/

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

    // Total items in cart - category quantity total
    $total_items_in_cart -= $category_qty_total;

    // Lunchbox total = total_items_in_cart & pakket total = total_items_in_cart
    $lunchbox_total = $total_items_in_cart;
    $pakket_total = $total_items_in_cart;

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

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

    /********** APPLY NEW TOTALS TO LUNCHBOX & PAKKET **********/

    // 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 ) {
        // 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 = 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) ) {
            // Set quantity, pakket
            $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 );

/**
 * Display custom fields values under item name in checkout
 */
function steak_custom_checkout_cart_item_name( $item_qty, $cart_item, $cart_item_key ) {
    if( isset($cart_item['steak_option']) ) {
        $item_qty .= '<div class="my-steak-class"><strong>' . __("Steak Weight", "woocommerce") . ':</strong> ' . $cart_item['steak_option'] . 'g</div>';
    }
    return $item_qty;
}
add_filter( 'woocommerce_checkout_cart_item_quantity', 'steak_custom_checkout_cart_item_name', 10, 3 );

/**
 * Display custom fields values under item name in checkout
 */
function save_order_item_steak_field( $item, $cart_item_key, $values, $order ) {
    if( isset($values['steak_option']) ) {
        $key = __('Steak Weight', 'woocommerce');
        $value = $values['steak_option'];
        $item->update_meta_data( $key, $value ,$item->get_id());
    }
}
add_action('woocommerce_checkout_create_order_line_item', 'save_order_item_steak_field', 10, 4 );

At one time, user @7uc1f3r helped make custom sorting so that packaging is always at the very bottom of the product list in the cart.

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 );

But unfortunately, the sort code is a bit outdated, because now the package is added by SKU, not by ID. Accordingly, sorting does not work.

How to change the sort code, given the addition of packaging by SKU?

I will be happy for your help!


Solution

  • The following code will sort products last, based on the product sku

    Related thread:

    function sort_cart_specific_product_at_bottom( $cart ) { 
        // Product sku to to display at tbe bottom of the product list
        $product_sku_last = array( 'lunchbox', 'pakket' );
    
        // 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 sku
            $product_sku = $cart_item['data']->get_sku();
    
            // Get product id
            $product_id = $cart_item['data']->get_id();
    
            // In_array — checks if a value exists in an array
            if ( in_array( $product_sku, $product_sku_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 );
    

    And this code ensures that the items based on sku are not removable from the shopping cart

    function prevent_cart_item_remove_link( $link, $cart_item_key ) {
        // Product sku that should not be removable
        $product_sku_last = array( 'lunchbox', 'pakket' );
    
        if( WC()->cart->find_product_in_cart( $cart_item_key ) ) {
            $cart_item = WC()->cart->cart_contents[ $cart_item_key ];
    
            // Get product sku
            $product_sku = $cart_item['data']->get_sku();
    
            // In_array — checks if a value exists in an array
            if ( in_array( $product_sku, $product_sku_last ) ) {
                $link = '';
            }
        }
    
        return $link;
    }
    add_filter( 'woocommerce_cart_item_remove_link', 'prevent_cart_item_remove_link', 10, 2 );