অপসারণ_অ্যাকশন বা অপসারণ_ফিল্টার বাহ্যিক ক্লাসের সাথে?


59

এমন পরিস্থিতিতে যেখানে কোনও প্লাগইন তার পদ্ধতিগুলি একটি শ্রেণীর মধ্যেই আবদ্ধ করে ফেলেছে এবং তারপরে সেগুলির একটির বিরুদ্ধে একটি ফিল্টার বা ক্রিয়াকলাপ নিবন্ধিত করেছে, আপনি যদি সেই শ্রেণীর উদাহরণটিতে অ্যাক্সেস না পান তবে আপনি কীভাবে ক্রিয়া বা ফিল্টারটি সরিয়ে ফেলবেন?

উদাহরণস্বরূপ, ধরুন আপনার কাছে এমন একটি প্লাগইন রয়েছে যা এটি করে:

class MyClass {
    function __construct() {
       add_action( "plugins_loaded", array( $this, 'my_action' ) );
    }

    function my_action() {
       // do stuff...
    }
}

new MyClass();

আমার কাছে এখন উদাহরণটি অ্যাক্সেস করার কোনও উপায় নেই তা উল্লেখ করে, আমি কীভাবে ক্লাসটি নিবন্ধভুক্ত করব? এটি: remove_action( "plugins_loaded", array( MyClass, 'my_action' ) );সঠিক পদ্ধতির মতো বলে মনে হচ্ছে না - কমপক্ষে, আমার ক্ষেত্রে এটি কাজ করবে বলে মনে হচ্ছে না।


এন / পি। নীচে একটি কাজ কি আপনার জন্য?
কায়সার 21

উত্তর:


16

এখানে করার সবচেয়ে ভাল কাজটি হল একটি স্ট্যাটিক ক্লাস ব্যবহার করা। নিম্নলিখিত কোডটি নির্দেশমূলক হওয়া উচিত:

class MyClass {
    function __construct() {
        add_action( 'wp_footer', array( $this, 'my_action' ) );
    }
    function my_action() {
        print '<h1>' . __class__ . ' - ' . __function__ . '</h1>';
    }
}
new MyClass();


class MyStaticClass {
    public static function init() {
        add_action( 'wp_footer', array( __class__, 'my_action' ) );
    }
    public static function my_action() {
        print '<h1>' . __class__ . ' - ' . __function__ . '</h1>';
    }
}
MyStaticClass::init();

function my_wp_footer() {
    print '<h1>my_wp_footer()</h1>';
}
add_action( 'wp_footer', 'my_wp_footer' );

function mfields_test_remove_actions() {
    remove_action( 'wp_footer', 'my_wp_footer' );
    remove_action( 'wp_footer', array( 'MyClass', 'my_action' ), 10 );
    remove_action( 'wp_footer', array( 'MyStaticClass', 'my_action' ), 10 );
}
add_action( 'wp_head', 'mfields_test_remove_actions' );

আপনি যদি এই কোডটি একটি প্লাগইন থেকে চালনা করেন তবে আপনার লক্ষ্য করা উচিত যে স্ট্যাটিক ক্লাসের পদ্ধতি পাশাপাশি ফাংশনটি wp_footer থেকে সরানো হবে।


7
পয়েন্ট নেওয়া হয়েছে, তবে সমস্ত শ্রেণিকে কেবল স্থিতিশীল রূপান্তর করা যায় না।
Geert

আমি এই উত্তরটি গ্রহণ করেছি কারণ এটি প্রশ্নের সরাসরি উত্তর দেয়, যদিও অট্টোর প্রতিক্রিয়া সেরা অনুশীলন। আমি এখানে নোট করেছি যে আপনার স্পষ্টতই স্থির ঘোষণা করার দরকার নেই বলে আমার মনে হয় না। এটি আমার অভিজ্ঞতা হয়েছে (যদিও আমি ভুল হতে পারি) আপনি কেবল ফাংশনটি এমনভাবে আচরণ করতে পারেন যেমন এটি স্থির অ্যারে ('মাইক্লাস', 'মেম্বার ফাংশন') এবং এটি প্রায়শই 'স্ট্যাটিক' কীওয়ার্ড ছাড়াই কাজ করে।
টম অ্যাগার

