Réponses:
C'est une très bonne question. Cela va au cœur sombre de l'API du plugin et aux meilleures pratiques de programmation.
Pour la réponse suivante, j'ai créé un plugin simple pour illustrer le problème avec du code facile à lire.
<?php # -*- coding: utf-8 -*-
/* Plugin Name: Anonymous OOP Action */
if ( ! class_exists( 'Anonymous_Object' ) )
{
/**
* Add some actions with randomized global identifiers.
*/
class Anonymous_Object
{
public function __construct()
{
add_action( 'wp_footer', array ( $this, 'print_message_1' ), 5 );
add_action( 'wp_footer', array ( $this, 'print_message_2' ), 5 );
add_action( 'wp_footer', array ( $this, 'print_message_3' ), 12 );
}
public function print_message_1()
{
print '<p>Kill me!</p>';
}
public function print_message_2()
{
print '<p>Me too!</p>';
}
public function print_message_3()
{
print '<p>Aaaand me!</p>';
}
}
// Good luck finding me!
new Anonymous_Object;
}
Maintenant nous voyons ceci:
WordPress a besoin d'un nom pour le filtre. Nous n'en avons pas fourni, donc WordPress appelle _wp_filter_build_unique_id()
et en crée un. Ce nom n'est pas prévisible car il utilise spl_object_hash()
.
Si nous courons un var_export()
sur $GLOBALS['wp_filter'][ 'wp_footer' ]
nous obtenons quelque chose comme ça maintenant:
array (
5 =>
array (
'000000002296220e0000000013735e2bprint_message_1' =>
array (
'function' =>
array (
0 =>
Anonymous_Object::__set_state(array(
)),
1 => 'print_message_1',
),
'accepted_args' => 1,
),
'000000002296220e0000000013735e2bprint_message_2' =>
array (
'function' =>
array (
0 =>
Anonymous_Object::__set_state(array(
)),
1 => 'print_message_2',
),
'accepted_args' => 1,
),
),
12 =>
array (
'000000002296220e0000000013735e2bprint_message_3' =>
array (
'function' =>
array (
0 =>
Anonymous_Object::__set_state(array(
)),
1 => 'print_message_3',
),
'accepted_args' => 1,
),
),
20 =>
array (
'wp_print_footer_scripts' =>
array (
'function' => 'wp_print_footer_scripts',
'accepted_args' => 1,
),
),
1000 =>
array (
'wp_admin_bar_render' =>
array (
'function' => 'wp_admin_bar_render',
'accepted_args' => 1,
),
),
)
Pour trouver et supprimer notre action maléfique, nous devons passer en revue les filtres associés au point d'ancrage (une action est simplement un filtre très simple), vérifiez si c'est un tableau et si l'objet est une instance de la classe. Ensuite, nous prenons la priorité et retirons le filtre, sans jamais voir l'identifiant réel .
Ok, mettons cela dans une fonction:
if ( ! function_exists( 'remove_anonymous_object_filter' ) )
{
/**
* Remove an anonymous object filter.
*
* @param string $tag Hook name.
* @param string $class Class name
* @param string $method Method name
* @return void
*/
function remove_anonymous_object_filter( $tag, $class, $method )
{
$filters = $GLOBALS['wp_filter'][ $tag ];
if ( empty ( $filters ) )
{
return;
}
foreach ( $filters as $priority => $filter )
{
foreach ( $filter as $identifier => $function )
{
if ( is_array( $function)
and is_a( $function['function'][0], $class )
and $method === $function['function'][1]
)
{
remove_filter(
$tag,
array ( $function['function'][0], $method ),
$priority
);
}
}
}
}
}
Quand appelons-nous cette fonction? Il n'y a aucun moyen de savoir avec certitude quand l'objet original est créé. Peut-être parfois avant 'plugins_loaded'
? Peut-être plus tard?
Nous utilisons le même point auquel l'objet est associé et nous y allons très tôt avec priorité 0
. C'est le seul moyen d'être vraiment sûr. Voici comment nous supprimerions la méthode print_message_3()
:
add_action( 'wp_footer', 'kill_anonymous_example', 0 );
function kill_anonymous_example()
{
remove_anonymous_object_filter(
'wp_footer',
'Anonymous_Object',
'print_message_3'
);
}
Résultat:
Et cela devrait supprimer l'action de votre question (non testée):
add_action( 'comments_array', 'kill_FbComments', 0 );
function kill_FbComments()
{
remove_anonymous_object_filter(
'comments_array',
'SEOFacebookComments',
'FbComments'
);
}
'plugins_loaded'
. Pas seulement lorsque votre plugin est appelé par WordPress.plugins_loaded
appelle, ce qui est exactement ce à quoi ils servent plugins_loaded
. Bien entendu, l’instance de classe doit toujours être accessible, éventuellement via un modèle singleton.
remove_action()
Je ne suis pas sûr, mais vous pouvez utiliser un singleton.
Vous devez stocker la référence de l'objet dans une propriété statique de votre classe, puis renvoyer cette variable statique à partir d'une méthode statique. Quelque chose comme ça:
class MyClass{
private static $ref;
function MyClass(){
$ref = &$this;
}
public static function getReference(){
return self::$ref;
}
}
Tant que vous connaissez l'objet (et que vous utilisez PHP 5.2 ou une version ultérieure - la version stable actuelle de PHP est 5.5, la version 5.4 est toujours prise en charge, la version 5.3 est en fin de vie), vous pouvez simplement le supprimer à l'aide de la remove_filter()
méthode. Tout ce dont vous devez vous souvenir est l'objet, le nom de la méthode et la priorité (si utilisée):
remove_filter('comment_array', [$this, 'FbComments']);
Cependant, vous faites une petite erreur dans votre code. Ne préfixez pas $this
l'esperluette &
, cela était nécessaire en PHP 4 (!) Et il est en retard depuis longtemps. Cela peut rendre la gestion de vos hooks problématique, alors laissez-le de côté:
add_filter('comments_array', [$this, 'FbComments]));
Et c'est tout.
$this
de l'extérieur (un autre plugin / thème).
&
de votre&$this
, c'est une chose de PHP 4