哀悼默认值全部改为不勾选 - 九个纪念日的 default 全改成 0。之前法定那三个是 1,导致全新安装的站点 一到日子就自己变黑白,而站主根本没同意过这件事。 - 后台多选组件的 std 全为 0,打开设置页一个都不勾。 - 「从未保存过」与「保存过但全不勾」两条路径都返回空数组, 不能因为结果为空就回退到默认 —— 那等于用户取消勾选无效。 新增彩色说明页(inc/theme-mourning-page.php + pages/page-mourning.php) - 站点变黑白后必须有个地方解释清楚,否则访客只看到一片灰、以为站点坏了。 - 三处入口:顶部提示条(wp_body_open,首屏可见)、页脚常驻链接、 [yang_mourning] 短代码。 - 页面内容由真实配置驱动,不是写死的文案:没勾的日期不会出现, 今天在列表里带「今天」标记,一个都没勾时明说「不会生效」。 - 页面必须保持彩色,否则解释「为什么是灰的」的页面自己也是灰的。 取消灰度做了两层:filter:none 与 grayscale(0%) 都写,且带 !important; 优先级放在 wp_head 的 2,晚于灰度样式的 1。 - 路由走 parse_request 优先级 5 而非 template_redirect: 避免先走一遍 404 判定与 404 模板。带子目录安装时先剥掉前缀再比对。 - 不抢占用户自己建的页面:如果站里已有同名 slug 的页面就放手。 否则用户会觉得「我建的页面坏了」,且没有任何提示。 邮件不受影响,且回复邮件同时给出双方内容 - 邮件是独立 HTML,不走 wp_head,结构上就不可能被灰度,已断言验证。 - theme-mail-template 的单个 quote 改成 quotes 列表,一个模板同时渲染 「被回复的那条」与「新的回复」,最后一块用主色高亮(回复是重点), 前面的用弱化色。只有一块时退化为主色,与旧行为一致。 - 通过 wpdiscuz_email_content 重建整封邮件,不需要改插件。 审核通过通知用 wpdiscuz_comment_approved_email_content 走同一模板, 但它只给 post_id、不给评论对象,能放的内容受此限制。 两个必须记下来的坑 - wpDiscuz 在过滤器之后还会做一次 html_entity_decode 再发信。 esc_html 的输出会被那一步还原成真标签,评论里的 <script> 直接生效。 所以返回前先把 & 编码一次。本地 stub 没有这一步,测试看不出来。 - header.php 从来没有调用 wp_body_open,挂在上面的东西全部静默失效。 不调用不会报错,只会「什么都没发生」。已补在 <body> 之后。 yang_mail_text 保留换行 - 原来用 wp_strip_all_tags($t, true),第二个参数 remove_breaks 会把换行 压成空格;而 strip_tags 遇到 <br> 是直接删掉不补换行的。 结果整条评论被拍成一行,模板里的 nl2br 成了死代码。 - 改为先把块级边界降级成 \n,再去标签(remove_breaks=false)。 收行内空白用 [^\S\n] 而不是 [ \t\f\v]:PCRE 的 \v 是垂直空白类, 会把 \n 一起匹配掉。 说明页对比度修正(WCAG AA) - 金色 #b8860b 在白底只有 3.06:1,当装饰色没问题,当 12-15px 文字偏虚。 拆成 --ym-gold(装饰)与 --ym-gold-text(#946600,4.75:1,仍属金色)。 - 分组小标题 #9aa5b1 只有 2.36:1,改用 #5f6b78(5.12:1)。 - 「今天」标签白字压金底 3.25:1,改用 #8a6100(5.54:1)。
423 lines
18 KiB
PHP
423 lines
18 KiB
PHP
<?php
|
||
/**
|
||
* 邮件模板渲染
|
||
*
|
||
* 设计约束(写这套模板的全部理由):
|
||
*
|
||
* 1. **必须是表格布局**。Outlook 2007-2019 用 Word 的排版引擎,完全不支持
|
||
* flex / grid,连 `max-width` 都不稳。只有 `<table>` + `cellpadding` 在老
|
||
* Outlook 里可靠。现在的 web 布局写法在邮件里必崩。
|
||
*
|
||
* 2. **样式必须内联**。Gmail 会把 `<head>` 里的 `<style>` 全部剥掉(含 media query),
|
||
* QQ 邮箱、网易邮箱同样。所以每个 `td` 都要带 `style="..."`,不能依赖 class。
|
||
*
|
||
* 3. **宽度 600px**。这是邮件客户端预览窗格的通用安全宽度。用
|
||
* `width="600"` 属性 + `style="width:600px;max-width:600px"` 双保险。
|
||
*
|
||
* 4. **不用外部图片做装饰**。邮件里的外链图默认被 Gmail / QQ 邮箱屏蔽,
|
||
* 用户看到的是一堆灰框。所有视觉元素用纯色块 + 圆角 + 文字实现。
|
||
*
|
||
* 5. **不用 CSS 变量**。邮件客户端不支持,写了就是丢失样式。
|
||
*
|
||
* 6. 深色模式:Android Gmail / Apple Mail 会反色。这里显式声明
|
||
* `color-scheme` 与 `supported-color-schemes`,并避免纯黑纯白。
|
||
*
|
||
* @author Yongquan Yang <yangyq.net>
|
||
* @license MIT License
|
||
*/
|
||
|
||
if (!defined('ABSPATH')) {
|
||
exit;
|
||
}
|
||
|
||
/**
|
||
* 站点主色(可被选项覆盖)
|
||
*
|
||
* 取主题的主色选项;取不到就用一个稳妥的深蓝灰。
|
||
* 不用亮色,因为邮件背景是浅灰,亮色正文对比度不够。
|
||
*/
|
||
function yang_mail_brand_color()
|
||
{
|
||
$c = kratos_option('top_color', '#24292e');
|
||
if (!preg_match('/^#[0-9a-fA-F]{6}$/', (string) $c)) {
|
||
$c = '#24292e';
|
||
}
|
||
return $c;
|
||
}
|
||
|
||
/**
|
||
* 把主色调暗一档,用作渐变末端 / 描边
|
||
*
|
||
* 邮件里不能用 `filter: brightness()`(不支持),只能算。
|
||
*/
|
||
function yang_mail_shade($hex, $ratio = 0.82)
|
||
{
|
||
$hex = ltrim($hex, '#');
|
||
if (strlen($hex) !== 6) {
|
||
return '#24292e';
|
||
}
|
||
$out = '#';
|
||
foreach (str_split($hex, 2) as $pair) {
|
||
$v = max(0, min(255, (int) round(hexdec($pair) * $ratio)));
|
||
$out .= str_pad(dechex($v), 2, '0', STR_PAD_LEFT);
|
||
}
|
||
return $out;
|
||
}
|
||
|
||
/**
|
||
* 判断一个颜色是深是浅,决定叠在上面的文字用白还是深色
|
||
*
|
||
* 用相对亮度公式(WCAG),不是简单取平均 —— 人眼对绿最敏感、蓝最不敏感,
|
||
* 直接平均会把 #00ff00 判成中等亮度。
|
||
*/
|
||
function yang_mail_is_dark($hex)
|
||
{
|
||
$hex = ltrim((string) $hex, '#');
|
||
if (strlen($hex) !== 6) {
|
||
return true;
|
||
}
|
||
$r = hexdec(substr($hex, 0, 2)) / 255;
|
||
$g = hexdec(substr($hex, 2, 2)) / 255;
|
||
$b = hexdec(substr($hex, 4, 2)) / 255;
|
||
$lin = function ($c) {
|
||
return $c <= 0.03928 ? $c / 12.92 : pow(($c + 0.055) / 1.055, 2.4);
|
||
};
|
||
$L = 0.2126 * $lin($r) + 0.7152 * $lin($g) + 0.0722 * $lin($b);
|
||
return $L < 0.5;
|
||
}
|
||
|
||
/**
|
||
* 把可能含 HTML 的片段转成邮件安全的纯文本(保留换行)
|
||
*
|
||
* 邮件正文里塞用户提交的评论内容,必须防注入:邮件客户端也会执行
|
||
* `<script>`(部分 webmail 会),而且一旦渲染出畸形 HTML,整封邮件布局就崩。
|
||
*
|
||
* ── 换行为什么要专门处理 ─────────────────────────────────────
|
||
* 两个坑都会把整条评论拍成一行:
|
||
* 1. `wp_strip_all_tags($x, true)` 的第二个参数是 remove_breaks,
|
||
* 真实实现里会 `preg_replace('/[\r\n\t ]+/', ' ', $x)` —— 换行直接没了。
|
||
* 所以这里必须传 false。
|
||
* 2. `strip_tags()` 遇到 `<br>` 是**直接删掉、不补换行**的,`</p>` 同理。
|
||
* 评论里手写的换行和段落因此在去标签阶段就无痕消失。
|
||
* 结论:先把块级边界换成 `\n`,再去标签,最后才收拾空白。
|
||
* 这样模板里的 `nl2br()` 才有换行可转,不是一段死代码。
|
||
*/
|
||
function yang_mail_text($html, $limit = 0)
|
||
{
|
||
$t = (string) $html;
|
||
// 1. 先把"视觉上的换行"降级成真正的 \n
|
||
$t = preg_replace('@<br\s*/?>@i', "\n", $t);
|
||
$t = preg_replace('@</(p|div|blockquote|pre|h[1-6])\s*>@i', "\n", $t);
|
||
// <li> 自己带前缀,就不要</li>再加换行,否则列表每项之间会多一个空行
|
||
$t = preg_replace('@<li[^>]*>@i', "\n- ", $t);
|
||
// 2. 去标签,但不要 remove_breaks(那是换行消失的真正原因)
|
||
$t = wp_strip_all_tags($t, false);
|
||
// 3. 收拾空白:行内空白收成一个空格,换行保留,最多一个空行
|
||
$t = html_entity_decode($t, ENT_QUOTES, 'UTF-8');
|
||
$t = str_replace(array("\r\n", "\r"), "\n", $t);
|
||
/* 用 [^\S\n]("非空白"取反 + 排除换行 = 除换行外的空白)而不是
|
||
[ \t\f\v]:PCRE 里 \v 是**垂直空白类**,把 \n 也算进去,
|
||
写成 [ \t\f\v] 会连换行一起替换成空格 —— 而且只在带 /u 时表现如此,
|
||
极易漏看。语义直接写出来,别依赖转义字母的记忆。 */
|
||
$t = preg_replace('/[^\S\n]+/u', ' ', $t);
|
||
$t = preg_replace('/ *\n */u', "\n", $t);
|
||
$t = preg_replace('/\n{3,}/u', "\n\n", $t);
|
||
$t = trim($t);
|
||
if ($limit > 0 && mb_strlen($t, 'UTF-8') > $limit) {
|
||
$t = mb_substr($t, 0, $limit, 'UTF-8') . '…';
|
||
}
|
||
return $t;
|
||
}
|
||
|
||
/**
|
||
* 把主色与白色按比例混合,得到一档浅色
|
||
*
|
||
* 为什么不用 rgba:Outlook(Word 引擎)完全不支持 rgba(),
|
||
* 写了会当成非法值丢弃 ⇒ 半透明背景变成完全透明,badge 直接"消失"。
|
||
* 所以这里预先算出实色。$ratio 是白色的占比(0=纯主色,1=纯白)。
|
||
*/
|
||
function yang_mail_tint($hex, $ratio = 0.18, $onto = '#ffffff')
|
||
{
|
||
$hex = ltrim((string) $hex, '#');
|
||
$onto = ltrim((string) $onto, '#');
|
||
if (strlen($hex) !== 6 || strlen($onto) !== 6) {
|
||
return '#ffffff';
|
||
}
|
||
$out = '#';
|
||
for ($i = 0; $i < 3; $i++) {
|
||
$a = hexdec(substr($hex, $i * 2, 2));
|
||
$b = hexdec(substr($onto, $i * 2, 2));
|
||
$v = (int) round($a + ($b - $a) * $ratio);
|
||
$out .= str_pad(dechex(max(0, min(255, $v))), 2, '0', STR_PAD_LEFT);
|
||
}
|
||
return $out;
|
||
}
|
||
|
||
/**
|
||
* 生成一个按钮(邮件里的按钮只能用表格单元格做,不能用 <button>)
|
||
*
|
||
* Outlook 不认 `<a>` 的 `padding`,必须把 padding 放在 `<td>` 上。
|
||
*/
|
||
function yang_mail_button($text, $url, $bg = null)
|
||
{
|
||
if ($bg === null) {
|
||
$bg = yang_mail_brand_color();
|
||
}
|
||
$fg = yang_mail_is_dark($bg) ? '#ffffff' : '#1a1a1a';
|
||
$url = esc_url($url);
|
||
$text = esc_html($text);
|
||
return '<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="margin:0 auto;">'
|
||
. '<tr><td align="center" bgcolor="' . esc_attr($bg) . '" style="border-radius:6px;padding:13px 34px;">'
|
||
. '<a href="' . $url . '" target="_blank" rel="noopener" '
|
||
. 'style="display:inline-block;font-family:-apple-system,BlinkMacSystemFont,\'Segoe UI\',Roboto,\'Helvetica Neue\',Arial,\'PingFang SC\',\'Microsoft YaHei\',sans-serif;'
|
||
. 'font-size:15px;font-weight:600;line-height:1;color:' . $fg . ';text-decoration:none;letter-spacing:0.3px;">'
|
||
. $text . '</a></td></tr></table>';
|
||
}
|
||
|
||
/**
|
||
* 渲染整封邮件
|
||
*
|
||
* @param array $args {
|
||
* @type string $title 邮件主标题(收件箱预览也会看到)
|
||
* @type string $preheader 预读文字,显示在收件箱标题后面,不影响正文
|
||
* @type string $heading 正文第一行大字
|
||
* @type string $intro 正文引导段落(纯文本)
|
||
* @type array $rows 表格数据,每项 array('label'=>, 'value'=>, 'strong'=>bool)
|
||
* @type array $quote 引用块 array('label'=>, 'content'=>, 'meta'=>)
|
||
* @type string $cta_text 按钮文字
|
||
* @type string $cta_url 按钮链接
|
||
* @type string $note 底部提示(纯文本)
|
||
* @type string $badge 顶部小标签,如「新评论」
|
||
* }
|
||
* @return string 完整 HTML
|
||
*/
|
||
function yang_mail_render($args)
|
||
{
|
||
$d = wp_parse_args($args, array(
|
||
'title' => get_bloginfo('name'),
|
||
'preheader' => '',
|
||
'heading' => '',
|
||
'intro' => '',
|
||
'rows' => array(),
|
||
'quote' => array(), // 单个引用块(旧接口,保留兼容)
|
||
'quotes' => array(), // 多个引用块,按顺序渲染
|
||
'cta_text' => '',
|
||
'cta_url' => '',
|
||
'note' => '',
|
||
'badge' => '',
|
||
));
|
||
|
||
/* 统一成 $quoteList:
|
||
* 调用方可能只给一个 quote,也可能给 quotes 数组(评论回复场景要同时放
|
||
* 「被回复的那条」和「新的回复」,两段各自有作者和时间,必须分开渲染)。
|
||
* 两者都给时以 quotes 为准,避免重复出现。 */
|
||
$quoteList = array();
|
||
if (!empty($d['quotes']) && is_array($d['quotes'])) {
|
||
$quoteList = $d['quotes'];
|
||
} elseif (!empty($d['quote'])) {
|
||
$quoteList = array($d['quote']);
|
||
}
|
||
|
||
$brand = yang_mail_brand_color();
|
||
$brandD = yang_mail_shade($brand, 0.78);
|
||
$onBrand = yang_mail_is_dark($brand) ? '#ffffff' : '#1a1a1a';
|
||
|
||
// badge 的背景:把主色往白色方向提亮一档,得到比主色浅、但同色相的实色。
|
||
// 主色本身是深色时提亮 22%,浅色时压暗 —— 否则浅主色上叠浅 badge 会看不见。
|
||
$badgeBg = yang_mail_is_dark($brand)
|
||
? yang_mail_tint($brand, 0.22)
|
||
: yang_mail_shade($brand, 0.88);
|
||
$badgeBd = yang_mail_is_dark($brand)
|
||
? yang_mail_tint($brand, 0.34)
|
||
: yang_mail_shade($brand, 0.72);
|
||
|
||
$site = get_bloginfo('name');
|
||
$home = home_url('/');
|
||
$year = date('Y');
|
||
|
||
// 字体栈:中文优先 PingFang / 微软雅黑,英文走系统默认。
|
||
// 邮件里不能用 @font-face(Gmail 剥掉),只能靠系统字体。
|
||
$sans = "-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,'PingFang SC','Hiragino Sans GB','Microsoft YaHei',sans-serif";
|
||
|
||
ob_start();
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<meta name="x-apple-disable-message-reformatting">
|
||
<meta name="color-scheme" content="light">
|
||
<meta name="supported-color-schemes" content="light">
|
||
<title><?php echo esc_html($d['title']); ?></title>
|
||
<!--[if mso]>
|
||
<style type="text/css">
|
||
body,table,td,p,a{font-family:Arial,'Microsoft YaHei',sans-serif !important;}
|
||
</style>
|
||
<![endif]-->
|
||
</head>
|
||
<body style="margin:0;padding:0;width:100%;background-color:#eef1f4;">
|
||
|
||
<?php /* 预读文字:显示在收件箱列表里标题的后面。藏起来但必须真实存在,且要足够长,
|
||
否则客户端会把正文第一句抓上去当摘要。 */ ?>
|
||
<div style="display:none;font-size:1px;color:#eef1f4;line-height:1px;max-height:0;max-width:0;opacity:0;overflow:hidden;">
|
||
<?php echo esc_html($d['preheader'] ? $d['preheader'] : $d['heading']); ?>
|
||
</div>
|
||
|
||
<table border="0" cellpadding="0" cellspacing="0" width="100%" role="presentation" style="background-color:#eef1f4;">
|
||
<tr><td align="center" style="padding:32px 12px;">
|
||
|
||
<?php /* 宽度写法是「混合式」:
|
||
· Outlook(Word 引擎)只认 HTML 属性 width="600",CSS 的 max-width 它当没看见;
|
||
· 其它客户端认 CSS,于是 width:100% + max-width:600px 让手机窄屏自动收窄。
|
||
两套并存,各取所需。只写死 600px 会让手机横向滚动——实测过。 */ ?>
|
||
<table border="0" cellpadding="0" cellspacing="0" width="600" role="presentation" style="width:100%;max-width:600px;background-color:#ffffff;border-radius:12px;overflow:hidden;border:1px solid #e3e7ec;">
|
||
|
||
<?php /* ── 顶部品牌条 ── */ ?>
|
||
<tr>
|
||
<td bgcolor="<?php echo esc_attr($brand); ?>" style="background-color:<?php echo esc_attr($brand); ?>;padding:0;">
|
||
<table border="0" cellpadding="0" cellspacing="0" width="100%" role="presentation">
|
||
<tr>
|
||
<td style="padding:26px 32px;">
|
||
<div style="font-family:<?php echo $sans; ?>;font-size:19px;font-weight:600;color:<?php echo esc_attr($onBrand); ?>;letter-spacing:0.2px;line-height:1.3;">
|
||
<?php echo esc_html($site); ?>
|
||
</div>
|
||
<?php if ($d['badge'] !== ''): ?>
|
||
<?php /* badge 用预算好的实色,不用 rgba —— Outlook 不认 rgba,会直接丢掉背景 */ ?>
|
||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="margin-top:10px;">
|
||
<tr>
|
||
<td bgcolor="<?php echo esc_attr($badgeBg); ?>" style="background-color:<?php echo esc_attr($badgeBg); ?>;border:1px solid <?php echo esc_attr($badgeBd); ?>;border-radius:20px;padding:4px 12px;font-family:<?php echo $sans; ?>;font-size:12px;font-weight:500;line-height:1.4;">
|
||
<span style="color:<?php echo esc_attr($onBrand); ?>;"><?php echo esc_html($d['badge']); ?></span>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
<?php endif; ?>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</td>
|
||
</tr>
|
||
<?php /* 主色条下沿压一条深色,给扁平色块一点层次(渐变在 Outlook 里不生效,用纯色)。
|
||
height 必须**同时**写成 HTML 属性和 CSS:Outlook 只认属性,
|
||
只写 CSS 高度时这条 3px 带会撑成一行文字高(约 18px),比例就毁了。 */ ?>
|
||
<tr>
|
||
<td bgcolor="<?php echo esc_attr($brandD); ?>" height="3" style="background-color:<?php echo esc_attr($brandD); ?>;height:3px;line-height:3px;font-size:0;mso-line-height-rule:exactly;"> </td>
|
||
</tr>
|
||
|
||
<?php /* ── 正文 ── */ ?>
|
||
<tr>
|
||
<td style="padding:34px 32px 8px 32px;">
|
||
|
||
<?php if ($d['heading'] !== ''): ?>
|
||
<div style="font-family:<?php echo $sans; ?>;font-size:21px;font-weight:600;color:#1a2028;line-height:1.45;margin:0 0 12px 0;">
|
||
<?php echo esc_html($d['heading']); ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if ($d['intro'] !== ''): ?>
|
||
<div style="font-family:<?php echo $sans; ?>;font-size:15px;color:#4a5560;line-height:1.7;margin:0 0 22px 0;">
|
||
<?php echo esc_html($d['intro']); ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php foreach ($quoteList as $qi => $q): ?>
|
||
<?php
|
||
/* 引用块:左边一条竖线,用 border-left 而不是伪元素(邮件不支持 ::before)。
|
||
*
|
||
* 配色规则:**最后一块用主色高亮,前面的用弱化灰**。
|
||
* 为什么是「最后」而不是「第一」:评论回复场景里顺序是
|
||
* 「被回复的原评论」→「新的回复」,语义重点在新的回复上,所以让它高亮。
|
||
* 只有一个块时它既是第一也是最后 ⇒ 拿到主色,与旧版行为一致。
|
||
*/
|
||
$isLast = ($qi === count($quoteList) - 1);
|
||
$barColor = $isLast ? $brand : '#c2cbd4';
|
||
$barBg = $isLast ? '#f6f8fa' : '#fafbfc';
|
||
$barMargin = $isLast ? '22px' : '14px';
|
||
?>
|
||
<table border="0" cellpadding="0" cellspacing="0" width="100%" role="presentation" style="margin:0 0 <?php echo $barMargin; ?> 0;">
|
||
<tr>
|
||
<td style="border-left:3px solid <?php echo esc_attr($barColor); ?>;background-color:<?php echo esc_attr($barBg); ?>;padding:16px 18px;border-radius:0 8px 8px 0;">
|
||
<?php if (!empty($q['label'])): ?>
|
||
<div style="font-family:<?php echo $sans; ?>;font-size:12px;font-weight:600;color:#5f6b78;letter-spacing:0.6px;text-transform:uppercase;margin:0 0 8px 0;">
|
||
<?php echo esc_html($q['label']); ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
<div style="font-family:<?php echo $sans; ?>;font-size:15px;color:#2d3740;line-height:1.7;word-break:break-word;">
|
||
<?php echo nl2br(esc_html(isset($q['content']) ? $q['content'] : '')); ?>
|
||
</div>
|
||
<?php if (!empty($q['meta'])): ?>
|
||
<div style="font-family:<?php echo $sans; ?>;font-size:13px;color:#5f6b78;line-height:1.6;margin:9px 0 0 0;">
|
||
<?php echo esc_html($q['meta']); ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
<?php endforeach; ?>
|
||
|
||
<?php if (!empty($d['rows'])): ?>
|
||
<?php /* 信息表:两列。label 列定宽 88px 并右对齐,value 左对齐,视觉上最稳。
|
||
不用 table-layout:fixed 之外的花样,Outlook 只认这个。 */ ?>
|
||
<table border="0" cellpadding="0" cellspacing="0" width="100%" role="presentation" style="margin:0 0 24px 0;border-top:1px solid #edf0f3;">
|
||
<?php foreach ($d['rows'] as $row): ?>
|
||
<tr>
|
||
<td width="88" valign="top" style="width:88px;padding:11px 0;border-bottom:1px solid #edf0f3;font-family:<?php echo $sans; ?>;font-size:13px;color:#5f6b78;line-height:1.6;white-space:nowrap;">
|
||
<?php echo esc_html($row['label']); ?>
|
||
</td>
|
||
<td valign="top" style="padding:11px 0 11px 16px;border-bottom:1px solid #edf0f3;font-family:<?php echo $sans; ?>;font-size:14px;color:#2d3740;line-height:1.6;word-break:break-word;">
|
||
<?php
|
||
$v = isset($row['value']) ? $row['value'] : '';
|
||
if (!empty($row['strong'])) {
|
||
echo '<strong style="font-weight:600;">' . esc_html($v) . '</strong>';
|
||
} else {
|
||
echo esc_html($v);
|
||
}
|
||
?>
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
</table>
|
||
<?php endif; ?>
|
||
|
||
<?php if ($d['cta_text'] !== '' && $d['cta_url'] !== ''): ?>
|
||
<div style="margin:0 0 28px 0;">
|
||
<?php echo yang_mail_button($d['cta_text'], $d['cta_url']); ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if ($d['note'] !== ''): ?>
|
||
<div style="font-family:<?php echo $sans; ?>;font-size:13px;color:#5f6b78;line-height:1.7;padding:16px 0 0 0;border-top:1px solid #edf0f3;">
|
||
<?php echo esc_html($d['note']); ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
</td>
|
||
</tr>
|
||
|
||
<?php /* ── 页脚 ── */ ?>
|
||
<tr>
|
||
<td style="padding:24px 32px 30px 32px;">
|
||
<div style="border-top:1px solid #edf0f3;padding-top:20px;font-family:<?php echo $sans; ?>;font-size:12px;color:#5f6b78;line-height:1.9;">
|
||
<div style="margin:0 0 6px 0;">
|
||
<a href="<?php echo esc_url($home); ?>" target="_blank" rel="noopener" style="color:#3d4752;text-decoration:none;font-weight:600;"><?php echo esc_html($site); ?></a>
|
||
</div>
|
||
<div style="margin:0;">此邮件由系统自动发出,请勿直接回复。</div>
|
||
<div style="margin:6px 0 0 0;color:#6b7684;">© <?php echo esc_html($year); ?> <?php echo esc_html($site); ?></div>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
|
||
</table>
|
||
|
||
<?php /* 底部说明:为什么收到这封邮件。放在卡片外面,视觉上属于系统信息 */ ?>
|
||
<div style="font-family:<?php echo $sans; ?>;font-size:12px;color:#5f6b78;line-height:1.7;padding:18px 8px 0 8px;max-width:600px;">
|
||
您收到这封邮件,是因为本站记录了与您邮箱相关的订阅或互动。
|
||
</div>
|
||
|
||
</td></tr>
|
||
</table>
|
||
</body>
|
||
</html>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|