web-dev-qa-db-fra.com

Supprimer une action d'une classe de plug-in, obligé d'utiliser une instance globale

J'ai essayé désespérément de trouver une solution à ce problème. Il existe des exemples de ce problème sur tout ce site (et d’autres), mais aucune des réponses n’aide dans mon cas. Si vous souhaitez ignorer l'arrière-plan et répondre à ma question, vous devez terminer à la suite des extraits de code.

Comment je suis arrivé ici: Je dois supprimer une action qui a été ajoutée par un plugin au sein d'une classe qui n'a pas été instanciée. Cela signifie qu'il n'y a pas eu d'instanciation globale comme celle-ci (exemple) dans la classe en question:

global $Class_name;
$Class_name = new This_Class;

Dans le plugin (Woocommerce Services), l'action (qui doit être supprimée) a été ajoutée comme suit:

add_action( 'woocommerce_email_after_order_table', array( $this, 'add_tracking_info_to_emails' ), 10, 3 );

J'ai vu et lu de nombreux articles sur la suppression réussie d'une action. Ils sont tous utiles en suggérant ce qui suit:

1) Assurez-vous que le timing est correct. Vous ne pouvez supprimer une action qu'après l'avoir ajoutée.

2) Vous devez supprimer l'action en utilisant la même priorité que celle dans laquelle l'action a été ajoutée.

Cependant, lorsqu'il s'agit de supprimer une action qui a été ajoutée dans une classe sans instance ... ils ont échoué. La plupart suggèrent de supprimer l'action de cette façon en transmettant le nom de la classe elle-même (dans ce cas, 'WC_Connect_Loader'):

remove_action( 'woocommerce_email_after_order_table', array( 'WC_Connect_Loader', 'add_tracking_info_to_emails' ), 10 );

Certains ont prétendu que ce qui précède fonctionnait pour eux, alors j’ai essayé et essayé de le faire pour moi sans succès. Je me suis assuré de suivre les conseils de mes recherches. 1) J'ai confirmé que j'essayais de supprimer l'action après son ajout (vérification). 2) J'ai confirmé que j'utilisais la même priorité pour supprimer l'action que lors de l'ajout, dans ce cas 10 (Vérification). J'étais perdue.

Après de nombreuses opérations de débogage et d’expérimentation, il est devenu clair que je ne pourrai pas supprimer l’action simplement en passant le nom de la classe. J'ai fini par devoir modifier le plugin lui-même (ce que je déteste) pour créer une instance globale de la classe 'WC_Connect_Loader', puis transmettre l'instance lors d'une tentative de suppression de l'action.

Pour les besoins de cet article/question, j'ai inclus la version de débogage de mon code pour montrer comment j'ai été en mesure de confirmer ce qui fonctionnait et ce qui ne fonctionnait pas. Je suis sûr qu'il existe de meilleures méthodes que wp_mail () mais ce fut la plus facile pour moi. J'ai WP m'envoie un courrier électronique me permettant de déterminer le succès ou l'échec.

Dans les deux cas ci-dessous, il n'y a que de légers changements. J'ai commenté les lignes qui sont modifiées.

Cela ne fonctionne pas:

//woocommerce-services.php:
...
public function attach_hooks() {
...
add_action( 'woocommerce_email_after_order_table', array( $this, 'add_tracking_info_to_emails' ), 10, 3 );
...
}
...
if ( ! defined( 'WC_UNIT_TESTING' ) ) {
    new WC_Connect_Loader();
}



//functions.php
...
add_action('woocommerce_init','remove_add_tracking_info_to_emails',999);
function remove_add_tracking_info_to_emails() {
    if (remove_action('woocommerce_email_after_order_table',array('WC_Connect_Loader','add_tracking_info_to_emails'),10)){
        wp_mail('[email protected]','Successfully removed the hook','Message');
    }
    else {
        wp_mail('[email protected]','Failed to remove the hook','Message');
    }
}

Cela fonctionne:

//woocommerce-services.php
...
public function attach_hooks() {
...
add_action( 'woocommerce_email_after_order_table', array( $this, 'add_tracking_info_to_emails' ), 10, 3 );
...
}
...
if ( ! defined( 'WC_UNIT_TESTING' ) ) {
        global $WC_Connect; // created global
    $WC_Connect = new WC_Connect_Loader(); // Class 'WC_Connect_Loader' now has a global instance
}


// functions.php
...
add_action('woocommerce_init','remove_add_tracking_info_to_emails',999);
function remove_add_tracking_info_to_emails() {
    global $WC_Connect; // Global instance of class
    if (remove_action('woocommerce_email_after_order_table',array($WC_Connect,'add_tracking_info_to_emails'),10)){ // Pass in global instance here
        wp_mail('[email protected]','Successfully removed the hook','Message');
    }
    else {
        wp_mail('[email protected]','Failed to remove the hook','Message');
    }
}

Ma question: Pourquoi est-ce que je ne peux pas passer dans le nom de la classe comme beaucoup l'ont suggéré et prétendu fonctionner? Pourquoi dois-je passer dans l'instance de classe pour que cela fonctionne?

Je n'arrive pas à trouver quoi que ce soit qui m'aide à comprendre cela. J'espère obtenir l'un des deux résultats en postant cette question:

1) Quelqu'un peut expliquer cette limitation comme tout simplement inévitable et le plugin aurait dû être écrit correctement pour être extensible. J'espère que quelqu'un bénéficiera du temps que j'ai passé à travailler sur ceci et ceux qui répondent.

2) Il me manque quelque chose et je ne suis pas aussi intelligent que je le pense. Dans ce cas, je suis prêt à parier que je ne suis pas la première personne à être confrontée à ce problème et que plus que moi en bénéficiera.

2
rrwebdev

Parce que ce ne sont pas les mêmes, et signifient des choses différentes:

  • array( $this, 'method' ) = $this->method();
  • array( 'classname', 'method' ) = classname::method();

L'un appelle une méthode sur un objet, l'autre appelle une méthode statique sur une classe.

Étant donné que ce que vous essayez de libérer n'est pas une méthode statique, vous avez besoin d'une référence à l'objet. Par conséquent, votre deuxième exemple fonctionne et le premier ne fonctionne pas.

3
Tom J Nowell