I'm trying to create a custom function for a WooCommerce shipping plugin by wooforce. There are two plugins, ups and usps.
What I'm trying to achieve is if a customer adds a product from category X or any of its sub categories, all rates except for ups ground get unset.
If those products are not present in the cart, all options remain available.
The developers pointed me to this code, but I'm still pretty new to PHP and WordPress/WooCommerce structured PHP so I'm a bit stuck as how to proceed.
Here's the code they gave me.
add_filter('woocommerce_package_rates', 'hide_shipping_method_when_shipping_class_product_is_not_in_cart', 10, 2);
function hide_shipping_method_when_shipping_class_product_is_not_in_cart($available_shipping_methods, $package)
{
// Shipping class IDs that need the method removed
$shipping_class_ids = array(
27,
);
$shipping_services_to_hide = array(
'wf_fedex_woocommerce_shipping:FEDEX_GROUND',
'wf_fedex_woocommerce_shipping:FEDEX_2_DAY_AM'
);
$shipping_class_exists = false;
foreach(WC()->cart->cart_contents as $key => $values) {
if (in_array($values['data']->get_shipping_class_id() , $shipping_class_ids)) {
$shipping_class_exists = true;
break;
}
}
if (!$shipping_class_exists) {
foreach($shipping_services_to_hide as & $value) {
unset($available_shipping_methods[$value]);
}
}
return $available_shipping_methods;
}
I was able to figure this out on my own. Here's the code for anyone who may need this function in the future.
This function works specifically with the WooForce Shipping plugins.
add_filter('woocommerce_package_rates', 'hide_shipping_method_when_shipping_class_product_is_not_in_cart', 10, 2);
function hide_shipping_method_when_shipping_class_product_is_not_in_cart($available_shipping_methods, $package){
// 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'];
// replace 'membership' with your category's slug
if ( has_term( 'ammo', '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 ) {
// we have the category, do what we want
// Shipping class IDs that need the method removed
$shipping_class_ids = array(
1,
2,
3,
18,
23,
33,
47,
49
);
$shipping_services_to_hide = array(
'wf_shipping_usps:D_PRIORITY_MAIL',
'wf_shipping_usps:D_EXPRESS_MAIL'
);
$shipping_class_exists = false;
foreach(WC()->cart->cart_contents as $key => $values) {
if (in_array($values['data']->get_shipping_class_id() , $shipping_class_ids)) {
$shipping_class_exists = true;
break;
}
}
if (!$shipping_class_exists) {
foreach($shipping_services_to_hide as & $value) {
unset($available_shipping_methods[$value]);
}
}
return $available_shipping_methods;
}
else{
return $available_shipping_methods;
}
}
Related
I added a plugin that creates a shipping method with Id "pisol_extended_flat_shipping:52540" when the product category is "baby-care" and the country is "India" and It's working fine. When someone adds different products from different categories in the cart and one of the categories is "baby-care". then I want to hide the "pisol_extended_flat_shipping:52540" shipping when there are other category products at the checkout along with "baby-care".
I tried this code, but not working
function check_cart_categories() {
$baby_care = false;
$other_categories = false;
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
if ( has_term( 'baby-care', 'product_cat', $product->id ) ) {
$baby_care = true;
} else {
$other_categories = true;
}
}
return ( $baby_care && $other_categories );
}
add_filter( 'woocommerce_available_shipping_methods', 'hide_pisol_extended_flat_shipping' );
function hide_pisol_extended_flat_shipping( $available_methods ) {
if ( check_cart_categories() ) {
unset( $available_methods['pisol_extended_flat_shipping:52540'] );
}
return $available_methods;
}
Here is the full code:
function check_cart_categories() {
// your logic here...
}
add_filter( 'woocommerce_package_rates', 'hide_pisol_extended_flat_shipping' , 10, 2 );
function hide_pisol_extended_flat_shipping( $rates, $package ) {
if ( check_cart_categories() ) {
unset( $rates['pisol_extended_flat_shipping:52540'] );
}
return $rates;
}
If it doesn't work, try increasing the priority of the hook (I set default 10). Some plugins are also using this hook and could interfere.
In Woocommerce, i want to hide the credit card payment option if a specific product variation is in the cart. Please help.
Thanks.
This is what i have working now. I assigned a separate shipping class to each variation i want to disable a specific payment method at checkout. But it would be much easier if i coud target specific attribute values, so i don't have to assign a shipping class.
<?php
add_filter('woocommerce_available_payment_gateways', 'conditional_payment_gateways', 10, 1);
function conditional_payment_gateways( $available_gateways ) {
$shipping_class_target = 106; // the shipping class ID assigned to specific variations
$in_cart = false;
foreach ( WC()->cart->get_cart_contents() as $key => $values ) {
if ( $values[ 'data' ]->get_shipping_class_id() == $shipping_class_target ) {
$in_cart = true;
break;
}
}
if ( $in_cart ) {
unset($available_gateways['cod']); // unset 'cod'
}
else {
unset($available_gateways['bacs']); // unset 'bacs'
}
return $available_gateways;
}
If you are looking to check the variations for each item in the cart, you have to lookup the attributes $product->get_attributes() and then loop through those and get the array key and value for each.
In this example, I used
Size (pa_size) and Small
add_filter('woocommerce_available_payment_gateways', 'conditional_payment_gateways', 10, 1);
function conditional_payment_gateways( $available_gateways ) {
$in_cart = false;
foreach ( WC()->cart->get_cart_contents() as $key => $values ) {
// See if there is an attribute called 'pa_size' in the cart
// Replace with whatever attribute you want
if (array_key_exists('pa_size', (array) $values['data']->get_attributes() ) ) {
foreach ($values['data']->get_attributes() as $attribute => $variation);
// Replace 'small' with your value.
if ($variation == 'small') $in_cart = true; //edited
}
}
if ( $in_cart ) {
unset($available_gateways['cod']); // unset 'cod'
}
else {
unset($available_gateways['bacs']); // unset 'bacs'
}
return $available_gateways;
}
I need to customize cash on delivery (COD) in WooCommerce based on user role and product category.
Requirements:
By default COD is hidden
COD is visible when a product in cart, belongs to a certain category (category 1)
Users who have the role "x" must always see COD, even if they don't have category 1 products in the cart.
This is my code attempt to meet the above requirements:
function disable_cod($available_gateways)
{
if (is_admin()) return $available_gateways;
$role = false;
//check whether the avaiable payment gateways have Cash on delivery and user is not logged in or he is a user with role customer
if (isset($available_gateways['cod']) && (current_user_can('customer') || !is_user_logged_in()))
{
$role = true;
}
foreach (WC()
->cart
->get_cart() as $cart_item_key => $cart_item)
{
$prod_simple = true;
// Get the WC_Product object
$product = wc_get_product($cart_item['product_id']);
// Get the product types in cart (example)
if ($product->is_product_category('X')) $prod_simple = false;
}
if ($prod_simple = $role = true) unset($available_gateways['cod']); // unset 'cod'
return $available_gateways;
}
add_filter('woocommerce_available_payment_gateways', 'disable_cod', 99, 1);
I definitely got something wrong in the syntax, but I hope the logical concept is correct? Any advice?
Your code contains some minor mistakes:
is_product_category() is a conditional tag which returns true when viewing a product category archive. Use has_term() instead.
Loop through the cart is only necessary when the user role is not fulfilled.
So you get:
function filter_woocommerce_available_payment_gateways( $payment_gateways ) {
// Not on admin
if ( is_admin() ) return $payment_gateways;
// Initialize: flag - default true
$flag = true;
// Has certain user role
if ( current_user_can( 'certain-user-role' ) ) {
// False
$flag = false;
} else {
// Specific categories: the term name/term_id/slug. Several could be added, separated by a comma
$categories = array( 63, 15, 'categorie-1' );
// Isset
if ( WC()->cart ) {
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ) {
// Has term (product category)
if ( has_term( $categories, 'product_cat', $cart_item['product_id'] ) ) {
// False, break loop
$flag = false;
break;
}
}
}
}
// True
if ( $flag ) {
// Cod
if ( isset( $payment_gateways['cod'] ) ) {
// Remove
unset( $payment_gateways['cod'] );
}
}
return $payment_gateways;
}
add_filter( 'woocommerce_available_payment_gateways', 'filter_woocommerce_available_payment_gateways', 10, 1 );
Good afternoon!
Please help me implement this feature in woocommerce.
I have three specific products (with specific IDs 2, 3, 4).
I need to make sure that when adding two of them together to the cart, the prices for both of them change automatically. For example, for a product with id #2, the price was set to $ 100, and for a product with id #3, the price became$200.
Also, when they are all added together (three of them), the price changed for all three of them: product # 2 = 100; product # 3 = 200; product # 4 = 250.
I haven't found anything like this anywhere yet, so I would appreciate any hint.
I managed to solve the problem on my own.
I made sure that the products I need "watch" each other in the basket. And if one of them "notices" the other, the price is updated for both of them.
In the same way, the price is updated if the three of them simultaneously "see" each other in the basket.
It may not be the best code, but it works and it works well.
The original code was taken from this resource and modified by me for my tasks.
(https://www.webroomtech.com/change-product-price-when-other-product-is-in-cart-woocommerce/)
function simple_func_product_in_cart($product_id){
$product_cart_id = WC()->cart->generate_cart_id( $product_id );
$in_cart = WC()->cart->find_product_in_cart( $product_cart_id );
if ( $in_cart ) {
return true;
}
return false;
}
add_action( 'woocommerce_before_calculate_totals', 'simple_change_price_of_product' );
function simple_change_price_of_product( $cart_object ) {
$target_product_id = 7101; // CHANGE THIS WITH YOUR PRODUCT ID
if(simple_product_in_cart(7105)) {
// Product is already in cart
foreach ( $cart_object->get_cart() as $key => $value ) {
if ( $value['product_id'] == $target_product_id ) {
$value['data']->set_price(160); // CHANGE THIS: set the new price
$new_price = $value['data']->get_price();
}
}
}
$target_product_id = 7101; // CHANGE THIS WITH YOUR PRODUCT ID
if(simple_product_in_cart(7107)) {
// Product is already in cart
foreach ( $cart_object->get_cart() as $key => $value ) {
if ( $value['product_id'] == $target_product_id ) {
$value['data']->set_price(160); // CHANGE THIS: set the new price
$new_price = $value['data']->get_price();
}
}
}
$target_product_id = 7105; // CHANGE THIS WITH YOUR PRODUCT ID
if(simple_product_in_cart(7101)) {
// Product is already in cart
foreach ( $cart_object->get_cart() as $key => $value ) {
if ( $value['product_id'] == $target_product_id ) {
$value['data']->set_price(170); // CHANGE THIS: set the new price
$new_price = $value['data']->get_price();
}
}
}
$target_product_id = 7105; // CHANGE THIS WITH YOUR PRODUCT ID
if(simple_product_in_cart(7107)) {
// Product is already in cart
foreach ( $cart_object->get_cart() as $key => $value ) {
if ( $value['product_id'] == $target_product_id ) {
$value['data']->set_price(170); // CHANGE THIS: set the new price
$new_price = $value['data']->get_price();
}
}
}
$target_product_id = 7107; // CHANGE THIS WITH YOUR PRODUCT ID
if(simple_product_in_cart(7101)) {
// Product is already in cart
foreach ( $cart_object->get_cart() as $key => $value ) {
if ( $value['product_id'] == $target_product_id ) {
$value['data']->set_price(180); // CHANGE THIS: set the new price
$new_price = $value['data']->get_price();
}
}
}
$target_product_id = 7107; // CHANGE THIS WITH YOUR PRODUCT ID
if(simple_product_in_cart(7105)) {
// Product is already in cart
foreach ( $cart_object->get_cart() as $key => $value ) {
if ( $value['product_id'] == $target_product_id ) {
$value['data']->set_price(180); // CHANGE THIS: set the new price
$new_price = $value['data']->get_price();
}
}
}
}
One of my client wants that when new users comes to website then they"ll get Rs. 500 discount. Here's the complication, the discount like that on first order he get Rs. 250 discount after entering the coupon code and on second order he also get coupon discount of Rs. xxxx.
NOTE : Only one coupon used at a time.
So can you please suggest me how to do that or if any plugin available like that for first and second order discount.
/**
* Frontend validate new customer only coupon code
* hook: woocommerce_after_checkout_validation
*/
add_action('woocommerce_after_checkout_validation','check_new_customer_coupon', 0);
function check_new_customer_coupon(){
global $woocommerce;
// you might change the firstlove to your coupon
$new_cust_coupon_code = 'firstlove';
$has_apply_coupon = false;
foreach ( WC()->cart->get_coupons() as $code => $coupon ) {
if($code == $new_cust_coupon_code) {
$has_apply_coupon = true;
}
}
if($has_apply_coupon) {
if(is_user_logged_in()) {
$user_id = get_current_user_id();
// retrieve all orders
$customer_orders = get_posts( array(
'meta_key' => '_customer_user',
'meta_value' => $user_id,
'post_type' => 'shop_order',
'numberposts'=> -1
) );
if(count($customer_orders) > 0) {
$has_ordered = false;
$statuses = array('wc-failed', 'wc-cancelled', 'wc-refunded');
// loop thru orders, if the order is not falled into failed, cancelled or refund then it consider valid
foreach($customer_orders as $tmp_order) {
$order = wc_get_order($tmp_order->ID);
if(!in_array($order->get_status(), $statuses)) {
$has_ordered = true;
}
}
// if this customer already ordered, we remove the coupon
if($has_ordered == true) {
WC()->cart->remove_coupon( $new_cust_coupon_code );
wc_add_notice( sprintf( "Coupon code: %s is only applicable for new customer." , $new_cust_coupon_code), 'error' );
return false;
}
} else {
// customer has no order, so valid to use this coupon
return true;
}
} else {
// new user is valid
return true;
}
}
}
May help you. Got from some blog.