Melewati parameter untuk memfilter dan fungsi aksi

52

Adalah cara untuk mengirimkan parameter saya sendiri ke fungsi di add_filteratau add_action. Misalnya, lihat kode berikut:

function my_content($content, $my_param)
{
do something...
using $my_param here ...
return $content;
}
add_filter('the_content', 'my_content', 10, 1);

Bisakah saya melewati parameter saya sendiri? sesuatu seperti:

add_filter('the_content', 'my_content($my_param)', 10, 1)

atau

add_filter('the_content', 'my_content', 10, 1, $my_param)
Aakash Chakravarthy
sumber

Jawaban:

78

Secara default ini tidak mungkin. Ada beberapa solusi jika Anda melakukannya dengan cara OOP.
Anda bisa membuat kelas untuk menyimpan nilai yang ingin Anda gunakan nanti.

Contoh:

/**
 * Stores a value and calls any existing function with this value.
 */
class WPSE_Filter_Storage
{
    /**
     * Filled by __construct(). Used by __call().
     *
     * @type mixed Any type you need.
     */
    private $values;

    /**
     * Stores the values for later use.
     *
     * @param  mixed $values
     */
    public function __construct( $values )
    {
        $this->values = $values;
    }

    /**
     * Catches all function calls except __construct().
     *
     * Be aware: Even if the function is called with just one string as an
     * argument it will be sent as an array.
     *
     * @param  string $callback Function name
     * @param  array  $arguments
     * @return mixed
     * @throws InvalidArgumentException
     */
    public function __call( $callback, $arguments )
    {
        if ( is_callable( $callback ) )
            return call_user_func( $callback, $arguments, $this->values );

        // Wrong function called.
        throw new InvalidArgumentException(
            sprintf( 'File: %1$s<br>Line %2$d<br>Not callable: %3$s',
                __FILE__, __LINE__, print_r( $callback, TRUE )
            )
        );
    }
}

Sekarang Anda dapat memanggil kelas dengan fungsi apa pun yang Anda inginkan - jika fungsi itu ada di suatu tempat, ia akan dipanggil dengan parameter tersimpan Anda.

Mari kita buat fungsi demo ...

/**
 * Filter function.
 * @param  array $content
 * @param  array $numbers
 * @return string
 */
function wpse_45901_add_numbers( $args, $numbers )
{
    $content = $args[0];
    return $content . '<p>' . implode( ', ', $numbers ) . '</p>';
}

... dan gunakan sekali ...

add_filter(
    'the_content',
    array (
        new WPSE_Filter_Storage( array ( 1, 3, 5 ) ),
        'wpse_45901_add_numbers'
    )
);

… dan lagi …

add_filter(
    'the_content',
    array (
        new WPSE_Filter_Storage( array ( 2, 4, 6 ) ),
        'wpse_45901_add_numbers'
    )
);

Keluaran:

masukkan deskripsi gambar di sini

Kuncinya adalah usabilitas : Anda dapat menggunakan kembali kelas (dan dalam contoh kami juga fungsinya).

PHP 5.3+

Jika Anda dapat menggunakan PHP versi 5.3 atau penutupan yang lebih baru akan membuat itu lebih mudah:

$param1 = '<p>This works!</p>';
$param2 = 'This works too!';

add_action( 'wp_footer', function() use ( $param1 ) {
        echo $param1;
    }, 11 
);
add_filter( 'the_content', function( $content ) use ( $param2 ) {
        return t5_param_test( $content, $param2 );
    }, 12
);

/**
 * Add a string to post content
 *
 * @param  string $content
 * @param  string $string This is $param2 in our example.
 * @return string
 */
function t5_param_test( $content, $string )
{
    return "$content <p><b>$string</b></p>";
}

Kelemahannya adalah Anda tidak bisa menulis unit test untuk penutupan. 

fuxia
sumber
17
Anda tidak hanya mendapatkan suara untuk jawaban berkualitas untuk masalah yang seharusnya memiliki solusi bawaan dalam WP core , Anda juga mendapatkan satu untuk datang kembali lima bulan kemudian untuk memperbarui jawaban Anda dengan contoh penutupan PHP 5.3+.
Adam
1
Jawaban yang sangat bagus! Tetapi bagaimana saya bisa menghapus filter ini yang dibuat oleh fungsi anonim ini nanti?
Vinicius Tavares
2
@ViniciusTavares Kamu tidak bisa. Pikirkan sebelum Anda menggunakannya. :)
fuxia
5
Perhatikan bahwa jika Anda menyimpan fungsi anonim ke variabel (misalnya $func = function() use ( $param1 ) { $param1; };dan add_action( $func, 11);) maka Anda dapat menghapusnya melaluiremove_action( $func, 11 );
bonger
1
Tetapi tidak disarankan untuk menggunakan fungsi anonim pada plugin atau tema yang Anda rilis ke dunia (Anda dapat menggunakannya pada proyek Anda sendiri). Masalahnya adalah Anda tidak akan bisa melepaskannya. Pendekatan apa pun yang Anda putuskan untuk dilakukan harusnya tidak bisa dilakukan nanti.
Mueyiwa Moses Ikomi
1

Buat fungsi dengan argumen yang diperlukan yang mengembalikan fungsi. Lewati fungsi ini (fungsi anonim, juga dikenal sebagai penutupan) ke kait wp.

Ditampilkan di sini untuk pemberitahuan admin di wordpress backend.

