Bài 07: Custom Meta Boxes - Metadata trong WordPress

WordPress là một CMS nên hệ thống dữ liệu của nó chỉ dừng lại ở một mức độ nào đó, nghĩa là bạn không thể thêm bớt các field một cách tự tiện được vì điều này sẽ làm cho hệ thống cấu trúc của nó bị phá vỡ. Tuy nhiên vấn đề này đã được khắc phục bởi WordPress sử dụng mô hình EAV (Entity-Attribute-Value), đây là mô hình cho phép bạn thêm một field bất kì bởi mối quan hệ (1 - n) giữa các table.

Trước tiên chúng ta tìm hiểu mô hình này đã nhé :)

1. Mô hình EAV trong WordPress

EAV là chữ viết tắt của Entity-Attribute-Value, đây là mô hình cho phép mỗi table có thể tạo ra nhiều trường lưu trữ khác nhau. Mô hình này thường áp dụng với những CMS hoặc lưu trữ cho những hệ thống đa ngôn ngữ.

Trong WordPress có nhiều table áp dụng mô hình này, tuy nhiên mình chỉ đưa ra 2 table postspostmeta thôi bởi vì đa số chúng ta sử dụng nó thường xuyên.

Với cấu trúc này thì table postmeta đóng vai trò lưu trữ các thuộc tính cho table posts, vì vậy nó có một khóa ngoại là post_id. Nói là khóa ngoại nhưng thực chất khi bạn cài đặt WordPress thì nó sẽ không thiết lập các tham chiếu, vì vậy ta có thể coi đây là 2 bảng tách biệt không có mối quan hệ khóa ngoại (vẫn join được nhé các bạn).

Với mỗi bài viết bạn có thể thêm rất nhiều key cho nó và được lưu trữ trong bảng postmeta, field meta_key sẽ là tên của key và meta_value sẽ là giá trị của key. Ví dụ bạn cần luu trữ link_downloadlink_demo cho bài viết có id = 12 thì cách lưu trữ như sau:

ID post_id meta_key meta_value
# - auto increment 12 link_download http://freetuts.net/download.php
# - auto increment 12 link_demo http://freetuts.net/demo.php

Lúc này muốn lấy danh sách key của bài viết có id = 12 thì quá đơn giản phải không nào :)

2. WordPress Meta Boxes là gì?

Khi bạn đăng nhập vào admin và bạn edit một bài viết nào đó thì các khối trong giao diện ta gọi là các Meta Boxes. Vậy Meta Boxes là các khối hiển thị dữ liệu cho phép người dùng chỉnh sửa và lưu lại trong trang quản lý bài viết của WordPress.

Các vị trí mà mình kẻ ô màu đỏ chính là các Meta Boxes. Vậy mỗi Meta Box sẽ có những đặc điểm như thế nào? Làm sao để có thể phân biệt các Meta Boxes? Để trả lời câu hỏi này thì chúng ta tiếp tục tìm hiểu nhé.

3. Hàm add_meta_box trong WordPress

Hàm add_meta_box() dùng để thêm một Meta Box vào trong giao diện admin của WordPress, hàm này có cú pháp như sau:

add_meta_box($id, $title, $callback, $screen, $context, $priority, $callback_args);

Trong đó:

  • $id: Là ID của meta box, ID này phải là duy nhất không trùng với các Meta Boxes khác, kể cả các Meta Boxes mặc định của WordPress.
  • $title: Tiêu đề của Meta Box
  • $callback: Hàm callback dùng để hiển thị mã HTML nằm bên trong Meta Box
  • $screen: Hay còn gọi là page. Đối tượng mà Meta Box sẽ hiển thị, có thể là Page, Post hoặc là một custom post type.
  • $context: Vị trí mà Meta Box sẽ hiển thị bên trên giao diện. Chúng ta có ba vị trí đó là normal, advancedside.
  • $priority: Mức độ ưu tiên của Meta box, có bốn giá trị là default, core, high, và low.
  • $callback_args: Một mảng các tham số truyền vào Meta Box

Lưu ý: Action Hook của Meta Box có tên là add_meta_boxes.

Ví dụ: Thêm một Meta Box có tên là Thể Loại vào Post

Như thường lệ bạn tạo một file tên là my-meta-boxes.php nằm trong thư mục include và đừng quên require nó ở file wp-learn.php nhé. Nếu bạn chưa biết cấu trúc thì hãy xem lại bài tìm hiểu plugin là gì nhé.

Tiếp theo bạn hãy nhập nội dung sau vao file vừa tạo trên.

function add_metabox()
{
    add_meta_box('the-loai', 'Thể Loại', 'show_metabox_contain', 'post', 'advanced', 'high', array(1, 2, 3));
}

function show_metabox_contain($post, $metabox)
{
    echo "Nội dung của metabox";
}

