Come sostituire una funzione dichiarata nella classe di un plugin in functions.php?

29 lug 2015, 18:25:43
Visualizzazioni: 33.5K
Voti: 11

Voglio modificare una funzione in un plugin. È dichiarata nel file principale del plugin in questo modo:

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

E viene richiamata in questo modo:

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

Immagino sarebbe possibile sostituirla se avessi accesso alla classe in functions.php. In quel caso potrei scrivere qualcosa del genere:

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

Il mio pensiero per ottenere accesso alla classe nel file functions.php era di includere il file dove la classe è dichiarata in functions.php:

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

Ma questo non funziona perché il file del plugin viene incluso quando il plugin viene inizializzato in WordPress, immagino.

C'è un modo per riscrivere la funzione senza toccare i file del plugin?

0
Tutte le risposte alla domanda 3
1
12

Se il tuo plugin è registrato in questo modo:

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

Allora dovresti essere in grado di rimuovere il filtro accedendo alla variabile globale:

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

Altrimenti, dovrai scorrere la variabile globale $wp_filter per trovare la chiave di registrazione:

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

Questa operazione è dispendiosa in termini di risorse e dovrebbe essere evitata a meno che non ci siano alternative.

29 lug 2015 21:19:19
Commenti

Questa dovrebbe essere la risposta accettata. È più generalmente utile e non limitata solo al caso specifico dell'OP.

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

Dovrebbe funzionare:

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 lug 2015 18:50:10
Commenti

esiste una funzione remove_action: https://codex.wordpress.org/Function_Reference/remove_action

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

Sì, è quello che mi mancava, questo plugin ha una variabile che può essere accessibile come globale. Mia stupidità. Grazie per la tua risposta, funziona in questo caso particolare (per questo plugin).

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

Alex Older ha linkato il posto che spiega perché la sua risposta funziona. La remove_action accetta un array con la classe statica o l'istanza della classe all'interno della quale desideri rimuovere un metodo.

ninja08 ninja08
7 mar 2017 23:36:57
0

Quel plugin rend la sua funzione di inizializzazione wcpgsk_init() sovrascrivibile, quindi un altro modo per modificarla è definirla prima in un plugin must-use (poiché è troppo tardi nel "functions.php" del tuo tema). Potresti quindi inserire la tua sovrascrittura in "wp-content/mu-plugins/functions.php":

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

        // La tua sovrascrittura.
        class My_WCPGSK_Main extends WCPGSK_Main {
            public function wcpgsk_email_after_order_table($order) {
                echo "O la la";
            }
        }
        define( 'WCRGSK_DOMAIN', WCPGSK_DOMAIN ); // Correzione di un refuso! (WooCommerce Rich Guys Swiss Knife?)

        //carica nel nostro globale
        $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;
    }
}

Ma un modo ancora migliore per sovrascriverlo è installare runkit (https://github.com/padraic/runkit) e poi sostituirlo direttamente nel "functions.php" del tuo 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
    );
} );

(È uno scherzo, comunque.)

30 lug 2015 10:05:52