public function admin_notice_func( $message = '')
{
$class = 'error';
    $output = sprintf('<div class="%s"><p>%s</p></div>',$class, $message);
    $func = function() use($output) { print $output; };
    return $func;
}
$func = admin_notice_func('Message');
add_action('admin_notices', $func);
Hornament
sumber
1

Gunakan fungsi Anonim php :

$my_param = 'my theme name';
add_filter('the_content', function ($content) use ($my_param) {
    //$my_param is available for you now
    if (is_page()) {
        $content = $my_param . ':<br>' . $content;
    }
    return $content;
}, 10, 1);
wesamly
sumber
1

Saya tahu waktu telah berlalu, tapi saya punya masalah dengan melewati parameter saya sendiri sampai saya menemukan bahwa parameter ke-4 di add_filter adalah jumlah parameter yang dilewati termasuk konten untuk diubah. Jadi, jika Anda melewati 1 parameter tambahan, angka harus 2 dan bukan 1 dalam kasus Anda

add_filter('the_content', 'my_content', 10, 2, $my_param)

dan menggunakan

function my_content($content, $my_param) {...}
giacoder
sumber
1

Cara yang benar, benar-benar singkat dan paling efisien untuk menyampaikan jumlah argumen apa pun ke filter dan tindakan WP dari @Wesam Alalem di sini , yang menggunakan penutupan.

Saya hanya akan menambahkan bahwa Anda bisa membuatnya lebih jelas dan lebih fleksibel dengan memisahkan metode pelaku sebenarnya dari penutupan anonim. Untuk ini, Anda cukup memanggil metode dari penutupan sebagai berikut (contoh dimodifikasi dari jawaban @Wesam Alalem).

Dengan cara ini Anda dapat menulis logika panjang atau rumit seperti yang Anda inginkan secara leksikal di luar penutupan yang Anda gunakan untuk memanggil pelaku sebenarnya.

// ... inside some class

private function myMethod() {
    $my_param = 'my theme name';
    add_filter('the_content', function ($content) use ($my_param) {
        // This is the anonymous closure that allows to pass 
        // whatever number of parameters you want via 'use' keyword.
        // This is just oneliner.
        // $my_param is available for you now via 'use' keyword above
        return $this->doThings($content, $my_param);
    }, 10, 2);
}

private function doThings($content, $my_param) {
    // Call here some other method to do some more things
    // however complicated you want.
    $morethings = '';
    if ($content = 'some more things') {
        $morethings = (new MoreClass())->get();
    }
    return $my_param . ':<br>' . $content . $morethings;
}
bob-12345
sumber
0

jika Anda membuat kait Anda sendiri, berikut adalah contohnya.

// lets say we have three parameters  [ https://codex.wordpress.org/Function_Reference/add_filter ]
add_filter( 'filter_name', 'my_func', 10, 3 );
my_func( $first, $second, $third ) {
  // code
}

lalu terapkan kait:

// [ https://codex.wordpress.org/Function_Reference/apply_filters ]
echo apply_filters( 'filter_name', $first, $second, $third );
T.Todua
sumber
Ini tidak meneruskan informasi dari registrasi ke callback. Itu hanya mengatakan berapa banyak parameter yang bisa diterima oleh callback.
fuxia
@ Fluxia, dapatkah Anda menyarankan perubahan sederhana agar informasi tidak diteruskan? Apakah orang hanya akan menempel pada nilai-nilai param setelah 3?
SherylHohman
0

Anda selalu dapat menggunakan global bukan?

  global $my_param;
samjco
sumber
Ini tidak memberikan jawaban untuk pertanyaan itu. Setelah memiliki reputasi yang cukup, Anda dapat mengomentari setiap pos ; alih-alih, berikan jawaban yang tidak memerlukan klarifikasi dari penanya . - Dari Ulasan
cjbj
@ cjbj Sebenarnya begitu. Pertanyaannya adalah apakah parameter dapat diteruskan ke "fungsi" yang ada di add_filter atau add_action. Tidak jelas apakah pengguna ingin meneruskannya di fungsi add_filter atau add_action itu sendiri meskipun itu asumsi. :)
samjco
0

Meskipun memanggil fungsi secara langsung, lakukan ini dengan cara yang lebih elegan: operasikan fungsi anonim sebagai panggilan balik.

Sebagai contoh:

Saya memiliki fungsi tunggal untuk menerjemahkan judul, konten, dan kutipan dari posting saya. Jadi, saya perlu beralih ke fungsi utama ini beberapa argumen yang mengatakan siapa yang memanggil.

add_filter( 'the_title', function( $text ) { 
    return translate_text( $text, 'title', 'pl' );
});

add_filter( 'the_content', function( $text ) { 
    return translate_text( $text, 'content', 'pl' );
});

add_filter( 'the_excerpt', function( $text ) { 
    return translate_text( $text, 'excerpt', 'pl' );
});

Jadi, fungsi utama translate_textmenerima parameter sebanyak yang saya inginkan, hanya karena saya telah melewati fungsi anonim sebagai panggilan balik.

Marcos Rezende
sumber
-1

Saya berharap untuk melakukan hal yang sama tetapi karena itu tidak mungkin saya kira solusi sederhana adalah memanggil fungsi yang berbeda add_filter('the_content', 'my_content_filter', 10, 1);

maka my_content_filter () dapat memanggil my_content () lewat argumen yang diinginkan.

Pierre-Verthume Larivière
sumber