() translation by (you can also view the original English article)
Trong phần trước của loạt bài này, chúng tôi đã xem xét chủ đề làm việc cùng Ajax trong WordPress. Sau cùng, mục tiêu là cải thiện những bản trước đó vài năm.
Để nhắc lại, không phải là các kỹ thuật được dạy trong loạt bài ban đầu là sai, nhưng phần mềm thay đổi qua thời gian nên luôn tốt khi xem lại các khái niệm đã được nhắc đến từ nhiều năm trước và cố gắng cập nhật theo những thứ hiện tại và linh hoạt hơn cho những nỗ lực phát triển của chúng tôi.
Nhớ lại từ bài trước, chúng tôi đã xem xét nhận xét sau từ loạt bài gốc:
Chúng ta sẽ đưa ra một cái nhìn tổng quan ngắn gọn về Ajax là gì, cách thức nó hoạt động, cách thiết lập nó và hiểu các hook mà WordPress cung cấp. Chúng tôi cũng sẽ thực sự xây dựng một dự án nhỏ thực tế hoá lý thuyết. Chúng tôi sẽ xem qua mã nguồn và cũng sẽ đảm bảo nó có sẵn trên GitHub.
Và trong bài viết đó, chúng tôi đã xem xét một số cách nâng cao nhằm kết hợp API WordPress Ajax vào các dự án của chúng tôi bằng cách sử dụng lập trình thủ tục (procedural programing). Trong bài này, chúng tôi sẽ lấy mã mà chúng tôi đã viết trong phần đầu của loạt bài này và cấu trúc lại nó để nó sử dụng phương pháp hướng đối tượng.
Tổng kết thì mục tiêu không phải để bàn đến một trường hợp nên sử dụng mô hình nào; thay vào đó, là cho thấy cách chúng ta đạt được cùng chức năng dù cho sử dụng bất kỳ phương pháp nào khi bạn chọn để xây dựng plugin của mình.
Lên kế hoạch cho Plugin
Trước khi chúng tôi bắt đầu tái cấu trúc mã, một cái gì đó mà chúng tôi cần phải xem xét là làm thế nào chúng tôi sẽ bố trí các file khác nhau. Sau cùng, một phần của quá trình bắt đầu một dự án mới - hoặc thậm chí can thiệp vào một dự án cũ - là lên kế hoạch công việc sẽ được thực hiện như thế nào.
Đối với plugin cụ thể này, chúng tôi sẽ cần những điều sau đây:
- file bootstrap chịu trách nhiệm khởi tạo class chính và bắt đầu plugin
- một class có trách nhiệm tải các phụ thuộc như JavaScript
- một class đóng vai trò là class plugin chính
Như bạn có thể thấy, không có quá nhiều thứ mà chúng tôi cần phải làm với plugin. Chúng tôi cũng sẽ tổ chức lại một số file để có cấu trúc thư mục nhất quán và chúng tôi sẽ đảm document lại tất cả code để theo WordPress Coding Standards.
Với điều đó, chúng tôi hãy bắt đầu.
Tổ chức các file
Trước khi chúng tôi viết bất kỳ code gì, hãy tiếp tục làm như sau:
- Tạo thư mục
assets
. - Tạo thư mục
js
sẽ nằm trong thư mụcassets
. - Di chuyển
frontend.js
vào thư mụcjs
.



