¿Cómo reemplazo una función declarada dentro de la clase de un plugin en functions.php?

29 jul 2015, 18:25:43
Vistas: 33.5K
Votos: 11

Quiero modificar una función en un plugin. Está declarada en el archivo principal del plugin de esta manera:

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

Y es llamada desde allí así:

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

Supongo que sería posible reemplazarla si tuviera acceso a la clase en functions.php. Entonces podría escribir algo como esto:

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

Mi idea para obtener acceso a la clase en el archivo functions.php fue incluir el archivo donde se declara la clase en functions.php:

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

Pero esto no funciona porque el archivo del plugin se incluye cuando el plugin se está inicializando en WordPress, supongo.

¿Hay alguna manera de reescribir la función sin tocar los archivos del plugin?

0
Todas las respuestas a la pregunta 3
1
12

Si tu plugin está registrado de esta manera:

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

Entonces deberías poder eliminar el filtro accediendo al 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();

De lo contrario, necesitarás recorrer el global $wp_filter para encontrar la clave 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();

Esto consume muchos recursos y realmente no debería hacerse a menos que no tengas otra opción.

29 jul 2015 21:19:19
Comentarios

Esta debería ser la respuesta aceptada. Es más útil en general y no se limita solo al caso específico del OP.

David R. David R.
23 ago 2016 13:45:01
3

Esto debería 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' ) );

}
29 jul 2015 18:50:10
Comentarios

existe una función remove_action: https://codex.wordpress.org/Function_Reference/remove_action

Alex Older Alex Older
29 jul 2015 19:10:47

Sí, eso es lo que me faltó, este plugin tiene una variable a la que se puede acceder como global. Mi estupidez. Gracias por tu respuesta, esto funciona en este caso particular (para este plugin).

Igor Skoldin Igor Skoldin
30 jul 2015 19:18:10

Alex Older enlazó al lugar que explica por qué su respuesta funciona. El remove_action acepta un array con la clase estática o de instancia dentro de la cual deseas eliminar un método.

ninja08 ninja08
7 mar 2017 23:36:57
0

Ese plugin hace que su función de inicialización wcpgsk_init() sea pluggable, por lo que otra forma de sobrescribirla es definirla primero en un plugin must-use (ya que es demasiado tarde en el "functions.php" de tu tema). Así que podrías poner tu sobrescritura en "wp-content/mu-plugins/functions.php":

function wcpgsk_init() {
    global $wcpgsk, $wcpgsk_about, $wcpgsk_options, $wcpgsk_session, $wcpgsk_woocommerce_active;    
    //solo continuar cargando
    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;

        // Tu sobrescritura.
        class My_WCPGSK_Main extends WCPGSK_Main {
            public function wcpgsk_email_after_order_table($order) {
                echo "O la la";
            }
        }
        define( 'WCRGSK_DOMAIN', WCPGSK_DOMAIN ); // ¡Corrección de typo! (¿WooCommerce Rich Guys Swiss Knife?)

        //cargar en nuestro 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;
    }
}

Pero una forma aún mejor de sobrescribirlo es instalar runkit (https://github.com/padraic/runkit) y luego simplemente reemplazarlo directamente en el "functions.php" de tu tema:

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

(Eso es una broma, por cierto.)

30 jul 2015 10:05:52