Передача параметра в функции фильтра и действия


52

Это способ передать мои собственные параметры функции в add_filterили add_action. Например, взгляните на следующий код:

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

Могу ли я передать свой собственный параметр? что-то вроде:

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

или же

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

Ответы:


78

По умолчанию это невозможно. Есть обходные пути, если вы делаете это ООП способом.
Вы можете создать класс для хранения значений, которые вы хотите использовать позже.

Пример:

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

Теперь вы можете вызывать класс с любой функцией, которую хотите - если функция где-то существует, она будет вызываться с вашими сохраненными параметрами.

Давайте создадим демонстрационную функцию ...

/**
 * 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>';
}

... и использовать его один раз ...

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

… и снова …

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

Выход:

введите описание изображения здесь

Ключом является возможность повторного использования : вы можете повторно использовать класс (и в наших примерах также функцию).

PHP 5.3+

Если вы можете использовать PHP версии 5.3 или более новые замыкания, это сделает это намного проще:

$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>";
}

Недостатком является то, что вы не можете писать модульные тесты для замыканий. 


17
Мало того, что вы получили положительный голос за качественный ответ на проблему, которая должна иметь встроенное решение в ядре WP , вы также получите ответ за пять месяцев спустя, чтобы обновить ваш ответ с примером закрытия PHP 5.3+.
Адам

1
Отличный ответ! Но как я могу позже удалить этот фильтр, созданный этой анонимной функцией?
Виниций Таварес

2
@ViniciusTavares Вы не можете. Подумайте, прежде чем использовать его. :)
fuxia

5
Обратите внимание, что если вы сохраняете анонимную функцию в переменной (например, $func = function() use ( $param1 ) { $param1; };и add_action( $func, 11);), вы можете удалить ее с помощьюremove_action( $func, 11 );
bonger

1
Но не рекомендуется использовать анонимные функции в плагинах или темах, которые вы публикуете для всего мира (вы можете использовать их в своих собственных проектах). Проблема в том, что вы не сможете отцепить их. Какой бы подход вы ни решили использовать, он должен быть отключен позже.
Mueyiwa Моисей Икоми

1

Создайте функцию с необходимыми аргументами, которая возвращает функцию. Передайте эту функцию (анонимная функция, также известная как замыкание) на хук wp.

Показано здесь для уведомления администратора в 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);

1

Используйте 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);

1

Я знаю, что время прошло, но у меня были некоторые проблемы с передачей моего собственного параметра, пока я не обнаружил, что 4-й параметр в add_filter - это количество переданных параметров, включая содержимое, которое нужно изменить. Таким образом, если вы передаете 1 дополнительный параметр, число должно быть 2, а не 1 в вашем случае

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

и используя

function my_content($content, $my_param) {...}

1

Правильно, очень короткий и наиболее эффективный путь прохождения независимо от количества аргументов WP фильтров и действий от @Wesam Alalem здесь , который использует замыкание.

Я бы только добавил, что вы можете сделать его еще более понятным и гораздо более гибким, отделив реальный метод делателя от анонимного закрытия. Для этого вы просто вызываете метод из замыкания следующим образом (модифицированный пример из ответа @Wesam Alalem).

Таким образом, вы можете написать настолько длинную или сложную логику, сколько пожелаете, за пределами замыкания, которое вы используете для вызова фактического делателя.

// ... 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;
}

0

если вы создаете свой собственный хук, вот пример.

// 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
}

затем реализовать крюк:

// [ https://codex.wordpress.org/Function_Reference/apply_filters ]
echo apply_filters( 'filter_name', $first, $second, $third );

Это не передает информацию от регистрации к обратному вызову. Он просто говорит, сколько параметров может принять обратный вызов.
fuxia

@fuxia, можете ли вы предложить простое изменение, чтобы информация передавалась? Можно ли просто добавить значения параметров после 3?
Шерил Хохман

0

Вы всегда можете использовать глобальный, не так ли?

  global $my_param;

Это не дает ответа на вопрос. Как только у вас будет достаточно репутации, вы сможете комментировать любой пост ; вместо этого предоставьте ответы, которые не требуют разъяснений от автора . - Из обзора
cjbj

@cjbj На самом деле это так. Вопрос в том, можно ли передать параметры в «функцию», которая находится в add_filter или add_action. Было неясно, хочет ли пользователь передать его в функцию add_filter или add_action, даже если это предположение. :)
samjco

0

Несмотря на прямой вызов функции, сделайте это более элегантным способом: передайте анонимную функцию в качестве обратного вызова.

Например:

У меня есть одна функция для перевода заголовка, содержания и выдержки из моих сообщений. Итак, мне нужно передать этой основной функции несколько аргументов, говорящих о том, кто звонит.

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' );
});

Итак, основная функция translate_textполучает столько параметров, сколько я хочу, только потому, что я передала анонимную функцию в качестве обратного вызова.


-1

Я надеялся сделать то же самое, но так как это невозможно, я думаю, что простой обходной путь - это вызвать другую функцию, такую ​​как add_filter('the_content', 'my_content_filter', 10, 1);

тогда my_content_filter () может просто вызвать my_content (), передавая любой аргумент, который он хочет.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.