学习 WordPress 插件开发是一个非常有益且实用的技能,可以帮助你扩展和定制 WordPress 网站的功能。以下是一个详细的指南,帮助你从零开始学习 WordPress 插件开发。
友情链接:ACEJoy
1. 基础知识准备
在开始插件开发之前,你需要具备一些基本知识:
- HTML/CSS:了解基本的网页结构和样式。
- JavaScript:掌握基本的编程逻辑和DOM操作。
- PHP:WordPress 插件主要使用 PHP 编写,需要了解 PHP 的基本语法和功能。
- MySQL:了解基本的数据库操作,因为 WordPress 使用 MySQL 作为数据库。
2. 设置开发环境
为插件开发设置一个合适的开发环境:
- 本地服务器:使用工具如 XAMPP、MAMP 或 Local by Flywheel 来设置一个本地开发服务器。
- 文本编辑器或 IDE:选择一个代码编辑器,如 Visual Studio Code、Sublime Text 或 PHPStorm。
- WordPress 安装:在本地服务器上安装最新版本的 WordPress。
3. 了解 WordPress 插件结构
一个简单的 WordPress 插件通常包含以下文件和文件夹:
- 插件主文件:通常命名为
plugin-name.php
,包含插件的主要功能代码。 - README 文件:包含插件的基本信息和说明。
- 其他文件:如 CSS、JavaScript、图片等资源文件。
4. 创建第一个插件
下面是创建一个简单插件的步骤:
4.1 创建插件目录和主文件
在 wp-content/plugins
目录下创建一个新文件夹,例如 my-first-plugin
。在该文件夹中创建一个 PHP 文件,例如 my-first-plugin.php
。
4.2 插件头部信息
在 my-first-plugin.php
文件中添加插件的头部信息:
<?php
/*
Plugin Name: My First Plugin
Plugin URI: https://example.com/my-first-plugin
Description: This is my first WordPress plugin.
Version: 1.0
Author: Your Name
Author URI: https://example.com
License: GPL2
*/
4.3 插件的基本功能
添加一些基本功能,如在 WordPress 后台显示一个简单的信息:
function my_first_plugin_admin_notice() {
echo '<div class="notice notice-success is-dismissible">
<p>My First Plugin is activated!</p>
</div>';
}
add_action('admin_notices', 'my_first_plugin_admin_notice');
5. 学习 WordPress 钩子(Hooks)
WordPress 插件开发的核心是钩子(Hooks),它包括动作钩子(Action Hooks)和过滤器钩子(Filter Hooks)。通过钩子,你可以在特定的时间点执行代码:
- 动作钩子(Actions):允许你在 WordPress 的执行过程中插入自定义代码。
- 过滤器钩子(Filters):允许你修改 WordPress 数据或输出。
例子:
// 动作钩子
add_action('wp_footer', 'my_first_plugin_footer_message');
function my_first_plugin_footer_message() {
echo '<p>Thank you for visiting my website!</p>';
}
// 过滤器钩子
add_filter('the_content', 'my_first_plugin_content_filter');
function my_first_plugin_content_filter(
content . '<p>Custom content added by My First Plugin.</p>';
}
6. 学习 WordPress 插件 API
WordPress 提供了丰富的 API 供插件开发者使用:
- Settings API:管理插件设置页面。
- Shortcode API:创建短代码。
- Widgets API:创建自定义小工具。
- REST API:创建自定义 REST 端点。
7. 学习插件国际化和本地化
为了使你的插件可以被翻译成不同的语言,了解如何国际化和本地化插件是很重要的:
// 加载插件文本域
function my_first_plugin_load_textdomain() {
load_plugin_textdomain( 'my-first-plugin', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
}
add_action('plugins_loaded', 'my_first_plugin_load_textdomain');
8. 探索插件开发资源
- 官方文档:阅读 WordPress 插件开发手册。
- 教程和书籍:查找相关的在线教程和书籍,如《Professional WordPress Plugin Development》。
9. 配置插件设置页面
为插件添加一个设置页面是常见的需求。以下是如何使用 Settings API 创建一个简单的插件设置页面的步骤:
9.1 添加菜单项
首先,需要在 WordPress 管理菜单中添加一个新的菜单项:
function my_first_plugin_menu() {
add_menu_page(
'My First Plugin Settings', // 页面标题
'My First Plugin', // 菜单标题
'manage_options', // 用户权限
'my-first-plugin', // 菜单别名
'my_first_plugin_settings_page', // 回调函数
'dashicons-admin-generic' // 图标
);
}
add_action('admin_menu', 'my_first_plugin_menu');
9.2 创建设置页面
在回调函数 my_first_plugin_settings_page
中定义设置页面的内容:
function my_first_plugin_settings_page() {
?>
<div class="wrap">
<h1>My First Plugin Settings</h1>
<form method="post" action="options.php">
<?php
settings_fields('my_first_plugin_options_group');
do_settings_sections('my-first-plugin');
submit_button();
?>
</form>
</div>
<?php
}
9.3 注册设置
使用 Settings API 注册插件设置:
function my_first_plugin_settings_init() {
register_setting('my_first_plugin_options_group', 'my_first_plugin_option_name');
add_settings_section(
'my_first_plugin_settings_section', // ID
'My First Plugin Settings', // 标题
'my_first_plugin_settings_section_callback', // 回调函数
'my-first-plugin' // 页面
);
add_settings_field(
'my_first_plugin_field', // ID
'Sample Field', // 标签
'my_first_plugin_field_callback', // 回调函数
'my-first-plugin', // 页面
'my_first_plugin_settings_section' // 部分
);
}
add_action('admin_init', 'my_first_plugin_settings_init');
function my_first_plugin_settings_section_callback() {
echo 'Enter your settings below:';
}
function my_first_plugin_field_callback() {
option) . '" />';
}
10. 创建短代码
短代码允许用户在文章和页面中插入自定义内容。以下是如何创建一个简单的短代码:
function my_first_plugin_shortcode(
atts = shortcode_atts(
array(
'text' => 'Hello, World!',
),
atts['text']) . '</div>';
}
add_shortcode('my_shortcode', 'my_first_plugin_shortcode');
11. 创建小工具
小工具可以在 WordPress 侧边栏等小工具区域显示内容。以下是如何创建一个简单的小工具:
“`php
class My_First_Plugin_Widget extends WP_Widget {
function construct() { parent::_construct( ‘my_first_plugin_widget’, // ID (‘My First Plugin Widget’, ‘text_domain’), // 名称
array(‘description’ => _(‘A simple widget’, ‘text_domain’)) // 描述
);
}
public function widget(
instance) {
echo
args['before_title'] . apply_filters('widget_title',
args['after_title'];
echo '<p>' . esc_html(
args['after_widget'];
}
public function form(
title = !empty(
instance['title'] : __('New title', 'text_domain');
instance['text']) ?
this->get_field_id('title')); ?>"><?php _e('Title:'); ?></label>
<input class="widefat" id="<?php echo esc_attr(
this->get_field_name('title')); ?>" type="text" value="<?php echo esc_attr(
this->get_field_id('text')); ?>"><?php _e('Text:'); ?></label>
11. 创建小工具(续)
11.1 完成小工具的表单和更新方法
在上面的代码基础上,继续完成小工具的表单和更新方法:
<textarea class="widefat" id="<?php echo esc_attr(
this->get_field_name('text')); ?>"><?php echo esc_attr(
new_instance,
instance = array();
new_instance['title'])) ? strip_tags(
instance['text'] = (!empty(
new_instance['text']) : '';
return
request) {
return new WP_REST_Response(array('message' => 'Hello, World!'), 200);
}
13. 安全性和最佳实践
确保你的插件是安全的,并遵循最佳实践:
13.1 数据验证和清理
在处理用户输入时,确保对数据进行验证和清理:
// 验证和清理输入数据
function my_first_plugin_validate_data(
data);
}
13.2 使用非ces (Nonces) 进行安全验证
在处理表单提交时,使用非ces 来防止跨站请求伪造 (CSRF) 攻击:
// 创建一个 nonce
function my_first_plugin_create_nonce() {
return wp_create_nonce('my_first_plugin_nonce_action');
}
// 验证 nonce
function my_first_plugin_verify_nonce(
nonce, 'my_first_plugin_nonce_action');
}
13.3 避免直接文件访问
在插件的每个文件顶部添加以下代码,防止直接访问:
if (!defined('ABSPATH')) {
exit; // 退出如果直接访问
}
14. 插件国际化和本地化(续)
确保你的插件可以被翻译成不同的语言:
14.1 创建语言文件
在插件目录下创建一个 languages
文件夹,并使用 .pot
文件保存插件的翻译字符串。例如,创建一个 my-first-plugin.pot
文件。
14.2 加载语言文件
在插件初始化时加载语言文件:
function my_first_plugin_load_textdomain() {
load_plugin_textdomain('my-first-plugin', false, dirname(plugin_basename(__FILE__)) . '/languages');
}
add_action('plugins_loaded', 'my_first_plugin_load_textdomain');
15. 发布和分发插件
当你完成插件开发后,可以考虑将插件发布到 WordPress 插件目录中。
15.1 准备插件
确保你的插件包含以下文件:
- 主插件文件:包含插件头部信息和主要功能代码。
- README 文件:详细描述插件的功能、安装方法和使用说明。
- 语言文件:包含
.pot
文件和翻译文件。 - 其他资源文件:如 CSS、JavaScript、图片等资源文件。
15.2 创建 README 文件
使用 Markdown 编写 README 文件,并确保它包含以下部分:
- Plugin Name: 插件名称
- Description: 插件描述
- Installation: 安装说明
- Frequently Asked Questions: 常见问题解答
- Changelog: 更新日志
15.3 提交插件
访问 WordPress 插件提交页面 并按照指南提交你的插件。一旦审核通过,你的插件将出现在 WordPress 插件目录中。
16. 进一步学习资源
要深入学习 WordPress 插件开发,以下资源非常有用:
16.1 官方文档
- WordPress Plugin Handbook: 官方插件开发手册,包含详细的开发指南和示例代码。
- WordPress Code Reference: 提供了 WordPress 核心函数、类、钩子的详细文档。
16.2 在线课程和教程
- Udemy: 提供了许多关于 WordPress 插件开发的在线课程。
- Lynda/LinkedIn Learning: 提供了高质量的 WordPress 开发视频教程。
16.3 开发者社区
- WordPress Stack Exchange: 专门针对 WordPress 开发问题的问答社区。
- WordPress.org 支持论坛: 官方支持论坛,可以在这里提问和回答问题。
16.4 博客和文章
- Tuts+: 提供了大量关于 WordPress 开发的文章和教程。
- Smashing Magazine: 定期发布关于 WordPress 的开发技巧和最佳实践的文章。
17. 高级插件开发技巧
17.1 面向对象编程 (OOP)
使用面向对象编程风格可以使你的插件代码更具可维护性和可扩展性。以下是一个简单的 OOP 插件示例:
class My_First_Plugin {
public function __construct() {
add_action('init', array(
args = array(
'public' => true,
'label' => 'Custom Post',
);
register_post_type('custom_post',
my_first_plugin = new My_First_Plugin();
17.2 使用命名空间
使用命名空间可以避免类名和函数名冲突:
namespace MyFirstPlugin;
class Main {
public function __construct() {
add_action('init', array(
args = array(
'public' => true,
'label' => 'Custom Post',
);
register_post_type('custom_post',
main = new Main();
17.3 自动加载
使用自动加载器可以简化类文件的加载:
spl_autoload_register(function (
prefix = 'MyFirstPlugin\\';
len = strlen(
prefix,
len) !== 0) {
return;
}
class,
file =
relative_class) . '.php';
if (file_exists(
file;
}
});
17.4 单例模式
使用单例模式确保插件的主类只实例化一次:
class My_First_Plugin {
private static
this, 'init'));
}
public static function get_instance() {
if (self::
instance = new self();
}
return self::
cache_key = 'my_first_plugin_cached_data';
cache_key);
if (
data = '...';
wp_cache_set(
data, '', 3600);
}
return
wpdb;
wpdb->prefix . 'my_first_plugin_table';
wpdb->get_charset_collate();
table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
name tinytext NOT NULL,
email text NOT NULL,
date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
PRIMARY KEY (id)
)
sql);
}
register_activation_hook(__FILE__, 'my_first_plugin_create_table');
19.2 插入数据
function my_first_plugin_insert_data(
email) {
global
table_name =
wpdb->insert(
name,
'email' =>
wpdb;
wpdb->prefix . 'my_first_plugin_table';
wpdb->get_results("SELECT * FROM
results;
}
20. AJAX 操作
使用 AJAX 可以在不刷新页面的情况下与服务器进行交互。
20.1 在前端调用 AJAX
jQuery(document).ready(function(
('#my-button').click(function() {
data =
response = array('message' => 'Success', 'data' =>
response);
}
add_action('wp_ajax_my_first_plugin_action', 'my_first_plugin_ajax_handler');
add_action('wp_ajax_nopriv_my_first_plugin_action', 'my_first_plugin_ajax_handler');
21. 使用自定义钩子和过滤器
创建自定义钩子和过滤器,使其他开发者可以扩展你的插件功能。
21.1 创建自定义动作钩子
function my_first_plugin_do_custom_action() {
do_action('my_first_plugin_custom_action');
}
function my_first_plugin_add_custom_action() {
echo 'Custom Action Triggered!';
}
add_action('my_first_plugin_custom_action', 'my_first_plugin_add_custom_action');
21.2 创建自定义过滤器
function my_first_plugin_apply_custom_filter(
content);
}
function my_first_plugin_modify_content(
content . ' - Modified by custom filter';
}
add_filter('my_first_plugin_custom_filter', 'my_first_plugin_modify_content');
22. 使用第三方库
有时,你可能需要在插件中使用第三方库。你可以通过 Composer 来管理依赖关系。
22.1 安装 Composer
确保在你的开发环境中安装了 Composer。
22.2 创建 composer.json
文件
在插件根目录下创建一个 composer.json
文件:
{
"name": "yourname/yourplugin",
"description": "A description of your plugin",
"require": {
"some/package": "^1.0"
}
}
22.3 安装依赖
在终端中运行以下命令:
composer install
22.4 在插件中加载 Composer 自动加载器
在插件的主文件中添加以下代码:
require_once __DIR__ . '/vendor/autoload.php';
23. 测试和调试(续)
23.1 使用 WP_DEBUG
在 wp-config.php
文件中启用调试模式:
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
@ini_set('display_errors', 0);
此设置会将错误记录到 wp-content/debug.log
文件中,而不是直接显示在页面上。
23.2 使用 PHPStorm 和 Xdebug 进行调试
- 安装 Xdebug: 根据你的 PHP 版本和操作系统安装 Xdebug。
- 配置 php.ini: 添加以下行到你的
php.ini
文件:zend_extension="path/to/xdebug.so" xdebug.remote_enable=1 xdebug.remote_host=127.0.0.1 xdebug.remote_port=9000 xdebug.remote_handler=dbgp
- 配置 PHPStorm: 在 PHPStorm 中配置 Xdebug 远程调试。在 “Preferences” -> “Languages & Frameworks” -> “PHP” -> “Debug” 中设置 Xdebug 端口为 9000。
- 设置断点: 在 PHPStorm 中打开你的插件代码并设置断点。
- 启动调试: 启动 PHPStorm 的调试监听,然后在浏览器中访问你的插件页面。代码将在断点处暂停,你可以逐步调试。
24. 国际化与本地化
24.1 准备插件以进行翻译
使用 __()
和 _e()
函数准备你的插件代码:
echo __('Hello, World!', 'my-first-plugin');
_e('Hello, World!', 'my-first-plugin');
24.2 创建 POT 文件
使用 xgettext
或 Poedit 等工具生成 POT 文件:
xgettext --from-code=UTF-8 -k__ -k_e -o languages/my-first-plugin.pot
函数来防止 SQL 注入:cleaned_data = sanitize_text_field(
wpdb->prepare()
global
sql =
wpdb->prefix}my_table WHERE id = %d",
results =
sql);
26. 创建设置页面
26.1 添加设置页面
function my_first_plugin_add_admin_menu() { add_options_page( __('My First Plugin Settings', 'my-first-plugin'), __('My First Plugin', 'my-first-plugin'), 'manage_options', 'my-first-plugin', 'my_first_plugin_options_page' ); } add_action('admin_menu', 'my_first_plugin_add_admin_menu');
26.2 创建设置页面内容
function my_first_plugin_options_page() { ?> <div class="wrap"> <h1><?php _e('My First Plugin Settings', 'my-first-plugin'); ?></h1> <form action="options.php" method="post"> <?php settings_fields('my_first_plugin_options'); do_settings_sections('my-first-plugin'); submit_button(); ?> </form> </div> <?php }
26.3 注册设置
```php
function my_first_plugin_settings_init() {
register_setting('my_first_plugin_options', 'my_first_plugin_options');add_settings_section( 'my_first_plugin_section', __('General Settings', 'my-first-plugin'), 'my_first_plugin_section_callback', 'my-first-plugin' ); add_settings_field( 'my_first_plugin_field_text', __('Sample Text Field', 'my-first-plugin'), 'my_first_plugin_field_text_callback', '
26. 创建设置页面(续)
26.3 注册设置(续)
add_settings_field( 'my_first_plugin_field_text', __('Sample Text Field', 'my-first-plugin'), 'my_first_plugin_field_text_callback', 'my-first-plugin', 'my_first_plugin_section' ); } add_action('admin_init', 'my_first_plugin_settings_init'); function my_first_plugin_section_callback() { echo __('Enter your settings below:', 'my-first-plugin'); } function my_first_plugin_field_text_callback() {
options['my_first_plugin_field_text']) ? esc_attr(
args,
args['before_widget']; if (!empty(
args['before_title'] . apply_filters('widget_title',
args['after_title']; } echo __('Hello, World!', 'my-first-plugin'); echo
instance) {
instance['title']) ?
this->get_field_id('title'); ?>"><?php _e('Title:', 'my-first-plugin'); ?></label> <input class="widefat" id="<?php echo
this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr(
new_instance,
instance = array();
new_instance['title'])) ? strip_tags(
instance; } }
27.2 注册小工具
function my_first_plugin_register_widgets() { register_widget('My_First_Plugin_Widget'); } add_action('widgets_init', 'my_first_plugin_register_widgets');
28. 使用 REST API
28.1 创建自定义 REST API 路由
function my_first_plugin_register_rest_route() { register_rest_route('my-first-plugin/v1', '/data/', array( 'methods' => 'GET', 'callback' => 'my_first_plugin_get_data', )); } add_action('rest_api_init', 'my_first_plugin_register_rest_route'); function my_first_plugin_get_data(
data = array('message' => 'Hello, World!'); return new WP_REST_Response(
atts = [],
atts = array_change_key_case((array)
a = shortcode_atts([ 'title' => 'Default Title', ],
a['title']) . '</div>'; } add_shortcode('my_first_plugin', 'my_first_plugin_shortcode');
29.2 使用短代码
在文章或页面中使用短代码:
[my_first_plugin title="Hello, World!"]
30. 单元测试(续)
30.1 设置 PHPUnit(续)
在
tests
目录中创建bootstrap.php
文件以初始化测试环境:<?php
_tests_dir) {
_tests_dir . '/includes/functions.php'; function _manually_load_plugin() { require dirname(__DIR__) . '/my-first-plugin.php'; } tests_add_filter('muplugins_loaded', '_manually_load_plugin'); require
this->assertTrue(true); } }
30.2 运行测试
使用以下命令运行 PHPUnit 测试:
phpunit --bootstrap tests/bootstrap.php tests/test-sample.php
31. 使用自定义表单
31.1 创建自定义表单
在插件中使用 HTML 和 PHP 创建自定义表单:
function my_first_plugin_form() { ?> <form action="<?php echo esc_url(admin_url('admin-post.php')); ?>" method="post"> <input type="hidden" name="action" value="my_first_plugin_form_action"> <?php wp_nonce_field('my_first_plugin_form_nonce', 'my_first_plugin_nonce'); ?> <label for="name"><?php _e('Name:', 'my-first-plugin'); ?></label> <input type="text" name="name" id="name" required> <input type="submit" value="<?php _e('Submit', 'my-first-plugin'); ?>"> </form> <?php }
31.2 处理表单提交
在插件中处理表单提交:
function my_first_plugin_form_handler() { if (!isset(
_POST['my_first_plugin_nonce'], 'my_first_plugin_form_nonce')) { wp_die(__('Nonce verification failed', 'my-first-plugin')); } if (!current_user_can('manage_options')) { wp_die(__('You do not have sufficient permissions to access this page.', 'my-first-plugin')); }
_POST['name']); // 处理表单数据,例如保存到数据库 wp_redirect(admin_url('options-general.php?page=my-first-plugin&message=success')); exit; } add_action('admin_post_my_first_plugin_form_action', 'my_first_plugin_form_handler');
32. 使用 AJAX
32.1 注册 AJAX 动作
function my_first_plugin_ajax_handler() { check_ajax_referer('my_first_plugin_nonce', 'security'); if (!current_user_can('manage_options')) { wp_send_json_error(__('You do not have sufficient permissions to access this page.', 'my-first-plugin')); }
response); } add_action('wp_ajax_my_first_plugin_action', 'my_first_plugin_ajax_handler');
32.2 在前端使用 AJAX
在前端脚本中使用 AJAX 进行请求:
jQuery(document).ready(function(
('#my-button').on('click', function() {
wpdb;
wpdb->prefix . 'my_first_plugin_table';
wpdb->get_charset_collate();
table_name ( id mediumint(9) NOT NULL AUTO_INCREMENT, name tinytext NOT NULL, value text NOT NULL, PRIMARY KEY (id) )
sql); } register_activation_hook(__FILE__, 'my_first_plugin_create_db_table');
33.2 插入数据
在插件中插入数据到自定义表:
function my_first_plugin_insert_data(
value) { global
table_name =
wpdb->insert(
name, 'value' =>
wpdb;
wpdb->prefix . 'my_first_plugin_table';
wpdb->get_results("SELECT * FROM
results; }
34. 本地化
34.1 加载插件的翻译文件
在插件中加载翻译文件:
function my_first_plugin_load_textdomain() { load_plugin_textdomain('my-first-plugin', false, dirname(plugin_basename(__FILE__)) . '/languages'); } add_action('plugins_loaded', 'my_first_plugin_load_textdomain');
34.2 创建翻译文件
使用 Poedit 或其他翻译工具创建
.po
和.mo
文件,并将它们放在languages
目录中。例如,创建my-first-plugin-zh_CN.po
和my-first-plugin-zh_CN.mo
文件。35. 安全性
35.1 数据验证和清理
在处理用户输入时,确保数据的验证和清理:
_POST['name']);
35.2 非可信数据的输出
在输出非可信数据时,使用适当的 WordPress 函数进行转义:
echo esc_html(
_POST['my_first_plugin_nonce']) || !wp_verify_nonce(
data = wp_cache_get('my_first_plugin_data'); if (
data = my_first_plugin_get_data(); wp_cache_set('my_first_plugin_data',
url) { if (strpos(
url; } else if (is_admin()) { return str_replace('#async', '',
url) . "' async='async"; } } add_filter('clean_url', 'my_first_plugin_enqueue_async_script', 11, 1);
37. 与第三方服务集成
37.1 使用 API 密钥
存储和使用 API 密钥:
response = wp_remote_get("https://api.example.com/data?api_key={
response)) {
response->get_error_message(); echo "Something went wrong:
body = wp_remote_retrieve_body(
data = json_decode(
*** QuickLaTeX cannot compile formula: body); }</code></pre> <!-- /wp:code --> <!-- wp:paragraph --> <!-- /wp:paragraph --> <!-- wp:heading {"level":3} --> <h3 class="wp-block-heading">38. 版本控制</h3> <!-- /wp:heading --> <!-- wp:heading {"level":4} --> <h4 class="wp-block-heading">38.1 使用 Git</h4> <!-- /wp:heading --> <!-- wp:paragraph --> 使用 Git 进行版本控制是现代开发的最佳实践。以下是一些基本步骤来初始化和使用 Git: <!-- /wp:paragraph --> <!-- wp:list {"ordered":true} --> <ol><!-- wp:list-item --> <li><strong>初始化 Git 仓库</strong>: <code>git init</code></li> <!-- /wp:list-item --> <!-- wp:list-item --> <li><strong>添加 <code>.gitignore</code> 文件</strong>: 创建一个 <code>.gitignore</code> 文件,以忽略不需要版本控制的文件和目录。例如: <code>/vendor/ /node_modules/ /wp-content/uploads/ .env</code></li> <!-- /wp:list-item --> <!-- wp:list-item --> <li><strong>添加并提交文件</strong>: <code>git add . git commit -m "Initial commit"</code></li> <!-- /wp:list-item --> <!-- wp:list-item --> <li><strong>推送到远程仓库</strong>: <code>git remote add origin <remote-repository-URL> git push -u origin master</code></li> <!-- /wp:list-item --></ol> <!-- /wp:list --> <!-- wp:heading {"level":4} --> <h4 class="wp-block-heading">38.2 使用 GitHub Actions 进行 CI/CD</h4> <!-- /wp:heading --> <!-- wp:paragraph --> GitHub Actions 可以帮助你自动化测试、构建和部署插件。 <!-- /wp:paragraph --> <!-- wp:list {"ordered":true} --> <ol><!-- wp:list-item --> <li><strong>创建 GitHub Actions 工作流</strong>: 在你的仓库中创建 <code>.github/workflows/main.yml</code> 文件: <code>name: CI on: push: branches: - master pull_request: branches: - master jobs: build: runs-on: ubuntu-lateststeps: - name: Checkout code uses: actions/checkout@v2 - name: Set up PHP uses: shivammathur/setup-php@v2 with: php-version: '7.4' - name: Install dependencies run: composer install - name: Run tests run: vendor/bin/phpunit</code></pre></li></code></li> <!-- /wp:list-item --></ol> <!-- /wp:list --> <!-- wp:heading {"level":3} --> <h3 class="wp-block-heading">39. 钩子和过滤器</h3> <!-- /wp:heading --> <!-- wp:heading {"level":4} --> <h4 class="wp-block-heading">39.1 自定义钩子</h4> <!-- /wp:heading --> <!-- wp:paragraph --> 创建自定义钩子,让其他开发者可以扩展你的插件功能: <!-- /wp:paragraph --> <!-- wp:code --> <pre class="wp-block-code"><code>do_action('my_first_plugin_custom_action', *** Error message: Cannot download image from QuickLaTeX server: cURL error 28: Operation timed out after 5000 milliseconds with 32523 out of 47661 bytes received Please make sure your server/PHP settings allow HTTP requests to external resources ("allow_url_fopen", etc.) These links might help in finding solution: http://wordpress.org/extend/plugins/core-control/ http://wordpress.org/support/topic/an-unexpected-http-error-occurred-during-the-api-request-on-wordpress-3?replies=37arg1,arg1,
value = apply_filters('my_first_plugin_custom_filter',
value) { // 修改并返回数据 return
request) {
data, 200); }
41. Gutenberg 块
41.1 创建自定义 Gutenberg 块
继续创建和注册自定义 Gutenberg 块。
- 创建编辑器脚本(续): 在
src
目录中继续创建index.js
文件的内容:import { registerBlockType } from '@wordpress/blocks'; import { useBlockProps, RichText } from '@wordpress/block-editor'; registerBlockType('my-first-plugin/my-custom-block', { edit({ attributes, setAttributes }) { const blockProps = useBlockProps(); return ( <div {...blockProps}> <RichText tagName="p" onChange={(content) => setAttributes({ content })} value={attributes.content} placeholder="Write your content here..." /> </div> ); }, save({ attributes }) { const blockProps = useBlockProps.save(); return ( <div {...blockProps}> <RichText.Content tagName="p" value={attributes.content} /> </div> ); }, attributes: { content: { type: 'string', source: 'html', selector: 'p' } } });
- 编译脚本: 更新
package.json
以添加构建脚本:{ "scripts": { "build": "wp-scripts build", "start": "wp-scripts start" }, "devDependencies": { "@wordpress/scripts": "^23.0.0" } }
然后运行构建命令:npm run build
- 加载脚本: 在插件的 PHP 文件中加载编译后的 JavaScript 文件:
function my_first_plugin_register_block() { wp_register_script( 'my-first-plugin-editor-script', plugins_url('build/index.js', __FILE__), array('wp-blocks', 'wp-element', 'wp-editor') );register_block_type('my-first-plugin/my-custom-block', array( 'editor_script' => 'my-first-plugin-editor-script', ));} add_action('init', 'my_first_plugin_register_block');
42. 使用 WP-CLI
WP-CLI 是一个强大的命令行工具,可以用于管理 WordPress 安装,包括插件的开发和调试。
42.1 创建自定义 WP-CLI 命令
- 注册自定义命令: 在插件的主文件中注册一个自定义 WP-CLI 命令:
if (defined('WP_CLI') && WP_CLI) { WP_CLI::add_command('my_first_plugin', 'My_First_Plugin_CLI_Command'); } class My_First_Plugin_CLI_Command { public function hello(
assoc_args) { WP_CLI::success('Hello, World!'); } }
- 运行命令: 在终端中运行自定义 WP-CLI 命令:
wp my_first_plugin hello
43. 单元测试
43.1 使用 PHPUnit 进行单元测试
- 安装 PHPUnit: 使用 Composer 安装 PHPUnit:
composer require --dev phpunit/phpunit
- 设置测试环境: 创建
phpunit.xml.dist
文件以配置测试环境:<phpunit bootstrap="tests/bootstrap.php"> <testsuites> <testsuite name="My First Plugin Test Suite"> <directory>tests</directory> </testsuite> </testsuites> </phpunit>
- 编写测试: 在
tests
目录中创建测试文件,例如test-sample.php
:class SampleTest extends WP_UnitTestCase { public function test_sample() {
email = sanitize_email(
url = esc_url(
_POST['_wpnonce'], 'my_action')) { die('Security check failed'); }
45.2 SQL 注入防护
使用
prepare
方法来防止 SQL 注入:global
wpdb->query(
wpdb->posts WHERE post_title = %s",
message = __('Hello, World!', 'my-first-plugin'); _e('Welcome to my plugin!', 'my-first-plugin');
wp i18n
工具来生成 POT 文件: npx wp i18n make-pot . languages/my-first-plugin.pot
47. 优化性能
47.1 缓存
- 使用 Transients API: 缓存临时数据,以减少数据库查询:
data === false) {
data, 12 * HOUR_IN_SECONDS); }
- 使用对象缓存: 使用
wp_cache_set
和wp_cache_get
进行对象缓存:wp_cache_set('my_cache_key',
cached_data = wp_cache_get('my_cache_key');
47.2 优化数据库查询
确保数据库查询高效,避免不必要的查询和数据加载:
global
results =
wpdb->prepare("SELECT * FROM
instance = null;public static function get_instance() { if (null === self::
instance = new self(); } return self::
this->setup_hooks(); } private function setup_hooks() { add_action('init', array(
this, 'add_admin_menu')); }public function add_admin_menu() { add_menu_page('My First Plugin', 'My First Plugin', 'manage_options', 'my-first-plugin', array(
instances = array();public function set(
instance) {
name] =
name) { return
name]; }}
container->set('admin', new MyFirstPlugin_Admin());
container->get('admin');
49. REST API
49.1 创建自定义 REST API 端点
WordPress 提供了一个内置的 REST API,可以用来创建自定义端点。
- 注册自定义端点: 使用
register_rest_route
函数注册一个自定义 REST API 端点:function my_first_plugin_register_api_routes() { register_rest_route('my-first-plugin/v1', '/data', array( 'methods' => 'GET', 'callback' => 'my_first_plugin_get_data', )); } add_action('rest_api_init', 'my_first_plugin_register_api_routes'); function my_first_plugin_get_data(
blog_ids as
blog_id); my_first_plugin_single_deactivate(); restore_current_blog(); } } else { my_first_plugin_single_deactivate(); } } register_deactivation_hook(__FILE__, 'my_first_plugin_deactivate'); ```
50.2 处理多站点特定功能
- 存储全局设置: 在多站点环境中,可以使用
get_site_option
和update_site_option
来存储和检索全局设置:function my_first_plugin_get_global_setting(
key); } function my_first_plugin_set_global_setting(
value) { update_site_option(
value); }
- 跨站点数据同步: 在多站点网络中,可以通过
switch_to_blog
和restore_current_blog
函数在不同站点之间切换,以同步数据:function my_first_plugin_sync_data_across_sites(
wpdb;
wpdb->get_col("SELECT blog_id FROM
blog_ids as
blog_id); update_option('my_first_plugin_data',
this->assertTrue(true); } }
- 运行测试: 运行 PHPUnit 以执行测试:
vendor/bin/phpunit
52. 钩子和过滤器
52.1 创建自定义钩子
- 创建自定义动作钩子: 在插件代码中创建一个自定义动作钩子:
do_action('my_first_plugin_custom_action',
arg2);
- 创建自定义过滤器钩子: 在插件代码中创建一个自定义过滤器钩子:
value,
arg2);
52.2 使用钩子和过滤器
- 添加动作钩子: 使用
add_action
函数来挂载自定义动作钩子:add_action('my_first_plugin_custom_action', 'my_custom_action_function', 10, 2); function my_custom_action_function(
arg2) { // 自定义动作处理逻辑 }
- 添加过滤器钩子: 使用
add_filter
函数来挂载自定义过滤器钩子:add_filter('my_first_plugin_custom_filter', 'my_custom_filter_function', 10, 3); function my_custom_filter_function(
arg1,
value; }
发表回复