Files
laoyang 1cf4267c18 fix(lightbox): 无附件 ID 的图片改用 img 的 data-full 作原图兜底
3.2.40 初版把「原图地址」只做了两级兜底:附件 ID → href。
`yang_lightbox_img_src()`(读 data-full / data-large-file /
data-orig-file)当时是**定义了但没人调用**的死代码,等于白写。

后果是这一类结构取不到原图:

    <a href="xxx-300x200.png"><img src="xxx-300x200.png" data-full="xxx.png">

三处都是缩略图,只有 data-full 里是真原图,且 img 没有 wp-image 类
—— 编辑器之外插入的图、部分插件输出的图常是这种形态。用户点开
看到的还是那张小图,会认为灯箱根本没起作用。

改成三级兜底:附件 ID → img 上的 data-full 等属性 → href。
第二级取到的值必须再过一次「像不像图片」,因为有些插件会在
data-full 里放页面地址,不验就会让灯箱加载出一个 HTML 页面。

守卫补在服务端探针 B2 段(4 条,直接看输出里的 href,不看函数里
有没有出现那个字符串),并新增两条反向注入:
S12 砍掉第二级兜底、S13 去掉图片校验。同时更新 S2 的注入锚点 ——
它原来只删第一级,会被第二级救回来,注入等于没做。

Refs #10
2026-10-25 22:17:45 +08:00

