it-swarm.com.de

So entfernen Sie einen Filter, der ein anonymes Objekt ist?

In meiner functions.php Datei möchte ich den folgenden Filter entfernen, aber ich bin mir nicht sicher, wie ich das machen soll, da es in einer Klasse ist. Wie sollte remove_filter() aussehen?

add_filter('comments_array',array( &$this, 'FbComments' ));

Es ist in Zeile 88 hier .

61
Jonas

Das ist eine sehr gute Frage. Es geht um das dunkle Herz der Plugin-API und die besten Programmiermethoden.

Für die folgende Antwort habe ich ein einfaches Plugin erstellt, um das Problem mit einfach zu lesendem Code zu veranschaulichen.

<?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;
}

Jetzt sehen wir Folgendes:

enter image description here

WordPress benötigt einen Namen für den Filter. Wir haben keine bereitgestellt, daher ruft WordPress _wp_filter_build_unique_id() auf und erstellt eine. Dieser Name ist nicht vorhersehbar, da er spl_object_hash() verwendet.

Wenn wir eine var_export() auf $GLOBALS['wp_filter'][ 'wp_footer' ] ausführen, erhalten wir jetzt so etwas:

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,
    ),
  ),
)

Um unsere böse Aktion zu finden und zu entfernen, müssen wir die zugehörigen Filter für den Hook durchgehen (eine Aktion ist nur ein sehr einfacher Filter), prüfen, ob es sich um ein Array handelt und ob das Objekt eine Instanz der Klasse ist. Dann nehmen wir die Priorität und entfernen den Filter ohne jemals den wirklichen Bezeichner zu sehen.

Okay, lassen Sie uns das in eine Funktion umwandeln:

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
                    );
                }
            }
        }
    }
}

Wann rufen wir diese Funktion auf? Es ist nicht sicher, wann das ursprüngliche Objekt erstellt wird. Vielleicht schon mal vor 'plugins_loaded'? Vielleicht später?

Wir verwenden genau den Haken, dem das Objekt zugeordnet ist, und springen sehr früh mit der Priorität 0 ein. Nur so können Sie wirklich sicher sein. So entfernen wir die Methode 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'
    );
}

Ergebnis:

enter image description here

Und das sollte die Aktion aus Ihrer Frage entfernen (nicht getestet):

add_action( 'comments_array', 'kill_FbComments', 0 );

function kill_FbComments()
{
    remove_anonymous_object_filter(
        'comments_array',
        'SEOFacebookComments',
        'FbComments'
    );
}

Fazit

  • Schreiben Sie immer vorhersehbaren Code. Legen Sie lesbare Namen für Ihre Filter und Aktionen fest. Haken lassen sich leicht entfernen.
  • Erstellen Sie Ihr Objekt mit einer vorhersehbaren Aktion, zum Beispiel mit 'plugins_loaded'. Nicht nur, wenn Ihr Plugin von WordPress aufgerufen wird.
79
fuxia

Solange Sie das Objekt kennen (und PHP 5.2 oder höher verwenden - aktuell stabile PHP Version 5.5, 5.4 wird weiterhin unterstützt, 5.3 ist das Ende der Lebensdauer), können Sie nur entfernen Sie es mit der Methode remove_filter(). Alles, was Sie sich merken müssen, ist das Objekt, der Methodenname und die Priorität (falls verwendet):

remove_filter('comment_array', [$this, 'FbComments']);

Sie machen jedoch einen kleinen Fehler in Ihrem Code. Stellen Sie $this nicht das kaufmännische Und & voran, das in PHP 4 (!) Benötigt wurde, und es ist seit langem überfällig. Dies kann den Umgang mit Ihren Hooks problematisch machen. Lassen Sie es einfach aus dem Weg:

add_filter('comments_array', [$this, 'FbComments]));

Und das ist es.

0
hakre

Ich bin nicht sicher, aber Sie können versuchen, einen Singleton zu verwenden.
Sie müssen die Objektreferenz in einer statischen Eigenschaft Ihrer Klasse speichern und dann diese statische Variable von einer statischen Methode zurückgeben. Etwas wie das:

class MyClass{
    private static $ref;
    function MyClass(){
        $ref = &$this;
    }
    public static function getReference(){
        return self::$ref;
    }
}
0
Hamed Momeni