Kinh nghiệm lập trình website mã nguồn mở PHP

Xây dựng WordPress plugin – level 1

Xây dựng WordPress plugin

Đọc bài này được lợi gì?

  • Bài này dành cho lập trình viên WordPress (WP), những bạn đang học WP. Hiện nay đã có rất nhiều tài liệu hướng dẫn viết plugin WP, tuy nhiên viết cũng đã lâu, theo hướng Function, các hàm WP version cũ, do đó, loạt bài xây dựng WP plugin với trình độ từ thấp tới cao, theo hướng đối tượng (OOP), sử dụng các hàm WP mới nhất, chắc chắn sẽ mang lại cho các bạn nhiều kiến thức thú vị.
  • Dành cho các blogger sử dụng WP. Thật ra cộng đồng WP rất khổng lồ, plugin trên mạng thì vô vàn chức năng, dễ dàng để bạn tìm thấy các plugin được viết sẵn, tuy nhiên tự tay viết 1 plugin đơn giản theo nhu cầu bản thân mình sẽ vô cùng hữu ích, đặc biệt là vấn đề hạn chế rủi ro bảo mật.

Xin trích dẫn bài viết về vấn đề xử dụng plugin WP tràn lan trên mạng của 1 blogger WP có tiếng ở Việt Nam – Thạch Phạm https://thachpham.com/wordpress/su-dung-hang-null-va-cuoc-hoi-ngo-voi-cryptophp.html
Theo mình, các plugin trên mạng download từ chính nhà cung cấp thì cũng chỉ tin tưởng ở mức 80%. Còn các plugin có phí, nhưng được share free ở 1 trang không chính thống thì chắc chắn 100% có vấn đề. Mình cũng từng gặp nhiều chủ website mếu máo vì trang web WP của mình dính Malware, bị đưa vào blacklist trên internet, việc khắc phục tốn khá nhiều thời gian.

1 nạn nhân xấu số bị Google Safe Browsing thông.

Giới thiệu

Loạt bài này sẽ gồm 3 level
Level 1 – bạn sẽ lên xương sống (backpone) cho plugin theo kiểu OOP. Tiền đề để các bạn xây dựng các plugin phức tạp hơn sau này. Bạn sẽ viết 1 plugin đơn giản, chức năng đếm số người truy cập website.
Level 2 – dựa trên bài level 1, ta sẽ viết 1 plugin cao cấp hơn, truy xuất và lưu trữ trong database xử dụng hàm của WP. bạn sẽ viết plugin quản lý banner.
Level 3 – phức tạp thật sự, bạn sẽ học cách thiết kế table riêng độc lập với WP, để dễ dàng tái sử dụng cho các dự án khác. bạn sẽ viết plugin quản lý giải bóng đá.

WP Plugin level 1 – HitCounter

Overview

Mục tiêu của bài viết này là xây dựng được 1 WP plugin class có các chức năng:

  1. Khai báo 1 plugin với hệ thống WP
  2. Kích hoạt plugin
  3. Lưu 1 biến chứa thông tin visit home page vào WP
  4. Tạo trang quản lý trong admin dashboard
  5. Dọn dẹp dữ liệu sau khi plugin được uninstall khỏi WP


Giao diện Admin Dashboard của plugin

Cấu trúc


– Toàn bộ WP plugin đặt trong thư mục: wp-content/plugins/
– Tên plugin của chúng ta sẽ là: nam-hitcounter-bp
– Folder chứa code plugin + Main file trùng tên plugin.

Main file

File: wp-content/plugins/nam-hitcounter-bp/nam-hitcounter-bp.php
Đây là tập tin chính của plugin, xử lý hầu hết mọi thao tác trong plugin
1. Khai báo plugin với hệ thống WP

/*
Plugin Name: Nam Hit Counter BoilerPlate
Plugin URI: namluu.com
Description: Hit counter when Home Page is visited
Version: 1.1
Author: Nam Luu
Author URI: namluu.com
Author Email: nam.luuduc@gmail.com
License:

  Copyright blah blah

*/