@ টমএগার আপনি পারবেন না, কেবলমাত্র এটি স্ট্যাটিক ক্লাস হিসাবে যুক্ত করা হলে আপনি এই remove_actionফাংশনটি ব্যবহার করতে পারবেন , অন্যথায় এটি কাজ করবে না ... এ কারণেই যখন স্ট্যাটিক শ্রেণি না হয় তখন হ্যান্ডেল করার জন্য আমাকে নিজের ফাংশনটি লিখতে হয়েছিল। এই উত্তরটি কেবল তখনই সেরা হতে পারে যদি আপনার প্রশ্নটি নিজের কোড সম্পর্কিত হয়, অন্যথায় আপনি অন্য কারও কোডবেস থেকে অন্য ফিল্টার / ক্রিয়াকে সরিয়ে ফেলার চেষ্টা করছেন এবং এটিকে
স্থিতিতে

78

যখনই কোনও প্লাগইন একটি তৈরি করে new MyClass();, এটি এটি একটি অনন্যরূপযুক্ত ভেরিয়েবলের জন্য নির্ধারণ করা উচিত। এইভাবে, ক্লাসের উদাহরণটি অ্যাক্সেসযোগ্য।

সুতরাং যদি তিনি কাজ করে থাকেন $myclass = new MyClass();তবে আপনি এটি করতে পারতেন:

global $myclass;
remove_action( 'wp_footer', array( $myclass, 'my_action' ) );

এটি কাজ করে কারণ প্লাগইনগুলি বিশ্বব্যাপী নেমস্পেসের অন্তর্ভুক্ত, সুতরাং একটি প্লাগইনের মূল অংশে অন্তর্নিহিত পরিবর্তনশীল ঘোষণাগুলি হ'ল বৈশ্বিক চলক।

প্লাগইন যদি নতুন শ্রেণীর সনাক্তকারীকে কোথাও সংরক্ষণ না করে তবে প্রযুক্তিগতভাবে, এটি একটি বাগ। অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিংয়ের সাধারণ নীতিগুলির মধ্যে একটি হ'ল যে বিষয়গুলি কোথাও কিছু পরিবর্তনশীল দ্বারা রেফারেন্স করা হচ্ছে না সেগুলি পরিষ্কার বা নির্মূলকরণের সাপেক্ষে।

এখন, বিশেষত পিএইচপি এই জাভা যেমন করে না, কারণ পিএইচপি অর্ধ-আর্সড ওওপি বাস্তবায়নকে সাজিয়ে তোলে। উদাহরণস্বরূপ ভেরিয়েবলগুলি কেবলমাত্র স্ট্রিংগুলির মধ্যে স্বতন্ত্র অবজেক্টের নাম, সাজানোর মতো জিনিস। ->অপারেটরটির সাথে ভেরিয়েবল ফাংশন নামের ইন্টারঅ্যাকশন যেভাবে কাজ করে সে কারণে তারা কেবল কাজ করে । সুতরাং ঠিক করা new class()সত্যিই নিখুঁতভাবে কাজ করতে পারে, কেবল বোকাভাবে। :)

সুতরাং, নীচের লাইন, কখনও না new class();। কি $var = new class();এবং যে $ Var অন্যান্য বিট এটা উল্লেখ করার জন্য কিছু উপায় অ্যাক্সেসযোগ্য করে।

সম্পাদনা করুন: বছর পরে

একটি জিনিস যা আমি প্রচুর প্লাগইনগুলি দেখেছি তা হ'ল "সিঙ্গেলটন" প্যাটার্নের অনুরূপ কিছু ব্যবহার করা। তারা ক্লাসের একক উদাহরণ পেতে একটি getInstance () পদ্ধতি তৈরি করে। এটি সম্ভবত আমি দেখেছি সেরা সমাধান। উদাহরণ প্লাগইন:

class ExamplePlugin
{
    protected static $instance = NULL;

    public static function getInstance() {
        NULL === self::$instance and self::$instance = new self;
        return self::$instance;
    }
}

প্রথমবার getInstance () বলা হয়, এটি ক্লাসটি ইনস্ট্যান্ট করে এবং এর পয়েন্টারটি সংরক্ষণ করে। আপনি এটিকে কাজে ব্যবহার করতে পারেন।

এর সাথে একটি সমস্যা হ'ল আপনি যদি এই জাতীয় জিনিস ব্যবহার করেন তবে আপনি কনস্ট্রাক্টরের অভ্যন্তরে getInstance () ব্যবহার করতে পারবেন না। এটি কারণ new উদাহরণ স্থাপনের আগে নতুন কনস্ট্রাক্টরকে কল করে, সুতরাং কনস্ট্রাক্টরের কাছ থেকে getInstance () কল করা একটি অসীম লুপের দিকে নিয়ে যায় এবং সমস্ত কিছু ভেঙে দেয়।

