WordPress.org

Make WordPress Core

Opened 17 years ago

Closed 17 years ago

#768 closed enhancement (fixed)

Add support for additional arguments to filters

Reported by: morganiq Owned by: ryan
Milestone: Priority: normal
Severity: normal Version: 1.5
Component: General Keywords:
Focuses: Cc:

Description

It is often difficult or impossible within a filter to discover the context with which the function being filtered was called. For example, get_permalink() takes an optional $id argument; when this argument is used, it is unknown to the filter which post id has been passed. Suggest adding support for passing additional arguments to filters, and passing useful information to apply_filters() where appropriate.

Attachments (1)

filter-args.diff (746 bytes) - added by morganiq 16 years ago.

Download all attachments as: .zip

Change History (13)

#1 @morganiq
17 years ago

  • Patch set to No

#2 @morganiq
17 years ago

  • Summary changed from Add support to filters for additional arguments to Add support for additional arguments to filters

#3 @morganiq
17 years ago

Not also that call_user_func_array() could be called in place of call_user_func(), to pass additional arguments into filter functions as normal list of arguments rather than as a single array.

function apply_filters($tag, $string, $filter = true) {

global $wp_filter;

+
+ if ($filter)
+ $args = array($string) + array_slice(func_get_args(), 3);
+ else
+ $args = array($string) + func_get_arg(3);
+

if (isset($wp_filterall?)) {

foreach ($wp_filterall? as $priority => $functions) {

if (isset($wp_filter[$tag][$priority]))

$wp_filter[$tag][$priority] = array_merge($wp_filterall?[$priority], $wp_filter[$tag][$priority]);

else

$wp_filter[$tag][$priority] = array_merge($wp_filterall?[$priority], array());

$wp_filter[$tag][$priority] = array_unique($wp_filter[$tag][$priority]);

}


}


if (isset($wp_filter[$tag])) {

ksort($wp_filter[$tag]);
foreach ($wp_filter[$tag] as $priority => $functions) {

if (!is_null($functions)) {

foreach($functions as $function) {

if ($filter)

! $string = call_user_func_array($function, $args);

else

! call_user_func_array($function, $args);

}

}

}

}
return $string;

}

Note also that call_user_func_array() can pass values by reference, whereas call_user_func() cannot.

#4 @morganiq
17 years ago

Patch submitted for consideration.

#5 @ryan
17 years ago

I just committed a close version of this. I got rid of the $filter argument to apply_filters since it was used only by do_action. Factoring some things out of apply_filters and into merge_filters and copying the remaining filter logic into do_action allowed me to get rid of $filter and also give do_action a more suitable call signature. BTW, when we want to do call time pass by reference, we must use the array trick on the call to do_action. Ex:

do_action('generate_rewrite_rules', array(&$this)); Works

Directly specifying &$this will result in the call time pass by reference error.

do_action('generate_rewrite_rules', &$this); Won't work.

I thought about making the call signature for do_action be do_action($tag, &$arg = NULL) and changing all calls to accommodate that sig, but do_action is used in templates in a manner incompatible with that sig. I'd rather not break templates. Perhaps we should have had a user space do_template_action() wrapper, but it's too late for that.

Thanks morganiq. Another fine patch. Now we need to pass extra args where they are needed. We can take care of that in another bug.

edited on: 02-01-05 09:42

#6 @ryan
17 years ago

  • Owner changed from anonymous to rboren
  • Status changed from new to assigned

#7 @morganiq
17 years ago

Great Ryan, thanks so much. This will really take the plugin API to the next level, I think.

By the way, I wasn't aware of the call time pass by reference error, but in your illustration you used the same example for what will work and what won't. Just to clarify, did you mean:

do_action('generate_rewrite_rules', array(&$this)); Works
do_action('generate_rewrite_rules', &$this);
Won't work.

Is this a PHP bug? Or is it a logical anomaly that can't be repaired?

#8 @ryan
17 years ago

I fixed the examples.

PHP no longer allows call time pass by reference. You must declare an arg as being a reference at the function definition rather than at function call time. We would have to update the function definition of do_action to accept a reference, but doing so would require updating all templates in the wild since they contain do_action('wp_footer', ). You can't make a reference to a literal string, only a variable.

#9 @morganiq
17 years ago

Gotcha, thanks for the explanation.

I'll start compiling extra arguments and submit another bug for their addition.

#10 @morganiq
17 years ago

Found one minor error, on line 940 of function.php:

$args = array($action) + array_slice(func_get_args(), 2);

$action should be $arg.

#11 @morganiq
17 years ago

Maybe I was a little heavy on the rhetoric -- "taking the plugin API to the next level." Looking through the filters and actions, there are far fewer places where multiple arguments are useful than I figured there would be.

Oh well, it's still useful in many places. :-)

#12 @ryan
17 years ago

  • fixed_in_version set to 1.5
  • Resolution changed from 10 to 20
  • Status changed from assigned to closed
Note: See TracTickets for help on using tickets.