Cách tạo custom meta box và custom field trong WordPress không dùng plugin

Tính năng tạo custom fields mặc định trong WordPress giúp cho người dùng cuối tùy chỉnh website của họ khá nhanh và dễ dàng. Tuy nhiên, nó bị giới hạn bởi việc chỉ hỗ trợ các field dạng text. Và vì vậy, trong nhiều trường hợp, tính năng này không thể đáp ứng được hết nhu cầu của họ.

Trong bài viết này, chúng ta sẽ cùng tìm hiểu một cách khác hiệu quả hơn để tạo custom fields ở dạng field type bất kỳ mà bạn muốn nhé.

Yêu cầu:

Trước khi vào phần thực hiện chi tiết, mình cần phải lưu ý bạn một chút là để làm theo được các hướng dẫn này, bạn cần có một phần kiến thức cơ bản về các nội dung sau:

  1. PHP và HTML
  2. Cách tạo một plugin đơn giản trong WordPress

Trong WordPress, không có tính năng nào để tạo UI một cách trực tiếp cho việc tạo custom fields. Tất cả các tính năng liên quan đến custom fields đều được tạo thông qua một API tên là meta box. Vì vậy, hãy cùng tìm hiểu về meta box trước khi đi vào phần tạo custom fields nhé.

Meta box là gì?

Quay trở lại bài viết đầu tiên trong series này, chúng ta biết rằng định nghĩa về custom fields là:

Custom fields là một tính năng giúp chúng ta tạo các form và field để tương tác với metadata.

Như vậy, nói đến UI thì custom fields cũng được coi như là một dạng fields cho phép người dùng điền dữ liệu vào.

Trong trang chỉnh sửa bài viết của WordPress, bạn sẽ thấy một khu vực chứa các thông tin thêm vào bài viết như là ô Publish, ô Format, ô Category. Các thông tin này được nhóm lại vào một ô và ô này được gọi là “meta box”. Điều đó có nghĩa là các ô này chứa metadata. Đây chính là nguồn gốc cho cái tên của plugin Meta Box mà chúng ta vẫn hay dùng đó. Tuy nhiên, cụm từ “meta box” ở đây ý nói đến về các ô, chứ không phải nói đến plugin kia nhé.

Meta box trong trang chỉnh sửa bài viết.
Các meta box ở trong phần chỉnh sửa bài viết

Trong bài viết trước, meta box có tên là Custom Fields được sử dụng để thêm custom fields dạng text. Trong phần sau, chúng ta sẽ tạo một meta box có chứa nhiều loại field hơn nhé. Để làm được việc đó, chúng ta sẽ cần tạo một plugin nho nhỏ trước đã.

Tạo một plugin đơn giản cho custom fields

Tạo một plugin là cách phổ biến và nên làm để thêm các tính năng cho WordPress. Bây giờ, hãy cùng tạo một plugin đơn giản có tên là “Hello Custom Fields” nhé. Các bước cơ bản như sau:

  1. Tạo một folder có tên là hello-custom-fields bên trong thư mục wp-content/plugins.
  2. Trong folder vừa tạo, tạo một file php có tên là hello-custom-fields.php với nội dung như sau:
<?php
/**
Plugin Name: Hello Custom Field
Plugin URI: https://metabox.io
Description: A simple plugin for custom fields.
Version: 1.0
Author: Meta Box
Author URI: https://metabox.io
License: GPL2
*/

Bạn có thể tìm hiểu chi tiết hơn về cách tạo một plugin ở đây nhé.

Để dễ tưởng tượng thì chúng ta sẽ dùng plugin này để tạo các field cho phép người dùng điền các thông tin về một cuốn sách lên trang web. Các fields mà chúng ta cần tạo sẽ là:

  1. Author (tác giả): field dạng text
  2. Publish year (năm xuất bản): field dạng ngày tháng
  3. Price (giá): field dạng số

Những việc chúng ta sẽ cần làm tiếp theo đó là:

  1. Tạo một meta box
  2. Thêm các custom fields vào bên trong meta box trên
  3. Lưu các giá trị của custom fields vào database
  4. Hiển thị giá trị của mỗi field lên frontend