একটি কাজ হ'ল কনস্ট্রাক্টর ব্যবহার না করা (বা কমপক্ষে, এর মধ্যে getInstance () ব্যবহার না করা), তবে ক্লাসে স্পষ্টভাবে একটি "init" ফাংশন আপনার ক্রিয়াকলাপ এবং এই জাতীয় সেট আপ করার জন্য। এটার মত:

public static function init() {
    add_action( 'wp_footer', array( ExamplePlugin::getInstance(), 'my_action' ) );
}

এই জাতীয় কিছু দিয়ে, ফাইলের শেষে, ক্লাসটি সমস্ত সংজ্ঞায়িত করার পরে এবং এর পরে, প্লাগইন ইনস্ট্যান্ট করা এত সহজ হয়ে যায়:

ExamplePlugin::init();

ইনিশ আপনার ক্রিয়াগুলি যুক্ত করা শুরু করে এবং এর ফলে এটি getInstance () বলে। আপনার যদি দীক্ষা ফাংশন না থাকে তবে ক্লাসটি শুরুতে ইনস্ট্যান্ট করার পরিবর্তে আপনি এটি করবেন:

ExamplePlugin::getInstance();

মূল প্রশ্নের সমাধানের জন্য, বাইরে থেকে ক্রিয়া হুক অপসারণ (ওরফে, অন্য প্লাগইনে) এর পরে এটি করা যেতে পারে:

remove_action( 'wp_footer', array( ExamplePlugin::getInstance(), 'my_action' ) );

plugins_loadedঅ্যাকশন হুককে এমন কিছু দিয়ে দিন যা মূল প্লাগইন দ্বারা ক্রমটিকে পূর্বাবস্থায় ফিরিয়ে আনবে।


3
+1 ট্রু ডাট এটি স্পষ্টতই একটি সেরা অনুশীলন। আমাদের সবার উচিত আমাদের প্লাগইন কোডটি সেভাবে লেখার চেষ্টা করা উচিত।
টম অ্যাগার

3
+1 এই নির্দেশাবলী সত্যই আমাকে সিঙ্গলটন প্যাটার্ন শ্রেণিতে ফিল্টার সরাতে সহায়তা করেছে।
ডেভিন ওয়াকার

+1, তবে আমি মনে করি আপনার সাধারণত সাধারণত আঁকানো উচিত wp_loaded, না plugins_loaded, যা খুব তাড়াতাড়ি বলা যেতে পারে।
EML

4
না, plugins_loadedসঠিক জায়গা হবে। wp_loadedকর্ম পরে কি initকর্ম, তাই আপনার প্লাগইন কোনো ক্রিয়া লাগে যদি init(এবং সবচেয়ে না), তাহলে আপনি প্লাগিন আরম্ভ এবং যে সামনে এটি সেট আপ করতে চান। plugins_loadedহুক যা নির্মাণ ফেজ জন্য সঠিক জায়গা।
অটো

13

"বেনামে" শ্রেণীর সাথে ফিল্টার / অ্যাকশন সরিয়ে দেওয়ার জন্য 2 টি ছোট পিএইচপি ফাংশন: https://github.com/herewithme/wp-filters-extras/


খুব দুর্দান্ত ফাংশন। এখানে পোস্ট করার জন্য ধন্যবাদ!
টম অগার

যেমনটি নীচে আমার পোস্টে অন্যদের হিসাবে উল্লেখ করা হয়েছে, এগুলি ওয়ার্ডপ্রেস ৪.7 এ
বিভক্ত

1
কেবলমাত্র লক্ষণীয় যে ডাব্লুপি-ফিল্টারগুলি-এক্সট্রা রেপো সত্যই v4.7 এবং ডাব্লুপিহুক শ্রেণীর জন্য আপডেট করা হয়েছে।
ডেভ রোমসে

13

ফিল্টারগুলি অপসারণের জন্য আমি তৈরি করা এখানে একটি বিস্তৃত নথিযুক্ত ফাংশন রয়েছে যখন আপনার ক্লাস অবজেক্টে অ্যাক্সেস নেই (ওয়ার্ডপ্রেস 1.2+ এর সাথে কাজ করে, 4.7+ সহ):

https://gist.github.com/tripflex/c6518efc1753cf2392559866b4bd1a53

