จะลบตัวกรองที่เป็นวัตถุที่ไม่ระบุชื่อได้อย่างไร


62

ในfunctions.phpไฟล์ของฉันฉันต้องการลบตัวกรองด้านล่าง แต่ฉันไม่แน่ใจว่าจะทำอย่างไรเนื่องจากอยู่ในชั้นเรียน สิ่งที่ควรremove_filter()มีลักษณะอย่างไร

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

มันอยู่ในสาย 88 ที่นี่


คุณควรลบออก&จากของคุณ&$thisมันเป็นสิ่ง PHP 4
Tom J Nowell

คำตอบ:


79

นั่นเป็นคำถามที่ดีมาก มันลงไปที่หัวใจอันมืดมิดของปลั๊กอิน API และวิธีปฏิบัติในการเขียนโปรแกรมที่ดีที่สุด

สำหรับคำตอบต่อไปนี้ฉันสร้างปลั๊กอินง่าย ๆ เพื่อแสดงปัญหาพร้อมรหัสที่อ่านง่าย

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

ตอนนี้เราเห็นสิ่งนี้:

ป้อนคำอธิบายรูปภาพที่นี่

WordPress ต้องการชื่อสำหรับตัวกรอง เราไม่ได้ให้บริการหนึ่งดังนั้นจึงเรียก WordPress _wp_filter_build_unique_id()และสร้างหนึ่ง spl_object_hash()ชื่อนี้คือไม่สามารถคาดเดาเพราะมันใช้

ถ้าเราวิ่งvar_export()ต่อไป$GLOBALS['wp_filter'][ 'wp_footer' ]เราจะได้อะไรแบบนี้:

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

ในการค้นหาและลบการกระทำที่ชั่วร้ายของเราเราต้องผ่านตัวกรองที่เกี่ยวข้องสำหรับเบ็ด (การกระทำเป็นเพียงตัวกรองที่ง่ายมาก) ตรวจสอบว่ามันเป็นอาร์เรย์และถ้าวัตถุเป็นตัวอย่างของชั้นเรียน จากนั้นเราก็จะมีความสำคัญและลบตัวกรองไม่เคยเห็นตัวระบุจริง

เอาล่ะเรามาใส่ฟังก์ชั่น:

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

เราจะเรียกใช้ฟังก์ชันนี้เมื่อใด ไม่มีวิธีที่จะทราบได้อย่างแน่นอนเมื่อสร้างวัตถุต้นฉบับ อาจจะบางครั้งมาก่อน'plugins_loaded'หรือไม่ ไว้ก่อน?

0เราใช้เพียงตะขอเดียวกันวัตถุที่ถูกเชื่อมโยงกับและกระโดดในช่วงต้นมากที่มีความสำคัญ นั่นเป็นวิธีเดียวที่จะมั่นใจได้จริงๆ นี่คือวิธีที่เราจะลบวิธีการ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'
    );
}

ผลลัพธ์:

ป้อนคำอธิบายรูปภาพที่นี่

และควรลบการดำเนินการออกจากคำถามของคุณ (ไม่ได้ทดสอบ):

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

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

ข้อสรุป

  • เขียนโค้ดที่คาดเดาได้เสมอ ตั้งชื่อที่อ่านได้สำหรับตัวกรองและการกระทำของคุณ ทำให้ถอดตะขอออกได้ง่าย
  • 'plugins_loaded'สร้างวัตถุของคุณในการดำเนินการคาดเดาได้เช่นบน ไม่เพียงแค่เมื่อปลั๊กอินของคุณถูกเรียกโดย WordPress


@MikeSchinkel แนวคิดที่เกี่ยวข้องยังไม่ได้ลองในทางปฏิบัติ
fuxia

น่าสนใจ ฉันพบคำตอบของคุณดีมาก แต่ข้อสรุปสุดท้ายของคุณค่อนข้างแย่ ในความคิดของฉันอินสแตนซ์ของคลาสควรเป็นอินสแตนซ์ทันทีที่ WordPress โหลดปลั๊กอิน จากนั้นตัวสร้างของอินสแตนซ์ของชั้นเรียนไม่ควรทำการกระทำจริงใด ๆ เพียงเพิ่มการกระทำและตัวกรอง ด้วยวิธีนี้ปลั๊กอินที่ต้องการลบการกระทำและตัวกรองจากอินสแตนซ์ของชั้นเรียนของคุณสามารถมั่นใจได้ว่าพวกเขาจะถูกเพิ่มจริง ๆ เมื่อplugins_loadedมีการเรียกซึ่งเป็นสิ่งที่plugins_loadedมีไว้สำหรับ แน่นอนอินสแตนซ์ของคลาสยังต้องสามารถเข้าถึงได้อาจเป็นผ่านรูปแบบซิงเกิล
Engelen

@engelen นี่คือคำตอบเก่า ทุกวันนี้ฉันจะเสนอการดำเนินการเพื่อลบการเรียกกลับ แต่ไม่ใช่ซิงเกิลนั่นเป็นรูปแบบการต่อต้านด้วยเหตุผลหลายประการ
fuxia

คำตอบนี้ใช้ได้กับการลบการกระทำเช่นremove_action()
Nick Pyett

0

ฉันไม่แน่ใจ แต่คุณสามารถลองใช้ซิงเกิลตันได้
คุณต้องจัดเก็บการอ้างอิงวัตถุในคุณสมบัติคงที่ในชั้นเรียนของคุณแล้วส่งกลับตัวแปรคงที่จากวิธีการคงที่ บางสิ่งเช่นนี้

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

0

ตราบใดที่คุณรู้ว่าวัตถุ (และคุณใช้ PHP 5.2 หรือสูงกว่า - เวอร์ชั่นเสถียร PHP ปัจจุบันคือ 5.5, 5.4 ยังคงได้รับการสนับสนุน, 5.3 คือจุดสิ้นสุดของชีวิต), คุณสามารถลบออกได้ด้วยremove_filter()วิธีการ สิ่งที่คุณต้องจำคือวัตถุชื่อเมธอดและลำดับความสำคัญ (ถ้าใช้):

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

อย่างไรก็ตามคุณทำผิดเล็กน้อยในรหัสของคุณ อย่านำหน้า$thisด้วยเครื่องหมายแอมเปอร์แซนด์&ซึ่งจำเป็นใน PHP 4 (!) และเกินกำหนดเป็นเวลานาน วิธีนี้จะทำให้การจัดการกับ hooks มีปัญหาของคุณดังนั้นเพียงแค่ปล่อยให้มันออกไป:

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

และนั่นคือมัน


1
คุณไม่สามารถเข้าถึง$thisจากภายนอก (ปลั๊กอิน / ชุดรูปแบบอื่น)
fuxia
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.