Jak uzyskać wartości wejściowe shortcode w filtrze?

9

Próbuję uzyskać wartość wejściową shortcode wewnątrz funkcji, która jest używana przez filtr, ale wydaje się, że nie ma sukcesu. Oto co zrobiłem:

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

Teraz wiem, że używanie $valuewewnątrz filter_value()nie będzie działać z powodu zmiennych zakresów, ale nawet używanie $GLOBALS['value']nie działa.

Próbowałem nawet użyć w $value = $atts['id']środku, filter_value();ale też bez powodzenia.

Jak mogę użyć mojego krótkiego kodu [my-shortcode id='123']i przekazać wartość 123 do filtra?

Dzięki.

Jack Johansson
źródło

Odpowiedzi:

7

Korzystanie ze zmiennej globalnej będzie działać. Oto demonstracja:

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

Uwaga dodatkowa: deklarowanie funkcji w ramach innej funkcji nie jest dobrą praktyką .

Dave Romsey
źródło
To jest naprawdę dziwne. Jeśli ustawię wartość za pomocą, $GLOBALS['value'] = some valuea następnie wywołam, $GLOBALS['value']to zadziała, ale jeśli ustawię wartość bezpośrednio jako, $value = some valuea następnie wywołanie przy użyciu $GLOBALS['value']nie zadziała, podczas gdy powinno działać zgodnie z instrukcją PHP.
Jack Johansson
Przed zainicjowaniem go wartością należy ustawić $valuezakres globalny global $value;. Np. global $value; $value = $a['id']; W filtrze możesz to zrobić global $value; echo $value;Czy to pomaga?
Dave Romsey
Tak, dziękuję. Czytałem to w instrukcji, aw pierwszym przykładzie wartości są definiowane bezpośrednio. Czy muszę je definiować poza JAKĄKOLWIEK funkcją, aby były dostępne bezpośrednio przy użyciu $GLOBALS['value'];?
Jack Johansson
2
Fajne. cieszę się, że to mamy. W pierwszym przykładzie z tych dokumentów zmienne są deklarowane poza funkcją i w zakresie globalnym. Tak więc żadne globalsłowo kluczowe nie jest potrzebne. W naszych przykładach pracowaliśmy z zakresu funkcji, więc globalsłowo kluczowe jest konieczne.
Dave Romsey
1
Filtry są naszymi przyjaciółmi! :-) Jestem pewien, że w pobliżu znajdą się chętni odpowiedzi, aby odpowiedzieć na twoje pytania, jeśli potrzebujesz dodatkowej pomocy!
Dave Romsey
7

Oto kilka obejść:

Podejście nr 1

Można zawinąć definicję skrótu i posts_wherewywołanie zwrotne filtra w klasę, aby móc przekazywać określoną wartość między metodami klasowymi, np. Jako zmienną prywatną .

Podejście nr 2

Innym podejściem byłoby przekazanie wartości jako danych wejściowych do WP_Querywywołania zwrotnego kodu krótkiego:

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

a następnie w filtrze post_where możesz uzyskać do niego dostęp:

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

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

    return $where;

}, 10, 2 );

Podejście nr 3

... lub możesz także dostosować przykład przez @tam_dramatist, aby móc później usunąć wywołanie zwrotne, przypisując funkcję anonimową do zmiennej:

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

Sprawdź np. Dokumentację PHP, w jaki sposób przypisać anonimową funkcję za pomocą słowa kluczowego use do zmiennej.

ps: Myślę, że po raz pierwszy dowiedziałem się o tej sztuczce przypisywania zmiennych przez @gmazzap, aby ułatwić usunięcie wywołania zwrotnego anonimowego filtra.

Mam nadzieję, że to pomoże!

birgire
źródło
Dziękuję bardzo, życzliwa i precyzyjna odpowiedź jak zawsze. Czy zaleca się zdefiniowanie funkcji wewnątrz funkcji zamiast używania globalnej zmiennej unikalnej? Jeśli tak, czy możesz mi powiedzieć, dlaczego?
Jack Johansson
To nie byłby dobry pomysł, gdybyśmy musieli ponownie użyć tej funkcji i utknęła w zasięgu innej funkcji, a innym programistom byłoby trudniej np. Pominąć filtr z anonimowymi wywołaniami zwrotnymi. Więc jako formalna wtyczka do repozytorium wp.org najprawdopodobniej postaram się pozwolić innym programistom na usunięcie filtrów tak łatwo, jak to możliwe ;-) Ogólnie starałbym się również unikać dodawania większej liczby globali, ponieważ mogą być z tym różne problemy podejście. Jeśli wejdziemy w kąt z naszą strukturą wtyczek, być może jest to znak, aby użyć alternatywnej struktury, cokolwiek to może być ;-)
birgire
Chyba wybieram twoje trzecie podejście. Wydaje się działać w moim przypadku. Twoje zdrowie!
Jack Johansson
na pewno cokolwiek będzie dla ciebie najlepsze. Mogę przejść z numerem 1 lub nr 2 bez żadnej innej funkcji, aby łatwo go ponownie usunąć ;-) @JackJohansson
birgire
2
Możemy faktycznie przejść na własnych argumentów i ich wartości do WP_Querykierowania danej instancji i do niego dostęp za pomocą różnych filtrów, takich jak posts_where, pre_get_postsi posts_clauses. To właśnie robimy w podejściu nr 2.
birgire
4

Możesz użyć usesłowa kluczowego PHP . Tak więc za pomocą tego usesłowa kluczowego można wprowadzić zmienną do funkcji. A także możesz napisać anonimową funkcję, aby zmniejszyć kod. Więc cała sprawa będzie-

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

Mam nadzieję, że to pomaga.

CodeMascot
źródło
To fajne, ale anonimowe funkcje są trudne do odblokowania.
Dave Romsey
2
Ooh, usunięcie anonimowej funkcji zostało teraz objęte przez @birgire w innej odpowiedzi na pytanie. Fajne!
Dave Romsey
0

Dlaczego nie przekazać wartości $ jako parametru?

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

dokumentacja

madalinivascu
źródło