12

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

5
  • Simply do your "crazy calculation" inside that function... Commented Apr 11, 2012 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
    Commented Apr 11, 2012 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). Commented Apr 11, 2012 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
    Commented Apr 11, 2012 at 20:07
  • possible duplicate of Passing a parameter to filter and action functions
    – T.Todua
    Commented May 14, 2015 at 9:20

3 Answers 3

12

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

14
  • This has nothing to do with the number of arguments passed to the function by apply_filters... Commented Apr 11, 2012 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
    Commented Apr 11, 2012 at 19:55
  • Sorry you were right. I calculated $score first and then globalized it. No wonder it wasn't working. Thank you!
    – kingkool68
    Commented Apr 11, 2012 at 20:11
  • -1. First option exposes a variable in the global state, 2nd option doesn't work... Commented Apr 11, 2012 at 20:28
  • 1
    "Globals are evil"? Really? Then the entire WordPress code had better be written, since it relies on quite a few global variables. Commented Apr 11, 2012 at 20:37
4
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
  • 4
    Anonymous functions should not be used in add_filter() or add_action() calls. They cannot be removed via remove_function(). Commented Apr 11, 2012 at 20:31
  • You mean remove_filter, which is mainly used to remove built-in filters, not filters added by plugins/themes... Commented Apr 11, 2012 at 20:36
  • 2
    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. Commented Apr 11, 2012 at 20:38
1

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?

6
  • How is this any different from what he already has? Commented Apr 11, 2012 at 20:00
  • Once less declaration of "global". Look at his second example, he declares gloabl $wp twice!
    – Adam
    Commented Apr 11, 2012 at 20:02
  • It also doesn't work. This is the first thing I tried.
    – kingkool68
    Commented Apr 11, 2012 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?
    – Adam
    Commented Apr 11, 2012 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
    Commented Apr 11, 2012 at 20:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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