WooCommerce - send custom email on custom order status change - php

I added a custom status wc-order-confirmed:
// Register new status
function register_order_confirmed_order_status() {
register_post_status( 'wc-order-confirmed', array(
'label' => 'Potvrzení objednávky',
'public' => true,
'exclude_from_search' => false,
'show_in_admin_all_list' => true,
'show_in_admin_status_list' => true,
'label_count' => _n_noop( 'Potvrzení objednávky <span class="count">(%s)</span>', 'Potvrzení objednávky <span class="count">(%s)</span>' )
) );
}
add_action( 'init', 'register_order_confirmed_order_status' );
// Add to list of WC Order statuses
function add_order_confirmed_to_order_statuses( $order_statuses ) {
$new_order_statuses = array();
// add new order status after processing
foreach ( $order_statuses as $key => $status ) {
$new_order_statuses[ $key ] = $status;
if ( 'wc-processing' === $key ) {
$new_order_statuses['wc-order-confirmed'] = 'Potvrzení objednávky';
}
}
return $new_order_statuses;
}
add_filter( 'wc_order_statuses', 'add_order_confirmed_to_order_statuses' );
I added a custom email wc_confirmed_order:
/**
* A custom confirmed Order WooCommerce Email class
*
* #since 0.1
* #extends \WC_Email
*/
class WC_Confirmed_Order_Email extends WC_Email {
/**
* Set email defaults
*
* #since 0.1
*/
public function __construct() {
// set ID, this simply needs to be a unique name
$this->id = 'wc_confirmed_order';
// this is the title in WooCommerce Email settings
$this->title = 'Potvrzení objednávky';
// this is the description in WooCommerce email settings
$this->description = 'Confirmed Order Notification';
// these are the default heading and subject lines that can be overridden using the settings
$this->heading = 'Potvrzení objednávky';
$this->subject = 'Potvrzení objednávky';
// these define the locations of the templates that this email should use, we'll just use the new order template since this email is similar
$this->template_html = 'emails/customer-confirmed-order.php';
$this->template_plain = 'emails/plain/admin-new-order.php';
// Trigger on confirmed orders
add_action( 'woocommerce_order_status_pending_to_order_confirmed', array( $this, 'trigger' ) );
add_action( 'woocommerce_order_status_processing_to_order_confirmed', array( $this, 'trigger' ) );
// Call parent constructor to load any other defaults not explicity defined here
parent::__construct();
// this sets the recipient to the settings defined below in init_form_fields()
$this->recipient = $this->get_option( 'recipient' );
// if none was entered, just use the WP admin email as a fallback
if ( ! $this->recipient )
$this->recipient = get_option( 'admin_email' );
}
/**
* Determine if the email should actually be sent and setup email merge variables
*
* #since 0.1
* #param int $order_id
*/
public function trigger( $order_id ) {
// bail if no order ID is present
if ( ! $order_id )
return;
if ( $order_id ) {
$this->object = wc_get_order( $order_id );
$this->recipient = $this->object->billing_email;
$this->find['order-date'] = '{order_date}';
$this->find['order-number'] = '{order_number}';
$this->replace['order-date'] = date_i18n( wc_date_format(), strtotime( $this->object->order_date ) );
$this->replace['order-number'] = $this->object->get_order_number();
}
if ( ! $this->is_enabled() || ! $this->get_recipient() )
return;
// woohoo, send the email!
$this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
}
/**
* get_content_html function.
*
* #since 0.1
* #return string
*/
public function get_content_html() {
ob_start();
wc_get_template( $this->template_html, array(
'order' => $this->object,
'email_heading' => $this->get_heading()
) );
return ob_get_clean();
}
/**
* get_content_plain function.
*
* #since 0.1
* #return string
*/
public function get_content_plain() {
ob_start();
wc_get_template( $this->template_plain, array(
'order' => $this->object,
'email_heading' => $this->get_heading()
) );
return ob_get_clean();
}
/**
* Initialize Settings Form Fields
*
* #since 2.0
*/
public function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => 'Enable/Disable',
'type' => 'checkbox',
'label' => 'Enable this email notification',
'default' => 'yes'
),
'recipient' => array(
'title' => 'Recipient(s)',
'type' => 'text',
'description' => sprintf( 'Enter recipients (comma separated) for this email. Defaults to <code>%s</code>.', esc_attr( get_option( 'admin_email' ) ) ),
'placeholder' => '',
'default' => ''
),
'subject' => array(
'title' => 'Subject',
'type' => 'text',
'description' => sprintf( 'This controls the email subject line. Leave blank to use the default subject: <code>%s</code>.', $this->subject ),
'placeholder' => '',
'default' => ''
),
'heading' => array(
'title' => 'Email Heading',
'type' => 'text',
'description' => sprintf( __( 'This controls the main heading contained within the email notification. Leave blank to use the default heading: <code>%s</code>.' ), $this->heading ),
'placeholder' => '',
'default' => ''
),
'email_type' => array(
'title' => 'Email type',
'type' => 'select',
'description' => 'Choose which format of email to send.',
'default' => 'html',
'class' => 'email_type',
'options' => array(
'plain' => __( 'Plain text', 'woocommerce' ),
'html' => __( 'HTML', 'woocommerce' ),
'multipart' => __( 'Multipart', 'woocommerce' ),
)
)
);
}
} // end \WC_confirmed_Order_Email class
I can see the email in the email settings, and the status in the order statuses dropdown. Now, I need to send my new email whenever the order status is changed to wc-order-confirmed. The transition hook seems to never be firing.
I also tried:
/**
* Register the "woocommerce_order_status_pending_to_quote" hook which is necessary to
* allow automatic email notifications when the order is changed to refunded.
*
* #modified from http://stackoverflow.com/a/26413223/2078474 to remove anonymous function
*/
add_action( 'woocommerce_init', 'so_25353766_register_email' );
function so_25353766_register_email(){
add_action( 'woocommerce_order_status_pending_to_order_confirmed', array( WC(), 'send_transactional_email' ), 10, 10 );
add_action( 'woocommerce_order_status_processing_to_order_confirmed', array( WC(), 'send_transactional_email' ), 10, 10 );
}
Which also doesn't seem to work at all... Any ideas, please?

