<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>taxonomy &#8211; 小豬日常</title>
	<atom:link href="https://piglife.tw/tag/taxonomy/feed/" rel="self" type="application/rss+xml" />
	<link>https://piglife.tw</link>
	<description>Hello World，一個紀錄生活與學習的地方</description>
	<lastBuildDate>Thu, 25 Dec 2025 05:53:50 +0000</lastBuildDate>
	<language>zh-TW</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9</generator>

<image>
	<url>https://piglife.tw/wp-content/uploads/2017/10/cropped-logo-1-32x32.png</url>
	<title>taxonomy &#8211; 小豬日常</title>
	<link>https://piglife.tw</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>WordPress Polylang 多語翻譯批次複製工具實作解析</title>
		<link>https://piglife.tw/technical-notes/wordpress-polylang-bulk-copy/</link>
					<comments>https://piglife.tw/technical-notes/wordpress-polylang-bulk-copy/#respond</comments>
		
		<dc:creator><![CDATA[小豬]]></dc:creator>
		<pubDate>Wed, 24 Dec 2025 22:21:27 +0000</pubDate>
				<category><![CDATA[技術筆記]]></category>
		<category><![CDATA[acf]]></category>
		<category><![CDATA[Polylang]]></category>
		<category><![CDATA[taxonomy]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[多語翻譯]]></category>
		<category><![CDATA[批次複製]]></category>
		<category><![CDATA[特色圖片]]></category>
		<guid isPermaLink="false">https://piglife.tw/technical-notes/wordpress-polylang-bulk-copy/</guid>

					<description><![CDATA[介紹一款基於 Polylang 官方 API 的 WordPress 多語翻譯批次複製工具，支援任意...]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">前言</h2>
<p>在多語網站開發中，使用 Polylang 外掛管理翻譯文章是一種常見做法。但當需要將大量文章從某一語言批次複製到另一語言時，手動操作效率低且容易出錯。這段程式碼提供一個獨立於特定文章類型的批次翻譯複製工具，適合有基礎 WordPress 與 Polylang 使用經驗的工程師或自學者，幫助快速複製文章並保持翻譯關聯。</p>
<h2 class="wp-block-heading">工具功能與設計架構</h2>
<h3 class="wp-block-heading">1. 固定來源語言與多目標語言選擇</h3>
<p>程式碼中定義常數 <code>IR_SOURCE_LANG</code> 為來源語言（此處固定為中文 zh），目標語言則可從下拉選單選擇（預設有英文 en、日文 ja），方便擴充其他語言。</p>
<h3 class="wp-block-heading">2. 獨立後台介面</h3>
<p>透過 <code>add_submenu_page</code> 將工具掛載於 WordPress 後台「工具」選單下，並提供兩種操作模式：</p>
<ul>
<li>單筆測試：指定文章 ID，快速測試複製功能。</li>
<li>批次複製：依選定文章類型，批次複製該語言下所有文章。</li>
</ul>
<h3 class="wp-block-heading">3. 使用 Polylang 官方 API 確保語言設定與翻譯關聯</h3>
<p>核心複製流程依序使用 <code>wp_insert_post</code> 建立新文章，<code>pll_set_post_language</code> 設定語言，最後用 <code>pll_save_post_translations</code> 儲存翻譯群組關聯，確保與 Polylang 外掛的正確整合。</p>
<h2 class="wp-block-heading">核心複製流程解析</h2>
<h3 class="wp-block-heading">Step 1: 確認來源文章與語言</h3>
<p>先取得來源文章，確認文章類型與來源語言是否符合設定，避免誤複製。</p>
<pre><code class="lang-php language-php php">ir_set_lang_official( $source_id, IR_SOURCE_LANG );</code></pre>
<p>這行確保來源文章語言正確。</p>
<h3 class="wp-block-heading">Step 2: 建立新文章</h3>
<p>使用 <code>wp_insert_post</code> 複製文章標題、內容、狀態、作者、日期等基本欄位，確保新文章與原文一致。</p>
<h3 class="wp-block-heading">Step 3: 設定新文章語言</h3>
<p>新文章建立後，設定為目標語言，保持語言一致性。</p>
<h3 class="wp-block-heading">Step 4: 儲存翻譯關聯</h3>
<p>將新文章加入翻譯群組，讓 Polylang 知道這是原文的翻譯版本。</p>
<h3 class="wp-block-heading">Step 5: 複製分類法（Taxonomy）</h3>
<p>複製原文文章所屬的分類與標籤，但排除語言相關的 taxonomy，避免衝突。</p>
<h3 class="wp-block-heading">Step 6: 複製特色圖片</h3>
<p>如果原文有設定特色圖片，將同一張圖片設定給新文章，保持視覺一致性。</p>
<h3 class="wp-block-heading">Step 7: 複製 ACF 自訂欄位</h3>
<p>利用 Advanced Custom Fields (ACF) 官方 API 安全複製所有自訂欄位，避免欄位名稱變動造成錯誤。</p>
<h2 class="wp-block-heading">實務應用與優化建議</h2>
<ul>
<li><strong>資料備份</strong>：批次操作前務必備份資料庫，避免誤操作造成資料遺失。</li>
<li><strong>語言擴充</strong>：可依需求擴充 <code>$allowed_target_langs</code> 陣列，支援更多語言。</li>
<li><strong>效能考量</strong>：批次複製大量文章時，可能造成伺服器負擔，可分批執行或加入排程。</li>
<li><strong>錯誤處理</strong>：目前以回傳日誌方式呈現，可擴充為錯誤通知或記錄檔。</li>
</ul>
<h2 class="wp-block-heading">常見問題與注意事項</h2>
<ul>
<li>複製後的文章不會自動翻譯內容，僅複製原文內容，需後續人工或機器翻譯。</li>
<li>Polylang API 函式必須存在，否則功能無法使用。</li>
<li>ACF 複製需確保 ACF 外掛已啟用且函式存在。</li>
</ul>
<h2 class="wp-block-heading">完整程式碼</h2>
<pre><code>&lt;?php
/**
 * Universal Polylang Bulk Copy Tool (Final Version - FIXED)
 * - 獨立在「工具 &rarr; Bulk Copy Translations」底下（不綁每個 post type）
 * - 任意 Post Type 下拉選單選擇
 * - 來源語言固定 zh
 * - 目標語言下拉選（en / ja，可自行擴充）
 * - 單筆測試 / 批次處理
 * - 已存在翻譯自動跳過
 * - Polylang 官方流程：wp_insert_post + pll_set_post_language + pll_save_post_translations
 * - taxonomy / featured image / ACF 全欄位複製（ACF 安全寫法）
 *

if ( ! defined( &#039;ABSPATH&#039; ) ) {
    exit;
}

define( &#039;IR_SOURCE_LANG&#039;, &#039;zh&#039; ); // 固定來源語言（Polylang code）

/* =========================
 * 共用：設定語言（官方 API）
 * ========================= */
function ir_set_lang_official( $post_id, $lang_code ) {
    if ( function_exists( &#039;pll_set_post_language&#039; ) ) {
        pll_set_post_language( $post_id, $lang_code );
    }
}

/* =========================
 * 後台選單（獨立於 post type）
 * ========================= */
add_action( &#039;admin_menu&#039;, function () {
    add_submenu_page(
        &#039;tools.php&#039;,                         // 掛在「工具」
        &#039;Bulk Copy Translations (Official)&#039;, // 頁面標題
        &#039;Bulk Copy Translations&#039;,            // 左側選單名稱
        &#039;manage_options&#039;,                    // 權限
        &#039;ir-bulk-translations&#039;,              // slug
        &#039;ir_bulk_translations_page&#039;          // callback
    );
});

/* =========================
 * 後台頁面
 * ========================= */
function ir_bulk_translations_page() {

    if ( ! current_user_can( &#039;manage_options&#039; ) ) {
        wp_die( &#039;沒有權限。&#039; );
    }

    // Polylang API 檢查
    if ( ! function_exists( &#039;pll_set_post_language&#039; ) || ! function_exists( &#039;pll_save_post_translations&#039; ) ) {
        echo &#039;&lt;div class=&quot;notice notice-error&quot;&gt;&lt;p&gt;Polylang API 不存在，請確認 Polylang 是否啟用。&lt;/p&gt;&lt;/div&gt;&#039;;
        return;
    }

    // 允許的目標語言（依照 Polylang 的 code）
    $allowed_target_langs = [ &#039;en&#039;, &#039;ja&#039; ];

    // 可選 post types（public）
    $post_types = get_post_types( [ &#039;public&#039; =&gt; true ], &#039;objects&#039; );

    // 預設值
    $current_post_type = isset( $_POST[&#039;ir_post_type&#039;] ) ? sanitize_text_field( wp_unslash( $_POST[&#039;ir_post_type&#039;] ) ) : &#039;post&#039;;
    if ( ! isset( $post_types[ $current_post_type ] ) ) {
        $current_post_type = &#039;post&#039;;
    }

    $current_target = isset( $_POST[&#039;ir_target_lang&#039;] ) ? sanitize_text_field( wp_unslash( $_POST[&#039;ir_target_lang&#039;] ) ) : &#039;en&#039;;
    if ( ! in_array( $current_target, $allowed_target_langs, true ) ) {
        $current_target = &#039;en&#039;;
    }

    echo &#039;
&lt;h1&gt;通用翻譯複製工具（Polylang 官方流程）&lt;/h1&gt;&#039;;
    echo &#039;
&lt;p&gt;來源語言固定為：&lt;code&gt;&#039; . esc_html( IR_SOURCE_LANG ) . &#039;</code></p>';
    echo '<p style="color:#b32d2e"><strong>⚠️ 執行前請先備份資料庫</strong></p>';

    echo '

        .ir-box{background:#fff;border:1px solid #ccd0d4;padding:12px 14px;margin:12px 0;}
        .ir-row{margin:10px 0;}
        .ir-row label{display:inline-block;min-width:90px;font-weight:600;}
        .ir-pre{background:#fff;border:1px solid #ccd0d4;padding:10px;max-height:520px;overflow:auto;white-space:pre-wrap;}
    ';

    /* =========================
     * 單筆測試
     * ========================= */
    echo '<div class="ir-box">';
    echo '<div style="margin-top:0">單筆測試</div>';
    echo '';
    wp_nonce_field( 'ir_single' );

    echo '<div class="ir-row"><label>Post Type</label> ';
    echo '';
    foreach ( $post_types as $pt ) {
        printf(
            '%s (%s)',
            esc_attr( $pt-&gt;name ),
            selected( $current_post_type, $pt-&gt;name, false ),
            esc_html( $pt-&gt;labels-&gt;singular_name ),
            esc_html( $pt-&gt;name )
        );
    }
    echo '</div>';

    echo '<div class="ir-row"><label>文章 ID</label> ';
    echo '<input type="number" name="ir_test_id" required></div>';

    echo '<div class="ir-row"><label>目標語言</label> ';
    echo '';
    foreach ( $allowed_target_langs as $lang ) {
        printf(
            '%s',
            esc_attr( $lang ),
            selected( $current_target, $lang, false ),
            esc_html( strtoupper( $lang ) )
        );
    }
    echo '</div>';

    submit_button( '測試複製', 'secondary', 'ir_single_run' );
    echo '';
    echo '</div>';

    /* =========================
     * 批次處理
     * ========================= */
    echo '<div class="ir-box">';
    echo '<div style="margin-top:0">批次複製（來源語言：' . esc_html( IR_SOURCE_LANG ) . '）</div>';
    echo '';
    wp_nonce_field( 'ir_bulk' );

    echo '<div class="ir-row"><label>Post Type</label> ';
    echo '';
    foreach ( $post_types as $pt ) {
        printf(
            '%s (%s)',
            esc_attr( $pt-&gt;name ),
            selected( $current_post_type, $pt-&gt;name, false ),
            esc_html( $pt-&gt;labels-&gt;singular_name ),
            esc_html( $pt-&gt;name )
        );
    }
    echo '</div>';

    echo '<div class="ir-row"><label>目標語言</label> ';
    echo '';
    foreach ( $allowed_target_langs as $lang ) {
        printf(
            '%s',
            esc_attr( $lang ),
            selected( $current_target, $lang, false ),
            esc_html( strtoupper( $lang ) )
        );
    }
    echo '</div>';

    submit_button( '執行批次複製', 'primary', 'ir_bulk_run' );
    echo '';
    echo '</div>';

    /* =========================
     * 執行
     * ========================= */
    if ( isset( $_POST['ir_single_run'] ) ) {
        check_admin_referer( 'ir_single' );

        $post_id   = isset( $_POST['ir_test_id'] ) ? absint( $_POST['ir_test_id'] ) : 0;
        $target    = $current_target;
        $post_type = $current_post_type;

        echo '
<div>單筆結果</div>';
        $log = ir_clone_post( $post_id, $target, $post_type );

        echo '<pre class="ir-pre">' . esc_html( implode( "\n", $log ) ) . '</pre>';
    }

    if ( isset( $_POST['ir_bulk_run'] ) ) {
        check_admin_referer( 'ir_bulk' );

        $target    = $current_target;
        $post_type = $current_post_type;

        echo '
<div>批次結果（Post Type：' . esc_html( $post_type ) . '，目標語言：' . esc_html( strtoupper( $target ) ) . '）</div>';

        $posts = get_posts( [
            'post_type'      =&gt; $post_type,
            'posts_per_page' =&gt; -1,
            'post_status'    =&gt; 'any',
            'lang'           =&gt; IR_SOURCE_LANG, // Polylang 的語言 query var
            'fields'         =&gt; 'ids',
        ] );

        if ( empty( $posts ) ) {
            echo '
<p>找不到來源語言（' . esc_html( IR_SOURCE_LANG ) . '）的文章。</p>';
        } else {
            $output = [];
            foreach ( $posts as $id ) {
                $output = array_merge( $output, ir_clone_post( $id, $target, $post_type ) );
            }
            echo '<pre class="ir-pre">' . esc_html( implode( "\n", $output ) ) . '</pre>';
        }
    }

}

/* =========================
 * 核心：複製一篇文章 → 目標語言翻譯
 * ========================= */
function ir_clone_post( $source_id, $target_lang, $post_type ) {

    $log = [];

    if ( ! $source_id ) {
        return [ '❌ 文章 ID 不可為 0' ];
    }

    $src = get_post( $source_id );
    if ( ! $src ) {
        return [ "❌ 找不到文章 {$source_id}" ];
    }

    // 確保來源文章屬於選定的 post type（避免拿錯）
    if ( $src-&gt;post_type !== $post_type ) {
        return [ "❌ 文章 {$source_id} 的 post_type 是 {$src-&gt;post_type}，不是你選的 {$post_type}，已中止。" ];
    }

    // Step 1) 確保原文語言
    ir_set_lang_official( $source_id, IR_SOURCE_LANG );
    $log[] = "Step 1) 設定原文語言：{$source_id} → " . IR_SOURCE_LANG;

    // 取得翻譯群組
    $translations = function_exists( 'pll_get_post_translations' )
        ? pll_get_post_translations( $source_id )
        : [];

    if ( empty( $translations[ IR_SOURCE_LANG ] ) ) {
        $translations[ IR_SOURCE_LANG ] = $source_id;
    }

    // 已存在目標語言 → 跳過
    if ( ! empty( $translations[ $target_lang ] ) ) {
        $existing = (int) $translations[ $target_lang ];
        $log[] = "⚠️ 已存在 {$target_lang} 翻譯（ID {$existing}），跳過。";

        // debug 狀態
        if ( function_exists( 'pll_get_post_language' ) ) {
            $lang_debug = [];
            foreach ( $translations as $code =&gt; $pid ) {
                $lang_debug[] = $code . ':' . $pid . '(' . pll_get_post_language( $pid ) . ')';
            }
            $log[] = '🧪 目前語言狀態：' . implode( ', ', $lang_debug );
        }

        return $log;
    }

    // Step 2) 建立新文章
    $new_id = wp_insert_post( [
        'post_type'      =&gt; $post_type,
        'post_status'    =&gt; $src-&gt;post_status,
        'post_title'     =&gt; $src-&gt;post_title,
        'post_content'   =&gt; $src-&gt;post_content,
        'post_excerpt'   =&gt; $src-&gt;post_excerpt,
        'post_author'    =&gt; $src-&gt;post_author,
        'post_date'      =&gt; $src-&gt;post_date,
        'post_date_gmt'  =&gt; $src-&gt;post_date_gmt,
        'menu_order'     =&gt; $src-&gt;menu_order,
        'post_parent'    =&gt; $src-&gt;post_parent,
    ], true );

    if ( is_wp_error( $new_id ) ) {
        $log[] = '❌ wp_insert_post 錯誤：' . $new_id-&gt;get_error_message();
        return $log;
    }
    $log[] = "Step 2) 建立新文章：{$new_id}";

    // Step 3) 設定新文章語言
    ir_set_lang_official( $new_id, $target_lang );
    $log[] = "Step 3) 設定新文章語言：{$new_id} → {$target_lang}";

    // Step 4) 儲存翻譯關聯
    $translations[ $target_lang ] = $new_id;
    pll_save_post_translations( $translations );
    $log[] = 'Step 4) 儲存翻譯關聯：' . wp_json_encode( $translations );

    // Step 5) 複製 taxonomy（排除語言 taxonomy）
    $taxes = get_object_taxonomies( $post_type );
    $taxes = array_diff( $taxes, [ 'language', 'pll_language' ] );

    foreach ( $taxes as $tax ) {
        $terms = wp_get_object_terms( $source_id, $tax, [ 'fields' =&gt; 'ids' ] );
        if ( ! is_wp_error( $terms ) ) {
            wp_set_object_terms( $new_id, $terms, $tax, false );
        }
    }
    $log[] = 'Step 5) Taxonomy 複製完成';

    // Step 6) 複製特色圖片
    $thumb = get_post_thumbnail_id( $source_id );
    if ( $thumb ) {
        set_post_thumbnail( $new_id, $thumb );
        $log[] = 'Step 6) Featured Image 複製完成';
    } else {
        $log[] = 'Step 6) 原文沒有 Featured Image';
    }

    // Step 7) 複製 ACF 全欄位（官方安全寫法）
    if ( function_exists( 'get_field_objects' ) &amp;&amp; function_exists( 'update_field' ) ) {
        $fields = get_field_objects( $source_id );
        $count  = 0;

        if ( $fields ) {
            foreach ( $fields as $field ) {
                // 用 field key 複製最穩（不怕改欄位 name）
                update_field( $field['key'], $field['value'], $new_id );
                $count++;
            }
        }

        $log[] = "Step 7) ACF 全欄位複製完成（{$count} 個欄位）";
    } else {
        $log[] = 'Step 7) ACF API 不存在（get_field_objects / update_field），跳過 ACF 複製';
    }

    // 最後：語言檢查
    if ( function_exists( 'pll_get_post_language' ) ) {
        $src_lang_real = pll_get_post_language( $source_id );
        $new_lang_real = pll_get_post_language( $new_id );
        $log[] = "🧪 實際語言檢查：原文 {$source_id} 語言：{$src_lang_real}；新文 {$new_id} 語言：{$new_lang_real}";
    }

    $log[] = "✅ 完成：原文 {$source_id} → {$target_lang} 翻譯 {$new_id}";
    return $log;
}</code></pre>]]></content:encoded>
					
					<wfw:commentRss>https://piglife.tw/technical-notes/wordpress-polylang-bulk-copy/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>在 WordPress 頁面列表加入自訂分類篩選下拉選單</title>
		<link>https://piglife.tw/technical-notes/wordpress-page-taxonomy-filter/</link>
					<comments>https://piglife.tw/technical-notes/wordpress-page-taxonomy-filter/#respond</comments>
		
		<dc:creator><![CDATA[小豬]]></dc:creator>
		<pubDate>Wed, 10 Dec 2025 03:42:03 +0000</pubDate>
				<category><![CDATA[技術筆記]]></category>
		<category><![CDATA[taxonomy]]></category>
		<category><![CDATA[WordPress]]></category>
		<guid isPermaLink="false">https://piglife.tw/technical-notes/wordpress-page-taxonomy-filter/</guid>

					<description><![CDATA[在 WordPress 後台的頁面列表中，預設並沒有提供依自訂分類法（taxonomy）篩選頁面的功...]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">前言</h2>
<p>在 WordPress 後台的頁面列表中，預設並沒有提供依自訂分類法（taxonomy）篩選頁面的功能。這對於管理大量頁面且需要依分類快速查找的情境來說，十分不便。本文示範如何在頁面列表上方加入一個自訂分類的下拉選單，並讓該選單能真正影響頁面列表的查詢結果。</p>
<p>此範例適合對 WordPress 後台操作有基礎認識，並且希望透過程式碼自訂後台介面行為的工程師或自學者。</p>
<h2 class="wp-block-heading">在頁面列表加入 taxonomy 篩選下拉選單</h2>
<p>我們利用 <code>restrict_manage_posts</code> action，在頁面列表上方輸出一個下拉選單。這個下拉選單會列出指定 taxonomy（本例為 <code>page_cat</code>）的所有分類，讓使用者可以選擇篩選條件。</p>
<h3 class="wp-block-heading">關鍵程式碼片段</h3>
<pre><code class="lang-php language-php php">add_action( &#039;restrict_manage_posts&#039;, function() {
    global $typenow;

    // 只在頁面列表顯示
    if ( $typenow !== &#039;page&#039; ) {
        return;
    }

    $taxonomy = &#039;page_cat&#039;;
    $tax_obj  = get_taxonomy( $taxonomy );
    if ( ! $tax_obj ) {
        return;
    }

    $selected = isset( $_GET[$taxonomy] ) ? (int) $_GET[$taxonomy] : 0;

    wp_dropdown_categories( array(
        &#039;show_option_all&#039; =&gt; &#039;所有 &#039; . $tax_obj-&gt;labels-&gt;name,
        &#039;taxonomy&#039;        =&gt; $taxonomy,
        &#039;name&#039;            =&gt; $taxonomy,
        &#039;orderby&#039;         =&gt; &#039;name&#039;,
        &#039;selected&#039;        =&gt; $selected,
        &#039;hierarchical&#039;    =&gt; true,
        &#039;depth&#039;           =&gt; 3,
        &#039;show_count&#039;      =&gt; false,
        &#039;hide_empty&#039;      =&gt; false,
    ) );
} );</code></pre>
<p>這段程式碼的重點：</p>
<ul>
<li>只在頁面（post_type 為 <code>page</code>）的列表頁顯示。</li>
<li>使用 <code>wp_dropdown_categories()</code> 產生下拉選單，並以 taxonomy slug 作為 name，方便後續讀取。</li>
<li>透過 <code>$_GET</code> 讀取目前選擇的分類，保持選單狀態。</li>
</ul>
<h2 class="wp-block-heading">利用篩選條件修改查詢結果</h2>
<p>僅有下拉選單還不夠，我們必須讓 WordPress 查詢時根據選擇的 taxonomy 篩選頁面。這裡使用 <code>parse_query</code> filter，攔截後台頁面列表的查詢參數，並將 taxonomy 的 ID 轉換成 slug，塞入查詢條件。</p>
<h3 class="wp-block-heading">關鍵程式碼片段</h3>
<pre><code class="lang-php language-php php">add_filter( &#039;parse_query&#039;, function( $query ) {
    global $pagenow;

    // 只在後台頁面列表
    if ( ! is_admin() || $pagenow !== &#039;edit.php&#039; ) {
        return $query;
    }

    if ( ! isset( $query-&gt;query_vars[&#039;post_type&#039;] ) || $query-&gt;query_vars[&#039;post_type&#039;] !== &#039;page&#039; ) {
        return $query;
    }

    $taxonomy = &#039;page_cat&#039;;
    if ( isset( $_GET[$taxonomy] ) &amp;&amp; ! empty( $_GET[$taxonomy] ) &amp;&amp; (int) $_GET[$taxonomy] !== 0 ) {

        $term_id = (int) $_GET[$taxonomy];
        $term    = get_term_by( &#039;id&#039;, $term_id, $taxonomy );

        if ( $term ) {
            // 將 ID 轉為 slug，符合查詢格式
            $query-&gt;query_vars[$taxonomy] = $term-&gt;slug;
        }
    }

    return $query;
} );</code></pre>
<p>這段程式碼說明：</p>
<ul>
<li>僅在後台頁面列表 (<code>edit.php?post_type=page</code>) 生效。</li>
<li>從 <code>$_GET</code> 取得 taxonomy 篩選值，並轉換為 slug。</li>
<li>將 slug 設定到查詢變數中，讓 WordPress 查詢時套用此條件。</li>
</ul>
<h2 class="wp-block-heading">實務應用與延伸</h2>
<ul>
<li>可依照需求替換 <code>$taxonomy</code> 為其他自訂分類法。</li>
<li>若頁面數量龐大，搭配分頁與排序功能使用，能大幅提升管理效率。</li>
<li>若想支援多個 taxonomy 篩選，可依此模式複製擴充。</li>
<li>注意 taxonomy slug 與分類名稱必須正確，避免查詢失效。</li>
</ul>
<h2 class="wp-block-heading">常見問題與注意事項</h2>
<ul>
<li>若 taxonomy 沒有正確註冊或名稱錯誤，篩選下拉不會顯示。</li>
<li>篩選條件若為空或 0，會顯示所有頁面。</li>
<li>轉換 ID 為 slug 是為了符合 WordPress 查詢的格式，直接用 ID 會無效。</li>
</ul>
<h2 class="wp-block-heading">完整程式碼</h2>
<pre><code class="lang-php language-php php">&lt;?php
// 在「頁面列表」上方加入 taxonomy 篩選下拉
add_action( &#039;restrict_manage_posts&#039;, function() {
    global $typenow;

    // 只在「頁面」列表顯示
    if ( $typenow !== &#039;page&#039; ) {
        return;
    }

    $taxonomy = &#039;page_cat&#039;; // &larr; 換成你的 taxonomy slug
    $tax_obj  = get_taxonomy( $taxonomy );
    if ( ! $tax_obj ) {
        return;
    }

    $selected = isset( $_GET[$taxonomy] ) ? (int) $_GET[$taxonomy] : 0;

    wp_dropdown_categories( array(
        &#039;show_option_all&#039; =&gt; &#039;所有 &#039; . $tax_obj-&gt;labels-&gt;name,
        &#039;taxonomy&#039;        =&gt; $taxonomy,
        &#039;name&#039;            =&gt; $taxonomy,
        &#039;orderby&#039;         =&gt; &#039;name&#039;,
        &#039;selected&#039;        =&gt; $selected,
        &#039;hierarchical&#039;    =&gt; true,
        &#039;depth&#039;           =&gt; 3,
        &#039;show_count&#039;      =&gt; false,
        &#039;hide_empty&#039;      =&gt; false,
    ) );
} );

// 讓剛剛那個下拉選單的值，真的用來篩選頁面
add_filter( &#039;parse_query&#039;, function( $query ) {
    global $pagenow;

    // 只在後台頁面列表 edit.php?post_type=page
    if ( ! is_admin() || $pagenow !== &#039;edit.php&#039; ) {
        return $query;
    }

    if ( ! isset( $query-&gt;query_vars[&#039;post_type&#039;] ) || $query-&gt;query_vars[&#039;post_type&#039;] !== &#039;page&#039; ) {
        return $query;
    }

    $taxonomy = &#039;page_cat&#039;; // &larr; 同一個 taxonomy slug
    if ( isset( $_GET[$taxonomy] ) &amp;&amp; ! empty( $_GET[$taxonomy] ) &amp;&amp; (int) $_GET[$taxonomy] !== 0 ) {

        $term_id = (int) $_GET[$taxonomy];
        $term    = get_term_by( &#039;id&#039;, $term_id, $taxonomy );

        if ( $term ) {
            // 把 ID 換成 slug 給查詢用
            $query-&gt;query_vars[$taxonomy] = $term-&gt;slug;
        }
    }

    return $query;
} );</code></pre>]]></content:encoded>
					
					<wfw:commentRss>https://piglife.tw/technical-notes/wordpress-page-taxonomy-filter/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
