remove_action o remove_filter con classi esterne?
-
-
N/P.Sotto Afunzionaperte?N/P. Does below A work for you?
- 0
- 2011-12-09
- kaiser
-
7 risposta
- voti
-
- 2011-12-10
La cosamigliore dafare qui è usare una classe statica. Il codice seguente dovrebbeessere didattico:
class MyClass { function __construct() { add_action( 'wp_footer', array( $this, 'my_action' ) ); } function my_action() { print '<h1>' . __class__ . ' - ' . __function__ . '</h1>'; } } new MyClass(); class MyStaticClass { public static function init() { add_action( 'wp_footer', array( __class__, 'my_action' ) ); } public static function my_action() { print '<h1>' . __class__ . ' - ' . __function__ . '</h1>'; } } MyStaticClass::init(); function my_wp_footer() { print '<h1>my_wp_footer()</h1>'; } add_action( 'wp_footer', 'my_wp_footer' ); function mfields_test_remove_actions() { remove_action( 'wp_footer', 'my_wp_footer' ); remove_action( 'wp_footer', array( 'MyClass', 'my_action' ), 10 ); remove_action( 'wp_footer', array( 'MyStaticClass', 'my_action' ), 10 ); } add_action( 'wp_head', 'mfields_test_remove_actions' );
Seesegui questo codice da unplugin dovrestinotare cheilmetodo di StaticClasse lafunzione verranno rimossi da wp_footer.
The best thing to do here is to use a static class. The following code should be instructional:
class MyClass { function __construct() { add_action( 'wp_footer', array( $this, 'my_action' ) ); } function my_action() { print '<h1>' . __class__ . ' - ' . __function__ . '</h1>'; } } new MyClass(); class MyStaticClass { public static function init() { add_action( 'wp_footer', array( __class__, 'my_action' ) ); } public static function my_action() { print '<h1>' . __class__ . ' - ' . __function__ . '</h1>'; } } MyStaticClass::init(); function my_wp_footer() { print '<h1>my_wp_footer()</h1>'; } add_action( 'wp_footer', 'my_wp_footer' ); function mfields_test_remove_actions() { remove_action( 'wp_footer', 'my_wp_footer' ); remove_action( 'wp_footer', array( 'MyClass', 'my_action' ), 10 ); remove_action( 'wp_footer', array( 'MyStaticClass', 'my_action' ), 10 ); } add_action( 'wp_head', 'mfields_test_remove_actions' );
If you run this code from a plugin you should notice that the method of the StaticClass as well as the function will removed from wp_footer.
-
Puntopreso,manontutte le classipossonoessere semplicemente convertitein statiche.Point taken, but not all classes can simply be converted to be static.
- 8
- 2012-02-29
- Geert
-
Ho accettato questa rispostaperché risponde alla domandain modopiù diretto,sebbene la risposta di Otto sia lamigliorepratica.Noto qui chenonpenso sianecessario dichiarareesplicitamente statico.È stata lamiaesperienza (anche sepotrei sbagliarmi) chepuoi semplicementetrattare lafunzione come sefosse un array statico ('MyClass','member_function')e spessofunziona senza laparola chiave 'static'.I accepted this answer because it answers the question most directly, though Otto's response is the best practice. I note here that I don't think you need to explicitly declare static. It's been my experience (though I could be wrong) that you can just treat the function as though it were static array( 'MyClass', 'member_function' ) and it often works without the 'static' keyword.
- 0
- 2012-04-24
- Tom Auger
-
@TomAugernononpuoi,SOLO se viene aggiunta come classe staticapuoi usare lafunzione `remove_action`,altrimentinonfunzionerà ...eccoperché ho dovuto scrivere lamiafunzione dagestire quandonon è una classe statica.Questa risposta sarebbe lamigliore solo se latua domanda riguardasseiltuo codice,altrimentiproverai a rimuovere un altrofiltro/azione dallabase di codice di qualcun altroe nonpotrai cambiarloin statico@TomAuger no you can't, ONLY if it's added as a static class can you use the `remove_action` function, otherwise it will not work...that's why I had to write my own function to handle when it's not a static class. This answer would only be the best if your question was regarding your own code, otherwise you will be trying to remove another filter/action from someone else's codebase and can't change it to static
- 0
- 2016-09-20
- sMyles
-
- 2011-12-10
Ogni volta che unplugin crea un
new MyClass();
,dovrebbe assegnarlo a una variabile dalnome univoco. In questomodo,l'istanza della classe è accessibile.Quindi se stavafacendo
$myclass = new MyClass();
,allorapotrestifarlo:global $myclass; remove_action( 'wp_footer', array( $myclass, 'my_action' ) );
Questofunzionaperchéi plugin sonoinclusinello spazio deinomiglobale,quindi le dichiarazioni di variabiliimplicitenel corpoprincipale di unplugin sono variabiliglobali.
Seilpluginnon salva l'identificatore dellanuova classe da qualcheparte ,tecnicamente sitratta di unbug. Uno deiprincipigenerali dellaprogrammazione orientata agli oggetti è chegli oggetti chenon sono referenziati da qualche variabile da qualcheparte sono soggetti apulizia oeliminazione.
Ora,PHPin particolarenon lofa comefarebbe Java,perché PHP è una sorta diimplementazione OOP ametà. Le variabili diistanza sono solo stringhe connomi di oggetti univoci al lorointerno,più omeno. Funzionano soloperilmodoin cui l'interazione delnome dellafunzione variabilefunziona con l'operatore
->
. Quindi anche solofarenew class()
puòfunzionareperfettamente,semplicemente stupidamente. :)Quindi,in ultima analisi,noneseguiremai
new class();
. Esegui$var = new class();
e rendi quella $ var accessibilein qualchemodoperfarvi riferimento ad altribit.Modifica: anni dopo
Una cosa che ho vistofaremoltiplugin è usare qualcosa di simile alpattern "Singleton". Creano unmetodogetInstance ()per ottenere la singolaistanza della classe. Questa èprobabilmente lamigliore soluzione che ho visto. Plugin diesempio:
class ExamplePlugin { protected static $instance = NULL; public static function getInstance() { NULL === self::$instance and self::$instance = new self; return self::$instance; } }
Laprima volta chegetInstance () viene chiamato,istanzia la classee salvail suopuntatore. Puoi usarloper agganciare le azioni.
Unproblema con questo è chenonpuoi usaregetInstance () all'interno del costruttore se usi una cosa delgenere. Questoperchéilnew chiamail costruttoreprima diimpostare l'istanza $,quindi chiamaregetInstance () dal costruttoreporta a un cicloinfinitoe interrompetutto.
Una soluzione alternativa ènon utilizzareil costruttore (o,almeno,non usaregetInstance () al suointerno),ma avereesplicitamente unafunzione "init"nella classeperimpostare leproprie azionie simili. In questomodo:
public static function init() { add_action( 'wp_footer', array( ExamplePlugin::getInstance(), 'my_action' ) ); }
Con qualcosa delgenere,allafine delfile,dopo che la classe è statatutta definitae simili,istanziareilplugin diventa così semplice:
ExamplePlugin::init();
Initinizia ad aggiungere letue azioni,e cosìfacendo chiamagetInstance (),cheistanzia la classee si assicura cheesista solo una diesse. Senon hai unafunzioneinit,dovrestifarloperistanziareinizialmente la classe:
ExamplePlugin::getInstance();
Per rispondere alla domanda originale,èpossibile rimuovere quell'action hook dall'esterno (ovveroin un altroplugin)in questomodo:
remove_action( 'wp_footer', array( ExamplePlugin::getInstance(), 'my_action' ) );
Inserisciloin qualcosa di agganciato all'action hook
plugins_loaded
e annullerà l'azione agganciata dalplugin originale.Whenever a plugin creates a
new MyClass();
, it should assign it to a uniquely named variable. That way, the instance of the class is accessible.So if he was doing
$myclass = new MyClass();
, then you could do this:global $myclass; remove_action( 'wp_footer', array( $myclass, 'my_action' ) );
This works because plugins are included in the global namespace, so implicit variable declarations in the main body of a plugin are global variables.
If the plugin doesn't save the identifier of the new class somewhere, then technically, that's a bug. One of the general principles of Object Oriented Programming is that objects which are not being referenced by some variable somewhere are subject to cleanup or elimination.
Now, PHP in particular doesn't do this like Java would, because PHP is sorta a half-arsed OOP implementation. The instance variables are just strings with unique object names in them, sort of thing. They only work because of the way the variable function name interaction works with the
->
operator. So just doingnew class()
can indeed work perfectly, just stupidly. :)So, bottom line, never do
new class();
. Do$var = new class();
and make that $var accessible in some way for other bits to reference it.Edit: years later
One thing I've seen a lot of plugins doing is to use something similar to the "Singleton" pattern. They create a getInstance() method to get the single instance of the class. This is probably the best solution I've seen. Example plugin:
class ExamplePlugin { protected static $instance = NULL; public static function getInstance() { NULL === self::$instance and self::$instance = new self; return self::$instance; } }
The first time getInstance() is called, it instantiates the class and saves its pointer. You can use that to hook in actions.
One problem with this is that you can't use getInstance() inside the constructor if you use such a thing. This is because the new calls the constructor before setting the $instance, so calling getInstance() from the constructor leads to an infinite loop and breaks everything.
One workaround is to not use the constructor (or, at least, not to use getInstance() within it), but to explicitly have an "init" function in the class to set up your actions and such. Like this:
public static function init() { add_action( 'wp_footer', array( ExamplePlugin::getInstance(), 'my_action' ) ); }
With something like this, at the end of the file, after the class has been all defined and such, instantiating the plugin becomes as simple as this:
ExamplePlugin::init();
Init starts to add your actions, and in so doing it calls getInstance(), which instantiates the class and makes sure only one of them exists. If you don't have an init function, you would do this to instantiate the class initially instead:
ExamplePlugin::getInstance();
To address the original question, removing that action hook from the outside (aka, in another plugin) can then be done like so:
remove_action( 'wp_footer', array( ExamplePlugin::getInstance(), 'my_action' ) );
Put that in something hooked to the
plugins_loaded
action hook and it'll undo the action being hooked by the original plugin.-
+1 Tru dat.Questa è chiaramente unabestpractice.Dovremmotutti sforzarci di scrivereilnostro codicepluginin questomodo.+1 Tru dat. This is clearly a best practice. We should all endeavour to write our plugin code that way.
- 3
- 2012-04-24
- Tom Auger
-
+1 questeistruzionimi hanno davvero aiutato a rimuovere unfiltroin una classe dipattern singleton.+1 these instructions really helped me to remove a filter in a singleton pattern class.
- 3
- 2014-03-28
- Devin Walker
-
+1,mapenso che dovrestigeneralmente agganciarti a `wp_loaded`,non a`plugins_loaded`,chepotrebbeessere chiamatotroppopresto.+1, but I think you should generally hook to `wp_loaded`, not `plugins_loaded`, which may be called too early.
- 0
- 2015-04-28
- EML
-
No,"plugins_loaded" sarebbeilposto corretto.L'azione `wp_loaded` avviene dopo l'azione`init`,quindi seiltuopluginesegue un'azione su `init` (e lamaggiorparte lofa),allora vuoiinizializzareilplugine configurarloprima.L'hook `plugins_loaded` èilpostogiustoper quellafase di costruzione.No, `plugins_loaded` would be the correct place. The `wp_loaded` action happens after the `init` action, so if your plugin takes any actions on `init` (and most do), then you want to initialize the plugin and set it up before that. The `plugins_loaded` hook is the right place for that construction phase.
- 4
- 2015-04-28
- Otto
-
Potrebbeessere unpo 'tardiper rispondere.Magrazieper questo contributo.Dopo aver cercatoper ore abbiamo scoperto chenon rispettavamoi principigenerali dellaprogrammazione orientata agli oggetti,ovvero chegli oggetti chenon sono referenziati da qualche variabile da qualcheparte sono soggetti apulizia oeliminazione.This might be a little late to respond. But thank you for this input. After looking for hours we found out that we did not respect the general principles of Object Oriented Programming which is saying objects which are not being referenced by some variable somewhere are subject to cleanup or elimination.
- 0
- 2020-01-21
- NME New Media Entertainment
-
- 2012-11-06
2piccolefunzioni PHPper consentire la rimozione difiltri/azioni con la classe "anonima": https://github.com/herewithme/wp-filters-extras/
2 small PHP functions for allow removing filter/action with "anonymous" class : https://github.com/herewithme/wp-filters-extras/
-
Funzionimoltointeressanti.Grazieper averlopubblicato qui!Very cool functions. Thanks for posting that here!
- 0
- 2012-11-06
- Tom Auger
-
Come accennatoin altrinelmiopost di seguito,questi siinterromperannoin WordPress 4.7 (ameno cheil repositorynon venga aggiornato,manon lo è da 2 anni)As mentioned be others in my post below, these will break in WordPress 4.7 (unless the repo gets updated, but hasn't in 2 years)
- 0
- 2016-09-20
- sMyles
-
Notando solo cheil repository wp-filters-extras è statoeffettivamente aggiornatoper v4.7e la classe WP_Hook.Just noting that the wp-filters-extras repo has indeed been updated for v4.7 and the WP_Hook class.
- 1
- 2017-05-04
- Dave Romsey
-
- 2017-12-25
Le soluzioni di cui sopra sembrano obsolete,ho dovuto scrivere lamia ...
function remove_class_action ($action,$class,$method) { global $wp_filter ; if (isset($wp_filter[$action])) { $len = strlen($method) ; foreach ($wp_filter[$action] as $pri => $actions) { foreach ($actions as $name => $def) { if (substr($name,-$len) == $method) { if (is_array($def['function'])) { if (get_class($def['function'][0]) == $class) { if (is_object($wp_filter[$action]) && isset($wp_filter[$action]->callbacks)) { unset($wp_filter[$action]->callbacks[$pri][$name]) ; } else { unset($wp_filter[$action][$pri][$name]) ; } } } } } } } }
Above solutions look like outdated, had to write my own...
function remove_class_action ($action,$class,$method) { global $wp_filter ; if (isset($wp_filter[$action])) { $len = strlen($method) ; foreach ($wp_filter[$action] as $pri => $actions) { foreach ($actions as $name => $def) { if (substr($name,-$len) == $method) { if (is_array($def['function'])) { if (get_class($def['function'][0]) == $class) { if (is_object($wp_filter[$action]) && isset($wp_filter[$action]->callbacks)) { unset($wp_filter[$action]->callbacks[$pri][$name]) ; } else { unset($wp_filter[$action][$pri][$name]) ; } } } } } } } }
-
- 2019-11-13
In casi come questo,Wordpress aggiunge un hash (id univoco) alnome dellafunzionee lomemorizzanella variabileglobale
$wp_filter
. Quindi se usi lafunzioneremove_filter
non succederànulla. Anche se aggiungiilnome della classe alnome dellafunzione comeremove_filter('plugins_loaded', ['MyClass', 'my_action'])
. Tutto quello chepuoi è rimuoveremanualmentetuttigli hookmy_action
dalla variabileglobale$wp_filter
.Ecco lafunzioneperfarlo:
function my_remove_filter($tag, $function_name, $priority = 10){ global $wp_filter; if( isset($wp_filter[$tag]->callbacks[$priority]) and !empty($wp_filter[$tag]->callbacks[$priority]) ){ $wp_filter[$tag]->callbacks[$priority] = array_filter($wp_filter[$tag]->callbacks[$priority], function($v, $k) use ($function_name){ return ( stripos($k, $function_name) === false ); }, ARRAY_FILTER_USE_BOTH ); } }
usalo come:
my_remove_filter('plugins_loaded', 'my_action');
In cases like this the Wordpress adds a hash (unique id) to the function name and stores it in the global
$wp_filter
variable. So if you useremove_filter
function nothing will happen. Even if you add the class name to the function name likeremove_filter('plugins_loaded', ['MyClass', 'my_action'])
. All you can is to remove all themy_action
hooks from the global$wp_filter
variable manually.Here is the function to do this:
function my_remove_filter($tag, $function_name, $priority = 10){ global $wp_filter; if( isset($wp_filter[$tag]->callbacks[$priority]) and !empty($wp_filter[$tag]->callbacks[$priority]) ){ $wp_filter[$tag]->callbacks[$priority] = array_filter($wp_filter[$tag]->callbacks[$priority], function($v, $k) use ($function_name){ return ( stripos($k, $function_name) === false ); }, ARRAY_FILTER_USE_BOTH ); } }
use it like:
my_remove_filter('plugins_loaded', 'my_action');
-
- 2019-05-29
Questafunzione sibasa sulla risposta di @Digerkam. Aggiunto confronto se
$def['function'][0]
è una stringae finalmente hafunzionatoperme.Anche l'uso di
$wp_filter[$tag]->remove_filter()
dovrebbe renderlopiù stabile.function remove_class_action($tag, $class = '', $method, $priority = null) : bool { global $wp_filter; if (isset($wp_filter[$tag])) { $len = strlen($method); foreach($wp_filter[$tag] as $_priority => $actions) { if ($actions) { foreach($actions as $function_key => $data) { if ($data) { if (substr($function_key, -$len) == $method) { if ($class !== '') { $_class = ''; if (is_string($data['function'][0])) { $_class = $data['function'][0]; } elseif (is_object($data['function'][0])) { $_class = get_class($data['function'][0]); } else { return false; } if ($_class !== '' && $_class == $class) { if (is_numeric($priority)) { if ($_priority == $priority) { //if (isset( $wp_filter->callbacks[$_priority][$function_key])) {} return $wp_filter[$tag]->remove_filter($tag, $function_key, $_priority); } } else { return $wp_filter[$tag]->remove_filter($tag, $function_key, $_priority); } } } else { if (is_numeric($priority)) { if ($_priority == $priority) { return $wp_filter[$tag]->remove_filter($tag, $function_key, $_priority); } } else { return $wp_filter[$tag]->remove_filter($tag, $function_key, $_priority); } } } } } } } } return false; }
Esempio di utilizzo:
Corrispondenzaesatta
add_action('plugins_loaded', function() { remove_class_action('plugins_loaded', 'MyClass', 'my_action', 0); });
Qualsiasipriorità
add_action('plugins_loaded', function() { remove_class_action('plugins_loaded', 'MyClass', 'my_action'); });
Qualsiasi classee qualsiasipriorità
add_action('plugins_loaded', function() { remove_class_action('plugins_loaded', '', 'my_action'); });
This function based on @Digerkam answer. Added compare if
$def['function'][0]
is string and it's finally worked for me.Also using
$wp_filter[$tag]->remove_filter()
should make it more stable.function remove_class_action($tag, $class = '', $method, $priority = null) : bool { global $wp_filter; if (isset($wp_filter[$tag])) { $len = strlen($method); foreach($wp_filter[$tag] as $_priority => $actions) { if ($actions) { foreach($actions as $function_key => $data) { if ($data) { if (substr($function_key, -$len) == $method) { if ($class !== '') { $_class = ''; if (is_string($data['function'][0])) { $_class = $data['function'][0]; } elseif (is_object($data['function'][0])) { $_class = get_class($data['function'][0]); } else { return false; } if ($_class !== '' && $_class == $class) { if (is_numeric($priority)) { if ($_priority == $priority) { //if (isset( $wp_filter->callbacks[$_priority][$function_key])) {} return $wp_filter[$tag]->remove_filter($tag, $function_key, $_priority); } } else { return $wp_filter[$tag]->remove_filter($tag, $function_key, $_priority); } } } else { if (is_numeric($priority)) { if ($_priority == $priority) { return $wp_filter[$tag]->remove_filter($tag, $function_key, $_priority); } } else { return $wp_filter[$tag]->remove_filter($tag, $function_key, $_priority); } } } } } } } } return false; }
Example usage:
Exact match
add_action('plugins_loaded', function() { remove_class_action('plugins_loaded', 'MyClass', 'my_action', 0); });
Any priority
add_action('plugins_loaded', function() { remove_class_action('plugins_loaded', 'MyClass', 'my_action'); });
Any Class and any priority
add_action('plugins_loaded', function() { remove_class_action('plugins_loaded', '', 'my_action'); });
-
- 2019-08-06
Questanon è una rispostagenerica,ma specificaper Tema Avadae WooCommerce ,che secondome altrepersonepotrebberotrovare utili:
function remove_woo_commerce_hooks() { global $avada_woocommerce; remove_action( 'woocommerce_single_product_summary', array( $avada_woocommerce, 'add_product_border' ), 19 ); } add_action( 'after_setup_theme', 'remove_woo_commerce_hooks' );
This is not a generic answer, but one specific to Avada theme and WooCommerce, which I think other people may find helpful:
function remove_woo_commerce_hooks() { global $avada_woocommerce; remove_action( 'woocommerce_single_product_summary', array( $avada_woocommerce, 'add_product_border' ), 19 ); } add_action( 'after_setup_theme', 'remove_woo_commerce_hooks' );
In una situazionein cui unplugin haincapsulatoi suoimetodi all'interno di una classee poi ha registrato unfiltro o un'azione contro uno di queimetodi,come rimuovi l'azione oilfiltro senon haipiù accesso all'istanza di quella classe?
Peresempio,supponi di avere unplugin chefa questo:
Notando che oranon homodo di accedere all'istanza,comeposso annullare la registrazione della classe?Questo:
remove_action( "plugins_loaded", array( MyClass, 'my_action' ) );
non sembraessere l'approcciogiusto - almeno,non sembrafunzionarenelmio caso.