The hook you need is:
woocommerce_order_status_changed
add_action("woocommerce_order_status_changed", "my_awesome_publication_notification");
function my_awesome_publication_notification($order_id, $checkout=null) {
global $woocommerce;
$order = new WC_Order( $order_id );
if($order->status === 'completed' ) {
// Create a mailer
$mailer = $woocommerce->mailer();
$message_body = __( 'Hello world!!!' );
$message = $mailer->wrap_message(
// Message head and message body.
sprintf( __( 'Order %s received' ), $order->get_order_number() ), $message_body );
// Cliente email, email subject and message.
$mailer->send( $order->billing_email, sprintf( __( 'Order %s received' ), $order->get_order_number() ), $message );
}
}
}

As Xcid's answer indicates, you need to register the email.
In WC 2.2+ I believe you can do this via the following:
add_action( 'woocommerce_order_status_wc-order-confirmed', array( WC(), 'send_transactional_email' ), 10, 10 );
I'd added a filter to WooCommerce 2.3, so when that comes out custom emails will be able to be added to the list of email actions that WooCommerce registers:
// As of WooCommerce 2.3
function so_27112461_woocommerce_email_actions( $actions ){
$actions[] = 'woocommerce_order_status_wc-order-confirmed';
return $actions;
}
add_filter( 'woocommerce_email_actions', 'so_27112461_woocommerce_email_actions' );

As you can see here :
https://github.com/woothemes/woocommerce/blob/f8a161c40673cb019eb96b04c04a774ca040a15a/includes/abstracts/abstract-wc-order.php#L2097
you can use this hook :
do_action( 'woocommerce_order_status_' . $new_status, $this->id );
with you custom status should give :
add_action( 'woocommerce_order_status_wc-order-confirmed' , array( $this, 'trigger' ) );
I imagine that you also add you custom email to the mailer, if not :
just add :
add_filter( 'woocommerce_email_classes', array($this,'edit_woocommerce_email_classes' ));
function edit_woocommerce_email_classes( $email_classes ) {
require_once( 'your-email-class.php' );
$email_classes[ 'WC_Confirmed_Order_Email' ] = new WC_Confirmed_Order_Email();
return $email_classes;
}
Edit :
You need to instanciate woocommerce emails before so you can add
add_action( 'init' , 'initiate_woocommerce_email' );
function initiate_woocommerce_email(){
// Just when you update the order_status on backoffice
if( isset($_POST['order_status']) ) {
WC()->mailer();
}
}

You can try to watch when the order status changed so put this into functions.php:
function confirmed_notifications($order_id, $checkout=null) {
global $woocommerce;
$order = new WC_Order( $order_id );
if( $order->status === 'order-confirmed' ) {
// Trigger transactional email to client
$email = $mailer->emails['WC_Confirmed_Order_Email'];
$email->trigger( $order_id );
}
}
add_action("woocommerce_order_status_changed", "confirmed_notifications");
This function will trigger your email and send it.

Related

Wordpress Custom Email Sending Twice

