WooCommerce remove shipping method based on product IDs & quantity bought - php

I am trying to remove a shipping method based on two parameters in my cart.
Parameter 1 = Product ID
Parameter 2 = Quantity added for that Product ID.
I have been searching around and combining different solutions, however using the snippet underneath still doesn't give me the correct result. The expected result would be that if any of the products ( 6 , 9, 69 , 71 ) are added 52 times to my cart, the shipping fee (flexible_shipping_2_1) should dissapear.
All suggestions would be appreciated.
add_filter( 'woocommerce_package_rates', 'specific_products_shipping_methods', 10, 2 );
function specific_products_shipping_methods( $rates, $package ) {
$product_ids = array( 6 , 9, 69 , 71 ); // HERE set the product IDs in the array
$method_id = 'flexible_shipping_2_1'; // HERE set the shipping method ID
$found = false;
// Loop through cart items Checking for defined product IDs
foreach( WC()->cart->get_cart_contents() as $cart_item_key => $cart_item ) {
if ( in_array( $cart_item['product_id'], $product_ids ) && $cart_item['quantity'] == 52){
$found = true;
break;
}
}
if ( $found )
unset( $rates[$method_id] );
return $rates;
}

Maybe this is what you would like (to get the cumulated quantity for all defined product ids):
add_filter( 'woocommerce_package_rates', 'specific_products_shipping_methods', 10, 2 );
function specific_products_shipping_methods( $rates, $package ) {
$product_ids = array( 6 , 9, 69 , 71 ); // HERE set the product IDs in the array
$method_id = 'flexible_shipping_2_1'; // HERE set the shipping method ID
$quantity = 0;
// Get cart items for the current shipping package
foreach( $package['contents'] as $cart_item ) {
if ( in_array( $cart_item['product_id'], $product_ids ) ){
$quantity += $cart_item['quantity'];
}
}
if ( $quantity >= 52 && isset($rates[$method_id]) ) {
unset($rates[$method_id]);
}
return $rates;
}
Don't forget to empty your cart, to refresh shipping cached data…

Related

Hide multiple shipping methods for specific products in Woocommerce [duplicate]

I want to hide a set of shipping methods if a set of products are selected on WooCommerce
I think I'm almost there but I am getting an error on the unset( $rates[$method_ids] ) line.
Here's what I've got so far:
add_filter( 'woocommerce_package_rates', 'specific_products_shipping_methods_hide_many', 10, 2 );
function specific_products_shipping_methods_hide_many( $rates, $package ) {
$product_ids = array( 240555 ); // HERE set the product IDs in the array
$method_ids = array( 'flat_rate:7', 'flat_rate:13', 'flat_rate:26', 'flat_rate:27', 'local_pickup:24' ) ; // HERE set the shipping method IDs
$found = false;
// Loop through cart items Checking for defined product IDs
foreach( $package['contents'] as $cart_item ) {
if ( in_array( $cart_item['product_id'], $product_ids ) ){
$found = true;
break;
}
}
if ( $found )
unset( $rates[$method_ids] );
return $rates;
}
Any advice?
You are close, but you need to loop through $rates and if it occurs $rate_id, you can unset it
So you get:
function filter_woocommerce_package_rates( $rates, $package ) {
// Set the product IDs in the array
$product_ids = array( 240555, 30 );
// Set the rate IDs in the array
$rate_ids = array( 'flat_rate:7', 'flat_rate:13', 'flat_rate:26', 'flat_rate:27', 'local_pickup:24', 'local_pickup:1', 'free_shipping:2' );
// Initialize
$found = false;
// Loop through cart items checking for defined product IDs
foreach( $package['contents'] as $cart_item ) {
// Checks if a value exists in an array
if ( in_array( $cart_item['product_id'], $product_ids ) ) {
$found = true;
break;
}
}
// True
if ( $found ) {
// Loop trough
foreach ( $rates as $rate_id => $rate ) {
// Checks if a value exists in an array
if ( in_array( $rate_id, $rate_ids ) ) {
unset( $rates[$rate_id] );
}
}
}
return $rates;
}
add_filter( 'woocommerce_package_rates', 'filter_woocommerce_package_rates', 10, 2 );

Hide multiple shipping methods based on product IDs in WooCommerce