Lý do để làm điều này là chúng tôi đang chuyển sang phong cách lập trình hướng đối tượng. Một phần của điều này gồm việc tổ chức các file của chúng tôi để chúng tuân theo các quy ước thường được coi là các package.
Trong trường hợp của chúng tôi, thư mục assets
bao gồm tất cả những thứ cần thiết để giúp cho chương trình chạy. Đối với một số plugin, đây có thể là JavaScript, CSS, image (hình ảnh), font (phông chữ), v.v. Trong trường hợp này, chúng tôi có một file JavaScript duy nhất.
Dependency loader (trình tải phần phụ thuộc)
Tiếp theo, chúng tôi cần giới thiệu một class sẽ chịu trách nhiệm tải các phụ thuộc cho dự án của chúng tôi. Đối với plugin cụ thể này, phụ thuộc duy nhất mà chúng tôi có là file JavaScript mà chúng tôi vừa đặt trong thư mục nội dung.
Một phần của lập trình hướng đối tượng là đảm bảo rằng mỗi class có một mục đích cụ thể. Trong trường hợp này, class chúng tôi sắp giới thiệu sẽ chịu trách nhiệm tải JavaScript bằng cách sử dụng API WordPress.
Hãy bắt đầu bằng cách tạo cấu trúc cơ bản của class:
1 |
<?php
|
2 |
|
3 |
/**
|
4 |
* Loads and enqueues dependencies for the plugin.
|
5 |
*
|
6 |
* @since 1.0.0
|
7 |
*
|
8 |
* @package WPA/includes
|
9 |
*/
|
10 |
class Dependency_Loader { |
11 |
|
12 |
}
|
Tiếp theo, chúng tôi sẽ thêm một phương thức chịu trách nhiệm cho việc enqueuing JavaScript theo API WordPress.
1 |
<?php
|
2 |
/**
|
3 |
* Loads and registers dependencies.
|
4 |
*
|
5 |
* @since 1.0.0
|
6 |
*
|
7 |
* @package WPA
|
8 |
* @author Tom McFarlin
|
9 |
* @license https://www.gnu.org/licenses/gpl-2.0.txt
|
10 |
* @link https://tommcfarlin.com/
|
11 |
*/
|
12 |
|
13 |
/**
|
14 |
* Loads and enqueues dependencies for the plugin.
|
15 |
*
|
16 |
* @package WPA
|
17 |
* @subpackage WPA/includes
|
18 |
* @since 1.0.0
|
19 |
* @author Tom McFarlin
|
20 |
* @license http://www.gnu.org/licenses/gpl-2.0.txt
|
21 |
* @link https://tommcfarlin.com/
|
22 |
*/
|
23 |
class Dependency_Loader { |
24 |
|
25 |
/**
|
26 |
* Initializes the plugin by enqueuing the necessary dependencies.
|
27 |
*
|
28 |
* @since 1.0.0
|
29 |
*/
|
30 |
public function initialize() { |
31 |
$this->enqueue_scripts(); |
32 |
}
|
33 |
|
34 |
/**
|
35 |
* Enqueues the front-end scripts for getting the current user's information
|
36 |
* via Ajax.
|
37 |
*
|
38 |
* @access private
|
39 |
*
|
40 |
* @since 1.0.0
|
41 |
*/
|
42 |
private function enqueue_scripts() { |
43 |
|
44 |
wp_enqueue_script( |
45 |
'ajax-script', |
46 |
plugin_dir_url( dirname( __FILE__ ) ) . 'assets/js/frontend.js', |
47 |
array( 'jquery' ) |
48 |
);
|
49 |
|
50 |
wp_localize_script( |
51 |
'ajax-script', |
52 |
'sa_demo', |
53 |
array( 'ajax_url' => admin_url( 'admin-ajax.php' ) ) |
54 |
);
|
55 |
|
56 |
}
|
57 |
}
|
Sau đó, chúng tôi cần triển khai các hàm chịu trách nhiệm xử lý các yêu cầu Ajax và cung cấp response và sau đó bổ sung chúng vào class. Vì chúng sẽ trong ngữ cảnh của một class, chúng tôi cần thêm một hàm mới sẽ đăng ký chúng với WordPress.
Chúng ta sẽ tạo một hàm setup_ajax_handlers
. Hàm đó trông như thế này:
1 |
<?php |
2 |
|
3 |
/** |
4 |
* Registers the callback functions responsible for providing a response |
5 |
* to Ajax requests setup throughout the rest of the plugin. |
6 |
* |
7 |
* @since 1.0.0 |
8 |
*/ |
9 |
public function setup_ajax_handlers() { |
10 |
|
11 |
add_action( |
12 |
'wp_ajax_get_current_user_info', |
13 |
array( $this, 'get_current_user_info' ) |
14 |
); |
15 |
|
16 |
add_action( |
17 |
'wp_ajax_nopriv_get_current_user_info', |
18 |
array( $this, 'get_current_user_info' ) |
19 |
); |
20 |
|
21 |
} |
Tiếp theo, chúng tôi cần chuyển các hàm vào class này. Lưu ý rằng các hàm ban đầu được bắt đầu bằng _sa
không còn được đánh dấu như vậy nữa. Vì chúng nằm trong class, chúng tôi có thể bỏ tiền tố và cũng bỏ dấu gạch dưới có lợi cho từ khóa private
.
1 |
<?php
|
2 |
|
3 |
public function get_current_user_info() { |
4 |
|
5 |
$user_id = get_current_user_id(); |
6 |
|
7 |
if ( $this->user_is_logged_in( $user_id ) && $this->user_exists( $user_id ) ) { |
8 |
|
9 |
wp_send_json_success( |
10 |
wp_json_encode( get_user_by( 'id', $user_id ) ) |
11 |
);
|
12 |
|
13 |
}
|
14 |
|
15 |
}
|
16 |
|
17 |
private function user_is_logged_in( $user_id ) { |
18 |
|
19 |
$is_logged_in = true; |
20 |
|
21 |
if ( 0 === $user_id ) { |
22 |
|
23 |
wp_send_json_error( |
24 |
new WP_Error( '-2', 'The visitor is not currently logged into the site.' ) |
25 |
);
|
26 |
|
27 |
$is_logged_in = false; |
28 |
|
29 |
}
|
30 |
|
31 |
return $is_logged_in; |
32 |
|
33 |
}
|
34 |
|
35 |
private function user_exists( $user_id ) { |
36 |
|
37 |
$user_exists = true; |
38 |
|
39 |
if ( false === get_user_by( 'id', $user_id ) ) { |
40 |
|
41 |
wp_send_json_error( |
42 |
new WP_Error( '-1', 'No user was found with the specified ID [' . $user_id . ']' ) |
43 |
);
|
44 |
|
45 |
$user_exists = false; |
46 |
|
47 |
}
|
48 |
|
49 |
return $user_exists; |
50 |
|
51 |
}
|
Sau đó, chúng tôi sẽ lưu file này trong thư mục includes
trong thư mục gốc của thư mục plugin. Thư mục includes
gồm thường là nơi chứa code được sử dụng trong suốt dự án. Có thể nói thêm về thư mục quan trọng này, nhưng đó là nội dung ở một bài viết dài hơn.
Phiên bản cuối cùng của class này sẽ giống như sau:
1 |
<?php
|
2 |
/**
|
3 |
* Loads and registers dependencies.
|
4 |
*
|
5 |
* @since 1.0.0
|
6 |
*
|
7 |
* @package WPA
|
8 |
* @author Tom McFarlin
|
9 |
* @license http://www.gnu.org/licenses/gpl-2.0.txt
|
10 |
* @link https://tommcfarlin.com/
|
11 |
*/
|
12 |
|
13 |
/**
|
14 |
* Loads and enqueues dependencies for the plugin.
|
15 |
*
|
16 |
* @package WPA
|
17 |
* @subpackage WPA/includes
|
18 |
* @since 1.0.0
|
19 |
* @author Tom McFarlin
|
20 |
* @license http://www.gnu.org/licenses/gpl-2.0.txt
|
21 |
* @link https://tommcfarlin.com/
|
22 |
*/
|
23 |
class Dependency_Loader { |
24 |
|
25 |
/**
|
26 |
* Initializes the plugin by enqueuing the necessary dependencies.
|
27 |
*
|
28 |
* @since 1.0.0
|
29 |
*/
|
30 |
public function initialize() { |
31 |
$this->enqueue_scripts(); |
32 |
}
|
33 |
|
34 |
/**
|
35 |
* Enqueues the front-end scripts for getting the current user's information
|
36 |
* via Ajax.
|
37 |
*
|
38 |
* @access private
|
39 |
*
|
40 |
* @since 1.0.0
|
41 |
*/
|
42 |
private function enqueue_scripts() { |
43 |
|
44 |
wp_enqueue_script( |
45 |
'ajax-script', |
46 |
plugin_dir_url( dirname( __FILE__ ) ) . 'assets/js/frontend.js', |
47 |
array( 'jquery' ) |
48 |
);
|
49 |
|
50 |
wp_localize_script( |
51 |
'ajax-script', |
52 |
'sa_demo', |
53 |
array( 'ajax_url' => admin_url( 'admin-ajax.php' ) ) |
54 |
);
|
55 |
|
56 |
}
|
57 |
|
58 |
/**
|
59 |
* Registers the callback functions responsible for providing a response
|
60 |
* to Ajax requests setup throughout the rest of the plugin.
|
61 |
*
|
62 |
* @since 1.0.0
|
63 |
*/
|
64 |
public function setup_ajax_handlers() { |
65 |
|
66 |
add_action( |
67 |
'wp_ajax_get_current_user_info', |
68 |
array( $this, 'get_current_user_info' ) |
69 |
);
|
70 |
|
71 |
add_action( |
72 |
'wp_ajax_nopriv_get_current_user_info', |
73 |
array( $this, 'get_current_user_info' ) |
74 |
);
|
75 |
|
76 |
}
|
77 |
|
78 |
/**
|
79 |
* Retrieves information about the user who is currently logged into the site.
|
80 |
*
|
81 |
* This function is intended to be called via the client-side of the public-facing
|
82 |
* side of the site.
|
83 |
*
|
84 |
* @since 1.0.0
|
85 |
*/
|
86 |
public function get_current_user_info() { |
87 |
|
88 |
$user_id = get_current_user_id(); |
89 |
|
90 |
if ( $this->user_is_logged_in( $user_id ) && $this->user_exists( $user_id ) ) { |
91 |
|
92 |
wp_send_json_success( |
93 |
wp_json_encode( get_user_by( 'id', $user_id ) ) |
94 |
);
|
95 |
|
96 |
}
|
97 |
|
98 |
}
|
99 |
|
100 |
/**
|
101 |
* Determines if a user is logged into the site using the specified user ID. If not,
|
102 |
* then the following error code and message will be returned to the client:
|
103 |
*
|
104 |
* -2: The visitor is not currently logged into the site.
|
105 |
*
|
106 |
* @access private
|
107 |
* @since 1.0.0
|
108 |
*
|
109 |
* @param int $user_id The current user's ID.
|
110 |
*
|
111 |
* @return bool $is_logged_in Whether or not the current user is logged in.
|
112 |
*/
|
113 |
private function user_is_logged_in( $user_id ) { |
114 |
|
115 |
$is_logged_in = true; |
116 |
|
117 |
if ( 0 === $user_id ) { |
118 |
|
119 |
wp_send_json_error( |
120 |
new WP_Error( '-2', 'The visitor is not currently logged into the site.' ) |
121 |
);
|
122 |
|
123 |
$is_logged_in = false; |
124 |
|
125 |
}
|
126 |
|
127 |
return $is_logged_in; |
128 |
|
129 |
}
|
130 |
|
131 |
/**
|
132 |
* Determines if a user with the specified ID exists in the WordPress database. If not, then will
|
133 |
* the following error code and message will be returned to the client:
|
134 |
*
|
135 |
* -1: No user was found with the specified ID [ $user_id ].
|
136 |
*
|
137 |
* @access private
|
138 |
* @since 1.0.0
|
139 |
*
|
140 |
* @param int $user_id The current user's ID.
|
141 |
*
|
142 |
* @return bool $user_exists Whether or not the specified user exists.
|
143 |
*/
|
144 |
private function user_exists( $user_id ) { |
145 |
|
146 |
$user_exists = true; |
147 |
|
148 |
if ( false === get_user_by( 'id', $user_id ) ) { |
149 |
|
150 |
wp_send_json_error( |
151 |
new WP_Error( '-1', 'No user was found with the specified ID [' . $user_id . ']' ) |
152 |
);
|
153 |
|
154 |
$user_exists = false; |
155 |
|
156 |
}
|
157 |
|
158 |
return $user_exists; |
159 |
|
160 |
}
|
161 |
}
|
Class chính
Bây giờ chúng tôi đã sẵn sàng để viết class chính cho plugin. Class đặc biệt này sẽ nằm trong thư mục gốc của thư mục plugin và cấu trúc cơ bản của class sẽ trông giống như sau:
1 |
<?php
|
2 |
|
3 |
/**
|
4 |
* Loads and enqueues dependencies for the plugin.
|
5 |
*
|
6 |
* @since 1.0.0
|
7 |
*
|
8 |
* @package WPA
|
9 |
*/
|
10 |
class WP_Simple_Ajax { |
11 |
|
12 |
}
|
Tiếp theo, chúng tôi sẽ thêm một vài thuộc tính mà chúng tôi sẽ thiết lập khi class được khởi tạo:
1 |
<?php
|
2 |
|
3 |
class WP_Simple_Ajax { |
4 |
|
5 |
private $version; |
6 |
|
7 |
private $loader; |
8 |
|
9 |
}
|
Sau đó, chúng tôi sẽ tạo một hàm tạo và một hàm khởi tạo sẽ được sử dụng để kích hoạt plugin.
1 |
<?php
|
2 |
/**
|
3 |
* The primary class for the plugin
|
4 |
*
|
5 |
* Stores the plugin version, loads and enqueues dependencies
|
6 |
* for the plugin.
|
7 |
*
|
8 |
* @since 1.0.0
|
9 |
*
|
10 |
* @package WPA
|
11 |
* @author Tom McFarlin
|
12 |
* @license http://www.gnu.org/licenses/gpl-2.0.txt
|
13 |
* @link https://tommcfarlin.com/
|
14 |
*/
|
15 |
|
16 |
/**
|
17 |
* Stores the plugin version, loads and enqueues dependencies
|
18 |
* for the plugin.
|
19 |
*
|
20 |
* @package WPA
|
21 |
* @author Tom McFarlin
|
22 |
* @license http://www.gnu.org/licenses/gpl-2.0.txt
|
23 |
* @link https://tommcfarlin.com/
|
24 |
*/
|
25 |
class WP_Simple_Ajax { |
26 |
|
27 |
/**
|
28 |
* Represents the current version of this plugin.
|
29 |
*
|
30 |
* @access private
|
31 |
* @since 1.0.0
|
32 |
* @var string
|
33 |
*/
|
34 |
private $version; |
35 |
|
36 |
/**
|
37 |
* A reference to the Dependency Loader.
|
38 |
*
|
39 |
* @access private
|
40 |
* @since 1.0.0
|
41 |
* @var Dependency_Loader
|
42 |
*/
|
43 |
private $loader; |
44 |
|
45 |
/**
|
46 |
* Initializes the properties of the class.
|
47 |
*
|
48 |
* @access private
|
49 |
* @since 1.0.0
|
50 |
*/
|
51 |
public function __construct() { |
52 |
|
53 |
$this->version = '1.0.0'; |
54 |
$this->loader = new Dependency_Loader(); |
55 |
|
56 |
}
|
57 |
|
58 |
/**
|
59 |
* Initializes this plugin and the dependency loader to include
|
60 |
* the JavaScript necessary for the plugin to function.
|
61 |
*
|
62 |
* @access private
|
63 |
* @since 1.0.0
|
64 |
*/
|
65 |
public function initialize() { |
66 |
|
67 |
$this->loader->initialize(); |
68 |
$this->loader->setup_ajax_handlers(); |
69 |
|
70 |
}
|
71 |
}
|
Trong đoạn code trên, hàm constructor sẽ thiết lập các thuộc tính và khởi tạo các dependency cần thiết để kích hoạt plugin.
Khi hàm initialize
được gọi, plugin sẽ khởi động và nó sẽ gọi phương thức khởi tạo trong class dependency mà chúng tôi đã tạo trước đó trong hướng dẫn này.
Bootstrap
Điều cuối cùng mà chúng tôi cần làm là lấy file chính mà chúng tôi có, sử dụng chức năng include
của PHP và đảm bảo rằng nó biết đến các file PHP cần thiết mà chúng tôi có.
1 |
<?php
|
2 |
|
3 |
/**
|
4 |
* Loads and registers dependencies.
|
5 |
*/
|
6 |
include_once( 'includes/class-dependency-loader.php' ); |
7 |
|
8 |
/**
|
9 |
* The primary class for the plugin
|
10 |
*/
|
11 |
include_once( 'class-wp-simple-ajax.php' ); |
Sau đó, chúng tôi cần định nghĩa một phương thức sẽ khởi tạo file plugin chính và kích hoạt mọi thứ.
1 |
<?php
|
2 |
|
3 |
/**
|
4 |
* Instantiates the main class and initializes the plugin.
|
5 |
*/
|
6 |
function wpa_start_plugin() { |
7 |
|
8 |
$plugin = new WP_Simple_Ajax(); |
9 |
$plugin->initialize(); |
10 |
|
11 |
}
|
Phiên bản cuối cùng của file bootstrap sẽ trông giống như sau:
1 |
<?php
|
2 |
/**
|
3 |
* This plugin demonstrates how to use the WordPress Ajax APIs.
|
4 |
*
|
5 |
* @package WPA
|
6 |
*
|
7 |
* @wordpress-plugin
|
8 |
* Plugin Name: Simple Ajax Demo
|
9 |
* Description: A simple demonstration of the WordPress Ajax APIs.
|
10 |
* Version: 1.0.0
|
11 |
* Author: Tom McFarlin
|
12 |
* Author URI: https://tommcfarlin.com/
|
13 |
* License: GPL-2.0+
|
14 |
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
|
15 |
*/
|
16 |
|
17 |
// If this file is called directly, abort.
|
18 |
if ( ! defined( 'WPINC' ) ) { |
19 |
die; |
20 |
}
|
21 |
|
22 |
/**
|
23 |
* Loads and registers dependencies.
|
24 |
*/
|
25 |
include_once( 'includes/class-dependency-loader.php' ); |
26 |
|
27 |
/**
|
28 |
* The primary class for the plugin
|
29 |
*/
|
30 |
include_once( 'class-wp-simple-ajax.php' ); |
31 |
|
32 |
/**
|
33 |
* Instantiates the main class and initializes the plugin.
|
34 |
*/
|
35 |
function wpa_start_plugin() { |
36 |
|
37 |
$plugin = new WP_Simple_Ajax(); |
38 |
$plugin->initialize(); |
39 |
|
40 |
}
|
41 |
wpa_start_plugin(); |
Đầu tiên, file sẽ kiểm tra xem liệu nó có được truy cập trực tiếp hay không bằng cách kiểm tra xem hằng số WordPress đã được định nghĩa chưa. Nếu chưa, thì xử lý dừng lại.
Sau đó, nó include các class khác nhau mà chúng tôi đã tạo ra trong hướng dẫn này. Cuối cùng, nó định nghĩa một hàm được gọi khi WordPress tải plugin để khởi động plugin và đưa mọi thứ vào hoạt động.
Tổng kết
Và chúng ta đã đi đến kết thúc của loạt bài gồm hai phần này. Hy vọng rằng bạn không chỉ học được một số thực hành tốt nhất để kết hợp Ajax vào các dự án WordPress của bạn, mà còn một chút về việc làm tài liệu cho code thủ tục và hướng đối tượng, cũng như nhìn ra sự khác biệt trong mức độ sắp đặt của code.
Trong bài viết sắp đến, tôi có thể xem lại một số khái niệm hướng đối tượng đã được giới thiệu ở đây và bao gồm chúng chi tiết hơn. Tuy nhiên, bây giờ, hãy xem qua plugin bằng cách sử dụng liên kết GitHub trên sidebar của trang này.
Hãy nhớ rằng, bạn có thể tìm thấy tất cả các khóa học và hướng dẫn của tôi trên trang profile của tôi và bạn có thể theo dõi tôi trên blog và/hoặc Twitter của tôi tại @tommcfarlin, đó là nơi tôi nói về phát triển phần mềm trong bối cảnh của WordPress.
Như thường lệ, vui lòng để lại bất kỳ câu hỏi hoặc nhận xét nào trong feed bên dưới và tôi sẽ cố gắng trả lời từng cái một.