Dans une situation où un plugin a encapsulé ses méthodes dans une classe, puis enregistré un filtre ou une action contre l'une de ces méthodes, comment supprimer l'action ou le filtre si vous n'avez plus accès à l'instance de cette classe?
Par exemple, supposons que vous ayez un plugin qui fait ceci:
class MyClass {
function __construct() {
add_action( "plugins_loaded", array( $this, 'my_action' ) );
}
function my_action() {
// do stuff...
}
}
new MyClass();
Notant que je n'ai maintenant aucun moyen d'accéder à l'instance, comment puis-je annuler l'enregistrement de la classe? Cela: remove_action( "plugins_loaded", array( MyClass, 'my_action' ) );
ne semble pas être la bonne approche - du moins, cela ne semblait pas fonctionner dans mon cas.
Réponses:
La meilleure chose à faire ici est d'utiliser une classe statique. Le code suivant devrait être instructif:
Si vous exécutez ce code à partir d'un plugin, vous remarquerez que la méthode de StaticClass ainsi que la fonction seront supprimées de wp_footer.
la source
remove_action
fonction, sinon cela ne fonctionnera pas ... c'est pourquoi j'ai dû écrire ma propre fonction pour qu'elle puisse gérer quand ce n'est pas une classe statique. Cette réponse ne serait la meilleure si votre question concernait votre propre code, sinon vous essayez de supprimer un autre filtre / action de la base de code de quelqu'un d'autre et vous ne pouvez pas le changer en statiqueChaque fois qu'un plugin crée un
new MyClass();
, il doit l'affecter à une variable portant un nom unique. De cette façon, l'instance de la classe est accessible.Donc, s'il le faisait
$myclass = new MyClass();
, vous pourriez faire ceci:Cela fonctionne car les plugins sont inclus dans l'espace de noms global. Par conséquent, les déclarations de variables implicites dans le corps principal d'un plugin sont des variables globales.
Si le plugin n'enregistre pas l'identifiant de la nouvelle classe quelque part , techniquement, c'est un bug. L'un des principes généraux de la programmation orientée objet est que les objets qui ne sont pas référencés par une variable quelque part sont sujets à nettoyage ou à élimination.
Maintenant, PHP en particulier ne fait pas cela comme le ferait Java, parce que PHP est en quelque sorte une implémentation POO à demi-arsée. Les variables d'instance sont juste des chaînes avec des noms d'objet uniques, en quelque sorte. Ils fonctionnent uniquement en raison de la manière dont l'interaction du nom de la fonction variable fonctionne avec l'
->
opérateur. Donc, fairenew class()
peut parfaitement fonctionner, simplement bêtement. :)Donc, en bout de ligne, ne faites jamais
new class();
. Faites$var = new class();
et rendez ce $ var accessible d'une certaine manière pour que d'autres bits le référencent.Edit: ans plus tard
Une chose que j'ai vu beaucoup de plugins est d'utiliser quelque chose de similaire au motif "Singleton". Ils créent une méthode getInstance () pour obtenir l'instance unique de la classe. C'est probablement la meilleure solution que j'ai vue. Exemple de plugin:
La première fois que getInstance () est appelé, il instancie la classe et enregistre son pointeur. Vous pouvez l'utiliser pour accrocher des actions.
Un problème avec ceci est que vous ne pouvez pas utiliser getInstance () dans le constructeur si vous utilisez une telle chose. En effet, new appelle le constructeur avant de définir l'instance $. L'appel de getInstance () à partir du constructeur conduit donc à une boucle infinie et interrompt tout.
Une solution de contournement consiste à ne pas utiliser le constructeur (ou, du moins, à ne pas utiliser getInstance () dans celui-ci), mais à avoir explicitement une fonction "init" dans la classe pour configurer vos actions, etc. Comme ça:
Avec quelque chose comme ceci, à la fin du fichier, une fois que la classe a été définie et telle, instancier le plugin devient aussi simple que cela:
Init commence à ajouter vos actions et appelle ainsi getInstance (), qui instancie la classe et s'assure que seul l'un d'entre eux existe. Si vous n'avez pas de fonction init, faites ceci pour instancier initialement la classe:
Pour répondre à la question initiale, supprimer ce crochet d'action de l'extérieur (c'est-à-dire dans un autre plugin) peut alors être effectué comme suit:
Mettez cela dans quelque chose qui est accroché au
plugins_loaded
crochet d’action et cela annulera l’action accrochée par le plugin original.la source
wp_loaded
, pasplugins_loaded
, qui peut être appelé trop tôt.plugins_loaded
serait le bon endroit. L'wp_loaded
action se produit après l'init
action. Par conséquent, si votre plug-in effectue une action surinit
(et la plupart le font), vous souhaitez alors l'initialiser et le configurer avant. Leplugins_loaded
crochet est le bon endroit pour cette phase de construction.2 petites fonctions PHP permettant de supprimer les filtres / actions avec la classe "anonymous": https://github.com/herewithme/wp-filters-extras/
la source
Voici une fonction très documentée que j'ai créée pour supprimer les filtres lorsque vous n'avez pas accès à l'objet de classe (fonctionne avec WordPress 1.2+, y compris 4.7+):
https://gist.github.com/tripflex/c6518efc1753cf2392559866b4bd1a53
la source
Les solutions ci-dessus semblent obsolètes, j'ai dû écrire la mienne ...
la source
Cette fonction est basée sur la réponse @Digerkam. Ajouté compare if
$def['function'][0]
is string et ça a finalement fonctionné pour moi.Aussi utiliser
$wp_filter[$tag]->remove_filter()
devrait le rendre plus stable.Exemple d'utilisation:
Correspondance exacte
Toute priorité
Toute classe et toute priorité
la source
Ce n'est pas une réponse générique, mais une spécifique au thème Avada et à WooCommerce , que d'autres personnes pourraient trouver utile:
la source