I'm developing a plugin to integrate my WooCommerce store with a third-party right now, and as part of that integration I need to send the customer a new email with some license keys in it. The email sending functionality is fine, the class and its template are working as intended, but the email's sending twice, and I can't figure out why.
I've combed over the new email class and compared it with vanilla WooCommerce email classes, and can't tell where I'm going wrong. I've also tried using an if (did_action( 'woocommerce_order_status_completed_notification' ) === 1) {} check to limit the trigger function to one email, and even still it's sending two.
The code for my email class is here, which is where I'm assuming the problem to be as it doesn't interface with anything other than the default WooCommerce hooks that are working as expected with the vanilla emails. I've tested it with a number of different hooks (both vanilla WooCommerce ones and those I'm calling from my plugin's code), and I'm getting this same double email regardless. If anyone can see where I'm going wrong it'd be tremendously helpful!
<?php
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
if ( ! class_exists( 'Foundry_Code_Email', false ) ) :
class Foundry_Code_Email extends WC_Email {
/**
* Set email defaults
*/
public function __construct() {
$this->id = 'foundry_code_email'; // Unique ID for custom email
$this->customer_email = true; // Is a customer email
$this->title = __( 'Foundry Premium Content Email', 'woocommerce' ); // Title field in WooCommerce Email settings
$this->description = __( 'Foundry email is sent when customer purchases Foundry Premium Content', 'woocommerce' ); // Description field in WooCommerce email settings
$this->template_base = WP_PLUGIN_DIR . '/foundry-premium-content/templates/';
$this->template_html = 'emails/foundry-code-email.php';
$this->template_plain = 'emails/plain/foundry-code-email.php';
// $this->template_html = 'emails/customer-refunded-order.php';
$this->placeholders = array(
// '{site_title}' => $this->get_blogname(),
'{order_date}' => '',
'{order_number}' => '',
);
// Trigger email when woocommerce_order_status_completed_notification is called when payment is complete - double email debug
add_action( 'woocommerce_order_status_completed_notification', array( $this, 'trigger' ), 10, 2 );
// Call parent constructor to load any other defaults not explicitly defined here.
parent::__construct();
}
/**
* Prepares email content and triggers the email
*
* #param int $order_id
*/
public function trigger( $order_id, $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();
// Maybe include an additional check to make sure that stuff happened
}
if ( $this->is_enabled() && $this->get_recipient() ) {
// All well, send the email
$this->send ( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
}
$this->restore_locale();
// Add order note about the same
$this->object->add_order_note( sprintf(__('%s email sent to the customer.', 'woocommerce'), $this->get_title() ) );
// Set order meta to indicate that the welcome email was sent
update_post_meta( $order_id, 'foundry_code_email_sent', 1);
}
/**
* Get email subject.
*
* #since 3.1.0
* #return string
*/
public function get_default_subject() {
return __( '{site_title}: Foundry VTT Premium Content Codes', 'woocommerce' );
}
/**
* Get email heading
*
* #since 3.1.0
* #return string
*/
public function get_default_heading() {
return __('Your Foundry Premium Content Codes', 'woocommerce' );
}
/**
* get_content_html function
*
* #return string
*/
public function get_content_html() {
return wc_get_template_html(
$this->template_html,
array(
'order' => $this->object,
'email_heading' => $this->get_heading(),
'additional_content' => $this->get_additional_content(),
'sent_to_admin' => false,
'plain_text' => false,
'email' => $this,
), '', $this->template_base
);
}
public function get_content_plain() {
return wc_get_template_html(
$this->template_plain,
array(
'order' => $this->object,
'email_heading' => $this->get_heading(),
'additional_content' => $this->get_additional_content(),
'sent_to_admin' => false,
'plain_text' => true,
'email' => $this,
), '', $this->template_base
);
}
public function get_default_additional_content() {
return __( 'Thanks for shopping with us.', 'woocommerce' );
}
/*
* Initialise settings form fields
*/
public function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => __( 'Enable/Disable', 'woocommerce' ),
'type' => 'checkbox',
'label' => 'Enable this email notification',
'default' => 'yes'
),
'subject' => array(
'title' => __( 'Subject', 'woocommerce' ),
'type' => 'text',
'desc_tip' => true,
'description' => sprintf( 'This controls the email subject line. Leave blank to use the default subject: <code>%s</code>.', $this->get_subject() ),
'placeholder' => $this->get_default_subject(),
'default' => ''
),
'heading' => array(
'title' => __( 'Email Heading', 'woocommerce' ),
'type' => 'text',
'desc_tip' => true,
'description' => sprintf( __( 'This controls the main heading contained within the email notification. Leave blank to use the default heading: <code>%s</code>.' ), $this->get_heading() ),
'placeholder' => $this->get_default_heading(),
'default' => ''
),
'email_type' => array(
'title' => __( 'Email type', 'woocommerce'),
'type' => 'select',
'description' => __( 'Choose which format of email to send.', 'woocommerce' ),
'default' => 'html',
'class' => 'email_type wc-enhanced-select',
'options' => $this->get_email_type_options(),
'desc_tip' => true,
)
);
}
}
endif;
return new Foundry_Code_Email();
?>
I found the root issue with this was that I was returning the email class twice: once in the class file itself and once in my overall functions file.
This was my old code in that functions file:
function fpc_custom_woocommerce_emails( $email_classes ) {
// Custom email for Foundry Premium Content
$plugin_dir = dirname(__DIR__);
include_once( $plugin_dir . '/Includes/class-foundry-code-email.php' );
$email_classes['Foundry_Code_Email'] = new Foundry_Code_Email(); // Add to the list of email classes that WooCommerce loads.
return $email_classes;
}
And this is the revised code in that file now:
function fpc_custom_woocommerce_emails( $email_classes ) {
// Custom email for Foundry Premium Content
$plugin_dir = dirname(__DIR__);
$email_classes['Foundry_Code_Email'] = include_once( $plugin_dir . '/Includes/class-foundry-code-email.php' );
return $email_classes;
}

Send cancelled and failed order email to customer in Woocommerce 3

