Jawaban:
Itu pertanyaan yang sangat bagus. Itu turun ke jantung gelap dari plugin API dan praktik pemrograman terbaik.
Untuk jawaban berikut ini saya membuat plugin sederhana untuk menggambarkan masalah dengan kode yang mudah dibaca.
<?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;
}
Sekarang kita melihat ini:
WordPress membutuhkan nama untuk filter. Kami tidak menyediakan satu, jadi WordPress memanggil _wp_filter_build_unique_id()
dan membuat satu. Nama ini tidak dapat diprediksi karena digunakan spl_object_hash()
.
Jika kita menjalankan var_export()
pada, $GLOBALS['wp_filter'][ 'wp_footer' ]
kita mendapatkan sesuatu seperti ini sekarang:
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,
),
),
)
Untuk menemukan dan menghapus tindakan jahat kita, kita harus melalui filter terkait untuk kait (tindakan hanyalah filter yang sangat sederhana), periksa apakah itu adalah array dan jika objek adalah turunan dari kelas. Lalu kami mengambil prioritas dan menghapus filter, tanpa pernah melihat pengenal yang sebenarnya .
Oke, mari kita fungsi itu:
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
);
}
}
}
}
}
Kapan kita memanggil fungsi ini? Tidak ada cara untuk mengetahui dengan pasti kapan objek asli dibuat. Mungkin terkadang sebelumnya 'plugins_loaded'
? Mungkin nanti?
Kami menggunakan kait yang sama dengan objek yang dikaitkan dan melompat di awal dengan prioritas 0
. Itulah satu-satunya cara untuk benar-benar yakin. Inilah cara kami menghapus metode 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'
);
}
Hasil:
Dan itu akan menghapus tindakan dari pertanyaan Anda (tidak diuji):
add_action( 'comments_array', 'kill_FbComments', 0 );
function kill_FbComments()
{
remove_anonymous_object_filter(
'comments_array',
'SEOFacebookComments',
'FbComments'
);
}
'plugins_loaded'
. Bukan hanya ketika plugin Anda dipanggil oleh WordPress.plugins_loaded
dipanggil, yang memang untuk apa plugins_loaded
. Tentu saja, instance kelas masih perlu diakses, mungkin melalui pola singleton.
remove_action()
Saya tidak yakin tetapi Anda dapat mencoba menggunakan singleton.
Anda harus menyimpan referensi objek di properti statis kelas Anda dan kemudian mengembalikan variabel statis dari metode statis. Sesuatu seperti ini:
class MyClass{
private static $ref;
function MyClass(){
$ref = &$this;
}
public static function getReference(){
return self::$ref;
}
}
Selama Anda tahu objek (dan Anda menggunakan PHP 5.2 atau lebih tinggi - versi PHP stabil saat ini adalah 5.5, 5.4 masih didukung, 5.3 adalah akhir hidup), Anda bisa menghapusnya dengan remove_filter()
metode ini. Yang perlu Anda ingat adalah objek, nama-metode, dan prioritas (jika digunakan):
remove_filter('comment_array', [$this, 'FbComments']);
Namun Anda melakukan sedikit kesalahan dalam kode Anda. Jangan awali $this
dengan ampersand &
, yang diperlukan di PHP 4 (!) Dan sudah lama ditunggu. Ini bisa membuat berurusan dengan kait Anda bermasalah, jadi biarkan saja:
add_filter('comments_array', [$this, 'FbComments]));
Dan itu saja.
$this
dari luar (plugin / tema lain).
&
dari Anda&$this
, itu adalah hal PHP 4