How to Preventing free-range Wordpress hooks

How to Preventing free-range Wordpress hooks

One of the major frustrations I experience when developing for WordPress is the abundance of functionality that relies on writing opaque strings. The most common of these are Actions and Filters.

One of the major frustrations I experience when developing for WordPress is the abundance of functionality that relies on writing opaque strings. The most common of these are Actions and Filters. Pretty much every tutorial or piece of documentation you might find on creating and applying filters will present you with code like this:

add_filter('post_class', 'my_post_class_modifier', 10);

function my_post_class_modifier($classes){ if($myConditionIsMet){ $classes[] = 'another-css-class'; } return $classes; }

I've always had a disdain for this approach. It requires:

  • Prefixing the function name with a clunky namespace to avoid potential clashes
  • Writing the function name twice, one of which is inside a string, so Intellisense won't be any help

You won't be able to option-click on the function name and find out where it's being called, or find the function by clicking on the calling code. This is more of an issue when you need to use the same function for multiple filters. Your function gets further and further away from the calling code and unless you're very organised your functions.php file (which by default is where you'll put this code) will end up becoming an unnavigable dumping area full of nasty opaque string function calls. Ack!

Object method hooks

Ok, so most of the time I am a little bit cleaner in my approach and I'll try to corral hooks related to eachother or to particular custom post types into a class. You can of course use object methods in your hooks.

