如何應用WordPress的自訂區塊(Meta Box)和自訂欄位(Custom Fields)?


作者: | 2011/03/30 19:19:49 | 3 則迴響


什麼是自訂欄位?
所謂的自訂欄位(Custom Fields)是指WordPress內建的自訂欄位功能(見圖),它能讓每篇文章都附掛一些屬於該文章的自訂資料,例如你希望儲存每篇文章的英文標題,以便能在前端佈景中呈現出來,開發者就能設計一個自訂欄位來儲存該篇文章的英文標題。於是使用者就能在後台建立文章時,利用自訂欄位來設定英文標題,或進行更多其他資料的擴充。而且自訂欄位不受限於內容型別,也就是說除了內建的文章(Post)、網誌分頁(Page)…等,也能使用自訂的內容型別。

自訂欄位能讓開發人員可以預先自訂最多30組由「名稱」對應「值」的文字框欄位,提供給使用者或程式去存取,當然也不一定限於要在後台寫入,寫入的時間點可以是任何的Hook時間點,就看你想做出什麼樣的功能。常見的運用是在後台由使用者存好自訂資料後發佈,就能在前台輸出佈景時,隨著取出該文章的內容時,也取出其附掛的自訂資料來做出一些功能或特效。常見的應用像是計算每篇文章的瀏覽次數、存放縮圖路徑…等,都是自訂欄位的應用。

為何要使用自訂區塊(meta box)來包裝自訂欄位?
直接使用自訂欄位的相關Function,對開發人員來說快速又方便,如add_post_meta、update_post_meta及delete_post_meta等,缺點是使用者必須將就一點,使用預設的UI,而且還需要「聰明」一點,需要知道每個特定的自訂欄位有什麼特殊效果,何況要達成某些效果,有些還要設定多個自訂欄位。因此如果後台要提供給新手使用者操作,看到自訂欄位預設的UI,可能會覺得很醜或覺得難用。

要改善自訂欄位的使用性問題,我們可以透過建立自訂區塊(Meta Box)來「包裝」一下自訂欄位的UI。是的,Meta Box骨子裡還是用自訂欄位相關的操作Function來存取設定值。使用Meta Box可讓開發人員建立自訂的區塊,如此可達成包裝原本自訂欄位的UI,您可以放文字框、下拉方塊、勾選鈕…等,甚至是一個所見即所得的編輯介面(Editor)都行,讓後台能擁有更友善的操作介面。

實例應用說明
文章一開始提到的「英文選單標題」的例子,很適合當成範例說明,我們就來看看怎麼應用Meta Box吧,要試試看的話,首先打開您佈景中的functions.php,加入以下程式:


/* 小範例:建立英文選單標題 */
add_action('admin_init', 'admin_init_fn'); // 指定後台初始化時要執行我們自訂的函式admin_init_fn

function admin_init_fn() {
    // 使用add_meta_box來增加一個「自訂區塊」,在callback的參數位置,放上我們自訂的函式 EnTitleCB_fn
    add_meta_box('EnTitle', '英文標題', 'EnTitleCB_fn', 'page', 'normal', 'high', null);
}

function EnTitleCB_fn() {
    // 需要取得目前編輯的post資訊,如id
    global $post;
    // 如果是進入編輯模式,WP會POST資料進來
    $entitle_cnt = get_post_meta( $post->ID, 'EnTitle', true );
    ?>
    <th scope="row">主選單英文標題:</th>
    <td>
        <label for="EnTitle">
            <input id="EnTitle" type="text" size="75" name="EnTitle" value="<?php echo $entitle_cnt;?>" />
            <br /><em>說明:設定分頁出現在選單時的英文翻譯。</em>
        </label>
    </td>
</tr>
<?php
}

加入上述程式碼,WP會在後台初始化時呼叫我們寫的函式admin_init_fn,然後發現我們寫了一個add_meta_box,就為我們在後台加上一個自訂區塊叫「英文標題」,並且依照我們給的CallBack函式定義,輸出自訂區塊的外觀。

是的,目前只有「外觀」! 如果真的輸入值,按下「更新」,還是無法被儲存,因為我們還要在使用者儲存文章時,一併的把我們的值也存起來,所以還要在functions.php加上一些程式碼:


add_action('wp_insert_post', 'insert_post_fn', 10, 2); // 讓WP在新增文章內容時,也執行我們定義的insert_post_fn

function insert_post_fn($post_id, $post = null) {
    $meta_post_fields = array("EnTitle"); // EnTitle是我們定義的input的name
    $goloop = false;

    // 如果是我們要處理的內容型別-page (讓自訂的meta box只出現在網誌分頁裡的文章)
    if ($post->post_type == "page") {
        $mfs = $meta_post_fields;
        $goloop = true;
    }

    if ($goloop) {
        // 取得Post進來的欄位資料,針對我們自訂的欄位$meta_fields
        foreach ($mfs as $key) {
            // 如果有空值就不進行處理
            $value = @$_POST[$key];
            if (empty($value)) {
                delete_post_meta($post_id, $key);
                continue;
            }

            // 如果丟過來的參數不是陣列
            if (!is_array($value)) {
                // 更新資料,若無法更新,代表是要新增資料
                if (!update_post_meta($post_id, $key, $value)) {
                    add_post_meta($post_id, $key, $value);
                }
            }else{
                // 如果丟過來的參數是陣列,先刪除之前的值,再一個個建進相同名稱的post meta
                delete_post_meta($post_id, $key);

                // Loop through the array adding new values to the post meta as different entries with the same name
                foreach ($value as $entry) {
                    add_post_meta($post_id, $key, $entry);
                }
            }
        }
    }
}

我們從meta box裡面的input所丟出來的值也可能是陣列,但這有機會再介紹。加入上述的程式碼,最後我們就能得到如下圖的結果,值也能存起來,不過因為我們使用了add_post_meta來幫助我們把值存在自訂欄位中,所以我們存的值也會自動出現在自訂欄位裡。

覺得自訂欄位區塊很多餘嗎?加入以下的程式碼,就可以移除它囉!


function remove_post_custom_fields() {
    remove_meta_box( 'postcustom' , 'post' , 'normal' );
}
add_action( 'admin_menu' , 'remove_post_custom_fields' );

成功的使用add_post_meta儲存每篇文章的自訂資料後,我們就可以在前台使用get_post_meta把我們在每篇文章存的值取出來用,只要指定post id和欄位名稱就可以把對應的值取出來囉,是不是很方便呢?

如此您也能打造一個專業又好用的WP客製介面!

參考資料:WordPress API – Meta Box


標籤:,

分類:,

本文作者是Audi Lu

3 則留言

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。

*

*

*

這個網站採用 Akismet 服務減少垃圾留言。進一步瞭解 Akismet 如何處理網站訪客的留言資料