Cụ thể thao tác như sau:

Tạo một meta box

WordPress có một hàm là add_meta_box để thêm meta box vào bất cứ trang nào bạn muốn. Hàm này có cấu trúc như sau:

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

Trong đó:

NameDescription
$idID của meta box đang tạo
$title Tên của meta box
$callbackNhập nội dung mong muốn cho meta box và trả về đúng giá trị đó
$screenNơi sẽ hiển thị meta box (ví dụ như là post type hay là link, comment)
$contextChính xác vị trí mà meta box được hiển thị trên trang, ở dưới post editor, post title, hay là sidebar, … Thường thuộc tính này có giá trị mặc định là advanced.
$priorityMức độ ưu tiên hiển thị của meta box. Giá trị mặc định là high tức là độ ưu tiên cao > sẽ hiển thị bên trên những meta box có mức độ ưu tiên là low.
$callback_argsDữ liệu sẽ được đặt vào thuộc tính $args của meta box (là tham số thứ hai được trả về). Giá trị mặc định là null.

Chúng ta sẽ tạo một meta box với tên tiêu đề (title) là Hello Custom Fields và hiển thị nó trong phần chỉnh sửa một bài viết (post). Bạn mở file hello-custom-fields.php lên và thêm đoạn code này vào nhé:

/**
 * Register meta boxes.
 */
function hcf_register_meta_boxes() {
    add_meta_box( 'hcf-1', __( 'Hello Custom Field', 'hcf' ), 'hcf_display_callback', 'post' );
}
add_action( 'add_meta_boxes', 'hcf_register_meta_boxes' );

/**
 * Meta box display callback.
 *
 * @param WP_Post $post Current post object.
 */
function hcf_display_callback( $post ) {
    echo "Hello Custom Field";
}

Bất cứ dữ liệu nào được gọi trong hàm hcf_display_callback sẽ đều được hiển thị.

Hiển thị dữ liệu meta box bằng hàm hcf_display_callback.
Kết quả mà hàm hcf_display_callback trả về

Bây giờ, hàm này mới chỉ hiển thị một đoạn text đơn giản mà thôi. Trong phần tiếp theo, chúng ta sẽ hiển thị một vài trường thông tin (field) để người dùng có thể nhập thông tin cho các quyển sách nhé.

Thêm các custom field vào một meta box

Để thêm các custom field vào một meta box, bạn cần chỉnh sửa lại hàm callback để lấy ra các thông tin được nhập vào. Để phần code được ngắn gọn, mình tạo một file là form.php để chá toàn bộ các đoạn code cho các form field này. Nội dung file sẽ như sau:

/**
 * Meta box display callback.
 *
 * @param WP_Post $post Current post object.
 */
function hcf_display_callback( $post ) {
    include plugin_dir_path( FILE ) . './form.php';
}

Và thêm đoạn code sau và file form.php:

<div class="hcf_box">
    <style scoped>
        .hcf_box{
            display: grid;
            grid-template-columns: max-content 1fr;
            grid-row-gap: 10px;
            grid-column-gap: 20px;
        }
        .hcf_field{
            display: contents;
        }
    </style>
    <p class="meta-options hcf_field">
        <label for="hcf_author">Author</label>
        <input id="hcf_author" type="text" name="hcf_author">
    </p>
    <p class="meta-options hcf_field">
        <label for="hcf_published_date">Published Date</label>
        <input id="hcf_published_date" type="date" name="hcf_published_date">
    </p>
    <p class="meta-options hcf_field">
        <label for="hcf_price">Price</label>
        <input id="hcf_price" type="number" name="hcf_price">
    </p>
</div>

Bạn có thể tách phần định dạng cho form sang một file khác. Tuy nhiên, việc này cũng không cần thiết lắm vì chúng ta cũng chỉ đang tạo một ví dụ nhỏ thôi, nên phần code khá đơn giản. Còn trong thực tế, nếu phần code của bạn nhiều và đủ lớn, thì bạn nên tách cho dễ quản lý.

Bây giờ, bạn sẽ thấy meta box của bạn hiển thị như sau:

Thêm custom field vào trong một meta box.
Thêm custom field vào một meta box

