Removing difficult WordPress Actions

Actions can only be removed after they've been added. Makes sense. But sometimes actions are added from within loops or down the execution tree somewhere.

Have a look at this code and try to think how would you remove the oh_noes function from whaap_whaap action:

// outside the scope of our ability to modify
$arr = array('foobar', 'doobar');
foreach ( $arr as $name ) {
	$title = apply_filters('foobar', $name);
	do_action('whaap_whaap');
}

// the function we don't want to call
function oh_noes(){
	echo "Oh Noes!";
}
// somewhere else, also outside our ability to modify
add_filter('foobar', function( $name ) {
	add_action('whaap_whaap', 'oh_noes');
	return "<h2>$name</h2>";
});

Can you see what the code above does? It's going to display "foobar" and "doobar" wrapped in "h2" tags, but it will also call the "oh-noes" function right after, and that's the function we don't want in our code. So how do you remove it if you cannot access the code above? The regular remove_action() isn't going to work. 

The fix is actually very simple – remove action before it's triggered on the same action hook.  You add another action that's executed before oh_noes to remove oh_noes. Like so:

add_action( 'whaap_whaap',
	function () {
		remove_action( 'whaap_whaap', 'oh_noes' );
	},
	5 // lower priority means this will be run before `oh_noes`
);

Actions are run in an order by priority. The default priority for all actions is 10, which means that you can run your own action to remove an undesired action. That's it.

Bonus Round

Using PHP anonymous functions it's easy to make a helper function that's just going to unconditionally detach an action that we don't want. Doing the same thing as above, but in a reusable & pretty way.


function always_remove_action( $action, $callback, $priority = 10 ) {

	add_action( $action,
		// Anonymous function to remove the action
		function () use ( $action, $callback, $priority ) {
			remove_action( $action, $callback, $priority );
		},
		// Run this right before the callback
		        $priority - 1
	);
}

// Ta-da. An easy way to force remove actions. Just make sure you set the $priority correctly.
always_remove_action( 'whaap_whaap', 'oh_noes' );

Leave a Reply

Your email address will not be published. Required fields are marked *