用 Claude Code 幫 Ghost CMS 加上推薦閱讀區塊

推薦閱讀不只是「最新文章」,應該是「跟這篇有關的文章」。本文示範如何讓 Claude Code 直接修改 Ghost 主題模板,實現依 tag 的智慧推薦。

分享
用 Claude Code 幫 Ghost CMS 加上推薦閱讀區塊
Photo by Giulia Bertelli on Unsplash

Ghost CMS 的 Source 主題預設就有「Read more」區塊,但仔細看它的邏輯——它只是抓最新的 3 篇文章,跟當前文章的主題毫無關聯。一篇講 Python 的文章,底部跑出一篇講咖啡的推薦,這不是推薦,這是亂數。

這篇文章記錄如何讓 Claude Code 幫我修掉這個問題:把推薦邏輯從「最新文章」改成「同 tag 文章」,整個過程不需要下載主題、不需要手動編輯檔案、也不需要進 Ghost 後台。

Ghost 推薦閱讀的運作原理

Ghost 的 Handlebars 模板提供一個 {{#get}} helper,可以直接在主題模板裡查詢 Ghost 的資料——文章、標籤、作者都可以。推薦閱讀區塊就是利用這個 helper,在 post.hbs 底部加入一段查詢邏輯。

Source 主題原本的寫法:

{{#get "posts" include="authors" filter="id:-{{post.id}}" limit="4" as |next|}}
    {{! 顯示文章卡片 }}
{{/get}}

這段程式碼的意思是:「取得所有文章,排除目前這篇,顯示 4 篇」。沒有任何主題相關性,純粹依時間排序。

改成依 tag 篩選的寫法:

{{#get "posts" include="authors" filter="tags:[{{post.tags}}]+id:-{{post.id}}" limit="3" as |next|}}
    {{! 顯示文章卡片 }}
{{/get}}

多了 tags:[{{post.tags}}] 這個 filter,Ghost 會找出所有跟目前文章共享至少一個 tag 的文章,再排除自己,顯示最多 3 篇。這才是真正有意義的推薦。

為什麼不直接進後台改?

Ghost 後台的「Code Injection」只支援 HTML、CSS 和 JavaScript,不支援 Handlebars 語法。Handlebars 是 Ghost 的伺服器端模板語言,只能存在於主題的 .hbs 檔案中,在瀏覽器執行前就已經被伺服器處理完畢。

所以要改推薦邏輯,必須直接修改主題檔案 post.hbs。這通常意味著:下載主題 ZIP、解壓縮、修改、重新打包、重新上傳——步驟繁瑣,而且容易出錯。

Claude Code 的做法:直接進容器

因為 Ghost 架設在 Zeabur 上,Zeabur CLI 提供了 service exec 指令,可以直接在執行中的容器裡執行命令。Claude Code 利用這個能力,繞過了整個「下載→修改→上傳」的流程。

整個修改過程分三步:

第一步:找到主題位置

npx zeabur@latest service exec --id <ghost-service-id> --   find /var/lib/ghost/current/content/themes -name 'post.hbs'

Ghost 的主題存放在容器的 /var/lib/ghost/current/content/themes/ 目錄下。找到 Source 主題的 post.hbs 路徑後,就可以直接操作。

第二步:用 Node.js 修改檔案

Ghost 容器內建 Node.js(因為 Ghost 本身就是 Node 應用),所以可以直接在容器內執行 Node 腳本來修改檔案:

npx zeabur@latest service exec --id <ghost-service-id> -- node -e "
const fs = require('fs');
const path = '/var/lib/ghost/current/content/themes/source/post.hbs';
let content = fs.readFileSync(path, 'utf8');
content = content.replace(
  'filter="id:-{{post.id}}" limit="4"',
  'filter="tags:[{{post.tags}}]+id:-{{post.id}}" limit="3"'
);
fs.writeFileSync(path, content, 'utf8');
console.log('done');
"

這段腳本讀取 post.hbs,用字串替換更新 filter 條件,再寫回去。整個過程在容器內部完成,不需要任何檔案傳輸。

第三步:重啟服務

npx zeabur@latest service restart --id <ghost-service-id>

Ghost 會在重啟時重新讀取主題檔案,修改立即生效。

效果:推薦變精準了

改完之後,文章底部的「Read more」區塊會顯示與當前文章共享相同 tag 的文章。寫 Ghost CMS 的文章,推薦的就是其他 Ghost 相關文章;寫 Claude Code 的,推薦的就是 AI 工具相關文章。

這個邏輯有一個邊緣情況:如果某篇文章沒有設定 tag,或所有 tag 文章只有這一篇,區塊就不會顯示。這是合理的行為——沒有相關文章就不顯示,比隨機推薦更誠實。

FAQ

Q:這樣修改容器內的檔案,重新部署後會不會被覆蓋?

這取決於 Zeabur 的部署設定。如果 Ghost 的 content 目錄掛載了持久化 Volume,修改會保留;如果是純容器映像檔,重新部署後可能還原。建議確認 Zeabur 專案是否有 Volume 掛載,或考慮將修改後的主題透過 Ghost Admin 上傳,作為持久化備份。

Q:除了推薦閱讀,還有哪些主題設定可以這樣改?

所有 .hbs 模板檔案都可以用相同方式修改,例如頁首(default.hbs)、文章列表(index.hbs)、標籤頁(tag.hbs)。只要是 Handlebars 模板層的邏輯,都可以透過這個方式調整。

Q:Source 主題以外的主題也適用嗎?

邏輯完全相同,但具體的 HTML 結構和 CSS class 名稱會不一樣。不同主題的 post.hbs 裡,負責顯示文章卡片的 partial 名稱可能是 post-cardloop-grid 或其他名稱,需要先閱讀主題原始碼確認。

結語

「推薦閱讀」這個功能說小不小——它影響讀者在你網站上的停留時間,也影響他們對你內容的整體印象。Ghost 的 Source 主題雖然內建了這個區塊,但預設的實作並不夠聰明。

用 Claude Code 直接進容器修改主題,整個流程不到 5 分鐘,省去了手動處理主題檔案的繁瑣。現在的 AI 真的是超級厲害,省去了開好幾個分頁貼來貼去的麻煩,讚!

Read more

Gaze Guard 短影片旁白的 TTS 成本與隱私防護示意圖

短影片旁白的成本,其實比我想像低

我最近在做一支 Gaze Guard 的 20 秒產品介紹影片。 原本想說簡單做個動畫就好。 後來想說如果有配音,會感覺比較生動也比較能夠描述使用的情境和達成的效果。 這次我測了什麼 我測的是產品介紹影片用的英文旁白。 工具底層使用的是 Edge TTS,也就是 Microsoft Edge 的線上 Text-to-Speech 服務。常見的底層工具是 edge-tts。 這不是正式 Azure Speech API 的計費路徑。 在我這次的環境裡,它沒有要求 API key,也沒有回傳可見的 per-use billing。 所以這次測試本身,比較像是快速 prototype。 如果未來要正式商用、穩定大量產出,就要回頭看 Azure Speech、OpenAI TTS、ElevenLabs 這類正式付費方案。

By SteepingLogic
用 Cloudflare Tunnel,從外面連回本機 Hermes Dashboard

用 Cloudflare Tunnel,從外面連回本機 Hermes Dashboard

# 用 Cloudflare Tunnel,從外面連回本機 Hermes Dashboard 我有一台 local Hermes。 平常它就在自己的機器上跑。 可能是家裡的桌機。 可能是 NAS。 可能是一台一直開著的 Linux box。 也可能只是我自己的筆電。 問題是,人一離開那個網路,Hermes dashboard 就變成一個只存在於 localhost 的東西。 我想在外面打開它。 但我沒有 static IP。 沒有買網域。 也不想進路由器開 port forwarding。 因為那條路通常長這樣: * 找 public IP * 設定 NAT * 開 port * 處理防火牆 * 補 HTTPS * 設定憑證 * 再擔心 origin IP 被掃 非常友善。 所以這篇先走另一條路:

By SteepingLogic
Invoshot 開發日記|正向回饋

Invoshot 開發日記|正向回饋

想信很多人在開發的時候都常常會做一件事,那就是: 不斷地反覆思考,在腦袋內把流程跑過很多次,然後思考哪裡可以做得更好 不限坐在電腦前的時後,可能是在捷運上,在人行道上, 在馬桶上或是在洗澡的時候 🤪 我不斷地在想:AI 辨識完一張發票後,使用者接下來最需要的是什麼? 每個欄位都要核對嗎? 這麼多欄位真的不會漏看嗎? 所以我在 Invoshot 裡加了提醒功能。 辨識結果出來後,系統會把比較需要注意的地方標出來。 不是把所有不確定都丟給使用者,而是把他真正需要介入的那幾秒鐘留出來。 今天收到一則訊息: 今天用了有新增提醒功能很棒! 真的有變輕鬆 😎 看到這句的時候,我第一個想到的是: 原來那些只是我腦內風暴的優化項目,使用者是真的可以感受到差異的! 感覺又有動力了!

By SteepingLogic