एक गुमनाम वस्तु है कि एक फिल्टर को हटाने के लिए कैसे?


62

अपनी functions.phpफ़ाइल में मैं नीचे दिए गए फ़िल्टर को निकालना चाहूंगा, लेकिन मुझे यकीन नहीं है कि यह कैसे करना है क्योंकि यह एक कक्षा में है। कैसा remove_filter()दिखना चाहिए ?

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

यह यहां लाइन 88 पर है


आप निकाल देना चाहिए &अपने से &$this, यह एक PHP 4 बात है
टॉम जम्मू नॉवेल

जवाबों:


79

यह एक बहुत अच्छा सवाल है। यह प्लगइन एपीआई और सबसे अच्छा प्रोग्रामिंग प्रथाओं के अंधेरे दिल के लिए नीचे चला जाता है।

निम्नलिखित उत्तर के लिए मैंने कोड को पढ़ने में आसान के साथ समस्या का वर्णन करने के लिए एक सरल प्लगइन बनाया।

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

अब हम इसे देखते हैं:

यहाँ छवि विवरण दर्ज करें

वर्डप्रेस को फ़िल्टर के लिए एक नाम की आवश्यकता होती है । हमने एक प्रदान नहीं किया, इसलिए वर्डप्रेस कॉल _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

दिलचस्प। मुझे आपका उत्तर बहुत अच्छा लगता है, लेकिन आपका अंतिम निष्कर्ष काफी घटिया है। मेरी राय में, वर्ग उदाहरण सामान्य रूप से, वर्डप्रेस प्लगइन को लोड करने के तुरंत बाद होना चाहिए। फिर, वर्ग उदाहरण के निर्माता को कोई वास्तविक क्रिया नहीं करनी चाहिए, बस क्रिया और फ़िल्टर जोड़ें। इस तरह, प्लगइन्स जो आपके वर्ग उदाहरण से क्रियाओं और फ़िल्टर को हटाने की इच्छा रखते हैं, वे यह सुनिश्चित कर सकते हैं कि उन्हें वास्तव में जोड़ा plugins_loadedजाता है जब कहा जाता है, जो वास्तव plugins_loadedमें है। बेशक, वर्ग उदाहरण अभी भी सुलभ होने की जरूरत है, संभवतः सिंगलटन पैटर्न के माध्यम से।
Engelen

@engelen यह एक पुराना जवाब है। आजकल मैं कॉलबैक को हटाने के लिए एक कार्रवाई की पेशकश करूंगा। लेकिन एक सिंगलटन नहीं, यह कई कारणों से एक विरोधी पैटर्न है।
FUXIA

यह उत्तर क्रियाओं को हटाने के लिए भी काम करता है, जैसेremove_action()
निक पिएट

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 (!) में आवश्यक था और यह लंबे समय से अतिदेय है। यह आपके हुक समस्याग्रस्त से निपटने को प्रस्तुत कर सकता है, इसलिए बस इसे रास्ते से बाहर छोड़ दें:

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

और बस।


1
आपके पास $thisबाहर (किसी अन्य प्लगइन / थीम) से कोई पहुंच नहीं है ।
FUXIA
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.