如何使用WordPress插件上的构造函数覆盖类?

问题描述:

I'm trying to override a plugin class on a WordPress plugin. Here is the original plugin class :

class WCV_Vendor_Dashboard
{
       /**
        * __construct()
        */
        function __construct()
        {
            add_shortcode( 'wcv_shop_settings', array( $this, 'display_vendor_settings' ) );
            add_shortcode( 'wcv_vendor_dashboard', array( $this, 'display_vendor_products' ) );

            add_action( 'template_redirect', array( $this, 'check_access' ) );
            add_action( 'init', array( $this, 'save_vendor_settings' ) );
        }

        public function save_vendor_settings(){
               //some codes here
        }
 }

Here is what I'm trying (in functions.php), but it doesn't work :

$wcv_vendor_dashboard = new WCV_Vendor_Dashboard();
global $wcv_vendor_dashboard;
remove_action( 'init', array( $wcv_vendor_dashboard , 'save_vendor_settings' ) );

How to remove it correctly and how to create the replacement?

Additional info: I did similar thing on the WooCommerce core. When I want to override a class / function, I use this (for example):

remove_action( 'template_redirect', array( 'WC_Form_Handler', 'save_account_details' ) );
function new_save_account_details() {
  //custom code here
}
add_action( 'template_redirect', 'new_save_account_details' );

It's working properly on WooCommerce core. I tried something similar on WCV_Vendor_Dashboard but it doesn't work.

我正在尝试覆盖WordPress插件上的插件类。 这是原始的插件类: p>

 类WCV_Vendor_Dashboard 
 {
 / ** 
 * __construct()
 * / 
函数__construct()
 {
 add_shortcode('wcv_shop_settings',array  ($ this,'display_vendor_settings')); 
 add_shortcode('wcv_vendor_dashboard',array($ this,'display_vendor_products')); 
 
 add_action('template_redirect',array($ this,'check_access'));  
 add_action('init',array($ this,'save_vendor_settings')); 
} 
 
公共函数save_vendor_settings(){
 //这里有些代码
} 
} 
  code  >  pre> 
 
 

这是我正在尝试的(在functions.php中),但它不起作用: p>

  $ wcv_vendor_dashboard =  new WCV_Vendor_Dashboard(); 
global $ wcv_vendor_dashboard; 
remove_action('init',array($ wcv_vendor_dashboard,'save_vend  or_settings')); 
  code>  pre> 
 
 

如何正确删除它以及如何创建替换? p>

其他信息 : strong> 我在WooCommerce核心上做了类似的事情。 当我想覆盖一个类/函数时,我使用它(例如): p>

  remove_action('template_redirect',array('WC_Form_Handler','save_account_details'));  
 
函数new_save_account_details(){
 //自定义代码
} 
add_action('template_redirect','new_save_account_details'); 
  code>  pre> 
 
 

它在WooCommerce上正常运行 核心。 我在WCV_Vendor_Dashboard上尝试了类似的东西,但它不起作用。 p> div>

Why it was working with woocommerce, but it does not work in this case?

When you attach a function on to a specific action, WoredPress creates unique id for that callback and stores that in global $wp_filter array ( in fact, it was an array before, but now it is an object ). For object method callbacks ( like array( $this, 'save_vendor_settings' ) ), the id is generated with spl_object_hash php function. For the above example,

spl_object_hash( $this ) . 'save_vendor_settings'

, and it looks like 000000001c0af63f000000006d7fe83asave_vendor_settings.

To "legally" remove the object method with remove_action() you will need to have access to the original object that was used to attach the function in the first place. If the object exists in global namespace:

global $wcv;
remove_action( 'init', array( $wcv, 'save_vendor_settings' ) );

Creating another class instance will not work because the generated id is unique for each object, even if they are instances of the same class.

In the case of WooCommerce I guess it was about static class methods. Different logic is used to generate the ids for static class methods, functions and static method callbacks are just returned as strings. For your example it would be:

'WC_Form_Handler' . '::' . 'save_account_details'

You see why it works for one case, but not for the other.

There is a hack to replace functions attached by replacing them directly in global $wp_filter object, but it's not 100% reliable. Since we do not have access to the original object, we can only filter $wp_filter by the name of the function, if there are identical names for the same action it will replace wrong handlers.

global $wp_filter;
foreach ( $wp_filter['init']->callbacks as $priority => &$callbacks ) {

    foreach ( $callbacks as $id => &$callback ) {

        if ( substr( $id, -strlen( 'save_vendor_settings' ) ) === 'save_vendor_settings' ) {
            // replace the callback with new function
            $callback['function'] = 'new_save_vendor_settings';
        }
    }
}

I hope it will work, greetings.

Example for child class

class WCV_Vendor_Dashboard_Child extends WCV_Vendor_Dashboard
{
   /**
    * __construct()
    */
    function __construct()
    {
        parent::__construct();
    }

    public function new_save_vendor_settings(){
           //some codes here
    }
}