Skip to content

Releases: ivanusto/omni-wp-perf-hardening

v1.9.0 — search finds post content again

Choose a tag to compare

@ivanusto ivanusto released this 05 Aug 09:02

Two search defaults change. Existing sites need one manual step — see below.

Constant Was Now
PH_SEARCH_TITLE_ONLY true false
PH_SEARCH_MAX_PAGES 3 10

Matching titles and excerpts only is a large saving, but it makes search results depend on whether an editor happened to put the word in the headline. A keyword that appears in the body of a post was simply unfindable, and nothing on the results page suggested why — visitors just concluded the site had no such article. Coverage now wins by default.

The trade-off is real and unchanged: turning it back on avoids the LIKE '%keyword%' scan over post_content that this plugin exists to contain. If search load is a genuine problem on your site and your keywords tend to live in titles, tick it — the setting is still there, and everything else in search hardening is untouched either way.

The 3-page cap made sense while v1.8.0 was still hiding pagination links. Now that the links are back, a low cap puts visible links in front of visitors that lead to empty pages. 0 removes the cap entirely.

Existing sites: saving the settings screen even once writes every field to the database, and stored values always beat defaults. So this release changes nothing on a site you have already configured. To pick the new behaviour up, go to Settings → Omni Performance Hardening and untick Match titles and excerpts only, then set Result pages limit to 10. Or define the constants in wp-config.php, which overrides both. Fresh installs get the new defaults directly.

Also in this release, from the settings screen:

  • Every field now has a description. Six were bare number boxes with no explanation — both keyword length limits, results per page, archive posts per page and the two Heartbeat intervals. The limits applied on save are stated too: per-page minimum 1, Heartbeat clamped to 15–300. Neither was visible anywhere in the UI before.
  • The three count-related settings are written in plain language rather than SQL_CALC_FOUND_ROWS and found_posts, which meant nothing to the person deciding whether to tick a box. The archive one now also states that tag and taxonomy archives keep their pagination while author and date archives do not — a difference that until now lived only in README.md.

Verified on WordPress 7.0.2: both defaults on a fresh install, an existing option row surviving the upgrade untouched, the constants overriding both, and search results now matching keywords that appear only in post content. Plugin Check clean.

If you want body-text search without the table scan, the real answer is a dedicated search index — Relevanssi, Elasticsearch or similar. This plugin can only keep native LIKE search from getting out of hand; it cannot make it both fast and complete.


兩項搜尋預設值變更。既有站台需要手動操作一步,見下方。

常數 原本 現在
PH_SEARCH_TITLE_ONLY true false
PH_SEARCH_MAX_PAGES 3 10

只比對標題與摘要省下的成本相當可觀,但它會讓搜尋結果取決於編輯有沒有剛好把那個詞寫進標題。只出現在文章內文的關鍵字一律搜尋不到,而結果頁上沒有任何線索指出原因——訪客只會認為站上沒有這篇文章。現在改為涵蓋率優先。

取捨本身沒有變:把它開回去,就能避免對 post_contentLIKE '%關鍵字%' 的全表掃描,而那正是這支外掛存在的理由。若搜尋負載在你的站上確實造成問題、且關鍵字多半落在標題,就勾起來——設定仍在,且不論哪種取捨,搜尋防護的其餘部分都不受影響。

3 頁的上限是在 v1.8.0 仍隱藏分頁連結的前提下才合理。分頁連結恢復後,過低的上限等於把看得到卻通往空白頁的連結放在訪客面前。設為 0 則完全解除上限。

既有站台請注意:後台設定只要儲存過一次,所有欄位都會寫進資料庫,而已儲存的值永遠優先於預設值。 因此這一版對你已經設定過的站台不會有任何改變。要套用新行為,請至「設定 → Omni 效能強化」取消勾選只比對標題與摘要,並將結果頁數上限改為 10;或於 wp-config.php 定義對應常數,其優先序高於兩者。全新安裝則直接適用新預設。

