wp_mail重复自定义标头丢失:如何无需修改原函数解决?
解决wp_mail()重复自定义标头被覆盖的问题
嘿,这个坑我之前踩过!确实,wp_mail()在处理自定义标头时,会把它们转换成关联数组来处理——这就导致如果多次传递相同名称的标头,后面的会直接覆盖前面的,最后只留下最后一个实例。不过完全不用修改核心的pluggable.php文件,咱们有几个灵活的解决方案:
方法1:直接用PHPMailer的addCustomHeader方法(最推荐)
WordPress的wp_mail底层是用PHPMailer实现的,我们可以通过phpmailer_init动作钩子,在邮件发送前直接操作PHPMailer实例,手动添加多个相同的标头,完全绕开wp_mail的关联数组限制。
举个实际的例子:
// 先定义一个全局变量用来临时存储要添加的标头(如果需要多次收集的话) $pending_custom_headers = []; // 自定义函数,用来收集要添加的标头 function add_multi_mail_header($header_name, $header_value) { global $pending_custom_headers; $pending_custom_headers[] = [$header_name, $header_value]; } // 绑定phpmailer_init钩子,在邮件发送前批量添加标头 add_action('phpmailer_init', function($phpmailer) { global $pending_custom_headers; foreach ($pending_custom_headers as $header) { list($name, $value) = $header; // PHPMailer的addCustomHeader支持重复添加同名标头 $phpmailer->addCustomHeader($name, $value); } // 清空临时变量,避免影响下一次邮件发送 $pending_custom_headers = []; }); // 现在你可以自由添加多个同名标头,然后发送邮件 add_multi_mail_header('X-Tracking-ID', 'user_123'); add_multi_mail_header('X-Tracking-ID', 'campaign_456'); wp_mail('user@example.com', '测试邮件', '这是一封带多个自定义标头的邮件');
这样发送出去的邮件里,就会同时存在两个X-Tracking-ID标头,不会被覆盖。
如果是单次发送邮件需要添加多个标头,也可以直接在调用wp_mail前临时绑定钩子:
// 定义添加标头的命名函数(方便后续移除) function add_specific_headers($phpmailer) { $phpmailer->addCustomHeader('X-Custom-1', 'ValueA'); $phpmailer->addCustomHeader('X-Custom-1', 'ValueB'); } // 绑定钩子 add_action('phpmailer_init', 'add_specific_headers'); // 发送邮件 wp_mail('user@example.com', '单次测试', '内容'); // 移除钩子,避免影响其他邮件 remove_action('phpmailer_init', 'add_specific_headers');
方法2:通过wp_mail过滤器修改标头处理逻辑
如果你更习惯用wp_mail自带的$headers参数传递标头,可以通过wp_mail过滤器,把重复的标头从关联数组转成可重复的字符串格式:
add_filter('wp_mail', function($mail_atts) { $headers = $mail_atts['headers']; $processed = []; // 先把字符串格式的标头转成数组 if (is_string($headers)) { $headers = explode("\n", str_replace("\r\n", "\n", $headers)); } if (is_array($headers)) { foreach ($headers as $key => $val) { // 处理数字索引的标头行(比如"X-Header: 值") if (is_numeric($key)) { list($header_name, $header_value) = explode(':', $val, 2); $header_name = trim($header_name); $header_value = trim($header_value); $processed[$header_name][] = $header_value; } else { // 处理关联数组格式的标头 $processed[$key][] = $val; } } // 把处理后的标头转成多个独立的标头行 $new_headers = []; foreach ($processed as $name => $values) { foreach ($values as $v) { $new_headers[] = "$name: $v"; } } $mail_atts['headers'] = $new_headers; } return $mail_atts; });
使用的时候,要注意不要用关联数组传递重复标头(因为PHP本身会覆盖关联数组的重复键),而是用字符串格式的标头行:
$headers = [ 'X-Custom-Header: 第一个值', 'X-Custom-Header: 第二个值', ]; wp_mail('user@example.com', '测试过滤后的标头', '内容', $headers);
这样过滤器会把这两个标头都保留下来,不会被wp_mail的关联数组逻辑覆盖。
内容的提问来源于stack exchange,提问作者bicarlsen
相关产品推荐
相关产品推荐

