WordPress Hooks无法正确设置构造函数数据问题求助
问题:WordPress日志SDK钩子回调获取错误插件数据
我正在开发一款日志SDK,在WordPress插件主文件中通过rpt_wpb()函数初始化Logger类并传入当前插件的product_data,构造函数将该数据存入静态属性self::$product_data,同时调用dynamic_init()注册相关钩子。但在set_logs_schedule()、deactivation_model()等钩子回调函数中,获取到的并非当前插件的product_data,而是插件列表中最后一个集成该SDK的插件的数据。
相关代码
插件主文件初始化代码
function rpt_wpb() { global $rpt_wpb; if (!isset($rpt_wpb)) { require_once RELATED_POSTS_THUMBNAILS_PLUGIN_DIR . '/lib/wpb-sdk/require.php'; $rpt_wpb = new Logger( array( 'id' => 7, 'name' => 'Related Posts Thumbnails Plugin for WordPress', 'slug' => 'related-posts-thumbnails', 'type' => 'plugin', 'path' => __FILE__, 'version' => RELATED_POSTS_THUMBNAILS_VERSION, 'public_key' => '7e240de74fb1ed08fa08d38063f6a691462a815', 'is_premium' => false, 'has_addons' => false, 'has_paid_plans' => false, 'menu' => array() ) ); } return $rpt_wpb; } // 初始化 rpt_wpb(); do_action('rpt_wpb_loaded');
Logger类构造函数及钩子注册代码
public function __construct($product_data) { self::$product_data = $product_data; $this->dynamic_init(); } /** * 注册WP钩子初始化日志操作 * * @return void */ public function dynamic_init() { add_action('init', array($this, 'set_logs_schedule')); add_action('wpb_logger_cron_' . self::$product_data['slug'], array($this, 'log_plugin')); add_action('admin_footer', array($this, 'deactivation_model')); add_action('wp_ajax_wpb_sdk_' . self::$product_data['slug'] . '_deactivation', array($this, 'ajax_deactivation')); register_activation_hook(self::$product_data['path'], array(__CLASS__, 'log_activation')); register_deactivation_hook(self::$product_data['path'], array(__CLASS__, 'product_deactivation')); register_uninstall_hook(self::$product_data['path'], array(__CLASS__, 'log_uninstallation')); }
钩子回调函数代码
public function set_logs_schedule() { if (!wp_next_scheduled('wpb_logger_cron_' . self::$product_data['slug'])) { wp_schedule_event(time(), 'weekly', 'wpb_logger_cron_' . self::$product_data['slug']); } } /** * 添加停用弹窗 * * @return void */ public function deactivation_model() { if (function_exists('get_current_screen')) { $screen = get_current_screen(); if ('plugins.php' === $screen->parent_file) { $product_slug = self::$product_data['slug']; $product_name = self::$product_data['name']; $has_pro_version = (in_array($product_slug, self::$has_pro_version)) ? true : false; include dirname(__DIR__) . '/views/wpb-sdk-deactivate-form.php'; } } }
问题原因
核心问题出在静态属性self::$product_data的共享特性:静态属性属于类本身,而非类的实例。当多个插件集成这个SDK时,最后一个初始化Logger类的插件会覆盖self::$product_data的值,导致所有钩子回调都读取到最后一个插件的数据。
解决方案
1. 将静态属性改为实例属性
每个Logger实例单独存储自己的product_data,避免实例间的数据覆盖:
// 在Logger类中定义实例属性 private $product_data; public function __construct($product_data) { // 替换静态赋值为实例赋值 $this->product_data = $product_data; $this->dynamic_init(); }
2. 修改所有引用self::$product_data的代码
将回调和钩子注册中所有的self::$product_data替换为$this->product_data:
public function dynamic_init() { add_action('init', array($this, 'set_logs_schedule')); // 替换self为$this add_action('wpb_logger_cron_' . $this->product_data['slug'], array($this, 'log_plugin')); add_action('admin_footer', array($this, 'deactivation_model')); add_action('wp_ajax_wpb_sdk_' . $this->product_data['slug'] . '_deactivation', array($this, 'ajax_deactivation')); // 处理激活/停用/卸载钩子:用闭包绑定实例数据 $product_path = $this->product_data['path']; $product_data = $this->product_data; register_activation_hook($product_path, function() use ($product_data) { $this->log_activation($product_data); }); register_deactivation_hook($product_path, function() use ($product_data) { $this->product_deactivation($product_data); }); register_uninstall_hook($product_path, function() use ($product_data) { $this->log_uninstallation($product_data); }); } public function set_logs_schedule() { if (!wp_next_scheduled('wpb_logger_cron_' . $this->product_data['slug'])) { wp_schedule_event(time(), 'weekly', 'wpb_logger_cron_' . $this->product_data['slug']); } } public function deactivation_model() { if (function_exists('get_current_screen')) { $screen = get_current_screen(); if ('plugins.php' === $screen->parent_file) { $product_slug = $this->product_data['slug']; $product_name = $this->product_data['name']; $has_pro_version = (in_array($product_slug, self::$has_pro_version)) ? true : false; include dirname(__DIR__) . '/views/wpb-sdk-deactivate-form.php'; } } }
3. 调整静态钩子方法(可选)
如果原本的log_activation、product_deactivation、log_uninstallation是静态方法,需要修改为非静态方法,或者调整方法参数接收product_data:
// 修改为非静态方法,接收product_data参数 public function log_activation($product_data) { // 使用传入的product_data进行操作 } public function product_deactivation($product_data) { // 使用传入的product_data进行操作 } public function log_uninstallation($product_data) { // 使用传入的product_data进行操作 }
关键说明
- 实例属性
$this->product_data属于每个单独的Logger实例,不会被其他插件的实例覆盖。 - 对于
register_activation_hook这类要求静态回调的钩子,使用闭包+use关键字绑定当前实例的product_data,确保回调能获取到正确的插件数据。
内容的提问来源于stack exchange,提问作者ahmedwp
相关产品推荐
相关产品推荐

