How to Pass External Variables to Filters/Actions

I find myself needing to pass custom data to a filter provided by a 3rd party plugin. All of the ways I’ve seen to do this are really complicated and hard to wrap my head around.

Take this example:

Read More
$score = 42; //Some crazy calculation I don't want to repeat.

function add_score_to_title($title) {
    return 'Quiz Results (' . $score . '/') - ' . $title;
}

add_filter( 'aioseop_title_single', 'add_score_to_title');

How can I pass the $score variable to add_score_to_title()?

What I ended up doing was adding my variable onto the global $wp object. So you end up with this:

global $wp;
$score = 42; //Some crazy calculation I don't want to repeat.
$wp->some_random_name_for_score = $score;

function add_score_to_title($title) {
    global $wp;
    $score = $wp->some_random_name_for_score;
    return 'Quiz Results (' . $score . '/') - ' . $title;
}

add_filter( 'aioseop_title_single', 'add_score_to_title');

Dirty? Maybe. Simple? Yup! Any downsides to this technique? Please discuss.

UPDATE
Here is the complete code in question -> http://pastebin.com/fkSXY04m

Related posts

Leave a Reply

3 comments

  1. You have at least two options:

    1. Globalize the desired variable, and then reference it inside the callback
    2. Wrap the score calculation logic with a function, then reference it inside the callback

    Globalize the Variable

    <?php
    global $score;
    $score = 42; //Some crazy calculation I don't want to repeat.
    
    function add_score_to_title($title) {
        global $score;
        return 'Quiz Results (' . $score . '/') - ' . $title;
    }
    
    add_filter( 'aioseop_title_single', 'add_score_to_title');
    ?>
    

    Wrap the Score Calculation

    If you only ever need the score calculation inside the filter, pull the logic into the callback itself:

    <?php
    function add_score_to_title($title) {
        $score = 0;
        $questions = get_quiz_result_questions();
        $total_questions = 0;
        foreach( $questions as $question ) {
            $order = $question->order;
    
            if( $order >= 100 ) {
                break;
        }
    
        if( $question->correct == $_POST['Q'][$order] ) {
            $score++;
        }
        $total_questions++;
    
        return 'Quiz Results (' . $score . '/') - ' . $title;
    }
    
    add_filter( 'aioseop_title_single', 'add_score_to_title');
    ?>
    

    Better yet, you could wrap your score calculation in a function of its own, and then call that function inside your callback:

    <?php
    function wpse48677_get_score() {
        $score = 0;
        $questions = get_quiz_result_questions();
        $total_questions = 0;
        foreach( $questions as $question ) {
        $order = $question->order;
    
        if( $order >= 100 ) {
            break;
        }
    
        if( $question->correct == $_POST['Q'][$order] ) {
            $score++;
        }
        $total_questions++;
        $output['score'] = $score;
        $output['total_questions'] = $total_questions;
    
        return $output;
    }
    
    function add_score_to_title($title) {
    
        $score_results = wpse48677_get_score();
    
        $score = $score_results['score'];
    
        return 'Quiz Results (' . $score . '/') - ' . $title;
    }
    
    add_filter( 'aioseop_title_single', 'add_score_to_title');
    ?>
    

    If you find you have problems referencing the $_POST object, you can also register your query variable and then use get_query_var() internally to get data:

    function add_score_query_vars( $query_vars ) {
        $query_vars[] = 'Q';
    
        return $query_vars;
    }
    add_filter( 'query_vars', 'add_score_query_vars' );
    

    With this in place, $_POST['Q'] can be replaced with get_query_var('Q').

  2. function add_score_to_title($title = false) {
      static $score = false;
    
      if($score === false){
        // do calc
      }
    
      // plugin call (filter)   
      if($title !== false)
        return 'Quiz Results (' . $score . ') - ' . $title;
    
      // your call
      return $score;
    }
    

    Call the function anywhere in your script to get the score, it will only be calculated once.

    Another way, using anonymous functions:

    // do the calc
    $score = 'xxx';
    
    add_filter('aioseop_title_single', function($title) use($score){
      return 'Quiz Results (' . $score . ') - ' . $title;  
    });
    
  3. The following example sees the variable $my_calculation in the global scope, however from within our local function we need to declare global $my_calculation in order to access the variable in the global scope.

    <?php 
    
        $my_calculation = 'result!';
    
        function my_function() {
    
            global $my_calculation;
            return $my_calculation;
    
        }
    
        add_filter( 'function_something_here', 'my_function');   
    
    ?>
    

    This is just one way to go about it and it appears to be neat. Would this work for you?