如何在插件类中使用Apply_Filters()?

时间:2020-11-12 作者:Shoelaced

我希望主题能够改变插件类中的默认数据数组。目前的设置如下:

namespace Example;

class Example_Class {

    private $stuff;

    public function __construct() {

        $this->stuff = $this->set_stuff();

    }

    public function set_stuff() {

        $things = array(
            \'first\' => \'First\',
            \'second\' => \'Second\',
        );

        return apply_filters( \'my_cool_filter\', $things );
     }

}
然后为了测试它,我把它放在主题的函数中。php:

function change_things( $things ) {

    $things = array(
        \'third\' => \'Third\',
        \'fourth\' => \'Fourth\',
    );

    return $things;
 }

 add_filter( \'my_cool_filter\', \'change_things\' );
但是它不起作用。这个$stuff 属性仍设置为原始默认数组,因此add_filter() 没有任何效果。看起来是的the same question as this, 但我看不出我做错了什么。

编辑:该类位于插件中,并作为插件加载的一部分进行实例化-从主插件文件调用。类中的方法管理设置,使用该属性的主方法连接到admin_init, 但如果我加上die( var_dump( $this->stuff ) ) 在构造器中,设置完之后,我得到的是原始数组,而不是过滤后的数组。我想从大家的说法中可以清楚地看出,这一定是因为事情发生的顺序不对,但插件不是总是在主题之前加载吗?

1 个回复
最合适的回答,由SO网友:Sally CJ 整理而成

Your code is good — you are using both apply_filters() and add_filter() correctly.

But the timing/hook does not seem correct.

I think it\'s clear from what everyone is saying that it must be an issue of things happening in the wrong order, but don\'t plugins always load before the theme?

  • Wrong order: Yes — you most likely called apply_filters() before the filter (change_things()) is added (via add_filter()) or that you instantiated the class Example_Class in the wrong place/hook (i.e. instantiated too early).

  • Don\'t plugins always load before the theme? Yes they do, therefore you need to ensure your filter is added on-time — and the earliest hook you\'d use to ensure your code runs after the theme is loaded would be after_setup_theme:

    /**
     * Fires after the theme is loaded.
     *
     * @since 3.0.0
     */
    do_action( \'after_setup_theme\' );
    

    See this Codex article for a list of the hooks and their order of execution on a WordPress page, both admin and non-admin sides, but for an up-to-date list, try Query Monitor or the other options here.

So for example, if you instantiated the class in plugins_loaded, then the property Example_Class::$stuff would not be filtered by the change_things().

And here are two examples demonstrating how should and should not the class be instantiated:

  • On-time/good instantiation — admin_init runs after after_setup_theme:

    // In main plugin file:
    // Note: I used closure merely for testing purposes.
    
    add_action( \'admin_init\', function () {
        require_once \'/path/to/class-example-class.php\';
        new Example\\Example_Class;
        // the $this->stuff in the class would now be the $things returned by
        // change_things()
    } );
    

    And as you may have guessed it, you can use after_setup_theme in place of the admin_init. But in most plugins, they initialize things via the init hook which runs after WordPress setups things like the theme and current user:

    /**
     * Fires after WordPress has finished loading but before any headers are sent.
     *
     * Most of WP is loaded at this stage, and the user is authenticated. WP continues
     * to load on the {@see \'init\'} hook that follows (e.g. widgets), and many plugins instantiate
     * themselves on it for all sorts of reasons (e.g. they need a user, a taxonomy, etc.).
     *
     * If you wish to plug an action once WP is loaded, use the {@see \'wp_loaded\'} hook below.
     *
     * @since 1.5.0
     */
    do_action( \'init\' );
    
  • Too-early instantiation — plugins_loaded runs before after_setup_theme:

    // In main plugin file:
    
    add_action( \'plugins_loaded\', function () {
        require_once \'/path/to/class-example-class.php\';
        new Example\\Example_Class;
        // change_things() was not executed
    } );