← 返回

WordPress 開放 AI 存取方案研究

研究日期:2026-05-29  |  適用場景:kunhang.com.tw(WordPress + Elementor 商業官網) |  目標:讓 AI 直接修改 Elementor HTML Widget 內容,取代手動複製貼上
推薦組合

方案 2(自訂 REST Endpoint)+ 方案 3(Elementor MCP Plugin)雙軌並行

搭配嚴格管制措施:IP 白名單、最小角色、pending 狀態、Discord 通知。攻擊面最小、效率最高、可追溯。

一、重點摘要

方案 效率提升 實作複雜度 整體風險 適合此場景
WordPress REST API + Application Passwords ✓ 推薦
自訂 REST Endpoint(限定存取範圍) ✓ 最推薦
Elementor MCP Plugin(bvisible/elementor-mcp-api) 極高 ✓ 值得評估
SSH/SFTP 直接改檔案 ✗ 不推薦
WP-CLI 遠端執行 ✗ 不推薦
第三方外掛(WPCode 等) △ 功能有限

二、各方案詳細評估

方案 1:WordPress REST API + Application Passwords
原生內建方案,WordPress 5.6+ 即可用

運作方式

  1. 在 WordPress 後台 → 使用者 → 建立 Application Password
  2. AI 用 Basic Auth(Authorization: Basic base64(user:app_password))呼叫 /wp-json/wp/v2/pages/{id}
  3. 用 PATCH 更新頁面的 content 欄位(包含 Elementor 的 _elementor_data postmeta)

能做什麼

風險評估

風險項目等級說明
Token 洩漏Application Password 被截取,攻擊者可用對應帳號全部權限操作
預設繞過 2FAApplication Passwords 本來就設計成繞過登入流程,不經過 2FA 驗證
用戶枚舉/wp-json/wp/v2/users 預設公開,洩漏帳號資訊
Elementor data 損壞直接寫 _elementor_data JSON 格式若有誤,會導致頁面 Elementor 資料損毀
低權限帳號建立 App Password預設所有角色(含 Subscriber)都能建立 App Password

Token 洩漏最壞情況

管理員帳號:攻擊者取得全站控制權,可安裝惡意外掛、建立後門帳號、竄改所有內容。

Editor 帳號:攻擊者可修改 / 刪除所有文章頁面,但無法更動外掛、主題、系統設定。

SEO / 穩定性影響

直接更新 post_content 可能觸發 Elementor CSS 重新快取需求

若 Elementor JSON 格式錯誤,頁面會顯示為純文字而非設計稿

不影響 SEO 結構本身,但若不刷新快取,CDN 可能繼續服務舊版本

方案 3:Elementor MCP Plugin
2025–2026 年新興方案,已有現成外掛可用

現有外掛選項

外掛功能授權備注
bvisible/elementor-mcp-api REST API + MCP 協議,Widget 級別操作 GPL-3.0 最完整,可 PATCH 單一 widget
msrbuilds/elementor-mcp 97 個 AI 工具,涵蓋 layout + widget 未知 功能最豐富
Royal MCP MCP Server + OAuth 2.0 + 限速 + 日誌 商業 安全機制最完整

運作方式

  1. 安裝外掛後,在 Claude Code 的 MCP 設定加入此 server
  2. Claude 可直接呼叫 update_widget_content(page_id, widget_id, html) 等工具
  3. 省去手動構建 REST 請求的步驟

風險評估

風險項目等級說明
外掛本身的漏洞第三方外掛,需評估維護頻率和程式碼品質
平行操作覆蓋多個 PATCH 請求並行會互相覆蓋(已知問題)
CSS 快取未刷新需在每次更新後呼叫 /flush-css endpoint
Token 洩漏使用 Application Passwords,風險同方案 1

特別注意:bvisible/elementor-mcp-api 的 Elementor widget ID 是 8 字元 hex,要先用 GET 取得頁面結構才能知道正確 ID。

方案 4:SSH/SFTP 直接改檔案 不推薦
風險最高,不推薦用於 AI 自動化

風險評估

風險項目等級說明
SSH key 洩漏極高攻擊者取得整台伺服器控制權,不只是 WordPress
誤刪系統檔案AI 操作失誤可能刪除核心 WordPress 檔案
沒有 WordPress 層的驗證繞過所有 WP 的 permission 和 hook 機制
Elementor data 損壞直接修改 DB dump 或主題檔案極易出錯
難以審計SSH 操作難以追蹤到具體的 WordPress 層變更

Token 洩漏最壞情況:完整伺服器控制,資料庫可被 dump,可植入後門。

方案 5:WP-CLI 遠端執行 不推薦
需要 SSH 存取,風險與方案 4 類似,但稍微受控

