删除通过匿名函数添加的操作/过滤器

时间:2014-03-12 作者:Abhik

我必须说,这是一种非常糟糕的做法。在过去的两个小时里,我们一直在寻找一个解决方案来删除通过匿名函数添加的操作和过滤器。

这是用于父主题的代码,我需要将其删除。

/**
 * Add custom columns to admin comments grid
 *  * Rate that user set.
 */
add_filter( \'manage_edit-comments_columns\', function( $default ) {
    $columns[\'smr_comment_rate\']  = __( \'Rate\', \'txtdmn\' );

    return array_slice( $default, 0, 3, true ) + $columns + array_slice( $default, 2, NULL, true );
});
得到toscho\'s answer, 玩得很重,但没有帮助。那么,是否有其他替代方案可以删除通过匿名函数添加的操作/过滤器?

谢谢

4 个回复
SO网友:gmazzap

问题是您无法区分匿名函数和其他函数,因此可以删除闭包(即匿名函数),但if more than one closure act on same filter at same priority you have to make a choice, remove them all, ore remove only one (不知道具体是哪个)。

我将展示如何使用一个从您发布的@toscho answer中高度派生的函数来删除它们:

/**
 * Remove an object filter.
 *
 * @param  string $tag                Hook name.
 * @param  string $class              Class name. Use \'Closure\' for anonymous functions.
 * @param  string|void $method        Method name. Leave empty for anonymous functions.
 * @param  string|int|void $priority  Priority
 * @return void
 */
