I see a lot of WordPress developers doing things like this:
<?php
class SomeClass {
// ...
public function __construct() {
add_action("init", array($this, "some_method")); // This is bad!
}
}
Why Using $this
in add_action
Is Bad
The problem with this code is that you don’t have access to that specific object ($this
) outside the class, and most probably it’s a class from a plugin or a theme that you cannot directly modify. This makes it a lot difficult, to remove the action later because WordPress requires the exact same callback to remove_action
as was used in add_action
.
The add_action
function stores the action along with the callback in WordPress’ hooks system, which you can later use remove_action
to remove. However, when the callback is an instance method, as in the example above, you need access to the exact instance of the object ($this
) to remove it. Without that exact instance, trying to call remove_action
won’t work.
For example, if you try this:
remove_action("init", array(SomeClass::class, "some_method"));
It won’t work because remove_action
expects the exact same object that was passed to add_action
. Since $this
refers to the specific instance of the class, and not the class itself, you don’t have access to it.
The Solution: Removing the Callback from the Global $wp_filter
To solve this problem, I created a helper function called remove_class_method_action
. This function searches through the global $wp_filter
for a specific hook, checks if the callback is tied to a class method, and removes the action if it matches.
Here’s the code for the function:
function remove_class_method_action($hook_name, $class_name, $method_name)
{
global $wp_filter;
if (isset($wp_filter[$hook_name]->callbacks)) {
foreach ($wp_filter[$hook_name]->callbacks as $priority => $callbacks) {
foreach ($callbacks as $key => $callback) {
if (is_array($callback["function"])) {
$object = $callback["function"][0];
$method = $callback["function"][1];
if (
is_object($object) &&
get_class($object) === $class_name &&
$method === $method_name
) {
remove_action(
$hook_name,
[$object, $method],
$priority
);
}
}
}
}
}
}
How It Works
The function takes three arguments:
$hook_name
: The name of the action hook (e.g.,'init'
,'wp_footer'
).$class_name
: The class name where the method is located.$method_name
: The specific method you want to remove from the hook.
It works by iterating through the $wp_filter
global variable, which stores all the hooks and their callbacks. For each callback, it checks if it’s an array (which indicates it’s a class method), and if so, it compares the class and method names. Once it finds a match, it uses remove_action
to remove the action.
Important: When to Call It
You need to call the function after the action you want to remove has been added, which means selecting the appropriate hook.
For example:
add_action("plugins_loaded", "remove_dlm_scripts");
function remove_dlm_scripts() {
remove_class_method_action(
"wp_footer",
"DLM_TC_Modal",
"add_footer_scripts"
);
}
In this example, I’m using the plugins_loaded
hook because I knew that at that point, the action had already been added.
Good Practices for add_action
and add_filter
To make your themes and plugins developer-friendly, make sure that all add_action
and add_filter
calls are reversible.
- Use static methods with
add_action
andadd_filter
whenever possible. - Avoid using closures.
- It’s fine to use objects, as long as they are accessible. But don’t put them in the global scope, as that’s another bad practice.