/**
 * Remove Class Filter Without Access to Class Object
 *
 * In order to use the core WordPress remove_filter() on a filter added with the callback
 * to a class, you either have to have access to that class object, or it has to be a call
 * to a static method.  This method allows you to remove filters with a callback to a class
 * you don't have access to.
 *
 * Works with WordPress 1.2+ (4.7+ support added 9-19-2016)
 * Updated 2-27-2017 to use internal WordPress removal for 4.7+ (to prevent PHP warnings output)
 *
 * @param string $tag         Filter to remove
 * @param string $class_name  Class name for the filter's callback
 * @param string $method_name Method name for the filter's callback
 * @param int    $priority    Priority of the filter (default 10)
 *
 * @return bool Whether the function is removed.
 */
function remove_class_filter( $tag, $class_name = '', $method_name = '', $priority = 10 ) {
    global $wp_filter;

    // Check that filter actually exists first
    if ( ! isset( $wp_filter[ $tag ] ) ) return FALSE;

    /**
     * If filter config is an object, means we're using WordPress 4.7+ and the config is no longer
     * a simple array, rather it is an object that implements the ArrayAccess interface.
     *
     * To be backwards compatible, we set $callbacks equal to the correct array as a reference (so $wp_filter is updated)
     *
     * @see https://make.wordpress.org/core/2016/09/08/wp_hook-next-generation-actions-and-filters/
     */
    if ( is_object( $wp_filter[ $tag ] ) && isset( $wp_filter[ $tag ]->callbacks ) ) {
        // Create $fob object from filter tag, to use below
        $fob = $wp_filter[ $tag ];
        $callbacks = &$wp_filter[ $tag ]->callbacks;
    } else {
        $callbacks = &$wp_filter[ $tag ];
    }

    // Exit if there aren't any callbacks for specified priority
    if ( ! isset( $callbacks[ $priority ] ) || empty( $callbacks[ $priority ] ) ) return FALSE;

    // Loop through each filter for the specified priority, looking for our class & method
    foreach( (array) $callbacks[ $priority ] as $filter_id => $filter ) {

        // Filter should always be an array - array( $this, 'method' ), if not goto next
        if ( ! isset( $filter[ 'function' ] ) || ! is_array( $filter[ 'function' ] ) ) continue;

        // If first value in array is not an object, it can't be a class
        if ( ! is_object( $filter[ 'function' ][ 0 ] ) ) continue;

        // Method doesn't match the one we're looking for, goto next
        if ( $filter[ 'function' ][ 1 ] !== $method_name ) continue;

        // Method matched, now let's check the Class
        if ( get_class( $filter[ 'function' ][ 0 ] ) === $class_name ) {

            // WordPress 4.7+ use core remove_filter() since we found the class object
            if( isset( $fob ) ){
                // Handles removing filter, reseting callback priority keys mid-iteration, etc.
                $fob->remove_filter( $tag, $filter['function'], $priority );

            } else {
                // Use legacy removal process (pre 4.7)
                unset( $callbacks[ $priority ][ $filter_id ] );
                // and if it was the only filter in that priority, unset that priority
                if ( empty( $callbacks[ $priority ] ) ) {
                    unset( $callbacks[ $priority ] );
                }
                // and if the only filter for that tag, set the tag to an empty array
                if ( empty( $callbacks ) ) {
                    $callbacks = array();
                }
                // Remove this filter from merged_filters, which specifies if filters have been sorted
                unset( $GLOBALS['merged_filters'][ $tag ] );
            }

            return TRUE;
        }
    }

    return FALSE;
}

/**
 * Remove Class Action Without Access to Class Object
 *
 * In order to use the core WordPress remove_action() on an action added with the callback
 * to a class, you either have to have access to that class object, or it has to be a call
 * to a static method.  This method allows you to remove actions with a callback to a class
 * you don't have access to.
 *
 * Works with WordPress 1.2+ (4.7+ support added 9-19-2016)
 *
 * @param string $tag         Action to remove
 * @param string $class_name  Class name for the action's callback
 * @param string $method_name Method name for the action's callback
 * @param int    $priority    Priority of the action (default 10)
 *
 * @return bool               Whether the function is removed.
 */
function remove_class_action( $tag, $class_name = '', $method_name = '', $priority = 10 ) {
    remove_class_filter( $tag, $class_name, $method_name, $priority );
}

2
প্রশ্ন - আপনি এটি 4.7 এ পরীক্ষা করেছেন? কলব্যাকগুলি যে নতুন ফিল্টারগুলিতে নিবন্ধিত হয়েছে তাতে কিছু পরিবর্তন হয়েছে। আমি আপনার কোডটি গভীরতার সাথে দেখিনি
টম

হ্যাঁ, এটি নিশ্চিত হয়ে যায় যে এটি 4.7 এ ভাঙ্গবে
গাজাজাজেপ

আহা! না, আমি ধন্যবাদ
জানাইনি

