WooCommerce Email Title / subject line based on shipping method - woocommerce

I'm trying to customise the woocommerce email title based on the shipping method used. I've searched and there's many conditional examples, but none that seem to work for the shipping option of local pickup. Here's what I am trying:
add_action( 'woocommerce_email_header', 'local_pickup_processing_email_header', 10, 2);
function local_pickup_processing_email_header( $email_heading, $email ) {
if ( $email->id == 'customer_processing_order' ) {
$order = wc_get_order($order_id);
if ($order->has_shipping_method('local_pickup')){
echo "Thanks for Your Local Pickup Order";
}
}
}
The above results in "Fatal error: Uncaught Error: Call to a member function get_shipping_method() on bool"
How do I resolve get_shipping_method ?
I also tried with a foreach, but had a similar error (Call to a member function get_items() )
add_action( 'woocommerce_email_header', 'local_pickup_processing_email_header', 10, 2);
function local_pickup_processing_email_header( $email_heading, $email ) {
$order = wc_get_order( $order_id );
if ( $email->id == 'customer_processing_order' ) {
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);
// Display a custom text for local pickup shipping method only
if( 'local_pickup' == $shipping_method_id ){
echo "Thanks for Your Local Pickup Order";
}
}
}
}

The reason for the error is, you are using a variable which is not defined anywhere i,e $order.
The two parameters available in your function as parameters are $email_heading and $email. So you have to make use of this variables.
You will get $order object by using the instance of $email. So you can use the line as shown below in your code.
$order = $email->object;

Related

How to add ACF product meta to Woocommerce Order Completed Email [duplicate]

There are many threads which deal with the topic "custom fields in WooCommerce emails" but I couldn't find the exact case I am struggling with.
I could achieve 50% of this project to display the field as a meta in the order table.
add_action( 'woocommerce_order_item_meta_end', 'custom_product_info', 20, 4 );
function custom_product_info ( $item_id, $item, $order, $plain_text ) {
$id = $item->get_product_id();
$erlebnisidgc = get_field('erlebnis_id',$id);
if($erlebnisidgc){
echo "<p>Here's your Link</p><a href=https://b-ceed.de/?eventid='.$erlebnisidgc'>Testlink</a>";
}
}
So this code works perfectly with the custom field. Problem is that this output isn't shown only in the customer_completed_order email but also in all other emails.
Therefore, I tried this code snippet:
add_action( 'woocommerce_order_item_meta_end', 'custom_product_info', 20, 4 );
function custom_product_info ( $item_id, $item, $order, $plain_text ) {
if ( $email->id == 'customer_completed_order' ) {
$id = $item->get_product_id();
$erlebnisidgc = get_field('erlebnis_id',$id);
if($erlebnisidgc){
echo "<p>Here's your Link</p><a href=https://b-ceed.de/?eventid='.$erlebnisidgc'>Testlink</a>";
}
}
}
But now the output won't be displayed in any email anymore and it triggers a internal server error. Any advice?
$email ($email->id) is not passed as argument to the woocommerce_order_item_meta_end hook, therefore it is undefined
So to target specific email notifications a workaround will be needed, this can be done by creating a global variable via the woocommerce_email_before_order_table hook
So you get:
// Setting global variable
function action_woocommerce_email_before_order_table( $order, $sent_to_admin, $plain_text, $email ) {
$GLOBALS['email_data'] = array(
'email_id' => $email->id, // The email ID (to target specific email notification)
'is_email' => true // When it concerns a WooCommerce email notification
);
}
add_action( 'woocommerce_email_before_order_table', 'action_woocommerce_email_before_order_table', 1, 4 );
function action_woocommerce_order_item_meta_end( $item_id, $item, $order, $plain_text ) {
// Getting the custom 'email_data' global variable
$ref_name_globals_var = $GLOBALS;
// Isset & NOT empty
if ( isset ( $ref_name_globals_var ) && ! empty( $ref_name_globals_var ) ) {
// Isset
$email_data = isset( $ref_name_globals_var['email_data'] ) ? $ref_name_globals_var['email_data'] : '';
// NOT empty
if ( ! empty( $email_data ) ) {
// Target specific emails, several can be added in the array, separated by a comma
$target_emails = array( 'customer_completed_order' );
// Target specific WooCommerce email notifications
if ( in_array( $email_data['email_id'], $target_emails ) ) {
// Get product ID
$product_id = $item->get_product_id();
// Get field
$erlebnisidgc = get_field( 'erlebnis_id', $product_id );
// Has some value
if ( $erlebnisidgc ) {
echo '<p>Here is your Link</p>';
echo 'Testlink';
}
}
}
}
}
add_action( 'woocommerce_order_item_meta_end', 'action_woocommerce_order_item_meta_end', 10, 4 );
Used in this answer:
Determine only for WooCommerce admin email notification
How to target other WooCommerce order emails