本版另外針對後台設定頁:

  • 每個欄位都有說明文字了。 原本有六個是沒有任何提示的數字框——兩個關鍵字長度限制、每頁筆數、封存頁每頁筆數,以及兩個 Heartbeat 間隔。儲存時套用的夾限也一併寫明:每頁筆數最小 1、Heartbeat 限制在 15–300,這兩項先前在介面上完全看不到。
  • 三個與筆數計算有關的設定改用白話撰寫,不再是 SQL_CALC_FOUND_ROWSfound_posts 這類對「正在決定要不要勾選」的人毫無意義的詞。封存頁那條另外寫明標籤/分類法頁的分頁會保留、作者頁與日期頁不會——此差異先前只記載於 README.md。

已於 WordPress 7.0.2 驗證:全新安裝的兩項新預設、既有 options 於升級後維持不變、常數覆寫兩者,以及搜尋確實能找到只出現在內文的關鍵字。Plugin Check 通過。

若你要的是「內文搜得到又不要全表掃描」,正解是改用專用搜尋索引(Relevanssi、Elasticsearch 等)。本外掛只能把原生 LIKE 搜尋的成本壓住,無法讓它同時又快又完整。

安裝:後台「外掛 → 安裝外掛 → 上傳外掛」上傳附件 ZIP。

完整變更紀錄見 CHANGELOG.md

v1.8.0 — search pagination is back

Choose a tag to compare

@ivanusto ivanusto released this 05 Aug 08:33

Bug fix release. Update if visitors use your site's search.

Search results collapsed to a single page. With search hardening on — the default — the plugin unconditionally set no_found_rows on the search query, so found_posts and max_num_pages stayed at 0 and themes drew no pagination links. A search matching a hundred pages of posts looked like it matched one. Nothing in the markup hints at the cause; the first page of results is entirely correct, there is simply no way to reach the second.

Skipping that count is now its own setting, off by default:

Constant Default Behaviour
PH_SEARCH_NO_FOUND_ROWS false Drops SQL_CALC_FOUND_ROWS on the search query. Saves the full scan, at the cost of every pagination link on the results page

This is the same treatment v1.6.0 gave to widget and page-builder queries, and for the same reason: an optimisation that silently removes something from the page does not belong in a default. Search pagination recovers from the upgrade alone — no setting to change, no wp-config.php edit.

Unlike tag and taxonomy archives, search has no cheap stored count to rebuild the page total from, so the trade-off is genuine rather than an oversight: keeping the count means paying for the scan. Everything else in search hardening — junk-probe filtering, the narrowed post_type / post_status, title-and-excerpt matching — is unchanged and still on.

One thing to check after upgrading: PH_SEARCH_MAX_PAGES (default 3) is a separate cap and still applies. Now that pagination links are visible again, visitors can see links to pages that intentionally return nothing. Raise it, or set it to 0 to lift the cap, if searches on your site should page deeper than three.

Verified on WordPress 7.0.2: default and hardened modes, both the admin setting and the constant, the save round-trip, and pagination output on a multi-page search. Plugin Check clean.


修正版本,站上有站內搜尋功能者請更新。

搜尋結果會塌成只有一頁。搜尋防護開啟時(預設即開啟),外掛會無條件對搜尋查詢套用 no_found_rowsfound_postsmax_num_pages 因此固定為 0,佈景主題隨之不輸出任何分頁連結——原本符合上百頁的搜尋,看起來就像只有一頁。畫面上沒有任何線索指出原因:第一頁的結果完全正確,只是沒有任何途徑能走到第二頁。

略過該計算改為獨立設定,且預設關閉:

常數 預設 行為
PH_SEARCH_NO_FOUND_ROWS false 搜尋查詢關閉 SQL_CALC_FOUND_ROWS。省下全表掃描,代價是結果頁的所有分頁連結

處理方式與 v1.6.0 對次要查詢的修正相同,理由也相同:會讓畫面上某個東西無聲消失的優化,不該是預設值。搜尋分頁光是升級就會恢復,不需調整任何設定,也不需修改 wp-config.php

與標籤/分類法封存頁不同,搜尋沒有如 term count 那樣的便宜既存計數可用來還原總頁數,因此這是真正的取捨而非疏漏:要保留計數就得付掃描成本。搜尋防護的其餘部分——垃圾關鍵字過濾、限縮 post_type / post_status、只比對標題與摘要——皆未變動且維持開啟。

