Sort WooCommerce cart by category - wordpress

I already found a snippet to sort the checkout cart alphabetically. This works perfect but as mentioned I try to sort and group my products by category.
Is there anyone who could tweak the following snippet so it sorts the products by category?
add_action( 'woocommerce_cart_loaded_from_session', 'bbloomer_sort_cart_items_alphabetically' );
function bbloomer_sort_cart_items_alphabetically() {
global $woocommerce;
// READ CART ITEMS
$products_in_cart = array();
foreach ( $woocommerce->cart->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 ] = $woocommerce->cart->cart_contents[ $cart_key ];
}
$woocommerce->cart->cart_contents = $cart_contents;
}

In order to grouped cart items by categories, add follows code snippet -
function woocommerce_before_cart_contents(){
global $woocommerce;
$cat_wisw_pros = array();
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $cart_item ) {
$product_id = $cart_item['product_id'];
$cat_ids = wp_get_post_terms( $product_id, 'product_cat', array( 'fields' => 'ids' ) );
foreach ( $cat_ids as $id ) {
$cat_wisw_pros[$id][$cart_item_key] = $cart_item;
}
}
ksort( $cat_wisw_pros ); // Cat ID wise sort
$grouped_cart_items = array();
foreach ( $cat_wisw_pros as $cat_id => $cart_items ) {
foreach ( $cart_items as $cart_item_key => $cart_item ) {
if( !array_key_exists( $cart_item_key, $grouped_cart_items ) )
$grouped_cart_items[$cart_item_key] = $cart_item;
}
}
$woocommerce->cart->cart_contents = $grouped_cart_items;
}
add_action( 'woocommerce_before_cart_contents', 'woocommerce_before_cart_contents' );

You should be able to access the category ids with the method get_category_ids() as defined in the class WC_Product
$item['data']->get_category_ids()
but this gives you back an array, so you need to handle getting the id, e.g.
$ids = $item['data']->get_category_ids();
$id = $ids[ 0 ];
and transforming to a string, e.g.
$term_obj = get_term( $id, 'product_cat' );
$name = $term_obj->name;
you could then do
$products_in_cart[ $key ] = $name;
and by the same logic used in the code in your question sort by category.
There are several things to consider though, this does not handle items being in multiple categories, it just gets the first by using index 0. Additionally, this has no extra logic of sorting, if there are multiple products in the same category.
Please note, this is untested and merely an idea of an approach of how this could be handled.

Related

Sort products in cart by category and also apply this sorting method on orders pages and email notifications in WooCommerce

I sort my cart by category using this code snippet:
//order in cart
function woocommerce_before_cart_contents(){
global $woocommerce;
$cat_wisw_pros = array();
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $cart_item ) {
$product_id = $cart_item['product_id'];
$cat_ids = wp_get_post_terms( $product_id, 'product_cat', array( 'fields' => 'ids' ) );
foreach ( $cat_ids as $id ) {
$cat_wisw_pros[$id][$cart_item_key] = $cart_item;
}
}
ksort( $cat_wisw_pros ); // Cat ID wise sort
$grouped_cart_items = array();
foreach ( $cat_wisw_pros as $cat_id => $cart_items ) {
foreach ( $cart_items as $cart_item_key => $cart_item ) {
if( !array_key_exists( $cart_item_key, $grouped_cart_items ) )
$grouped_cart_items[$cart_item_key] = $cart_item;
}
}
$woocommerce->cart->cart_contents = $grouped_cart_items;
}
add_action( 'woocommerce_before_cart_contents', 'woocommerce_before_cart_contents' );
This works perfectly, as you can see on the picture:
Red Boxes:
The product category "Basic Products-GNC-Verkauf" is the first one, and then comes "Werbematerial/Luxusproben".
But as soon I paid, there isn't the sorted order. So the problem is, that on the invoice the sorted order vanishes. But I need, that the customer can see that the order is sorted.
How can I apply the order needs to be sorted?
The custom sort order is no longer applied when leaving the cart page because you are using woocommerce_before_cart_contents hook.
You can replace it with the woocommerce_cart_loaded_from_session hook, so the custom sort order is also applied on the order received page. Furthermore, I made some adjustments to your existing code:
The use of global $woocommerce is not necessary, as $cart is passed to the callback function
wp_get_post_terms() is replaced by get_category_ids()
So you get:
// Order in cart and order review page
function action_woocommerce_cart_loaded_from_session( $cart ) {
// Initialize
$cat_cart_items = array();
$grouped_cart_items = array();
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
// Get the product categories ID for this item
$cat_ids = $cart_item['data']->get_category_ids();
// Push to array
foreach ( $cat_ids as $id ) {
$cat_cart_items[$id][$cart_item_key] = $cart_item;
}
}
// Sort an array by key in ascending order
ksort( $cat_cart_items );
// Loop through cat cart items
foreach ( $cat_cart_items as $cart_items ) {
// Loop through cart items
foreach ( $cart_items as $cart_item_key => $cart_item ) {
// Checks an array for a specified key and if the key does not exist
if ( ! array_key_exists( $cart_item_key, $grouped_cart_items ) ) {
// Push to array
$grouped_cart_items[$cart_item_key] = $cart_item;
}
}
}
// Cart contents
$cart->cart_contents = $grouped_cart_items;
}
add_action( 'woocommerce_cart_loaded_from_session', 'action_woocommerce_cart_loaded_from_session', 10, 1 );

