Getting categories id for all products in cart

What I'm trying to do is to take the categories for products which are in the cart. Then check via some conditions what category id is and show different notice.

So far I have this

/**
* Cart collaterals hook.
*
* @hooked woocommerce_cross_sell_display
* @hooked woocommerce_cart_totals - 10
*/
$categories = array( 39 );

foreach ( WC()-cart-get_cart() as $cart_item ) {
    if ( has_term( $categories, 'product_cat', $cart_item['product_id'] ) ) {
        $found = true; // Set to true
        break; // Stop the loop
    }
}        

if( $found ) {
    echo 'Category with ID = 39';
}
else if ($found != $cart_item['category_ids']) {
    echo "Category with ID = 39 and other ID('s)";
}
else {
    "Category with ID != 39";
}

Seems like $cart_item['category_ids'] doesn't return categories. $found is working and showing category with ID = 39.

When I var_dump($cart_items) I do see different categories like this:

["category_ids"]=
  array(1) {
    [0]=
    int(39)
  }
   /// another stuff in the array

["category_ids"]=
    array(2) {
      [0]=
      int(32)
      [1]=
      int(33)
    }

So, in cart I have products from categories with id 39, 32 and 33.

I've tried also WC()-cart-get_cart()-category_ids but this return NULL

UPDATE: This

$cat_ids = array();
foreach ( wc()-cart-get_cart() as $cart_item_key = $cart_item ) {
    $cat_ids = array_merge(
        $cat_ids, $cart_item['data']-get_category_ids()
    );
}

$cat_id = 39;
if ( in_array( $cat_id, $cat_ids ) ) {
    echo 'Only 39 ';
} elseif ( ! empty( $cat_ids ) ) {
    echo '39 + other';
} else {
    echo ' all other without 39';
}

Currently matching

When: category 39 + other -> Only 39

When: all other without 39 -> 39 + other

When: Only 39 -> Only 39

It should be

When: category 39 + other -> 39 + other

When: all other without 39 -> all other without 39

When: Only 39 -> Only 39

UPDATE

When: Category 39 + product from other category ( Category ID = 32, 33 etc )

var_dump(count( $cat_ids )); - int(1)
var_dump($has_cat); - bool(true)
var_dump(cat_ids); - array(1) { [0]= int(39) } ---- there are 3 products in the cart 2 of them are from other categories.

When: Category 39 only

var_dump(count( $cat_ids )); - int(1)
var_dump($has_cat); - bool(true)
var_dump(cat_ids); - array(1) { [0]= int(39) }

When: No category 39

var_dump(count( $cat_ids )); - int(2)
var_dump($has_cat); - bool(false)
var_dump(cat_ids); - array(2) { [0]= int(32) [1]= int(33) } --- product is added in 2 categories

UPDATE 2

Condition 1

1) cat 30; 
2) cat 39; 
$cond = 2 (because there are products in cart from 39 + other category)

Condition 2

1) cat 39; 
$cond = 1 (because in cart is/are product/s only from cat 39)

Condition 3

1) cat 40; 
2) cat 15;
$cond = last one (because there is no product/s from cat 39 in cart)

Topic woocommerce-offtopic categories Wordpress

Category Web


The answer from @sally works great, as long as your products are Simple products.

If your product uses a variation, then the above code no longer works as the $cart_item['data'] does not return the parent category for the variations.

This will allow you to get any products with variations - using the "product_id" to look up the "category id"

    $cat_id = '39'; // category to check against
    $cat_ids = [];
    foreach ( wc()->cart->get_cart() as $cart_item_key => $cart_item ) {
        $the_product = wc_get_product( $cart_item['product_id'] );
        $array_cat = $the_product->get_category_ids();
        if ( in_array($cat_id, $array_cat)) {
            array_push($cat_ids, $cat_id);
        }
        else {
            $cat_ids = array_merge($cat_ids, $array_cat);
        }    
    }

    // Count unique categories
    $count = count(array_unique($cat_ids));
    if ( ($count < 2) && ($cat_ids[0] == $cat_id)){
        echo 'only in category 39';
    }
    else {
        echo 'in category 39 and other';
    }

Use $cart_item['data']->get_category_ids() to retrieve the category IDs:

$category_ids = $cart_item['data']->get_category_ids(); // array

The category_ids you see is not a direct item in the $cart_item array:

var_dump( $cart_item['category_ids'] ); // null and PHP throws a notice

It's an item in a protected property of the product data ($cart_item['data']) which is an object, or a class instance — e.g. the class is WC_Product_Simple for Simple products.

UPDATE

If you want to collect all the product category IDs, you can do it like so:

$cat_ids = array();
foreach ( wc()->cart->get_cart() as $cart_item_key => $cart_item ) {
    $cat_ids = array_merge(
        $cat_ids, $cart_item['data']->get_category_ids()
    );
}
var_dump( $cat_ids );

UPDATE #2

You can use this to check if a product in the cart is in certain categories:

$cat_ids = array( 39 );
foreach ( wc()->cart->get_cart() as $cart_item_key => $cart_item ) {
    if ( has_term( $cat_ids, 'product_cat', $cart_item['data'] ) ) {
        echo 'Has category 39<br>';
    } else {
        echo 'No category 39<br>';
    }
}

UPDATE #3/#4/#5

This should work as expected:

// Collect the category IDs.
$cat_ids = array();
foreach ( wc()->cart->get_cart() as $cart_item_key => $cart_item ) {
    $cat_ids = array_merge(
        $cat_ids, $cart_item['data']->get_category_ids()
    );
}

// And here we check the IDs.
$cat_id = 39;
$count = count( $cat_ids );
if ( 1 === $count && in_array( $cat_id, $cat_ids ) ) {
    echo 'Only in category 39';
} elseif ( $count && in_array( $cat_id, $cat_ids ) ) {
    echo 'In category 39 and other categories';
} else {
    echo 'No category 39';
}

Here's an alternate version of the if block above:

if ( $count && in_array( $cat_id, $cat_ids ) ) {
    // Only one category.
    if ( $count < 2 ) {
        echo 'Only in category 39';
    // Multiple categories.
    } else {
        echo 'In category 39 and other categories';
    }
} else {
    echo 'No category 39';
}

About

Geeks Mental is a community that publishes articles and tutorials about Web, Android, Data Science, new techniques and Linux security.