Hide item meta data in certain WooCommerce email notifications

I've got this code snippet in my functions.php file:
add_action( 'woocommerce_checkout_create_order_line_item', 'add_custom_field_to_order_item_meta', 10, 4 );
function add_custom_field_to_order_item_meta( $item, $cart_item_key, $values, $order ) {
$custom_field_value = get_post_meta( $item->get_product_id(), 'supplier_sku', true );
if ( ! empty($custom_field_value) ){
$item->update_meta_data( __('Supplier SKU', 'woocommerce'), $custom_field_value );
}
}
It pulls in the custom field on products, called Supplier SKU and then adds it to the WooCommerce email notifications. Which is fine, but I want to exclude it from the customer email notification and only have it display in the admin email notification.
How can I achieve this?
You could use the woocommerce_display_item_meta hook and return an empty string
function filter_woocommerce_display_item_meta ( $html, $item, $args ) {
$html = '';
return $html;
}
add_filter( 'woocommerce_display_item_meta', 'filter_woocommerce_display_item_meta', 10, 3 );
While the above would work, there would be some issues, namely:
The hook doesn't run just for email notifications, so it wouldn't show up anywhere
Even if this hook would only be executed for email notifications, we would still need to specify that this should only be the case for certain email notifications. However, this hook does not offer a solution for it by default to make this distinction
So a workaround will be needed, this can be done by creating a global variable through another hook that applies only to email notifications
Step 1) creating and adding a global variable
// Setting global variable
function action_woocommerce_email_before_order_table( $order, $sent_to_admin, $plain_text, $email ) {
$GLOBALS['email_id'] = $email->id;
}
add_action( 'woocommerce_email_before_order_table', 'action_woocommerce_email_before_order_table', 1, 4 );
Step 2) In the hook woocommerce_display_item_meta, add and check for specific conditions
Only for email notifications
Only for specific meta data
Only for admin 'new order' email
function filter_woocommerce_display_item_meta ( $html, $item, $args ) {
// For email notifications and specific meta
if ( ! is_wc_endpoint_url() && $item->is_type( 'line_item' ) && $item->get_meta( 'Supplier SKU' ) ) {
// Getting the email ID global variable
$ref_name_globals_var = isset( $GLOBALS ) ? $GLOBALS : '';
$email_id = isset( $ref_name_globals_var['email_id'] ) ? $ref_name_globals_var['email_id'] : '';
// NOT empty and targeting specific email. Multiple statuses can be added, separated by a comma
if ( ! empty ( $email_id ) && ! in_array( $email_id, array( 'new_order' ) ) ) {
$html = '';
}
}
return $html;
}
add_filter( 'woocommerce_display_item_meta', 'filter_woocommerce_display_item_meta', 10, 3 );

Add custom field (ACF) to WooCommerce completed order email notification

