在wordpress上为md格式远程链接添加灯箱效果

在wordpress上为md格式远程链接添加灯箱效果

环境:

wordpress6.9版本,ari fancy Lightbox插件1.3.18版本

问题:

要让灯箱插件可以识别到本地以md格式插入的远程链接

解决办法:

注意使用时关闭主题或者其他插件附带的灯箱效果。

在主题的functions.php末尾中追加

//这个版本会误识别多余的特色图片
// 前端保险脚本(只在单篇页面加载)
if (!function_exists('ari_enqueue_md_fallback_script')) {
    add_action('wp_enqueue_scripts', 'ari_enqueue_md_fallback_script');
    function ari_enqueue_md_fallback_script() {
        if (!is_singular()) return;
        wp_register_script('ari-md-fallback', '', [], false, true);
        wp_enqueue_script('ari-md-fallback');
        wp_add_inline_script('ari-md-fallback', "
        (function($){
            $(function(){
                $('.entry-content, article, .post').find('img').each(function(){
                    var \$img = $(this);
                    if (\$img.parent('a').length === 0){
                        var src = \$img.attr('src');
                        if (src && /^https?:\\/\\/.+\\.(jpe?g|png|gif|webp|svg)(\\?.*)?$/i.test(src)){
                            \$img.wrap('<a href=\"'+src+'\" class=\"ari-fancybox\" data-ari=\"gallery\"></a>');
                        }
                    } else {
                        var \$a = \$img.parent('a');
                        if (!\$a.attr('data-ari') && !\$a.hasClass('ari-fancybox')){
                            var href = \$a.attr('href') || '';
                            if (/^https?:\\/\\/.+\\.(jpe?g|png|gif|webp|svg)(\\?.*)?$/i.test(href)){
                                \$a.addClass('ari-fancybox').attr('data-ari','gallery');
                            }
                        }
                    }
                });
            });
        })(jQuery);
        ");
    }
}

// 服务器端:用 DOMDocument 安全解析并为每个 img 添加/包裹 <a>
if (!function_exists('ari_wrap_remote_images_for_lightbox')) {
    add_filter('the_content', 'ari_wrap_remote_images_for_lightbox', 20);
    function ari_wrap_remote_images_for_lightbox($content) {
        if (!is_singular() || empty($content)) {
            return $content;
        }

        // 如果已经有 ARI 标记则跳过(避免重复处理)
        if (strpos($content, 'data-ari') !== false || strpos($content, 'ari-fancybox') !== false) {
            return $content;
        }

        // 使用 DOMDocument 解析 HTML(比复杂正则更稳健)
        libxml_use_internal_errors(true);
        $doc = new DOMDocument();

        // 为避免编码问题,添加 XML 声明
        $wrapped = '<?xml encoding="utf-8" ?>' . $content;
        if (!$doc->loadHTML($wrapped, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD)) {
            libxml_clear_errors();
            return $content; // 解析失败则返回原始内容
        }
        libxml_clear_errors();

        // 找到所有 img(注意:getElementsByTagName 返回实时集合)
        $imgs = $doc->getElementsByTagName('img');
        $toProcess = [];
        foreach ($imgs as $img) {
            $toProcess[] = $img;
        }

        foreach ($toProcess as $img) {
            $parent = $img->parentNode;
            // 如果父节点是 <a>,并且 href 指向图片,则给父 <a> 添加 ARI 属性
            if ($parent && $parent->nodeName === 'a') {
                $href = $parent->getAttribute('href');
                if ($href && preg_match('/\.(jpe?g|png|gif|webp|svg)(\?.*)?$/i', $href)) {
                    $existing_class = $parent->getAttribute('class');
                    if (strpos($existing_class, 'ari-fancybox') === false) {
                        $parent->setAttribute('class', trim($existing_class . ' ari-fancybox'));
                    }
                    if (!$parent->hasAttribute('data-ari')) {
                        $parent->setAttribute('data-ari', 'gallery');
                    }
                }
                continue;
            }

            // 否则检查 img 的 src 是否为远程图片(http/https)并且是常见图片扩展
            $src = $img->getAttribute('src');
            if (!$src || !preg_match('/^https?:\\/\\//i', $src)) {
                continue;
            }
            if (!preg_match('/\.(jpe?g|png|gif|webp|svg)(\?.*)?$/i', $src)) {
                continue;
            }

            // 创建 <a> 并把 img 移入其中
            $a = $doc->createElement('a');
            $a->setAttribute('href', $src);
            $a->setAttribute('class', 'ari-fancybox');
            $a->setAttribute('data-ari', 'gallery');

            // cloneNode(true) 保留 img 的所有属性
            $newImg = $img->cloneNode(true);
            $a->appendChild($newImg);

            // 用 a 替换原 img 节点
            $parent->replaceChild($a, $img);
        }

        // 导出处理后的 HTML,去掉我们加的 xml 声明
        $html = $doc->saveHTML();
        $html = preg_replace('/^<\\?xml.*?\\?>/','', $html);
        return $html;
    }
}

使用最新版ari fancy(1.4.1)灯箱插件

在functions中添加

/**
 * 开启灯箱,仅使用灯箱的点击图片效果
 * 自动为 Markdown 图片添加灯箱链接包裹
 */
function add_lightbox_to_markdown_images($content) {
    // 匹配没有被 <a> 标签包裹的 <img> 标签
    // 只针对文章详情页生效
    if (is_singular() && is_main_query()) {
        $pattern = '/<img(.*?)src="(.*?)"(.*?)>/i';
        $replacement = '<a href="$2" class="ari-fancybox" title="点击放大"><img$1src="$2"$3></a>';
        
        // 执行替换,但排除掉已经有链接的图片
        $content = preg_replace_callback($pattern, function($matches) {
            // 如果图片外层已经是 <a> 标签,则不处理
            return $matches[0]; 
        }, $content);
        
        // 更简单的正则处理:直接包装所有图片(ARI 插件通常会自动处理重复链接)
        $content = preg_replace('/(?<!<a href=")(<img[^>]*src="([^"]*)"[^>]*>)(?!<\/a>)/i', '<a href="$2" class="ari-fancybox">$1</a>', $content);
    }
    return $content;
}
add_filter('the_content', 'add_lightbox_to_markdown_images', 99);
/**
 * 注意:使用了插件,但是全部预览图不能正常加载
 * 自动为 Markdown 图片添加灯箱链接包裹,并实现“上一张/下一张”分组
 */
function add_lightbox_group_to_markdown_images($content) {
    // 仅在文章详情页处理
    if (is_singular() && is_main_query()) {
        global $post;
        $post_id = $post->ID; // 获取文章ID作为组名

        // 匹配 img 标签
        $pattern = '/<img(.*?)src="(.*?)"(.*?)>/i';
        
        /**
         * 关键点:
         * 给 a 标签加上 data-fancybox="gallery-{$post_id}"
         * 这样 ARI Fancy Lightbox 会把所有拥有相同 data-fancybox 值的图片归为一组
         */
        $replacement = '<a href="$2" class="ari-fancybox" data-fancybox="gallery-' . $post_id . '" title="点击放大"><img$1src="$2"$3></a>';
        
        // 排除掉已经手动带了 a 标签链接的图片,避免嵌套
        $content = preg_replace_callback($pattern, function($matches) use ($post_id) {
            // 如果图片已经在 a 标签里,就不再包裹(或者你可以根据需求强制替换)
            // 这里我们采用简单直接的替换,如果发现图片已经被 a 标签包裹,正则逻辑会略微复杂
            // 为了保证 Markdown 兼容,我们直接处理未被包裹的情况
            return '<a href="' . $matches[2] . '" class="ari-fancybox" data-fancybox="gallery-' . $post_id . '"><img' . $matches[1] . 'src="' . $matches[2] . '"' . $matches[3] . '></a>';
        }, $content);
    }
    return $content;
}
add_filter('the_content', 'add_lightbox_group_to_markdown_images', 100);

无插件解决方案

关闭所有灯箱插件。

在functions.php后追加


add_filter('the_content', function($content) {
    if (is_singular() && is_main_query()) {
        global $post;
        $pattern = '/<img(.*?)src="(.*?)"(.*?)>/i';
        
        $replacement = '<a href="$2" class="spotlight" data-gallery="gallery-' . $post->ID . '" data-control="zoom,close,prev,next,fullscreen,theme"><img$1src="$2"$3></a>';
        $content = preg_replace($pattern, $replacement, $content);
    }
    return $content;
}, 100);

add_action('wp_footer', function() {
    if (is_singular()) {
        echo '
        <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/spotlight.bundle.js"></script>
        <script type="text/javascript">
        (function() {
            var refreshSpotlight = function() {
                var links = document.querySelectorAll(".spotlight");
                links.forEach(function(link) {
                    if (link.getAttribute("data-hooked") !== "true") {
                        link.setAttribute("data-hooked", "true");
                        link.onclick = function(e) {
                            e.preventDefault();
                            e.stopPropagation();
                            
                            // 启动灯箱并强制指定 UI 按钮
                            Spotlight.show(links, {
                                index: Array.from(links).indexOf(this),
                                theme: "dark",
                                show: ["zoom", "close", "prev", "next", "fullscreen", "theme"],
                                thumbs: false // 彻底移除预览图模块
                            });
                            return false;
                        };
                    }
                });
            };
            refreshSpotlight();
            setInterval(refreshSpotlight, 1000);
        })();
        </script>
        <style>
            /* 1. 强制显示切换按钮(那个半圆图标) */
            .spl-theme { 
                display: inline-block !important; 
                visibility: visible !important; 
                opacity: 1 !important; 
            }
            
            /* 2. 定义切换后的白色背景样式,否则点按钮没反应 */
            #spotlight.white { background-color: #ffffff !important; }
            #spotlight.white .spl-pane, 
            #spotlight.white .spl-footer { color: #333 !important; }
            
            /* 3. 彻底隐藏缩略图容器 */
            .spl-thumbs { display: none !important; height: 0 !important; }
            
            /* 4. 基础 UI 修正 */
            .spotlight { cursor: zoom-in !important; }
            #spotlight { z-index: 99999999 !important; }
        </style>
        ';
    }
}, 100);

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注