I'm trying to get the input value of a shortcode inside a function that is used by a filter, but there seems to be no success. Here is what i did:

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

Now i know using $value inside filter_value() won't work because of variable scopes, but even using $GLOBALS['value'] doesn't work.

I even tried using $value = $atts['id'] inside the filter_value(); but no success either.

How can i use my shortcode like [my-shortcode id='123'] and pass the 123 value to the filter?

Thanks.

up vote 7 down vote accepted

Using a global variable will work. Here's a demonstration:

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

Side note, declaring a function within another function is not a good practice.

  • This is actually strange. If i set the value using $GLOBALS['value'] = some value and then call the $GLOBALS['value'] it does work, but if i set the value directly as $value = some value and then call it using $GLOBALS['value'] it doesn't work, while it should work according to PHP manual. – Jack Johansson May 15 '17 at 4:20
  • You have to set $value to the global scope with global $value; before initializing it with a value. E.g. global $value; $value = $a['id']; Then in the filter you can do global $value; echo $value; Does that help? – Dave Romsey May 15 '17 at 4:22
  • Yes thanks. I was reading this on the manual, and in the first example the values are defined directly. Do i have to define them outside ANY function to be available directly using $GLOBALS['value'];? – Jack Johansson May 15 '17 at 4:24
  • 2
    Cool. glad we got it. In the first example from those docs, the variables are declared outside of a function and within the global scope. So, no global keyword is needed. In our examples, we've been working from within the scope of functions, so the global keyword is necessary. – Dave Romsey May 15 '17 at 4:31
  • 1
    Filters are our friends! :-) I'm sure some eager answerers will be around to answer your questions if you need more help! – Dave Romsey May 15 '17 at 4:35

Here are few workarounds:

Approach #1

You could wrap the shortcode's definition and the posts_where filter's callback in a class to be able to pass around a given value between the class methods e.g. as a private variable.

Approach #2

Another approach would be to pass the value as an input to WP_Query within your shortcode's callback:

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

and then within your posts_where filter you can access it:

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

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

    return $where;

}, 10, 2 );

Approach #3

...or you could also adjust the example by @the_dramatist to be able to remove the callback afterwards by assigning the anonymous function to a variable:

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

Check e.g. the PHP docs on how to assign an anonymous function, with the use keyword, to a variable.

ps: I think I first learned about this variable assigning trick by @gmazzap, to make it easier to remove an anonymous filter's callback.

Hope it helps!

  • Thanks birgire, kind and precise answer as always. Do you recommend defining a function inside a function over using a global unique variable? If yes, could you please tell me why? – Jack Johansson May 15 '17 at 16:31
  • That would not be a good idea, if we need to reuse that function and it's stuck within another function's scope and it would be harder for other developers to e.g. skip the filter with anonymous callbacks. So as a formal plugin for the wp.org repo I would most likely try to allow other developers to remove filters as easy as possible ;-) I would also in general try to avoid adding more globals, as there can be various issues with that approach. If we get into a corner with our plugin structure, then maybe it's a sign to use an alternative structure, whatever that might be ;-) – birgire May 15 '17 at 17:13
  • I guess I'm going with your 3rd approach. Seems to work in my case. Cheers! – Jack Johansson May 15 '17 at 17:50
  • sure whatever works best for you. I might go with #1 or #2 without anyomous function to easily remove it again ;-) @JackJohansson – birgire May 15 '17 at 17:57
  • 2
    We can actually pass on custom arguments and their values to WP_Query to target a given instance and access it through various filters like posts_where, pre_get_posts and posts_clauses. That's what we do in approach #2. – birgire May 15 '17 at 18:31

You can use the use keyword of PHP. So with the help of this use keyword you can bring variable inside a function. And also you can write anonymous function to reduce the code. So the whole thing will be-

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

Hope that helps.

  • This is cool, but anonymous functions are difficult to unhook. – Dave Romsey May 15 '17 at 4:04
  • 2
    Ooh, removing the anonymous function has now been covered by @birgire in another answer to the question. Cool! – Dave Romsey May 17 '17 at 22:56

Why not pass the $value as a param?

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

documentation

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.