Không giống như việc tạo field text mà WordPress cung cấp mặc định, cách viết code để tạo field như trên sẽ cho phép bạn tạo bất cứ loại field nào mà bạn muốn. Trong ví dụ ở trên, chúng ta đã tạo một field dạng ngày tháng và cho phép người dùng chọn một ngày bất kỳ trên lịch mà không cần phải gõ thủ công.

Cách này giúp cho người dùng điền thông tin đơn giản hơn, giảm việc sai lỗi, và giúp bạn xác thực thông tin dễ hơn (nếu cần).

Lưu dữ liệu của custom field

Chúng ta đã có form để người dùng điền dữ liệu rồi, nhưng WordPress lại không hỗ trợ việc tự động lưu các dữ liệu đó vào database. Vì vậy, chúng ta sẽ phải tự thao tác để lưu chúng lại.

Để lưu dữ liệu của các custom field khi người dùng lưu hoặc cập nhật bài viết, chúng ta cần tạo một hook vào save_post. save_post sẽ được gọi ra sau khi bài viết được lưu. Để lưu các giá trị nhập vào custom field, chúng ta sẽ dùng hàm update_post_meta. Bạn thêm đoạn code sau vào file của plugin đã tạo ở trên như sau:

/**
 * Save meta box content.
 *
 * @param int $post_id Post ID
 */
function hcf_save_meta_box( $post_id ) {
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
    if ( $parent_id = wp_is_post_revision( $post_id ) ) {
        $post_id = $parent_id;
    }
    $fields = [
        'hcf_author',
        'hcf_published_date',
        'hcf_price',
    ];
    foreach ( $fields as $field ) {
        if ( array_key_exists( $field, $_POST ) ) {
            update_post_meta( $post_id, $field, sanitize_text_field( $_POST[$field] ) );
        }
     }
}
add_action( 'save_post', 'hcf_save_meta_box' );

Bây giờ, hãy thử điền dữ liệu vào một field và lưu lại bài viết nhé. Sau khi tải lại trang chỉnh sửa bài viết, bạn sẽ không thấy dữ liệu bạn vừa nhập vào đâu. Đừng lo, dữ liệu của bạn lúc này đã được lưu vào database rồi, chẳng qua là nó chưa được hiển thị ra mà thôi.

Xem lại đoạn code của form custom field lại một lần nữa, bạn sẽ thấy các field đang bị thiếu thuộc tính value để hiển thị các giá trị của field ra. Vì vậy, chúng ta cần lấy dữ liệu của field, rồi output vào thuộc tính value như sau:

<div class="hcf_box">
    <style scoped>
        .hcf_box{
            display: grid;
            grid-template-columns: max-content 1fr;
            grid-row-gap: 10px;
            grid-column-gap: 20px;
        }
        .hcf_field{
            display: contents;
        }
    </style>
    <p class="meta-options hcf_field">
        <label for="hcf_author">Author</label>
        <input id="hcf_author"
            type="text"
            name="hcf_author"
            value="<?php echo esc_attr( get_post_meta( get_the_ID(), 'hcf_author', true ) ); ?>">
    </p>
    <p class="meta-options hcf_field">
        <label for="hcf_published_date">Published Date</label>
        <input id="hcf_published_date"
            type="date"
            name="hcf_published_date"
           value="<?php echo esc_attr( get_post_meta( get_the_ID(), 'hcf_published_date', true ) ); ?>">
    </p>
    <p class="meta-options hcf_field">
        <label for="hcf_price">Price</label>
        <input id="hcf_price"
            type="number"
            name="hcf_price"
            value="<?php echo esc_attr( get_post_meta( get_the_ID(), 'hcf_price', true ) ); ?>">
    </p>
</div>

Sau đó, bạn sẽ thấy các dữ liệu được hiển thị ra như sau:

Các giá trị của custom field được hiển thị ra sau khi lưu bài viết.
Hiển thị các giá trị của các custom field sau khi lưu bài viết

Chúng ta đã xong phần tạo một meta box, thêm custom field rồi lưu giá trị của custom field rồi đó. Ở trong backend như vậy cũng là xong rồi. Bây giờ hãy cùng hiển thị giá trị của custom field ra frontend nhé.

