web-dev-qa-db-ja.com

無名関数によって追加されたアクション/フィルタを削除する

それは私が言わなければならないおかしい風習です。匿名関数によって追加されたアクションとフィルタを削除するための解決策を見つけるために2時間を費やしました。

これは親テーマで使用されているコードなので、削除する必要があります。

/**
 * 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 、ひどくそれで遊んだが、助けにはならない。それで、無名関数によって追加されたアクション/フィルタを削除する他の代替案はありますか?

ありがとう

10
Abhik

問題は、匿名関数と別の関数を区別できないことです。そのため、はい、クロージャー(つまり、匿名関数)を削除できますが、複数のクロージャーが同じ優先度で同じフィルターに作用する場合選択するには、それらをすべて削除するか、1つのみを削除します(正確にはどちらを知らないか)。

あなたが投稿した@toscho回答の関数から高度に派生した関数を使用して、それらをすべて削除する方法を示します。

/**
 * 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 );
10
gmazzap

匿名のフィルタとアクションは、次の方法でネイティブに削除できます。

remove_filter( $tag, function(){}, $priority )

spl_object_hash()を使用してユニークなidを生成するとき、無名関数はお互いに匹敵するので、完全クロージャオブジェクトは再び作り直される必要はありません。

複数のフィルタまたはアクションが同じ優先度で同じタグに接続されている場合は、追加された最新のフィルタまたはアクションが削除されます。保持する必要があるものがある場合は、必要なフィルタまでのすべてのフィルタを削除してから、必要に応じて他のフィルタを追加し直す必要があります。

// 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(){} );

これは通常ベストプラクティスに戻ります。私は今まで私がクライアント用に開発しているカスタムテーマの一部として匿名関数を使用するだけで、フィルタを上書きしたり削除したりしたくありません。私が開発するパブリックテーマやプラグインでは、ファクトリを使用してクラスを初期化し、すべてのフィルタとアクションを追加してから、インスタンスを静的変数として格納します。

2
Shaun Cockerill

優先順位11でフィルタを追加した場合はどうなりますか。それは醜いですが、あなたの場合はうまくいくかもしれません。

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

    return $default;
}, 11, 1 );
2
tivnet