前言
在 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">編輯 |