1
@ টমএগার প্রধানদের জন্য ধন্যবাদ! আমি ফাংশনটি আপডেট করেছি, ওয়ার্ডপ্রেস 4.7+ এ কাজ করার পরীক্ষা করেছি (পিছনের সামঞ্জস্যের সাথে এখনও বজায় রয়েছে)
এসমাইলস

1
মূল অভ্যন্তরীণ অপসারণের পদ্ধতিটি (মধ্য-পুনরাবৃত্তি হ্যান্ডেল করতে এবং পিএইচপি সতর্কতা প্রতিরোধ করতে) ব্যবহার করার জন্য
সবেমাত্র এটি আপডেট করেছেন

2

উপরের সমাধানগুলি পুরানো মত দেখতে, আমার নিজের লিখতে হয়েছিল ...

function remove_class_action ($action,$class,$method) {
    global $wp_filter ;
    if (isset($wp_filter[$action])) {
        $len = strlen($method) ;
        foreach ($wp_filter[$action] as $pri => $actions) {
            foreach ($actions as $name => $def) {
                if (substr($name,-$len) == $method) {
                    if (is_array($def['function'])) {
                        if (get_class($def['function'][0]) == $class) {
                            if (is_object($wp_filter[$action]) && isset($wp_filter[$action]->callbacks)) {
                                unset($wp_filter[$action]->callbacks[$pri][$name]) ;
                            } else {
                                unset($wp_filter[$action][$pri][$name]) ;
                            }
                        }
                    }
                }
            }
        }
    }
}

0

@ ডিগারকাম উত্তরের উপর ভিত্তি করে এই ফাংশন। $def['function'][0]স্ট্রিং থাকলে তুলনা যোগ করা হয়েছে এবং শেষ পর্যন্ত এটি আমার জন্য কাজ করেছে।

এছাড়াও ব্যবহার $wp_filter[$tag]->remove_filter()করা এটি আরও স্থিতিশীল করে তোলে।

function remove_class_action($tag, $class = '', $method, $priority = null) : bool {
    global $wp_filter;
    if (isset($wp_filter[$tag])) {
        $len = strlen($method);

        foreach($wp_filter[$tag] as $_priority => $actions) {

            if ($actions) {
                foreach($actions as $function_key => $data) {

                    if ($data) {
                        if (substr($function_key, -$len) == $method) {

                            if ($class !== '') {
                                $_class = '';
                                if (is_string($data['function'][0])) {
                                    $_class = $data['function'][0];
                                }
                                elseif (is_object($data['function'][0])) {
                                    $_class = get_class($data['function'][0]);
                                }
                                else {
                                    return false;
                                }

                                if ($_class !== '' && $_class == $class) {
                                    if (is_numeric($priority)) {
                                        if ($_priority == $priority) {
                                            //if (isset( $wp_filter->callbacks[$_priority][$function_key])) {}
                                            return $wp_filter[$tag]->remove_filter($tag, $function_key, $_priority);
                                        }
                                    }
                                    else {
                                        return $wp_filter[$tag]->remove_filter($tag, $function_key, $_priority);
                                    }
                                }
                            }
                            else {
                                if (is_numeric($priority)) {
                                    if ($_priority == $priority) {
                                        return $wp_filter[$tag]->remove_filter($tag, $function_key, $_priority);
                                    }
                                }
                                else {
                                    return $wp_filter[$tag]->remove_filter($tag, $function_key, $_priority);
                                }
                            }

                        }
                    }
                }
            }
        }

    }

    return false;
}

ব্যবহারের উদাহরণ:

খাপে খাপ

add_action('plugins_loaded', function() {
    remove_class_action('plugins_loaded', 'MyClass', 'my_action', 0);
});

কোন অগ্রাধিকার

add_action('plugins_loaded', function() {
    remove_class_action('plugins_loaded', 'MyClass', 'my_action');
});

যে কোনও ক্লাস এবং যে কোনও অগ্রাধিকার

add_action('plugins_loaded', function() {
    remove_class_action('plugins_loaded', '', 'my_action');
});

0

এটি জেনেরিক উত্তর নয়, তবে আভাডা থিম এবং ডাব্লুকমার্সের জন্য নির্দিষ্ট একটি , যা আমার ধারণা অন্যান্য লোকেরা সহায়ক হতে পারে:

function remove_woo_commerce_hooks() {
    global $avada_woocommerce;
    remove_action( 'woocommerce_single_product_summary', array( $avada_woocommerce, 'add_product_border' ), 19 );
}
add_action( 'after_setup_theme', 'remove_woo_commerce_hooks' );
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.