Search code examples
phpwordpresswoocommercearray-filter

Filtering the WooCommerce $order items by Category (term)


In this problem, I have all the pieces but I just can't seem to get them to fit together.

I have a printing template for WooCommerce orders that lists the products in the normal way, the order they are stored in the array which in turn is the order they were placed in the basket etc. However, we want them grouped by Category (Term). So this will mean that all items under term_id 17 are listed first, then all term_id 18, etc.

Ideally, this would be an automatic process where the code reads all of the Terms in use, then steps through them one at a time and outputs any products for that Term that are in the basket. But I'm nowhere near that stage yet.

So far I have had partial success with this code:

foreach ($order->get_items() as $item) {

     $product_id = $item['product_id'];

     $meta = $item['item_meta'];
     $meta = array_filter($meta, function ($key) {
     return !in_array($key, Order::getHiddenKeys());
}, ARRAY_FILTER_USE_KEY);

$terms = get_the_terms ( $product_id, 'product_cat' );

foreach ( $terms as $term ) {
    $cat_id = $term->term_id;
    
    if($cat_id === 18) {
        var_dump($item['name']);
    }
}

This will successfully dump the order items that are categorised in term_id 18. However, if I modify the IF statement like this:

if($cat_id === 18) {
    var_dump($item['name']);
} elseif($cat_id === 17) {
    var_dump($item['name']);
}

I would have expected it to output the term_id 18 items, then the term_id 17 ones AFTER them. Unfortunately, it simply shows the array in the default order of 17, then 18, despite the fact the code is laid out in this fashion.

I thought that maybe it was outputting in this way because it's not modifying the original array, simply masking parts of it at different points. So, I have been experimenting with the array_filter function, but I can't seem the get the logic right. I know this attempt is awful, but this is as far as I've gotten experimenting with array_filter:

function test ($var) {
    foreach ( $terms as $term ) {
        $cat_id = $term->term_id;
    
        if($cat_id === 18) {
            print_r($item['name']);
        }
    }
    return $var;
}
    
foreach ($order->get_items() as $item) {

    $product_id = $item['product_id'];

    $meta = $item['item_meta'];
    $meta = array_filter($meta, function ($key) {
    return !in_array($key, Order::getHiddenKeys());
}, ARRAY_FILTER_USE_KEY);
    
$terms = get_the_terms ( $product_id, 'product_cat' );

print_r(array_filter($terms, "test"));

I know it's significantly wrong, but I just can't get my head around it. I'm fine with basic PHP and WordPress PHP usage normally, but WooCommerce is so much more complicated!

Just to recap, I want the products in the order printed / echoed / etc in Category Order (ideally automatically). I don't really mind how this is achieved so long as it's safe and secure obviously.


Solution

  • It looks to me like you're looping the orders, but you're not looping the categories you want to be ordering them.

    I've not run this code, but the pattern should do what you want I think.

    // Group items into Categories - If you have a custom order you wish, pre-populate this array, or you can sort after
    $categories = [];
    foreach ($order->get_items() as $item) {
        $product_id = $item['product_id'];
        $terms = get_the_terms($product_id, 'product_cat');
        $cat_id = $terms[0]->term_id;
        $categories[$cat_id][] = $item;
    }
    
    // Loop Categories
    foreach($categories as $category => $items){
        echo sprintf("<h1>%s</h1>", $category);
        //Loop Items in Category
        foreach ($items as $item) {
            print_r($item['name']);
        }
    }