WordPress 动作钩子 (Actions)
动作钩子是 WordPress 钩子系统的两大核心之一,用于在特定事件发生时执行自定义代码。
📚 钩子工作原理
mermaid
sequenceDiagram
participant WP as WordPress 核心
participant Hook as 钩子系统
participant Plugin as 插件/主题
WP->>Hook: do_action('init')
Hook->>Hook: 检查注册的回调
Hook->>Plugin: 调用回调函数
Plugin-->>Hook: 执行自定义代码
Hook-->>WP: 返回执行结果1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
🎯 常用动作钩子
初始化钩子
| 钩子 | 说明 | 优先级 |
|---|---|---|
muplugins_loaded | 必须插件加载后 | 10 |
registered_taxonomy | 分类法注册后 | 10 |
registered_post_type | 文章类型注册后 | 10 |
load-{page} | 特定页面加载时 | 10 |
init | WordPress 初始化 | 10 |
widgets_init | 小工具初始化 | 10 |
wp_loaded | WP 完全加载后 | 10 |
auth_cookie_valid | 认证 Cookie 验证 | 10 |
头部和页脚钩子
| 钩子 | 说明 |
|---|---|
wp_head | 在 </head> 前调用 |
wp_footer | 在 </body> 前调用 |
wp_meta | 在侧边栏 Meta 部分调用 |
login_head | 登录页面头部 |
内容钩子
| 钩子 | 说明 |
|---|---|
the_post | 循环中处理文章时 |
loop_start | 循环开始时 |
loop_end | 循环结束时 |
the_content | 文章内容输出前 |
the_excerpt | 文章摘要输出前 |
文章和页面钩子
| 钩子 | 说明 |
|---|---|
add_meta_boxes | 添加 Meta Box 时 |
save_post_{post_type} | 保存特定类型文章时 |
publish_{post_type} | 发布文章时 |
delete_post | 删除文章时 |
transition_post_status | 文章状态改变时 |
评论钩子
| 钩子 | 说明 |
|---|---|
comment_post | 评论提交后 |
comment_form_before | 评论表单前 |
comment_form_after | 评论表单后 |
wp_insert_comment | 插入评论后 |
用户钩子
| 钩子 | 说明 |
|---|---|
user_register | 用户注册后 |
profile_update | 用户资料更新后 |
delete_user | 删除用户时 |
set_user_role | 设置用户角色时 |
仪表盘钩子
| 钩子 | 说明 |
|---|---|
admin_menu | 管理菜单创建时 |
admin_init | 管理页面初始化时 |
admin_head | 管理页面头部 |
admin_footer | 管理页面底部 |
wp_dashboard_setup | 仪表盘小工具设置时 |
💡 常用钩子示例
init 钩子
WordPress 初始化时执行:
php
<?php
// 注册分类法和文章类型
add_action('init', 'my_custom_post_types');
function my_custom_post_types() {
register_post_type('portfolio', array(
'labels' => array(
'name' => '作品集',
'singular_name' => '作品',
),
'public' => true,
'has_archive' => true,
'supports' => array('title', 'editor', 'thumbnail'),
));
}
// 加载文本域
add_action('init', 'my_load_textdomain');
function my_load_textdomain() {
load_plugin_textdomain('my-plugin', false, dirname(__FILE__) . '/languages');
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
save_post 钩子
保存文章时执行:
php
<?php
// 保存自定义字段
add_action('save_post', 'my_save_custom_meta', 10, 3);
function my_save_custom_meta($post_id, $post, $update) {
// 防止自动保存
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
// 检查权限
if (!current_user_can('edit_post', $post_id)) {
return;
}
// 保存数据
if (isset($_POST['my_custom_field'])) {
update_post_meta($post_id, '_my_custom_field',
sanitize_text_field($_POST['my_custom_field'])
);
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
wp_head 钩子
在 <head> 中添加代码:
php
<?php
// 添加自定义 CSS
add_action('wp_head', 'my_custom_css');
function my_custom_css() {
if (is_single()) {
echo '<style type="text/css">
.single-post .entry-content {
font-size: 18px;
line-height: 1.8;
}
</style>';
}
}
// 添加 Meta 标签
add_action('wp_head', 'my_custom_meta');
function my_custom_meta() {
if (is_singular()) {
global $post;
$description = get_post_meta($post->ID, '_meta_description', true);
if ($description) {
echo '<meta name="description" content="' . esc_attr($description) . '">' . "\n";
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
wp_enqueue_scripts 钩子
加载脚本和样式:
php
<?php
add_action('wp_enqueue_scripts', 'my_enqueue_assets');
function my_enqueue_assets() {
// 加载样式
wp_enqueue_style(
'my-style',
get_template_directory_uri() . '/css/style.css',
array(),
'1.0.0'
);
// 加载脚本
wp_enqueue_script(
'my-script',
get_template_directory_uri() . '/js/main.js',
array('jquery'),
'1.0.0',
true // 加载到页脚
);
// 传递数据到 JS
wp_localize_script('my-script', 'myData', array(
'ajaxUrl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('my-nonce'),
));
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
admin_menu 钩子
添加管理菜单:
php
<?php
add_action('admin_menu', 'my_admin_menu');
function my_admin_menu() {
// 添加主菜单
add_menu_page(
'插件设置', // 页面标题
'我的插件', // 菜单标题
'manage_options', // 权限
'my-plugin-settings', // 菜单 slug
'my_plugin_settings_page', // 回调函数
'dashicons-admin-generic', // 图标
30 // 菜单位置
);
// 添加子菜单
add_submenu_page(
'my-plugin-settings',
'常规设置',
'常规',
'manage_options',
'my-plugin-general',
'my_plugin_general_page'
);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
widget_init 钩子
注册小工具:
php
<?php
add_action('widgets_init', 'my_register_widgets');
function my_register_widgets() {
register_widget('My_Custom_Widget');
}
class My_Custom_Widget extends WP_Widget {
public function __construct() {
parent::__construct(
'my_custom_widget',
'自定义小工具',
array('description' => '显示自定义内容')
);
}
public function widget($args, $instance) {
echo $args['before_widget'];
if (!empty($instance['title'])) {
echo $args['before_title'] . apply_filters('widget_title', $instance['title']) . $args['after_title'];
}
echo '<p>' . esc_html($instance['content']) . '</p>';
echo $args['after_widget'];
}
public function form($instance) {
$title = !empty($instance['title']) ? $instance['title'] : '';
$content = !empty($instance['content']) ? $instance['content'] : '';
?>
<p>
<label for="<?php echo $this->get_field_id('title'); ?>">标题:</label>
<input class="widefat" id="<?php echo $this->get_field_id('title'); ?>"
name="<?php echo $this->get_field_name('title'); ?>" type="text"
value="<?php echo esc_attr($title); ?>">
</p>
<?php
}
public function update($new_instance, $old_instance) {
$instance = array();
$instance['title'] = !empty($new_instance['title']) ? sanitize_text_field($new_instance['title']) : '';
$instance['content'] = !empty($new_instance['content']) ? sanitize_textarea_field($new_instance['content']) : '';
return $instance;
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
📊 钩子优先级
php
<?php
// 默认优先级为 10
add_action('init', 'my_function');
// 更高优先级(较早执行)
add_action('init', 'my_early_function', 1);
// 更低优先级(较晚执行)
add_action('init', 'my_late_function', 20);
// 带参数
add_action('save_post', 'my_save_function', 10, 3);
function my_save_function($post_id, $post, $update) {
// $post_id - 文章 ID
// $post - 文章对象
// $update - 是否为更新
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
🗑️ 移除钩子
php
<?php
// 移除默认钩子
remove_action('the_content', 'wptexturize');
// 移除带特定优先级的钩子
remove_action('init', 'wp_schedule_update_checks', 2);
// 移除所有特定钩子的回调
remove_all_actions('save_post');1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