I want to hide a set of shipping methods if a set of products are selected on WooCommerce
I think I'm almost there but I am getting an error on the unset( $rates[$method_ids] ) line.
Here's what I've got so far:
add_filter( 'woocommerce_package_rates', 'specific_products_shipping_methods_hide_many', 10, 2 );
function specific_products_shipping_methods_hide_many( $rates, $package ) {
$product_ids = array( 240555 ); // HERE set the product IDs in the array
$method_ids = array( 'flat_rate:7', 'flat_rate:13', 'flat_rate:26', 'flat_rate:27', 'local_pickup:24' ) ; // HERE set the shipping method IDs
$found = false;
// Loop through cart items Checking for defined product IDs
foreach( $package['contents'] as $cart_item ) {
if ( in_array( $cart_item['product_id'], $product_ids ) ){
$found = true;
break;
}
}
if ( $found )
unset( $rates[$method_ids] );
return $rates;
}
Any advice?
You are close, but you need to loop through $rates and if it occurs $rate_id, you can unset it
So you get:
function filter_woocommerce_package_rates( $rates, $package ) {
// Set the product IDs in the array
$product_ids = array( 240555, 30 );
// Set the rate IDs in the array
$rate_ids = array( 'flat_rate:7', 'flat_rate:13', 'flat_rate:26', 'flat_rate:27', 'local_pickup:24', 'local_pickup:1', 'free_shipping:2' );
// Initialize
$found = false;
// Loop through cart items checking for defined product IDs
foreach( $package['contents'] as $cart_item ) {
// Checks if a value exists in an array
if ( in_array( $cart_item['product_id'], $product_ids ) ) {
$found = true;
break;
}
}
// True
if ( $found ) {
// Loop trough
foreach ( $rates as $rate_id => $rate ) {
// Checks if a value exists in an array
if ( in_array( $rate_id, $rate_ids ) ) {
unset( $rates[$rate_id] );
}
}
}
return $rates;
}
add_filter( 'woocommerce_package_rates', 'filter_woocommerce_package_rates', 10, 2 );

Adding cart fees based on product’s category and quantity using php (WooCommerce 4.5.1 )

I've tried searching for an answer to this but most of the code is old or not exactly what I'm looking for. Here is the scenario - when people order digital image rights from our store, they must pay for it's usage as well as a copy fee. The usage fee is variable based on several factors and non-taxable - this would be the product added to the cart. The copy fee is a fixed, taxable, cost per image. I want this to be automatically added to my cart whenever an product from the 'images' category is added.
I found code on WPFactory that adds a fee based on category that works well.
add_action( 'woocommerce_cart_calculate_fees', 'wpf_wc_add_cart_fees_by_product_category' );
if ( ! function_exists( 'wpf_wc_add_cart_fees_by_product_category' ) ) {
/**
* wpf_wc_add_cart_fees_by_product_category.
*/
function wpf_wc_add_cart_fees_by_product_category( $cart ) {
// You need to enter your fees here, in `category slug` => `fee amount` format
$fees = array(
'images' => 25,
);
foreach ( $cart->get_cart() as $cart_item_key => $values ) {
$product_categories = get_the_terms( $values['product_id'], 'product_cat' );
if ( $product_categories && ! is_wp_error( $product_categories ) ) {
$product_categories = wp_list_pluck( $product_categories, 'slug' );
foreach ( $product_categories as $product_category ) {
if ( ! empty( $fees[ $product_category ] ) ) {
$name = 'Digital Image Copy Fee'
$amount = $fees;
$taxable = true;
$tax_class = '';
$cart->add_fee( $name, $amount, $taxable, $tax_class );
}
}
}
}
}
}
The problem is, it only adds the fee once and I need it to multiply the fee based on the total quantity of items from the category in the cart. I've attempted to calculate $qty and multiply $fee by $qty but my php is incredibly rusty and I have not been successful. Any help would be much appreciated.
Here is the solution:
add_action( 'woocommerce_cart_calculate_fees', 'wpf_wc_add_cart_fees_by_product_category', 10, 1 );
function wpf_wc_add_cart_fees_by_product_category( $cart ) {
$product_cat_id = 119; // set "image" cat id
$total_qty = 0; // initialize qty products
$fee = 25; // set fee amount
foreach ( $cart->get_cart() as $cart_item ) {
$product_id = $cart_item['product_id'];
// get all category ids by product id
$categories = wp_get_post_terms( $product_id, 'product_cat', array( 'fields' => 'ids' ) );
// if product has "image" category
if ( in_array( $product_cat_id, $categories ) ) {
// get quantity
$total_qty += $cart_item['quantity'];
}
}
if ( $total_qty > 0 ) {
$tax = true; // set "false" for no tax
$cart->add_fee( __( "Digital Image Copy Fee", "woocommerce" ), $fee * $total_qty, $tax ); // add custom fee
}
}
The code goes into your theme's functions.php file and it works.