add_action('add_meta_boxes', 'add_metabox');

Bạn vào admin edit một bài post bất kì thì sẽ thấy một ô với giao diện như sau:

Bây giờ ta sẽ tìm hiểu chi tiết hơn nữa nhé.

Tham số truyền vào hàm callback

Như ở ví dụ trên thì trong hàm callback mặc định sẽ có hai tham số truyền vào, tham số đầu tiên là $post và đây chính là một đối tượng lưu trữ thông tin của bài viết hiện tại. Tham số thứ hai là $metabox lưu trữ thông tin của metabox như $id, $title và các $callback_args

Bây giờ bạn sửa lại hàm show_metabox_contain() như sau:

function show_metabox_contain($post, $metabox)
{
    var_dump($post);
    var_dump($metabox);
}

Chạy lên bạn sẽ thấy giao diện như sau:

Bạn để ý phần in giá trị của $metabox sẽ có một key là args, đây chính là giá trị các tham số truyền vào lúc add_meta_box.

$context và $priority

Đây là hai giá trị mà có lẽ bạn thắc mắc nhất phải không nào :) Thực ra nó không có gì to tác cả mà chỉ là vị trí hiển thị của meta box trong giao diện thôi.

  • $context là vị trí hiển thị, chúng ta có hai vị trí chính đó là bên sidebar và main contain.
  • $priority là độ ưu tiên hiển thị, bạn hãy tự mình thay đổi các giá trị để xem kết quả nhé.

4. Căn bản về Meta data

Vấn đề về xử lý meta data rất nhiều và mình sẽ dành nó ở một bài nâng cao, vì vậy trong phần này mình sẽ hướng dẫn các bạn cách sử dụng căn bản thôi nhé.

Trước khi đọc phần 4 này thì bạn hãy xem kỹ phần 1 nhé vì ở đó mình có giới thiệu cách lưu trữ của bảng postmeta.

Hiển thị giao diện

Giả sử trong phần Meta box thể loại mình sẽ có 3 loại đó là video, text hoặc image, lúc này trong hàm hiển thị nội dung meta box ta sẽ show nó ra ở dạng select để người dùng chọn. Bạn sửa lại hàm show_metabox_contain như sau:

function show_metabox_contain($post, $metabox)
{
    // Input hidden bảo mật
    wp_nonce_field(basename(__FILE__), "meta-box-the-loai-nonce");
    ?>
    <select name="meta-box-the-loai">
        <?php 
            // Danh sách thể loại
            $option_values = array('Video', 'Image', "Text");

            // Lấy thông tin trong database
            $the_loai = get_post_meta($post->ID, "meta-box-the-loai", true);
                    
            // Lặp qua các thể loại và thiết lập selected
            foreach($option_values as $key => $value) 
            {
                if($value == $the_loai)
                {
                    ?>
                        <option selected value="<?php echo $value; ?>"><?php echo $value; ?></option>
                    <?php    
                }
                else
                {
                    ?>
                        <option value="<?php echo $value; ?>"><?php echo $value; ?></option>
                    <?php
                }
            }
        ?>
    </select>
    <?php 
}

Chạy lên bạn sẽ thấy giao diện như sau:

Mình sẽ giải thích nội dung của hàm này một chút.

Đoạn code dưới đây ta có thể ví nó như là một input hidden dùng để xử lý vấn đề bảo mật, nó sẽ sinh ra một ô input hidden bạn có thể dùng firebug để xem.

wp_nonce_field(basename(__FILE__), "meta-box-the-loai-nonce");

Đoạn code dưới đây sẽ lấy thông tin trong bảng postmeta, tham số truyền vào là ID và KEY cần lấy, giá trị true sẽ nói cho WordPress biết là sẽ trả về giá trị đơn thay vì trả về một mảng (đỡ mất công phải xử lý mảng để lấy giá trị).

$the_loai == get_post_meta($post->ID, "meta-box-the-loai", true);

Các đoạn code còn lại thì quá đơn giản rồi :)

Xử lý lưu dữ liệu

Trên là vấn đề hiển thị giao diện, tiếp theo chúng ta cần phải xử lý lưu lại thông tin. Để lưu trữ thông tin thì ta sẽ phải sử dụng một Hook Action tên là save_post, action này sẽ xảy ra khi người dùng click save bài viết. Bây giờ bạn bổ sung một đoạn code sau vào phía bên dưới của file my-meta-boxes.php.