I need to send cancelled and failed order email to customers in Woocommerce 3.4+.
I'm constantly getting Fatal error: Uncaught Error: Call to a member function get_billing_email() on null in
I've tried few function (like below) from stackoverflow with same result:
function wc_cancelled_order_add_customer_email( $recipient, $order )
{
return $recipient .= "," . $order->get_billing_email();
}
add_filter( 'woocommerce_email_recipient_cancelled_order', 'wc_cancelled_order_add_customer_email', 10, 2 );
add_filter( 'woocommerce_email_recipient_failed_order', 'wc_cancelled_order_add_customer_email', 10, 2 );
What is wrong? How can I avoid this error?
You should need check that $order argument is valid instance of the WC_Order Class:
add_filter( 'woocommerce_email_recipient_cancelled_order', 'wc_cancelled_order_add_customer_email', 10, 2 );
add_filter( 'woocommerce_email_recipient_failed_order', 'wc_cancelled_order_add_customer_email', 10, 2 );
function wc_cancelled_order_add_customer_email( $recipient, $order ){
// Avoiding errors in backend (mandatory when using $order argument)
if ( ! is_a( $order, 'WC_Order' ) ) return $recipient;
return $recipient .= "," . $order->get_billing_email();
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
You could also use instead in this particular case:
// Avoiding errors in backend (mandatory when using $order argument)
if ( ! method_exists( $order, 'get_billing_email' ) ) return $recipient;
Related and similar:
Sending email to customer on cancelled order in Woocommerce
Add recipients based on user role to failed and cancelled WooCommerce emails
I have found a very nice approach:
First, extend the woocommerce default emails by adding a filter to woocommerce_email_classes:
add_filter('woocommerce_email_classes', function ($classes) {
$classes['WC_Email_Customer_Order_Failed'] = include __DIR__ . "/wc-emails/class-wc-customer-order-failed.php";
// you can add as many classes as you want here
return $classes;
});
Then, we create the ./wc-emails/class-wc-customer-order-failed.php file. I recommend starting with one of the original WC_Email classes, located under /wp-content/plugins/woocommerce/emails/class-wc-email-{$email-name}.php. Make sure you rename the class after you do it. As the time of this writing I'm using Woocommerce 5.3.0, and the class-wc-customer-order-failed.php should look like this:
<?php
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly.
}
if (!class_exists('WC_Email_Customer_Order_Failed', false)) {
/**
* Cancelled Order Email.
*
* An email sent to the admin when an order is cancelled.
*
* #class WC_Email_Cancelled_Order
* #version 2.2.7
* #package WooCommerce\Classes\Emails
* #extends WC_Email
*/
class WC_Email_Customer_Order_Failed extends WC_Email
{
/**
* Constructor.
*/
public function __construct()
{
$this->id = 'custom_failed_order';
// add this to send to customer
$this->customer_email = true;
$this->title = 'This is a custom email template';
$this->description = 'You can modify this text to appear in the admin area';
// I'm pointing to a new template which I created in the THEME folder
// to use default email file should be admin-failed-order.php
$this->template_html = 'emails/customer-failed-order.php';
$this->template_plain = 'emails/plain/customer-failed-order.php';
$this->placeholders = array(
'{order_date}' => '',
'{order_number}' => '',
);
// Triggers for this email.
add_action('woocommerce_order_status_pending_to_failed_notification', array($this, 'trigger'), 10, 2);
add_action('woocommerce_order_status_on-hold_to_failed_notification', array($this, 'trigger'), 10, 2);
// Call parent constructor.
parent::__construct();
}
/**
* Get email subject.
*
* #since 3.1.0
* #return string
*/
public function get_default_subject()
{
return __('[{site_title}]: Order #{order_number} has failed', 'woocommerce');
}
/**
* Get email heading.
*
* #since 3.1.0
* #return string
*/
public function get_default_heading()
{
return __('Order Failed: #{order_number}', 'woocommerce');
}
/**
* Trigger the sending of this email.
*
* #param int $order_id The order ID.
* #param WC_Order|false $order Order object.
*/
public function trigger($order_id, $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 is the correct place to get_billing_email() working
$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();
}
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 content html.
*
* #return string
*/
public function get_content_html()
{
return wc_get_template_html(
$this->template_html,
array(
'order' => $this->object,
'email_heading' => $this->get_heading(),
'additional_content' => $this->get_additional_content(),
'sent_to_admin' => false,
'plain_text' => false,
'email' => $this,
)
);
}
/**
* Get content plain.
*
* #return string
*/
public function get_content_plain()
{
return wc_get_template_html(
$this->template_plain,
array(
'order' => $this->object,
'email_heading' => $this->get_heading(),
'additional_content' => $this->get_additional_content(),
// remove sending to admin, there is another email that does that
'sent_to_admin' => false,
'plain_text' => true,
'email' => $this,
)
);
}
/**
* Default content to show below main email content.
*
* #since 3.7.0
* #return string
*/
public function get_default_additional_content()
{
return __('Hopefully they’ll be back. Read more about troubleshooting failed payments.', 'woocommerce');
}
/**
* Initialise settings form fields.
*/
public function init_form_fields()
{
/* translators: %s: list of placeholders */
$placeholder_text = sprintf(__('Available placeholders: %s', 'woocommerce'), '<code>' . esc_html(implode('</code>, <code>', array_keys($this->placeholders))) . '</code>');
$this->form_fields = array(
'enabled' => array(
'title' => __('Enable/Disable', 'woocommerce'),
'type' => 'checkbox',
'label' => __('Enable this email notification', 'woocommerce'),
'default' => 'yes',
),
// no need to define recipients in the admin panel
// 'recipient' => array(
// 'title' => __('Recipient(s)', 'woocommerce'),
// 'type' => 'text',
// /* translators: %s: WP admin email */
// 'description' => sprintf(__('Enter recipients (comma separated) for this email. Defaults to %s.', 'woocommerce'), '<code>' . esc_attr(get_option('admin_email')) . '</code>'),
// 'placeholder' => '',
// 'default' => '',
// 'desc_tip' => true,
// ),
'subject' => array(
'title' => __('Subject', 'woocommerce'),
'type' => 'text',
'desc_tip' => true,
'description' => $placeholder_text,
'placeholder' => $this->get_default_subject(),
'default' => '',
),
'heading' => array(
'title' => __('Email heading', 'woocommerce'),
'type' => 'text',
'desc_tip' => true,
'description' => $placeholder_text,
'placeholder' => $this->get_default_heading(),
'default' => '',
),
'additional_content' => array(
'title' => __('Additional content', 'woocommerce'),
'description' => __('Text to appear below the main email content.', 'woocommerce') . ' ' . $placeholder_text,
'css' => 'width:400px; height: 75px;',
'placeholder' => __('N/A', 'woocommerce'),
'type' => 'textarea',
'default' => $this->get_default_additional_content(),
'desc_tip' => true,
),
'email_type' => array(
'title' => __('Email type', 'woocommerce'),
'type' => 'select',
'description' => __('Choose which format of email to send.', 'woocommerce'),
'default' => 'html',
'class' => 'email_type wc-enhanced-select',
'options' => $this->get_email_type_options(),
'desc_tip' => true,
),
);
}
}
}
return new WC_Email_Customer_Order_Failed();
Please note
In occasion of Woocommerce update, you should check if the customised files have been updated, and its up to you to keep compatibility :)

