JavaScript SEO——WordPress 動態內容索引指南

你花時間寫好的商品說明、產品價格、文章內文,打開網頁明明都看得到,Google 卻好像沒收錄、排名也上不來。這種情況最常見的元兇之一,就是這些內容是靠 JavaScript 在瀏覽器裡「事後」產生的,而搜尋引擎當下不一定看得到。這正是 JavaScript SEO 要處理的核心問題。

對多數 WordPress 站長來說,好消息是:一個沒有大量客製化的標準安裝,幾乎不會踩到這些雷。真正會出事的,是把內容、選單、商品列表、價格交給 JavaScript 動態載入的情境。這篇會先講清楚 Google 到底怎麼處理 JavaScript,再帶你判斷自己的 WordPress 站有沒有風險、怎麼自己檢查、發現問題又該怎麼補。

Google 處理 JavaScript 分成哪三個階段

Google 看一個網頁不是一步到位,而是拆成檢索(Crawl)、轉譯(Render)、建立索引(Index)三個階段。理解這三步,後面所有問題都好解釋。

第一步檢索,是 Googlebot 發現你的網址、發出請求、把頁面排進佇列。這一步它拿到的是伺服器回傳的「原始 HTML」,也就是還沒執行任何 JavaScript 的版本。

第二步轉譯,是 Google 用一個叫做 Web Rendering Service 的系統,透過無頭(headless)的 Chromium 瀏覽器去執行頁面上的 JavaScript,產生最終的 DOM(也就是瀏覽器實際呈現的那份結構)。

第三步建立索引,Google 是拿「轉譯後的 HTML」去分析內容、建立索引、決定排名。

關鍵就在這裡:如果你的內容寫死在原始 HTML 裡,Google 第一步就看到了,又快又穩;如果內容要等 JavaScript 執行完才會出現,就得熬到第二步轉譯才看得到。而轉譯這一步,是整個流程裡最耗資源、最可能出狀況的環節。

為什麼轉譯會延遲,甚至被跳過

Google 處理一般 HTML 和處理 JavaScript 的成本差很多。讀一份純 HTML 很便宜,下載一支 JavaScript 應用程式、執行它、再搞懂它產生了什麼,在時間、運算力、成本上都貴得多。

所以 Google 實務上採取的是「兩波(two-wave)」式的處理。第一波先用原始 HTML 快速索引看得到的內容,甚至開始形成初步排名;第二波才把頁面排進轉譯佇列,執行 JavaScript、補上動態內容。這第二波可能在初次檢索後幾個小時,也可能是幾天之後,視網站重要性、檢索預算(crawl budget)與資源排程而定。

對純靠 JavaScript 產生內容的網站,這代表兩件事。一是你的主要內容會晚好幾天才進索引;二是萬一轉譯出錯、逾時、或被檢索預算卡住,那些內容可能根本進不了索引。Google 官方到現在仍建議,能用伺服器端轉譯或預先轉譯,就盡量不要把核心內容完全交給瀏覽器端的 JavaScript。

SSR、CSR、動態轉譯差在哪裡

差別在於「HTML 是誰先把內容組好的」,這直接決定 Google 第一步看到的是完整內容還是空殼。

用做蛋糕來比喻最清楚。伺服器端轉譯(Server-Side Rendering, SSR)是伺服器在後端就把蛋糕烤好,Google 和使用者拿到的都是成品 HTML,內容一開始就在裡面。客戶端轉譯(Client-Side Rendering, CSR)則是伺服器只給一份食譜(幾乎空白的 HTML 加上一包 JavaScript),蛋糕要等瀏覽器自己照食譜烤出來。問題是 Googlebot 不像真人會滾動、點擊、跟頁面互動,它只會建構 DOM,所以全 CSR 的頁面風險最高。

SSR
伺服器先烤好
CSR
瀏覽器自己烤
動態
給爬蟲成品

動態轉譯(Dynamic Rendering)是折衷做法,把使用者導向完整的 JavaScript 體驗,但偵測到搜尋引擎爬蟲時,改回一份預先轉譯好的靜態 HTML。它解決了爬蟲看不到內容的問題,不過要同時維護兩個版本、隨時保持同步,micromanage 的成本不低,Google 也把它定位成過渡方案而非長久之計。對技術成熟度足夠的團隊,更理想的是用同構(isomorphic / universal)JavaScript,讓前後端跑同一套程式碼,後端直接吐出已轉譯的 HTML,再在前端接手互動,一套程式碼兼顧 SEO 與體驗。

標準 WordPress 安裝會不會被 Google 看不到

