How to use apply_filters() inside a plugin class?

I’d like themes to be able to alter a default array of data inside a plugin class. It’s currently set up like:

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 );
     }

}

Then to test it I put this in the theme’s functions.php:

function change_things( $things ) {

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

    return $things;
 }

 add_filter( 'my_cool_filter', 'change_things' );

However it’s not working. The $stuff property is still getting set as the original default array, so add_filter() isn’t having any effect. It would seem to be the same question as this, but I can’t see what I’m doing wrong.

EDIT:
The class is in a plugin and instantiated as part of the plugin loading – called from the main plugin file. The methods in the class manage settings and the main one that uses the property is hooked to admin_init, but if I add die( var_dump( $this->stuff ) ) inside the constructor just after it’s set, I get the original array instead of the filtered array. 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?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

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 ExampleExample_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 ExampleExample_Class;
        // change_things() was not executed
    } );
    


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x