Wordpress - Passing a parameter to filter and action functions
By default this is not possible. There are workarounds if you do it the OOP way.
You could create a class to store the values you want to use later.
Example:
/**
* Stores a value and calls any existing function with this value.
*/
class WPSE_Filter_Storage
{
/**
* Filled by __construct(). Used by __call().
*
* @type mixed Any type you need.
*/
private $values;
/**
* Stores the values for later use.
*
* @param mixed $values
*/
public function __construct( $values )
{
$this->values = $values;
}
/**
* Catches all function calls except __construct().
*
* Be aware: Even if the function is called with just one string as an
* argument it will be sent as an array.
*
* @param string $callback Function name
* @param array $arguments
* @return mixed
* @throws InvalidArgumentException
*/
public function __call( $callback, $arguments )
{
if ( is_callable( $callback ) )
return call_user_func( $callback, $arguments, $this->values );
// Wrong function called.
throw new InvalidArgumentException(
sprintf( 'File: %1$s<br>Line %2$d<br>Not callable: %3$s',
__FILE__, __LINE__, print_r( $callback, TRUE )
)
);
}
}
Now you can call the class with any function you want – if the function exists somewhere it will be called with your stored parameters.
Let’s create a demo function …
/**
* Filter function.
* @param array $content
* @param array $numbers
* @return string
*/
function wpse_45901_add_numbers( $args, $numbers )
{
$content = $args[0];
return $content . '<p>' . implode( ', ', $numbers ) . '</p>';
}
… and use it once …
add_filter(
'the_content',
array (
new WPSE_Filter_Storage( array ( 1, 3, 5 ) ),
'wpse_45901_add_numbers'
)
);
… and again …
add_filter(
'the_content',
array (
new WPSE_Filter_Storage( array ( 2, 4, 6 ) ),
'wpse_45901_add_numbers'
)
);
Output:
The key is reusability: You can reuse the class (and in our examples also the function).
PHP 5.3+
If you can use a PHP version 5.3 or newer closures will make that much easier:
$param1 = '<p>This works!</p>';
$param2 = 'This works too!';
add_action( 'wp_footer', function() use ( $param1 ) {
echo $param1;
}, 11
);
add_filter( 'the_content', function( $content ) use ( $param2 ) {
return t5_param_test( $content, $param2 );
}, 12
);
/**
* Add a string to post content
*
* @param string $content
* @param string $string This is $param2 in our example.
* @return string
*/
function t5_param_test( $content, $string )
{
return "$content <p><b>$string</b></p>";
}
The downside is that you cannot write unit tests for closures.
Use php Anonymous functions:
$my_param = 'my theme name';
add_filter('the_content', function ($content) use ($my_param) {
//$my_param is available for you now
if (is_page()) {
$content = $my_param . ':<br>' . $content;
}
return $content;
}, 10, 1);
The correct, really short and most efficient way of passing whatever number of arguments to WP filters and actions is from @Wesam Alalem here, that uses the closure.
I would only add that you could make it even clearer and much more flexible by separating the actual doer method from anonymous closure. For this you just call the method from the closure as follows (modified example from @Wesam Alalem answer).
This way you can write as long or complicated logic as you wish lexically outside of the closure you use to call the actual doer.
// ... inside some class
private function myMethod() {
$my_param = 'my theme name';
add_filter('the_content', function ($content) use ($my_param) {
// This is the anonymous closure that allows to pass
// whatever number of parameters you want via 'use' keyword.
// This is just oneliner.
// $my_param is available for you now via 'use' keyword above
return $this->doThings($content, $my_param);
}, 10, 2);
}
private function doThings($content, $my_param) {
// Call here some other method to do some more things
// however complicated you want.
$morethings = '';
if ($content = 'some more things') {
$morethings = (new MoreClass())->get();
}
return $my_param . ':<br>' . $content . $morethings;
}