function save_metabox_data($post_id, $post, $update)
{
    // Đây chính là input hidden Security mà ta đã tạo ở hàm show_metabox_contain
    if (!isset($_POST["meta-box-the-loai"]) || !wp_verify_nonce($_POST["meta-box-the-loai-nonce"], basename(__FILE__)))
    {
        return $post_id;
    }
    
    // Kiểm tra quyền
    if(!current_user_can("edit_post", $post_id))
    {
        return $post_id;
    }
        
    // Nếu auto save thì không làm gì cả
    if(defined("DOING_AUTOSAVE") && DOING_AUTOSAVE)
    {
        return $post_id;
    }
    
    // Vì metabox này dành cho Post nên phải kiểm tra có đúng vậy không?
    if('post' != $post->post_type){
        return $post_id;
    }
        

    // Lấy thông tin từ client
    $metabox_the_loai = (isset($_POST["meta-box-the-loai"])) ? $_POST["meta-box-the-loai"] : '';
    
    // Cập nhật thông tin, hàm này sẽ tạo mới nếu như trong db chưa tồn tại
    update_post_meta($post_id, "meta-box-the-loai", $metabox_the_loai);
}

add_action('save_post', 'save_metabox_data', 10, 3);

Trong code mình có giải thích rồi nên mình không giải thích lại nữa. 

Và đây chính là toàn bộ nội dung của file my-meta-boxes.php.

/*PHẦN HIỂN THỊ BOX META*/
function add_metabox()
{
    add_meta_box('the-loai', 'Thể Loại', 'show_metabox_contain', 'post', 'advanced', 'high', array(1, 2, 3));
}

function show_metabox_contain($post, $metabox)
{
    // Input hidden bảo mật
    wp_nonce_field(basename(__FILE__), "meta-box-the-loai-nonce");
    ?>
    <select name="meta-box-the-loai">
        <?php 
            // Danh sách thể loại
            $option_values = array('Video', 'Image', "Text");

            // Lấy thông tin trong database
            $the_loai = get_post_meta($post->ID, "meta-box-the-loai", true);
                    
            // Lặp qua các thể loại và thiết lập selected
            foreach($option_values as $key => $value) 
            {
                if($value == $the_loai)
                {
                    ?>
                        <option selected value="<?php echo $value; ?>"><?php echo $value; ?></option>
                    <?php    
                }
                else
                {
                    ?>
                        <option value="<?php echo $value; ?>"><?php echo $value; ?></option>
                    <?php
                }
            }
        ?>
    </select>
    <?php 
}

add_action('add_meta_boxes', 'add_metabox');


/*PHẦN XỬ LÝ LƯU TRỮ TRONG CSDL*/
function save_metabox_data($post_id, $post, $update)
{
    // Đây chính là input hidden Security mà ta đã tạo ở hàm show_metabox_contain
    if (!isset($_POST["meta-box-the-loai"]) || !wp_verify_nonce($_POST["meta-box-the-loai-nonce"], basename(__FILE__)))
    {
        return $post_id;
    }
    
    // Kiểm tra quyền
    if(!current_user_can("edit_post", $post_id))
    {
        return $post_id;
    }
        
    // Nếu auto save thì không làm gì cả
    if(defined("DOING_AUTOSAVE") && DOING_AUTOSAVE)
    {
        return $post_id;
    }
    
    // Vì metabox này dành cho Post nên phải kiểm tra có đúng vậy không?
    if('post' != $post->post_type){
        return $post_id;
    }
     
    // Lấy thông tin từ client
    $metabox_the_loai = (isset($_POST["meta-box-the-loai"])) ? $_POST["meta-box-the-loai"] : '';
    
    // Cập nhật thông tin, hàm này sẽ tạo mới nếu như trong db chưa tồn tại
    update_post_meta($post_id, "meta-box-the-loai", $metabox_the_loai);
}

add_action('save_post', 'save_metabox_data', 10, 3);

Hãy chạy lên và thử lưu lại xem kết quả có đúng không nhé :) Nếu sai thì tức là bạn đã thực hiện các thao tác bị lỗi rồi đấy.

5. Lời kết

Như vậy mình đã giới thiệu toàn bộ kiến thức về Meta Boxes và cách tạo Meta Box trong WordPress. Bên cạnh đó mình có giới thiệu sơ lược về cách sử dụng metadata, đặc biệt là hai hàm update_post_meta và get_post_metaBài tiếp theo chúng ta sẽ tìm hiểu rõ hơn về cách sử dụng Metadata.

Hãy để lại link bài viết gốc khi chia sẻ bài viết này, mình sẽ report DMCA với những website lấy nội dung mà không để nguồn hoặc copy bài với số lượng lớn.

Nguồn: freetuts.net

Profile photo of adminTheHalfHeart

TheHalfHeart

Có sở thích viết tuts nên đã từng tham gia viết ở một số diễn đàn, đến năm 2014 mới có điều kiện sáng lập ra freetuts.net. Sinh năm 90 và có 1 vợ 2 con, thích ca hát và lập trình.

ĐĂNG BÌNH LUẬN: Đăng câu hỏi trên Group Facebook để được hỗ trợ nhanh nhất.