Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

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:

$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

share|improve this question
    
Simply do your "crazy calculation" inside that function... –  onetrickpony Apr 11 '12 at 19:45
    
It's probably hard to understand from my simplified example. The $score variable is used throughout that template. I want to calculate it once and pass that value to the function which is a callback for a filter for changing the page title. This filter is used in the All In One SEO Pack. Running the calculation multiple times is not desired. –  kingkool68 Apr 11 '12 at 19:54
    
Then you should post more code if you want to get a solution that doesn't involve introducing global state (which should never be needed). –  onetrickpony Apr 11 '12 at 20:00
    
Here is the complete code in a template file. $score is calculated by looping over an array of things and incrementing a variable. pastebin.com/fkSXY04m –  kingkool68 Apr 11 '12 at 20:07
add comment

3 Answers

up vote 4 down vote accepted

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

share|improve this answer
    
This has nothing to do with the number of arguments passed to the function by apply_filters... –  onetrickpony Apr 11 '12 at 19:46
    
Tried method #1 you mention of globalizing the variable. It doesn't work. Accepted args paramter doesn't help me either since I have no control over what variables are passed to the callback function. –  kingkool68 Apr 11 '12 at 19:55
    
Sorry you were right. I calculated $score first and then globalized it. No wonder it wasn't working. Thank you! –  kingkool68 Apr 11 '12 at 20:11
    
-1. First option exposes a variable in the global state, 2nd option doesn't work... –  onetrickpony Apr 11 '12 at 20:28
    
Updated to reflect I was in err on the second option. But what's wrong with exposing a global variable? It's certainly better than using an anonymous function in a callback. :) –  Chip Bennett Apr 11 '12 at 20:29
show 7 more comments
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;  
});
share|improve this answer
    
Anonymous functions should not be used in add_filter() or add_action() calls. They cannot be removed via remove_function(). –  Chip Bennett Apr 11 '12 at 20:31
    
You mean remove_filter, which is mainly used to remove built-in filters, not filters added by plugins/themes... –  onetrickpony Apr 11 '12 at 20:36
    
Yes; sorry: remove_filter() and remove_action(). And there's no reason that Plugin/Theme filters shouldn't reasonably be able to be removed: override Plugin stylesheet enqueues, Child Themes, etc. –  Chip Bennett Apr 11 '12 at 20:38
add comment

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?

share|improve this answer
    
How is this any different from what he already has? –  onetrickpony Apr 11 '12 at 20:00
    
Once less declaration of "global". Look at his second example, he declares gloabl $wp twice! –  userabuser Apr 11 '12 at 20:02
    
It also doesn't work. This is the first thing I tried. –  kingkool68 Apr 11 '12 at 20:02
    
Are you able to print or echo your result to ensure that your function is indeed working prior to passing it to the filter? –  userabuser Apr 11 '12 at 20:04
    
Oops! Globalizing $score does indeed work. I goofed and set $score first then globalized which clearly doesn't work. Doing it the proper way by globalizing $score first then giving it a value works as expected. Thanks all. –  kingkool68 Apr 11 '12 at 20:12
show 1 more comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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