Ở phần trước chúng ta đã tìm hiểu Widget là gì và làm thể nào để đưa các widget vào giao diện thiết kế của mình. Phần bài hôm nay sẽ là phần chuyên sâu hơn, bởi chúng ta sẽ học cách làm thế nào thiết kế một widget riêng cho mình.
Để bắt đầu phần này, trước tiên tôi xin giới thiêu sơ qua với mọi người một lớp (class) widget của WordPress.
Trong WordPress, các widget được xây dựng dựa trên sự kế thừa(inherit) lớp cha của nó. Lớp cha này chính là những xác lập mặc định của widget mà WordPress đã xây dựng sẵn cho bạn. Một khi bạn kế thừa từ lớp cha, các thuộc tính của lớp cha sẽ được di truyền sang lớp con. Điều này nếu bạn nào học lập trình hướng đối tượng sẽ dễ dàng hình dung ra, còn những bạn mới làm quen với các khái niệm lập trình hướng đối tượng sẽ cảm thấy bỡ ngỡ. Tuy nhiên, tôi chỉ nói cho các bạn biết là như vậy thôi vì tôi không muốn đi quá sâu vào mảng kiến thức lập trình.
Như đã nói ở trên, khi thiết kế một widget, chúng ta sẽ thừa kế lớp cha widget của nó đã được định nghĩa đầy đủ. Việc cần làm là xác định object widget cần xây dựng thừa kế từ lớp cha widget đã được WordPress xây dựng sẵn và xây dựng thêm các thuộc tính riêng mà bạn mong muốn. Object widget cần xây dựng được viết dưới dạng class như sau.
[php] class Widget_name extends WP_Widget{
function Widget_name(){
}
/* Displays the Widget in the front-end */
function widget($args, $instance){
}
/*Saves the settings. */
function update($new_instance, $old_instance){
}
/*Creates the form for the widget in the back-end. */
function form($instance){
}
}// end Widget_name class
function registerWidget_nameInit() {
register_widget(‘Widget_name’);
}
add_action(‘widgets_init’, ‘registerWidget_nameInit’);
[/php]
Hãy nhìn đoạn mã mà tôi đã cung cấp cho các bạn ở bên trên.
Chúng ta có 1 class tên là Widget_name, một hàm registerWidget_nameInit và một hành động gọi hàm registerWidget_nameInit khi hook widgets_init hoạt động.
Class Widget_name mà tôi thiết kế ở trên bao gồm 4 action tương ứng với 4 function được khai báo bên trong:
- Widget_name(): đây là hàm khởi tạo(còn gọi là hàm Constructor). Nó được gọi khi bạn tạo một đối tượng (object) với tên là tên class. Ví dụ, khi bạn tạo một object A, hàm contructor sẽ tự động được thực thi và làm một số công việc bạn mong muốn như khai báo ngày tháng năm sinh, khởi tạo các giá trị chiều cao, cân nặng gì đó…
- widget(): hàm này sẽ có nhiệm vụ thể hiện widget của bạn ra ngoài giao diện. Bạn muốn nó hiển thị cái gì thì khai báo ở đó.
- update(): hàm này tôi dùng cho backend để thực hiện việc lưu dữ liệu thiết lập cho widget của tôi. Ví dụ như tôi muốn lưu tiêu đề widget, số tin sẽ hiện, có hiện ngày tháng đăng tin hay ko…
- form(): hàm này sẽ tạo ra form ở phần widget trong backend cho tôi. Tôn muốn lưu cái gì tôi sẽ thể hiện ở form này.
– Hàm registerWidget_nameInit(), tôi xây dựng để khai báo với anh chàng WordPress rằng tôi sẽ xử dụng cái class Widget_name như một Widget.
Xong, vậy là tôi đã giới thiệu sơ qua cho các bạn cấu trúc Widget rồi. Giờ chúng ta sẽ bắt tay viết một widget đơn giản.
Phụ mục
Viết một widget đơn giản: Giới thiêu Admin.
Tôi suy nghĩ và lựa chọn mãi mà chưa biết viết plugin nào có lợi cho người dùng để vừa làm ví dụ, vừa vác về xài luôn được :D Thôi tôi chọn đại cái widget Giới thiệu Admin (about me) để biết nhé. Theo đó tôi đặt tên cho widget của tôi là nhanweb_Aboutme. Để tránh việc trùng tên với các function và class mà có thể các plugin khác sẽ đặt. Tốt nhất khi viết code hoặc function bạn nên đặt tên bằng cách chèn thêm một tiếp đầu ngữ (prefix) giống như tôi để tránh trùng nhé !
Tôi lấy đoạn mã trên đặt vào functions.php của giao diện như sau:
[php] class nhanweb_Aboutme extends WP_Widget{
function nhanweb_Aboutme(){
}
/* Displays the Widget in the front-end */
function widget($args, $instance){
}
/*Saves the settings. */
function update($new_instance, $old_instance){
}
/*Creates the form for the widget in the back-end. */
function form($instance){
}
}// end Widget_name class
function registernhanweb_AboutmeInit() {
register_widget(‘nhanweb_Aboutme’);
}
add_action(‘widgets_init’, ‘registernhanweb_AboutmeInit’);
[/php]
Bắt đầu viết các sự kiện cho class nhanweb_Aboutme mà tôi đã giải thích với mọi người thôi :)
Viết hàm Contructor
Hàm này được tôi viết như sau:
[php] function nhanweb_Aboutme(){$widget_ops = array(‘description’ => ‘Hiện thông tin giới thiệu tác giả’);
$control_ops = array(‘width’ => 400, ‘height’ => 300);
parent::WP_Widget(false,$name=’NhanWeb About me’,$widget_ops,$control_ops);
}
[/php]
Bạn chú ý là các giá trị $widget_ops và $control_ops bạn không được đổi keyword của mảng nếu bạn không nắm rõ về nó vì nó được thừa kế từ lớp cha WP_Widget như chúng ta đã khai báo ở đầu class:
[php]
class nhanweb_Aboutme extends WP_Widget
[/php]
Sau khi viết xong hàm này tôi đã có một widget trong admin. Nhưng nếu kéo và thảy widget vài vị trí cần thể hiện tôi chẳng có một lựa chọn nào cho nó cả.
Viết hàm form để tùy chọn cho Admin
Để bổ sung các lựa chọn cho Widget, tôi sẽ viết tiếp một form nhập liệu thông qua hàm form() như sau:
[php] function form($instance){//Defaults
$instance = wp_parse_args( (array) $instance, array(‘title’=>’Về tôi’, ‘imagePath’=>’Ảnh’, ‘aboutText’=>’Giới thiệu’) );
$title = htmlspecialchars($instance[‘title’]);
$imagePath = htmlspecialchars($instance[‘imagePath’]);
$aboutText = htmlspecialchars($instance[‘aboutText’]);
# Title
echo ‘<p><label for="’ . $this->get_field_id(‘title’) . ‘">’ . ‘Tiêu đề:’ . ‘</label><input class="widefat" id="’ . $this->get_field_id(‘title’) . ‘" name="’ . $this->get_field_name(‘title’) . ‘" type="text" value="’ . $title . ‘" /></p>’;
# Image
echo ‘<p><label for="’ . $this->get_field_id(‘imagePath’) . ‘">’ . ‘Ảnh:’ . ‘</label><textarea cols="20" rows="2" class="widefat" id="’ . $this->get_field_id(‘imagePath’) . ‘" name="’ . $this->get_field_name(‘imagePath’) . ‘" >’. $imagePath .’</textarea></p>’;
# About Text
echo ‘<p><label for="’ . $this->get_field_id(‘aboutText’) . ‘">’ . ‘Giới thiệu:’ . ‘</label><textarea cols="20" rows="5" class="widefat" id="’ . $this->get_field_id(‘aboutText’) . ‘" name="’ . $this->get_field_name(‘aboutText’) . ‘" >’. $aboutText .’</textarea></p>’;
}
[/php]
Đoạn mã
[php]
$instance = wp_parse_args( (array) $instance, array(‘title’=>”, ‘imagePath’=>”, ‘aboutText’=>”) );
[/php]
Sẽ thiết lập các giá trị mặc định nếu như các thông tin không được bổ sung. Đoạn mã phía dưới nó sẽ hiện form nhập liệu như hình:
Viết hàm update để cập nhật dữ liệu
Sau khi nhập liệu đầy đủ, chúng ta tiến hành lưu các dữ liệu đã nhập để sử dụng khi thể hiện. Hàm update() được viết như sau:
[php] /*Saves the settings. */function update($new_instance, $old_instance){
$instance = $old_instance;
$instance[‘title’] = stripslashes($new_instance[‘title’]);
$instance[‘imagePath’] = stripslashes($new_instance[‘imagePath’]);
$instance[‘aboutText’] = stripslashes($new_instance[‘aboutText’]);
return $instance;
}
[/php]
Bạn thấy đoạn code trên không ! Khi bạn nhấn nút Save, WordPress sẽ hiểu là các giá trị nhập vào là các giá trị $new_instance, các giá trị cũ sẽ là $old_instance. Với 2 giá trị này bạn sẽ xử lý tùy ý và trả về cái cuối cùng là $instance dạng mảng (array) để wordpress tự động gọi lưu trữ. Xem chừng việc lưu dữ liệu của Widget rất dễ dàng :)
Viết hàm widget
Chúng ta đã tiến hành khai báo, tạo form nhập liệu và lưu dữ liệu rồi, giờ công việc cuối cùng là thể hiện cái Widget chúng ta đã thiết kế ra ngoài thế nào thôi. Đây là đoạn mã tôi viết cho hàm widget():
[php] function widget($args, $instance){extract($args);
$title = apply_filters(‘widget_title’, empty($instance[‘title’]) ? ‘Về tôi’ : $instance[‘title’]);
$imagePath = empty($instance[‘imagePath’]) ? ” : $instance[‘imagePath’];
$aboutText = empty($instance[‘aboutText’]) ? ” : $instance[‘aboutText’];
echo $before_widget;
if ( $title )
echo $before_title . $title . $after_title;
?>
<div class="clearfix">
<img src="<?php echo $imagePath; ?>" id="about-image" alt="about us image" />
<p><?php echo($aboutText)?></p>
</div>
<?php
echo $after_widget;
}
[/php]
Bạn chú ý: các biến $before_widget, $before_title, $after_title,$after_widget cần được đặt vào để có thể khai báo thêm các thông số cần thiết sau này.
Vậy là xong, cùng ngắm nhìn thành quả nào:
Bonus: toàn bộ mã nguồn
Để dễ dàng và trực quan. Mình post lại toàn bộ đoạn mã đã viết và thêm vào functions.php đã nói đến ở bài này và cả bài trước (toàn bộ nội dung đã hướng dẫn liên quan đến widget). Bạn nào cần thì copy về nhé.
[php] <?php/**
* Register widgetized areas, including two sidebars and widget-ready columns in the footer.
*
* To override nhanweb_widget() in a child theme, remove the action hook and add your own
* function tied to the init hook.
*
* @uses register_sidebar
*/
function nhanweb_widget() {
// Dang ky widget cho Admin
register_sidebar( array(
‘name’ => __( ‘Widget cột phải’, ‘nhanweb’ ),
‘id’ => ‘right-widget-area’,
‘description’ => __( ‘Vị trí widget cột bên phải’, ‘nhanweb’ ),
‘before_widget’ => ‘<li id="%1$s" class="widget-container %2$s">’,
‘after_widget’ => ‘</li>’,
‘before_title’ => ‘<h3 class="widget-title">’,
‘after_title’ => ‘</h3>’,
) );
register_sidebar( array(
‘name’ => __( ‘Widget Footer’, ‘nhanweb’ ),
‘id’ => ‘footer-widget-area’,
‘description’ => __( ‘Vị trí widget ở cuối thang’, ‘nhanweb’ ),
‘before_widget’ => ‘<li id="%1$s" class="widget-container %2$s">’,
‘after_widget’ => ‘</li>’,
‘before_title’ => ‘<h3 class="widget-title">’,
‘after_title’ => ‘</h3>’,
) );
}
/** Register sidebars by running nhanweb_widget() on the widgets_init hook. */
add_action( ‘widgets_init’, ‘nhanweb_widget’ );
class nhanweb_Aboutme extends WP_Widget
{
function nhanweb_Aboutme(){
$widget_ops = array(‘description’ => ‘Hiện thông tin giới thiệu tác giả’);
$control_ops = array(‘width’ => 400, ‘height’ => 300);
parent::WP_Widget(false,$name=’NhanWeb About me’,$widget_ops,$control_ops);
}
/*Creates the form for the widget in the back-end. */
function form($instance){
//Defaults
$instance = wp_parse_args( (array) $instance, array(‘title’=>”, ‘imagePath’=>”, ‘aboutText’=>”) );
$title = htmlspecialchars($instance[‘title’]);
$imagePath = htmlspecialchars($instance[‘imagePath’]);
$aboutText = htmlspecialchars($instance[‘aboutText’]);
# Title
echo ‘<p><label for="’ . $this->get_field_id(‘title’) . ‘">’ . ‘Tiêu đề:’ . ‘</label><input class="widefat" id="’ . $this->get_field_id(‘title’) . ‘" name="’ . $this->get_field_name(‘title’) . ‘" type="text" value="’ . $title . ‘" /></p>’;
# Image
echo ‘<p><label for="’ . $this->get_field_id(‘imagePath’) . ‘">’ . ‘Ảnh:’ . ‘</label><textarea cols="20" rows="2" class="widefat" id="’ . $this->get_field_id(‘imagePath’) . ‘" name="’ . $this->get_field_name(‘imagePath’) . ‘" >’. $imagePath .’</textarea></p>’;
# About Text
echo ‘<p><label for="’ . $this->get_field_id(‘aboutText’) . ‘">’ . ‘Giới thiệu:’ . ‘</label><textarea cols="20" rows="5" class="widefat" id="’ . $this->get_field_id(‘aboutText’) . ‘" name="’ . $this->get_field_name(‘aboutText’) . ‘" >’. $aboutText .’</textarea></p>’;
}
/*Saves the settings. */
function update($new_instance, $old_instance){
$instance = $old_instance;
$instance[‘title’] = stripslashes($new_instance[‘title’]);
$instance[‘imagePath’] = stripslashes($new_instance[‘imagePath’]);
$instance[‘aboutText’] = stripslashes($new_instance[‘aboutText’]);
return $instance;
}
/* Displays the Widget in the front-end */
function widget($args, $instance){
extract($args);
$title = apply_filters(‘widget_title’, empty($instance[‘title’]) ? ‘Về tôi’ : $instance[‘title’]);
$imagePath = empty($instance[‘imagePath’]) ? ” : $instance[‘imagePath’];
$aboutText = empty($instance[‘aboutText’]) ? ” : $instance[‘aboutText’];
echo $before_widget;
if ( $title )
echo $before_title . $title . $after_title;
?>
<div class="clearfix">
<img src="<?php echo $imagePath; ?>" id="about-image" alt="about us image" />
<p><?php echo($aboutText)?></p>
</div>
<?php
echo $after_widget;
}
}// end Widget_name class
function registernhanweb_AboutmeInit() {
register_widget(‘nhanweb_Aboutme’);
}
add_action(‘widgets_init’, ‘registernhanweb_AboutmeInit’);
?>
[/php]
Chúc các bạn thành công và nhớ để lại comment nhé :)
MrSix says
Chào anh Nhân, cho em hỏi
site em đã cài plugin PageNavi nhưng hình như theme em đang xài ko hỗ trợ, nó vẫn hiện Older Entries, không biết file chỉnh sửa file nào và chỉnh sửa ra sao ? :)
Anh Nhân có thể giúp em ko ah. :)
Nguyễn Duy Nhân says
Bạn phải thay thế đoạn code mặc định của theme bằng đoạn code phân trang mới do plugin cung cấp. Đọc thêm phần install của plugin này để biết nhé.
Blog Cơ Khí says
Cái widget của bác không thua gì cái widget User Profile của bọn Genesis =))
tin7117 says
hi anh Nhân!
Em cũng đang làm về phần này, có gặp tí rắc rối, dạo quanh internet xem có topic nào của anh em VN mình thảo luận về phần này ko, may quá gặp topic này của bác!
vấn đề của em là bây giờ em muốn tạo 1 widget có cho chọn multi category, em thử hoài mà chưa được.
Vấn đề tạo multi select category trong theme option thì được rồi, nhưng qua widget này thì thực sự em đang bí!
Bí ở chỗ cái biến mảng lưu lại các giá trị ID của category ko biết khai báo và sử dụng nó như thế nào!
Mong pác Nhân và các bác nào biết chỉ giúp em, thanks các pác nhìu lắm!
tin7117 says
thanks all!
Em tự giải quyết dc rùi! :D
KKFashion says
Hi Nhan. Không biết widget này có giữ vị trí ben trái không. Mình đang cần cái này. Đề mình áp dung thử
Nguyễn Duy Nhân says
Widget có thể hiển thị ở bất kì đâu (trái, phải, trên, dưới…). Bạn đọc lại phần 9, chú ý đoạn khai báo widget. Muốn sử dụng Widget chỗ nào thì khai báo widget chỗ đó.
KKfashion says
Cảm ơn bác nhân đã giúp đỡ rất nhiều. Mình sẽ tham khảo trên phần 9 mới được
HocPham says
Bài này của bác hay quá ;):x
Lanky says
Cám ơn sự nhiệt tình của pác, chuỗi bài viết hay quá, điểm 10 cho chất lượng :D!
Hy vọng pác ngày càng có thêm nhiều bài viết hay để anh em học hỏi!
Rau Mam says
Đang nghiên cứu cái này. Thanks bác nhé :P
DT2 says
Thanks much for the tutorial series !
It’s very interesting and useful !
>:D:D:D<
Đầm công sở says
hix hix em không biết gì về code, có cách nào dễ hơn không anh
phamtung says
bài viết rất hay. cám ơn bạn nhiều.
[email protected] says
Mỗi lần thay dổi giao diện là các widget sẽ quay trở về mặc định của giao diện đó, có cách nào ta lưu lại vị trí các widget của 1 theme rồi khi ta dùng giao diện khác một thời gian rồi ta quay lại giao diện cũ thì vẫn ko mất thời gian để thiết lập widget lại từ đầu.
Cám ơn bác trước
BiBi says
thanks bạn, bài viết rất hữu ích >:D<
Hoang Phung says
Admin ơi giúp mình với: web http://www.bieutrungkyniemchuong.com sử dụng theme http://www.elegantthemes.com/gallery/estore/ theme này ko hỗ trợ widget header va widget footer, giờ mình muốn thêm vào thì thêm thế nào nhĩ, tìm cả tuần này mà ko được, hoặc dùng PLUGIN nào ah, nhờ các cao thủ giúp em với >:D<
Nguyễn Duy Nhân says
Phần hướng dẫn của bài 9 và bài 10 chứa đầy đủ thông tin về việc tạo widget(bài 10) và cả tích hợp widget vào giao diện (bài 9). Bạn có thể xem lại và thực hành theo. Không khó đâu, cố lên nhé.
Hứa Thiếu Gia says
thầy ơi xây dựng demo mẫu một trang category.php đươc không thầy em cảm ơn thẩy nhiều
Trần Quốc Nhất says
Cám ơn anh.Bài viết của anh hay quá :).Nó giúp ích cho em rất nhiều >:D:D<
Ngoc Son says
Thank vì cái hướng dẫn rất hữu ích. Cho mình hỏi thêm là trong bài hướng dẫn này bạn add luôn cái class widget vào trong file functions luôn. Nhưng mà mình muốn tách nó ra một file riêng cho dễ quản lý được không bạn, với lại để sau này còn xài lại nữa.
Mình cố thử tách nó ra một file riêng, rồi trong file functions cũng đăng ký đàng hoàng
[code]register_widget( ‘nhanweb_Aboutme’ )[/code]
Nhưng nó lại báo lỗi:
[code]Fatal error: Class ‘nhanweb_Aboutme’ not found in C:\xampp\htdocs\wordpress\wp-includes\widgets.php on line 324[/code]
Góp ý cho mình chỗ này tí nha.
Thank nhiều
Ngoc Son says
à, mình tìm ra rồi, mình chưa include cái class đó vào. Gà quá, hihi. Thank mọi người và admin nhiều
mình ghi ở đây cách giải quyết cho mọi người tham khảo
[code]
require( get_template_directory() . ‘/widgets/nhanweb_Aboutme.php’ );
[/code]
Ho Thi Diem says
Thầy Nhân ơi!Sao em cũng làm giống y như thầy nhưng mà chi chạy được title và giới thiệu thôi hà.Còn hình thi không load lên được nè.Em cũng code giống thầy như ở trên đóa
Nguyễn Duy Nhân says
Xem lại link ảnh ;))
Ho Thi Diem says
Thanks thầy Nhân.Em đã chạy được rồi.Chúc thầy khỏe.