WordPress如何彻底排除指定文章 ID 同步到 Meilisearch(Scry Search 插件实战)

我最近在折腾一个WordPress网站,想给它加个高性能的全站搜索。选来选去,用了Meilisearch,然后搭配了一个叫Scry Search的插件。

一开始挺顺利的,插件装上,配置一下,索引就自动生成了。搜索速度嗖嗖的,体验确实不错。

خو دلته ستونزه راځي.

网站里有几篇很特殊的文章。有的是内部测试用的,有的是给特定客户看的专属落地页,还有的是还没打磨好但不想删掉的内容。这些文章的ID,我需要它们彻底从搜索结果里消失。

不是搜不到就行,是连Meilisearch的索引里都不能有。

WordPress如何彻底排除指定文章 ID 同步到 Meilisearch(Scry Search 插件实战)

我以为这事很简单,不就是排除几个ID嘛。插件文档里肯定有对应的钩子,加个filter不就完事了。

结果,我错了。

为什么常规的拦截方法会失效?

我先是试了官方文档里提到的那个过滤钩子。在functions.php里加了几行代码,保存,刷新后台,重新索引。

然后去Meilisearch后台一看。

那几篇文章,还在那儿呢。

我当时就愣住了。

我以为是我代码写错了,检查了好几遍,没毛病啊。然后我又去插件的GitHub Issues里搜了一圈,发现有好几个人遇到过类似的问题。

原来Scry Search这个插件,为了不拖慢后台的保存速度,搞了一套异步任务队列机制。就是说,当你在后台点”保存文章”的时候,数据可能瞬间就被推进了自定义的任务表,绕过了常规的单篇过滤。

更骚的是,当你在后台点”Index Posts”想重新生成全局索引的时候,插件会直接走底层的批量数据库查询。这时候,你之前加的那个过滤钩子,根本就没机会执行。

等于说,常规的拦截方法,只在你手动保存文章的那一刻生效。但Scry Search的同步逻辑,远比你想象的复杂。

双保险拦截器核心代码

我寻思了一下,这事不能这么算了。

既然常规钩子只管”单篇保存”这个入口,那我就得想办法,从别的地方也堵上。

我想到了两个路径。

第一个是网络传输端。不管是单篇同步还是批量同步,最终数据都得通过HTTP请求发给Meilisearch服务器吧?那我在HTTP请求发出去之前,先检查一下请求体里有没有包含那几个被排除的文章ID。如果有,直接掐断,不让请求发出去。

第二个是数据库查询端。既然批量索引的时候,插件会直接从数据库里捞文章列表,那我就在数据库查询执行之前,把那几个ID从查询结果里剔除掉。在插件看来,这几篇文章压根就不存在,自然也就不会被捞出来。

两个路径,双保险。一条路堵不死,还有另一条兜底。

想明白之后,开始写代码。

第一个拦截器,我用了WordPress原生的pre_http_request过滤器。这个钩子会在WordPress发出任何HTTP请求之前触发。我的逻辑是,只要发现请求的URL里包含meilisearch,并且请求体里包含了那几个被排除的文章ID,就直接拦截这次请求。

为了让插件那边不报错,我还得伪造一个成功的响应。Meilisearch的标准响应格式是{"taskUid":0,"status":"enqueued"},我直接返回这个,让插件以为同步成功了。

第二个拦截器,我用了pre_get_posts钩子。这个钩子在WordPress执行数据库查询之前触发。我的逻辑是,只要是在后台管理员操作,或者是在插件执行异步同步的时候,就把那几个被排除的ID合并到post__not_in参数里。

写完之后,我测试了一下。

先去后台,打开其中一篇被排除的文章,随便改了几个字,点更新。保存成功,没有任何报错。然后去Meilisearch后台一看,那篇文章的索引,还是老样子,没有多出来。

我又去点了一下”Index Posts”,全量重新构建索引。等了一会儿,去Meilisearch后台检查。那几篇被排除的文章,依然干干净净。

成了。

深度解析:双保险机制是如何工作的?

说实话,这个过程让我想起了一件挺有意思的事。

你知道1880年代,电力刚在美国普及的时候,很多工厂主花大价钱买了发电机和电动机,装在自己的工厂里。但是装完之后,很多人发现生产效率并没有显著提升。

ولې؟

因为他们只是用电动机替代了蒸汽机,但整个工厂的布局、流程、管理方式都没有变。电力是新的,但使用电力的思维方式还是旧的。

后来那些真正吃到电力红利的人,其实是最早想明白”电力到底意味着什么”的那波人。他们不只是换了个动力源,而是重新设计了整个生产流程。

همدا اوسAI时代也是一样。很多人把AI当成一个工具来用,但很少有人去想,AI到底改变了什么底层逻辑。工具是新的,但使用工具的思维方式可能还是旧的。

就像我这次搞WordPress搜索拦截,如果我只是按照插件文档里的常规方法去做,大概率是搞不定的。因为Scry Search的同步逻辑已经不是传统的”保存一篇文章就同步一篇文章”了,它有异步队列,有批量处理,有自己的一套机制。

你得先搞明白这套机制是怎么运转的,然后才能找到真正的突破口。

方案的局限性与注意事项

不过我得坦率地说,这套方案也不是完美的。

它有一个很明显的局限,就是只能管住未来的同步,没法自动抹去Meilisearch里已经存在的历史记录。也就是说,如果你之前已经同步过那几篇文章,那你还得手动去Meilisearch的仪表盘或者用API命令,把那些旧数据删掉。

