如何在函数.php中替换在插件的类中声明的函数?

时间:2015-07-29 作者:Igor Skoldin

I want to modify a function in a plugin. It is declared in the plugin\'s main file like this:

class WCPGSK_Main {
  ...
  public function wcpgsk_email_after_order_table($order) {
    ...
  }
}

Add called from there like this:

add_action( \'woocommerce_email_after_order_table\', array($this, \'wcpgsk_email_after_order_table\') );

I guess it would be possible to replace it if had an access to the class in functions.php. Then I would be able to write something like this:

$wcpgsk = new WCPGSK_Main;

remove_action( \'woocommerce_email_after_order_table\', array($wcpgsk, \'wcpgsk_email_after_order_table\') );

function customized_wcpgsk_email_after_order_table($order) {
  ...
}
add_action( \'woocommerce_email_after_order_table\', array($wcpgsk, \'customized_wcpgsk_email_after_order_table\') );

My thought to get an access to the class in the functions.php file was to include the file where the class is declared in functions.php:

require_once(\'/wp-content/plugins/woocommerce-poor-guys-swiss-knife/woocommerce-poor-guys-swiss-knife.php\');
$wcpgsk = new WCPGSK_Main;
...

But this does not work because the plugin\'s file is included when the plugin is getting initialized in WordPress, I guess.

Is there a way to rewrite the function without touching plugin\'s files?

3 个回复
最合适的回答,由SO网友:passatgt 整理而成

This should work:

add_action( \'woocommerce_init\', \'remove_wcpgsk_email_order_table\' );
function remove_wcpgsk_email_order_table() {

    global $wcpgsk;
    remove_action( \'woocommerce_email_after_order_table\', array( $wcpgsk, \'wcpgsk_email_after_order_table\' ) );

}
SO网友:s_ha_dum

如果您的插件是这样注册的:

class Test_Class_Parent {
  function __construct() {
    add_action(\'wp_head\',array($this,\'test_method\'));
  }

  function test_method() {
    echo \'Echoed from the parent\';
  }
}
$p = new Test_Class_Parent();
然后,您应该能够通过访问全局:

class Test_Class_Child extends Test_Class_Parent {
  function __construct() {
    $this->unregister_parent_hook();
    add_action(\'wp_head\',array($this,\'test_method\'));
  }

  function unregister_parent_hook() {
    global $p;
    remove_action(\'wp_head\',array($p,\'test_method\'));
  }

  function test_method() {
    echo \'Echoed from the child\';
  }
}
$c = new Test_Class_Child();
否则,您将需要爬网$wp_filter global 对于注册密钥:

class Test_Class_Child extends Test_Class_Parent {
  function __construct() {
    $this->unregister_parent_hook();
    add_action(\'wp_head\',array($this,\'test_method\'));
  }

  function unregister_parent_hook() {
    global $wp_filter;
    if (!empty($wp_filter[\'wp_head\'])) {
      foreach($wp_filter[\'wp_head\'] as $cb) {
        foreach ($cb as $k => $v) {
          if (
            isset($v[\'function\'])
            && is_a($v[\'function\'][0],\'Test_Class_Parent\')
            && isset($v[\'function\'][1])
            && \'test_method\' == $v[\'function\'][1]
          ) {
            remove_action(\'wp_head\',$k);
          }
        }
      }
    }
  }

  function test_method() {
    echo \'Echoed from the child\';
  }
}
$c = new Test_Class_Child();
这是资源密集型的,除非你别无选择,否则不应该这样做。

SO网友:bonger

该插件使其init函数wcpgsk_init() 可插拔的,所以另一种覆盖它的方法是首先在必须使用的插件中定义它(因为在主题的“functions.php”中已经太晚了)。因此,您可以将覆盖放在“wp-content/mu-plugins/functions.php”中:

function wcpgsk_init() {
    global $wcpgsk, $wcpgsk_about, $wcpgsk_options, $wcpgsk_session, $wcpgsk_woocommerce_active;    
    //only continue loading
    if ( $wcpgsk_woocommerce_active && version_compare( WOOCOMMERCE_VERSION, "2.0" ) >= 0 ) {
        $FILE = WP_PLUGIN_DIR . \'/woocommerce-poor-guys-swiss-knife/woocommerce-poor-guys-swiss-knife.php\'; // Fake __FILE__
        $dirname = dirname( $FILE ) . \'/\';
        $wcpgsk_options = get_option(\'wcpgsk_settings\', true);
        require_once( $dirname . \'classes/woocommerce-poor-guys-swiss-knife.php\' );
        require_once( $dirname . \'classes/woocommerce-poor-guys-swiss-knife-about.php\' );   
        require_once( $dirname . \'wcpgsk-af.php\' );

        if ( !is_admin() ) :
            add_action( \'plugins_loaded\', \'wcpgsk_load_wcsession_helper\' );
        endif;

        // Your override.
        class My_WCPGSK_Main extends WCPGSK_Main {
            public function wcpgsk_email_after_order_table($order) {
                echo "O la la";
            }
        }
        define( \'WCRGSK_DOMAIN\', WCPGSK_DOMAIN ); // Fix typo! (WooCommerce Rich Guys Swiss Knife?)

        //load into our global
        $wcpgsk = new My_WCPGSK_Main( $FILE );
        $wcpgsk->version = \'2.2.4\'; 
        $wcpgsk->wcpgsk_hook_woocommerce_filters();


    } elseif ( version_compare( WOOCOMMERCE_VERSION, "2.0" ) < 0 ) {
        add_action( \'admin_notices\', \'wcpgsk_woocommerce_version_message\', 0 ) ;    
        return;
    } else {
        return;
    }
}
但覆盖它的更好方法是安装runkit (https://github.com/padraic/runkit) 然后直接在主题的“functions.php”中替换它:

add_action( \'init\', function () {
    $code = <<<\'EOD\'
echo "O la la";
EOD;
    runkit_method_redefine(
        \'WCPGSK_Main\',
        \'wcpgsk_email_after_order_table\',
        \'$order\',
        $code,
        RUNKIT_ACC_PUBLIC
    );
} );
(顺便说一句,这是个玩笑。)

结束

相关推荐

Single必须使用Plugins目录进行本地开发

我有多个本地安装的WordPress,并希望有一个单一的必须使用插件目录为我的所有本地网站。有什么我可以添加到wp配置,例如,让我有一个文件夹,可以用于我的所有网站?或者另一种方法?例如:/根/站点/站点1//根/站点/站点2//根/站点/站点3/。。。所有用途:/根/mu插件/谢谢