WordPress 自訂文章類型批次內容關鍵字取代工具實作

前言

在 WordPress 後台管理自訂文章類型(Custom Post Type)時,有時需要快速批次更新文章內容中的特定字串。這段程式碼示範如何在名為 solution 的自訂文章類型新增一個子選單,提供後台管理者輸入舊字串與新字串,並批次替換所有相關文章內容中的文字。適合有基本 WordPress 開發經驗,想要自訂後台功能以提升內容維護效率的工程師或自學者。

新增子選單介面

利用 admin_menu action 新增子選單,並限定該選單只在 solution 文章類型下顯示。權限設定為 edit_posts,確保只有有編輯文章權限的使用者能操作。

add_action('admin_menu', function () {
    if (!post_type_exists('solution')) {
        return;
    }

    add_submenu_page(
        'edit.php?post_type=solution',
        '內容關鍵字取代',
        '內容關鍵字取代',
        'edit_posts',
        'solution-content-replace',
        'solution_content_replace_page'
    );
});

這段程式碼確保子選單只會在 solution 文章類型的管理頁面出現,並且點擊後會呼叫 solution_content_replace_page 函式來渲染頁面。

後台頁面與表單處理

solution_content_replace_page 函式負責顯示輸入表單與處理替換邏輯。首先檢查使用者權限,避免未授權存取。接著使用 WordPress 的 Nonce 機制保障表單安全。

if (!current_user_can('edit_posts')) {
    wp_die('沒有權限。');
}

if (isset($_POST['solution_replace_submit'])) {
    check_admin_referer('solution_replace_action', 'solution_replace_nonce');

    $old = isset($_POST['old_keyword']) ? sanitize_text_field($_POST['old_keyword']) : '';
    $new = isset($_POST['new_keyword']) ? sanitize_text_field($_POST['new_keyword']) : '';

    // 進行批次替換
}

使用者輸入的舊字串與新字串會經過 sanitize_text_field 清理,避免 XSS 或其他安全問題。

批次搜尋與替換邏輯

當舊字串不為空時,使用 WP_Query 撈取所有 solution 文章的 ID,並逐篇讀取內容。若文章內容包含舊字串,則使用 str_replace 替換後,呼叫 wp_update_post 更新文章。

$query = new WP_Query([
    'post_type'      => 'solution',
    'post_status'    => 'any',
    'posts_per_page' => -1,
    'fields'         => 'ids',
]);

foreach ($query->posts as $post_id) {
    $post = get_post($post_id);
    if (!$post) {
        continue;
    }

    $content = $post->post_content;

    if (mb_strpos($content, $old) !== false) {
        $updated_content = str_replace($old, $new, $content);

        wp_update_post([
            'ID'           => $post_id,
            'post_content' => $updated_content
        ]);

        $results[] = [
            'id'     => $post_id,
            'title'  => $post->post_title,
            'status' => '已替換'
        ];
    }
}
wp_reset_postdata();

此處使用 mb_strpos 確保多字元編碼正確判斷字串位置,避免誤判。替換後的結果會存入 $results 陣列,供後續顯示。

結果呈現與使用者體驗

頁面會根據執行狀態顯示不同訊息:

  • 若未輸入舊字串,提醒使用者必須填寫。
  • 若找不到包含舊字串的文章,顯示資訊提示。
  • 若有替換成功的文章,列出文章 ID、標題、狀態與編輯連結,方便管理者後續檢視。

這樣的設計讓使用者能清楚知道批次操作的結果,並快速跳轉編輯。

實務應用與優化建議

此功能適合內容量大且需定期文字修正的網站,如產品說明、技術文件等。未來可擴充:

  • 支援正則表達式替換,提高靈活度。
  • 加入替換前後內容差異預覽,降低誤替換風險。
  • 加入分頁或批次處理,避免大量文章一次更新造成伺服器負擔。

常見問題與注意事項

  • 請確認使用者權限設定正確,避免誤用。
  • 替換操作無法還原,建議先備份資料庫。
  • 文字替換為純字串,不支援 HTML 或多語系複雜處理。

完整程式碼

<?php
// 在 solution post type 底下新增子選單:內容關鍵字取代
add_action('admin_menu', function () {
    if (!post_type_exists('solution')) {
        return;
    }

    add_submenu_page(
        'edit.php?post_type=solution',
        '內容關鍵字取代',
        '內容關鍵字取代',
        'edit_posts',
        'solution-content-replace',
        'solution_content_replace_page'
    );
});

// 後台頁面
function solution_content_replace_page() {
    if (!current_user_can('edit_posts')) {
        wp_die('沒有權限。');
    }

    $old = '';
    $new = '';
    $results = [];
    $executed = false;

    if (isset($_POST['solution_replace_submit'])) {
        check_admin_referer('solution_replace_action', 'solution_replace_nonce');

        $old = isset($_POST['old_keyword']) ? sanitize_text_field($_POST['old_keyword']) : '';
        $new = isset($_POST['new_keyword']) ? sanitize_text_field($_POST['new_keyword']) : '';

        $executed = true;

        if ($old !== '') {
            $query = new WP_Query([
                'post_type'      => 'solution',
                'post_status'    => 'any',
                'posts_per_page' => -1,
                'fields'         => 'ids',
            ]);

            foreach ($query->posts as $post_id) {
                $post = get_post($post_id);
                if (!$post) {
                    continue;
                }

                $content = $post->post_content;

                // 檢查舊字串是否存在
                if (mb_strpos($content, $old) !== false) {
                    // 替換
                    $updated_content = str_replace($old, $new, $content);

                    // 更新文章
                    wp_update_post([
                        'ID'           => $post_id,
                        'post_content' => $updated_content
                    ]);

                    $results[] = [
                        'id'     => $post_id,
                        'title'  => $post->post_title,
                        'status' => '已替換'
                    ];
                }
            }
            wp_reset_postdata();
        }
    }
    ?>

<div class="wrap">

<h2>Solution – 內容關鍵字取代</h2>

<p>此工具會掃描所有 <code>solution 文章的內容,將符合的字串批次替換。

<input type="text" id="old_keyword" name="old_keyword" class="regular-text" value="" placeholder="例如:舊字串">
<input type="text" id="new_keyword" name="new_keyword" class="regular-text" value="" placeholder="例如:新字串(可空白)">

取代結果

請輸入要搜尋的舊字串。

沒有任何文章包含「」。

ID 標題 狀態 編輯連結
<a href="" class="button button-small">編輯
<?php }