I need send email instructions when customer select shipping zone id = 0 (The rest of the world).
I found code below, but its based on payment method:
add_action( 'woocommerce_email_before_order_table', 'add_order_email_instructions', 10, 2 );
function add_order_email_instructions( $order, $sent_to_admin ) {
if ( ! $sent_to_admin ) {
if ( 'cod' == $order->payment_method ) {
// cash on delivery method
echo '<p><strong>Instructions:</strong> Full payment is due immediately upon delivery: <em>cash only, no exceptions</em>.</p>';
} else {
// other methods (ie credit card)
echo '<p><strong>Instructions:</strong> Please look for "Madrigal Electromotive GmbH" on your next credit card statement.</p>';
}
}
}
How can I change it to specific shipping zone please?
How can I set specific email instructions based on shipping zone in WooCommerce?
Any help on this will be appreciated.
Get the shipping zone for an order is not so easy. It can be done with the following code example:
add_action( 'woocommerce_email_before_order_table', 'custom_text_in_email_shipping_zone_based', 10, 4 );
function custom_text_in_email_shipping_zone_based( $order, $sent_to_admin, $plain_text, $email ) {
if ( ! $sent_to_admin ) {
// Get the shipping method related data (we need the Instance ID)
$shipping_item = $order->get_items('shipping');
$item = reset($shipping_item);
$shipping_method_id = $item->get_method_id();
$method_arr = explode( ':', $shipping_method_id );
// Get the Zone ID and related data
$shipping_zone_object = WC_Shipping_Zones::get_zone_by( 'instance_id', $method_arr[1] );
$zone_id = $shipping_zone_object->get_id(); // Zone ID
$zone_name = $shipping_zone_object->get_zone_name(); // Zone name
// Get the zone locations codes and types (if needed)
foreach( $shipping_zone_object->get_zone_locations() as $zone_location ){
$zone_location_code = $zone_location->code;
$zone_location_type = $zone_location->type;
}
if ( '0' == $zone_id ) {
// Rest of the world
echo '<p><strong>Instructions:</strong> for Rest of the world.</p>';
}
elseif ( 'Mexico' == $zone_name ) {
// Mexico zone name
echo '<p><strong>Instructions:</strong> for Mexico.</p>';
}
else {
// All other zones
echo '<p><strong>Instructions:</strong> Other zones.</p>';
}
}
}
Code goes in function.php file of the active child theme (or active theme).
Tested and works.
According to the WC_Abstract_Order codex page https://docs.woocommerce.com/wc-apidocs/class-WC_Abstract_Order.html#_has_shipping_method you can check the shipping method using has_shipping_method().
So, your if statement should be something like
if ( $order->has_shipping_method('name_of_my_shipping_method') ) {
I couldn't find an equivalent for shipping zones though.
Hope that helps
add_action( 'woocommerce_email_before_order_table', 'custom_text_in_email_shipping_zone_based', 10, 4 );
function custom_text_in_email_shipping_zone_based( $order, $sent_to_admin, $plain_text, $email ) {
if ( ! $sent_to_admin ) {
// Get the shipping method related data (we need the Instance ID)
$shipping_item = $order->get_items('shipping');
$item = reset($shipping_item);
$shipping_method_id = $item->get_method_id();
$method_arr = explode( ':', $shipping_method_id );
// Get the Zone ID and related data
$shipping_zone_object = WC_Shipping_Zones::get_zone_by( 'instance_id', $method_arr[1] );
$zone_id = $shipping_zone_object->get_id(); // Zone ID
$zone_name = $shipping_zone_object->get_zone_name(); // Zone name
// Get the zone locations codes and types (if needed)
foreach( $shipping_zone_object->get_zone_locations() as $zone_location ){
$zone_location_code = $zone_location->code;
$zone_location_type = $zone_location->type;
}
if ( '0' == $zone_id ) {
// Rest of the world
echo '<p><strong>Instructions:</strong> for Rest of the world.</p>';
}
elseif ( 'Mexico' == $zone_name ) {
// Mexico zone name
echo '<p><strong>Instructions:</strong> for Mexico.</p>';
}
else {
// All other zones
echo '<p><strong>Instructions:</strong> Other zones.</p>';
}
}
}
The code showing above doesn't work even though the author has stated tried and tested, can anybody update the code.
No matter what zone you select you always end up with All other zones.
Related
I'm having some issues when a customer select a certain delivery option and a certain payment. At the moment we are using bacs and local payment gateways methods to collect the money, and we have local pick up and express delivery options. also, we have custom statuses for woocommerce for each delivery option. The problem occurs when someone asks for express delivery, and he wants to pay with bacs. we tried to assign custom status for each combination but the code is not working, due its selecting the same custom status to every option in the code.
add_action( 'woocommerce_thankyou', 'express_shipping_update_order_status', 10, 1 );
function express_shipping_update_order_status( $order_id ) {
if ( ! $order_id ) return;
$search_rm = 'Despacho Express Todo Santiago (Excluye Padre Hurtado. Recibe al siguiente día hábil)';
$search_estoril = 'Retiro en Tienda Estoril';
$search_vina = 'Retiro en Tienda Reñaca';
$order = wc_get_order( $order_id );
$payment_method=$order->get_payment_method();
foreach($order->get_shipping_methods() as $shipping_item ){
if( strpos( $shipping_item->get_method_title(), $search_rm ) !== false && $payment_method == "bacs"){
$order->update_status('check-payment');
break;
} else {
$order->update_status('express-rm');
break;
}
if( strpos( $shipping_item->get_method_title(), $search_estoril ) !== false && $payment_method == "bacs"){
$order->update_status('check-payment');
break;
} else {
$order->update_status('retiro-rm');
break;
}
if( strpos( $shipping_item->get_method_title(), $search_vina ) !== false && $payment_method == "bacs"){
$order->update_status('check-payment');
break;
} else {
$order->update_status('retiro-vina');
break;
}
}
}
this is the result:
is there any way to fix this? thanks!
Because you use custom shipping methods and custom order statuses, it is difficult to give an appropriate answer.
However, if you run the following code and apply the debug information in the if condition, you should get the desired result.
A hint. Build your code step by step and test it in the meantime, see debugging in WooCommerce versus multiple if and else conditions without you really being able to determine where things are going wrong
Explanation via comment tags added in the code:
function action_woocommerce_thankyou( $order_id ) {
// Get $order object
$order = wc_get_order( $order_id );
// Get payment method
$payment_method = $order->get_payment_method();
// Get shipping method
$shipping_method = $order->get_shipping_method();
// DEBUGGING PURPOSES. Delete after testing
echo 'DEBUG: Shipping method = ' . $shipping_method;
// Compare payment method
if ( $payment_method == 'bacs' ) {
// Compare shipping method
if ( $shipping_method == 'my_shipping_method_copy_pasted_from_the_debug_information' ) {
$order->update_status( 'my-custom-order-status' );
} else {
// etc..
}
}
}
add_action( 'woocommerce_thankyou', 'action_woocommerce_thankyou', 10, 1 );
I am trying to, based on shipping and if / if not the order note is empty, to add information to the customer complete order email.
Two different messages based on if the order notes field is filled in or not. I've placed test orders but nothing shows up.
This is the code I am trying to get to work:
add_action( 'woocommerce_email_order_details', 'local_pickup_order_instructions', 10, 4 );
function local_pickup_order_instructions( $order, $sent_to_admin, $plain_text, $email ) {
if ( 'customer_completed_order' != $email->id ) return;
foreach( $order->get_items('shipping') as $shipping_item ) {
$shipping_rate_id = $shipping_item->get_method_id();
$method_array = explode(':', $shipping_rate_id );
$shipping_method_id = reset($method_array);
if ('local_pickup' == $shipping_method_id && empty($_POST['order_comments'])){ ?>
<div style="">Your instructions text here</div>
<?php
break;
}
else {
if ('local_pickup' == $shipping_method_id && !empty($_POST['order_comments'] ) ) { ?>
<div style="">Your instructions text here</div>
<?php
}
}
}
}
There are some mistakes in your code… To display a different custom text when shipping method is "Local Pickup" if there is (or not) a customer note, use the following simplified and revisited code:
add_action( 'woocommerce_email_order_details', 'local_pickup_order_instructions', 10, 4 );
function local_pickup_order_instructions( $order, $sent_to_admin, $plain_text, $email ) {
if ( $email->id === 'customer_completed_order' ) {
$shipping_items = $order->get_items('shipping');
$shipping_item = reset($shipping_items); // Get first shipping item
$customer_note = $order->get_customer_note(); // Get customer note
// Targeting Local pickup shipping methods
if ( strpos( $shipping_item->get_method_id(), 'local_pickup' ) !== false ) {
if ( empty($customer_note) ) {
echo '<div style="color:red;">'.__("Instructions text here… (No customer note)").'</div>'; // Empty order note
} else {
echo '<div style="color:green;">'.__("Instructions text here… (has a customer note)").'</div>'; // Filled order note
}
}
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
In woocommerce, I need to display custom message on cart or checkout page, based on shipping zone, like "you'll be charged 10% more for this zip code".
My workaround is about customizing that kind of default message :
add_filter( 'woocommerce_no_shipping_available_html', 'wf_customize_default_message', 10, 1 );
// For Checkout page
add_filter( 'woocommerce_cart_no_shipping_available_html', 'wf_customize_default_message', 10, 1 );
function wf_customize_default_message( $default_msg ) {
$zip_array = array(
'30031',
);
if ( in_array( WC()->customer->get_shipping_postcode() , $zip_array) ) {
$custom_msg = "Call us for quotation - 1-800-XXX-XXXX";
if( empty( $custom_msg ) ) {
return $default_msg;
}
return $custom_msg;
}
return $default_msg;
}
Updated
Try the following code based on a shipping Zones name (with postcodes restrictions) that will display your message on the shipping total lines (but that will not generate a woocommerce notice):
add_action( 'woocommerce_cart_totals_after_shipping' , 'shipping_zone_targeted_postcodes_custom_notice' );
add_action( 'woocommerce_review_order_after_shipping' , 'shipping_zone_targeted_postcodes_custom_notice' );
function shipping_zone_targeted_postcodes_custom_notice() {
// HERE DEFINE YOUR SHIPPING ZONE NAME(S)
$targeted_zones_names = array('France'); // <====== <====== <====== <====== <======
// Get the customer shipping zone name
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' ); // The chosen shipping mehod
$chosen_method = explode(':', reset($chosen_methods) );
$shipping_zone = WC_Shipping_Zones::get_zone_by( 'instance_id', $chosen_method[1] );
$current_zone_name = $shipping_zone->get_zone_name();
if( in_array( $current_zone_name, $targeted_zones_names ) ){
echo '<tr class="shipping">
<td colspan="2" style="text-align:center">' . sprintf(
__( "You'll be charged %s more for %s zip code", "woocommerce"),
'<strong>10%</strong>',
'<strong>' . WC()->customer->get_shipping_postcode() . '</strong>'
) . '</td>
</tr>';
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Using #LoicTheAztec's solution above, I modified it to give a message based on customer's country.
add_action( 'woocommerce_cart_totals_after_shipping' , 'out_of_zone_shipping_notice' );
add_action( 'woocommerce_review_order_after_shipping' , 'out_of_zone_shipping_notice' );
function out_of_zone_shipping_notice() {
// HERE DEFINE YOUR SHIPPING COUNTRY NAMES
$targeted_country_names = array("CA", "US"); //
// Get the customer shipping country
$shipping_country = WC()->customer->get_shipping_country();
if( !in_array( $shipping_country, $targeted_country_names ) ){
echo '<tr class="shipping"><td colspan="2" style="text-align:center">You are outside of our regular shipping zone. Please contact us with your address so we can get an accurate cost to ship.</td></tr>';
}
}
In order to see what format the $shipping_country showed up in, I used
echo $shipping_country
just below $shipping_country = WC()->customer->get_country(); to show on the cart page what the actual country code syntax was so that I could match it with the if statement. However, this code segment was removed prior to deployment to avoid random characters on the screen for the customer.
I need help with a custom email hook for woocommerce.
I am trying to send a different email depending on product ID whenever a product is completed.
My code, which is not working, is as follows:
/**************
DIFFERENT MESSAGES FOR DIFFERENT PRODUCTS
****************/
//hook our function to the new order email
add_action('woocommerce_email_order_details', 'uiwc_email_order_details_products', 1, 4);
function uiwc_email_order_details_products($order, $admin, $plain, $email) {
$status = $order->get_status();
// checking if it's the order status we want
if ( $status == "completed" ) {
$items = $order->get_items();
if ( $item['product_id'] == "3181") {
echo __( '<strong>IMPORTANT - NEXT STEP:</strong><br>To get started, please follow this link to complete the Policies form.<br><br>This is a really important first step, and only takes about 5 minutes. After completeing the Policies form, you will receive additional instructions on next steps.<br><br>Congratulations! Let your journey begin.<br><br>', 'uiwc' );
}
elseif ( $item['product_id'] == "3223") {
echo __( '<strong>IMPORTANT - NEXT STEP:</strong><br>Differnet product so differenct email....<br><br>', 'uiwc' );
}
}
}
Any suggestions is greatly appreciated
There is some mistakes in your code, instead try the following
//hook our function to the new order email
add_action( 'woocommerce_email_order_details', 'custom_email_order_details', 4, 4 );
function custom_email_order_details( $order, $admin, $plain, $email ) {
$domain = 'woocommerce';
// checking if it's the order status we want
if ( $order->has_status('completed') ) {
foreach( $order->get_items() as $item ){
if ( $item->get_product_id() == '3181' ) {
echo __( '<strong>IMPORTANT - NEXT STEP:</strong><br>To get started, please follow this link to complete the Policies form.<br><br>This is a really important first step, and only takes about 5 minutes. After completeing the Policies form, you will receive additional instructions on next steps.<br><br>Congratulations! Let your journey begin.<br><br>', $domain );
break;
}
elseif ( $item->get_product_id() == '3223' ) {
echo __( '<strong>IMPORTANT - NEXT STEP:</strong><br>Differnet product so differenct email....<br><br>', $domain );
break;
}
}
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
After Woocommerce update to 3.2, This code below does not work anymore.
add_action( 'woocommerce_email_order_details', 'my_completed_order_email_instructions', 10, 4 );
function my_completed_order_email_instructions( $order, $sent_to_admin, $plain_text, $email ) {
// Only for "Customer Completed Order" email notification
if( 'customer_completed_order' != $email->id ) return;
// Comptibility With WC 3.0+
if ( method_exists( $order, 'get_id' ) ) {
$order_id = $order->get_id();
} else {
$order_id = $order->id;
}
//$order->has_shipping_method('')
$shipping_method_arr = get_post_meta($order_id, '_shipping_method', false); // an array
$rate_id = $shipping_method_arr[0][0]; // the rate ID
if ( 'flat_rate:10' == $rate_id ){
echo pll__("Text 1");
} else {
echo pll__("Text 2");
}
}
What is wrong or obsolete in this code?
What changes need to be done to make it work again?
Here is the correct way to get the Shipping methods used in the Order and make this function works as expected:
add_action( 'woocommerce_email_order_details', 'my_completed_order_email_instructions', 10, 4 );
function my_completed_order_email_instructions( $order, $sent_to_admin, $plain_text, $email ) {
// Only for "Customer Completed Order" email notification
if( 'customer_completed_order' != $email->id ) return;
$found = false; // Initializing variable
// Iterating through Order shipping methods
foreach($order->get_shipping_methods() as $value){
$rate_id = $value->get_method_id(); // Get the shipping rate ID
if ( 'flat_rate:10' == $rate_id )
$found = true;
}
if ($found)
echo '<p>'.__("Text 1 (found)","woocommerce").'</p>';
else
echo '<p>'.__("Text 2 (else)","woocommerce").'</p>';
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested and works…