Warning! WordPress 4.7 revamps how the actions and filters are handled, and as a result, this method no longer works! Sorry :/
A problem I ran into on a job this week was a contact form plugin that uses irreversible form field invalidation. In short, once a field has been marked invalid, it’s impossible to mark it as valid, and thus an error will appear. What I needed, was a way to stop the invalidation from happening in the first place, which led me to this possible solution:
Stop Processing Filters
In my case, I needed to create a filter that fired early in the process using a high priority number (I used 2), and, if certain conditions were met, would stop the later filters from firing.
add_filters('example_filter', 'my_stop_processing_filters_func', 2);
The solution wound up being pretty simple. WordPress stores all its filters in a giant array: $wp_filter. It is set up by tag, then priority. So $wp_filter[‘example_filter’][10] is an array containing all the functions hooked into ‘example_filter’ with a priority of 10. When apply_filters() is called, WordPress iterates through the functions in order of priority, running each one and applying the return values to the variable being filtered. Luckily for me, WordPress uses this line to move through the priority list:
do {
...
} while ( next($wp_filter[$tag]) !== false );
This means that anywhere in the process, a function could fiddle with $wp_filter[‘tag’]’s internal array pointer, dictating which priority gets checked next. So using the end() function on the array will set the internal pointer to the end of the array (the lowest priority tags in this case). Then, when WordPress finishes applying all the functions in the current priority level (2 in our case), it will check the value of next($wp_filter[$tag]). Since the array pointer is currently pointing at the last element, the next() function returns false, ending WP’s processing right there. Here’s the final code snippet:
add_filters('example_filter', 'my_stop_processing_filters_func', 2);
function my_stop_processing_filters_func( $in ) {
// Stops filters of this tag from being applied after the current priority level is finished
global $wp_filter;
if ( $in['skip-me'] ) {
// using current_filter() allows one function to be used for multiple filter tags if necessary
end( $wp_filter[ current_filter() ] );
}
// never forget to return the filtered variable!
return $in;
}
That’s it! Post a comment if you have questions or suggestions.