functions.php
文件中,我想删除以下过滤器,但是由于它在一个类中,因此我不确定如何执行此操作。 remove_filter()
应该是什么样子?add_filter('comments_array',array( &$this, 'FbComments' ));
这是第88行。
#1 楼
这是一个很好的问题。它归结为插件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
2013年4月9日在3:57
@MikeSchinkel相关的想法,到目前为止还没有在实践中尝试过。
– fuxia♦
2013年4月9日4:02
有趣。我发现您的回答很好,但是您的最后结论很差。我认为,一般而言,类实例应在WordPress加载插件后立即实例化。然后,类实例的构造函数不应执行任何实际操作,而应添加操作和过滤器。这样,可以确保希望从类实例中删除操作和过滤器的插件在调用plugins_loaded时确实已添加,这正是plugins_loaded的目的。当然,仍然可以通过单例模式访问类实例。
–engelen
2014年6月20日14:20在
@engelen这是一个旧答案。现在,我将提供一个删除回调的操作。但不是Singleton,出于多种原因,这是一种反模式。
– fuxia♦
14年6月20日在17:16
此答案也适用于删除操作,例如remove_action()
–尼克·皮特(Nick Pyett)
15年1月28日在17:14
#2 楼
我不确定,但是您可以尝试使用单例。您必须将对象引用存储在类的静态属性中,然后从静态方法返回该静态变量。像这样的东西:
class MyClass{
private static $ref;
function MyClass(){
$ref = &$this;
}
public static function getReference(){
return self::$ref;
}
}
#3 楼
只要您知道对象(并且使用的是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]));
就这样。
评论
您无法从外部(另一个插件/主题)访问$ this。
– fuxia♦
13年7月28日在12:03
评论
您应该从&$ this中删除&,这是PHP 4事情