익명 개체 인 필터를 제거하는 방법은 무엇입니까?


62

functions.php파일에서 아래 필터를 제거하고 싶지만 클래스에 있기 때문에 어떻게 해야할지 모르겠습니다. 어떻게 remove_filter()생겼을까 요?

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

88 번 라인에 있습니다 .


당신은 제거해야합니다 &귀하의에서 &$this그것이 PHP 4 일이,
톰 J 노웰

답변:


79

아주 좋은 질문입니다. 그것은 플러그인 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가 전화를 걸고 _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 관련 아이디어 는 지금까지 실제로 시도하지 않았습니다.
fuxia

흥미 롭군 나는 당신의 대답이 매우 좋지만 마지막 결론은 상당히 좋지 않다는 것을 알았습니다. 내 의견으로는, WordPress가 플러그인을로드하자마자 클래스 인스턴스가 일반적으로 인스턴스화되어야합니다. 그런 다음 클래스 인스턴스의 생성자는 실제 작업을 수행하지 말고 작업 및 필터를 추가하십시오. 이렇게하면 클래스 인스턴스에서 액션과 필터를 제거하려는 플러그인 plugins_loaded이 호출 될 때 실제로 추가되도록 할 수 있습니다 plugins_loaded. 물론, 클래스 인스턴스는 싱글 톤 패턴을 통해 여전히 액세스 가능해야합니다.
engelen 2016 년

@engelen 이것은 오래된 답변입니다. 요즘에는 콜백을 제거하는 조치를 제안합니다. 그러나 Singleton이 아니라 여러 가지 이유로 반 패턴 입니다.
fuxia

이 답변은 다음과 같은 작업을 제거하는 데에도 사용됩니다.remove_action()
Nick Pyett

0

확실하지 않지만 싱글 톤을 사용해 볼 수 있습니다.
객체 참조를 클래스의 정적 속성에 저장 한 다음 정적 메서드에서 해당 정적 변수를 반환해야합니다. 이 같은:

class MyClass{
    private static $ref;
    function MyClass(){
        $ref = &$this;
    }
    public static function getReference(){
        return self::$ref;
    }
}

0

객체를 알고 있고 PHP 5.2 이상을 사용하는 한 현재 안정적인 PHP 버전은 5.5이고 5.4는 여전히 지원되며 5.3은 수명이 끝났습니다) remove_filter()메소드를 사용하여 제거 할 수 있습니다 . 기억해야 할 것은 객체, 메소드 이름 및 우선 순위 (사용 된 경우)뿐입니다.

remove_filter('comment_array', [$this, 'FbComments']);

그러나 코드에서 약간의 실수가 있습니다. PHP 4 (!)에서 필요했던 $this앰퍼샌드 접두어를 사용 하지 마십시오 &. 이렇게하면 후크를 처리하는 데 문제가 생길 수 있으므로 방해하지 마십시오.

add_filter('comments_array', [$this, 'FbComments]));

그리고 그게 다야.


1
$this외부 (다른 플러그인 / 테마)에서 액세스 할 수 없습니다 .
fuxia
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.