I've created my own email class in WooCommerce. Because I need a custom parameter in my email content, I've added a placeholder with this custom parameter to the wc email trigger function:
public function trigger( $order_id, $firstname, $lastname, $order = false ) {
$this->setup_locale();
if ( $order_id && ! is_a( $order, 'WC_Order' ) ) {
$order = wc_get_order( $order_id );
}
if ( is_a( $order, 'WC_Order' ) ) {
$this->object = $order;
$this->recipient = $this->object->get_billing_email();
$this->placeholders['{order_date}'] = wc_format_datetime( $this->object->get_date_created() );
$this->placeholders['{order_number}'] = $this->object->get_order_number();
$this->placeholders['{full_name}'] = $firstname . ' ' . $lastname;
}
if ( $this->is_enabled() && $this->get_recipient() ) {
$this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
}
$this->restore_locale();
}
After his I've did this in the content PHP file:
<?php printf( __( get_option( 'wc_custom_email_info' ) ), '{full_name}' ); ?>
In the option I've wrote %s so that I can add the full name into to content. But sadly I'm getting the name of the placeholder and not the content:
Blaaaaaaa {full_name} blaaaa
But I need this here:
Blaaaaaaa Joe Martin blaaaa
Update
The name here is not the customer name from the order. This is a name which I pass through a do_action which I trigger from a button. So when someone on my page clicks this button, I'm fetching his user id and get the name from the user who clicked the button. This is the custom email trigger I use:
$user = get_userdata( get_current_user_id() );
$firstname = $user->user_firstname;
$lastname = $user->last_name;
//Trigger email sending
do_action( 'trigger_email', $order_id, $firstname, $lastname );
Then I do this in the email class:
//Trigger for this email.
add_action( 'trigger_email', array( $this, 'trigger' ), 10, 10 );
After this you can go back to the top trigger function.
Updated
Placeholders in email are only for the email subject in Woocommerce
So what you are trying to do can't work this way.
Instead you will need to make a little change in your trigger() function and adding another method in your class:
/**
* Trigger the sending of this email.
*/
public function trigger( $order_id, $firstname, $lastname, $order = false ) {
$this->setup_locale();
if ( $order_id && ! is_a( $order, 'WC_Order' ) ) {
$order = wc_get_order( $order_id );
}
if ( is_a( $order, 'WC_Order' ) ) {
$this->object = $order;
$this->recipient = $this->object->get_billing_email();
$this->placeholders['{order_date}'] = wc_format_datetime( $this->object->get_date_created() );
$this->placeholders['{order_number}'] = $this->object->get_order_number();
$this->formatted_name = $firstname . ' ' . $lastname;
}
if ( $this->is_enabled() && $this->get_recipient() ) {
$this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
}
$this->restore_locale();
}
/**
* Get email content.
*
* #return string
*/
public function get_content() {
$this->sending = true;
if ( 'plain' === $this->get_email_type() ) {
$email_content = preg_replace( $this->plain_search, $this->plain_replace, strip_tags( $this->get_content_plain() ) );
} else {
$email_content = str_replace( '{full_name}', $this->formatted_name, $this->get_content_html() );
}
return wordwrap( $email_content, 70 );
}
This time your placeholder should be replaced with your dynamic $firstname . ' ' . $lastname; when using in your template (content):
<?php printf( get_option( 'wc_custom_email_info' ), '{full_name}' ); ?>
Original answer
Try the following instead that use WC_Order method get_formatted_billing_full_name():
public function trigger( $order_id, $firstname, $lastname, $order = false ) {
$this->setup_locale();
if ( $order_id && ! is_a( $order, 'WC_Order' ) ) {
$order = wc_get_order( $order_id );
}
if ( is_a( $order, 'WC_Order' ) ) {
$this->object = $order;
$this->recipient = $this->object->get_billing_email();
$this->placeholders['{order_date}'] = wc_format_datetime( $this->object->get_date_created() );
$this->placeholders['{order_number}'] = $this->object->get_order_number();
$this->placeholders['{full_name}'] = $this->object->get_formatted_billing_full_name();
}
if ( $this->is_enabled() && $this->get_recipient() ) {
$this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
}
$this->restore_locale();
}
It should works. Before on your code $firstname and $lastname were not defined;
Related
I have this function which adds custom meta field to the product detail in all WooCommerce emails. But I need to show only after the order is paid (this can be also just the "completed" email).
add_action( 'woocommerce_order_item_meta_start', 'email_confirmation_display_order_items', 10, 3 );
function email_confirmation_display_order_items( $item_id, $item, $order ) {
// On email notifications for line items
if ( ! is_wc_endpoint_url() && $item->is_type('line_item') ) {
$ot_address = get_post_meta( $item->get_product_id(), 'ot_address', true );
if ( ! empty($ot_address) ) {
printf( '<div>' . __("Terms: %s", "woocommerce") . '</div>', $ot_address );
}
}
}
I hoped that I can nest it inside if ( $email->id == 'customer_completed_order' ) {}, so the final code will look like this:
add_action( 'woocommerce_order_item_meta_start', 'email_confirmation_display_order_items', 10, 3 );
function email_confirmation_display_order_items( $item_id, $item, $order ) {
if ( $email->id == 'customer_completed_order' ) {
// On email notifications for line items
if ( ! is_wc_endpoint_url() && $item->is_type('line_item') ) {
$ot_address = get_post_meta( $item->get_product_id(), 'ot_address', true );
if ( ! empty($ot_address) ) {
printf( '<div>' . __("Terms: %s", "woocommerce") . '</div>', $ot_address );
}
}
}
}
But it stops working after that change. Any advice?
As you can see in your code attempt, $email is not part of the woocommerce_order_item_meta_start hook. So to target certain WooCommerce email notifications, you will need a workaround.
Step 1) creating and adding a global variable, via another hook that only applies to WooCommerce email notifications.
// 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_order_item_meta_start, use the global variable so we can target certain WooCommerce email notifications
function action_woocommerce_order_item_meta_start( $item_id, $item, $order, $plain_text ) {
// On email notifications for line items
if ( ! is_wc_endpoint_url() && $item->is_type('line_item') ) {
// 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', 'customer_completed_order' ) ) ) {
// Get meta
$ot_address = get_post_meta( $item->get_product_id(), 'ot_address', true );
// OR use to get meta
// $ot_address = $item->get_meta( 'ot_address' );
if ( ! empty( $ot_address ) ) {
printf( '<div>' . __( 'Terms: %s', 'woocommerce' ) . '</div>', $ot_address );
}
}
}
}
add_action( 'woocommerce_order_item_meta_start', 'action_woocommerce_order_item_meta_start', 10, 4 );
I'm adding a text with a hook for the email, but I'd like it to change according to the payment method.
My code attempt:
add_action( 'woocommerce_email_before_order_table', 'bbloomer_add_content_specific_email', 20, 4 );
function bbloomer_add_content_specific_email( $order, $sent_to_admin, $plain_text, $email, $order_id ) {
$order = wc_get_order( $order_id );
$order = wc_get_order( $order_id );
$user_complete_name_and_email = $order->billing_first_name . ' ' . $order->billing_last_name . ' <' . $order->billing_email . '>';
$to = $user_complete_name_and_email;
if ( $email->id == 'customer_processing_order' ) {
if ( get_post_meta($order->id, '_payment_method', true) == 'bacs' ) {
echo '<p>One text</p>';
}elseif ( get_post_meta($order->id, '_payment_method', true) == 'wocommerce_yape_peru' ) {
echo '<p>Another text</p>';
}
elseif ( get_post_meta($order->id, '_payment_method', true) == 'woo-mercado-pago-custom' ) {
echo '<p>Third text</p>';
}
}
}
Unfortunately this does not have the desired result. Am I doing something wrong? any advice?
You can use $order->get_payment_method(), so you get:
function action_woocommerce_email_before_order_table( $order, $sent_to_admin, $plain_text, $email ) {
// Only for order processing email
if ( $email->id == 'customer_processing_order' ) {
// Get payment method
$payment_method = $order->get_payment_method();
// Compare
if ( $payment_method == 'cod' ) {
echo 'text 1';
} elseif( $payment_method == 'bacs' ) {
echo 'text 2';
} else {
echo 'text 3';
}
}
}
add_action( 'woocommerce_email_before_order_table', 'action_woocommerce_email_before_order_table', 10, 4 );
I'm trying to hook into 'woocommerce_email_recipient_booking_confirmed' to update/add to the recipient field. The link below works perfectly for default WooCommerce emails (and their actions). The action works if I manually type in an email within the action but I need the email to come from the customer input (via a Custom Field on the product page).
I believe it is something to do with class-wc-email-booking-confirmed.php. When I compare it against class-wc-email-customer-completed-order.php
class-wc-email-booking-confirmed.php
public function trigger( $booking_id )
class-wc-email-customer-completed-order.php
public function trigger( $order_id, $order = false )
My code (which I haven't changed from the resource below):
add_filter( 'woocommerce_email_recipient_booking_confirmed', 'additional_customer_email_recipient', 9999, 2 ); // Completed Order
function additional_customer_email_recipient( $recipient, $order ) {
if ( ! is_a( $order, 'WC_Order' ) ) return $recipient; // when I comment this out, an ajax error is thrown. This is why I believe the order object directly accessible yet.
$additional_recipients = array(); // Initializing…
foreach( $order->get_items() as $item_id => $item_data ){
$email = wc_get_order_item_meta( $item_id, 'Email Address', true );
if( ! in_array( $email, $additional_recipients ) && strpos( $recipient, $email ) === false )
$additional_recipients[] = $email;
}
$additional_recipients = implode( ',', $additional_recipients);
if( count($additional_recipients) > 0)
{
$recipient = ','.$additional_recipients;
}
return $recipient;
}
Send Woocommerce Order to email address listed on product page
It was because it wasn't the order object, I just had to call get_order().
$order = $order->get_order();
Code:
add_filter( 'woocommerce_email_recipient_booking_confirmed', 'additional_customer_email_recipient', 10, 2 );
function additional_customer_email_recipient( $recipient, $order ) {
$order = $order->get_order();
$additional_recipients = array();
foreach( $order->get_items() as $item_id => $item_data ){
$email = wc_get_order_item_meta( $item_id, 'Email Address', true );
if( ! in_array( $email, $additional_recipients ) && strpos( $recipient, $email ) === false )
$additional_recipients[] = $email;
}
$additional_recipients = implode( ',', $additional_recipients);
if( count($additional_recipients) > 0)
{
$recipient = $additional_recipients;
}
return $recipient;
}
I am trying to change/add in the title of the "Order Recieved" Woocommerce page.
The below snippet works - I am able to change the pre-existing TEXT with the following code:
add_filter('woocommerce_thankyou_order_received_text', 'woo_change_order_received_text', 10, 2 );
function woo_change_order_received_text( $str, $order ) {
$new_str = $str . ' We have emailed the purchase receipt to you.';
return $new_str;
}
The below snippet does not work. - I am unable to change/add the TITLE and also pass in the username to personalise it. Here is the code and also an image of the output I am trying to achieve....The "You are awesome FIRSTNAME" added in.
<?php
add_filter( 'the_title', 'woo_personalize_order_received_title', 10, 2 );
function woo_personalize_order_received_title( $title, $id ) {
if ( is_order_received_page() && get_the_ID() === $id ) {
global $wp;
// Get the order. Line 9 to 17 are present in order_received() in includes/shortcodes/class-wc-shortcode-checkout.php file
$order_id = apply_filters( 'woocommerce_thankyou_order_id', absint( $wp->query_vars['order-received'] ) );
$order_key = apply_filters( 'woocommerce_thankyou_order_key', empty( $_GET['key'] ) ? '' : wc_clean( $_GET['key'] ) );
if ( $order_id > 0 ) {
$order = wc_get_order( $order_id );
if ( $order->get_order_key() != $order_key ) {
$order = false;
}
}
if ( isset ( $order ) ) {
//$title = sprintf( "You are awesome, %s!", esc_html( $order->billing_first_name ) ); // use this for WooCommerce versions older then v2.7
$title = sprintf( "You are awesome, %s!", esc_html( $order->get_billing_first_name() ) );
}
}
return $title;
}
This should be possible as there are examples on how to do it, such as here...I just can't figure out why the main title wont even appear?
As a workaround I inspected the CSS and changed the text below the header to be a larger size and the font family required.
Then through the below PHP I created the custom text with the customer name in the header.
add_filter('woocommerce_thankyou_order_received_text', 'woo_change_order_received_text', 10, 2 );
function woo_change_order_received_text( $str, $order ) {
$new_str = sprintf( "You are awesome, %s :) - We've recieved your order.", esc_html( $order->get_billing_first_name() ) );
return $new_str;
}
2022 update:
function ps_title_order_received( $title, $id ) {
if ( is_order_received_page() && get_the_ID() === $id ) {
global $wp;
$order_id = apply_filters( 'woocommerce_thankyou_order_id', absint( $wp->query_vars['order-received'] ) );
$order_key = apply_filters( 'woocommerce_thankyou_order_key', empty( $_GET['key'] ) ? '' : wc_clean( $_GET['key'] ) );
if ( $order_id > 0 ) {
$order = wc_get_order( $order_id );
if ( $order->get_order_key() != $order_key ) {
unset( $order );
}
}
if ( isset ( $order ) ) {
$title = sprintf( "Thank you, %s!", esc_html( $order->get_billing_first_name() ) );
}
}
return $title;
}
add_filter( 'the_title', 'ps_title_order_received', 10, 2 );
I noticed that the customer on hold order email is not available so i tried to replace the actions with a single action that would send the appropriate email.
This seems to work except for the on-hold status. I dont see what the difference is between the on-hold and processing case other than its not in the $available_emails in class-wc-meta-box-order-actions.php and I have removed all the others and they still work.
What I am doing wrong? Is it a way to make this possible?
My code is:
function ulmh_resend1( $actions ) {
$actions['ulmh_resend'] = __( 'Resend Email', 'text_domain' );
return $actions;
}
function ulmh_resend2( $order ) {
$mailer = WC()->mailer();
$mails = $mailer->get_emails();
if ($order->has_status( 'on-hold' )) {
$eml = 'customer_on_hold_order';
}elseif ($order->has_status( 'processing' )) {
$eml = 'customer_processing_order';
}elseif ($order->has_status( 'completed' )) {
$eml = 'customer_completed_order';
} else {
$eml = "nothing";
}
if ( ! empty( $mails ) ) {
foreach ( $mails as $mail ) {
if ( $mail->id == eml ) {
$mail->trigger( $order->id );
}
}
}
}
function ulmh_resend3( $order_emails ) {
$remove = array( 'new_order', 'cancelled_order', 'customer_processing_order', 'customer_completed_order', 'customer_invoice' );
$order_emails = array_diff( $order_emails, $remove );
return $order_emails;
}
add_action( 'woocommerce_order_actions', 'ulmh_resend1' );
add_action( 'woocommerce_order_action_ulmh_resend', 'ulmh_resend2' );
add_filter( 'woocommerce_resend_order_emails_available', 'ulmh_resend3' );
I have revisited and compacted your code because there where some errors like a typo error in if ( $mail->id == eml ){ for eml as a variable name… Also to get the Order ID from the WC_Order object you should use $order->get_id() method instead of $order->id.
Here is this new functional code:
add_action( 'woocommerce_order_actions', 'ulmh_resend1' );
function ulmh_resend1( $actions ) {
$actions['ulmh_resend'] = __( 'Resend Email', 'text_domain' );
return $actions;
}
add_action( 'woocommerce_order_action_ulmh_resend', 'ulmh_resend2' );
function ulmh_resend2( $order ) {
$wc_emails = WC()->mailer()->get_emails();
if( empty( $wc_emails ) ) return;
if ($order->has_status( 'on-hold' ))
$email_id = 'customer_on_hold_order';
elseif ($order->has_status( 'processing' ))
$email_id = 'customer_processing_order';
elseif ($order->has_status( 'completed' ))
$email_id = 'customer_completed_order';
else
$email_id = "nothing";
foreach ( $wc_emails as $wc_mail )
if ( $wc_mail->id == $email_id )
$wc_mail->trigger( $order->get_id() );
}
add_filter( 'woocommerce_resend_order_emails_available', 'ulmh_resend3' );
function ulmh_resend3( $order_emails ) {
$remove = array( 'new_order', 'cancelled_order', 'customer_processing_order', 'customer_completed_order', 'customer_invoice' );
$order_emails = array_diff( $order_emails, $remove );
return $order_emails;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested in WooCommerce 3+ and works fine now for on-hold order status email notifications, when resending