WooCommerce的邮件发送逻辑历经版本已经发生了很多变化,所以决定更新这篇过时的文章,记录一下WooCommerce 7.8.1里发送邮件的逻辑,以及如何用代码发送任意邮件,如何延迟邮件的发送。
目录
WooCommerce邮件发送过程
用【文件名+相关代码】的方式描述,以order complete订单为例,代码都可以在对应文件里找到。
(A) class-wc-order.php
- $order->save()
- $this->status_transition()
- do_action( ‘woocommerce_order_status_’ . $status_transition[‘to’], $this->get_id(), $this );
(B) class-woocommerce.php
- add_action( ‘init’, array( ‘WC_Emails’, ‘init_transactional_emails’ ) );
(C) class-wc-emails.php
- do_action( $action, array( __CLASS__, ‘send_transactional_email’ ), 10, 10 );
- do_action_ref_array( current_filter() . ‘_notification’, $args );
(D) class-wc-email-customer-completed-order.php
- add_action( ‘woocommerce_order_status_completed_notification’, array( $this, ‘trigger’ ), 10, 2 );
文字版描述:
(A) 当用户保存订单、通过REST API保存订单或用代码保存订单($order->save())时,执行status_transition()
函数,该函数会对比订单之前的状态和更新后的状态,比如更新前是pending,更新后是completed,就执行do_action('woocommerce_order_status_completed',$order_id, $order)
,把订单完成这个状态广播给所有订阅了它的组件。
(B)init_transactional_emails()
是class-wc-emails.php
里定义的函数,负责维护一个$email_actions数组,它记录了所有email需要关注的actions,然后通过add_action来订阅这些action的变化,当变化发生时,通过函数send_transactional_email()
或queue_transactional_email()
来做对应处理。
(C)调用send_transactional_email()
函数,用当前的action名称创建一个新的action,叫woocommerce_order_status_completed_notification
,负责发送email的组件订阅可以订阅它,这样当这个action触发时,email组件就知道自己要发邮件了。
(D)最后来到负责发送order complete邮件的组件,它接收到woocommerce_order_status_completed_notification
这个action的通知后,就调用自己的trigger()方法,这个方法最终调用WC_Email的send()
函数发送邮件。
如何用程序发送WC Order Complete邮件
只需要用对应的组件发送即可,例如定义一个发送order complete邮件的函数,并以order ID作为参数
function send_order_complete_email($order_id) {
add_filter('woocommerce_email_enabled_customer_completed_order', '__return_true');
$email_oc = new WC_Email_Customer_Completed_Order();
$email_oc->trigger($order_id);
}
第一句add_filter是保证即使后台关闭了这封邮件,也可以发送,因为trigger()函数只在后台开启了对应邮件时才能发送。这个filter定义在class-wc-email.php
的is_enabled()
函数里。
其他关于邮件的代码段
发送一封WC风格的自定义邮件,参数分别为:收件人地址,邮件标题,WooCommerce邮件header里的标题,邮件正文。
function send_email_woocommerce_style($email, $subject, $heading, $message) {
// Get woocommerce mailer from instance
$mailer = WC()->mailer();
// Wrap message using woocommerce html email template
$wrapped_message = $mailer->wrap_message($heading, $message);
// Create new WC_Email instance
$wc_email = new WC_Email;
// Style the wrapped message with woocommerce inline styles
$html_message = $wc_email->style_inline($wrapped_message);
// Send the email using wordpress mail function
$mailer->send($email, $subject, $html_message, $wc_email->get_headers());
}
列出所有woocommerce emails
function list_woocommerce_emails(){
$mailer = WC()->mailer();
$mails = $mailer->get_emails();
foreach($mails as $mail ){
echo esc_html($mail->title), '<br>';
}
}
延迟发送WooCommerce Order Complete邮件
1.
WooCommerce支持及时发送邮件或者延时发送,用户结算后需要等待邮件发送成功才能到达thank you页面,如果邮件发的慢就会影响用户体验,使用延时发送可以解决这个问题,只需要一行代码。
add_filter( 'woocommerce_defer_transactional_emails', '__return_true' );
2.
如果你想让不同邮件有不同的延时时间,参考这篇文章
。
3.
下面这个例子是将order complete邮件延迟两分钟发送,使用WooCommerce Action Scheduler,和2的区别是没有使用WC的延时系统,只是取消了默认的邮件发送,再在适当的时候手动发送邮件。
class Defer_WooCommerce_Order_Completed_Email {
private static $instance;
private $default_defer_time;
public static function get_instance() {
if (null == self::$instance) {
self::$instance = new Defer_WooCommerce_Order_Completed_Email();
}
return self::$instance;
}
public function __construct() {
$this->default_defer_time = 120; // 延迟120s,2分钟
add_filter('woocommerce_email_enabled_customer_completed_order', '__return_false');
add_action('woocommerce_order_status_completed_notification', [$this, 'schedule_email'], 10, 2);
add_action('send_deferred_order_completed_email', [$this, 'send_email']);
}
function schedule_email($order_id, $order = false) {
$event_id = as_schedule_single_action(time() + $this->default_defer_time, 'send_deferred_order_completed_email', array($order_id));
}
function send_email($order_id) {
add_filter('woocommerce_email_enabled_customer_completed_order', '__return_true');
WC()->mailer()->emails['WC_Email_Customer_Completed_Order']->trigger( $order_id );
}
}
new Defer_WooCommerce_Order_Completed_Email();
用WC REST API更改订单状态
测试订单邮件时使用REST API更改订单状态也是很方便的,方法也很简单。
- 打开WooCommerce->Settings->Advanced->REST API,点击Add Key并填入内容,权限选择Read/Write,这样就创建了一个有读写权限的API用户,创建好把用户名和密码(Consumer key & Consumer secret)记录下来。
- 从WC REST API文档中找到Update an Order,从中获得rest api地址,
/wp-json/wc/v3/orders/<id>
- 打开Postman,先打开Authorization选项卡,Type选择Basic Auth,然后填上刚才创建的用户名和密码。
- 在Postman地址栏输入REST API地址,方法选择PUT,Params里天上
{"status":"completed"}
,点击Send发送请求,就能将订单状态更新成completed。
用python更新订单状态
import requests
import base64
wordpress_user = "ck_29990e5f3e3053a727a75f9c1bcd7420b764d62e"
wordpress_password = "cs_b4c1c3eaf8ff36102bac0e425afbbd6971097c56"
rest_base = 'https://testwc.local/wp-json';
wordpress_credentials = wordpress_user + ":" + wordpress_password
wordpress_token = base64.b64encode(wordpress_credentials.encode())
wordpress_header = {'Authorization': 'Basic ' + wordpress_token.decode('utf-8')}
def update_wc_order(order_id, data):
api_url = f'{rest_base}/wc/v3/orders/{order_id}'
r = requests.put(api_url,headers=wordpress_header, json=data)
return r.json()
if __name__ == '__main__':
update_wc_order(65, {
'status': 'processing'
})
可以用VS Code快速开始一个python项目,步骤如下,参考https://code.visualstudio.com/docs/python/python-tutorial
- 保证系统安装了python。
- 用VS Code打开一个文件夹,快捷键Ctrl+Shift+P打开命令面板,输入Python: Create Environment,选择虚拟环境venv,再根据提示选择解释器。
- 创建一个python文件,例如order.py,将代码拷贝进去。
- 安装需要的模块,运行命令
pip install requests
,最后运行文件即可。
不知道博主还在不,想问一个问题,就是我的woo在用户使用paypal支付成功以后,订单状态还是不变,依旧是未支付,要手动去改变才行
paypal的状态需要通过接受伊布通知来实现,可能是你服务器配置有问题,或者拦截了来自paypal的请求。
去woocommerce的系统工具里看看,里面会显示必须安装的服务是否装了,如果没有装全就用不了paypal。
/?add-to-cart=28 是添加 ID 为 28 的商品到购物车的URL参数,那么能否同时添加两个商品呢?比如 ID 为 28 和 26 的这两个商品。
半年多没更新了,去哪了,呵呵。
掉线了…
欢迎回来,好久不见更新了
朋友,交换链接吗?
不换啦,暂时没时间经营
年纪越大,越是没有精力折腾网站了
博主不会属猪吧
不是
都喜欢养宠物猪吗
新年快乐!博主我想问一下在文章内的图片实现幻灯要怎么弄。
建议直接使用插件实现,slider插件非常多,可以根据自己需求选择简洁轻巧的或者功能复杂的。
https://premium.wpmudev.org/blog/free-responsive-slider-plugins/
高大上的akamai cdn 路過,zhu.vn
哈哈哈
网址不小心输成zhu.kr结果还是你,冰天雪地神豬一枚是你家猪吗,都长这么霸气了!
別家的。不是我的哈哈
嗯,在群里看了看这只猪你发了好多次,真是霸气侧漏。我家猪跟他比太瘦了,我得多喂喂,猪还是肥肥的好看。
快給多喂喂哈哈。我的公豬就不肥,估計沒閹割的過,大把力氣跑。
sola,请问您的网站都做了哪些有话?比如,缓存插件/CDN等优化细节,呵呵,多谢
我装了wp super cache和Autoptimize,别的就没有了。
cache效果肯定很好,但还有一个提速很明显的的设置是Autoptimize的Inline and Defer CSS” Option。具体介绍可以看
https://www.solagirl.net/optimize-website-speed-with-autoptimize.html
用了Autoptimize不能開啟javascript啊,一開驗證碼就出不來了。
嗯,使用minify插件时很容易出这个问题,因为压缩后可能更改js脚本加载顺序,导致某些脚本无法工作。
可以试试把验证码相关的脚本从minify里排除,可能就好了。