I'm need to hide paypal when there's any backordered item on cart or hide cod if there's not any item to be backordered. My problem here is if there's a item that's backorder together with one that is not, I end up whitout a payment processor
add_filter( 'woocommerce_available_payment_gateways', 'backordered_items_hide_cod', 90, 1 );
function backordered_items_hide_cod( $available_gateways ) {
// Only on front end
if ( is_admin() )
return;
// Loop through cart items
foreach( WC()->cart->get_cart() as $cart_item ){
if( $cart_item['data']->is_on_backorder( $cart_item['quantity'] ) ) {
// Hide payment gateway
unset($available_gateways['paypal']);
} else {
unset($available_gateways['cod']);
break; // Stop the loop
}
}
return $available_gateways;
}
The following function will hide paypal for any backordered item found or if there is no backordered items it will hide COD instead:
add_filter( 'woocommerce_available_payment_gateways', 'backordered_items_hide_cod', 90, 1 );
function backordered_items_hide_cod( $available_gateways ) {
// Not in backend (admin)
if( is_admin() )
return $available_gateways;
$has_a_backorder = false;
// Loop through cart items
foreach( WC()->cart->get_cart() as $cart_item ){
if( $cart_item['data']->is_on_backorder( $cart_item['quantity'] ) ) {
$has_a_backorder = true;
break;
}
}
if( $has_a_backorder ) {
unset($available_gateways['paypal']);
} else {
unset($available_gateways['cod']);
}
return $available_gateways;
}
Code goes in functions.php file of your active child theme (active theme). Tested and works.
Related
we are using WooCommerce Subscription and we want, that after a subscription is added to the cart redirect the customer to the checkout page. In the past I think there was a setting to set for this but I'm not able to find it. However, now I try to do it via code.
We use AJAX in order to add to the cart. But I think this will not work. And I have to disable ajax add to cart only for some products? Like check for a category?
So I have to disable ajax add to cart only for specific products and then redirect the customer when adding such a product to the cart to checkout. The code below works if I deactivate ajax add to cart for all products and also all product will redirect to the checkout. However, we only need it for specific products.
// redirect customer to checkout page
add_filter( 'woocommerce_add_to_cart_redirect', 'custom_skip_cart_redirect_checkout' );
function custom_skip_cart_redirect_checkout( $url ) {
return wc_get_checkout_url();
}
// Fix for “Sold Individually” Products
add_filter( 'woocommerce_product_add_to_cart_url', 'custom_fix_for_individual_products', 10, 2 );
function custom_fix_for_individual_products( $add_to_cart_url, $product ){
if( $product->get_sold_individually() // if individual product
&& WC()->cart->find_product_in_cart( WC()->cart->generate_cart_id( $product->id ) ) // if in the cart
&& $product->is_purchasable() // we also need these two conditions
&& $product->is_in_stock() ) {
$add_to_cart_url = wc_get_checkout_url();
}
return $add_to_cart_url;
}
// Remove “The product has been added to your cart” message
add_filter( 'wc_add_to_cart_message_html', 'custom_remove_add_to_cart_message' );
function custom_remove_add_to_cart_message( $message ){
return '';
}
Maybe it could help:
add_filter( 'woocommerce_add_to_cart_redirect', 'redirect_to_checkout_if_product_is_subscription', 99, 1 );
function redirect_to_checkout_if_product_is_subscription( $url ) {
if ( ! isset( $_REQUEST['add-to-cart'] ) ) {
return $url;
}
$product_id = intval( $_REQUEST['add-to-cart'] );
if ( $product_id <= 0 ) {
return $url;
}
$product = wc_get_product( $product_id );
if ( WC_Subscriptions_Product::is_subscription( $product ) ) {
$url = wc_get_checkout_url();
}
return $url;
}
I am using Auto add a product for cart item from specific product categories in WooCommerce answer code to auto add a free product to the cart. The code works great if the product is in a specific category but I need to add the product if it is NOT in a specific category.
I am able to add the free product if it is not in the specific category with this edit:
if( **!** has_term( $required_categories, 'product_cat', $item['product_id'] ) ) {
$matched_category = true;
}
But this does not remove the free product when the parent product is removed.
Any help would be appreciated!
Updated: Here are the changes that are required to "auto add a product in cart except for specific defined product categories (not removing the auto added product if mixed categories are in cart):
add_action( 'woocommerce_before_calculate_totals', 'auto_add_item_except_for_product_category', 10, 1 );
function auto_add_item_except_for_product_category( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Settings
$except_terms = array('t-shirts'); // Required product category(ies)
$auto_added_id = 70; // Specific product to be added automatically
$except_found = false;
$others_found = false;
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
// Check for product category
if( has_term( $except_terms, 'product_cat', $cart_item['product_id'] ) ) {
$except_found = true;
} else {
$others_found = true;
}
// Check if specific product is already auto added
if( $cart_item['data']->get_id() == $auto_added_id ) {
$auto_added_item_key = $cart_item_key; // keep cart item key
}
}
// If auto added product is in cart with at least an item from a the defined product category only
if ( isset($auto_added_item_key) && $except_found && ! $others_found ) {
$cart->remove_cart_item( $auto_added_item_key ); // Remove specific product
}
// If there is at least an item from others product categories and the specific product is not in cart
elseif ( ! isset($auto_added_item_key) && ! $except_found ) {
$cart->add_to_cart( $auto_added_id ); // Add specific product
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Based on: Auto add a product for cart item from specific product categories in WooCommerce
Might be able to hook into the Woo's remove item from cart hook:
function remove_free_item() {
if ( is_admin() ) {
return;
}
$product_id = 'ID_OF_FREE_ITEM';
$product_cart_id = WC()->cart->generate_cart_id( $product_id );
$cart_item_key = WC()->cart->find_product_in_cart( $product_cart_id );
if ( $cart_item_key ) {
WC()->cart->remove_cart_item( $cart_item_key );
}
}
add_action( 'woocommerce_cart_item_removed', 'after_remove_product_from_cart', 10, 2 );
function after_remove_product_from_cart($removed_cart_item_key, $cart) {
// removed item
$line_item = $cart->removed_cart_contents[ $removed_cart_item_key ];
// removed item product id
$product_id = $line_item[ 'product_id' ];
// might need to wrap this in some check depending on your case
remove_free_item();
}
I have a code to add a product (a deposit) automatically to a customers cart, no matter what product he has chosen - with the code below inside the functions.php. This works fine.
But now, how to extend the code that this product will only be automatically added to the cart when the customer has chosen a product from a specific product category? E.g. the deposit shouldn't be added to the cart when a customer buys a gift card.
Thanks a lot!
/**
* Automatically adds product to cart on visit
*/
add_action( 'template_redirect', 'add_product_to_cart' );
function add_product_to_cart() {
if ( ! is_admin() ) {
$product_id = 1267; //product added automatically
$found = false;
//check if product already in cart
if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->get_id() == $product_id )
$found = true;
}
// if product not found, add it
if ( ! $found )
WC()->cart->add_to_cart( $product_id );
} else {
}
}
}
You will have to use the Wordpress conditional function hast_term() in a completely different way.
The following code will auto add to cart a pre-defined product, if a product from a product category is already in cart:
add_action( 'woocommerce_before_calculate_totals', 'auto_add_item_based_on_product_category', 10, 1 );
function auto_add_item_based_on_product_category( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
$required_categories = array('t-shirts'); // Required product category(ies)
$added_product_id = 1267; // Specific product to be added automatically
$matched_category = false;
// Loop through cart items
foreach ( $cart->get_cart() as $item_key => $item ) {
// Check for product category
if( has_term( $required_categories, 'product_cat', $item['product_id'] ) ) {
$matched_category = true;
}
// Check if specific product is already auto added
if( $item['data']->get_id() == $added_product_id ) {
$saved_item_key = $item_key; // keep cart item key
}
}
// If specific product is already auto added but without items from product category
if ( isset($saved_item_key) && ! $matched_category ) {
$cart->remove_cart_item( $saved_item_key ); // Remove specific product
}
// If there is an item from defined product category and specific product is not in cart
elseif ( ! isset($saved_item_key) && $matched_category ) {
$cart->add_to_cart( $added_product_id ); // Add specific product
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Currently i have some custom calculation of product price based on different situation. When customer added a product in to cart then the custom price is set in session data , cart_item_data['my-price'] and i implemented using add_filter( 'woocommerce_add_cart_item') function and everything seems to working now .
Now the price in view cart page, checkout page is correct with my cart_item_data['my-price'].
But the only problem i am facing is the price is not updated in woocommerce mini cart that is appeared in the menu ,How can i change this ?
When i google i see a filter
add_filter('woocommerce_cart_item_price');
but i can't understand how to use this i do the following
add_filter('woocommerce_cart_item_price','modify_cart_product_price',10,3);
function modify_cart_product_price( $price, $cart_item, $cart_item_key){
if($cart_item['my-price']!==0){
$price =$cart_item['my-price'];
}
return $price;
//exit;
}
Here individual price is getting correct , but total price is wrong
Updated (october 2021)
For testing this successfully (and as I don't know how you make calculations), I have added a custom hidden field in product add to cart form with the following:
// The hidden product custom field
add_action( 'woocommerce_before_add_to_cart_button', 'add_gift_wrap_field' );
function add_gift_wrap_field() {
global $product;
// The fake calculated price
?>
<input type="hidden" id="my-price" name="my-price" value="115">
<?php
}
When product is added to cart, this my-price custom field is also submitted (posted). To set this value in cart object I use the following function:
add_filter( 'woocommerce_add_cart_item', 'custom_cart_item_prices', 20, 2 );
function custom_cart_item_prices( $cart_item_data, $cart_item_key ) {
// Get and set your price calculation
if( isset( $_POST['my-price'] ) ){
$cart_item_data['my-price'] = $_POST['my-price'];
// Every add to cart action is set as a unique line item
$cart_item_data['unique_key'] = md5( microtime().rand() );
}
return $cart_item_data;
}
Now to apply (set) the new calculated price my-price to the cart item, I use this last function:
// For mini cart *(cart item displayed price)*
add_action( 'woocommerce_cart_item_price', 'filter_cart_item_price', 10, 2 );
function filter_cart_item_price( $price, $cart_item ) {
if ( ! is_checkout() && isset($cart_item['my-price']) ) {
$args = array( 'price' => floatval( $cart_item['my-price'] ) );
if ( WC()->cart->display_prices_including_tax() ) {
$product_price = wc_get_price_including_tax( $cart_item['data'], $args );
} else {
$product_price = wc_get_price_excluding_tax( $cart_item['data'], $args );
}
return wc_price( $product_price );
}
return $price;
}
add_action( 'woocommerce_before_calculate_totals', 'set_calculated_cart_item_price', 20, 1 );
function set_calculated_cart_item_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( isset( $cart_item['my-price'] ) && ! empty( $cart_item['my-price'] ) || $cart_item['my-price'] != 0 ){
// Set the calculated item price (if there is one)
$cart_item['data']->set_price( $cart_item['my-price'] );
}
}
}
All code goes in function.php file of your active child theme (or active theme).
Tested and works
I try to disable a shipping method if a specific shipping class is in the cart. I'm using the newest woocommerce version.
Below is my Code for my task.
It's placed at the end of my functions.php file of my Theme.
Sadly its not working.
add_filter( 'woocommerce_package_rates', 'businessbloomer_hide_free_shipping_for_shipping_class', 10, 2 );
function businessbloomer_hide_free_shipping_for_shipping_class( $rates, $package ) {
$shipping_class_target = 513; // ID OF MY SHIPPING_CLASS
$in_cart = false;
foreach( WC()->cart->cart_contents as $key => $values ) {
if( $values[ 'data' ]->get_shipping_class_id() == $shipping_class_target ) {
$in_cart = true;
break;
}
}
if( $in_cart ) {
unset( $rates['flat_rate:2'] ); //VALUE:ID OF MY SHIPPING METHOD
}
return $rates;
}
I have tested simplifying a little your code (with the ids of my WC settings) and it works:
add_filter( 'woocommerce_package_rates', 'custom_hide_shipping_methods', 10, 2 );
function custom_hide_shipping_methods( $rates, $package ) {
foreach( WC()->cart->get_cart() as $cart_item ) {
$product = $cart_item[ 'data' ]; // The WC_Product object
$shipping_class_id = $product->get_shipping_class_id();
if( isset($rates['flat_rate:2']) && $shipping_class_id == 513 ) { // <== ID OF MY SHIPPING_CLASS
unset( $rates['flat_rate:2'] ); // Removing specific shipping method
break; // we stop the loop
}
}
return $rates;
}
So your code should work too (if you have set the correct IDs)
BUT you need (after saving your code to the function.php file of your active theme):
To remove all cart items that are remaining in cart when testing.
To refresh the shipping caches:
To do it, you can go in a shipping zone and disable one "flat rate" (for example) and "save". Then re-enable that "flat rate" and "save". You are done.
Now you can test again and it should work