Hide shipping methods by product category and if not

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

Sync custom product price by product category on cart items in Woocommerce

i have to arrange product price based on category . So every product in category A have price 5 ,
and in category B product price is 10 and in category c product price is 15 .
After this arrangement , when product is adding to cart , then i have to multiply product price by our margin . Currently our margin is 2.5.
So we write following codes in fucntions.php
add_filter('woocommerce_product_get_price', 'product_price_new', 10, 2);
function product_price_new($price, $product) {
if(!is_cart()){
if(has_term( 'accessories', 'product_cat' ,$product->id)){ $price=5; }
if(has_term( 'hoodies', 'product_cat' ,$product->id)){ $price=10; }
if(has_term( 'tshirts', 'product_cat' ,$product->id)){ $price=15;}
}
return $price;
}
add_filter( 'woocommerce_add_cart_item_data', 'margin_price', 30, 3 );
function margin_price( $cart_item_data, $product_id, $variation_id ) {
$the_id = $variation_id > 0 ? $variation_id : $product_id;
$product = wc_get_product( $the_id );
$product_price = (float) $product->get_price();
$cart_item_data['calculated-price'] = $product_price*2.5;
return $cart_item_data;
}
add_action( 'woocommerce_before_calculate_totals', 'add_caculted', 20, 1 );
function add_caculted( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ){
if( ! empty( $cart_item['calculated-price'] ) ){
// Set the calculated item price (if there is one)
$cart_item['data']->set_price( $cart_item['calculated-price'] );
}
}
}
Please see what happen .
For example if we are trying to add product in category hoodies , so price will be , 10 *2.5=25
(1) in cart page product pric is showing 25 , and this is correct .
[mywebsite.com/cart]
(2) In checkout page product price is showing 10, so the total is
coming as 10 . This is wrong it should be 25 .
(3) In the minicart that showing near the menu , it showing 1*10 and subtotal is 10 , but it NEED to show 1 *25 and subtotal = 25
Please help to solve this issue . What i missed ?
i tried all this code in default woocommerce storfront theme . https://woocommerce.com/storefront/
Only for simple products, you can try the following instead:
// Utility function
function get_special_product_category_prices( $price, $product_id ) {
// HERE your prices by product category
$prices_by_cat = array( 5 => 'accessories', 10 => 'hoodies', 15 => 't-shirts' );
foreach( $prices_by_cat as $key_price => $term ){
if( has_term( $term, 'product_cat', $product_id ) )
return $key_price;
}
return $price;
}
// Alter product displayed prices (for simple products only)
add_filter( 'woocommerce_get_price_html', 'alter_displayed_price_html', 20, 2 );
function alter_displayed_price_html( $price, $product ) {
if( $product->is_type('simple') ){
$raw_price = get_special_product_category_prices( $product->get_price(), $product->get_id() );
if( $raw_price > 0 )
$price = wc_price( wc_get_price_to_display( $product, array( 'price' => $raw_price ) ) );
}
return $price;
}
add_filter( 'woocommerce_add_cart_item_data', 'add_calculated_margin_price', 30, 3 );
function add_calculated_margin_price( $cart_item_data, $product_id, $variation_id ) {
$the_id = $variation_id > 0 ? $variation_id : $product_id;
$product = wc_get_product( $the_id );
$product_price = (float) get_special_product_category_prices( $product->get_price(), $product_id );
$cart_item_data['calculated-price'] = $product_price * 2.5;
return $cart_item_data;
}
add_action( 'woocommerce_before_calculate_totals', 'set_caculated_price', 20, 1 );
function set_caculated_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ){
if( ! empty( $cart_item['calculated-price'] ) ){
// Set the calculated item price (if there is one)
$cart_item['data']->set_price( $cart_item['calculated-price'] );
}
}
}
Code goes in function.php file of your active child theme (or theme). It should work.

Categories