升級後請一併確認PH_SEARCH_MAX_PAGES(預設 3)是另一個獨立的上限,仍然有效。分頁連結恢復顯示後,訪客會看得到那些刻意回傳空結果的頁面連結。若站上的搜尋需要翻超過三頁,請將其調高,或設為 0 解除上限。

已於 WordPress 7.0.2 驗證:預設與收斂兩種模式、後台設定與常數兩種寫法、後台儲存往返,以及多頁搜尋的分頁輸出。Plugin Check 通過。

安裝:後台「外掛 → 安裝外掛 → 上傳外掛」上傳附件 ZIP。

完整變更紀錄見 CHANGELOG.md

v1.7.0 — internal post embeds keep working

Choose a tag to compare

@ivanusto ivanusto released this 01 Aug 02:44

Bug fix release. Update if your site embeds its own posts.

Disabling oEmbed also broke embeds of the site's own posts. PH_DISABLE_OEMBED removed the oEmbed REST route, the json+oembed discovery link and the /embed/ rewrite rule in one go — WordPress needs all three for an internal embed. The <iframe> is still emitted, but it starts at visibility: hidden and only appears once /embed/ posts back its height; with the route gone that URL returns 404, so the card never shows and visitors see only the <blockquote> fallback link. Nothing on screen hints at the cause. Found on a live site that uses internal embeds as part of its content layout.

The switch is now split in two, because the two halves have very different trade-offs:

Constant Default Behaviour
PH_DISABLE_OEMBED_EXTERNAL true Disables embed_oembed_discover, so pasted links to unknown hosts are not probed. YouTube, X, Vimeo and everything else on the built-in provider list still embed
PH_DISABLE_OEMBED_ROUTES false Disables this site's own oEmbed REST endpoint, discovery links and /embed/ routes

PH_DISABLE_OEMBED still works and pins both fields, so existing wp-config.php files need no edit — set it to false if your site uses internal embeds. If you had "Disable oEmbed" ticked in the admin, only the external half carries over on upgrade; the routes return to the new default, so internal embeds recover from the upgrade alone. Re-tick the setting if you still want them gone.

Crawl load on /embed/ is now handled with headers rather than removal: X-Robots-Tag: noindex, follow and Cache-Control: public, max-age=3600, s-maxage=86400. Disallow: /*/embed/ goes into robots.txt only when the routes are actually removed — blocking crawlers stops them reading the noindex, which can strand existing URLs as "indexed, though blocked by robots.txt".

Rewrite rules now rebuild automatically after a version change, including mu-plugin installs where no activation hook runs.

Verified on WordPress 7.0.2: default and hardened modes, both constant forms, the legacy option migration, the admin save round-trip and the mu-plugin upgrade path.


修正版本,站上有使用「內部文章嵌入」者請更新。

停用 oEmbed 會連自家文章的內部嵌入一起關掉。PH_DISABLE_OEMBED 會一併移除 oEmbed REST 路由、<head>json+oembed discovery link 與 /embed/ 的 rewrite rule,而 WordPress 的內部嵌入三者缺一即壞。<iframe> 仍會輸出,但它初始為 visibility: hidden,要等 /embed/ 回傳高度才會現形;路由移除後該網址回 404,卡片因此永遠不顯示,訪客只看得到後備的 <blockquote> 純連結,畫面上沒有任何線索指出原因。此問題於實際站台(把內部嵌入當成內容編排一部分)重現。

該開關拆成兩段,因為兩者的取捨完全不同:

常數 預設 行為
PH_DISABLE_OEMBED_EXTERNAL true 停用 embed_oembed_discover,不對未知網址發出探測請求。核心 provider 清單上的 YouTube、X、Vimeo 等仍可正常嵌入
PH_DISABLE_OEMBED_ROUTES false 停用自家的 oEmbed REST 端點、discovery link 與 /embed/ 路由

舊的 PH_DISABLE_OEMBED 仍然有效,會同時鎖定兩個欄位,既有 wp-config.php 不需修改——站台若使用內部嵌入,將其設為 false 即可。後台曾勾選「停用 oEmbed」者,升級後該值只沿用到外部探索,路由回到新的預設,內部嵌入光是升級就會恢復;仍想移除路由請於後台重新勾選。

/embed/ 的爬取成本改以標頭收斂而非移除端點:送出 X-Robots-Tag: noindex, followCache-Control: public, max-age=3600, s-maxage=86400。robots.txt 的 Disallow: /*/embed/ 僅在路由確實已移除時才寫入——Disallow 會讓爬蟲讀不到 noindex,既有網址反而可能以「已建立索引但遭封鎖」的狀態長期滯留。