運作方式

Bash
# 透過 SSH 遠端執行 WP-CLI
ssh user@kunhang.com.tw "wp post update 123 --post_content='<new content>'"

風險評估

風險項目等級說明
需要 SSH 存取同方案 4,SSH key 洩漏風險
可執行任意 PHPwp eval 可執行任意 PHP 程式碼
審計能力WP-CLI 有 activity log 外掛可搭配
比純 SSH 受控低(相對)操作在 WP 框架內,不能直接改伺服器系統檔
方案 6:第三方外掛(WPCode / Custom CSS & JS)
功能受限,適合特定用途

WPCode 主要用途是管理 code snippets(PHP/CSS/JS),沒有原生 REST API 讓外部系統操作。目前沒有成熟的 WPCode REST API 方案可讓 AI 透過 API 新增 / 修改 snippets。

評估:對 Elementor HTML Widget 的修改需求不適用此方案。

三、管制措施詳解

3.1 最小權限原則

PHP — 建立專用 AI Agent 角色
// 在 mu-plugin 或 functions.php 中建立專用角色
function create_ai_agent_role() {
    add_role('ai_agent', 'AI Agent', [
        'read' => true,
        // 只給能修改頁面的最小能力
        'edit_pages' => true,
        'edit_published_pages' => true,
        // 明確不給的能力
        'publish_pages' => false,  // 不能直接發佈
        'install_plugins' => false,
        'manage_options' => false,
        'delete_pages' => false,
    ]);
    // 加入自訂能力
    $role = get_role('ai_agent');
    $role->add_cap('ai_edit_widgets');
}
add_action('init', 'create_ai_agent_role');

關鍵原則:

• AI 帳號預設只能寫 draft,不能直接 publish

• 完全不給 manage_options(不能動外掛 / 主題設定)

• 完全不給 install_plugins / activate_plugins

3.2 只允許改特定 Elementor Widget

PHP — 白名單 + 自動備份 + 狀態管控
// 在自訂 endpoint 中限制可操作的頁面
const ALLOWED_PAGE_IDS = [123, 456, 789];  // kunhang 網站的特定頁面 ID

function ai_update_elementor_widget(WP_REST_Request $request) {
    $page_id = $request->get_param('page_id');

    // 白名單檢查
    if (!in_array($page_id, ALLOWED_PAGE_IDS)) {
        return new WP_Error('forbidden', '此頁面不在允許修改清單中', ['status' => 403]);
    }

    // 建立修改前的 revision(備份)
    wp_save_post_revision($page_id);

    // 修改指定 widget 的 HTML
    $elementor_data = get_post_meta($page_id, '_elementor_data', true);
    $data = json_decode($elementor_data, true);

    $widget_id = $request->get_param('widget_id');
    $new_html  = wp_kses_post($request->get_param('html'));  // 清洗 HTML

    // 遞迴找到 widget 並更新
    $updated = update_widget_in_tree($data, $widget_id, $new_html);

    if (!$updated) {
        return new WP_Error('not_found', '找不到指定的 widget ID', ['status' => 404]);
    }

    // 儲存更新(狀態改為 pending review,不直接 publish)
    update_post_meta($page_id, '_elementor_data', wp_slash(json_encode($data)));
    wp_update_post(['ID' => $page_id, 'post_status' => 'pending']);

    // 記錄操作日誌
    ai_log_operation($page_id, $widget_id, get_current_user_id());

    return ['success' => true, 'message' => '修改已儲存為待審核狀態'];
}

3.3 備份和回滾機制

三層備份策略

層級機制恢復方式保留期
WordPress Revisions每次修改前自動建立 revision後台 → 頁面 → 版本最近 25 個版本
外掛備份(Duplicator / UpdraftPlus)每日排程備份整個網站外掛一鍵還原30 天
主機快照(若有)Hetzner / cPanel 層級快照主機控制台還原依主機商設定

Elementor 快取刷新(每次修改後必做):

REST API
POST /wp-json/neoservice/v1/flush-css

或透過 WP-CLI:

Bash
wp elementor flush-css

3.4 IP 白名單

方法一:Cloudflare WAF Rules(推薦,因 kunhang.com.tw 已用 Cloudflare)

Cloudflare Dashboard → Security → WAF → Custom Rules:

Cloudflare WAF Rule 條件
(http.request.uri.path contains "/wp-json/ai-kunhang/")
AND
(not ip.src in {你的Hetzner伺服器IP/32 Claude雲端IP/32})

→ 動作:Block

方法二:.htaccess(Apache)

Apache .htaccess
<LocationMatch "^/wp-json/ai-kunhang/">
    Order Deny,Allow
    Deny from all
    Allow from 195.x.x.x  # Hetzner Claude 伺服器 IP