Adding recipients to Woocommerce email notifications based on product variation term

I have created a Woocommerce plugin and require it to do two things:
Send a notification message to a specific email address, based on which product variation is in the cart.
The email must contain only the relevant product, and not products that contain other attributes.
For example:
Product A has an Attribute named Chef, with chef-one and chef-two as variable Terms. The user may select Product A from chef-one or chef-two.
If the user selects Product A from chef-one, a notification email must be sent to chefone#email.com containing the name of the product ordered (as it would show up in a regular Woocommerce notification email).
If the user selects Product A from chef-one and Product B from chef-two, a notification email must be sent to chef-one containing only Product A, and a notification email must be sent to chef-two containing only Product B.
I have created the plugin using the tutorial found on https://www.skyverge.com/blog/how-to-add-a-custom-woocommerce-email/ and have adapted it to suit the above purpose.
I have also adapted code found the following solutions:
Adding a custom woocommerce email based on the product attribute
Woocommerce - Need to send email to specific address based on zip code
Here is the code from my plugin's class file:
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
/**
* A custom WAKIKI Order WooCommerce Email class
*
* #since 0.1
* #extends \WC_Email
*/
class WC_Wakiki_Order_Email extends WC_Email {
/**
* Set email defaults
*
* #since 0.1
*/
public function __construct() {
// set ID, this simply needs to be a unique name
$this->id = 'wc_wakiki_order';
// this is the title in WooCommerce Email settings
$this->title = 'WAKIKI Order';
// this is the description in WooCommerce email settings
$this->description = 'WAKIKI Order Notification emails are sent when a customer places an order on the website';
// these are the default heading and subject lines that can be overridden using the settings
$this->heading = 'WAKIKI Delivery Order';
$this->subject = 'WAKIKI Delivery Order';
// these define the locations of the templates that this email should use, we'll just use the new order template since this email is similar
$this->template_html = 'emails/admin-new-order.php';
$this->template_plain = 'emails/plain/admin-new-order.php';
// Trigger on new paid orders
add_action( 'woocommerce_order_status_pending_to_processing_notification', array( $this, 'trigger' ) );
add_action( 'woocommerce_order_status_failed_to_processing_notification', array( $this, 'trigger' ) );
// Call parent constructor to load any other defaults not explicity defined here
parent::__construct();
// this sets the recipient to the settings defined below in init_form_fields()
$this->recipient = $this->get_option( 'recipient' );
// if none was entered, just use the WP admin email as a fallback
if ( ! $this->recipient )
$this->recipient = get_option( 'admin_email' );
}
/**
* Determine if the email should actually be sent and setup email merge variables
*
* #since 0.1
* #param int $order_id
*/
public function trigger( $order_id ) {
// Bail if no order ID is present
if ( ! $order_id )
return;
$order = new WC_Order( $order_id );
// Find the product_id
$items = $order->get_items();
foreach ( $items as $item ) {
$product_id = $item['product_id'];
}
// From the product_id get the product attribute
$product = new WC_Product( $product_id ); // create an object of WC_Product class
$patt = $product->get_attributes(); // call get_attributes method
// Condition valid to send the email (if the attributes is chef)
if ( array_key_exists('pa_chef', $patt) )
// Determine which email address to send to, based on Product Attribute Term)
add_filter( 'new_order' , 'add_recipient', 20, 2 );
function add_recipient( $email, $order ) {
$additional_email = "info#email.com";
$terms = get_terms("pa_chef");
if( $order->$term->name == "pa_chef-one" ){
$email = explode( ',', $email );
array_push( $email, $additional_email );
}
return $email;
}
{
// Send the email
// Setup order object
$this->object = new WC_Order( $order_id );
$this->recipient = $this->object->billing_email;
// Replace variables in the subject/headings
$this->find[] = '{order_date}';
$this->replace[] = date_i18n( woocommerce_date_format(), strtotime( $this->object->order_date ) );
$this->find[] = '{order_number}';
$this->replace[] = $this->object->get_order_number();
if ( ! $this->is_enabled() || ! $this->get_recipient() )
return;
// Send the email!
$this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
}
else
{
return; //do nothing if there is not chef attribute
}
}
/**
* get_content_plain function
*
* #since 0.1
* #return string
*/
public function get_content_plain() {
ob_start();
woocommerce_get_template( $this->template_plain, array(
'order' => $this->object,
'email_heading' => $this->get_heading()
) );
return ob_get_clean();
}
/**
* Initialize Settings Form Fields
*
* #since 2.0
*/
public function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => 'Enable/Disable',
'type' => 'checkbox',
'label' => 'Enable this email notification',
'default' => 'yes'
),
'recipient' => array(
'title' => 'Recipient(s)',
'type' => 'text',
'description' => sprintf( 'Enter recipients (comma separated) for this email. Defaults to <code>%s</code>.', esc_attr( get_option( 'admin_email' ) ) ),
'placeholder' => '',
'default' => ''
),
'subject' => array(
'title' => 'Subject',
'type' => 'text',
'description' => sprintf( 'This controls the email subject line. Leave blank to use the default subject: <code>%s</code>.', $this->subject ),
'placeholder' => '',
'default' => ''
),
'heading' => array(
'title' => 'Email Heading',
'type' => 'text',
'description' => sprintf( __( 'This controls the main heading contained within the email notification. Leave blank to use the default heading: <code>%s</code>.' ), $this->heading ),
'placeholder' => '',
'default' => ''
),
'email_type' => array(
'title' => 'Email type',
'type' => 'select',
'description' => 'Choose which format of email to send.',
'default' => 'html',
'class' => 'email_type',
'options' => array(
'plain' => __( 'Plain text', 'woocommerce' ),
'html' => __( 'HTML', 'woocommerce' ),
'multipart' => __( 'Multipart', 'woocommerce' ),
)
)
);
}
This is as close as I am able to get it, but it is not working. I suspect the problem lies somewhere around the line that says "Determine which email address to send to, based on Product Attribute Term". The plugin was loading until I added that section.
Is the function supposed to be in a separate plugin file?
I also need help in getting the email to contain only the information relevant to the vendor it is being sent to.
Any assistance in getting this plugin to work would be greatly appreciated.
The filter new_order doesn't exist in WooCommerce (or in your code)
The correct filter hook (located in WC_Email class core code, line 269) is this one:
$recipient = apply_filters( 'woocommerce_email_recipient_' . $this->id, $this->recipient, $this->object );
In this hook, $this->id is 'new_order' for you.
There is big errors in your code:
The term name should be something like "one" or "chef-one", but absolutely not "pa_chef-one", as "pa_chef" is the taxonomy slug for your attribute "Chef".
The multiple email recipients are not in an array, but in a coma separated string.
So the correct code should be something like:
add_filter( 'woocommerce_email_recipient_new_order', 'add_recipient', 10, 2 );
function add_recipient( $recipient, $order )
{
if ( ! is_a( $order, 'WC_Order' ) ) return $recipient;
// Additional email recipient
$additional_email = "info#email.com";
// The term name "pa_chef-one" is very strange … It should be "one" or "chef-one" (may be)
$term_slug = "one";
$has_term = false;
// Iterating through each order item
foreach ($order->get_items() as $item_id => $item_obj) {
$variation_id = $item_obj->get_variation_id();
$variation_obj = wc_get_product($variation_id);
$variation_attributes = $variation_obj->get_attributes();
foreach( $variation_attributes as $taxonomy_key => $term_value ){
if( $taxonomy_key == "pa_chef" && $term_value == $term_slug ){
$recipient .= ','. $additional_email;
$has_term = true;
break; // stop the 2nd loop
}
}
if( $has_term ) break; // stop the 1st loop
}
return $recipient;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Made for WooCommerce version 3+
Similar answers:
Add the New order email notification attachment to the vendor email
Woocommerce email notification recipient conditionally based on custom field
WooCommerce email notifications: different email recipient for different cities

Adding a custom woocommerce email based on the product attribute

I have tried to adapt the custom email plugin found on https://www.skyverge.com/blog/how-to-add-a-custom-woocommerce-email/
My intention is that if customer choose a product (it is a variable product) that has a specific attribute, a custom email is sent when the customer makes a new order (it has to be sent either it is pending or processing).
My atribute slug is "csr-dates". The custom plugin is composed (see the link above) by two files: woocommerce-csr-order-email.php and (stored in "includes" folder) class-wc-csr-order-email.php
I guess that the problem is in the class file, which I report here:
<?php
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
/**
* A custom Order WooCommerce Email class
*
* #since 0.1
* #extends \WC_Email
*/
class WC_CSR_Order_Email extends WC_Email {
/**
* Set email defaults
*
* #since 0.1
*/
public function __construct() {
// set ID, this simply needs to be a unique name
$this->id = 'customer_csr_order';
$this->customer_email = true;
// this is the title in WooCommerce Email settings
$this->title = 'CSR Cruise Order';
// this is the description in WooCommerce email settings
$this->description = 'CSR Cruise Order Notification emails are sent when a customer places an order for a CSR cruise';
// these are the default heading and subject lines that can be overridden using the settings
$this->heading = 'CSR Cruise Order';
$this->subject = 'CSR Cruise Order';
// these define the locations of the templates that this email should use, we'll just use the new order template since this email is similar
$this->template_html = 'emails/customer-processing-order-csr.php'; //qui posso duplicare il template e farne uno ad hoc per questo tipo di mail con i file attached
$this->template_plain = 'emails/plain/customer-processing-order.php';
// Trigger on new paid orders
add_action( 'woocommerce_order_status_pending_to_processing_notification', array( $this, 'trigger' ) );
add_action( 'woocommerce_order_status_failed_to_processing_notification', array( $this, 'trigger' ) );
add_action( 'woocommerce_order_status_pending_to_on-hold_notification', array( $this, 'trigger' ) );
add_action( 'woocommerce_order_status_failed_to_on-hold_notification', array( $this, 'trigger' ) );
// Call parent constructor to load any other defaults not explicity defined here
parent::__construct();
// if none was entered, just use the WP admin email as a fallback
if ( ! $this->recipient )
$this->recipient = get_option( 'admin_email' );
}
/**
* Determine if the email should actually be sent and setup email merge variables
*
* #since 0.1
* #param int $order_id
*/
public function trigger( $order_id ) {
// bail if no order ID is present
if ( ! $order_id )
return;
$order = new WC_Order( $order_id );
//step 1) find first the product_id
$items = $order->get_items();
foreach ( $items as $item ) {
$product_id = $item['product_id'];
}
//set 2) from the product_id get the product attribute
$product = new WC_Product( $product_id ); // create an object of WC_Product class
$patt = $product->get_attribute(); // call get_attribute method
//step 3) condition valid to send the email (if the attributes is csr-dates)
if ( $patt == 'pa_csr-dates' )
{
//send the email
// setup order object
$this->object = new WC_Order( $order_id );
$this->recipient = $this->object->billing_email;
// replace variables in the subject/headings
$this->find[] = '{order_date}';
$this->replace[] = date_i18n( woocommerce_date_format(), strtotime( $this->object->order_date ) );
$this->find[] = '{order_number}';
$this->replace[] = $this->object->get_order_number();
if ( ! $this->is_enabled() || ! $this->get_recipient() )
return;
// woohoo, send the email!
$this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
}
else
{
return; //do nothing if is not csr-dates attribute
}
}
/**
* get_content_html function.
*
* #since 0.1
* #return string
*/
public function get_content_html() {
ob_start();
woocommerce_get_template( $this->template_html, array(
'order' => $this->object,
'email_heading' => $this->get_heading(),
'sent_to_admin' => false,
'plain_text' => false,
'email' => $this
) );
return ob_get_clean();
}
/**
* get_content_plain function.
*
* #since 0.1
* #return string
*/
public function get_content_plain() {
ob_start();
woocommerce_get_template( $this->template_plain, array(
'order' => $this->object,
'email_heading' => $this->get_heading(),
'sent_to_admin' => false,
'plain_text' => true,
'email' => $this
) );
return ob_get_clean();
}
/**
* Initialize Settings Form Fields
*
* #since 2.0
*/
public function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => 'Enable/Disable',
'type' => 'checkbox',
'label' => 'Enable this email notification',
'default' => 'yes'
),
'subject' => array(
'title' => 'Subject',
'type' => 'text',
'description' => sprintf( 'This controls the email subject line. Leave blank to use the default subject: <code>%s</code>.', $this->subject ),
'placeholder' => '',
'default' => ''
),
'heading' => array(
'title' => 'Email Heading',
'type' => 'text',
'description' => sprintf( __( 'This controls the main heading contained within the email notification. Leave blank to use the default heading: <code>%s</code>.' ), $this->heading ),
'placeholder' => '',
'default' => ''
),
'email_type' => array(
'title' => 'Email type',
'type' => 'select',
'description' => 'Choose which format of email to send.',
'default' => 'html',
'class' => 'email_type',
'options' => array(
'plain' => __( 'Plain text', 'woocommerce' ),
'html' => __( 'HTML', 'woocommerce' ),
'multipart' => __( 'Multipart', 'woocommerce' ),
)
)
);
}
} // end \WC_CSR_Order_Email class
I imagine that something is wrong in the code I wrote to get the attribute (step 1-2) and/or the condition to send the email (step 3).
Could somebody help me in solve this problem? Thank you
Instead of using get_attribute() function you should try to use get_attributes() this way:
//set 2) from the product_id get the product attribute
$product = new WC_Product( $product_id ); // create an object of WC_Product class
$patt = $product->get_attributes(); // call get_attributes method
//step 3) condition valid to send the email (if the attributes is csr-dates)
if ( array_key_exists('pa_csr-dates', $patt) )
{
Try it, this should work…

Attach uploaded file to email in WooCommerce

I'm currently developing a simple plugin which creates a custom order status and custom email - the email is sent when the order status changed from 'Pending' to 'Processing' as the point in my plugin is so that I can send an attachment that needs to be signed by the customer, after payment has been made.
Currently, the custom order status works and the email is sent but I cannot figure out how to upload the attachment to WooCommerce / WordPress and then attach that to the email itself.
My code is relatively simple and currently consists of just two files, which can be seen below:
woocommerce-legal-documents.php
<?php
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
/**
* Add a custom email to the list of emails WooCommerce should load
*
* #since 0.1
* #param array $email_classes available email classes
* #return array filtered available email classes
*/
function add_legal_documents_woocommerce_email( $email_classes ) {
// include our custom email class
require_once( 'includes/class-wc-legal-documents.php' );
// add the email class to the list of email classes that WooCommerce loads
$email_classes['WC_Legal_Documents_Email'] = new WC_Legal_Documents_Email();
return $email_classes;
}
add_filter( 'woocommerce_email_classes', 'add_legal_documents_woocommerce_email' );
/**
* Register new status
**/
function register_legal_documents_status() {
register_post_status( 'wc-legal', array(
'label' => 'Legal',
'public' => true,
'exclude_from_search' => false,
'show_in_admin_all_list' => true,
'show_in_admin_status_list' => true,
'label_count' => _n_noop( 'Legal <span class="count">(%s)</span>', 'Legal <span class="count">(%s)</span>' )
) );
}
add_action( 'init', 'register_legal_documents_status' );
// Add to list of WC Order statuses
function add_legal_to_order_statuses( $order_statuses ) {
$new_order_statuses = array();
// add new order status after processing
foreach ( $order_statuses as $key => $status ) {
$new_order_statuses[ $key ] = $status;
if ( 'wc-processing' === $key ) {
$new_order_statuses['wc-legal'] = 'Legal';
}
}
return $new_order_statuses;
}
add_filter( 'wc_order_statuses', 'add_legal_to_order_statuses' );
/**
* Adds icons for any custom order statuses
**/
add_action( 'wp_print_scripts', 'add_custom_order_status_icon' );
function add_custom_order_status_icon() {
if( ! is_admin() ) {
return;
}
?> <style>
/* Add custom status order icons */
.column-order_status mark.legal:after {
content: "\e004";
font-family: WooCommerce;
color: #ffba00;
font-weight: 400;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
margin: 0;
text-indent: 0;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
text-align: center;
}
/* Repeat for each different icon; tie to the correct status */
</style> <?php
}
//enqueues our external font awesome stylesheet
function enqueue_our_required_stylesheets(){
wp_enqueue_style('woocommerce-icons', 'includes/style.css');
}
add_action('wp_enqueue_scripts','enqueue_our_required_stylesheets');
includes/class-wc-legal-documents.php
<?php
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
/**
* A custom Expedited Order WooCommerce Email class
*
* #since 0.1
* #extends \WC_Email
*/
class WC_Legal_Documents_Email extends WC_Email {
/**
* Set email defaults
*
* #since 0.1
*/
public function __construct() {
// set ID, this simply needs to be a unique name
$this->id = 'wc_legal_documents';
// this is the title in WooCommerce Email settings
$this->title = 'Legal Documents';
// this is the description in WooCommerce email settings
$this->description = 'Legal Document email is sent to the customer with an attachment of the required document.';
// these are the default heading and subject lines that can be overridden using the settings
$this->heading = 'Legal Documents';
$this->subject = 'Legal Documents';
// default message to add to the email
//$this->message = '<p>Hello,<br><br> please see attached the legal documentation in which requires your attention.</p>';
// these define the locations of the templates that this email should use, we'll just use the new order template since this email is similar
$this->template_html = 'emails/customer-invoice.php';
$this->template_plain = 'emails/plain/customer-invoice.php';
// Trigger on new paid orders
add_action( 'woocommerce_order_status_pending_to_processing_notification', array( $this, 'trigger' ) );
add_action( 'woocommerce_order_status_failed_to_processing_notification', array( $this, 'trigger' ) );
// Add message
add_action( 'woocommerce_email_before_order_table', array( $this, 'add_order_email_instructions' ) );
// Call parent constructor to load any other defaults not explicity defined here
parent::__construct();
// this gets the email attachments
$this->attachment = $this->get_option( 'attachment' );
// this gets the email message
$this->message = $this->get_option( 'message' );
}
public function add_order_email_instructions( $order, $sent_to_admin ) {
if ( ! $sent_to_admin ) {
//echo '<p><strong>Instructions:</strong> Full payment is due immediately upon delivery: <em>cash only, no exceptions</em>.</p>';
echo $this->message;
}
}
/**
* Determine if the email should actually be sent and setup email merge variables
*
* #since 0.1
* #param int $order_id
*/
public function trigger( $order_id ) {
// bail if no order ID is present
if ( ! $order_id )
return;
// setup order object
$this->object = new WC_Order( $order_id );
$this->recipient = $this->object->billing_email;
$this->object->update_status('wc-legal');
// woohoo, send the email!
$this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
}
/**
* get_content_html function.
*
* #since 0.1
* #return string
*/
public function get_content_html() {
ob_start();
woocommerce_get_template( $this->template_html, array(
'order' => $this->object,
'email_heading' => $this->get_heading()
) );
return ob_get_clean();
}
/**
* get_content_plain function.
*
* #since 0.1
* #return string
*/
public function get_content_plain() {
ob_start();
woocommerce_get_template( $this->template_plain, array(
'order' => $this->object,
'email_heading' => $this->get_heading()
) );
return ob_get_clean();
}
/**
* Initialize Settings Form Fields
*
* #since 2.0
*/
public function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => 'Enable/Disable',
'type' => 'checkbox',
'label' => 'Enable this email notification',
'default' => 'yes'
),
'subject' => array(
'title' => 'Subject',
'type' => 'text',
'description' => sprintf( 'This controls the email subject line. Leave blank to use the default subject: <code>%s</code>.', $this->subject ),
'placeholder' => '',
'default' => ''
),
'heading' => array(
'title' => 'Email Heading',
'type' => 'text',
'description' => sprintf( __( 'This controls the main heading contained within the email notification. Leave blank to use the default heading: <code>%s</code>.' ), $this->heading ),
'placeholder' => '',
'default' => ''
),
'message' => array(
'title' => 'Message',
'type' => 'textarea',
'description' => 'Add a custom message to the customer.',
'placeholder' => '',
'default' => ''
),
'attachment' => array(
'title' => 'Attachment',
'type' => 'file',
'description' => 'Select the legal document to be sent as an attachment in the email.',
'placeholder' => '',
'default' => ''
),
'email_type' => array(
'title' => 'Email type',
'type' => 'select',
'description' => 'Choose which format of email to send.',
'default' => 'html',
'class' => 'email_type',
'options' => array(
'plain' => __( 'Plain text', 'woocommerce' ),
'html' => __( 'HTML', 'woocommerce' ),
'multipart' => __( 'Multipart', 'woocommerce' ),
)
)
);
}
} // end \WC_Expedited_Order_Email class
Also, the custom message is added to all emails that are sent out but I only need it to be added to this email but I have not been able to find a way of doing this yet - any help would be greatly appreciated.

Categories