I need to hide a shipping method depending on if a discount code is used or not.
But I don't find how to hide a shipping method in the order confirmation page.
I saw that answer but it does nothing, I tried this code to verify:
add_filter( 'woocommerce_package_rates', 'custom_shipping_rates', 100, 2 );
function custom_shipping_rates( $rates, $package ) {
exit();
}
Which should block page display but the page is well loaded.
EDIT: The filter is never called because wordpress uses stored rates in class-wc-shipping.php:
if ( ! is_array( $stored_rates ) || $package_hash !== $stored_rates['package_hash'] || 'yes' === get_option( 'woocommerce_shipping_debug_mode', 'no' ) )
{
...
// Filter the calculated rates.
$package['rates'] = apply_filters( 'woocommerce_package_rates',
$package['rates'], $package );
...
}
else
{
$package['rates'] = $stored_rates['rates'];
}
That code should actually work unless you have an old wc version. You can verify if that hook exist by searching for it in /plugins/woocommerce code base. If you don't find it, then something is wrong with the updates.
If you find it and your code still doesn't work, then the only other reason is that you placed that snipped of code in a point that never get fired or you simple come too late.
Could you please add where and how you placed that code so that we can see better what is going on?
Edit:
if you look above the snipped you copied you will see:
// Get rates stored in the WC session data for this package.
$wc_session_key = 'shipping_for_package_' . $package_key ;
$stored_rates = WC()->session->get( $wc_session_key );
which makes me think that is a session-related thing. So in order to fully test you need to either open the website with another browser, empty your browser cache + cookie or use an anonymous browser session
There's a trick to disable the usage of cache, I limited it to the "update order review" action that way:
if (preg_match('#update_order_review#i',$_SERVER['REQUEST_URI']))
{
add_filter('transient_shipping-transient-version', function($value, $name)
{
return false;
}, 10, 2);
}
add_filter( 'woocommerce_package_rates', 'custom_shipping_rates', 100, 2 );
function custom_shipping_rates( $rates, $package )
{
//get coupons
$reduc=WC()->cart->get_coupons();
$hidemr=isset($reduc['thediscountcode']);
if ($hidemr)
{
foreach($rates as $k=>$v)
{
if (preg_match('#MethodLabelToHide#i',$v->get_label()))
unset($rates[$k]);
}
}
return $rates;
}
Related
How can I show to my user on the checkout page a specific shipping option ?
I know how to remove a shipping option but I can't add a new one (an existing one) in $rates.
I tried to add :
array_push($rates, 'flat_rate:5');
Isn't array_push supposed to do the job ?
Here is a basic snippet, from my function files.
add_filter( 'woocommerce_package_rates', 'custom_package_rates', 10, 2 );
function custom_package_rates( $rates, $package ) {
$total = WC()->cart->cart_contents_total;
if( $total < 100 ) {
// remove from shipping options
unset( $rates['advanced_free_shipping'] );
// Tryed it but critical error is thrown
array_push($rates, 'flat_rate:5');
}
return $rates;
}
Tried everybit of code that I found on stack and other places, seems I'm the only one to have an issue...
$rates is not a simple array, it contains also an object with data for each rate, so adding an array incl. the object is something you want to avoid. But you don't need to. Instead you can do it like this:
...
if( $total < 100 ) {
// remove from shipping options
unset( $rates['advanced_free_shipping'] );
}
else {
// only available when total is <= 100
unset( $rates['flat_rate:5'] );
}
...
It basically does the same.
I want to enable or disable Shipping Methods, according to user role.
I have tested various different codes and approaches, none of which have worked so far.
The current code: (source: stacklink )
add_filter( 'woocommerce_package_rates', 'hide_specific_shipping_method_based_on_user_role', 30, 2 );
function hide_shipping_method_based_on_user_role( $rates, $package ) {
$shipping_id = 'shipmondo:3';
foreach( $rates as $rate_key => $rate ){
if( $rate->method_id === $shipping_id ){
if( current_user_can( 'b2b' ) || ! is_user_logged_in()){
unset($rates[$rate_key]);
break;
}
}
}
return $rates;
}
(Have tested the original snippet as well, without changes, accept for the user role )
Does not work for me. I tested it with 'local_pickup' as well, It does work sometimes, but seems to be very sensitive to browser cache and session. Also what I need, is 3 methods which are called under the same name, but with a child number separating them: shipmondo:3, shipmondo:4, etc. (found in browser inspection under "Value") There is also something called ID, which looks like: 'shipping_method_0_shipmondo3' Dont know if I could use that instead, but it is kind of hard to figure out, when the code isn't updating correctly. The snippet is from 2018, so it could be an outdated thing, but the newer snippets I have found, are based on the same principale, and does not look to be doing it much different.
Also, why would the "|| ! is_user_logged_in()" be necessary? I only need to disable 2 out of 3 methods for a wholesale user, need not to effect any other roles, nor guests. Been fighting with this for days now.
Also, any advice on forcing Wordpress and Woocommerce to update, and not swim around in cache?
Thanks in advance.
You are confusing shipping method "Method Id" and shipping method "Rate Id". Also your code can be simplified. Try the following instead:
add_filter( 'woocommerce_package_rates', 'hide_specific_shipping_method_based_on_user_role', 100, 2 );
function hide_specific_shipping_method_based_on_user_role( $rates, $package ) {
// Here define the shipping rate ID to hide
$targeted_rate_id = 'shipmondo:3'; // The shipping rate ID to hide
$targeted_user_roles = array('b2b'); // The user roles to target (array)
$current_user = wp_get_current_user();
$matched_roles = array_intersect($targeted_user_roles, $current_user->roles);
if( ! empty($matched_roles) && isset($rates[$targeted_rate_id]) ) {
unset($rates[$targeted_rate_id]);
}
return $rates;
}
Code goes in functions.php file of the active child theme (or active theme). It should work.
Don't forget to empty your cart, to clear shipping cached data.
I am trying to change the PayPal address that Woocommerce uses, depending on what page they are on. I only have 5 products at the moment, and all 5 need to use a different PayPal address.
I found this hook that can change the Paypal address, although not too sure how to add it in exactly (code is 3 years old apparently).
$paypal_args = apply_filters( 'woocommerce_paypal_args', $paypal_args );
add_filter( 'woocommerce_paypal_args' , 'custom_override_paypal_email' );
function custom_override_paypal_email( $paypal_args ) {
$paypal_args['business'] = 'paypalemail#domain.com';
print_r( $paypal_args['business'] );
return $paypal_args;
}
How can I use this hook to change the Paypal address depending on which page/product the user is on?
I've checked and found out that woocommerce_paypal_args has two arguments, the settings and the order. So based on the order, we can check what product it has and use the appropriate email.
add_filter( 'woocommerce_paypal_args' , 'custom_override_paypal_email', 10, 2 );
function custom_override_paypal_email( $paypal_args, $order ) {
foreach ( $order->get_items() as $item ) {
switch( $item['product_id'] ) {
case 561:
$paypal_args['business'] = 'paypalemail1#domain.com';
break;
case 562:
$paypal_args['business'] = 'paypalemail2#domain.com';
break;
}
}
return $paypal_args;
}
please take note that you have to make sure that there can only be one item on the cart. If there are more than 1 product in the cart, this will use the last found product in the foreach loop. The code above is just for guidance, please change accordingly.
everyone, i am trying to stop a plugin function from executing if a certain product id is in the cart. I have tried and written the following code and put them in my theme functions.php, but it doesn't seem to work. Instead, the whole page become blank. Can anyone help me out?
$found = false;
global $woocommerce;
foreach($woocommerce->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if( $_product->id == 1097 ) {
$found = true;
}
}
if ($found){
remove_action('woocommerce_before_order_notes', array($wdt, 'show_field'), 20);
}
By itself, remove_action('woocommerce_before_order_notes', array($wdt, 'show_field'), 20); works. But once i tried to link it to work base on product id, the whole website just cannot load. Thank you!
The variable $wdt does not seam to be initialized. You should ether use the class name(string) or an instance of that class here.
An other guess is that your code runs before the action is added. Make sure you run your code on a later hook in the execution see this for reference: http://codex.wordpress.org/Plugin_API/Action_Reference#Actions_Run_During_a_Typical_Request
So if the code that add the hook runs at init, you can try to run your code at wp_loaded. Like this:
add_action('wp_loaded','my_remove_order_notes');
function my_remove_order_notes()
{
//Your code
}
Also, make sure that the priority parameter matches with the code where the action hook is added. The default priority is 10.
Edit:
Ok, you should not remove the filter. Filters are supposed to be used for manipulating the data and the return the new data back. Like this:
add_filter( 'woocommerce_checkout_fields' , 'custom_remove_order_comments', 99 );
function custom_remove_order_comments( $fields )
{
global $woocommerce;
foreach($woocommerce->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if( $_product->id == 1097 ) {
unset($fields['order']['order_comments']); //Remove the order comments field
}
return $fields; //Return the data back to WooCommerce
}
I have created a plugin mainly following this guide, which simply adds a small bit of data to a given product.
I know Woocommerce have made some changes outlined here.
The problem I'm having is that when I add my item to the cart, and access the cart page, I am getting a blank screen. I believe the problem stems from the use of this filter:
add_filter('woocommerce_get_cart_item_from_session'...
If I comment the line with this filter, my checkout page works (but without the extra details added to my product). I can't work out why this filter is not working, or what problem it is having??
The woocommerce changes said:
WooCommerce 2.0 no longer uses the PHP session_start function, instead it makes use of WordPress’ transients, which is great, unless your code happens to rely on $_SESSION.
I'm not starting any new sessions as far as I can see (my code is 90% the same as the first link). Maybe this is a problem with my server? Any ideas?
i was browsing a lot and i recommend that you read the following:
The solution is to hook in there and also restore your custom cart item data.
Example Code:
add_filter( 'woocommerce_add_cart_item_data', function ( $cartItemData, $productId, $variationId ) {
$cartItemData['myCustomData'] = 'someCustomValue';
return $cartItemData;
}, 10, 3 );
add_filter( 'woocommerce_get_cart_item_from_session', function ( $cartItemData, $cartItemSessionData, $cartItemKey ) {
if ( isset( $cartItemSessionData['myCustomData'] ) ) {
$cartItemData['myCustomData'] = $cartItemSessionData['myCustomData'];
}
return $cartItemData;
}, 10, 3 );
To also show the data at the cart/checkout page you can use the following code:
add_filter( 'woocommerce_get_item_data', function ( $data, $cartItem ) {
if ( isset( $cartItem['myCustomData'] ) ) {
$data[] = array(
'name' => 'My custom data',
'value' => $cartItem['myCustomData']
);
}
return $data;
}, 10, 2 );
The final thing now is to save the data when the order is made:
add_action( 'woocommerce_add_order_item_meta', function ( $itemId, $values, $key ) {
if ( isset( $values['myCustomData'] ) ) {
wc_add_order_item_meta( $itemId, 'myCustomData', $values['myCustomData'] );
}
}, 10, 3 );
You dont have to do anything else the show the data inside the backend, all order item meta data gets display automatically.
this is from
How to retrieve cart_item_data with WooCommerce?
you have to add this stuff to the functions.php file of your theme for example.