How to add ACF field to custom column on WooCommerce admin orders list

ACF is set up for post type on WooCommerce products. However, I am trying to add a custom column to WooCommerce orders list within Admin dashboard and add the products ACF field.
I have added the column to display after order_status, but I'm having problems getting the ACF field to display.
// ADD NEW COLUMN
add_filter( 'manage_edit-shop_order_columns', 'custom_shop_order_column', 20 );
function custom_shop_order_column($columns)
{
$reordered_columns = array();
foreach( $columns as $key => $column){
$reordered_columns[$key] = $column;
if( $key == 'order_status' ){
$reordered_columns['my-column'] = __( 'Location','theme_domain');
}
}
return $reordered_columns;
}
Here, adding ACF to new colum.
// ADD ACF FIELD TO COLUMN
add_action( 'manage_shop_order_posts_custom_column' , 'custom_orders_list_column_content', 20, 2 );
function custom_orders_list_column_content( $column, $post_id )
{
if ( 'Location' == $column_name ){
$product_id = method_exists( $product, 'get_id' ) ? $product->get_id() : $product->id;
echo get_field( 'location', $product_id );
}
return true;
}
Still learning and not sure how to do this, any advice?
An order generally consists of several products, therefore you cannot use $product_id directly, but you have to loop through the order items.
So you get:
/**
* Add columns
*/
function filter_manage_edit_shop_order_columns( $columns ) {
$reordered_columns = array();
foreach ( $columns as $key => $column ) {
$reordered_columns[$key] = $column;
if ( $key == 'order_status' ) {
$reordered_columns['my-column'] = __( 'Location','theme_domain' );
}
}
return $reordered_columns;
}
add_filter( 'manage_edit-shop_order_columns', 'filter_manage_edit_shop_order_columns', 10, 1 );
/**
* Populate columns
*/
function filter_manage_shop_order_posts_custom_column( $column, $post_id ) {
// Compare
if ( $column == 'my-column' ) {
// Get order
$order = wc_get_order( $post_id );
// Is a WC_Order
if ( is_a( $order, 'WC_Order' ) ) {
// Get items
$items = $order->get_items();
// Loop through
foreach ( $items as $key => $item ) {
// Product ID
$product_id = $item->get_variation_id() > 0 ? $item->get_variation_id() : $item->get_product_id();
// Get field
$address = get_field( 'location', $product_id );
// Output
echo ($address) ? '<div>Address: ' . $address . '</div>' : '<div>Address: No address found!</div>';
}
}
}
}
add_filter( 'manage_shop_order_posts_custom_column', 'filter_manage_shop_order_posts_custom_column', 10, 2 );

Show product categories in a new column on WooCommerce "My account" orders table

I want to add a custom column, to display the product categories on the orders history table in wooCommerce
I found how to add a custom column but I can't seem to display the taxonomy's product linked to the order in this column.
For this example, I had just 1 product, but if I can display more than one tax, it will be better.
This is what I found (from : skyverge blog) to add a new column:
/**
* Adds a new column to the "My Orders" table in the account.
*
* #param string[] $columns the columns in the orders table
* #return string[] updated columns
*/
function sv_wc_add_my_account_orders_column( $columns ) {
$new_columns = array();
foreach ( $columns as $key => $name ) {
$new_columns[ $key ] = $name;
// add ship-to after order status column
if ( 'order-number' === $key ) {
$new_columns['order-ship-to'] = __( 'Catégorie', 'textdomain' );
}
}
return $new_columns;
}
add_filter( 'woocommerce_my_account_my_orders_columns', 'sv_wc_add_my_account_orders_column' );
Any pointers are welcome
With your current code you can add a column between the existing columns, however:
The woocommerce_my_account_my_orders_columns filter is deprecated since WooCommerce 2.6.0. and replaced with woocommerce_account_orders_columns
The part to add content in the column is missing
To add content you can use the woocommerce_my_account_my_orders_column_{$column_id} hook,
where $column_id need to be replaced by order-category in this particular case
So you get:
// Adds a new column to the "My Orders" table in the account.
function filter_woocommerce_account_orders_columns( $columns ) {
$new_columns = array();
foreach ( $columns as $key => $column ) {
$new_columns[ $key ] = $column;
// Add after order number column
if ( $key === 'order-number' ) {
$new_columns['order-category'] = __( 'Catégorie', 'woocommerce' );
}
}
return $new_columns;
}
add_filter( 'woocommerce_account_orders_columns', 'filter_woocommerce_account_orders_columns', 10, 1 );
// Adds data to the custom "order-category" column in "My Account > Orders"
function filter_woocommerce_my_account_my_orders_column_order( $order ) {
// Initialize
$categories = array();
// Loop through order items
foreach ( $order->get_items() as $item_key => $item ) {
// Get product ID
$product_id = $item->get_product_id();
// Get terms
$term_names = wp_get_post_terms( $product_id, 'product_cat', array( 'fields' => 'names' ) );
// Loop through term names
foreach ( $term_names as $term_name ) {
// NOT in array
if ( ! in_array( $term_name, $categories, true ) ) {
// Push one or more elements onto the end of array
array_push( $categories, $term_name );
}
}
}
// NOT empty
if ( ! empty( $categories ) ) {
echo implode( ', ', $categories );
}
}
add_action( 'woocommerce_my_account_my_orders_column_order-category', 'filter_woocommerce_my_account_my_orders_column_order', 10, 1 );

