You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 08:34:59