Como substituo uma função, declarada dentro da classe de um plugin, no functions.php?

9

Eu quero modificar uma função em um plugin. É declarado no arquivo principal do plug-in assim:

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

Adicione chamadas de lá assim:

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

Eu acho que seria possível substituí-lo se tivesse acesso à classe em functions.php. Então eu seria capaz de escrever algo como isto:

$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') );

Meu pensamento para obter um acesso à classe no arquivo functions.php era incluir o arquivo em que a classe é declarada no functions.php:

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

Mas isso não funciona porque o arquivo do plug-in é incluído quando o plug-in está sendo inicializado no WordPress, eu acho.

Existe uma maneira de reescrever a função sem tocar nos arquivos do plug-in?

Igor Skoldin
fonte

Respostas:

8

Isso deve funcionar:

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' ) );

}
passatgt
fonte
11
existe uma função remove_action: codex.wordpress.org/Function_Reference/remove_action
Alex Older
Sim, perdi isso, este plugin tem uma variável que pode ser acessada como global. Minha estupidez. Obrigado pela sua resposta, isso está funcionando neste caso específico (para este plugin).
Igor Skoldin 30/07/2015
Alex Older vinculado ao lugar que explica por que sua resposta funciona. O remove_action aceita uma matriz com a classe estática ou instância dentro da qual você deseja remover um método.
Ninja08 7/0317
11

Se o seu plug-in estiver registrado assim:

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();

Em seguida, você poderá remover o filtro acessando o 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 $p;
    remove_action('wp_head',array($p,'test_method'));
  }

  function test_method() {
    echo 'Echoed from the child';
  }
}
$c = new Test_Class_Child();

Caso contrário, você precisará rastrear a $wp_filter globalchave de registro:

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();

Isso consome muitos recursos e realmente não deve ser feito, a menos que você não tenha outra escolha.

s_ha_dum
fonte
2
Essa deve ser a resposta aceita. Isso geralmente é útil e não se limita apenas ao caso específico do OP.
David R.
1

Esse plug-in torna sua função init wcpgsk_init()conectável, portanto, outra maneira de substituí-lo é defini-lo primeiro em um plug-in obrigatório (como é tarde demais nas "functions.php" do seu tema). Então você pode colocar sua substituição em "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;
    }
}

Mas uma maneira ainda melhor de substituí-lo é instalar runkit( https://github.com/padraic/runkit ) e substituí-lo diretamente nas funções do seu tema: "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
    );
} );

(Isso é uma piada, aliás.)

bonger
fonte