Come sostituire una funzione dichiarata nella classe di un plugin in functions.php?
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?
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.

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

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).

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.)