</LocationMatch>

方法三:mu-plugin 層 IP 檢查

PHP — IP 白名單過濾
add_filter('rest_authentication_errors', function($result) {
    if (strpos($_SERVER['REQUEST_URI'], '/ai-kunhang/') !== false) {
        $allowed_ips = ['195.x.x.x'];  // Hetzner IP
        $client_ip = $_SERVER['HTTP_CF_CONNECTING_IP'] ?? $_SERVER['REMOTE_ADDR'];
        if (!in_array($client_ip, $allowed_ips)) {
            return new WP_Error('ip_blocked', '不允許的 IP', ['status' => 403]);
        }
    }
    return $result;
});

3.5 操作日誌 / 審計

建議外掛:WP Activity Log(wp-security-audit-log)

• 記錄所有 REST API 修改

• 包含:操作時間、IP、使用者、修改內容摘要

• 可設定異常告警(短時間大量修改)

PHP — 自訂輕量日誌
function ai_log_operation($page_id, $widget_id, $user_id) {
    $log_entry = [
        'time'      => current_time('mysql'),
        'user_id'   => $user_id,
        'page_id'   => $page_id,
        'widget_id' => $widget_id,
        'ip'        => $_SERVER['HTTP_CF_CONNECTING_IP'] ?? $_SERVER['REMOTE_ADDR'],
    ];
    // 寫入自訂 table 或 option(短期快取)
    $logs = get_option('ai_operation_logs', []);
    array_unshift($logs, $log_entry);
    $logs = array_slice($logs, 0, 100);  // 保留最近 100 筆
    update_option('ai_operation_logs', $logs);
}

3.6 雙重確認機制(AI 改完要人工確認才上線)

工作流程設計:

AI 呼叫 API ↓ 修改內容寫入 _elementor_data(存為 pending 狀態) ↓ 發送通知給管理員(Email / Discord webhook) ↓ 管理員審核預覽(WordPress 後台 → 預覽) ↓ 確認 → 手動 Publish 或 拒絕 → 還原 Revision

PHP — Discord Webhook 通知
function notify_admin_for_review($page_id, $widget_id) {
    $preview_url = get_preview_post_link($page_id);
    $message = "AI 已更新頁面 #{$page_id} 的 widget {$widget_id},請審核後發佈:{$preview_url}";

    wp_remote_post(DISCORD_WEBHOOK_URL, [
        'body' => json_encode(['content' => $message]),
        'headers' => ['Content-Type' => 'application/json'],
    ]);
}

四、推薦方案與實作路線圖

推薦方案:「自訂最小 REST Endpoint + MCP」雙軌架構

理由:①攻擊面最小——只暴露允許頁面的 widget 修改 ②效率最高——AI 直接呼叫,不需複製貼上 ③可追溯——每次操作都有 revision + 日誌 ④人工確認門——AI 改完存為 pending,人確認才發佈 ⑤Cloudflare IP 白名單——非 Hetzner 伺服器的請求直接 Block

實作優先順序

1
Phase 1:最基本可用版本
預計 1–2 天
  • 建立 ai_agent WordPress 角色
  • 產生 Application Password
  • Cloudflare IP 白名單規則
  • 測試用標準 REST API(方案 1)+ 手動刷 Elementor 快取
2
Phase 2:安全強化
預計 3–5 天
  • 撰寫自訂 mu-plugin(方案 2)
  • 頁面 ID 白名單
  • 強制 pending 狀態
  • Discord webhook 通知
  • 操作日誌
3
Phase 3:MCP 整合
視需要
  • 安裝 elementor-mcp-api 外掛
  • 在 Claude Code MCP 設定中加入
  • 測試 widget ID 查找 + 更新流程

風險矩陣總覽

威脅場景發生機率影響程度緩解措施
Application Password 洩漏低–中(Editor 角色限制)IP 白名單 + 最小角色
Elementor JSON 格式錯誤(頁面顯示異常)API 層 JSON 驗證 + Revision
AI 誤更新錯誤頁面頁面 ID 白名單
外部攻擊者偽裝呼叫(IP 白名單阻擋)Cloudflare WAF
直接 publish 而不 pending(跳過人工審核)API 強制 pending 狀態
Elementor CSS 快取未刷新(舊樣式短暫顯示)API 呼叫完自動刷快取

五、給 kunhang.com.tw 的具體建議

絕對不做

不要給 AI 帳號 SSH 存取Admin 角色。就算要方便,這兩個的風險邊界太寬,一旦洩漏就是全站(甚至全伺服器)淪陷。

六、參考資源

研究日期:2026-05-29  |  適用專案:kunhang.com.tw