这是个一次性的工作,做完了就不用再管了。但我得提前说清楚,免得你部署完代码之后,发现那几篇文章还在搜索结果里,然后以为代码没生效。

还有一个点需要注意,就是这套方案依赖于WordPress的底层网络和数据库架构。只要Scry Search插件未来更新的版本还是基于这套架构运行,这套拦截器就一直有效。但如果它哪天改用了完全不同的同步机制,那可能就需要重新适配了。

不过说实话,这种可能性不大。WordPress的整个生态都是建立在这套架构之上的,插件想完全绕开,几乎不可能。

落地使用三步走指南

/**
 * Scry Search 双保险拦截器:彻底排除指定文章 ID 同步到 Meilisearch
 */
// ==========================================
// 【配置】请在这里填写你想要排除的文章或页面 ID
// ==========================================
define('MEILI_EXCLUDED_IDS', array(1067, 1014, 1474, 34020));


/**
 * 保险一:拦截单篇保存/更新时的网络推送 (方案 A 优化版)
 * 原理:当 WordPress 发送网络请求时,如果发现是发往 meilisearch 且带有排除的 ID,直接掐断
 */
add_filter('pre_http_request', function($preempt, $parsed_args, $url) {
    // 1. 检查是不是发往 Meilisearch 的请求
    if (strpos($url, 'meilisearch') !== false && isset($parsed_args['body'])) {
        $body_content = $parsed_args['body'];

        // 2. 检查请求体里是否包含任何一个被排除的文章 ID
        foreach (MEILI_EXCLUDED_IDS as $id) {
            // 匹配格式如 "id":1067 或 字符串中的 ID
            if (strpos($body_content, (string)$id) !== false) {
                // 找到匹配,直接拦截网络请求,并向插件伪造一个标准的成功响应
                return array(
                    'response' => array('code' => 200, 'message' => 'OK'), 
                    'body'     => '{"taskUid":0,"status":"enqueued"}'
                );
            }
        }
    }
    return $preempt;
}, 10, 3);


/**
 * 保险二:拦截后台全量索引时的数据库查询 (方案 B)
 * 原理:在插件试图从数据库捞取文章列表时,直接将这几个 ID 从查询结果中剔除
 */
add_action('pre_get_posts', function($query) {
    // 仅在后台管理员操作,或者插件执行异步同步时生效
    if (is_admin() || (defined('DOING_ASYNC') && DOING_ASYNC)) {

        // 获取当前查询已经存在的排除 ID(如果有的话)
        $current_excluded = $query->get('post__not_in');
        if (!is_array($current_excluded)) {
            $current_excluded = array();
        }

        // 将我们的专属排除 ID 合并进去
        $query->set('post__not_in', array_merge($current_excluded, MEILI_EXCLUDED_IDS));
    }
});

最后,总结一下操作步骤。

第一步,把代码复制到你的functions.php文件最底部,或者用Code Snippets插件添加。然后在顶部的define数组里,填上你想要排除的文章或页面ID。

第二步,清理历史索引。登录你的Meilisearch仪表盘,或者用API命令,手动删除那几篇被排除文章的旧索引数据。

第三步,测试。去后台随便改一下被排除的文章,点更新,然后去Meilisearch后台检查。如果没有多出来新的索引,说明拦截已经生效了。

说实话,写这种技术分享类的文章,我一直是有心理负担的。

因为我分享的这些东西,可能对某些人有用,但对另一些人来说,可能就是基本操作。

但这次搞WordPress搜索拦截的过程,确实让我挺有感触的。很多时候,我们遇到的问题,不是没有解决方案,而是我们被现有的框架限制住了思路。

Scry Search插件提供了过滤钩子,我们就以为只能用这个钩子。但其实,WordPress的整个架构,给了我们更多的可能性。网络层可以拦截,数据库层也可以拦截。只要你愿意去想,路总是有的。

这也是我为什么喜欢折腾这些技术玩意的原因。不是为了炫技,也不是为了显得自己很厉害。就是单纯地觉得,当你把一个问题彻底搞明白的时候,那种感觉太爽了。

就像这次,从一开始的困惑,到中间的思考,到最后的解决。整个过程,就像在解一个谜题。

谜题解开了,谜底揭晓了,原来这么简单。

但如果你没经历过那个困惑的过程,你永远体会不到这种简单的快乐。

以上,既然看到这里了,如果觉得不错,随手点赞、转发吧,如果想第一时间收到推送,也可以给我个关注。

زما د مقالې د لوستلو لپاره مننه. بل ځل به سره ګورو.

امید چن وییلینګ بلاګ ( https://www.chenweiliang.com/ ) 分享的《WordPress如何彻底排除指定文章 ID 同步到 Meilisearch(Scry Search 插件实战)》,对您有帮助。

د دې مقالې لینک شریکولو ته ښه راغلاست:https://www.chenweiliang.com/cwl-34343.html

د نورو پټو چلونو د خلاصولو لپاره، زموږ د ټیلیګرام چینل سره یوځای کیدو ته ښه راغلاست!

که مو خوښه شوه لایک او شریک کړئ! ستاسو شریکول او خوښول زموږ دوامداره هڅونه ده!

 

评论 评论

ستاسو بریښنالیک پته به خپره نشي. اړین ساحې کارول کیږي * لیبل

مقالې لارښود
پاس شئ