WordPress có tính năng Custom Field giúp người dùng dễ dàng thêm các dữ liệu thêm vào một post type nào đó. Nhưng khi sử dụng Custom Field, chúng ta hầu như chỉ có thể làm bằng một thao tác là chọn tên khoá (key) rồi điền giá trị, như vậy rất bất tiện.
Ở đây chắc ai cũng biết qua plugin SEO by Yoast phải không? Các dữ liệu liên quan tới SEO của plugn này được người dùng khai báo thông qua cái khung như dưới này.
Các dữ liệu đó cũng là custom field trong WordPress nhưng nó sẽ giúp người dùng dễ dàng khai báo thông tin thuận tiện hơn. Và những cái khung này, người ta gọi là Meta Box.
Nếu bạn không thích code thì plugin Advanced Custom Field sẽ giúp bạn tạo ra các meta box dễ dàng.
Meta Box nghĩa là một cái hộp nhập liệu được tích hợp trong khu vực soạn thảo nội dung, và các dữ liệu sẽ được gửi vào trong cơ sở dữ liệu của website. Nhưng hiện nay, Meta Box đa phần được ứng dụng để làm việc với Meta Data (gồm wp_usermeta
, wp_commentmeta
và wp_postmeta
).
Trong bài viết này, mình sẽ hướng dẫn bạn cách tự tạo meta box để xử lý post meta data (dữ liệu của custom field). Đại loại là thêm hoặc sửa giá trị trong một custom field nào đó.
Nên xem trước:
Để thực hành trong bài này, tốt hơn bạn nên tự tạo ra một plugin mới bằng cách tạo một file demo-metabox.php trong thư mục /wp-content/plugins/, sau đó khai báo thông tin plugin.
<?php /* Plugin Name: Ví dụ Meta Box Author: Thạch Phạm Description: Hướng dẫn tạo meta box Author URI: https://onet.vn */
Và nhớ là kích hoạt plugin này lên.
Bước này chúng ta sẽ tạo ra một cái khung meta box trong khu vực soạn thảo trước. Để tạo một khung meta box, chúng ta sẽ sử dụng hàm add_meta_box() trong WordPress với cấu trúc như sau:
add_meta_box( $id, $title, $callback, $screen, $context, $priority, $callback_args );
Trong đó:
$id
: Tên ID của cái khung.$title
: Tiêu đề hiển thị của khung meta box.$callback
: Hàm hiển thị các form bằng HTML để nó làm việc với dữ liệu.$screen
: Tên post type mà meta box này sẽ được hiển thị, nó có các giá trị là post, page, dashboard, link, attachment hoặc tên custom post type (lưu ý là tên được viết dưới dạng slug).$context
: Kiểu hiển thị meta box, gồm normal, advanced hoặc side.$priority
: Thứ tự ưu tiên hiển thị, bao gồm high, core, default hoặc low.$callback_args
: Các tham số mà bạn muốn trả về hàm callback.Tuy nhiên khi làm việc, chúng ta có thể sẽ không cần sử dụng hết các tham số trong hàm này mà chỉ sử dụng các tham số quan trọng (5 tham số đầu tiên hoặc ít hơn).
Các bạn phải lưu ý là hàm add_meta_box()
không thể gọi riêng lẻ mà bạn cần phải đặt nó vào một hàm nào đó của riêng bạn, sau đó móc vào action hook là add_meta_boxes
để thực thi.
Ví dụ ở bài này, mình sẽ tạo ra một cái khung meta box với tên Liên hệ như sau:
/** Khai báo meta box **/ function onetidc_meta_box() { add_meta_box( 'thong-tin', 'Thông tin ứng dụng', 'onetidc_thongtin_output', 'post' ); } add_action( 'add_meta_boxes', 'onetidc_meta_box' );
Trong đó,
Bây giờ bạn hãy vào khu vực Post và thêm/sửa một post sẽ thấy cái meta box của mình.
Nếu bạn thấy cái lỗi call_user_func() thì nghĩa là chúng ta chưa viết cái hàm callback nên nó thấy thiếu, chúng ta sẽ làm ngay đây.
Callback nghĩa là một hàm mà nó sẽ in ra nội dung bên trong cái box đó, mình lấy ví dụ đơn giản thế này để hiển thị một đoạn chữ nhé.
function onetidc_thongtin_output() { echo 'Đây là thông tin trong meta box'; }
Dĩ nhiên kết quả bây giờ sẽ là như thế này.
Nhưng mà ví dụ trong bài này, mình sẽ tạo ra hai cái thẻ <input>
bên trong đó để người ta nhập liệu, ví dụ mình muốn tạo ra một trường nhập liệu để nhập Link Download (sử dụng custom field) thì mình sẽ viết lại như sau:
/** Khai báo callback @param $post là đối tượng WP_Post để nhận thông tin của post **/ function onetidc_thongtin_output( $post ) { // Tạo trường Link Download echo ( '<label for="link_download">Link Download: </label>' ); echo ('<input type="text" id="link_download" name="link_download" value="'.esc_attr( $link_download ).'" />'); }
Kết quả ta có:
Ở đoạn trên là các nội dung HTML để tạo ra một form mà thôi, nhưng các bạn lưu ý cho mình là ở cái biến $link_download
ở trên nó là cái biến mà chúng ta sẽ hiển thị nội dung mà người dùng đã nhập vào để nó hiển thị ra nếu nó đã được khai báo.
Nhưng vấn đề là nếu bây giờ bạn thử điền giá trị vào rồi cập nhật lại bài viết nó sẽ không được lưu, đơn giản là chúng ta chưa thiết lập cho nó lưu dữ liệu nhập vào.
Nhưng mà trước khi lưu dữ liệu vào, chúng ta viết thêm đoạn này vào hàm onetidc_thongtin_output
để khai báo cho hệ thống hiểu $link_download
là cái biến gì vì ta chưa tạo ra cho nó.
/** Khai báo callback @param $post là đối tượng WP_Post để nhận thông tin của post **/ function onetidc_thongtin_output( $post ) { $link_download = get_post_meta( $post->ID, '_link_download', true ); // Tạo trường Link Download echo ( '<label for="link_download">Link Download: </label>' ); echo ('<input type="text" id="link_download" name="link_download" value="'.esc_attr( $link_download ).'" />'); }
Trong đó, hàm get_post_meta mình đã giải thích tại bài hướng dẫn custom field rồi đấy.
Chúng ta đã có meta box, đã có một trường nhập dữ liệu và trường đó sẽ in dữ liệu ra trên khung nhập liệu nếu nó có giá trị. Nhưng vấn đề là bây giờ nó chưa có được lưu vào cơ sở dữ liệu khi nhập vào nên chúng ta phải tạo ra một hàm riêng để xử lý việc này, và hàm này chúng ta sẽ móc vào action hook save_post để thực thi khi lưu dữ liệu post type.
/** Lưu dữ liệu meta box khi nhập vào @param post_id là ID của post hiện tại **/ function onetidc_thongtin_save( $post_id ) { $link_download = sanitize_text_field( $_POST['link_download'] ); update_post_meta( $post_id, '_link_download', $link_download ); } add_action( 'save_post', 'onetidc_thongtin_save' );
Hàm này rất đơn giản, trước hết là nó sẽ làm sạch các dữ liệu được nhập vào cái trường link_download ($_POST['link_download']
là nó lấy dữ liệu gửi đi từ trường dựa vào thuộc tínhname
trong thẻ <input>
của nó). Làm sạch ở đây nghĩa là nó sẽ loại bỏ các ký tự đặc biệt như <
, ;
để tránh gây lỗi phát sinh và cũng hạn chế SQL Injection & XSS.
Sau đó, hàm update_post_meta sẽ tiến hành lưu lại các dữ liệu ở biến $link_download
ở trên vào custom field tên là _link_download
. Nếu chưa có nó sẽ tạo mới.
Bây giờ bạn hãy thử vào nội dung và nhập dữ liệu vào rồi lưu lại, bạn sẽ thấy nó đã được lưu.
Toàn bộ code phần này
<?php /* Plugin Name: Ví dụ Meta Box Author: Thạch Phạm Description: Hướng dẫn tạo meta box Author URI: https://onet.vn */ /** Khai báo meta box **/ function onetidc_meta_box() { add_meta_box( 'thong-tin', 'Thông tin ứng dụng', 'onetidc_thongtin_output', 'post' ); } add_action( 'add_meta_boxes', 'onetidc_meta_box' ); /** Khai báo callback @param $post là đối tượng WP_Post để nhận thông tin của post **/ function onetidc_thongtin_output( $post ) { $link_download = get_post_meta( $post->ID, '_link_download', true ); // Tạo trường Link Download echo ( '<label for="link_download">Link Download: </label>' ); echo ('<input type="text" id="link_download" name="link_download" value="'.esc_attr( $link_download ).'" />'); } /** Lưu dữ liệu meta box khi nhập vào @param post_id là ID của post hiện tại **/ function onetidc_thongtin_save( $post_id ) { $link_download = sanitize_text_field( $_POST['link_download'] ); update_post_meta( $post_id, '_link_download', $link_download ); } add_action( 'save_post', 'onetidc_thongtin_save' );
Bước 4. Lấy dữ liệu ra ngoài template
Dĩ nhiên bạn đã có giá trị trong custom field rồi thì việc hiển thị ra ngoài template của theme chỉ là chuyện nhỏ, bạn cứ làm nó hiển thị với hàm get_post_meta như dưới đây để lấy giá trị của field _link_download.
get_post_meta( $post->ID, '_link_download', true );
Khi chúng ta làm việc với việc gửi và lưu dữ liệu từ form thì vấn đề bảo mật cực kỳ quan trọng và đáng để quan tâm, bởi khi lưu dữ liệu nó sẽ lưu vào cơ sở dữ liệu nên chúng ta phải tin chắc là các dữ liệu được lưu vào là an toàn, đáng tin cậy.
Ngoài việc escape các ký tự đặc biệt với hàm esc_attr và sanitize_text_field mà mình có dùng ở trong bài thì một việc khác nữa bạn cần nên sử dụng khi làm việc với meta box là sử dụng Nonce (Number used once).
Nonce ở đây bạn hãy hiểu nó sẽ sinh ra một chuỗi mã xác thực (với dạng số) vào mỗi lần mà chúng ta gửi dữ liệu vào form. Sau đó chúng ta có thể xác thực cái Nonce này xem nó có hợp lệ hay không, nếu có thì chúng ta sẽ cho nó xử lý việc lưu dữ liệu, còn nếu không phải thì nên cho nó out ra. Việc này sẽ giúp bạn chống được một vài kiểu tấn công thông dụng như XSS hay CSRF.
Bây giờ hãy quay lại hàm callback là onetidc_thongtin_output
của chúng ta, ở đây chúng ta sẽ tạo ra một nonce với hàm wp_nonce_field và gắn nó một cái tên và một cái hành động.
function onetidc_thongtin_output( $post ) { $link_download = get_post_meta( $post->ID, '_link_download', true ); wp_nonce_field( 'save_thongtin', 'thongtin_nonce' ); // Tạo trường Link Download echo ( '<label for="link_download">Link Download: </label>' ); echo ('<input type="text" id="link_download" name="link_download" value="'.esc_attr( $link_download ).'" />'); }
Trong đó,save_thongtin
là tên hành động mà chúng ta sẽ sử dụng để kiểm tra sau này,thongtin_nonce
là tên của nonce để lấy giá trị nonce.
Ngay sau khi thêm đoạn đó, bạn xem mã nguồn HTML của trang soạn thảo nội dung sẽ thấy nó tạo ra một trường ẩn với tên là thongtin_nonce và có giá trị là một dãy số, chúng ta sẽ sử dụng cái giá trị đó để kiểm tra khi lưu dữ liệu.
Bây giờ, ở hàmonetidc_thongtin_save
, chúng ta chỉ cần thêm hai điều kiện rẽ nhánh rằng sẽ không lưu dữ liệu nếu nonce chưa có giá trị và giá trị nonce không hợp lệ như dưới đây.
function onetidc_thongtin_save( $post_id ) {
$thongtin_nonce = $_POST[‘thongtin_nonce’];
// Kiểm tra nếu nonce chưa được gán giá trị if( !isset( $thongtin_nonce ) ) {
return;
}
// Kiểm tra nếu giá trị nonce không trùng khớp if( !wp_verify_nonce( $thongtin_nonce, ‘save_thongtin’ ) ) {
return;
}
// Lưu dữ liệu nếu thoả điều kiện $link_download = sanitize_text_field( $_POST[‘link_download’] );
update_post_meta( $post_id, ‘_link_download’, $link_download );
}
add_action( ‘save_post’, ‘onetidc_thongtin_save’ );
Vậy là xong rồi đó. ?
Trong bài này, mình tạm thời dừng lại việc tạo một field nhập liệu đơn giản. Và khi nào có thời gian thêm, mình sẽ hướng dẫn bạn thêm cách tạo các loại field khác như radio button, dropdown list,…vì nó khá dài dòng.
Phần trước: Thêm trường dữ liệu (custom field) cho bài viếtPhần kế tiếp: Hướng dẫn tự tạo Widget