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

9

Quiero modificar una función en un complemento. Se declara en el archivo principal del complemento de esta manera:

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

Agregue llamado desde allí así:

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

Supongo que sería posible reemplazarlo 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 pensamiento para obtener acceso a la clase en el archivo functions.php era 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 complemento se incluye cuando el complemento se inicializa en WordPress, supongo.

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

Igor Skoldin
fuente

Respuestas:

8

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

}
passatgt
fuente
1
hay una función remove_action: codex.wordpress.org/Function_Reference/remove_action
Alex Older
Sí, eso es lo que me perdí, este complemento tiene una variable a la que se puede acceder como global. Mi estupidez Gracias por su respuesta, esto está funcionando en este caso particular (para este complemento).
Igor Skoldin
Alex Older enlazó al lugar que explica por qué funciona su respuesta. Remove_action acepta una matriz con la clase estática o de instancia dentro de la cual desea eliminar un método.
ninja08
11

Si su complemento está registrado así:

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ía poder eliminar el filtro accediendo a la 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, deberá rastrear la $wp_filter globalclave 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 requiere muchos recursos y realmente no debe hacerse a menos que no tenga otra opción.

s_ha_dum
fuente
2
Esta debería ser la respuesta aceptada. Esto es más útil en general, y no se limita solo al caso específico de OP.
David R.
1

Ese complemento hace que su función de inicio sea wcpgsk_init()conectable, por lo que otra forma de anularlo es definirla primero en un complemento de uso obligatorio (ya que es demasiado tarde en las "funciones.php" de su tema). Por lo tanto, puede poner su anulación en "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;
    }
}

Pero una forma aún mejor de anularlo es instalarlo runkit( https://github.com/padraic/runkit ) y luego reemplazarlo directamente en las "funciones.php" de su 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)

bonger
fuente