Is it possible to allow a certain woocommerce coupon only on backorders?
I've tried to use If WooCommerce Cart items are on backorder do not apply coupon answer code that restricts backordered products from using any coupons.
I have changed if( $stock_info < 1 ){ to if( $stock_info > 0 ){ instead
But then I can only use coupons on backorders… but where do I make this work on a certain coupon?
May I use its ID? but where?
The following code will make specific defined coupons codes valid when there is backordered items in cart:
add_filter( 'woocommerce_coupon_is_valid', 'specific_coupons_valid_for_backorders', 10, 3 );
function specific_coupons_valid_for_backorders( $is_valid, $coupon, $discount ){
// HERE below define in the array your coupon codes
$coupon_codes = array( 'summer', 'tenpercent' );
if( in_array( $coupon->get_code(), $coupon_codes ) ) {
$is_valid = false;
// Loop through cart items and check for backordered items
foreach ( WC()->cart->get_cart() as $cart_item ) {
if( $cart_item['data']->is_on_backorder( $cart_item['quantity'] ) ) {
$is_valid = true; // Backorder found, coupon is valid
break; // Stop and exit from the loop
}
}
}
return $is_valid;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Related
I am trying to have mandatory Coupons when checking out for specific products in WooCommerce. I tried Allow specific products to be purchased only if a coupon is applied in Woocommerce answer code, which works perfectly.
However it allows to define only one coupon code at a time.
My client has 13 different Sales Agents that she'd like to assign coupons to.
Is there a way to define more coupons in an array (or something similar)?
For multiple coupon codes, use the following:
add_action( 'woocommerce_check_cart_items', 'mandatory_coupons_for_specific_items' );
function mandatory_coupons_for_specific_items() {
$targeted_ids = array(37); // Your targeted product ids (in this array)
$coupon_codes = array('summer2', 'summer4'); // The required coupon codes (in this array)
$applied_coupons = array_intersect( array_filter( array_map( 'sanitize_title', $coupon_codes) ), WC()->cart->get_applied_coupons() );
// Loop through cart items
foreach(WC()->cart->get_cart() as $cart_item ) {
// Check cart item for defined product Ids and applied coupon
if( in_array( $cart_item['product_id'], $targeted_ids ) && empty( $applied_coupons ) ) {
wc_clear_notices(); // Clear all other notices
// Avoid checkout displaying an error notice
wc_add_notice( sprintf( 'The product"%s" requires a coupon for checkout.', $cart_item['data']->get_name() ), 'error' );
break; // stop the loop
}
}
}
Code goes in functions.php file of the active child theme (or active theme). It should work.
It's straightforward to required registration globally in WooCommerce settings but for most of the products we sell, it's not necessary and I would rather restrict the logged in users.
However for one product I would like to require registration.
Something like
$product_id = $product->get_id();
if ($product_id !== 1024) {
remove_action( 'woocommerce_before_checkout_registration_form', 'action_woocommerce_checkout_registration_form', 10, 1 );
}
but it's obviously not that simple. Any ideas?
This answer assumes that WooCommerce > Settings > Accounts & privacy > Allow customers to place orders without an account is enabled
You can then use the following code, that will ensure that when there is 1 or more productID's in the shopping cart, registration during checkout will be required
function filter_woocommerce_checkout_registration_required( $bool_value ) {
// Several can be added, separated by a comma
$product_ids = array ( 30, 813 );
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ) {
// Product ID from cart item in specific array
if ( in_array( $cart_item['product_id'], $product_ids ) ) {
// Registration_required
$bool_value = true;
// Break loop
break;
}
}
return $bool_value;
}
add_filter( 'woocommerce_checkout_registration_required', 'filter_woocommerce_checkout_registration_required', 10, 1 );
I have a category gate for showing shipping on virtual products. Basically I have products I dont want to charge shipping on and I have them in a category called gifts... but I still want a shipping address. The problem is, is that when I use the category filter I built it wont save the address in the order... if i just use...
add_filter( 'woocommerce_cart_needs_shipping_address', '__return_true', 50 );
It works great...
But when i put the gate on it... it wont save the values... here is the gate...
//gifts filter
function HDM_gift_shipping() {
// set our flag to be false until we find a product in that category
$cat_check = false;
// check each cart item for our category
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
// if cat matches gift return true
if ( has_term( 'gift', 'product_cat', $product->id ) ) {
$cat_check = true;
// break because we only need one "true" to matter here
break;
}
}
// if a product in the cart is in our category, do something
if ( $cat_check ) {
add_filter( 'woocommerce_cart_needs_shipping_address', '__return_true', 50 );
}
}
add_action('woocommerce_before_checkout_billing_form', 'HDM_gift_shipping', 100);
There is some mistakes in your code. To get that working, you should better set your code directly in the woocommerce_cart_needs_shipping_address filter hook this way:
add_filter( 'woocommerce_cart_needs_shipping_address', 'custom_cart_needs_shipping_address', 50, 1 );
function custom_cart_needs_shipping_address( $needs_shipping_address ) {
// Loop though cat items
foreach ( WC()->cart->get_cart() as $cart_item ) {
if ( has_term( array('gift'), 'product_cat', $cart_item['product_id'] ) ) {
// Force enable shipping address for virtual "gift" products
return true;
}
}
return $needs_shipping_address;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
In cart, to handle Woocommerce custom taxonomies like product categories or tags when using has_term() WordPress conditional function, you need to use $cart_item['product_id'] instead of $cart_item['data']->get_id() that doesn't work for product variations.
I am trying to set the functionality in Woocommerce on the Add to Cart button to only allow a particular product to be added once to the Cart.
Once a particular product has been added to cart the first time, the Add to Cart needs to be hidden.
In the cart I can have any number of products - just a max of quantity 1 for each product.
I was doing research and saw that I can use woocommerce_add_to_cart_validation hook. But have no idea how to start off.
How can I allow a particular product to be added once to the Cart?
Disable add to cart button if product is in cart using woocommerce_is_purchasable hook:
add_filter( 'woocommerce_is_purchasable', 'disable_add_to_cart_if_product_is_in_cart', 10, 2 );
function disable_add_to_cart_if_product_is_in_cart ( $is_purchasable, $product ){
// Loop through cart items checking if the product is already in cart
foreach ( WC()->cart->get_cart() as $cart_item ){
if( $cart_item['data']->get_id() == $product->get_id() ) {
return false;
}
}
return $is_purchasable;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works (even for product variations in variable products).
Original answer:
Here is an example using woocommerce_add_to_cart_validation hook and that will do the trick (preventing add to cart action and displaying a custom notice when needed), and using a custom utility function that will remove quantity field for your specific defined product ID:
add_filter( 'woocommerce_add_to_cart_validation', 'limit_cart_items_from_category', 10, 3 );
function limit_cart_items_from_category ( $passed, $product_id, $quantity ){
// HERE define your product ID
$targeted_product_id = 37;
// Check quantity and display notice
if( $quantity > 1 && $targeted_product_id == $product_id ){
wc_add_notice( __('Only one item quantity allowed for this product', 'woocommerce' ), 'error' );
return false;
}
// Loop through cart items checking if the product is already in cart
foreach ( WC()->cart->get_cart() as $cart_item ){
if( $targeted_product_id == $product_id && $cart_item['data']->get_id() == $targeted_product_id ) {
wc_add_notice( __('This product is already in cart (only one item is allowed).', 'woocommerce' ), 'error' );
return false;
}
}
return $passed;
}
// Checking and removing quantity field for a specific product
add_filter( 'woocommerce_quantity_input_args', 'custom_quantity_input_args', 10, 2 );
function custom_quantity_input_args( $args, $product ) {
// HERE define your product ID
$targeted_product_id = 37;
if( $targeted_product_id == $product->get_id() )
$args['min_value'] = $args['max_value'] = $args['input_value'] = 1;
return $args;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
I need help in woocommerce shipping options, I want to hide flat rate for a particular product category, where I only want to show local delivery or local pickup options.
For all others categories all options should work.
I have try to do it with that code (added in function.php file of my theme):
function cart_has_product_with_orange_cats() {
global $woocommerce;
$product_in_cart = false;
// start of the loop that fetches the cart items
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
$terms = get_the_terms( $_product->id, 'product_cat' );
// second level loop search, in case some items have several categories
if($terms){
foreach ($terms as $term) {
$_categoryid = $term->term_id;
if ( $_categoryid == 16 ) {
//category is in cart!
$product_in_cart = true;
}
}
}
}
return $product_in_cart;
}
// add filter and function to hide method
add_filter( 'woocommerce_available_shipping_methods', 'custom_shipping_methods' , 10, 1 );
function custom_shipping_methods( $available_methods ){
if ( cart_has_product_with_orange_cats() ) {
foreach($available_methods as $key => $method){
if( $key == 'local_delivery' || $key == 'local_pickup'){
continue;
}
unset($available_methods[$key]);
}
// remove the rate you want
}
// return the available methods without the one you unset.
return $available_methods;
}
But it isn't working for me, maybe because outdated code for latest WooCommerce version or any other issue.
How can I achieve this?
Update (Compatible with WC 3+ and works with variable products too)
The fully functional tested and corrected code for this answer is located on another thread:
Shipping methods - Local Pickup option not available when Flat Rate is hidden
Important: woocommerce_available_shipping_methods hook is deprecated since WC version 2.1+ and you will need to use instead woocommerce_package_rates filter hook.
WooCommerce version 2.6+ introduce NEW shipping zones. So all WooCommerce prior version's code related to shipping rates is outdated and will not work anymore.
For info: global $woocommerce;** with $woocommerce->cart has been replaced by WC()->cart.
You will use instead WC()->cart->get_cart()…
We will not need anymore your custom conditional function, because there is already a conditional function that exist in WordPress, that you can target for WooCommerce product categories. This function accept the term ID, the term slug or the term name:
has_term( 'your_category', 'product_cat', $post_id )
So we can use has_term() conditional function in this code:
add_filter( 'woocommerce_package_rates', 'conditional_hide_shipping_methods', 100, 2 );
function conditional_hide_shipping_methods( $rates, $package ){
// Define/replace here your correct category slug (!)
$product_category = 'your_category';
$prod_cat = false;
// Going through each item in cart to see if there is anyone of your category
foreach ( WC()->cart->get_cart() as $cart_item ) {
$product_id = $cart_item['product_id'];
if ( has_term( $product_category, 'product_cat', $product_id ) ){
$prod_cat = true;
}
}
$rates_arr = array();
if ( $prod_cat ) {
foreach($rates as $key => $rate) {
if ('free_shipping' === $rate->method_id || 'local_pickup' === $rate->method_id || 'local_delivery' === $rate->method_id) {
$rates_arr[ $rate_id ] = $rate;
break;
}
}
}
return !empty( $rates_arr ) ? $rates_arr : $rates;
}
Before adding the snippet, make sure you clear your WooCommerce cache (WooCommerce > System Status > Tools > WC Transients > Clear transients), as shipping methods are cached.
This code goes on function.php file of your active child theme or theme.
This code should work if you have correctly set your shipping zones…
References:
Hide other shipping methods when FREE SHIPPING is available
WooCommerce - Hide other shipping methods when FREE SHIPPING is available
WooCommerce 2.6 - Hiding paid shipping when free shipping is triggered by reaching specific amount
WooCommerce Cart - Conditional Items categories validation
How to Setup Shipping Zones in WooCommerce 2.6