602 lines
27 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* 图片灯箱(正文图片点击放大)
*
* ── 做什么 ────────────────────────────────────────────────────
* 文章正文里的图片多是缩略图,点一下在**当前页面**覆盖展示原图,
* 不再跳新标签页。一篇文章有多张图时左右箭头可轮播,键盘方向键切换。
*
* ── 为什么必须重写 <a href>,而不是只加一个 class ────────────
* 现状是 WordPress 编辑器把图片包在 `<a href="原图">` 里,点击就跳转。
* 要让点击在页内打开,有两条路:
* ① 给 <a> 加一个 class,JS 拦截 click 并 preventDefault
* ② 由服务端改写成 <a href="原图" class="...">(保留 href 做无 JS 降级)
* 这里选 ②,原因有三:
* · **无 JS 时仍能点开原图**(href 还在),不会功能全废;
* · 原图地址由服务端确定,不依赖前端从 srcset 里猜最大的那张;
* · 右键「在新标签页打开图片」仍然可用(用户习惯不该被剥夺)。
*
* ── 为什么原图地址必须写在 href 里,不能用 data-full ────────
* 🔴 主题的 CDN 加速是**整页输出缓冲**改写(inc/theme-cdn.php),
* 但它只改 `src=` / `href=` 两个属性名和 CSS 里的 `url()`。
* 写成 `data-full="..."` 的话 CDN 完全看不见,开了 CDN 之后
* 缩略图走 CDN、灯箱里的原图却回源站 —— 用户会看到"点开放大就变慢"。
* 所以原图地址**只能**放 href。这条是硬约束,改之前先看 theme-cdn.php。
*
* ── 为什么不在前端拼接缩略图 → 原图地址 ──────────────────────
* 常见的做法是把 `xxx-300x200.jpg` 里的 `-300x200` 抠掉得到原图。
* 这个做法有三个坑:
* · 文件名本身就可能含 `-数字x数字`(比如 `photo-1920x1080.jpg` 是原名)
* · CDN 或图片优化插件可能给的是 `xxx.jpg?w=300` 或 `xxx-300x200.webp`
* · 多站点/子目录、域名替换之后字符串处理更容易错
* 服务端拿得到**附件 ID**,直接问 WordPress 要 full size 的原图地址,
* 这是唯一可靠的来源。
*
* @author Yongquan Yang <yangyq.net>
* @license MIT License
*/
if (!defined('ABSPATH')) {
exit;
}
/* ══════════════════════════════════════════════════════════════════
* 开关与配置
* ══════════════════════════════════════════════════════════════════ */
/**
* 灯箱功能是否开启
*
* std 与运行时默认值必须一致:Options Framework 的 `std` 只在
* 后台预填和「恢复默认」时起作用,**运行时完全不读它**。
* 所以默认值必须由这里提供,否则会出现「后台看着是勾上的、
* 前台却没生效」。
*/
function yang_lightbox_active()
{
if (!function_exists('kratos_option')) {
return false;
}
return kratos_option('a_lightbox_enable', '1') === '1';
}
/**
* 遮罩配色:'light'(白)或 'dark'(黑)
*
* 用户在需求里先说「黑背景也行、不黑也行,看哪种效果好」,
* 看过两套演示后明确选了**白色**,并要求遮罩半透明、
* 不把底下正文完全盖死、只突出照片。所以默认值从 dark 改成 light。
*/
function yang_lightbox_theme()
{
$v = function_exists('kratos_option') ? kratos_option('a_lightbox_theme', 'light') : 'light';
return $v === 'dark' ? 'dark' : 'light';
}
/**
* 遮罩不透明度(百分比,50~100)
*
* 用户要「约 80%」:底下内容隐约可见,照片仍然是视觉焦点。
* 为什么做成可调而不是写死 80:
* · 每个人屏幕亮度、正文配色不一样,80 在别人站上可能偏透或偏实;
* · 以后想临时更实一点(看清文字)或更透一点(确认自己在哪页),
* 改一个数字就行,不用改代码。
*
* ⚠️ 下限卡 50、上限 100:
* 低于 50 时遮罩几乎挡不住正文,文字会彻底读不清(不是审美问题,
* 是可用性问题);100 就是完全盖死,等于退回原来的实底效果。
*
* 🔴 注意这里返回的是「遮罩背景色的 alpha」,不是 CSS 的 opacity。
* 用 opacity 会让图片/箭头/文字一起变半透明,图片跟着发灰 ——
* 那不是用户要的效果(用户要的是底透、图清楚)。
*/
function yang_lightbox_opacity()
{
$v = function_exists('kratos_option') ? kratos_option('a_lightbox_opacity', '80') : '80';
$v = (int) $v;
if ($v < 50) {
$v = 50;
}
if ($v > 100) {
$v = 100;
}
return $v;
}
/* ══════════════════════════════════════════════════════════════════
* 正文改写:给图片链接打上灯箱标记
* ══════════════════════════════════════════════════════════════════ */
/**
* 判断一个 href 是不是「指向图片」的地址
*
* 只看扩展名会漏掉两类真实存在的地址:
* · 带查询串的(`img.php?f=a.jpg`、`a.jpg?ver=2`)
* · WordPress 的 `?attachment_id=123` 形式
* 所以先剥掉查询串与锚点再判扩展名。
*/
function yang_lightbox_is_image_url($url)
{
$u = (string) $url;
if ($u === '') {
return false;
}
// 只认 http(s) 与站内相对路径;data: / javascript: / mailto: 一律不是
if (!preg_match('#^(?:https?:)?//#i', $u) && substr($u, 0, 1) !== '/') {
return false;
}
// 剥查询串与锚点
$path = preg_replace('/[?#].*$/', '', $u);
return (bool) preg_match(
'#\.(?:jpe?g|png|gif|webp|avif|bmp|svg)$#i',
$path
);
}
/**
* 剥掉别的灯箱插件留下的触发标记
*
* ── 为什么必须有这条 ────────────────────────────────────────
* 🔴 实测线上(抽 100 篇文章、112 张图):**每一张**图片外层 `<a>` 都带着
* data-rel="lightbox-gallery-0"
* data-imagelightbox="0"
* data-rl_title="" data-rl_caption=""
* 这是用户为「点开在当前页放大」装的那个灯箱插件写进数据库的
* **触发标记** —— 那个插件的 JS 靠这些属性选中元素并接管 click。
*
* 而主题自身**从不**产生这些属性(全仓库 grep 为 0 处)。
*
* ── 两条路,选了后者 ────────────────────────────────────────
* ① 让给插件:凡是带这些属性的就跳过不动。
* ✗ 行不通 —— 线上 112/112 张图全带,等于主题灯箱一个字都不改,
* 装上去看上去「完全没效果」,比不装还让人困惑。
* ② 接管:开关开着就以主题为准,把这些触发属性剥掉,
* 插件 JS 找不到元素就不会绑事件,不会出现两套灯箱同时弹。
* ✓ 采用。语义清晰:**开关开 = 主题管,开关关 = 谁都不管**
* (用户关掉开关后属性原样保留,插件照常工作)。
*
* ── 为什么剥属性就够,不用删插件的 JS/CSS ──────────────────
* 这些插件都是「DOM ready 时按选择器找元素再绑事件」。
* 服务端已经把属性去掉了,JS 跑的时候就找不到目标,
* 自然不会绑、也不会弹层。它多加载的那点 CSS/JS 不影响功能。
*
* @param DOMElement $a 正文里的链接节点
* @return int 剥掉的属性个数(0 表示这个链接本来就没被插件接管)
*/
function yang_lightbox_strip_plugin_marks($a)
{
/* 常见灯箱插件的触发属性。新增别的插件时把它的标记加进来即可。
⚠️ 只剥「触发属性」,不动 class —— 很多插件/主题会给图片链接
加无关的 class(如 wp-editor-md-post-content-link),
乱删 class 会破坏原有样式。 */
$marks = array(
'data-rel', // Responsive Lightbox & Gallery 等
'data-imagelightbox', // Image Lightbox
'data-lightbox',
'data-lightbox-gallery',
'data-fancybox', // FancyBox
'data-fancybox-group',
'data-lb',
'data-featherlight', // Featherlight
'data-elementor-lightbox',
'data-elementor-open-lightbox',
'data-rl_title', // Responsive Lightbox 的说明文字
'data-rl_caption',
'data-gallery', // 部分画廊插件
);
$n = 0;
foreach ($marks as $m) {
if ($a->hasAttribute($m)) {
$a->removeAttribute($m);
$n++;
}
}
return $n;
}
/**
* 从 <img> 标签里取「原图地址」的兜底来源
*
* 优先级:`data-full` / `data-large-file` / `data-orig-file`(部分插件会写)
* → 否则取 src(此时 src 本身就是原图,够用)。
*
* ⚠️ 故意**不用** srcset 里最大的那张:srcset 给的是「不同 DPR 的显示用图」,
* 它的最大项仍可能是被裁过/压缩过的,跟「原图」不是一回事。
* 真正可靠的原图要从附件 ID 拿(见 yang_lightbox_content())。
*/
function yang_lightbox_img_src($img_tag)
{
foreach (array('data-full', 'data-large-file', 'data-orig-file', 'src') as $attr) {
if (preg_match('#\s' . preg_quote($attr, '#') . '\s*=\s*(["\'])(.*?)\1#is',
$img_tag, $m)) {
$v = trim($m[2]);
if ($v !== '') {
return $v;
}
}
}
return '';
}
/**
* 从 class 里取 WordPress 附件 ID
*
* 编辑器插入图片时会把 `wp-image-123` 写进 class,这是**服务端唯一**
* 能拿到原图的可靠线索。Gutenberg 的 <figure class="wp-block-image"> 里
* 图片本身也带这个 class。
*/
function yang_lightbox_attachment_id($img_tag)
{
if (preg_match('#\bwp-image-(\d+)\b#', $img_tag, $m)) {
return (int) $m[1];
}
return 0;
}
/**
* 由附件 ID 取原图地址
*
* 用 `wp_get_attachment_image_src($id, 'full')` 而不是拼字符串:
* 它会正确处理多站点、子目录、CDN 插件的 filters、以及
* 「原图被替换过」这类情况。
*
* 取不到就返回空,让调用方退回 href 自己。
*/
function yang_lightbox_full_url($id)
{
if ($id <= 0 || !function_exists('wp_get_attachment_image_src')) {
return '';
}
$src = wp_get_attachment_image_src($id, 'full');
if (!is_array($src) || empty($src[0])) {
return '';
}
$url = (string) $src[0];
// 有些环境会返回相对路径,补成绝对地址(灯箱里要做 URL 比较)
if (substr($url, 0, 1) === '/') {
$url = home_url($url);
}
return $url;
}
/**
* 给正文里的图片链接加灯箱标记
*
* ── 改什么、不改什么 ────────────────────────────────────────
* 改:`<a href="图片"><img ...></a>` → `<a class="yang-lb-item" href="原图" data-yang-lb="1">`
* 不改:
* · 链接到**非图片**的 <a>(外链、下载、锚点)—— 一改就把正常链接废了
* · 已经带 `data-yang-lb` 的(避免二次处理,比如 the_content 被调用两次)
* · 图片外面没有 <a> 的裸 <img> —— 单独处理见 yang_lightbox_bare_imgs()
* · 后台/feed/REST —— 那里不需要灯箱,改了反而干扰编辑
*
* ── 为什么用 DOM 而不是正则 ──────────────────────────────────
* 正文 HTML 里 <a> 套 <img> 的结构、属性顺序、引号风格都可能变。
* 正则改属性在「属性值里含 > 」这类边界上会崩。PHP 的 DOMDocument
* 能正确处理,代价是要处理编码问题(见下面的 mb_convert 说明)。
*/
function yang_lightbox_content($content)
{
if (!yang_lightbox_active()) {
return $content;
}
if (!is_string($content) || $content === '' || stripos($content, '<img') === false) {
return $content;
}
// 后台、feed、REST 里不处理
if (is_admin() || (function_exists('is_feed') && is_feed())) {
return $content;
}
/*
* ⚠️ DOMDocument 会把非 ASCII 当成 Latin-1,中文标题/alt 会被转成乱码。
* 标准做法是:处理前声明 UTF-8、处理后按 UTF-8 输出。
* 这里用「加 XML 声明 + 前缀包一层」的方式避免它自动补 <html><body>。
*
* ⚠️ 不依赖 mbstring:主题在 3.2.36 已经踩过「mbstring 是可选扩展,
* 依赖它 = 整站白屏」这个坑。DOMDocument 的编码用
* `<?xml encoding="UTF-8">` 处理,不需要 mb_* 函数。
*/
$wrapped = '<?xml encoding="UTF-8"><div id="yang-lb-root">' . $content . '</div>';
$prev = libxml_use_internal_errors(true);
$doc = new DOMDocument('1.0', 'UTF-8');
$ok = $doc->loadHTML($wrapped, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
libxml_clear_errors();
libxml_use_internal_errors($prev);
if (!$ok) {
// 解析失败就原样返回 —— 宁可不加灯箱,也不能把正文弄坏
return $content;
}
$root = $doc->getElementById('yang-lb-root');
if ($root === null) {
// getElementById 在 HTML 模式下对 id 的识别不总可靠,退回遍历
$divs = $doc->getElementsByTagName('div');
foreach ($divs as $d) {
if ($d->getAttribute('id') === 'yang-lb-root') {
$root = $d;
break;
}
}
}
if ($root === null) {
return $content;
}
$links = $root->getElementsByTagName('a');
// ⚠️ getElementsByTagName 返回的是**活**的 NodeList,边遍历边改属性没问题,
// 但如果要删/加节点必须倒序。这里只改属性,顺序无所谓。
$n = 0;
$stripped = 0;
foreach ($links as $a) {
if ($a->getAttribute('data-yang-lb') === '1') {
continue;
}
if ($a->getAttribute('data-yang-lb-skip') === '1') {
continue;
}
$href = trim($a->getAttribute('href'));
if (!yang_lightbox_is_image_url($href)) {
continue;
}
// 必须真的包着图片,否则只是个指向图片文件的普通链接
$imgs = $a->getElementsByTagName('img');
if ($imgs->length === 0) {
continue;
}
/* 🔴 到这里才**确定接管**这个链接,可以剥插件标记了(原因见函数注释)。
⚠️ 必须放在上面两个 continue 之后:日志里就有
`<a href=".../wp-login.php"><img src=".../avatar.jpg"></a>` 这种
「图片包在普通链接里」的结构 —— 那种链接不归灯箱管,
剥它的插件标记会连累别的功能。 */
$stripped = yang_lightbox_strip_plugin_marks($a);
$img = $imgs->item(0);
$imgHtml = $doc->saveHTML($img);
/* 原图地址的三级兜底,顺序不能换:
* ① 附件 ID → full 尺寸(最可靠:多站点/子目录/换过原图都能对上)
* ② <img> 自己带的 data-full / data-large-file / data-orig-file
* (很多插件会把原图塞在这些属性里,而 href 反而是缩略图)
* ③ 最后才是 href 本身
*
* 🔴 ② 这一步不能省。有些站点的结构是
* `<a href="xxx-300x200.jpg"><img src="xxx-300x200.jpg" data-full="xxx.jpg">`
* —— 三处都是缩略图、只有 data-full 里是真原图,且 img 没有
* wp-image 类(编辑器之外插入的图常这样)。只做 ①③ 就会
* 「点开还是那张小图」,用户会觉得灯箱没作用。
* ⚠️ 取到的值必须再验一次「像不像图片」,否则某些插件会在
* data-full 里放页面地址。 */
$full = yang_lightbox_full_url(yang_lightbox_attachment_id($imgHtml));
if ($full === '') {
$cand = yang_lightbox_img_src($imgHtml);
if ($cand !== '' && yang_lightbox_is_image_url($cand)) {
$full = $cand;
}
}
if ($full === '') {
$full = $href;
}
// 用 full 覆盖 href —— 这样「右键在新标签页打开」拿到的也是原图
$a->setAttribute('href', $full);
$a->setAttribute('data-yang-lb', '1');
// 保留/补上 class,CSS 用它做「可点击」的视觉提示
$cls = trim($a->getAttribute('class'));
if (strpos(' ' . $cls . ' ', ' yang-lb-item ') === false) {
$a->setAttribute('class', trim($cls . ' yang-lb-item'));
}
// 无障碍:让键盘用户也知道这是个按钮
if (!$a->hasAttribute('role')) {
$a->setAttribute('role', 'button');
}
// 提示文字,给读屏软件用(视觉上由 CSS 隐藏)
if (!$a->hasAttribute('aria-label')) {
$a->setAttribute('aria-label', '放大查看图片');
}
/*
* 🔴 删掉 target="_blank"
* 现状:inc/theme-article.php 的 imgnofollow() 会给正文里所有
* 站外/非本站的 <a> 加 target="_blank",图片链接也被加上了,
* 于是点击就跳新标签页。JS 里虽然会 preventDefault,
* 但**中键点击 / Ctrl+点击 / 无 JS** 时仍会开新窗口。
* 灯箱接管后,这个链接不再承担跳转职责,target 必须去掉。
*/
$a->removeAttribute('target');
// 同理,rel="nofollow" 对「打开自己站内的图」毫无意义
$rel = trim($a->getAttribute('rel'));
if ($rel !== '') {
$keep = array();
foreach (preg_split('/\s+/', $rel) as $r) {
if ($r !== '' && $r !== 'nofollow' && $r !== 'noopener' && $r !== 'noreferrer') {
$keep[] = $r;
}
}
if (empty($keep)) {
$a->removeAttribute('rel');
} else {
$a->setAttribute('rel', implode(' ', $keep));
}
}
$n++;
}
if ($n === 0) {
// 一张都没改到,直接返回原文 —— 别让 DOMDocument 的序列化
// 动到用户原有的 HTML(它可能重排属性、改自闭合写法)
return $content;
}
// 取回 div 内部 HTML(不要外层那个包壳)
$out = '';
foreach ($root->childNodes as $child) {
$out .= $doc->saveHTML($child);
}
return $out;
}
/**
* 裸图片(外面没有 <a> 的 <img>)也让它可点
*
* ── 为什么这条要做 ──────────────────────────────────────────
* 用户说「文章中的**所有**图片」。实际排版里常见两种:
* · 编辑器插入的「链接到媒体文件」→ 有 <a>,上面已处理
* · 直接粘的 <img> / 某些插件输出 / Markdown 渲染 → 没有 <a>
* 后者如果不管,就会出现「有的图能点、有的点不动」,很难解释。
*
* ── 怎么做 ──────────────────────────────────────────────────
* 在 <img> 外面包一个 <a class="yang-lb-item" href="原图">。
* ⚠️ 只包**真正是内容图**的:跳过表情、图标、以及任何带
* `data-yang-lb-skip` 的。判据用「有 wp-image-N 类 或 尺寸够大」,
* 避免把 16px 的小图标也包成可点。
*/
function yang_lightbox_bare_imgs($content)
{
/* 这个函数目前**不启用**。
理由:正文里的裸图在现代 WordPress 里基本不出现(媒体库插入
默认带链接,块编辑器也有 <figure>),而「包一层 <a>」会改变
原有布局(<a> 是 inline,包的如果是块级图会破坏排版)。
真需要时再开,且必须先解决 inline 包裹的问题。
保留函数体是为了让「想开的人」有现成起点,不是死代码 ——
但**不要在没验证布局的前提下直接挂上去**。 */
return $content;
}
/* ══════════════════════════════════════════════════════════════════
* 资源加载
* ══════════════════════════════════════════════════════════════════ */
/**
* 生成「遮罩不透明度」的行内 CSS
*
* ── 为什么只改背景色的 alpha,不改别的 ─────────────────────
* 用户要的是「底透一点、图清楚」。所以只让**遮罩背景**半透明,
* 图片、箭头、文字、底部说明条全部保持不变(各自的底色本来就近不透明,
* 详见 lightbox.css 里的说明)。
*
* ── 为什么底部说明条要跟着算 ────────────────────────────────
* 说明条压在遮罩上,它自己的底是 0.9 的白/黑。
* 遮罩越透,透上来的正文越多,说明条的对比度就越靠它自己的底撑着。
* 这里让说明条的 alpha 也按同一比例抬一点(最低 0.9),
* 保证「不管遮罩多透,文字始终可读」。
*
* @return string
*/
function yang_lightbox_inline_css()
{
$p = yang_lightbox_opacity();
$a = $p / 100;
/* alpha 用定点小数,避免 PHP 把 0.8 输出成 0.80000000000000004
这种难看且在某些老浏览器上舍入异常的形式 */
$a_str = rtrim(rtrim(sprintf('%.2f', $a), '0'), '.');
if ($a_str === '') {
$a_str = '0';
}
/* 底部说明条:始终比遮罩更实,最低 0.9 */
$foot = $a + 0.08;
if ($foot < 0.9) {
$foot = 0.9;
}
if ($foot > 1) {
$foot = 1;
}
$foot_str = rtrim(rtrim(sprintf('%.2f', $foot), '0'), '.');
$dark = yang_lightbox_theme() === 'dark';
/* 白色遮罩用纯白,深色遮罩用近黑(纯黑会让透上来的正文失去层次) */
$rgb = $dark ? '12, 14, 18' : '255, 255, 255';
$foot_rgb = $rgb;
/* 🔴 选择器必须带 [data-theme='...'],不能只写 `.yang-lb`。
原因:lightbox.css 里深色配色那条规则是 `.yang-lb[data-theme='dark']`,
优先级 (0,2,0);而裸 `.yang-lb` 只有 (0,1,0)。
只写裸类名的话,深色配色下这条注入会被样式表**压掉**,
表现成「换了深色配色,透明度设置不生效」—— 而且完全看不出原因,
因为白底那套是对的(基础规则也是 .yang-lb,优先级相同、行内样式胜)。
这里用同优先级的选择器,靠「行内样式排在样式表之后」取胜。 */
$sel = $dark ? ".yang-lb[data-theme='dark']" : ".yang-lb[data-theme='light']";
return $sel . '{--lb-bg:rgba(' . $rgb . ',' . $a_str . ');'
. '--lb-foot-bg:rgba(' . $foot_rgb . ',' . $foot_str . ');}';
}
/**
* 只在「真的会有图片可点」的页面加载资源
*
* 判据:单篇/单页,且正文里出现过 <img。
*
* ⚠️ 为什么不用 `is_singular()` 一把梭:列表页也可能有图,但灯箱在
* 列表页体验很差(图是摘要的一部分,点开就离开了浏览节奏)。
* 而且列表页少加载一份 CSS+JS 对首屏有实际好处。
*
* ⚠️ 为什么判 $post 用「是对象且有 post_content」而不是 `instanceof WP_Post`:
* 有些插件会把全局 $post 换成自己的对象(页面构建器、会员插件都干过),
* 那种对象往往也有 post_content。用 instanceof 会把它们一刀切排除,
* 表现成「某些页面灯箱就是不出现」,而且完全看不出原因。
* 这里要的只是「能读到正文」,不需要它是哪个类。
*/
function yang_lightbox_assets()
{
if (!yang_lightbox_active()) {
return;
}
if (!is_singular()) {
return;
}
$post = isset($GLOBALS['post']) ? $GLOBALS['post'] : null;
if (!is_object($post) || !isset($post->post_content)) {
return;
}
if (stripos((string) $post->post_content, '<img') === false) {
return;
}
/* 正文里一张「带链接的图」都没有时也不用加载:
只有裸图的话前端收集不到可点项,加载了也是白搭。 */
if (stripos((string) $post->post_content, 'href') === false) {
return;
}
wp_enqueue_style(
'yang-lightbox',
ASSET_PATH . '/assets/css/lightbox.css',
array('kratos'),
THEME_VERSION
);
wp_enqueue_script(
'yang-lightbox',
ASSET_PATH . '/assets/js/lightbox.js',
array(),
THEME_VERSION,
true
);
wp_localize_script('yang-lightbox', 'YANG_LB', array(
'theme' => yang_lightbox_theme(),
'prev' => '上一张',
'next' => '下一张',
'close' => '关闭',
'counter' => '%1$s / %2$s',
));
/* 透明度用行内样式注入,不改 lightbox.css 里的默认值。
── 为什么走行内样式而不是把数值传给 JS ──────────────────
遮罩颜色必须在**首帧**就是对的。走 JS 设置的话,覆盖层
打开的那一瞬会先按 CSS 默认色渲染,再被改掉 —— 快速点击时
能看到颜色闪一下(深色闪白色最明显)。
── 为什么挂在样式表之后 ──────────────────────────────────
wp_add_inline_style 会输出在 lightbox.css 之后,
同优先级下后者胜,才能覆盖掉默认 alpha。 */
wp_add_inline_style('yang-lightbox', yang_lightbox_inline_css());
}
add_action('wp_enqueue_scripts', 'yang_lightbox_assets', 22);
/* 正文过滤:优先级 11(在 do_shortcode 的 11 之后、wpautop 之后)
⚠️ 必须晚于 imgnofollow(默认 10)—— 那个会给 <a> 加 target="_blank",
我们要在它之后把 target 去掉,否则会被它重新加上。 */
add_filter('the_content', 'yang_lightbox_content', 20);