Как получить входные значения шорткода внутри фильтра?

9

Я пытаюсь получить входное значение шорткода внутри функции, которая используется фильтром, но, похоже, нет успеха. Вот что я сделал:

function my_shortcode_function($atts){
    $value = $atts['id'];
    function filter_value(){
        echo $value;
    }
    add_filter('posts_where','filter_value');
}
add_shortcode('my-shortcode','my_shortcode_function');

Теперь я знаю, что использование $valueinside filter_value()не будет работать из-за переменных областей, но даже использование $GLOBALS['value']не работает.

Я даже пытался использовать $value = $atts['id']внутри, filter_value();но безуспешно.

Как я могу использовать свой шорткод [my-shortcode id='123']и передать значение 123 в фильтр?

Спасибо.

Джек Йоханссон
источник

Ответы:

7

Использование глобальной переменной будет работать. Вот демонстрация:

function wpse_shortcode_function( $atts ){
    // User provided values are stored in $atts.
    // Default values are passed to shortcode_atts() below.
    // Merged values are stored in the $a array.
    $a = shortcode_atts( [
                'id'   => false,
    ], $atts );

    // Set global variable $value using value of shortcode's id attribute.
    $GLOBALS['value'] = $a['id'];

    // Add our filter and do a query.
    add_filter( 'posts_where', 'wpse_filter_value' );

    $my_query = new WP_Query( [
        'p' => $GLOBALS['value'],
    ] );

    if ( $my_query->have_posts() ) {
        while ( $my_query->have_posts() ) {
            $my_query->the_post();
            the_title( '<h1>', '</h1>');
        }
        wp_reset_postdata();
    }

    // Disable the filter.
    remove_filter( 'posts_where', 'wpse_filter_value' );
}
add_shortcode( 'my-shortcode', 'wpse_shortcode_function' );

function wpse_filter_value( $where ){
    // $GLOBALS['value'] is accessible here.

    // exit ( print_r( $GLOBALS['value'] ) );

    return $where;
}

Примечание: объявление функции в другой функции не является хорошей практикой .

Дэйв Ромси
источник
Это на самом деле странно. Если я устанавливаю значение с помощью, $GLOBALS['value'] = some valueа затем вызываю, $GLOBALS['value']оно работает, но если я устанавливаю значение напрямую как, $value = some valueа затем вызываю его с помощью, $GLOBALS['value']оно не работает, в то время как оно должно работать в соответствии с руководством по PHP.
Джек Йоханссон
Вы должны установить $valueглобальную область видимости, global $value;прежде чем инициализировать ее значением. Например, global $value; $value = $a['id']; тогда в фильтре вы можете сделать global $value; echo $value;это помогает?
Дейв Ромси,
Да, спасибо. Я читал это в руководстве, и в первом примере значения определены напрямую. Нужно ли определять их вне ЛЮБОЙ функции, чтобы они были доступны напрямую с помощью $GLOBALS['value'];?
Джек Йоханссон
2
Круто. рад, что мы получили это. В первом примере из этих документов переменные объявляются вне функции и в глобальной области видимости. Таким образом, globalключевое слово не требуется. В наших примерах мы работали изнутри функций, поэтому globalключевое слово необходимо.
Дейв Ромси,
1
Фильтры наши друзья! :-) Я уверен, что некоторые нетерпеливые ответчики будут рядом, чтобы ответить на ваши вопросы, если вам нужна дополнительная помощь!
Дейв Ромси,
7

Вот несколько обходных путей:

Подход № 1

Вы можете обернуть определение шорткода и posts_whereобратный вызов фильтра в класс, чтобы иметь возможность передавать определенное значение между методами класса, например, как частную переменную.

Подход № 2

Другой подход заключается в передаче значения в качестве входного сигнала WP_Queryв обратный вызов вашего шорткода:

$query = new WP_Query ( [ 'wpse_value' => 5, ... ] );

и затем в вашем фильтре posts_where вы можете получить к нему доступ:

add_filter( 'posts_where', function( $where, \WP_Query $query )
{

    if( $value = $query->get( 'wpse_value' ) )
    {
        // can use $value here
    }

    return $where;

}, 10, 2 );

Подход № 3

... или вы также можете настроить пример с помощью @the_dramatist, чтобы впоследствии иметь возможность удалить обратный вызов, назначив анонимную функцию переменной:

function my_shortcode_function( $atts, $content )
{
    // shortcode_atts stuff here

    $value = 5; // just an example  

    // Add a filter's callback
    add_filter( 'posts_where',  $callback = function( $where ) use ( $value ) {
        // $value accessible here
        return $where;
    } );

    // WP_Query stuff here and setup $out

    // Remove the filter's callback
    remove_filter( 'posts_where', $callback );

    return $out;
}

add_shortcode( 'my-shortcode', 'my_shortcode_function' );   

Посмотрите, например, документы PHP о том, как назначить анонимную функцию с ключевым словом use переменной.

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

Надеюсь, поможет!

birgire
источник
Спасибо Birgire, добрый и точный ответ как всегда. Вы рекомендуете определять функцию внутри функции, а не использовать глобальную уникальную переменную? Если да, не могли бы вы сказать мне, почему?
Джек Йоханссон
Это не было бы хорошей идеей, если нам нужно повторно использовать эту функцию, и она застряла в области действия другой функции, и другим разработчикам будет сложнее, например, пропустить фильтр с анонимными обратными вызовами. Так что как формальный плагин для репозитория wp.org я бы, скорее всего, попытался позволить другим разработчикам удалять фильтры как можно проще ;-) Я бы также вообще старался избегать добавления большего количества глобальных переменных, поскольку с этим могут быть различные проблемы. подходить. Если мы попадаем в угол с нашей структурой плагинов, то, возможно, это признак использования альтернативной структуры, какой бы она ни была ;-)
birgire
Я думаю, что я иду с вашим третьим подходом. Кажется, работает в моем случае. Ура!
Джек Йоханссон
уверен, что работает лучше для вас. Я мог бы пойти с № 1 или № 2 без какой-либо функции, чтобы легко удалить его снова ;-) @JackJohansson
birgire
2
На самом деле мы можем передавать пользовательские аргументы и их значения для WP_Queryнацеливания на данный экземпляр и доступа к нему через различные фильтры, такие как posts_where, pre_get_postsи posts_clauses. Это то, что мы делаем в подходе № 2.
Биргире
4

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

/**
 * How to get shorcode's input values inside a filter?
 *
 * @param $atts
 */
function my_shortcode_function($atts){
    $value = $atts['id'];
    add_filter('posts_where',function() use ( $value ){
        echo $value;
    });

}
add_shortcode('my-shortcode','my_shortcode_function');

Надеюсь, это поможет.

CodeMascot
источник
Это круто, но анонимные функции сложно отцепить.
Дейв Ромси
2
Ох, удаление анонимной функции теперь было рассмотрено @birgire в другом ответе на вопрос. Круто!
Дейв Ромси
0

Почему бы не передать значение $ в качестве параметра?

 function filter_value($value){
        echo $value;
    }

документация

madalinivascu
источник