function remove_object_filter( $tag, $class, $method = NULL, $priority = NULL ) {
  $filters = $GLOBALS[\'wp_filter\'][ $tag ];
  if ( empty ( $filters ) ) {
    return;
  }
  foreach ( $filters as $p => $filter ) {
    if ( ! is_null($priority) && ( (int) $priority !== (int) $p ) ) continue;
    $remove = FALSE;
    foreach ( $filter as $identifier => $function ) {
      $function = $function[\'function\'];
      if (
        is_array( $function )
        && (
          is_a( $function[0], $class )
          || ( is_array( $function ) && $function[0] === $class )
        )
      ) {
        $remove = ( $method && ( $method === $function[1] ) );
      } elseif ( $function instanceof Closure && $class === \'Closure\' ) {
        $remove = TRUE;
      }
      if ( $remove ) {
        unset( $GLOBALS[\'wp_filter\'][$tag][$p][$identifier] );
      }
    }
  }
}
我已重命名该函数remove_object_filter 因为它可以删除所有类型的对象过滤器:静态类方法、动态对象方法和闭包。

这个$priority 参数是可选的,但在删除闭包时应始终使用该参数,否则该函数将删除添加到过滤器中的任何闭包,无论其优先级如何,因为$priority 将删除使用目标类/方法或闭包的所有过滤器。

如何使用

// remove a static method
remove_object_filter( \'a_filter_hook\', \'AClass\', \'a_static_method\', 10 );

// remove a dynamic method
remove_object_filter( \'a_filter_hook\', \'AClass\', \'a_dynamic_method\', 10 );

// remove a closure
remove_object_filter( \'a_filter_hook\', \'Closure\', NULL, 10 );

SO网友:Shaun Cockerill

匿名筛选器和操作可以通过以下方式在本机删除:

remove_filter( $tag, function(){}, $priority )
使用生成唯一id时spl_object_hash(), 匿名函数可以相互比较,因此不需要再次重新创建完全闭包对象。

如果多个筛选器或操作连接到具有相同优先级的同一标记,则它将删除添加的最新筛选器或操作。如果需要保留一个过滤器,则必须删除所有过滤器,直到需要删除的过滤器为止,然后根据需要重新添加其他过滤器。

// Filter which was added and needs to be removed
add_filter( \'manage_edit-comments_columns\', function( $default ) {
    $columns[\'smr_comment_rate\']  = __( \'Rate\', \'txtdmn\' );

    return array_slice( $default, 0, 3, true ) + $columns + array_slice( $default, 2, NULL, true );
} );

// Removes the last anonymous filter to be added
remove_filter( \'manage_edit-comments_columns\', function(){} );
这通常会回到最佳实践。我只会将匿名函数用作我为客户机开发的自定义主题的一部分,我不希望覆盖或删除过滤器。在我开发的任何公共主题或插件中,我都会使用工厂初始化一个类,添加所有过滤器和操作,然后将实例存储为静态变量。

EDIT

remove_filter 使用匿名函数似乎不适用于最新版本的WordPress和PHP。功能_wp_filter_build_unique_id 自WordPress 5.3.0以来进行了更新,并删除了一些“spl\\u object\\u hash”解决方法,从而防止以这种方式删除过滤器。

我现在看到的删除过滤器的唯一方法是手动调整$wp_filter 全局变量。

global $wp_filter;
unset( $wp_filter[ $tag ]->callbacks[ $priority ][ $identifier ] );
// or
foreach ( $wp_filter[ $tag ]->callbacks[ $priority ] as $identifier => $callback ) {
    // Match identifier as necessary
}
// or
array_pop( $wp_filter[ $tag ]->callbacks[ $priority ] );

SO网友:tivnet

如果您添加优先级为11的过滤器,那么它会紧随其后吗?这很难看,但对你来说可能有用。

add_filter( \'manage_edit-comments_columns\', function( $default ) {
    unset( $default[\'smr_comment_rate\'] );

    return $default;
}, 11, 1 );

SO网友:Carlo

也许有人需要它:我修改了remove_object_filter 在@gmazzap answer中,要使其与WP 4.7+配合使用,请执行以下操作:

/**
 * Remove an object filter.
 *
 * @param  string $tag                Hook name.
 * @param  string $class              Class name. Use \'Closure\' for anonymous functions.
 * @param  string|void $method        Method name. Leave empty for anonymous functions.
 * @param  string|int|void $priority  Priority
 * @return void
 */
function remove_object_filter( $tag, $class, $method = NULL, $priority = NULL ) {
    global $wp_version;
    $new_wp_filter_struct = false;

    $filters = $GLOBALS[\'wp_filter\'][ $tag ];
    if ( empty ( $filters ) ) {
        return;
    }

    if (version_compare( $wp_version, \'4.7\', \'>=\' ) && isset($filters->callbacks)) { // new \'wp_filter\' structure (WP >= 4.7)
        $filters = $filters->callbacks;
        $new_wp_filter_struct = true;
    }

    foreach ( $filters as $p => $filter ) {
        if ( ! is_null($priority) && ( (int) $priority !== (int) $p ) ) continue;
        $remove = FALSE;
        foreach ( $filter as $identifier => $function ) {
            $function = $function[\'function\'];
            if (
                is_array( $function )
                && (
                    is_a( $function[0], $class )
                    || ( is_array( $function ) && $function[0] === $class )
                )
            ) {
                $remove = ( $method && ( $method === $function[1] ) );
            } elseif ( $function instanceof Closure && $class === \'Closure\' ) {
                $remove = TRUE;
            }
            if ( $remove ) {
                if ($new_wp_filter_struct) {
                    unset( $GLOBALS[\'wp_filter\'][$tag]->callbacks[$p][$identifier] );
                    if (count($GLOBALS[\'wp_filter\'][$tag]->callbacks[$p]) == 0) {
                        unset($GLOBALS[\'wp_filter\'][$tag]->callbacks[$p]);
                    }
                }
                else {
                    unset( $GLOBALS[\'wp_filter\'][$tag][$p][$identifier] );
                }
            }
        }
    }
}
我用一个匿名函数对它进行了一点测试,似乎可以工作。代码还应与WP版本兼容<;4.7(但我没有测试)。

结束

相关推荐

theme functions (hooks)

WordPress已经提出了这个问题,但没有答案。我只是想在这个论坛上试试,如果有人知道的话,因为我也有同样的问题。要使用jquery滑块编辑我的主题,如何转到该脚本?,显示“$主题->挂钩(\'content\\u before\');”在content div标记中。有人能帮忙吗?我的主题索引。php包含以下内容<div id=\"main\"> <?php $theme->hook(\'main_before\'); ?> &#x