rewrite rules 現在會於版本變動時自動重建,mu-plugin 模式(沒有啟用 hook)同樣涵蓋。

已於 WordPress 7.0.2 驗證:預設與收斂兩種模式、兩種常數寫法、舊選項的升級承接、後台儲存往返,以及 mu-plugin 的升級路徑。

升級後:先前失敗的嵌入結果仍留在 WordPress 的 oEmbed 快取(oembed_cache post type 與 _oembed_* postmeta),請重新儲存該篇文章,或執行 wp transient delete --all,卡片才會重新抓取。

安裝:後台「外掛 → 安裝外掛 → 上傳外掛」上傳附件 ZIP。

完整變更紀錄見 CHANGELOG.md

v1.6.0 — fixes blank post lists

Choose a tag to compare

@ivanusto ivanusto released this 31 Jul 06:04

Bug fix release. Update if you are running 1.5.0 or earlier.

Skipping the total-row count on secondary queries is now the PH_SECONDARY_NO_FOUND_ROWS setting, off by default. It previously always applied, with no way to switch it off.

Why it matters: no_found_rows sets found_posts and max_num_pages to 0, and themes and page builders that read those values to decide whether to output a list then render nothing at all. Elementor's post widgets return before emitting any markup, so the section disappears completely — no container, no "nothing found" notice — leaving no clue as to the cause. Found on a live OceanWP + Elementor Pro site whose news listing went blank.

If you want the optimisation, enable it in Settings → Omni Performance Hardening, then check that every post listing on the site still appears.


修正版本,1.5.0 以前的使用者請更新。

次要查詢略過總筆數計算改為 PH_SECONDARY_NO_FOUND_ROWS 設定,預設關閉。此行為原本無條件套用且沒有開關。

原因:no_found_rows 會使 found_postsmax_num_pages 為 0,凡是依這些值判斷是否輸出清單的佈景主題或頁面建構器都會整塊變空白。Elementor 的文章 widget 在該值為 0 時會直接中止渲染,連容器與「找不到文章」提示都不會產生,站長完全無從得知原因。此問題於實際站台(OceanWP + Elementor Pro)的最新消息頁重現。

需要此優化者可於「設定 → Omni 效能強化」開啟,開啟後請確認站上所有文章清單仍正常顯示。

安裝:後台「外掛 → 安裝外掛 → 上傳外掛」上傳附件 ZIP。

完整變更紀錄見 CHANGELOG.md

v1.5.0 — WordPress.org submission build

Choose a tag to compare

@ivanusto ivanusto released this 31 Jul 04:08

The build submitted to the WordPress.org plugin directory. Plugin Check reports zero errors and zero warnings.

  • Author page hardening is now off by default. Most sites want their author archives indexed, so this is opt-in. With the defaults, author feeds no longer return 410, author pages carry no noindex header and robots.txt does not block /author/. Existing installs that want the old behaviour must enable it in the settings or set define( 'PH_AUTHOR_HARDENING', true ); in wp-config.php.
  • Dashboard news widget removal is now an opt-out setting (PH_DASHBOARD_WIDGETS, default on) rather than always-on behaviour. It removes another plugin's widget (W3 Total Cache), which the directory guidelines expect to be under user control.
  • Corrected the sister plugin's name to Omni Webmaster & SEO Suite.

Install: upload the attached ZIP via Plugins → Add New → Upload, then configure under Settings → Omni Performance Hardening.