Chúng ta sẽ cần chỉnh sửa file code của theme một chút ở bước sau đó.

Lấy và hiển thị dữ liệu của custom field ra frontend

Để lấy giá trị của custom field, chúng ta chỉ cần thêm vào file code của theme hàm get_post_meta. Chúng ta đã nói đến hàm này ở bài viết trước rồi. Đoạn code mình cần thêm vào cũng không khác lần trước là mấy:

<ul>
    <li><strong>Author: </strong><?php echo esc_attr( get_post_meta( get_the_ID(), 'hcf_author', true ) ); ?></li>
    <li><strong>Published Date: </strong><?php echo esc_attr( get_post_meta( get_the_ID(), 'hcf_published_date', true ) ); ?></li>
    <li><strong>Price: </strong><?php echo esc_attr( get_post_meta( get_the_ID(), 'hcf_price', true ) ); ?></li>
</ul>
Hiển thị giá trị của custom field ra frontend.
Giá trị của custom field đã được hiển thị ra frontend

Lấy giá trị của custom field ở ngoài loop

Hàm get_post_meta yêu cầu một thông số bắt buộc là ID của bài viết. Nếu bạn muốn lấy giá trị của custom field ở bên ngoài loop từ một bài viết bất kỳ, thì bại cần biết ID của bài viết đó. Có rất nhiều cách để lấy ID này.

Cách 1: Thêm cố định ID một bài viết vào code

Lúc này, bạn cũng sẽ có rất nhiều cách để thêm ID vào code. Bạn có thể sẽ dùng post ID trực tiếp vào hàm get_post_meta như sau:

get_post_meta( 12, 'hcf_author', true );

Hoặc, xác định ID luôn bằng hàm:

// In the wp-config.php file
define( MY_POST_ID, 12 );
// In the theme's file
echo get_post_meta( MY_POST_ID, 'hcf_author', true);

Tuy nhiên, mình không khuyến khích việc thêm cố định một giá trị ID nào đó vào code như này. Có một cách ưu việt hơn là bạn có thể thực hiện một vài query để lấy các bài viết, sau đó bạn đưa ID của các bài viết được query vào hàm get_post_meta như cách 2 sau đây.

Cách 2: Lấy post ID bằng query

Đoạn code dưới đây mô phỏng việc bạn lấy giá trị của custom field từ một bài viết bằng một query tùy chỉnh như sau:

$the_slug = 'my_slug';
$args = array(
    'name' => $the_slug,
    'post_type' => 'post',
    'post_status' => 'publish',
    'posts_per_page' => 1,
);
$my_posts = get_posts( $args );
$my_post = current( $my_posts );
if ( $my_post ) {
    echo get_post_meta( $my_post->ID, 'hcf_author', true );
}

Lời cuối

Tạo custom field phục vụ cho nhu cầu riêng của bạn sẽ cần code đôi chút. Nhưng việc này sẽ cho phép bạn toàn quyền quyết định xem mình sẽ thêm field loại nào để phù hợp với mục đích riêng của bạn. Tuy vậy, song song với đó, bạn cũng sẽ phải tự mình xử lý vần lưu dữ liệu của custom field.

Bạn có thể tạo một loại field với dạng dữ liệu bất kỳ mà bạn muốn, thậm chí là những loại field phức tạo nhất như là gallery, hay repeated field. Nó phụ thuộc chủ yếu vào khả năng code và tưởng tượng của bạn mà thôi.

Quay trở lại với ý nghĩa của custom field, nó chính là phần hiển thị ra bên ngoài và là phần thực thi của kiến trúc metadata. Custom field cho chúng ta nhiều thông tin hơn về đối tượng (thường là bài viết). Tuy nhiên, cho đến bây giờ, chúng ta mới chỉ dùng nó cho việc lưu trữ các dữ liệu và hiển thị dữ liệu thôi. Mà một trong những ứng dụng phổ biến nhất của custom field đó là lấy ra các bài viết dựa trên giá trị của custom field cơ. Vì vậy, chúng ta sẽ tiếp tục nói về ứng dụng này ở các phần sau của series nhé.

Để lại bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *