39

WordPress hooks can be used in two ways:

  1. using callback function name and appropriate function

    add_action( 'action_name', 'callback_function_name' );
    function callback_function_name() {
        // do something
    }
    
  2. using anonymous function (closure)

    add_action( 'action_name', function() {
        // do something
    } );
    

Is there any difference for WordPress what way to use? What is prefered way and why?

Aleksandr Levashov
  • 403
  • 1
  • 4
  • 7
  • I'm no expert in WP, but most hooks I've seen don't use annon functions. Yet anyway. That's not to say there's anything wrong in using them. I suppose it boils down to how you've done them so far on the project. Stick with one or the other, be consistent. – Andrei Jul 06 '15 at 08:02

4 Answers4

45

The disadvantage of the anonymous function is that you're not able to remove the action with remove_action.

Important: To remove a hook, the $function_to_remove and $priority arguments must match when the hook was added. This goes for both filters and actions. No warning will be given on removal failure.

Because you didn't define function_to_remove, you can't remove it.

So you should never use this inside plugins or themes that somebody else might want to overwrite.

Simon East
  • 55,742
  • 17
  • 139
  • 133
TeeDeJee
  • 3,756
  • 1
  • 17
  • 24
  • 3
    You can remove even anonymous hooks using the `remove_all_actions()` and `remove_all_filters()`. But even so, I agree that defining a regular function is the preferred pattern in WordPress. – EFC Feb 25 '17 at 06:50
  • 1
    Interesting article about subject: https://inpsyde.com/en/remove-wordpress-hooks/ – Arek Kostrzeba Aug 20 '20 at 08:27
24

Using closures has the benefit of keeping the global namespace clean, because you don't have to create a global function first to pass as a callback.

add_action('admin_init', function () {
    // some code...
});

Personally I would prefer using closures as callbacks, unless:

  • You want the possibility of removing the callback
  • The callback function needs to be used more then once
  • You need support for older PHP versions (less then 5.3)

Closures in Classes

Closures can also be beneficial within classes.

class SomeClass
{
    public function __construct()
    {
        add_action('wp_head', function () {
            $this->addSomeStyling();
        });
    }

    protected function addSomeStyling()
    {
        echo '<style> body { color: #999; } </style>';
    }
}

Normally callback methods need to be made public, but in this case you can also make them private or protected.

This solution only works for PHP 5.4+. To also make it work for PHP 5.3, you need to explicitly pass the $this object reference to the closure, like:

    public function __construct()
    {
        $self = $this;

        add_action('wp_head', function () use ($self) {
            $self->addSomeStyling();
        });
    }
Victor
  • 371
  • 2
  • 6
  • 1
    Totally disagree about using closures in hooks. You can never know how hooks may be handled by others. One, for example, may have the necessity to remove your hook and using closures he/she's stuck . Closures are a good thing *only* when used in a context where you're not manipulating a public API interface. –  Jan 12 '17 at 09:07
  • You can use namespaced functions the other way too: `add_action('acf/init', 'child_theme\load_content_types');` You would use this below a `namespace child_theme;`. – Peter Ajtai Mar 16 '18 at 22:22
  • 1
    Word of advice, when you use anonymous functions for hooks callback, you are virtually making your code untestable. There's no way to even check the `has_action` for such callbacks, let alone making code covered. But code coverage is a different beast altogether... – dingo_d Aug 14 '19 at 11:25
  • Just came across this post and I really just wanted to emphasize against what has been stated in the comments to this answer. As stated in the answer of @TeeDeeJee, you should avoid this if your plugin / theme's supposed to be used / modified by others. But let's say you developed a main custom plugin on your own, which you only use for your own website, and the normal functioning of that plugin is vital to your website. In these cases, is it really a bad idea to make it more difficult to remove your (vital) plugin callbacks from hooks via anonymous functions? .... – DevelJoe Jan 02 '21 at 12:42
0

Just to be more precise, I wanted to add this from the current wordpress docs; to actually demonstrate how this depends on a use-case:

"Why do we use a named function here [as callback of an ajax action hook] [...]? Because closures are only recently supported by PHP. [...] Since some people may still be running older versions of PHP, we always use named functions for maximum compatibility. If you have a recent PHP version and are developing only for your own installation, go ahead and use closures if you like."

DevelJoe
  • 856
  • 1
  • 10
  • 24
0

You can use in both these ways. But using anonymous functions has two major disadvantages,

  1. You can not remove the hook if needed. So if any theme or plugin has conflict and tries to remove your hook usage, then it can't be done as remove_action() and remove_filter() needs the function name as a parameter and you don't have it in this way.
  2. Anonymous functions are not supported in all the PHP versions. So if any user has an older version installed and tries to use your plugin/theme, it will through an error.

So, I would prefer using a named function.

Reza Khan
  • 86
  • 3