There are many threads which deal with the topic "custom fields in WooCommerce emails" but I couldn't find the exact case I am struggling with.
I could achieve 50% of this project to display the field as a meta in the order table.
add_action( 'woocommerce_order_item_meta_end', 'custom_product_info', 20, 4 );
function custom_product_info ( $item_id, $item, $order, $plain_text ) {
$id = $item->get_product_id();
$erlebnisidgc = get_field('erlebnis_id',$id);
if($erlebnisidgc){
echo "<p>Here's your Link</p><a href=https://b-ceed.de/?eventid='.$erlebnisidgc'>Testlink</a>";
}
}
So this code works perfectly with the custom field. Problem is that this output isn't shown only in the customer_completed_order email but also in all other emails.
Therefore, I tried this code snippet:
add_action( 'woocommerce_order_item_meta_end', 'custom_product_info', 20, 4 );
function custom_product_info ( $item_id, $item, $order, $plain_text ) {
if ( $email->id == 'customer_completed_order' ) {
$id = $item->get_product_id();
$erlebnisidgc = get_field('erlebnis_id',$id);
if($erlebnisidgc){
echo "<p>Here's your Link</p><a href=https://b-ceed.de/?eventid='.$erlebnisidgc'>Testlink</a>";
}
}
}
But now the output won't be displayed in any email anymore and it triggers a internal server error. Any advice?
$email ($email->id) is not passed as argument to the woocommerce_order_item_meta_end hook, therefore it is undefined
So to target specific email notifications a workaround will be needed, this can be done by creating a global variable via the woocommerce_email_before_order_table hook
So you get:
// Setting global variable
function action_woocommerce_email_before_order_table( $order, $sent_to_admin, $plain_text, $email ) {
$GLOBALS['email_data'] = array(
'email_id' => $email->id, // The email ID (to target specific email notification)
'is_email' => true // When it concerns a WooCommerce email notification
);
}
add_action( 'woocommerce_email_before_order_table', 'action_woocommerce_email_before_order_table', 1, 4 );
function action_woocommerce_order_item_meta_end( $item_id, $item, $order, $plain_text ) {
// Getting the custom 'email_data' global variable
$ref_name_globals_var = $GLOBALS;
// Isset & NOT empty
if ( isset ( $ref_name_globals_var ) && ! empty( $ref_name_globals_var ) ) {
// Isset
$email_data = isset( $ref_name_globals_var['email_data'] ) ? $ref_name_globals_var['email_data'] : '';
// NOT empty
if ( ! empty( $email_data ) ) {
// Target specific emails, several can be added in the array, separated by a comma
$target_emails = array( 'customer_completed_order' );
// Target specific WooCommerce email notifications
if ( in_array( $email_data['email_id'], $target_emails ) ) {
// Get product ID
$product_id = $item->get_product_id();
// Get field
$erlebnisidgc = get_field( 'erlebnis_id', $product_id );
// Has some value
if ( $erlebnisidgc ) {
echo '<p>Here is your Link</p>';
echo 'Testlink';
}
}
}
}
}
add_action( 'woocommerce_order_item_meta_end', 'action_woocommerce_order_item_meta_end', 10, 4 );
Used in this answer:
Determine only for WooCommerce admin email notification
How to target other WooCommerce order emails

Display message in WooCommerce email notifications when order has backorder items in it

I am trying to display a specific message on the Order confirmation email IF one of several products of your order is/are on backorder.
I am struggling to get the right function to scan all the products and get my boolean working.
My current code:
add_action( 'woocommerce_email_after_order_table', 'backordered_items_checkout_notice_email', 20, 4 );
function backordered_items_checkout_notice_email( $order, $sent_to_admin, $plain_text, $email ) {
$found2 = false;
foreach ( $order->get_items() as $item ) {
if( $item['data']->is_on_backorder( $item['quantity'] ) ) {
$found2 = true;
break;
}
}
if( $found2 ) {
if ( $email->id == 'customer_processing_order' ) {echo ' <strong>'.__('⌛ One or several products are Currently out of stock. <br/>Please allow 2-3 weeks for delivery.', 'plugin-mve').'</strong><br/>';}
}
}
With this code, when you click on "Order" the page just freezes and no email is sent. But I get the order in the backend.
Could anyone give me a hand to fix?
Your code contains a CRITICAL uncaught error, namely: Call to a member function is_on_backorder() on null
Following code will add the message for the customer_processing_order email notification. Also see: How to target other WooCommerce order emails
So you get:
function action_woocommerce_email_after_order_table( $order, $sent_to_admin, $plain_text, $email ) {
// Initialize
$flag = false;
// Target certain email notification
if ( $email->id == 'customer_processing_order' ) {
// Iterating through each item in the order
foreach ( $order->get_items() as $item ) {
// Get a an instance of product object related to the order item
$product = $item->get_product();
// Check if the product is on backorder
if ( $product->is_on_backorder() ) {
$flag = true;
// Stop the loop
break;
}
}
// True
if ( $flag ) {
echo '<p style="color: red; font-size: 30px;">' . __( 'My message', 'woocommerce' ) . '</p>';
}
}
}
add_action( 'woocommerce_email_after_order_table', 'action_woocommerce_email_after_order_table', 10, 4 );