不會。一個沒有大量客製化的標準 WordPress 安裝,內容是靠後端的 PHP 加 MySQL 在伺服器端組好再吐 HTML,本質上就是 SSR,Google 第一步就拿到完整內容。多數主題和外掛用到的 JavaScript,只是替頁面加上互動效果,例如輪播、行事曆、彈窗、選單動畫,不會把核心內容藏在 JavaScript 後面。這種站幾乎不需要為 JavaScript SEO 操心。

WordPress 裡 JavaScript 的標準做法,是把程式拆成獨立檔案,再透過 wp_enqueue_script() 這個函式掛載進來,讓主題和外掛之間能共用資源、宣告相依、管理版本。早期大量主題以 jQuery 為基礎,較新或客製的主題則可能用上 React 這類現代框架。重點是:只要互動是「加分」性質,核心內容在沒有 JavaScript 的情況下照樣讀得到,SEO 就沒問題。

真正的風險來自客製化把內容本身交給了 JavaScript。當 JavaScript 被用來「建構整個頁面」「動態增刪頁面元素」「從多個來源即時抓內容」時,麻煩才開始。下一節就拆解 WordPress 站上最常見的幾種高風險情境。

哪些 WordPress 與 WooCommerce 功能容易讓內容被漏掉

風險集中在「使用者要先做某個動作,內容才被載入」這類設計,因為 Googlebot 不點、不捲、不互動。

最典型的是頁面建構器(page builder)的分頁標籤(tab)與折疊區塊(accordion)。很多人習慣把產品規格、常見說明塞進這些一點才展開的元件裡。如果這些內容是點擊後才用 Ajax 抓進來的,Google 預設不會去點,那段內容對它就是隱形的。判斷方式很簡單:內容是一開始就在 DOM 裡、只是被 CSS 收合,還是要等點擊事件才被載入?前者安全,後者有風險。

WooCommerce 的幾個功能也要特別留意:

  • Ajax 商品篩選與「載入更多」:許多商品列表外掛用 Ajax 在不換頁的情況下篩選、追加商品。若這些篩選結果頁沒有對應的、可被檢索的實體網址,Google 就只看得到初始那批商品,後面追加的商品等於沒被收錄。
  • 無限捲動(infinite scroll)的商品或文章列表:Googlebot 不會一直往下捲,捲動才載入的項目它看不到。建議同時保留一份有實體分頁網址的版本,讓爬蟲能逐頁檢索。
  • JavaScript 注入的價格、庫存或評論:如果價格或評價是頁面載入後才用 JavaScript 補上去的,要確認轉譯後的 HTML 裡真的有這些數字,否則商品結構化資料可能拿不到價格。

另外一個歷史包袱是 admin-ajax.php。早年大量主題與外掛重度依賴這個端點來抓內容,依賴到 WordPress 預設的 robots.txt 特別開了一條規則允許爬取它,就是為了讓那些原本「看不見」的內容能被檢索。現代開發更推薦走 WordPress REST API,它好開發、權限管理更完整、回應也更快。但無論走哪一條,原則不變:別把關鍵內容只透過 Ajax 載入。

怎麼自己檢查 Google 到底看到了什麼

不用會寫程式,三個層次的檢查就能判斷內容有沒有被 Google 看到,核心是去比對「原始 HTML」和「轉譯後 HTML」的差異。

第一層,最快的粗篩,是直接拿一段你頁面上的內容,加上引號丟進 Google 搜尋,例如搜尋「你商品描述裡一句獨特的話」。如果你的頁面有出現在結果裡,代表那段內容大致被看到了;搜不到,就值得進一步查。

第二層,比對原始碼與實際畫面。在瀏覽器對頁面按右鍵選「檢視網頁原始碼」,看到的是原始 HTML,也就是 Google 第一步拿到的東西;按右鍵選「檢查」(Inspect)看到的 Elements 面板,則接近轉譯後的 DOM。把你關心的那段內容(標題、H 標籤、商品描述)分別在這兩個地方搜尋。如果只在「檢查」裡找得到、在「檢視原始碼」裡找不到,代表這段是 JavaScript 事後產生的,要靠 Google 第二波轉譯才看得到。要測試折疊或下拉內容時,記得先複製文字、重新整理頁面或用無痕視窗重開再搜尋,避免你自己的點擊動作把內容載進來、造成誤判。

第三層,也是最準的,用 Google Search Console 的網址審查工具。它會回報 Google 實際檢索與轉譯的結果,包含轉譯後的 HTML、載入了哪些資源、有沒有資源被擋掉、JavaScript 主控台的錯誤訊息,甚至一張轉譯後的截圖。從那份轉譯後 HTML 去確認標題、描述、H 標籤、主要內容、alt 屬性是不是都在。如果截圖裡看不到重要內容,或原始碼裡缺了該有的段落,就是轉譯出了問題,內容很可能因此無法被索引。

