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的整個架構,給了我們更多的可能性。網路層可以攔截,資料庫層也可以攔截。只要你願意去想,路總是有的。

這也是我為什麼喜歡折騰這些技術玩意的原因。不是為了炫技,也不是為了顯得自己很厲害。就是單純地覺得,當你把一個問題徹底搞清楚的時候,那種感覺太爽了。

就像這次,從一開始的困惑,到中間的思考,到最後的解決。整個過程,就像在解一個謎題。

謎題解開了,謎底揭曉了,原來這麼簡單。

但如果你沒經歷過那個困惑的過程,你永遠體會不到這種簡單的快樂。

以上,既然看到這裡了,如果覺得不錯,隨手按讚、轉發吧,如果想第一時間收到推播,也可以給我個關注。

謝謝你看我的文章,我們,下次再見。

發表評論

您的郵箱地址不會被公開。 必填項已用 * 標註

回到頁首