好的,各位听众,欢迎来到今天的“WordPress源码深度解析”小课堂!我是你们今天的讲师,老码农一枚。今天咱们聊点有意思的,关于WordPress插件加载的两个关键action
:plugins_loaded
和 init
。 这俩哥们儿,初学者容易搞混,但它们在WordPress启动过程中扮演的角色可是大相径庭。
开场白:别被表象迷惑!
很多新手朋友觉得,插件加载嘛,不就是把插件里的代码执行一遍吗? 看起来好像是这样,但WordPress内部的处理机制远比我们想象的要复杂。 就像看魔术一样,台上光鲜亮丽,台下可都是精密的机关。 plugins_loaded
和 init
这两个action
,就是这些“机关”中的关键齿轮。
第一幕:WordPress的启动大戏
要理解plugins_loaded
和 init
的区别,我们先要对WordPress的启动流程有个大致的了解。 想象一下,WordPress的启动过程就像一场盛大的演出,各个角色(文件、函数、插件)按照剧本依次登场。
wp-config.php
:奠定基石- 这是演出的总策划书,定义了数据库连接信息、调试模式等关键配置。
- WordPress首先读取这个文件,建立与数据库的连接。
wp-settings.php
:加载核心文件- 这是演出的导演,负责加载核心文件、注册全局变量等。
- 它会加载
wp-load.php
,然后依次加载各种核心函数和类。
wp-load.php
:启动引擎- 这是演出的总调度,定义了WordPress的根目录、编码方式等。
- 它主要负责加载
wp-config.php
,为后续的加载做好准备。
wp-includes/plugin.php
:插件管理中心- 这是插件的登记处,负责激活、停用、加载插件。
- 它定义了
get_option('active_plugins')
函数,获取已激活的插件列表。
- 开始执行主题和插件
- 主题和插件开始“登台演出”
- 主题的
functions.php
和插件的代码会被加载和执行
第二幕:plugins_loaded
:插件的集体亮相
好,现在重点来了。 plugins_loaded
这个action
,就发生在核心文件加载完毕,但在主题和插件完全启动之前。 它的主要作用是:让所有已激活的插件加载它们的核心代码。
- 触发时机: 在
wp-settings.php
中,require( ABSPATH . WPINC . '/plugin.php' );
之后,do_action( 'plugins_loaded' );
被调用。 - 作用: 插件可以在这个
action
中注册全局变量、定义常量、加载核心类等。 - 特点: 这个
action
的触发时机非常早,此时WordPress的核心功能(比如用户认证、文章类型)可能还没有完全加载完毕。
代码示例:
<?php
/**
* Plugin Name: My Awesome Plugin
* Description: A plugin that does awesome things.
*/
add_action( 'plugins_loaded', 'my_awesome_plugin_loaded' );
function my_awesome_plugin_loaded() {
// 定义常量
define( 'MY_AWESOME_PLUGIN_VERSION', '1.0.0' );
// 加载核心类
require_once plugin_dir_path( __FILE__ ) . 'includes/class-my-awesome-plugin.php';
// 创建插件实例
$my_plugin = new My_Awesome_Plugin();
}
注意事项:
- 由于
plugins_loaded
触发时机较早,因此不要在这个action
中依赖WordPress的核心功能。 比如,不要尝试获取当前用户的信息,因为用户认证可能还没有完成。 - 尽量在这个
action
中完成插件的基础设置,为后续的操作做好准备。
第三幕:init
:万事俱备,只欠东风
init
这个action
,发生在WordPress核心功能加载完毕之后,但在页面渲染之前。 它的主要作用是:让插件和主题执行更复杂的操作,比如注册文章类型、添加自定义字段、处理用户请求等。
- 触发时机: 在
wp()
函数中,do_action( 'init' );
被调用。 - 作用: 插件和主题可以在这个
action
中执行各种操作,比如注册文章类型、添加自定义字段、处理用户请求等。 - 特点: 这个
action
的触发时机相对较晚,此时WordPress的核心功能已经完全加载完毕。
代码示例:
<?php
/**
* Plugin Name: My Awesome Plugin
* Description: A plugin that does awesome things.
*/
add_action( 'init', 'my_awesome_plugin_init' );
function my_awesome_plugin_init() {
// 注册自定义文章类型
register_post_type( 'my_awesome_post', array(
'labels' => array(
'name' => __( 'Awesome Posts', 'my-awesome-plugin' ),
'singular_name' => __( 'Awesome Post', 'my-awesome-plugin' ),
),
'public' => true,
'has_archive' => true,
'supports' => array( 'title', 'editor', 'thumbnail' ),
) );
// 添加自定义字段
add_meta_box(
'my_awesome_meta_box',
__( 'Awesome Meta Box', 'my-awesome-plugin' ),
'my_awesome_meta_box_callback',
'my_awesome_post',
'normal',
'default'
);
}
function my_awesome_meta_box_callback( $post ) {
// 显示自定义字段
echo '<label for="my_awesome_field">' . __( 'Awesome Field:', 'my-awesome-plugin' ) . '</label>';
echo '<input type="text" id="my_awesome_field" name="my_awesome_field" value="' . esc_attr( get_post_meta( $post->ID, 'my_awesome_field', true ) ) . '" />';
}
注意事项:
- 由于
init
触发时机较晚,因此可以在这个action
中安全地依赖WordPress的核心功能。 - 尽量在这个
action
中完成插件的业务逻辑处理。
第四幕:源码分析:追根溯源
光说理论还不够,我们来扒一扒WordPress的源码,看看plugins_loaded
和 init
到底是怎么被触发的。
plugins_loaded
的触发:
打开wp-settings.php
,你会发现:
<?php
// Loads the WordPress environment
if ( !isset( $wp_did_header ) ) {
$wp_did_header = true;
require_once( dirname(__FILE__) . '/wp-load.php' );
wp();
require_once( ABSPATH . WPINC . '/template-loader.php' );
}
再打开wp-load.php
,你会发现
<?php
/**
* Bootstrap file for loading the WordPress environment.
*
* @package WordPress
*/
if ( ! isset( $table_prefix ) )
$table_prefix = 'wp_';
define('WPINC', 'wp-includes');
require( dirname(__FILE__) . '/wp-config.php' );
require_once( ABSPATH . 'wp-includes/load.php' );
require_once( ABSPATH . 'wp-includes/default-constants.php' );
require_once( ABSPATH . 'wp-includes/plugin.php' );
// Sets up the WordPress vars and included files.
require_once( ABSPATH . 'wp-settings.php' );
关键的代码是require_once( ABSPATH . WPINC . '/plugin.php' );
之后,在wp-settings.php
中,你会看到:
do_action( 'plugins_loaded' );
这行代码就是触发plugins_loaded
的关键! 它告诉WordPress: “嘿,所有插件,该加载你们的核心代码了!”
init
的触发:
init
的触发稍微复杂一点,它藏在wp()
函数里面。 wp()
函数位于wp-includes/functions.php
文件中。 打开这个文件,找到wp()
函数,你会看到:
function wp() {
global $wp, $wp_query, $wp_the_query, $wp_rewrite, $wp_did_header;
$wp->main();
if ( ! isset( $wp_did_header ) ) {
$wp_did_header = true;
$wp->send_headers();
}
$wp_query->init();
$wp_the_query->init();
/**
* Fires after WordPress has finished loading but before any headers are sent.
*
* @since 1.5.0
*/
do_action( 'init' );
/**
* Fires before the HTTP headers are sent to the browser.
*
* @since 2.1.0
*/
do_action( 'wp_loaded' );
}
看到do_action( 'init' );
了吗? 这就是init
被触发的地方! 它告诉WordPress:“嘿,所有插件和主题,核心功能已经加载完毕,你们可以开始执行更复杂的操作了!”
第五幕:表格对比:一目了然
为了让大家更清晰地理解plugins_loaded
和 init
的区别,我们用一个表格来总结一下:
特性 | plugins_loaded |
init |
---|---|---|
触发时机 | 核心文件加载完毕,但在主题和插件完全启动之前 | WordPress核心功能加载完毕之后,但在页面渲染之前 |
主要作用 | 加载插件的核心代码 | 执行更复杂的操作,比如注册文章类型、添加自定义字段 |
依赖核心功能 | 尽量避免依赖 | 可以安全地依赖 |
典型应用 | 定义常量、加载核心类、注册全局变量 | 注册文章类型、添加自定义字段、处理用户请求 |
源码位置 | wp-settings.php |
wp-includes/functions.php 中的 wp() 函数 |
触发时机相对顺序 | 更早 | 更晚 |
第六幕:实战演练:避免踩坑
了解了plugins_loaded
和 init
的区别,我们再来看几个实际的例子,避免大家在开发过程中踩坑。
坑1:在plugins_loaded
中获取当前用户信息
<?php
add_action( 'plugins_loaded', 'my_plugin_get_current_user' );
function my_plugin_get_current_user() {
$current_user = wp_get_current_user();
if ( $current_user->exists() ) {
// Do something with the current user
echo 'Hello, ' . $current_user->display_name . '!';
} else {
echo 'Not logged in.';
}
}
这段代码看似没问题,但实际上在plugins_loaded
触发时,用户认证可能还没有完成,wp_get_current_user()
可能返回一个空对象。 正确的做法是将这段代码放在init
action
中:
<?php
add_action( 'init', 'my_plugin_get_current_user' );
function my_plugin_get_current_user() {
$current_user = wp_get_current_user();
if ( $current_user->exists() ) {
// Do something with the current user
echo 'Hello, ' . $current_user->display_name . '!';
} else {
echo 'Not logged in.';
}
}
坑2:在init
中定义常量
虽然在init
中可以安全地依赖WordPress的核心功能,但不建议在这个action
中定义常量。 因为常量通常需要在代码的最开始就定义,以便在后续的代码中使用。 如果将常量定义放在init
中,可能会导致一些代码无法访问到这些常量。 正确的做法是将常量定义放在plugins_loaded
action
中。
总结:各司其职,高效协作
plugins_loaded
和 init
这两个action
,就像一个团队里的两个重要成员,各司其职,高效协作,共同完成了WordPress的启动过程。 plugins_loaded
负责打基础,加载核心代码,init
负责执行业务逻辑,处理用户请求。 只有充分理解了它们的作用和特点,才能在WordPress开发中游刃有余,写出高质量的插件和主题。
课后作业:
- 编写一个插件,分别在
plugins_loaded
和init
action
中输出一段文字,观察它们的执行顺序。 - 尝试在
plugins_loaded
中注册一个自定义文章类型,看看会发生什么。
好啦,今天的课程就到这里。希望大家能够学有所获,在WordPress开发的道路上越走越远! 咱们下次再见!