remove_action ou remove_filter avec des classes externes?
-
-
N/P.Est-ce que ci-dessous Afonctionnepour vous?N/P. Does below A work for you?
- 0
- 2011-12-09
- kaiser
-
7 réponses
- votes
-
- 2011-12-10
Lameilleure chose àfaireiciest d'utiliser une classe statique. Le code suivant doit êtreinstructif:
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' );
Si vousexécutez ce code àpartir d'unplugin,vous devriez remarquer que laméthode de la StaticClass ainsi que lafonction seront supprimées de 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.
-
Pointpris,maistoutes les classesne peuventpas être simplement convertiesen statiques.Point taken, but not all classes can simply be converted to be static.
- 8
- 2012-02-29
- Geert
-
J'ai accepté cette réponseparce qu'elle répond leplus directement à la question,bien que la réponse d'Otto soit lameilleurepratique.Jenoteici queje nepensepas que vous ayezbesoin de déclarerexplicitement statique.C'estmonexpérience (bien queje puisseme tromper) que vouspouvez simplementtraiter lafonction comme s'il s'agissait d'untableau statique ('MyClass','member_function')et celafonctionne souvent sans lemot clé '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
-
@TomAugernon vousne pouvezpas,SEULEMENT s'ilest ajoutéen tant que classe statiquepouvez-vous utiliser lafonction `remove_action`,sinon celane fonctionnerapas ... c'estpourquoij'ai dû écriremaproprefonction àgérer quand cen'estpas une classe statique.Cette réponsene serait lameilleure que si votre question concernait votrepropre code,sinon vousessaierez de supprimer un autrefiltre/action de labase de code de quelqu'un d'autreet nepourrezpas le changeren statique@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
Chaquefois qu'unplugin crée un
new MyClass();
,il doit l'affecter à une variable dont lenomest unique. De cettefaçon,l'instance de la classeest accessible.Donc,s'ilfaisait
$myclass = new MyClass();
,alors vouspourriezfaire ceci:global $myclass; remove_action( 'wp_footer', array( $myclass, 'my_action' ) );
Celafonctionneparce que lesplugins sontinclus dans l'espace denomsglobal,donc les déclarations de variablesimplicites dans le corpsprincipal d'unplugin sont des variablesglobales.
Si lepluginne sauvegardepas l'identifiant de lanouvelle classe quelquepart ,alorstechniquement,c'est unbug. L'un desprincipesgénéraux de laprogrammation orientée objetest que les objets quine sontpas référencéspar une variable quelquepart sont sujets aunettoyage ou à l'élimination.
Maintenant,PHPen particulierne faitpas cela comme Java leferait,car PHPesten quelque sorte uneimplémentation de POO àmoitié arsée. Les variables d'instancene sont que des chaînes contenant desnoms d'objets uniques,en quelque sorte. Ilsfonctionnent uniquement à cause de lafaçon dont l'interaction dunom de lafonction variablefonctionne avec l'opérateur
->
. Donc,simplementfairenew class()
peuten effetfonctionnerparfaitement,simplement stupidement. :)Donc,en fin de compte,ne faitesjamais
new class();
. Faites$var = new class();
et rendez ce $ var accessible d'une certainemanièrepour que d'autresbits le référencent.Modifier: des annéesplustard
Une chose quej'ai vufairebeaucoup depluginsest d'utiliser quelque chose de similaire aumodèle "Singleton". Ils créent uneméthodegetInstance ()pour obtenir l'instance unique de la classe. C'estprobablement lameilleure solution quej'ai vue. Exemple deplugin:
class ExamplePlugin { protected static $instance = NULL; public static function getInstance() { NULL === self::$instance and self::$instance = new self; return self::$instance; } }
Lapremièrefois quegetInstance ()est appelée,elleinstancie la classeet enregistre sonpointeur. Vouspouvez l'utiliserpour accrocher des actions.
Unproblème avec ceciest que vousne pouvezpas utilisergetInstance () dans le constructeur si vous utilisez unetelle chose. C'estparce que lenouveau appelle le constructeur avant de définir l'instance $,donc appelergetInstance () depuis le constructeur conduit à uneboucleinfinie et cassetout.
Une solution de contournementest dene pas utiliser le constructeur (ou,dumoins,dene pas utilisergetInstance () à l'intérieur),mais d'avoirexplicitement unefonction "init" dans la classepour configurer vos actionset autres. Comme ceci:
public static function init() { add_action( 'wp_footer', array( ExamplePlugin::getInstance(), 'my_action' ) ); }
Avec quelque chose comme ça,à lafin dufichier,après que la classe a étéentièrement définieet ainsi de suite,instancier leplugin devient aussi simple que ceci:
ExamplePlugin::init();
Init commence à ajouter vos actions,et cefaisant,il appellegetInstance (),quiinstancie la classeet s'assure qu'une seule d'entreellesexiste. Si vousn'avezpas defonctioninit,vous leferiezpourinstancierinitialement la classe:
ExamplePlugin::getInstance();
Pour répondre à la question d'origine,supprimer ce crochet d'action de l'extérieur (c'est-à-dire dans un autreplugin)peut alors êtrefait comme ceci:
remove_action( 'wp_footer', array( ExamplePlugin::getInstance(), 'my_action' ) );
Mettez cela dans quelque chose accroché au hook d'action
plugins_loaded
et cela annulera l'action accrochéepar leplugin d'origine.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.C'est clairement unemeilleurepratique.Nous devrionstousnousefforcer d'écrire le code denotreplugin de cettefaçon.+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 cesinstructionsm'ont vraiment aidé à supprimer unfiltre dans une classe demotif singleton.+1 these instructions really helped me to remove a filter in a singleton pattern class.
- 3
- 2014-03-28
- Devin Walker
-
+1,maisje pense que vous devriezgénéralement vous connecter à `wp_loaded`,pas à`plugins_loaded`,quipeut être appelétroptôt.+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
-
Non,`plugins_loaded` serait lebonendroit.L'action `wp_loaded` seproduit après l'action`init`,donc si votreplugineffectue des actions sur `init` (et laplupart lefont),alors vous voulezinitialiser lepluginet le configurer avant cela.Le hook `plugins_loaded`est lebonendroitpour cettephase de construction.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
-
Celapourrait être unpeutardpour répondre.Maismercipour cette contribution.Après avoir cherchépendant des heures,nous avons découvert quenousne respectionspas lesprincipesgénéraux de laprogrammation orientée objet,qui dit que les objets quine sontpas référencéspar une variable quelquepart sont sujets aunettoyage ou à l'élimination.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
2petitesfonctions PHPpourpermettre la suppression dufiltre/action avec la classe "anonyme": 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/
-
Fonctionstrès cool.Merci deposter çaici!Very cool functions. Thanks for posting that here!
- 0
- 2012-11-06
- Tom Auger
-
Commementionné dansmon article ci-dessous,ceux-ci vont casser dans WordPress 4.7 (àmoins que le dépôtne soitmis àjour,maispas dans 2 ans)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
-
Il suffit denoter que le repo wp-filters-extras abien étémis àjourpour la v4.7et 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
Les solutions ci-dessus semblent obsolètes,ont dû écrire lesmiennes ...
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
Dans detels cas,Wordpress ajoute un hachage (identifiant unique) aunom de lafonctionet le stocke dans la variableglobale
$wp_filter
. Donc,si vous utilisez lafonctionremove_filter
,rienne sepassera. Même si vous ajoutez lenom de la classe aunom de lafonction commeremove_filter('plugins_loaded', ['MyClass', 'my_action'])
. Tout ce que vouspouvezest de supprimermanuellementtous les hooksmy_action
de la variableglobale$wp_filter
.Voici lafonctionpourfaire ceci:
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 ); } }
utilisez-le comme:
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
Cettefonctionbasée sur la réponse @Digerkam. Ajout de comparer si
$def['function'][0]
est une chaîneet cela afinalementfonctionnépourmoi.Utiliser également
$wp_filter[$tag]->remove_filter()
devrait le rendreplus 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; }
Exemple d'utilisation:
Correspondanceexacte
add_action('plugins_loaded', function() { remove_class_action('plugins_loaded', 'MyClass', 'my_action', 0); });
Toutepriorité
add_action('plugins_loaded', function() { remove_class_action('plugins_loaded', 'MyClass', 'my_action'); });
Toute classeet toutepriorité
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
Ilne s’agitpas d’une réponsegénérique,mais spécifique à Thème Avadaet WooCommerce ,queje pense que d'autrespersonnespourraienttrouver utiles:
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' );
Dans une situation où unplugin aencapsulé sesméthodes dans une classepuisenregistré unfiltre ou une action contre l'une de cesméthodes,comment supprimer l'action ou lefiltre si vousn'avezplus accès à l'instance de cette classe?
Parexemple,supposons que vous ayez unplugin quifait ceci:
Étant donné queje n'aiplus aucunmoyen d'accéder à l'instance,comment désinscrire la classe?Ceci:
remove_action( "plugins_loaded", array( MyClass, 'my_action' ) );
ne semblepas être labonne approche - dumoins,ne semblepasfonctionner dansmon cas.