優化 WordPress 性能的高級指南
已發表: 2022-03-11今天,WordPress 為超過 30% 的互聯網提供支持。 它易於使用,非常受歡迎,而且不會很快出現在任何地方。
但是 WordPress 可能很慢。 那麼如何優化呢?
有大量關於如何調整和優化 WordPress 的文章。 事實上,WordPress 本身提供了一個強大的 WordPress 優化指南。
在大多數情況下,這些文章和教程涵蓋了非常基本但有用的概念,例如使用緩存插件、與內容交付網絡 (CDN) 集成以及最小化請求。 雖然這些技巧非常有效,甚至是必要的,但最終,它們並沒有解決根本問題:大多數緩慢的 WordPress 網站都是由糟糕或低效的代碼造成的。
因此,本文主要旨在為開發人員和 WordPress 開發公司提供一些指導方針,以幫助他們解決許多 WordPress 性能問題的根本原因。
WordPress 提供了許多開發人員經常忽略的面向性能的功能。 不利用這些功能的代碼可能會減慢最簡單的任務,例如獲取帖子。 本文詳細介紹了四種可能的解決方案,它們解決了 WordPress 性能緩慢背後的一些潛在問題。
獲取帖子
WordPress 提供了從數據庫中獲取任何類型帖子的可能性。 有以下三種基本方法:
使用
query_posts()
函數:這是一種非常直接的方法,但問題是它會覆蓋主查詢,這可能會導致不便。 例如,如果我們想在獲取帖子後的某個時間點(例如在footer.php
)確定我們正在處理的頁麵類型,這可能是一個問題。 事實上,官方文檔有一個註釋建議不要使用此函數,因為您需要調用一個附加函數來恢復原始查詢。 此外,替換主查詢將對頁面加載時間產生負面影響。使用
get_posts()
函數:這幾乎與query_posts()
一樣工作,但它不會修改主查詢。 另一方面,get_posts()
默認情況下執行查詢時將suppress_filters
參數設置為true
。 這可能會導致不一致,特別是如果我們在代碼中使用與查詢相關的過濾器,因為此函數可能會返回您不希望出現在頁面中的帖子。使用
WP_Query
類:在我看來,這是從數據庫中檢索帖子的最佳方式。 它不會改變主查詢,並以標準方式執行,就像任何其他 WordPress 查詢一樣。
但是無論我們使用哪種方法與數據庫交互,我們都需要考慮其他一些事情。
限制查詢
我們應該始終指定我們的查詢必須獲取多少帖子。
為了實現這一點,我們使用了posts_per_page
參數。
WordPress 讓我們將 -1 指示為該參數的可能值,在這種情況下,系統將嘗試獲取滿足定義條件的所有帖子。
這不是一個好的做法,即使我們確信我們只會得到一些結果作為響應。
一方面,我們很少能確定只能得到一些結果。 即使我們可以,設置不限制將要求數據庫引擎掃描整個數據庫以查找匹配項。
相反,限制結果通常會使數據庫引擎只掃描部分數據,這意味著更少的處理時間和更快的響應。
WordPress 默認做的另一件事可能會對性能產生不利影響,它會嘗試引入粘性帖子併計算在查詢中找到了多少行。
但是,我們通常並不真正需要這些信息。 添加這兩個參數將禁用這些功能並加快我們的查詢:
$query = new WP_Query( array( 'ignore_sticky_posts' => true, 'no_found_rows' => true ) );
從查詢中排除帖子
有時我們想從查詢中排除某些帖子。 WordPress 提供了一種非常直接的實現方式:使用post__not_in
參數。 例如:
$posts_to_exclude = array( 1, 2, 3 ); $posts_per_page = 10; $query = new WP_Query( array( 'posts_per_page' => $posts_per_page, 'post__not_in' => $posts_to_exclude ) ); for ( $i = 0; $i < count( $query->posts ); $i++ ) { //do stuff with $query->posts[ $i ] }
但是雖然這很簡單,但它並不是最優的,因為它在內部會生成一個子查詢。 尤其是在大型安裝中,這可能會導致響應緩慢。 通過一些簡單的修改讓 PHP 解釋器完成該處理會更快:
$posts_to_exclude = array( 1, 2, 3 ); $posts_per_page = 10; $query = new WP_Query( array( 'posts_per_page' => $posts_per_page + count( $posts_to_exclude ) ) ); for ( $i = 0; $i < count( $query->posts ) && $i < $posts_per_page; $i++ ) { if ( ! in_array( $query->posts[ $i ]->ID, $posts_to_exclude ) ) { //do stuff with $query->posts[ $i ] } }
我在那裡做了什麼?
基本上,我從數據庫引擎中刪除了一些工作,並將其留給 PHP 引擎,它做同樣的事情,但在內存中,這要快得多。
如何?
首先,我從查詢中刪除了post__not_in
參數。
由於查詢可能會給我們帶來一些我們不想要的帖子,因此我增加了posts_per_page
參數。 這樣我就可以確保,即使我的回復中有一些不受歡迎的帖子,我也會在那里至少有$posts_per_page
所需的帖子。
然後,當我遍歷帖子時,我只處理那些不在$posts_to_exclude
數組中的帖子。
避免複雜的參數化
所有這些查詢方法都為獲取帖子提供了多種可能性:按類別、按元鍵或值、按日期、按作者等。
雖然這種靈活性是一項強大的功能,但應謹慎使用,因為參數化可能會轉化為複雜的表連接和昂貴的數據庫操作。
在下一節中,我們將概述一種在不影響性能的情況下仍能實現類似功能的優雅方法。
充分利用 WordPress 選項
WordPress 選項 API 提供了一系列工具來輕鬆加載或保存數據。 它對於處理少量信息很有用,因為 WordPress 提供的其他機制(如帖子或分類法)過於復雜。

例如,如果我們想要存儲身份驗證密鑰或網站標題的背景顏色,則我們正在尋找選項。
WordPress 不僅為我們提供了處理它們的功能,而且還使我們能夠以最有效的方式進行處理。
有些選項甚至在系統啟動時直接加載,從而為我們提供了更快的訪問速度(在創建新選項時,我們需要考慮是否要自動加載它)。
例如,考慮一個網站,我們有一個輪播顯示後端指定的突發新聞。 我們的第一反應是使用元密鑰,如下所示:
// functions.php add_action( 'save_post', function ( $post_id ) { // For simplicity, we do not include all the required validation before saving // the meta key: checking nonces, checking post type and status, checking // it is not a revision or an autosaving, etc. update_post_meta( $post_id, 'is_breaking_news', ! empty ( $_POST['is_breaking_news'] ) ); } ); // front-page.php $query = new WP_Query( array( 'posts_per_page' => 1, 'meta_key' => 'is_breaking_news' ) ); $breaking_news = $query->posts[0] ?: NULL;
如您所見,這種方法非常簡單,但不是最優的。 它將執行數據庫查詢,嘗試查找具有特定元鍵的帖子。 我們可以使用一個選項來實現類似的結果:
// functions.php add_action( 'save_post', function ( $post_id ) { // Same comment for post validation if ( ! empty ( $_POST['is_breaking_news'] ) ) update_option( 'breaking_news_id', $post_id ); } ); // front-page.php if ( $breaking_news_id = get_option( 'breaking_news_id' ) ) $breaking_news = get_post( $breaking_news_id ); else $breaking_news = NULL;
功能從一個示例到另一個示例略有不同。
在第一段代碼中,我們將始終獲得最新的突發新聞,就帖子的發布日期而言。
在第二個中,每次將新帖子設置為突發新聞時,都會覆蓋之前的突發新聞。
但是因為我們可能一次只想要一篇突發新聞,所以這應該不是問題。
最後,我們將繁重的數據庫查詢(使用帶有元鍵的WP_Query
)更改為簡單直接的查詢(調用get_post()
),這是一種更好、性能更高的方法。
我們也可以做一個小的改變,並使用瞬變代替選項。
瞬態的工作方式類似,但允許我們指定過期時間。
例如,對於突發新聞,它就像手套一樣合適,因為我們不希望將舊帖子作為突發新聞,如果我們將更改或刪除該突發新聞的任務留給管理員,[s]他可能會忘記做它。 因此,通過兩個簡單的更改,我們添加了一個到期日期:
// functions.php add_action( 'save_post', function ( $post_id ) { // Same comment for post validation // Let's say we want that breaking news for one hour // (3600 = # of seconds in an hour). if ( ! empty ( $_POST['is_breaking_news'] ) ) set_transient( 'breaking_news_id', $post_id, 3600 ); } ); // front-page.php if ( $breaking_news_id = get_transient( 'breaking_news_id' ) ) $breaking_news = get_post( $breaking_news_id ); else $breaking_news = NULL;
啟用持久緩存
WordPress 本機具有對象緩存機制。
例如,選項是使用該機制緩存的。
但是,默認情況下,緩存不是持久的,這意味著它只存在於單個請求的持續時間內。 所有數據都緩存在內存中,以便更快地訪問,但它僅在該請求期間可用。
支持持久緩存需要安裝持久緩存插件。
一些整頁緩存插件附帶了一個持久緩存插件(例如 W3 Total Cache),但有些沒有,我們需要單獨安裝它。
這將取決於我們平台的架構,我們是否會使用文件、Memcached 或其他一些機制來存儲緩存數據,但我們應該利用這個驚人的特性。
有人可能會問:“如果這是一個很棒的功能,為什麼 WordPress 不默認啟用它”?
主要原因是,根據我們平台的架構,一些緩存技術會起作用,而另一些則不會。
例如,如果我們將網站託管在我們的分佈式服務器中,我們應該使用外部緩存系統(例如 Memcached 服務器),但如果我們的網站駐留在單個服務器上,我們可以通過簡單地使用文件系統來節省一些錢緩存。
我們需要考慮的一件事是緩存過期。 這是使用持久緩存最常見的缺陷。
如果我們沒有正確解決這個問題,我們的用戶會抱怨他們不會看到他們所做的更改,或者他們的更改需要太長時間才能應用。
有時我們會發現自己在性能和動態之間進行權衡,但即使有這些障礙,持久緩存也是幾乎每個 WordPress 安裝都應該利用的東西。
AJAXing 最快的方式
如果我們需要通過 AJAX 與我們的網站進行通信,WordPress 在服務器端處理請求時會提供一些抽象。
即使在編寫後端工具或從前端提交表單時可以使用這些技術,但如果不是絕對必要的話,應該避免使用它們。
這樣做的原因是為了使用這些機制,我們有義務向位於wp-admin
文件夾中的某個文件發出 post 請求。 大多數(如果不是全部)WordPress 全頁緩存插件既不緩存發布請求也不緩存對管理員文件的調用。
例如,如果我們在用戶滾動我們的主頁時動態加載更多帖子,那麼最好直接調用其他一些前端頁面,這樣可以獲得緩存的好處。
然後我們可以通過瀏覽器中的 JavaScript 解析結果。
是的,我們發送的數據比我們需要的多,但我們在處理速度和響應時間方面取得了勝利。
打破 WordPress 只是慢的觀念
這些只是開發人員在為 WordPress 編碼時應考慮的一些建議。
有時,我們忘記了我們的插件或主題可能需要與其他插件一起使用,或者我們的網站可能由託管公司提供服務,該公司為數百或數千個具有公共數據庫的其他網站提供服務。
我們只關注插件應該如何運行,而不是它如何處理該功能,或者如何以有效的方式完成它。
從上面可以看出,WordPress 性能不佳的根本原因是糟糕且低效的代碼。 但是,WordPress 通過其各種 API 提供了所有必要的功能,這些 API 可以幫助我們構建性能更高的插件和主題,而不會影響整個平台的速度。