送交 WordPress.org 外掛目錄審核的版本,Plugin Check 0 錯誤、0 警告。

  • 作者頁收斂改為預設關閉。 多數站台需要作者頁被索引,故改為需要時再開啟。預設情況下 author feed 不再回 410、作者頁不送出 noindex、robots.txt 不封鎖 /author/。既有站台若要維持原本的收斂行為,請於後台開啟該項,或於 wp-config.php 定義 define( 'PH_AUTHOR_HARDENING', true );
  • 儀表板新聞 widget 的移除改為可關閉的設定(PH_DASHBOARD_WIDGETS,預設開啟),原本為無條件執行。由於該行為會移除其他外掛(W3 Total Cache)的 widget,依官方審核準則應交由使用者控制。
  • 姊妹外掛名稱更正為 Omni Webmaster & SEO Suite

安裝:後台「外掛 → 安裝外掛 → 上傳外掛」上傳附件 ZIP,於「設定 → Omni 效能強化」調整參數。

完整變更紀錄見 CHANGELOG.md

v1.4.0 — Omni Performance Hardening

Choose a tag to compare

@ivanusto ivanusto released this 31 Jul 03:52

The plugin is now Omni Performance Hardening (slug/text domain omni-performance-hardening). The official Plugin Check (PCP) now reports zero errors and zero warnings on this build.

  • Renamed plugin, main file and language files; PH_* wp-config constants are unchanged, so existing constant-based deployments keep working. mu-plugin users: deploy omni-performance-hardening.php and remove the old perf-hardening.php.
  • Global functions and filter hooks now use the omni_performance_hardening_ prefix.
  • Bundled translations load via load_textdomain(); wp.org-hosted translations keep loading automatically.
  • Sister plugin: Omni Webmaster SEO Suite — SEO and webmaster tooling from the same team, now linked from the readme and settings page.

Install: upload the attached ZIP via Plugins → Add New → Upload, then configure under Settings → Omni Performance Hardening.


外掛更名為 Omni Performance Hardening(slug/text domain 為 omni-performance-hardening)。此版本通過官方 Plugin Check(PCP)檢測,0 錯誤、0 警告

  • 主檔與翻譯檔一併更名;PH_* 常數不變,既有以 wp-config 常數部署的站台不受影響。mu-plugin 使用者更新時請改放 omni-performance-hardening.php 並移除舊的 perf-hardening.php
  • 全域函式與 filter hook 前綴改為 omni_performance_hardening_
  • 內附翻譯改以 load_textdomain() 載入;wp.org 託管翻譯仍由核心自動載入。
  • 姊妹外掛:Omni Webmaster SEO Suite——同團隊出品的 SEO 與站長工具,說明與設定頁已加入連結。

安裝:後台「外掛 → 安裝外掛 → 上傳外掛」上傳附件 ZIP,於「設定 → Omni 效能強化」調整參數。

完整變更紀錄見 CHANGELOG.md

v1.3.0

Choose a tag to compare

@ivanusto ivanusto released this 31 Jul 03:24

First packaged release. A single-file WordPress plugin that tames the most expensive endpoints — search table scans, archive SQL_CALC_FOUND_ROWS, low-value feeds, oEmbed and XML-RPC — with CDN-friendly cache headers.

Install: upload the attached ZIP via Plugins → Add New → Upload, then configure under Settings → Performance Hardening. Alternatively drop perf-hardening.php (plus languages/ if you want translations) into wp-content/mu-plugins/.

  • Settings priority: PH_* constants in wp-config.php > admin settings > defaults; defined constants lock their admin fields
  • English UI with bundled Traditional Chinese (zh_TW) translation
  • Passes the official Plugin Check (PCP); tested on WordPress 7.0.2 / PHP 8.3

首個打包發行版。單檔 WordPress 外掛,收斂高成本端點:站內搜尋全表掃描、封存頁 SQL_CALC_FOUND_ROWS、低價值 Feed、oEmbed、XML-RPC,並提供 CDN 友善的快取標頭。

安裝:後台「外掛 → 安裝外掛 → 上傳外掛」上傳附件 ZIP,於「設定 → 效能強化」調整參數;或將 perf-hardening.php(需翻譯時連同 languages/)放入 wp-content/mu-plugins/

  • 參數優先序:wp-config.php 的 PH_* 常數 > 後台設定 > 預設值,已定義常數會鎖定後台欄位
  • 介面英文,內附繁體中文(zh_TW)翻譯
  • 通過官方 Plugin Check(PCP);於 WordPress 7.0.2 / PHP 8.3 實測

完整變更紀錄見 CHANGELOG.md