Với khai báo này, ta sẽ nhìn thấy tên plugin hiện trên danh sách trong Dashboard WP.
2. Hàm constructor
Hàm này sẽ quyết định những method nào của Plugin sẽ được thực thi

class NamHitCounter 
{
	/**
	 * Initializes the plugin by setting localization, filters, and administration functions.
	 */
	public function __construct() 
    {
		// Register hooks that are fired when the plugin is activated, deactivated, and uninstalled, respectively.
		register_activation_hook( __FILE__, array( $this, 'activate' ) );
		
		// MOVE uninstall feature to uninstall.php
		//register_uninstall_hook( __FILE__, array( $this, 'uninstall' ) );

		// Register hook executes just before WordPress determines which template page to load
	    add_action( 'template_redirect', array( $this, 'increase_counter_when_home_visited' ) );
		
		// Add extra submenu to the admin panel
		add_action( 'admin_menu', array( $this, 'create_menu_admin_panel' ) );
		
		// Handle POST request, admin_action_($action)
		add_action( 'admin_action_nam_counter_action', array( $this, 'nam_counter_admin_action' ) );	

register_activation_hook là 1 hook đặc biệt để gọi hàm thực thi mỗi khi admin kích hoạt plugin, đoạn code __FILE__, array( $this, ‘activate’ ) là cách để gọi 1 method trong 1 class theo hướng OOP của chúng ta ($this chính là class NamHitCounter), thay vì gọi trực tiếp tên hàm như cách viết theo kiểu Function.
Phần hook cho hàm uninstall tôi comment lại vì chúng ta sẽ có 1 file code riêng, không để trong class.
template_redirect hook action sẽ thực thi mỗi khi page được load, giống như 1 event để chúng ta có thể tăng biến đếm counter visit.
admin_menu dùng để tạo trang quản lý trong admin cho plugin
admin_action_nam_counter_action dùng để xử lý khi ta ấn nút Save trong trang quản lý mà ta đã tạo ở bước admin_menu

3. Kích hoạt plugin
Method activate() trong plugin có tác dụng chạy mỗi khi plugin được kích hoạt, thường sử dụng để khởi tạo dữ liệu cho plugin.

public function activate( $network_wide ) 
{	
    // if the WordPress version is older than 2.6, deactivate this plugin
    // admin_action_ hook appearance 2.6 
    if ( version_compare( get_bloginfo( 'version' ), '2.6', '<' ) ) {
        deactivate_plugins( basename( __FILE__ ) );
    } else {
        $data = array(
            'counter' 	=> 0,
            'time' 	=> null,
            'active'	=> true
        );
        add_option( 'nam_hit_counter', $data, '', 'no' );
    }
}

– Ở đây ta check WP version trước khi cài đặt, nếu plugin của bạn sử dụng các hàm WP mới thì phần này rất quan trọng, tránh việc cài đặt plugin xong thì lại quăng lỗi deprecate
– Sau đó là khởi tạo data cho plugin, ta sẽ thêm 1 biến array vào system, lưu:
+ counter: đếm số người truy cập
+ time: thời gian truy cập mới nhất
+ active: biến cờ, cho phép admin bật tắc chức năng

Nói thêm vế hàm add_option()
– A safe way of adding a named option/value pair to the options database table.
Đây là hàm tốt nhất khi plugin của bạn muốn thêm 1 data nào đó vào hệ thống, hàm này hỗ trợ serialize trước khi đưa vào database.
Ta có thể quan sát record trong database, table wp_options

Có thể bạn chưa biết.
Ta có thể quan sát biến option vừa tạo bằng giao diện Dashboard Admin bằng đường dẫn bí mật mà WP không hiển thị ra menu: http://yourwebbsite/wp-admin/options.php

4. Tăng biến counter

public function increase_counter_when_home_visited() 
{
    if (is_home()) {
        $data = get_option( 'nam_hit_counter' );	
        if ( $data['active'] ) {
            $data['counter']++;	
            $data['time'] = current_time('mysql');
            update_option( 'nam_hit_counter', $data );
        }
    }
}

Trong phần constructor, ta dùng action hook template_redirect để trigger mỗi khi các trang được load, tuy nhiên để giới hạn lại, chỉ đếm người dùng khi vào trang home ta dùng hàm is_home()
Tiếp theo ta load option đã lưu trước đó và tăng biến đếm, set lại thời gian, và update lại vào database.

5. Tạo trang quản lý trong admin

public function create_menu_admin_panel() 
{
    add_options_page( 'Nam HitCounter Options', 'Nam HitCounter', 
    'manage_options', 'nam-hitcounter-unique_identifier', array($this, 'nam_hitcounter_plugin_form' ));
} 

Trong constructor, hook name admin_menu gọi tới method create_menu_admin_panel
Method này dùng hàm add_options_page của WP để tạo 1 menu link mới trong Dashboard, bạn có thể xem các tham số tại đây
2 tham số đầu là text hiển thị trên title và menu, tham số thứ 3 capability là quyền để truy cập vào menu này, dùng quyền mặc định admin là ‘manage_options’, tham số 4 menu_slug là url trang khi ấn vào menu (duy nhất), tham số 5 là 1 method khác dùng để xử lý sau khi admin nhấp vào menu link, ở đây chúng ta sẽ show ra 1 cái form.

6. Form trong admin

public function nam_hitcounter_plugin_form() 
{
    if (!current_user_can( 'manage_options' )) {
        wp_die( __('You do not have sufficient permission to access this page.') );
    }
    
    // Add css only plugin option page
    wp_enqueue_style( 'nam-hitcounter', plugins_url( 'css/admin.css', __FILE__ ) );
                
    // retrieve counter
    $data = get_option( 'nam_hit_counter' );
    
    // admin form manage counter
    include 'views/admin.php';
}

Check quyền
Có thể add thêm CSS nếu cần
Lấy dữ liệu của plugin từ database
Tách phần view ra file riêng

7. Form view
Trong form view của plugin, chúng ta sẽ hiển thị biến counter, và cho phép người dùng bật tắt chức năng hit counter. Code chi tiết mình sẽ cung cấp sau, ở đây ta chỉ chú ý phần:

<form action="<?php echo admin_url( 'admin.php' ); ?>" method="post">
<input type="hidden" name="action" value="nam_counter_action" />

Mọi form action trong WP Admin phải POST tới trang admin.php vì lý do bảo mật, nhưng làm sao để WP phân biệt được data do form nào post tới và sẽ gọi hàm nào xử lý? Nhờ có hidden field value=”nam_counter_action”
Quay lại đoạn constructor ta có:

// Handle POST request, admin_action_($action)
add_action( 'admin_action_nam_counter_action', array( $this, 'nam_counter_admin_action' ) );

Đây chính là cách ra đăng ký với hệ thống WP: admin_action_{value trong hidden field}
Khi hệ thống nhận được POST data có hidden field là nam_counter_action, method nam_counter_admin_action() sẽ được thực thi.

Uninstall

Như đã đề cập phần trên, chỉ cần trong plugin có 1 tập tin là: uninstall.php thì WP sẽ tự động thực thi khi admin ấn vào nút Xóa trong phần quản trị

<?php
	//if uninstall not called from WordPress exit
	if (!defined('WP_UNINSTALL_PLUGIN'))
		exit();
	
	// delete option from options table
	delete_option('nam_hit_counter');
?>

Source code

Toàn bộ code trong plugin tại đây
https://github.com/namluu/nam-hitcounter-bp

Star nếu bạn thấy có ích nhé!
Star

Tổng kết

Qua 1 plugin với chức năng đơn giản, ta có thể làm quen với cách viết WP Plugin bằng class, theo hướng OOP. Sau này ở các bài viết tiếp theo, với các plugin phức tạp hơn, bạn sẽ thấy được lợi điểm của cách viết này.

Xây dựng WordPress plugin – level 1
Đánh giá bài viết

2 phản hồi

  1. I like the valuable info you provide to your articles. I’ll bookmark your blog and check again right here regularly.
    I am rather certain I’ll be informed lots of new stuff proper right here!

    Best of luck for the next!

Gửi phản hồi

Your email address will not be published. Required fields are marked *