currently i can check if the cart contains categories (or a specific category) with this function..
function check_the_cart_for_categories() {
// holds checks for all products in cart to see if they're in our category
$category_checks = array();
// check each cart item for our category
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
$product_in_cat = false;
if ( has_term( array('clothing', 'shoes','hats'), 'product_cat', $product->id ) ) {
#if ( has_term( 'clothing', 'product_cat', $product->id ) ) { //or for one
$product_in_cat = true;
}
array_push( $category_checks, $product_in_cat );
}
// if all items are in this category, do something
if ( ! in_array( false, $category_checks, true ) AND $ship_check ) {
echo "showmessage";
}
}
add_action( 'woocommerce_proceed_to_checkout' , 'check_the_cart_for_categories');
add_action( 'woocommerce_review_order_before_submit' , 'check_the_cart_for_categories');
but i want to check if the cart contains SHOES and HATS! (not any of them) ?
thank you!
Your code can be done but need to do fix some bugs. check my below code.
function check_the_cart_for_categories() {
// holds checks for all products in cart to see if they're in our category
$product_in_cat = false;
// check each cart item for our category
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product_id = $cart_item['product_id'];
if ( has_term( 'shoes', 'product_cat', $product_id ) && has_term( 'hats', 'product_cat', $product_id ) ) {
$product_in_cat = true;
}
break;
}
// if all items are in this category, do something
if ( $product_in_cat ) {
echo "showmessage";
}
}
add_action( 'woocommerce_proceed_to_checkout', 'check_the_cart_for_categories' );
add_action( 'woocommerce_review_order_before_submit', 'check_the_cart_for_categories' );
UPDATE as per OP request. ( check both categories in cart )
function check_the_cart_for_categories() {
// Categories in a coma separated array
$must_categories = array('shoes','hats');
$fee_amount = 0;
$product_cat = array();
// Loop through cart items
foreach( $cart->get_cart() as $cart_item ){
$terms = get_the_terms( $cart_item['product_id'], 'product_cat' );
foreach ($terms as $term) {
$product_cat[] = $term->slug;
}
}
foreach ( $must_categories as $key => $must_cat ) {
if( in_array($must_cat, $product_cat) ){
$product_in_cat = true;
}else{
$product_in_cat = false;
break;
}
}
// if all items are in this category, do something
if ( $product_in_cat ) {
echo "showmessage";
}
}
add_action( 'woocommerce_proceed_to_checkout', 'check_the_cart_for_categories' );
add_action( 'woocommerce_review_order_before_submit', 'check_the_cart_for_categories' );
Related
I am trying to put together a function to hide a shipping method if there is a finished product category in the cart and if that category is not in the cart then hide another one.
This is the function that I have been able to put together, but it doesn't work. Can you help me please?
function product_category_find_id_in_cart() {
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ){
if ( has_term( 'hangers', 'product_cat', $cart_item['product_id'] ) ) {
unset( $rates['free_shipping1'] );
}
else {
unset( $rates['flat_rate:6'] );
}
return $rates;
}
}
I need it to also work for various shipping methods, not just to hide one. Thank you!
Thanks to # 7uc1f3r I have a new code that hides the shipping method if the product belongs to a category, but I need that if the product does not belong to that category other shipping methods are hidden. This would be the new formula, thanks to #LoicTheAztec:
add_filter( 'woocommerce_package_rates', 'specific_products_shipping_methods', 10, 2 );
function specific_products_shipping_methods( $rates, $package ) {
// HERE set the product category in the array (ID, slug or name)
$terms = array( 'hangers' );
$taxonomy = 'product_cat';
// HERE set the shipping methods to be removed (like "fat_rate:5")
$method_instances_ids = array('1');
$found = false;
// Loop through cart items checking for defined product IDs
foreach( $package['contents'] as $cart_item ) {
if ( has_term( $terms, $taxonomy, $cart_item['product_id'] ) ){
$found = true;
break;
}
}
if ( ! $found ) return $rates; // If not found we exit
// Loop through your active shipping methods
foreach( $rates as $rate_id => $rate ) {
// Remove all other shipping methods other than your defined shipping method
if ( in_array( $rate_id, $method_instances_ids ) ){
unset( $rates[$rate_id] );
}
}
return $rates;
}
I found it!!
add_filter( 'woocommerce_package_rates', 'specific_products_shipping_methods', 10, 2 );
function specific_products_shipping_methods( $rates, $package ) {
// HERE set the product category in the array (ID, slug or name)
$terms = array( 'hangers' );
$taxonomy = 'product_cat';
// HERE set the shipping methods to be removed (like "fat_rate:5")
$method_instances_ids = array('flat_rate:12','flat_rate:13','flat_rate:14');
$found = false;
// Loop through cart items checking for defined product IDs
foreach( $package['contents'] as $cart_item ) {
if ( has_term( $terms, $taxonomy, $cart_item['product_id'] ) ){
$found = true;
break;
}
}
if ( ! $found ) { unset( $rates['flat_rate:6'],$rates['flat_rate:7'],$rates['flat_rate:8'],$rates['flat_rate:9'],$rates['flat_rate:10'],$rates['flat_rate:11'] ); return $rates;} // If not found we exit
else {
// Loop through your active shipping methods
foreach( $rates as $rate_id => $rate ) {
// Remove all other shipping methods other than your defined shipping method
if ( in_array( $rate_id, $method_instances_ids ) ){
unset( $rates[$rate_id] );
}
}
return $rates;
}}
I'm trying to disable shipping method (and allow only local pickup) if:
Cart only contains items from a specific category.
Cart only contains items from a specific category combination.
I can successfully block one specific category, but how can I extend that for/by category combinations (if statement doesn't work)?
Thanks you
add_filter( 'woocommerce_package_rates', 'acessory_hide_shipping_methods', 90, 2 );
function acessory_hide_shipping_methods( $rates, $package ){
$category = 'acessory';
$product_cat = get_term_by( 'slug', $category, 'product_cat' );
$rates_arr = array();
if ( wp_is_category_alone_in_cart( $category ) && ! WC()->cart->is_empty() ) {
foreach($rates as $rate_id => $rate) {
if ('local_pickup' === $rate->method_id) {
$rates_arr[ $rate_id ] = $rate;
}
}
}
return !empty( $rates_arr ) ? $rates_arr : $rates;
}
function wp_is_category_alone_in_cart( $category ) {
$category_checks = array();
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
$product_in_cat = has_term( $category, 'product_cat', $product->get_id() );
array_push( $category_checks, $product_in_cat );
}
return ! in_array( false, $category_checks, true );
}
I'm trying to set notifications when I have products from these two different categories inside the card in WooCommerce.
This is the code which I using:
add_action( 'woocommerce_checkout_before_customer_details', 'webroom_check_if_product_category_is_in_cart' );
function webroom_check_if_product_category_is_in_cart() {
$cat_in_cart = false;
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
if ( has_term( 'cat1', 'product_cat', $cart_item['product_id'] ) &&
has_term( 'cat2', 'product_cat', $cart_item['product_id'] ) ) {
$cat_in_cart = true;
break;
}
}
if ( $cat_in_cart ) {
$notice = 'Notification';
wc_print_notice($notice, 'notice');
}
}
This code works perfectly if I only set one category, but when I set two categories, for some reason I don't have results nor errors.
This should get you what you want. The problem is in your original function, is that you were checking each product if it had both categories.
You need to split up the the conditions and then check the final conditions.
add_action( 'woocommerce_checkout_before_customer_details', 'webroom_check_if_product_category_is_in_cart' );
function webroom_check_if_product_category_is_in_cart() {
$cat_one_in_cart = false;
$cat_two_in_cart = false;
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
if ( has_term( 'cat1', 'product_cat', $cart_item ) ) {
$cat_one_in_cart = true;
break;
}
if ( has_term( 'cat2', 'product_cat', $cart_item ) ) {
$cat_two_in_cart = true;
break;
}
}
if ( $cat_one_in_cart && $cat_two_in_cart ) {
$notice = 'Notification';
wc_print_notice($notice, 'notice');
}
}
Here is the solution:
add_action( 'woocommerce_before_cart', 'webroom_check_if_product_category_is_in_cart' );
function webroom_check_if_product_category_is_in_cart() {
$cat1_in_cart = false;
$cat2_in_cart = false;
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
if ( has_term( 'cat1', 'product_cat', $cart_item['product_id'] ) ) {
$cat1_in_cart = true;
} elseif(has_term( 'cat2', 'product_cat', $cart_item['product_id'] )){
$cat2_in_cart = true;
}
}
if ($cat1_in_cart === true && $cat2_in_cart === true) {
$notice = 'Notification';
wc_print_notice($notice, 'notice');
}
}
I am working with two main parent categories on my store, each one subdivided on almost 10 categories.
I have a script that limits to 1 the number of categories added to the cart, What can I do to change it to only parent categories?, so I can select multiple products of the same kind.
function is_product_the_same_cat($valid, $product_id, $quantity) {
global $woocommerce;
if($woocommerce->cart->cart_contents_count == 0){
return true;
}
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
$terms = get_the_terms( $_product->id, 'product_cat' );
$target_terms = get_the_terms( $product_id, 'product_cat' );
foreach ($terms as $term) {
$cat_ids[] = $term->term_id;
}
foreach ($target_terms as $term) {
$target_cat_ids[] = $term->term_id;
}
}
$same_cat = array_intersect($cat_ids, $target_cat_ids);
if(count($same_cat) > 0) return $valid;
else {
wc_add_notice( 'Solo pueden comprarse productos de una misma categorÃa.', 'error' );
return false;
}
}
add_filter( 'woocommerce_add_to_cart_validation', 'is_product_the_same_cat',10,3);
Since WooCommerce 3, the code you are using is outdated… The following will work with the parent product category, allowing only add to cart from the same parent product category:
add_filter( 'woocommerce_add_to_cart_validation', 'avoid_add_to_cart_from_different_main_categories', 10, 3 );
function avoid_add_to_cart_from_different_main_categories( $passed, $product_id, $quantity ) {
$cart = WC()->cart;
$taxonomy = 'product_cat';
$ancestors = [];
if( $cart->is_empty() )
return $passed;
$terms = (array) wp_get_post_terms( $product_id, $taxonomy, array('fields' => 'ids') );
if( count($terms) > 0 ) {
// Loop through product category terms set for the current product
foreach( $terms as $term) {
foreach( get_ancestors( $term, $taxonomy ) as $term_id ) {
$ancestors[(int) $term_id] = (int) $term_id;
}
}
// Loop through cart items
foreach ( $cart->get_cart() as $item ) {
$terms = (array) wp_get_post_terms( $item['product_id'], $taxonomy, array('fields' => 'ids') );
if( count($terms) > 0 ) {
// Loop through product category terms set for the current cart item
foreach( $terms as $term) {
foreach( get_ancestors( $term, $taxonomy ) as $term_id ) {
$ancestors[(int) $term_id] = (int) $term_id;
}
}
}
}
// When there is more than 1 parent product category
if( count($ancestors) > 1 ) {
wc_add_notice( __('Only products of the same category can be purchased together.'), 'error' );
$passed = false;
}
}
return $passed;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
I want implement functionality on my site when user buy a x product then user will get a y product as free.
In my site i have variable products.If customer buy 1kg pack of X product then customer want to get Free 30ml of Y product.
I added below code in my function.php but its working the problem is when refreshing the page gift product count is increasing.
my updated code.
add_action( 'woocommerce_before_cart', 'bbloomer_apply_matched_coupons' );
function bbloomer_apply_matched_coupons() {
global $woocommerce;
$cat_in_cart = false;
foreach ( $woocommerce->cart->cart_contents as $key => $values ) {
// this is your product ID
$autocoupon = array( 123411 );
if( in_array( $values['variation_id'], $autocoupon ) ) {
$cat_in_cart = true;
break;
}
}
if ( $cat_in_cart ) {
$product_id = 2044;
$quantity = 1;
$variation_id = 2046;
$variation = array(
'pa_size' => '30ml'
);
$woocommerce->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation );
}
}
Add this to start of 'functions.php'.
ob_start();
session_start();
Then add this code.
add_action( 'woocommerce_before_cart', 'bbloomer_apply_matched_coupons' );
function bbloomer_apply_matched_coupons() {
if(!$_SESSION['GiftAdded']) {
global $woocommerce;
$cat_in_cart = false;
$coupon_in_cart = false;
$autocoupon = array( 123411 ); // variation ids of products that offers gifts
$freecoupon = array( 2046 ); // variation ids of products that are gift coupons
foreach ( $woocommerce->cart->cart_contents as $key => $values ) {
if( in_array( $values['variation_id'], $autocoupon ) ) {
$cat_in_cart = true;
}
if( in_array( $values['variation_id'], $freecoupon) ) {
$coupon_in_cart = true;
}
}
if ( $cat_in_cart && !$coupon_in_cart ) {
$product_id = 2044;
$quantity = 1;
$variation_id = 2046;
$variation = array( 'pa_size' => '30ml' );
$woocommerce->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation );
$_SESSION['GiftAdded']=true;
}
}
}
The $_SESSION['GiftAdded'] will prevent the gift product added again when its deleted manually.
There is an other alternative based on quantity using another hook… It handles when quantities are changed or products removed from cart and set the price of the free product to zero:
add_action( 'woocommerce_before_calculate_totals', 'add_free_product_to_cart', 20, 1 );
function add_free_product_to_cart( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
$products_ids = array( 123411 ); // Products IDs to check
$free_var_id = 2046; // free product (variation ID)
$free_prod_id = 2044; // free product (product ID)
$free_attr = array( 'pa_size' => 'medium' ); // Free product attribute
$free_price = 0;
$targeted = $free = array('qty' => 0 ); // Initializing
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
if ( in_array( $cart_item['data']->get_id(), $products_ids ) ) {
$targeted['qty'] += $cart_item['quantity'];
} elseif ( $cart_item['data']->get_id() == $free_var_id ) {
$cart_item['data']->set_price($free_price);
$free['qty'] += $cart_item['quantity'];
$free['key'] = $cart_item_key;
}
}
// We exit (No changes are needed)
if( $targeted['qty'] == $free['qty'] )
return;
if( $targeted['qty'] > 0 && $free['qty'] == 0 )
{
// Add the free product
$cart->add_to_cart( $free_prod_id, $targeted['qty'], $free_var_id, $free_attr );
}
elseif( $targeted['qty'] > 0 && $free['qty'] > 0 && $targeted['qty'] != $free['qty'] )
{
// Adjust free product quantity
$cart->set_quantity( $free['key'], $targeted['qty'] );
}
elseif( $targeted['qty'] == 0 && $free['qty'] > 0)
{
// Remove free product
$cart->remove_cart_item( $free['key'] );
}
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.