
Are you trying to modify the functionality of a 3rd party plugin without actually editing the code of their plugin (which would result in losing your customization upon the next update)? Having trouble with it because that plugin is object oriented or class-based?
I have run into this situation multiple times, and finally found a really good fix for it.
In this post, I’ll show you how to remove an action or filter hook from another plugin even though that plugin is class-based.
Basic Removing of Actions and Filters
You probably already know that you can remove someone’s add_action() using a remove_action() and you can remove someone’s add_filter() using remove_filter() .
So, in normal circumstances, it’s very simple. In someone’s plugin, they have something like…
add_action('save_post', 'my_action_function'); add_filter('the_content', 'my_filter_function');
… and you just remove them using…
remove_action('save_post', 'my_action_function'); remove_filter('the_content', 'my_filter_function');
Class-based Plugins are a bit more Complicated
A plugin that uses classes looks something like this…
class My_Plugin_Class { function __construct() { add_action( 'save_post', array( $this, 'my_action_function' ), 11); } function my_action_function(){ //do something } } $my_plugin_class = new My_Plugin_Class();
Notice that add_action doesn’t just have a simple string of the function callback, but instead it has an array with $this and then that function callback string. This allow plugin developers to use simple function names without the worry of conflicting with other plugins because they are limited to the scope of that class.
So, how do you remove that?
How to Remove a Hook from Within the Class-based Plugin
If you can hook into that plugin, then you should be able to use this method to gain access to the class object instance in order to remove the hook.
global $my_plugin_class; // Get access to the class object instance remove_action('save_post', array($my_plugin_class, 'my_action_function'), 11); // Remove the class hook using the same priority
How to Remove a Hook from Outside the Class-based Plugin
If you are not able to hook into the class-based plugin, then try to use the class name as a string in the first part of the callback array, like this…
remove_action('save_post', array('My_Plugin_Class', 'my_action_function'), 11); // Remove the class hook using the same priority
If None of Those Methods Work, Use These Functions
Sometimes, it just won’t work. But, here’s a couple nice helper functions that work great.
Credit to tripflex.
<?php /** * Make sure the function does not exist before defining it */ if( ! function_exists( 'remove_class_filter' ) ){ /** * Remove Class Filter Without Access to Class Object * * In order to use the core WordPress remove_filter() on a filter added with the callback * to a class, you either have to have access to that class object, or it has to be a call * to a static method. This method allows you to remove filters with a callback to a class * you don't have access to. * * Works with WordPress 1.2+ (4.7+ support added 9-19-2016) * Updated 2-27-2017 to use internal WordPress removal for 4.7+ (to prevent PHP warnings output) * * @param string $tag Filter to remove * @param string $class_name Class name for the filter's callback * @param string $method_name Method name for the filter's callback * @param int $priority Priority of the filter (default 10) * * @return bool Whether the function is removed. */ function remove_class_filter( $tag, $class_name = '', $method_name = '', $priority = 10 ) { global $wp_filter; // Check that filter actually exists first if ( ! isset( $wp_filter[ $tag ] ) ) { return FALSE; } /** * If filter config is an object, means we're using WordPress 4.7+ and the config is no longer * a simple array, rather it is an object that implements the ArrayAccess interface. * * To be backwards compatible, we set $callbacks equal to the correct array as a reference (so $wp_filter is updated) * * @see https://make.wordpress.org/core/2016/09/08/wp_hook-next-generation-actions-and-filters/ */ if ( is_object( $wp_filter[ $tag ] ) && isset( $wp_filter[ $tag ]->callbacks ) ) { // Create $fob object from filter tag, to use below $fob = $wp_filter[ $tag ]; $callbacks = &$wp_filter[ $tag ]->callbacks; } else { $callbacks = &$wp_filter[ $tag ]; } // Exit if there aren't any callbacks for specified priority if ( ! isset( $callbacks[ $priority ] ) || empty( $callbacks[ $priority ] ) ) { return FALSE; } // Loop through each filter for the specified priority, looking for our class & method foreach ( (array) $callbacks[ $priority ] as $filter_id => $filter ) { // Filter should always be an array - array( $this, 'method' ), if not goto next if ( ! isset( $filter['function'] ) || ! is_array( $filter['function'] ) ) { continue; } // If first value in array is not an object, it can't be a class if ( ! is_object( $filter['function'][0] ) ) { continue; } // Method doesn't match the one we're looking for, goto next if ( $filter['function'][1] !== $method_name ) { continue; } // Method matched, now let's check the Class if ( get_class( $filter['function'][0] ) === $class_name ) { // WordPress 4.7+ use core remove_filter() since we found the class object if ( isset( $fob ) ) { // Handles removing filter, reseting callback priority keys mid-iteration, etc. $fob->remove_filter( $tag, $filter['function'], $priority ); } else { // Use legacy removal process (pre 4.7) unset( $callbacks[ $priority ][ $filter_id ] ); // and if it was the only filter in that priority, unset that priority if ( empty( $callbacks[ $priority ] ) ) { unset( $callbacks[ $priority ] ); } // and if the only filter for that tag, set the tag to an empty array if ( empty( $callbacks ) ) { $callbacks = array(); } // Remove this filter from merged_filters, which specifies if filters have been sorted unset( $GLOBALS['merged_filters'][ $tag ] ); } return TRUE; } } return FALSE; } } /** * Make sure the function does not exist before defining it */ if( ! function_exists( 'remove_class_action') ){ /** * Remove Class Action Without Access to Class Object * * In order to use the core WordPress remove_action() on an action added with the callback * to a class, you either have to have access to that class object, or it has to be a call * to a static method. This method allows you to remove actions with a callback to a class * you don't have access to. * * Works with WordPress 1.2+ (4.7+ support added 9-19-2016) * * @param string $tag Action to remove * @param string $class_name Class name for the action's callback * @param string $method_name Method name for the action's callback * @param int $priority Priority of the action (default 10) * * @return bool Whether the function is removed. */ function remove_class_action( $tag, $class_name = '', $method_name = '', $priority = 10 ) { remove_class_filter( $tag, $class_name, $method_name, $priority ); } }
With these functions available in your code, you can use them like this…
remove_class_action('My_Plugin_Class', 'my_action_function', 11); // Remove the class hook using the same priority
Questions? Help?
Hopefully, this post solved your problem. If so, hit me up in the comments below.
Run into any issues? Let me know in the comments, and I’d love to help.

Blogger, expert WordPress developer, and developer of the awesome bbPress Voting plugin which is a must-have plugin for any bbPress forum.
Download bbPress Voting for free on the WordPress Plugin Directory.
Hi there,
I am trying to remove the action below within the given class and it did not work
class Dokan_Template_Products {
public static $errors;
public static $product_cat;
public static $post_content;
function __construct() {
//Bunch of other actions……
………….
add_action( ‘dokan_product_edit_after_inventory_variants’, array( __CLASS__, ‘load_others_template’ ), 85, 2 );
}
Can you suggest a way to remove it? Also how can I override the action?
Thank you
Hi Shahzaib, I suggested several different methods. Did you try them all? Did none of them work?
Just a note, __CLASS__ is a magic constant in PHP which represents the actual name of the class. Did you try removing it using the actual class name of Dokan_Template_Products?