问题描述

在我的 functions.php 文件中,我想删除下面的过滤器,但我不知道如何做,因为它在一个类中。 remove_filter()应该是什么样的?

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

它在线 88 here

最佳解决方案

这是一个很好的问题。它下降到插件 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()

如果我们在 $GLOBALS['wp_filter'][ 'wp_footer' ]上运行 var_export(),我们现在可以得到这样的东西:

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

Conclusion

  • 始终写可预见的代码。为您的过滤器和操作设置可读名称。使其轻松删除任何钩子。
  • 以可预测的方式创建对象,例如'plugins_loaded'。不只是当您的插件被 WordPress 调用时。

参考文献

注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。