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 (viaadd_filter()
) or that you instantiated the classExample_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 afterafter_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 theadmin_init
. But in most plugins, they initialize things via theinit
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 beforeafter_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 } );