Passing Variables by Reference in apply_filters(), do_actions()

This note shows how to pass a variable by reference to a filter. This is rarely needed, but sometimes it is necessary.

The essence of the problem.

A WordPress filter changes the passed value: it changes the value of the passed variable and returns it to the context from which the filter was called. However, it only does this with the first variable, while the additional variables are simply passed to the filter and can be used there for various purposes, but we cannot change them in a way that would affect the variable that was passed.

For example, in PHP we can do the following:

function func( $string, & $number ){
	$number = 2;
	return $string . ' orange';
}

$num = 1;
$str = 'crazy';

$str = func( $str, $num );

echo $str; //> crazy orange
echo $num; //> 2

As seen, we affected the variable $num from the function. This is passing a variable by reference from the current context to the function context.

But in WordPress filters, we can't do this:

// function for the filter
function func( $string, & $number ){
	$number = 2;

	return $string . ' orange';
}

// attach the function to the filter
add_filter( 'myfilter', 'func', 0, 2 );

// call the filter
$num = 1;
$str = 'crazy';

// both filter calls will result in a PHP error
$str = apply_filters('myfilter', $str, $num ); //> error: function expects a reference
$str = apply_filters('myfilter', $str, & $num ); //> error: unexpected symbol &

Passing a Variable by Reference in WordPress Filters

As a solution to this problem, you can use a global variable that will be visible from any context. But this is a bad solution because using a global variable can affect the operation of other processes and cause conflicts. Of course, hacks are our everything, but only when there is no other way.

Option 1

You need to pass two variables in the first filter parameter, so that we can influence both at once, not just the first one. You can pass two variables by putting them in an array and passing that array. It looks like this:

// function for the filter
function func( $array ){
	list( $string, $number ) = $array;

	$string = $string . ' orange';
	$number = 2;

	return array( $string, $number );
}

// attach the function to the filter
add_filter( 'myfilter', 'func' );

// call the filter
$num = 1;
$str = 'crazy';

list( $str, $num ) = apply_filters( 'myfilter', [ $str, $num ] );

// see what we got
echo $str; //> crazy orange
echo $num; //> 2

Option 2

The current problem can also be solved using the special function apply_filters_ref_array()

Passing a Variable by Reference in WordPress Events

In addition to all of the above, it should be added that in WordPress events, it is possible to pass variables by reference. For this, there is a special events function do_action_ref_array()

// hooking the action
add_action( 'myhook', 'myhook_func' );
function myhook_func( & $num ){
	$num = 2; // change the variable by reference
}

$num = 1;

// handling the action
do_action_ref_array('myhook', array( & $num ) );

echo $num; //> 2

In conclusion, I suggest familiarizing yourself with all WordPress hook functions.

Passing an Object by Reference to a Filter or Event

Objects are always passed by reference. Therefore, if we specify an object in the filter, there is no need to come up with anything, we can use standard hook functions: do_action() or apply_filters().

class MyClass {

	public $var;

	function __construct(){
		$this->var = 'Hello';
	}

}

add_filter( 'myfilter', function( $MyClass ){
	$MyClass->var .= ' World!';

	return $MyClass;
} );

$MyClass = new MyClass();

$MyClass = apply_filters( 'myfilter', $MyClass );

print_r( $MyClass );
/*
MyClass Object (
	[var] => Hello World!
)
*/