6

Somewhere in the plugin class there is this hook :

add_action( 'woocommerce_some_hook', array( $this, 'some_function') );

it adds something I don't want there. In my functions.php in my theme, I have tried everything such as : remove_action('woocommerce_some_hook','some_function');

or

remove_action( 'woocommerce_some_hook', array('original_plugin_class', 'some_function',));

but still, I simply can't remove the hook!

3 Answers 3

9

One problem with the way WordPress handles hooks is that to remove a specific hook with an OOP callback, you must have access to the exact same instance of the class as when the callback was added. This is generally easy enough to handle in your own plugins/themes.

However, it makes it nearly impossible to remove a hook from another plugin unless that developer globalized the instance of the class. If that's the case, then you can use the global keyword and remove the hook like normal. Another popular pattern is to use a singleton method to only allow one instance of the class.

Unfortunately, it seems that a lot of plugins (including WC) initialize the class when the file is included. To further complicate things, they add hooks in the constructor of the class. This makes it extremely difficult to remove hooks.

I've been working on a class that will remove a hook from the $wp_filter global variable if you know the Namespace\Class and Method of the callback. I've done limited testing of the class, so use at your own risk, but it does work for me.

Hopefully this will point you in right direction.

<?php

namespace WPSE\Q_258764;

/**
 * Class for interacting with hooks
 */

class hooks {

  /**
   * @var Namespace of the hook
   *
   * @access protected
   * @since 0.2
   */
  protected $namespace;

  /**
   * Object constructor
   *
   * @param string $namespace The namespace of the hook. Optional.
   *
   * @access public
   * @since 0.2
   */
  public function __construct( $namespace = __NAMESPACE__ ) {
    $this->namespace = $namespace;
  }

  /**
   * Remove a hook from the $wp_filter global
   *
   * @param string   $tag      The hook which the callback is attached to
   * @param callable $callback The callback to remove
   * @param int      $priority The priority of the callback
   *
   * @access public
   * @since 0.2
   *
   * @return bool Whether the filter was originally in the $wp_filter global
   */
  public function remove_hook( $tag, $callback, $priority = 10 ) {
    global $wp_filter;
    $tag_hooks = $wp_filter[ $tag ]->callbacks[ $priority ];
    foreach ( $tag_hooks as $the_tag => $the_callback ) {
      if( $this->parse_callback( $the_callback ) === $callback ) {
        return \remove_filter( $tag, $the_callback[ 'function' ], $priority );
      }
    }
    return \remove_filter( $tag, $callback, $priority );
  }

  /**
   * Trim backslash from string
   *
   * @param string $string
   *
   * @access protected
   * @since 0.2
   *
   * @return string
   */
  protected function trim_backslash( $string ) {
    return trim( $string, '\\' );
  }

  /**
   * Remove the namespace from the string
   *
   * @param string $string
   *
   * @access protected
   * @since 0.2
   *
   * @return string
   */
  protected function remove_namespace( $string ) {
    return str_ireplace( $this->namespace, '', $string );
  }

  /**
   * Get the class name of an object
   *
   * @param object $object
   *
   * @access protected
   * @since 0.2
   *
   * @return string
   */
  protected function get_class( $object ) {
    return get_class( $object );
  }

  /**
   * Return the callback object
   *
   * @param array $callback
   *
   * @access protected
   * @since 0.2
   *
   * @return object
   */
  protected function callback_object( $callback ) {
    return $callback[ 'function' ][ 0 ];
  }

  /**
   * Return the callback method
   *
   * @param array $callback
   *
   * @access protected
   * @since 0.2
   *
   * @return string
   */
  protected function callback_method( $callback ) {
    return $callback[ 'function' ][ 1 ];
  }

  /**
   * Return the class from the callback
   *
   * @param array $callback
   *
   * @access protected
   * @since 0.2
   *
   * @return string
   */
  protected function get_class_from_callback( $callback ) {
    return $this->get_class( $this->callback_object( $callback ) );
  }

  /**
   * Wrapper for strtolower
   *
   * @param string $string
   *
   * @access protected
   * @since 0.2
   *
   * @return string
   */
  protected function strtolower( $string ) {
    return strtolower( $string );
  }

  /**
   * Parse the callback into an array
   *
   * @param array $callback
   *
   * @access protected
   * @since 0.2
   *
   * @return array
   */
  protected function parse_callback( $callback ) {
    return is_array( $callback[ 'function' ] ) ?
      [ $this->class( $callback ), $this->method( $callback ) ] : false;
  }

  /**
   * Return the class of a callback
   *
   * @param array $callback
   *
   * @access protected
   * @since 0.2
   *
   * @return string
   */
  protected function class( $callback ) {
    $class = $this->get_class_from_callback( $callback );
    $class = $this->strtolower( $class );
    $class = $this->remove_namespace( $class );
    return $this->trim_backslash( $class );
  }

  /**
   * Return the method of a callback
   *
   * @param array $callback
   *
   * @access protected
   * @since 0.2
   *
   * @return string
   */
  protected function method( $callback ) {
    return $callback[ 'function' ][ 1 ];
  }
}

Edit: this will only work on WP versions greater than 4.7.

1
  • 1
    I would give a different spin on it - If the plugin do not have documentation on how to remove the filter, maybe it is just not a good idea to do it at all as the plugin might depend on it being there Commented Mar 3, 2017 at 16:32
0

It is necessary to pass an instance in which the hook was set up

global $my_class;
remove_action( 'woocommerce_some_hook', array( $my_class, 'some_function' ) );

make sure that the instance of the class is available

1
  • It didn't work... Can you tell me how to make sure that the instance of the class is available? And if it not available this means I cannot remove it? I don't want to deactivate any plugins or change the source code of them, any changes need to be in the functions.php of my theme.
    – chas ant
    Commented Mar 3, 2017 at 16:16
0

You can try,

remove_action( 'woocommerce_some_hook', array(new original_plugin_class(), 'some_function',));

you need to create the instance of the class when they are not globally created. Suppose if they have created the instance of the class some where, then you can use that like @TrubinE mentioned.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.