排查內容沒進索引的原因時,通常逃不出這幾類:轉譯逾時(頁面載入太重,Google 等不及)、資源被 robots.txt 擋住(連 JavaScript、CSS 都讀不到自然轉不出畫面)、重複內容、缺乏內部連結或 sitemap 沒收錄導致頁面根本沒被發現。先確認能被正確轉譯,再確認能被索引,最後才談優化排名,順序不要顛倒。

用了 JavaScript 動態內容,有哪些設定要顧好

核心原則只有一句:初次請求伺服器回傳的 HTML,就應該包含完整、可讀的內容;JavaScript 只用來「加強」,不用來「決定有沒有內容」。在這個前提下,以下幾個設定值得逐項檢查。

連結一律用標準的 a 標籤加 href。 Google 靠 <a href="..."> 發現並爬取連結。用 onclick、用 span 假裝成連結、或寫成 href="javascript:void(0)",Google 都不保證會跟。導覽列、分頁、內文連結全都適用這條。

單頁應用要用 History API 管理網址。 如果站台是單頁應用程式(SPA),每次切換內容都要透過 History API 更新網址,產生乾淨、可檢索的路徑。別用 ##! 這種片段(fragment)方式切頁,伺服器通常會忽略 # 之後的東西,結果 Google 永遠只索引得到首頁。

meta robots 要小心被覆蓋。 Google 對 meta robots 採「最嚴格者優先」。原始 HTML 是 noindex、就算 JavaScript 事後改成 index,Google 仍當 noindex,而且 noindex 的頁面根本不會進到轉譯階段。確認你沒有在原始 HTML 留下會誤殺頁面的 noindex。

別擋掉轉譯需要的資源。 robots.txt 裡別封鎖 JavaScript 與 CSS,否則 Google 轉不出完整畫面。常見做法是明確放行:

User-Agent: Googlebot
Allow: .js
Allow: .css

也別忘了檢查你 API 請求會打到的子網域或其他網域的 robots.txt。

標題與描述要逐頁唯一。 JavaScript 框架常套用同一份模板,很容易整批頁面共用同一個 title 或 meta description。用 SEO 模組(在框架裡常以 Helmet、Head 這類名稱出現)替每頁設定獨立標籤。

錯誤頁面要避免軟 404。 前端框架丟不出真正的 404 狀態碼,頁面不存在時可能回傳 200。解法是用 JavaScript 轉址到一個會正確回傳 404 的頁面,或在該頁加上 noindex 並顯示明確的錯誤訊息,讓它被當成軟 404 處理。

用內容指紋解決快取錯亂。 Google 會大量快取你的資源檔。當你更新了 dist.css 或某支 JavaScript,Google 可能還在用舊版轉譯,導致索引到一個拼湊出來、實際上不存在的版本。在檔名或網址帶上內容雜湊(例如 file.1bb991.js),改動後檔名就變,逼 Google 重新下載最新版。

效能直接牽動轉譯成敗。 JavaScript 執行太久會拖慢頁面,不只傷核心體驗指標的 INP 評分,還可能讓 Googlebot 等到逾時、轉譯不完整。壓縮(minify)程式碼、外部 script 善用 defer 或 async、用程式碼分割(code splitting)和 tree shaking 只載入該頁需要的部分。WordPress 站可以靠成熟的快取外掛處理大部分壓縮與快取工作,再用 PageSpeed Insights 檢視核心體驗指標。也要記得 JavaScript 的即時請求很吃檢索預算,這類請求不像一般資源會被快取,每次轉譯都重新抓。

從判斷風險到確認被收錄,該照什麼順序走

JavaScript 不是 SEO 的敵人,它只是跟傳統 HTML 不一樣,需要不同的檢查習慣。對絕大多數 WordPress 與 WooCommerce 站長,最務實的策略是先判斷自己屬於哪一種:如果你用的是標準安裝、主題與外掛都遵循慣例,核心內容由伺服器端產生,那基本上不用為 JavaScript SEO 多做什麼;只有當你把內容、商品列表、價格、選單交給 JavaScript 動態載入時,才需要認真處理。

真要動手,順序是固定的。先用引號搜尋和瀏覽器的原始碼比對做粗篩,再用 Search Console 網址審查工具確認 Google 轉譯後到底看到什麼,找出哪些內容掉了。確認問題後,把該被收錄的內容盡量挪回初次回傳的 HTML 裡,讓頁面在關掉 JavaScript 時功能依然完整,JavaScript 只負責加分。最後才回到一般 SEO 的優化節奏,處理唯一標題、結構化資料、內部連結與 sitemap。

把「Google 第一步就看得到核心內容」當成最高原則,剩下的 JavaScript 都是加分項,你的 WordPress 站就不會落入「人看得到、Google 看不到」的窘境。

相關文章
標籤: WooCommerce, WordPress, JavaScript SEO, 渲染, Googlebot 索引