class myClass {
    public function applyHooks(){
        add_action('hook_string', array($this, 'hookForThisThing'), 10);

public function hookForThisThing($arg){
    // Perform an action here


This approach means you don't have to prefix faux namespaces to function names and it does at least allow you to more easily find the original priority value - you could even make it a property of the class.

You can also use class properties inside your function's body which is a nice way of passing arbitrary data to the conditionals within. But you still have to use opaque strings which I'm frankly just against. I want my IDE to write as much of my code as possible as there's less room for typographic errors. Remembering function names is also an issue. A proper IDE will help you find it even if you only know one word in its name (a good reason for writing clear and long if necessary function names).

Anonymous functions

One approach I've started to use more frequently is to just pass an anonymous function to the filter:

add_filter('post_class', function($classes){
      $classes[] = 'another-css-class';
    return $classes;
}, 10);

This has a few advantages:

  • No clunkily named loose function knocking around the functions file
  • The hook being used is adjacent to the function.
  • You can pass in local variables if you need to like this:
$mySpecialValue = 87;
add_filter('post_class', function($classes) use ($mySpecialValue) {
    if(count($classes) == $mySpecialValue){
      $classes[] = 'has-88-css-classes';
    return $classes;
}, 10);

But disadvantages include the inability to use the function on multiple hooks, and crucially the ability to REMOVE the hooked function if you need to later. You can't use the WordPress remove_filter method using anonymous functions.

For the vast majority of cases though, this has worked well for me. I could always define the anonymous function as a variable if I needed to use it on multiple filters but that removal thing became a problem that I needed to solve.

The problem

I had a bit of a hacky filter that I needed to run on 'posts_where' to modify the main query. Once applied to the main query, however, it was subsequently applied to any and all other queries used within the page building process. In the past I'd removed this type of filter by use of the overly-convoluted method of applying an action to remove the filter on some arbitrary filter following the main query being run. This results in more cruft drifting about in the functions file. It also requires recall of the priority value since the removal parameters must match. If at some point in the future you, or another developer (you of the future is another developer), changes the priority on the original hook then your remove operation (which is buried in the body of an unrelated function somewhere else) won't work any more. Your IDE won't tell you about it either since this code is impenetrable.

I decided to see if I could make self-removing filter.

Introducing the Closure class

namespace MyNamespace;

class closure { public $priority = 10; public $method; public $args = 1; public $hook; public $persistent = false; public $hookType;

const TYPE_ACTION = 1;
const TYPE_FILTER = 2;

// Instantiators
public static function createFilter($hook, $method, $priority=10, $args=1, $persistent=false, $hookType=self::TYPE_FILTER){
    $closure = new static();
    if(is_callable($method)) {
        $closure-&gt;hookType = $hookType;
        $closure-&gt;hook = $hook;
        $closure-&gt;method = $method;
        $closure-&gt;priority = $priority;
        $closure-&gt;args = $args;
        $closure-&gt;persistent = $persistent;
    } else {
        $closure = false;
    return $closure;

public static function createAction($hook, $method, $priority=10, $args=1, $persistent=false){
    return static::createFilter($hook, $method, $priority, $args, $persistent, self::TYPE_ACTION);

public static function createPersistentFilter($hook, $method, $priority=10, $args=1){
    return static::createFilter($hook, $method, $priority, $args, true);

public static function createPersistentAction($hook, $method, $priority=10, $args=1){
    return static::createAction($hook, $method, $priority, $args, true);

// public API [WordPress needs public visibility]
public function filter(){
    $args = func_get_args();
    $val = $args[0];
        $val = call_user_func_array($this-&gt;method, $args);
    if(!$this-&gt;persistent) {
    if($this-&gt;hookType == self::TYPE_FILTER) {
        return $val;
    return true;

// Utility methods
public static function apply(closure $closure){
    global $wheels;
    if($closure-&gt;hookType == self::TYPE_ACTION){
        add_action($closure-&gt;hook, array($closure, 'filter'), $closure-&gt;priority, $closure-&gt;args);
    } else {
        add_filter($closure-&gt;hook, array($closure, 'filter'), $closure-&gt;priority, $closure-&gt;args);

public static function remove(closure $closure){
    global $wheels;
    if($closure-&gt;hookType == self::TYPE_ACTION){
        remove_action($closure-&gt;hook, array($closure, 'filter'), $closure-&gt;priority);
    } else {
        remove_filter($closure-&gt;hook, array($closure, 'filter'), $closure-&gt;priority);



As long as it's created using the createFilter or createAction instantiation methods, then by default, a closure object will remove it's own hook the first time it's employed. You can use the persistent methods if you don't want it to do that, but as I'm not envisaging using this for every single action and filter, only for ones like my posts_where where I need it removed following its first application, then I'm happy for that to be the default.

Here's an example of the closure class in use:

use MyNamespace\closure;

$mySpecialVar = 4077; closure::createFilter('posts_where', function($where) use ($mySpecialVar) { $currentWhere = preg_replace("'^\s?AND\s'i", '', $where); $where = ' AND wp_posts.ID IN (SELECT DISTINCT mp_a.meta_value FROM wp_postmeta mp_a WHERE mp_a.meta_key = 'my_meta_key_im_looking_for' AND mp_a.post_id = '.(1*$mySpecialVar).') OR (' . $currentWhere . ') '; return $where; });

If I needed to I could still store the closure object as a variable and use it on multiple filters. In fact I could probably add a method to the class to accept multiple filter strings to keep everything together.

Because the closure object remembers its own arguments, should you retain a copy of the closure you may at any time use the method:


To remove the hook. Changing the priority in the original closure creation won't now affect the removal.

Thanks for reading. If you liked this post, share it with all of your programming buddies!

Further reading

☞ PHP with Laravel for beginners - Become a Master in Laravel

☞ Projects in Laravel: Learn Laravel Building 10 Projects

☞ Laravel for RESTful: Build Your RESTful API with Laravel

☞ Fullstack Web Development With Laravel and Vue.js

☞ Laravel 5.8 Ajax CRUD tutorial using Datatable JS

☞ Laravel 5.8 Tutorial from Scratch for Beginners

☞ Build RESTful API In Laravel 5.8 Example

☞ Login with Google in Laravel 5.8 App using Socialite Package

☞ Laravel PHP Framework Tutorial - Full Course for Beginners (2019)

This post was originally published here

php wordpress web-development

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

PHP Web Application Development Company

As a top **PHP Web Application Development Company in USA**[]( ""), we at Data EximIT have...

PHP Website Development

Skenix Infotech is a leading PHP Web Development Company that helps companies get results with industry best practices. Get affordable PHP Development Services.

Hire Dedicated PHP Developer

Looking to hire affordable yet experienced PHP developers? **[Hire Dedicated PHP Developer]( "Hire Dedicated PHP Developer")**, who can convert your idea to reality, within the stipulated...

Hire WordPress Developer

Whether you want to develop a blog or you want a feature-rich, interactive WordPress website? **[]( "")** is a distinguished leader in the WordPress development market. **[Hire...

Best WordPress Development Services in India

Skenix Infotech is a top WordPress Website Development Company in India & USA with expert WordPress Developers. Get affordable WordPress Development Services.