WooCommerce variables in Webhooks

I'm using WooCommerce Bookings & WooCommerce Vendors plugins and I want to get the booking & vendor information in a Webhook (on order confirmation) along with the order information to send to a 3rd party.
Currently, the Order Created webhook only contains the product order details (not Booking & Vendor).
I've been searching a lot for different answers and trying to go down a few different paths (inputting into the webhook directly vs add_order_item_meta.
Here's one way I've tried:
add_action('woocommerce_add_order_item_meta', 'add_order_item_meta', 10, 2);
function add_order_item_meta($item_id, $values) {
// Get order id to get booking details
global $post;
$order = wc_get_order( $post->ID );
$order_id = $order->get_id();
$items = $order->get_items();
$booking_data = new WC_Booking_Data_Store();
$booking_ids = $booking_data->get_booking_ids_from_order_id( $order_id );
if ( is_array( $booking_ids ) && count( $booking_ids ) > 0 ) {
foreach ( $booking_ids as $booking_id ) {
$booking = get_wc_booking( $booking_id );
$booking_product = $booking->get_product()->get_title()
$booker_start_date = $booking->get_start_date();
$booker_end_date = $booking->get_end_date();
if ( ! empty( $booking_id ) ){
woocommerce_add_order_item_meta($item_id, "Booking Title", $booking_product);
}
if ( ! empty( $booking_id ) ){
woocommerce_add_order_item_meta($item_id, "Booking ID", $booking_id);
}
if ( ! empty( $booker_start_date ) ){
woocommerce_add_order_item_meta($item_id, "Booking Start Date", $booker_start_date);
}
if ( ! empty( $booker_end_date ) ){
woocommerce_add_order_item_meta($item_id, "Booking End Date", $booker_end_date);
}
}
}
The output of this is a large array of bookings that have been made under the user, so it seems the $order_id isn't passing into the $bookings_id properly.
Also, for some reason, I haven't been able to get $items = $order->get_items(); as I keep getting Uncaught Error: Call to a member function get_items() on boolean. I want to use this to get the vendor email.
I'd prefer a webhook rather than using the API because it looks like you can't filter through booking in the API (ie you have to fetch all bookings).
Happy to get any guidance on the best way to approach it.
Thanks, Andy
So I ended up creating a hook based on payment confirmed.
It might not be the best way, but it's piping the info through based on the correct trigger.
add_action('woocommerce_webhook_payload', 'my_woocommerce_webhook_payload', 1, 4);
function my_woocommerce_webhook_payload($payload, $resource, $resource_id, $id) {
// Get Order details via order id
$payload['order_id'] = $resource_id;
$order_id = $resource_id;
$order = wc_get_order( $order_id );
$order_data = $order->get_data();
// Get booking ids from Order
$booking_ids = WC_Booking_Data_Store::get_booking_ids_from_order_id( $order_id );
$payload['booking_ids'] = $booking_ids;
// Add relevant information to each booking
if ( is_array( $booking_ids ) && count( $booking_ids ) > 0 ) {
foreach ( $booking_ids as $key=>$booking_id ) {
// Fetch booking details
$booking = get_wc_booking( $booking_id );
$booking_product = $booking->get_product()->get_title();
$booker_start_date = $booking->get_start_date();
$booker_end_date = $booking->get_end_date();
$booking_details = [];
// Add booking details
$payload["bookings"][$key] = $booking_details;
}
}
return $payload;
}

Resources