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.
Related
I am using the weight based shipping method plugin (https://weightbasedshipping.com/). I want to hide shipping methods based on product category. But I can't seem to make this code work. Can you help me with what I am doing wrong here.
add_filter( 'woocommerce_package_rates', 'product_category_hide_shipping_methods', 90, 2);
function product_category_hide_shipping_methods( $rates, $package ){
$categories = array('tabak');
$found = false;
// Loop through cart items
foreach( $package['contents'] as $cart_item ) {
if ( has_term( $categories, 'product_cat', $cart_item['product_id'] ) ){
$found = true;
break;
}
}
$rates_arr = array('Method1','Method2','Method3');
if ( $found ) {
foreach($rates_arr as $rate_id => $rate) {
unset[$rate_id];
}
}
}
I am creating a landing page for the customers and with a specific products that has a category of landing-page.
I want the other products that is currently on the cart page to be removed when the category landing-page is present on the cart.
Here's the snippet. Right now, it removes all the products in it because of the $woocommerce->cart->empty_cart().
add_action('woocommerce_checkout_before_customer_details', 'check_if_landing_page_category_is_on_cart');
function check_if_landing_page_category_is_on_cart() {
global $woocommerce;
$categories = array('landing-page');
$has_category = false;
foreach ( WC()->cart->get_cart() as $cart_item ) {
// Check for product categories
if ( has_term( $categories, 'product_cat', $cart_item['product_id'] ) ) {
$woocommerce->cart->empty_cart();
$has_category = true;
break;
}
}
if ( $has_category ) {
?>
<style>
.coupon-form {
display: none;
}
</style>
<?php
}
}
Any advice?
You can use WC_Cart::remove_cart_item() opposite WC_Cart::empty_cart()
So you get:
function action_woocommerce_checkout_before_customer_details() {
// Add categories. Multiple can be added, separated by a comma
$categories = array( 'landing-page' );
// Initialize
$cart_item_keys = array();
$has_category = false;
// WC Cart NOT null
if ( ! is_null( WC()->cart ) ) {
// Loop through cart items
foreach ( WC()->cart->get_cart_contents() as $cart_item_key => $cart_item ) {
// Get product id
$product_id = $cart_item['product_id'];
// NOT certain category
if ( ! has_term( $categories, 'product_cat', $product_id ) ) {
// Push to array
$cart_item_keys[] = $cart_item_key;
} else {
$has_category = true;
}
}
// NOT empty & has category is true
if ( ! empty ( $cart_item_keys ) && $has_category ) {
// Loop through all cart item keys that do not contain the category
foreach ( $cart_item_keys as $cart_item_key ) {
// Remove product from cart
WC()->cart->remove_cart_item( $cart_item_key );
}
}
}
}
add_action( 'woocommerce_checkout_before_customer_details', 'action_woocommerce_checkout_before_customer_details', 10, 0 );
I want to unset the payment method 'bacs' for the product ID 6197.
I have tried the code below, but this does not have the desired result.
add_filter( 'woocommerce_available_payment_gateways', 'wp_unset_gateway_by_id', 10, 2 );`
function wp_unset_gateway_by_id( $available_gateways, $products) {
global $woocommerce;
$unset = false;
$product_ids = array('6197');
if( in_array( $product->get_id(), $product_ids ) || ( $product->is_type('variation') && in_array( $product->get_parent_id(), $product_ids ) ) ){
unset( $available_gateways['bacs'] );
return $available_gateways;
}
}
I believe I am doing something wrong, but I am relatively new to this. Any advice would be appreciated.
$products is not passed as argument to the woocommerce_available_payment_gateways filter hook
Apply it in the following way:
function filter_woocommerce_available_payment_gateways( $payment_gateways ) {
// Not on admin
if ( is_admin() ) return $payment_gateways;
// The targeted product ids (several can be added, separated by a comma)
$targeted_ids = array( 6197 );
// Flag
$found = false;
// WC Cart
if ( WC()->cart ) {
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ) {
if ( array_intersect( $targeted_ids, array( $cart_item['product_id'], $cart_item['variation_id'] ) ) ) {
$found = true;
break;
}
}
}
// True
if ( $found ) {
// Bacs
if ( isset( $payment_gateways['bacs'] ) ) {
unset( $payment_gateways['bacs'] );
}
}
return $payment_gateways;
}
add_filter( 'woocommerce_available_payment_gateways', 'filter_woocommerce_available_payment_gateways', 10, 1 );
Just starting in my WordPress/WooCommerce journey.
I found a question on here from a while back asking about restricting payment gateways for a specific attribute selection. I've tried to integrate this into my site and I cannot get it working! I've added the Attribute and Terms, and the slugs are as follows - pay_now_deposit (attr) and pay_now / deposit (terms).
I'm looking to restrict Klarna payments for those paying by deposit, and the code I have is below -
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_pay_now_deposit', (array) $values['data']->get_attributes() ) ) {
foreach ($values['data']->get_attributes() as $attribute => $variation);
// Replace 'small' with your value.
if ($variation == 'deposit') $in_cart = true; //edited
}
}
if ( $in_cart ) {
unset($available_gateways['klarna_payments']);
}
else {
unset($available_gateways['cod']);
}
return $available_gateways;
}
Any advice on where I'm going wrong would be greatly appreciated!
Try to add a break statement.
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 ) {
if ( array_key_exists( 'pa_pay_now_deposit', (array) $values['data']->get_attributes() ) ) {
foreach ( $values['data']->get_attributes() as $attribute => $variation ){
if ( $variation == 'deposit' ){
$in_cart = true; //edited
break;
}
}
}
if( $in_cart ){
break;
}
}
if ( $in_cart ) {
unset( $available_gateways['klarna_payments'] );
}else {
unset( $available_gateways['cod'] );
}
return $available_gateways;
}
How can I change shipping cost in Woocommerce by Ajax request?
I tried this:
add_action('wp_ajax_set_shipping_price', 'set_shipping_price');
add_action('wp_ajax_nopriv_set_shipping_price', 'set_shipping_price');
function set_shipping_price(){
$packages = WC()->cart->get_shipping_packages();
foreach ($packages as $package_key => $package){
$session_key = 'shipping_for_package_'.$package_key;
$stored_rates = WC()->session->__unset( $session_key );
$WC_Shipping = new WC_Shipping();
$WC_Shipping->calculate_shipping_for_package( $package, $package_key = 0);
WC()->cart->calculate_shipping();
WC()->cart->calculate_totals();
}
wp_die();
}
and:
add_filter( 'woocommerce_package_rates', 'custom_shipping_costs', 20, 2 );
function custom_shipping_costs( $rates, $package ) {
if (isset($_POST['cost'])){
$new_cost = $_POST['cost'];
}
$new_cost = 0;
$tax_rate = 0.2;
foreach( $rates as $rate_key => $rate ){
if( $rate->method_id != 'free_shipping'){
$rates[$rate_key]->cost = $new_cost;
$taxes = array();
foreach ($rates[$rate_key]->taxes as $key => $tax){
if( $rates[$rate_key]->taxes[$key] > 0 )
$taxes[$key] = $new_cost * $tax_rate;
}
$rates[$rate_key]->taxes = $taxes;
}
}
return $rates;
}
The hook woocommerce_package_rates works at page load but do nothing by ajax. Help please.
Here is the explanation on how to get post data from an Ajax call.
Additionally, you can use the WooCommerce update_checkout event to update the checkout (and thus recalculate shipping costs) after a field in the checkout has changed or been clicked (instead of creating a custom Ajax call). Here you will find a complete list.
So, assuming you want to recalculate shipping costs when the field with id custom_shipping_price (for example) changes, you can use this script:
// updates the checkout (and shipping charge calculation) when the value of a field changes
add_action( 'wp_footer', 'update_checkout' );
function update_checkout() {
// only in the checkout
if ( ! is_checkout() ) {
return;
}
?>
<script type="text/javascript">
jQuery( document ).ready(function( $ ) {
// when the value of the field with id "custom_shipping_price" changes it updates the checkout
jQuery('#custom_shipping_price').change(function(){
jQuery('body').trigger('update_checkout');
});
});
</script>
<?php
}
Now you will need to use the woocommerce_package_rates hook to calculate the new shipping cost.
Make sure you initialize the value of the $new_cost variable in
case the custom field is not set or is empty.
Here the function:
// update the shipping cost based on a custom field in the checkout
add_filter( 'woocommerce_package_rates', 'update_shipping_cost_based_on_custom_field', 10, 2 );
function update_shipping_cost_based_on_custom_field( $rates, $package ) {
if ( ! $_POST || is_admin() || ! is_ajax() ) {
return;
}
// gets the post serialized data sent with the Ajax call
if ( isset( $_POST['post_data'] ) ) {
parse_str( $_POST['post_data'], $post_data );
} else {
$post_data = $_POST;
}
// set the cost of shipping (if the custom field should be empty)
$new_cost = 0;
// if the field is set it gets the value
if ( isset( $post_data['custom_shipping_price'] ) && ! empty( $post_data['custom_shipping_price'] ) ) {
// forces conversion of value into number
$new_cost = (float) str_replace( ',', '.', $post_data['custom_shipping_price'] );
}
// set the percentage of taxes (ex. 22%)
$tax_rate = 0.22;
foreach( $rates as $rate_key => $rate ) {
if ( 'free_shipping' !== $rate->method_id ) {
// set rate cost
$rates[$rate_key]->cost = $new_cost;
// set taxes rate cost (if enabled)
$taxes = array();
foreach ( $rates[$rate_key]->taxes as $key => $tax ) {
if ( $rates[$rate_key]->taxes[$key] > 0 ) {
$taxes[$key] = $new_cost * $tax_rate;
}
}
$rates[$rate_key]->taxes = $taxes;
}
}
return $rates;
}
Both codes have been tested and work. Add them to your active theme's functions.php.