商店頁是訪客逛 WooCommerce 網站時停留最久、點擊最頻繁的一頁,偏偏它也是最難加速的一頁。它不像部落格文章可以整頁丟進快取,每次載入往往要跑一輪商品查詢、組出一整排商品縮圖,再加上購物車狀態、篩選條件這些動態元素,伺服器忙得不可開交。當商品數量從幾十筆長到幾千筆,原本順暢的商店頁就會開始拖泥帶水。
多數加速教學談的是「整站」優化,把主機、CDN、快取外掛講一輪就收尾,卻很少回頭看商店頁本身在做什麼。這篇把焦點收回到商店端的三個核心:商品查詢怎麼跑、商品圖怎麼出、哪些部分能快取哪些不能。把這三件事調對,商店頁的載入時間通常能砍掉一大截,而且不必砸錢換主機。
為什麼 WooCommerce 商店頁特別容易變慢
商店頁慢的根因,是它同時背了「動態查詢」與「大量圖片」兩個重擔,而這兩者都很難靠單純的全頁快取解決。
WooCommerce 的商品本質上是 WordPress 的 product 自訂文章類型,價格、庫存狀態存在 wp_postmeta 這張 meta 表裡,分類與標籤則是自訂分類法。商店頁每次載入,WooCommerce 會透過 pre_get_posts 掛鉤改寫查詢,撈出符合條件的商品,再逐一組成商品卡片。商品越多、篩選條件越複雜,這輪查詢就越吃資源。
更麻煩的是快取的限制。一般部落格幾乎所有內容都能從快取直接吐給訪客,但電商不行。當使用者登入、或把商品加進購物車的那一刻,WordPress 的登入 Cookie(wordpress_logged_in_ 開頭)與 WooCommerce 的工作階段 Cookie(wp_woocommerce_session、woocommerce_cart_hash)就會出現,全頁快取隨之失效。這代表很大一部分訪客拿到的是「現場重新生成」的頁面,而不是快取版本。
業界一個常被引用的數字是,行動裝置上有相當高比例的使用者,會在頁面載入超過 3 秒時直接離開。商店頁正好是廣告流量最常落地的地方,慢一秒就是真金白銀的流失。要解決它,得從商店端逐層拆開來看。
商店頁的商品查詢該怎麼調校
最被忽略、卻最該優先處理的,是商店頁背後那一輪商品查詢。它跑得快不快,直接決定伺服器回應時間(TTFB),而 TTFB 又是 LCP 的前置環節。
WooCommerce 在 WC_Query 類別裡,於查詢中段提供了一個 woocommerce_product_query 動作掛鉤,讓你能在商品被撈出資料庫前調整查詢參數。要客製商店頁顯示哪些商品、用什麼順序排,從這裡切入比硬改 SQL 安全得多。
每頁商品數要設得務實。商店頁的每頁商品數(posts_per_page)越大,單次查詢與要渲染的縮圖就越多。一頁塞 48 張商品卡,等於一次要跑 48 次商品物件載入加 48 張圖。對行動裝置而言,把每頁控制在 12 到 24 之間,搭配分頁,通常比無限捲動更友善,因為無限捲動會持續累積 DOM 節點與圖片請求,把記憶體與捲動效能一起拖下去。
價格篩選的型別陷阱要特別小心。如果你做了價格區間篩選,meta_query 比對 _price 這個 meta key 時,務必加上 'type' => 'NUMERIC'。少了這行,MySQL 會把價格當字串比,於是「9.99」會被判定大於「100.00」(因為字串比對時「9」大於「1」),結果頁面靜悄悄回傳一批錯誤商品,難以察覺。價格一律比對 _price 而非 _regular_price,因為 _price 反映的是含促銷規則後的當前生效價。
該偷懶的地方就偷懶。WooCommerce 的查詢有幾個能立即減負的旋鈕:
- 只要 ID 就別載入整包物件:當你只是要算商品數、或把一批 ID 丟給後續函式時,加上
'fields' => 'ids',可省去把每筆商品的完整文章物件載入記憶體的成本。 - 非分頁的小區塊關掉總數計算:像「精選商品」「相關商品」這類不需要分頁的小工具或區塊,加上
'no_found_rows' => true,省下 MySQL 為了算總筆數而多跑的SQL_CALC_FOUND_ROWS,在大型目錄上差異明顯。 - 促銷商品 ID 拿來重用:
wc_get_product_ids_on_sale()本身已被 WooCommerce 以暫存(transient)快取。若你在自訂查詢裡反覆用到它,可把整段查詢結果再包一層暫存(例如 12 小時到期),避免每次載入都重算。
分類用 tax_query、別硬塞 meta_query。依商品分類(product_cat)或屬性(pa_color 這類 pa_ 前綴的分類法)篩選時,走的是有索引的分類法資料表,比去比對 wp_postmeta 快得多。wp_postmeta 的索引相當有限,如果你的目錄很大又經常做價格區間查詢,替 _price 在 wp_postmeta 加一個資料庫索引(一行 ALTER TABLE 即可),查詢時間往往能大幅下降。
調查詢時,搭配 Query Monitor 外掛邊看邊改最有效,它能列出整頁跑了哪些查詢、哪幾筆最慢、各由哪個外掛或主題觸發。改完一輪就用它驗證查詢數有沒有降下來,比憑感覺調穩當得多。
商品圖在商店頁該怎麼處理
商品圖是商店頁體積最大的資產,也是 LCP(最大內容繪製)最常見的兇手。一排商品卡同時要拉幾十張圖,沒處理好,行動裝置的載入體驗會非常難看。
先把縮圖尺寸設定對。WooCommerce 有一個專門給商品卡用的縮圖尺寸(woocommerce_thumbnail),可在「外觀/自訂/WooCommerce/商品圖片」裡調整。重點是讓這個註冊尺寸貼近商品卡在版面上實際顯示的寬度,不要讓瀏覽器去縮放一張遠大於需求的原圖。改完尺寸後,務必用重新生成縮圖的工具把既有商品圖重跑一遍,否則新尺寸只對之後上傳的圖生效。
格式與壓縮要到位。把商品圖轉成 WebP 並做無損或近無損壓縮,是體積收益最大的一步,可透過 ShortPixel、EWWW 這類影像最佳化外掛,或具備影像優化的 CDN 來完成。照片類用 JPEG/WebP,需要透明背景的圖示類才用 PNG。
第一屏的圖別讓它延遲載入。WordPress 從 5.5 起原生支援圖片延遲載入,這對首屏以下的商品圖是好事,但首屏(above the fold)那幾張商品圖如果也被延遲載入,反而會拖慢 LCP。商店頁第一排可見的商品圖應該排除在延遲載入之外,甚至預先載入(preload),讓它優先下載。
寬高屬性一定要寫上。每張商品圖都標明 width 與 height,瀏覽器才能在圖還沒下載完時先保留版位,避免商品卡跳動造成的累計版面位移(CLS)。透過 wp_get_attachment_image() 輸出的圖,WordPress 會自動補上寬高,搭配 srcset 讓不同裝置拿到對應尺寸;若你的主題是手刻 HTML 塞圖,就得自己補。
把這幾項做齊,商店頁的圖片總傳輸量往往能降到原本的一半以下,LCP 也會跟著改善。
商店頁的快取要分層,動態片段要單獨處理
商店頁的快取策略,關鍵在於「分清楚哪些能快取、哪些不能」,而不是把整頁丟進全頁快取就了事。
全頁快取管得到匿名訪客。對還沒登入、購物車也是空的訪客,商店頁的 HTML 是可以整頁快取的。全頁快取能把伺服器回應時間從重新生成時的一秒多,壓到一百毫秒上下。WP Rocket、W3 Total Cache 這類外掛內建對 WooCommerce 的支援,會自動把購物車、結帳、我的帳戶這幾頁排除在全頁快取之外,這個排除設定務必確認有生效,否則訪客可能看到別人的購物車狀態。
物件快取管得到那些快取不了的頁。即使全頁快取失效(例如使用者已登入),商店頁背後那輪商品查詢仍會反覆執行。這時 Redis 或 Memcached 提供的物件快取(object cache)就派上用場,它把查詢結果、運算過的資料暫存在記憶體裡,重複使用,大幅減少打到資料庫的查詢次數。導入物件快取後,資料庫查詢數出現大幅下降是常見結果。
購物車片段是商店頁的隱形負擔。WooCommerce 預設會在每個頁面載入 wc-cart-fragments 這支腳本,透過 AJAX 即時更新頁面右上角的迷你購物車數字。問題是它會在商店頁這種「使用者還沒打算結帳」的地方持續發出 AJAX 請求,拖慢互動。處理方式不是粗暴地全站停用(那會讓加入購物車後的數字不更新),而是讓它只在真正需要的頁面載入,或改用點擊後才更新的策略。許多速度外掛(如 Perfmatters)內建了「優化購物車片段」的選項。
快取存活時間別設太短也別太長。電商網站的商品、價格、庫存變動比一般網站頻繁,把快取的存活時間(TTL)設在約一個月、再搭配商品異動時自動清快取的失效機制,通常比設成一年更貼合實況。重點是要有清楚的失效策略:當商品上下架或價格變動時,對應的快取要能自動更新,否則訪客會看到過期的價格。
拖慢商店頁的資料庫與外掛該怎麼清
商店頁的反應隨時間越來越鈍,多半不是 WooCommerce 本身扛不住,而是資料庫堆積與外掛各自為政把它拖垮。
WooCommerce 會為商品資料、運費試算、工作階段產生大量暫存(transient),這些資料存在 wp_options 表裡。過期的暫存若沒清,加上機器人爬站動態產生的客戶工作階段,wp_options 會越長越大,連帶拖慢幾乎每一個查詢。在 WooCommerce 的「狀態/工具」裡,定期清除客戶工作階段與過期暫存是基本功;用 WP-Optimize 這類工具清掉舊文章修訂、垃圾留言與廢棄資料表,也能讓資料庫輕一點。
外掛的問題不在數量,在品質。一個寫得差的外掛,破壞力勝過十個寫得好的外掛。最常見的禍首,是那些「撈出整個商品目錄、卻只為了顯示其中隨機五筆」的低效查詢——平常看不出來,等商品、訂單、流量一多就開始拖累。判斷哪個外掛有問題,可以用 Query Monitor 切到「依元件分組查詢」的分頁,直接看哪個外掛跑了最多、最慢的查詢。
還有一類隱形浪費,是外掛把自己的 CSS/JS 載到根本用不到的頁面。WooCommerce 本身就會在全站載入數支樣式表(woocommerce-layout.css、woocommerce-smallscreen.css、woocommerce.css),但這些在非電商頁面其實用不到。透過 Asset CleanUp 或 Perfmatters 這類資產管理外掛,可以指定某些腳本與樣式只在商店、購物車、結帳這些頁面載入,其餘頁面卸載,商店頁的整體請求數也會跟著精簡。
底層的執行環境同樣別忽略。把 PHP 升級到 8 以上、確認伺服器支援 HTTP/2 或 HTTP/3,這些不必改一行程式碼的調整,對 TTFB 的幫助往往比加裝外掛更實在。
量測商店頁速度該看哪些指標
調校的每一步都要回到量測,否則只是憑感覺改。商店頁要盯的,是核心網頁指標(Core Web Vitals)這三項:LCP 反映主要內容多快畫出來,通常就是首屏那張最大的商品圖;INP 反映頁面對點擊、捲動的回應速度,購物車片段、過重的 JavaScript 都會拉低它;CLS 反映版面跳動,沒寫寬高的商品圖是常見元兇。
要注意實驗室數據與真實數據的落差。用 PageSpeed Insights 或 GTmetrix 測出來的分數,是在它們的環境裡跑一次的結果;但你的訪客很多是登入狀態、拿不到全頁快取,他們的實際體驗可能比工具顯示的差。曾有案例是 PageSpeed 分數一片綠,核心網頁指標卻很差,追下去才發現多數訪客都登入著、又遇上廣告檔期流量暴增,伺服器吃不消——而測速工具享受到了全頁快取,結果完全不能代表真實使用者。所以除了實驗室測試,也要看 Google Search Console 裡的實地數據(CrUX),那才是 Google 用來評估排名的依據。
TTFB 是這一切的源頭。它超過 600 毫秒,Google 會標記為偏慢;能壓到 200 毫秒以下最理想。商店頁的 TTFB 高,幾乎都指向前面講的兩件事:查詢沒調好,或快取沒生效。
從第一次載入到回訪,商店頁速度怎麼維持
商店頁的優化不是設定一次就一勞永逸的工程,它會隨商品數、訂單量、流量一起長大,今天夠快的設定,半年後可能又開始吃力。把心力放在商店端的三個槓桿——讓商品查詢只撈該撈的、讓商品圖以對的尺寸與格式出場、讓能快取的整頁快取、不能快取的交給物件快取與片段優化——回報會比一味升級主機規格來得扎實。
接下來可以做的,是先用 Query Monitor 跑一次自己的商店頁,看清楚現在每次載入到底跑了多少查詢、哪幾筆最慢,再對照本文的順序逐項處理。改一項、量一次、留下有效的,這個節奏建立起來,商店頁就能在目錄持續成長的同時維持該有的速度,把廣告與自然流量真正接住,而不是在載入轉圈時白白流失。