Attach uploaded file to email in WooCommerce - php

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.

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 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…

WooCommerce - send custom email on custom order status change

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.

Woocommerce Refund Email

I have done a vast amount of searching and although I have found users that have asked how to achieve the following no examples of working solutions to the best of my knowledge exist.
The question is regarding the very popular Wordpress plugin "Woocommerce". The plugin comes with an email system to make life easier for the ecommerce site owner and the customer. One issue is that there is no email that is sent when a shop manager changes the order status to "Refunded". Someone has said this is because it is a manual process. This is true it is a process that the shop owner would do via there merchant account or paypal account. But once this is done and the shop owner then logs into their wordpress admin panel and changes an order status to Refunded it would be beneficial for an email to be generated and sent the customer.
This is something I've seen requested.
So I decided to modify a tutorial over at
http://www.skyverge.com/blog/how-to-add-a-custom-woocommerce-email/#comment-553147
I am trying to have an email sent out when an orders order status is updated to "Refunded".
Here is the code to the initial plugin file
<?php
/**
* Plugin Name: WooCommerce Custom Expedited Order Email
* Plugin URI: http://www.skyverge.com/blog/how-to-add-a-custom-woocommerce-email/
* Description: Demo plugin for adding a custom WooCommerce email that sends admins an email when an order is received with expedited shipping
* Author: SkyVerge
* Author URI: http://www.skyverge.com
* Version: 0.1
*
* License: GNU General Public License v3.0
* License URI: http://www.gnu.org/licenses/gpl-3.0.html
*
*/
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_expedited_order_woocommerce_email( $email_classes ) {
// include our custom email class
require( 'includes/class-wc-expedited-order-email.php' );
// add the email class to the list of email classes that WooCommerce loads
$email_classes['WC_Expedited_Order_Email'] = new WC_Expedited_Order_Email();
return $email_classes;
}
add_filter( 'woocommerce_email_classes', 'add_expedited_order_woocommerce_email' );
And here is a link to the code of my class
<?php
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
/**
* A custom Expedited Order WooCommerce Email class
*
* #since 0.1
* #extends \WC_Email
*/
class WC_Expedited_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_expedited_order';
// this is the title in WooCommerce Email settings
$this->title = 'Refunded Order Email';
// this is the description in WooCommerce email settings
$this->description = 'Refunded Emails are sent when an order status has been changed to Refunded';
// these are the default heading and subject lines that can be overridden using the settings
$this->heading = 'Refunded Order';
$this->subject = 'Refunded 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 );
//bail if not a refunded order
if ( 'refunded' !== $order->status ) {
return;
}
// setup order object
$this->object = new WC_Order( $order_id );
// bail if shipping method is not expedited
//if ( ! in_array( $this->object->get_shipping_method(), array( 'Three Day Shipping', 'Next Day Shipping' ) ) )
//return;
// 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() );
}
/**
* 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 0.1
*/
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',
'html' => 'HTML', 'woocommerce',
'multipart' => 'Multipart', 'woocommerce',
)
)
);
}
} // end \WC_Expedited_Order_Email class
These are the only 2 files in my plugin. I have activated it and it appears as an email in the list of emails in the woo commerce email tab. Unfortunately no email is sent when the order status is updated.
Can anyone advise why this is failing to work?
I have had some feedback of an individual who said the following
"the actions that you're adding the trigger to are for pending/failed to processing order status changes - http://cld.wthms.co/cZzw
You'd want these to be actions that are related to the refunded orders, like: add_action( 'woocommerce_order_status_refunded', array( $this, 'trigger' ) ); (for the exact one look around woocommerce's email classes)"
I am using Woocommerce 2.1.12
The main problem is that the woocommerce_order_status_refunded hook is not registered by default with the send_transactional_email callback, so you can't use the above method to send emails automatically when the order status is changed to Refunded.
You can change that with the following:
/**
* Register the "woocommerce_order_status_refunded" hook which is necessary to
* allow automatic email notifications when the order is changed to refunded.
*
* #see http://stackoverflow.com/a/26413223/2078474
*/
add_action( 'woocommerce_init', function() {
add_action(
'woocommerce_order_status_refunded',
array( WC(), 'send_transactional_email' ),
10,
10
);
});
Also make sure that you have enable it in the corresponding section in the Woo Settings -> Emails tab:
By default the following actions are registered for automatic email notifications:
woocommerce_low_stock
woocommerce_no_stock
woocommerce_product_on_backorder
woocommerce_order_status_pending_to_processing
woocommerce_order_status_pending_to_completed
woocommerce_order_status_pending_to_on-hold
woocommerce_order_status_failed_to_processing
woocommerce_order_status_failed_to_completed
woocommerce_order_status_completed
woocommerce_new_customer_note
woocommerce_created_customer
Update:
Good news, #helgatheviking just got her WooCommerce pull request merged (see the comments below).
This means we should be able to use the new woocommerce_email_actions filter:
add_filter( 'woocommerce_email_actions', function( $email_actions ) {
$email_actions[] = 'woocommerce_order_status_refunded';
return $email_actions;
});
in WooCommerce 2.3+.
Similar should work for other non-default email actions, like woocommerce_order_status_cancelled.
I think the problem is you are calling
add_action( 'woocommerce_order_status_pending_to_processing_notification', array( $this, 'trigger' ) );
Try calling:
add_action( 'woocommerce_order_status_refunded', array( $this, 'trigger' ) );

Categories