Sorting orders in backend based on SKU [duplicate]

This question already has answers here:
Sorting order items by SKU in Woocommerce
(2 answers)
Closed 2 years ago.
I am trying to sort orders added manually by sku.
I've tried all these codes:
Sort order items by SKU in Woocommerce admin order pages
Sorting order items via a hooked function in WooCommerce
Sorting order items by SKU in Woocommerce email notifications
Underneath code is working to sort by name.
add_filter('woocommerce_order_status_changed', 'sortOrderItemsSKU', 10, 2);
function sortOrderItemsSKU($items, $order) {
uasort( $items,
function( $a, $b ) {
return strcmp( $a['name'], $b['name'] );
}
);
return $items;
}
But when changing to _sku / sku both not working.
function( $a, $b ) {
return strcmp( $a['_sku'], $b['_sku'] );
}
Any help is appreciated.
I did find another solution. It returns the sorted array, but somehow the items in the order aren't being sorted:
add_action( 'woocommerce_order_status_changed', 'process_offline_order', 10, 4 );
function process_offline_order( $order_id, $items, $order, $types = 'line_item' ){
$order = new WC_Order( $order_id );
$items = $order->get_items();
$item_skus = $sorted_items = array();
foreach ( $items as $item_id => $item ) {
$product = wc_get_product( $item['product_id'] );
$product_id = $item->get_variation_id() ? $item->get_variation_id() : $item->get_product_id();
$product = $item->get_product();
$item_skus[$product->get_sku()] = $item_id;
}
ksort($item_skus);
foreach( $item_skus as $keyL => $valueL ){
$sorted_items[$keyL] = $items[$keyL];
$sorted_items[$valueL] = $items[$valueL];
}
return $item_skus;
}
So the problem is probably within this part:
foreach( $item_skus as $keyL => $valueL ){
$sorted_items[$keyL] = $items[$keyL];
$sorted_items[$valueL] = $items[$valueL];
}
return $item_skus;
Any suggestions?

Exclude grouped products children in woocommerce, without exclude simple products

THis code is working but I need to include single product without a parent grouped product associated
add_action( 'woocommerce_product_query', 'remove_grouped_children' );
function remove_grouped_children( $q ) {
//get current loop query
$taxonomy_query = $q->get('tax_query') ;
//appends the grouped products condition
$taxonomy_query['relation'] = 'AND';
$taxonomy_query[] = array(
'taxonomy' => 'product_type',
'field' => 'slug',
'terms' => array('grouped','variable')
);
$q->set( 'tax_query', $taxonomy_query );
}
This a walk-around, but finally work.
function wr_convert_array_to_ids(){
$products = wr_get_grouped_product_children();
$post_ids = array();
foreach ($products as $product){
foreach ($product as $id){
array_push($post_ids,$id);
}
}
return $post_ids;
}
function wr_get_grouped_product_children(){
global $wpdb;
$products = $wpdb->get_results(
$wpdb->prepare("SELECT * FROM $wpdb->prefix" . "postmeta WHERE meta_key = %s", '_children'),ARRAY_A
);
$products_id = array();
foreach($products as $product){
array_push($products_id, unserialize($product['meta_value']));
}
return $products_id;
}
function wr_custom_get_posts( $query ) {
if ( is_admin() || ! $query->is_main_query() )
return;
if ( $query->is_archive() || $query->is_shop()) {
$query->set( 'post__not_in', wr_convert_array_to_ids() );
}
}
add_action( 'pre_get_posts', 'wr_custom_get_posts', 1 );
Because the children of grouped products live in the post-meta table below the meta_key _children that is saved as a serialized array, the first thing is to get all the children, then save them in an array and call the 'pre_get_posts' action to exclude those identifiers.

Resources