22 | | /** |
23 | | * Hooks a function or method to a specific filter action. |
24 | | * |
25 | | * Filters are the hooks that WordPress launches to modify text of various types |
26 | | * before adding it to the database or sending it to the browser screen. Plugins |
27 | | * can specify that one or more of its PHP functions is executed to |
28 | | * modify specific types of text at these times, using the Filter API. |
29 | | * |
30 | | * To use the API, the following code should be used to bind a callback to the |
31 | | * filter. |
32 | | * |
33 | | * <code> |
34 | | * function example_hook($example) { echo $example; } |
35 | | * add_filter('example_filter', 'example_hook'); |
36 | | * </code> |
37 | | * |
38 | | * In WordPress 1.5.1+, hooked functions can take extra arguments that are set |
39 | | * when the matching do_action() or apply_filters() call is run. The |
40 | | * $accepted_args allow for calling functions only when the number of args |
41 | | * match. Hooked functions can take extra arguments that are set when the |
42 | | * matching do_action() or apply_filters() call is run. For example, the action |
43 | | * comment_id_not_found will pass any functions that hook onto it the ID of the |
44 | | * requested comment. |
45 | | * |
46 | | * <strong>Note:</strong> the function will return true no matter if the |
47 | | * function was hooked fails or not. There are no checks for whether the |
48 | | * function exists beforehand and no checks to whether the <tt>$function_to_add |
49 | | * is even a string. It is up to you to take care and this is done for |
50 | | * optimization purposes, so everything is as quick as possible. |
51 | | * |
52 | | * @package WordPress |
53 | | * @subpackage Plugin |
54 | | * @since 0.71 |
55 | | * @global array $wp_filter Stores all of the filters added in the form of |
56 | | * wp_filter['tag']['array of priorities']['array of functions serialized']['array of ['array (functions, accepted_args)']'] |
57 | | * @global array $merged_filters Tracks the tags that need to be merged for later. If the hook is added, it doesn't need to run through that process. |
58 | | * |
59 | | * @param string $tag The name of the filter to hook the $function_to_add to. |
60 | | * @param callback $function_to_add The name of the function to be called when the filter is applied. |
61 | | * @param int $priority optional. Used to specify the order in which the functions associated with a particular action are executed (default: 10). Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action. |
62 | | * @param int $accepted_args optional. The number of arguments the function accept (default 1). |
63 | | * @return boolean true |
64 | | */ |
65 | | function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) { |
66 | | global $wp_filter, $merged_filters; |
67 | | |
68 | | $idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority); |
69 | | $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args); |
70 | | unset( $merged_filters[ $tag ] ); |
71 | | return true; |
72 | | } |
73 | | |
74 | | /** |
75 | | * Check if any filter has been registered for a hook. |
76 | | * |
77 | | * @package WordPress |
78 | | * @subpackage Plugin |
79 | | * @since 2.5 |
80 | | * @global array $wp_filter Stores all of the filters |
81 | | * |
82 | | * @param string $tag The name of the filter hook. |
83 | | * @param callback $function_to_check optional. |
84 | | * @return mixed If $function_to_check is omitted, returns boolean for whether the hook has anything registered. |
85 | | * When checking a specific function, the priority of that hook is returned, or false if the function is not attached. |
86 | | * When using the $function_to_check argument, this function may return a non-boolean value that evaluates to false |
87 | | * (e.g.) 0, so use the === operator for testing the return value. |
88 | | */ |
89 | | function has_filter($tag, $function_to_check = false) { |
90 | | global $wp_filter; |
91 | | |
92 | | $has = !empty($wp_filter[$tag]); |
93 | | if ( false === $function_to_check || false == $has ) |
94 | | return $has; |
95 | | |
96 | | if ( !$idx = _wp_filter_build_unique_id($tag, $function_to_check, false) ) |
97 | | return false; |
98 | | |
99 | | foreach ( (array) array_keys($wp_filter[$tag]) as $priority ) { |
100 | | if ( isset($wp_filter[$tag][$priority][$idx]) ) |
101 | | return $priority; |
102 | | } |
103 | | |
104 | | return false; |
105 | | } |
106 | | |
107 | | /** |
108 | | * Call the functions added to a filter hook. |
109 | | * |
110 | | * The callback functions attached to filter hook $tag are invoked by calling |
111 | | * this function. This function can be used to create a new filter hook by |
112 | | * simply calling this function with the name of the new hook specified using |
113 | | * the $tag parameter. |
114 | | * |
115 | | * The function allows for additional arguments to be added and passed to hooks. |
116 | | * <code> |
117 | | * function example_hook($string, $arg1, $arg2) |
118 | | * { |
119 | | * //Do stuff |
120 | | * return $string; |
121 | | * } |
122 | | * $value = apply_filters('example_filter', 'filter me', 'arg1', 'arg2'); |
123 | | * </code> |
124 | | * |
125 | | * @package WordPress |
126 | | * @subpackage Plugin |
127 | | * @since 0.71 |
128 | | * @global array $wp_filter Stores all of the filters |
129 | | * @global array $merged_filters Merges the filter hooks using this function. |
130 | | * @global array $wp_current_filter stores the list of current filters with the current one last |
131 | | * |
132 | | * @param string $tag The name of the filter hook. |
133 | | * @param mixed $value The value on which the filters hooked to <tt>$tag</tt> are applied on. |
134 | | * @param mixed $var,... Additional variables passed to the functions hooked to <tt>$tag</tt>. |
135 | | * @return mixed The filtered value after all hooked functions are applied to it. |
136 | | */ |
137 | | function apply_filters($tag, $value) { |
138 | | global $wp_filter, $merged_filters, $wp_current_filter; |
139 | | |
140 | | $args = array(); |
141 | | |
142 | | // Do 'all' actions first |
143 | | if ( isset($wp_filter['all']) ) { |
144 | | $wp_current_filter[] = $tag; |
145 | | $args = func_get_args(); |
146 | | _wp_call_all_hook($args); |
147 | | } |
148 | | |
149 | | if ( !isset($wp_filter[$tag]) ) { |
150 | | if ( isset($wp_filter['all']) ) |
151 | | array_pop($wp_current_filter); |
152 | | return $value; |
153 | | } |
154 | | |
155 | | if ( !isset($wp_filter['all']) ) |
156 | | $wp_current_filter[] = $tag; |
157 | | |
158 | | // Sort |
159 | | if ( !isset( $merged_filters[ $tag ] ) ) { |
160 | | ksort($wp_filter[$tag]); |
161 | | $merged_filters[ $tag ] = true; |
162 | | } |
163 | | |
164 | | reset( $wp_filter[ $tag ] ); |
165 | | |
166 | | if ( empty($args) ) |
167 | | $args = func_get_args(); |
168 | | |
169 | | do { |
170 | | foreach( (array) current($wp_filter[$tag]) as $the_ ) |
171 | | if ( !is_null($the_['function']) ){ |
172 | | $args[1] = $value; |
173 | | $value = call_user_func_array($the_['function'], array_slice($args, 1, (int) $the_['accepted_args'])); |
174 | | } |
175 | | |
176 | | } while ( next($wp_filter[$tag]) !== false ); |
177 | | |
178 | | array_pop( $wp_current_filter ); |
179 | | |
180 | | return $value; |
181 | | } |
182 | | |
183 | | /** |
184 | | * Execute functions hooked on a specific filter hook, specifying arguments in an array. |
185 | | * |
186 | | * @see apply_filters() This function is identical, but the arguments passed to the |
187 | | * functions hooked to <tt>$tag</tt> are supplied using an array. |
188 | | * |
189 | | * @package WordPress |
190 | | * @subpackage Plugin |
191 | | * @since 3.0.0 |
192 | | * @global array $wp_filter Stores all of the filters |
193 | | * @global array $merged_filters Merges the filter hooks using this function. |
194 | | * @global array $wp_current_filter stores the list of current filters with the current one last |
195 | | * |
196 | | * @param string $tag The name of the filter hook. |
197 | | * @param array $args The arguments supplied to the functions hooked to <tt>$tag</tt> |
198 | | * @return mixed The filtered value after all hooked functions are applied to it. |
199 | | */ |
200 | | function apply_filters_ref_array($tag, $args) { |
201 | | global $wp_filter, $merged_filters, $wp_current_filter; |
202 | | |
203 | | // Do 'all' actions first |
204 | | if ( isset($wp_filter['all']) ) { |
205 | | $wp_current_filter[] = $tag; |
206 | | $all_args = func_get_args(); |
207 | | _wp_call_all_hook($all_args); |
208 | | } |
209 | | |
210 | | if ( !isset($wp_filter[$tag]) ) { |
211 | | if ( isset($wp_filter['all']) ) |
212 | | array_pop($wp_current_filter); |
213 | | return $args[0]; |
214 | | } |
215 | | |
216 | | if ( !isset($wp_filter['all']) ) |
217 | | $wp_current_filter[] = $tag; |
218 | | |
219 | | // Sort |
220 | | if ( !isset( $merged_filters[ $tag ] ) ) { |
221 | | ksort($wp_filter[$tag]); |
222 | | $merged_filters[ $tag ] = true; |
223 | | } |
224 | | |
225 | | reset( $wp_filter[ $tag ] ); |
226 | | |
227 | | do { |
228 | | foreach( (array) current($wp_filter[$tag]) as $the_ ) |
229 | | if ( !is_null($the_['function']) ) |
230 | | $args[0] = call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args'])); |
231 | | |
232 | | } while ( next($wp_filter[$tag]) !== false ); |
233 | | |
234 | | array_pop( $wp_current_filter ); |
235 | | |
236 | | return $args[0]; |
237 | | } |
238 | | |
239 | | /** |
240 | | * Removes a function from a specified filter hook. |
241 | | * |
242 | | * This function removes a function attached to a specified filter hook. This |
243 | | * method can be used to remove default functions attached to a specific filter |
244 | | * hook and possibly replace them with a substitute. |
245 | | * |
246 | | * To remove a hook, the $function_to_remove and $priority arguments must match |
247 | | * when the hook was added. This goes for both filters and actions. No warning |
248 | | * will be given on removal failure. |
249 | | * |
250 | | * @package WordPress |
251 | | * @subpackage Plugin |
252 | | * @since 1.2 |
253 | | * |
254 | | * @param string $tag The filter hook to which the function to be removed is hooked. |
255 | | * @param callback $function_to_remove The name of the function which should be removed. |
256 | | * @param int $priority optional. The priority of the function (default: 10). |
257 | | * @param int $accepted_args optional. The number of arguments the function accepts (default: 1). |
258 | | * @return boolean Whether the function existed before it was removed. |
259 | | */ |
260 | | function remove_filter( $tag, $function_to_remove, $priority = 10 ) { |
261 | | $function_to_remove = _wp_filter_build_unique_id($tag, $function_to_remove, $priority); |
262 | | |
263 | | $r = isset($GLOBALS['wp_filter'][$tag][$priority][$function_to_remove]); |
264 | | |
265 | | if ( true === $r) { |
266 | | unset($GLOBALS['wp_filter'][$tag][$priority][$function_to_remove]); |
267 | | if ( empty($GLOBALS['wp_filter'][$tag][$priority]) ) |
268 | | unset($GLOBALS['wp_filter'][$tag][$priority]); |
269 | | unset($GLOBALS['merged_filters'][$tag]); |
270 | | } |
271 | | |
272 | | return $r; |
273 | | } |
274 | | |
275 | | /** |
276 | | * Remove all of the hooks from a filter. |
277 | | * |
278 | | * @since 2.7 |
279 | | * |
280 | | * @param string $tag The filter to remove hooks from. |
281 | | * @param int $priority The priority number to remove. |
282 | | * @return bool True when finished. |
283 | | */ |
284 | | function remove_all_filters($tag, $priority = false) { |
285 | | global $wp_filter, $merged_filters; |
286 | | |
287 | | if( isset($wp_filter[$tag]) ) { |
288 | | if( false !== $priority && isset($wp_filter[$tag][$priority]) ) |
289 | | unset($wp_filter[$tag][$priority]); |
290 | | else |
291 | | unset($wp_filter[$tag]); |
292 | | } |
293 | | |
294 | | if( isset($merged_filters[$tag]) ) |
295 | | unset($merged_filters[$tag]); |
296 | | |
297 | | return true; |
298 | | } |
299 | | |
300 | | /** |
301 | | * Retrieve the name of the current filter or action. |
302 | | * |
303 | | * @package WordPress |
304 | | * @subpackage Plugin |
305 | | * @since 2.5 |
306 | | * |
307 | | * @return string Hook name of the current filter or action. |
308 | | */ |
309 | | function current_filter() { |
310 | | global $wp_current_filter; |
311 | | return end( $wp_current_filter ); |
312 | | } |
313 | | |
314 | | /** |
315 | | * Hooks a function on to a specific action. |
316 | | * |
317 | | * Actions are the hooks that the WordPress core launches at specific points |
318 | | * during execution, or when specific events occur. Plugins can specify that |
319 | | * one or more of its PHP functions are executed at these points, using the |
320 | | * Action API. |
321 | | * |
322 | | * @uses add_filter() Adds an action. Parameter list and functionality are the same. |
323 | | * |
324 | | * @package WordPress |
325 | | * @subpackage Plugin |
326 | | * @since 1.2 |
327 | | * |
328 | | * @param string $tag The name of the action to which the $function_to_add is hooked. |
329 | | * @param callback $function_to_add The name of the function you wish to be called. |
330 | | * @param int $priority optional. Used to specify the order in which the functions associated with a particular action are executed (default: 10). Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action. |
331 | | * @param int $accepted_args optional. The number of arguments the function accept (default 1). |
332 | | */ |
333 | | function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) { |
334 | | return add_filter($tag, $function_to_add, $priority, $accepted_args); |
335 | | } |
336 | | |
337 | | /** |
338 | | * Execute functions hooked on a specific action hook. |
339 | | * |
340 | | * This function invokes all functions attached to action hook $tag. It is |
341 | | * possible to create new action hooks by simply calling this function, |
342 | | * specifying the name of the new hook using the <tt>$tag</tt> parameter. |
343 | | * |
344 | | * You can pass extra arguments to the hooks, much like you can with |
345 | | * apply_filters(). |
346 | | * |
347 | | * @see apply_filters() This function works similar with the exception that |
348 | | * nothing is returned and only the functions or methods are called. |
349 | | * |
350 | | * @package WordPress |
351 | | * @subpackage Plugin |
352 | | * @since 1.2 |
353 | | * @global array $wp_filter Stores all of the filters |
354 | | * @global array $wp_actions Increments the amount of times action was triggered. |
355 | | * |
356 | | * @param string $tag The name of the action to be executed. |
357 | | * @param mixed $arg,... Optional additional arguments which are passed on to the functions hooked to the action. |
358 | | * @return null Will return null if $tag does not exist in $wp_filter array |
359 | | */ |
360 | | function do_action($tag, $arg = '') { |
361 | | global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter; |
362 | | |
363 | | if ( ! isset($wp_actions) ) |
364 | | $wp_actions = array(); |
365 | | |
366 | | if ( ! isset($wp_actions[$tag]) ) |
367 | | $wp_actions[$tag] = 1; |
368 | | else |
369 | | ++$wp_actions[$tag]; |
370 | | |
371 | | // Do 'all' actions first |
372 | | if ( isset($wp_filter['all']) ) { |
373 | | $wp_current_filter[] = $tag; |
374 | | $all_args = func_get_args(); |
375 | | _wp_call_all_hook($all_args); |
376 | | } |
377 | | |
378 | | if ( !isset($wp_filter[$tag]) ) { |
379 | | if ( isset($wp_filter['all']) ) |
380 | | array_pop($wp_current_filter); |
381 | | return; |
382 | | } |
383 | | |
384 | | if ( !isset($wp_filter['all']) ) |
385 | | $wp_current_filter[] = $tag; |
386 | | |
387 | | $args = array(); |
388 | | if ( is_array($arg) && 1 == count($arg) && isset($arg[0]) && is_object($arg[0]) ) // array(&$this) |
389 | | $args[] =& $arg[0]; |
390 | | else |
391 | | $args[] = $arg; |
392 | | for ( $a = 2; $a < func_num_args(); $a++ ) |
393 | | $args[] = func_get_arg($a); |
394 | | |
395 | | // Sort |
396 | | if ( !isset( $merged_filters[ $tag ] ) ) { |
397 | | ksort($wp_filter[$tag]); |
398 | | $merged_filters[ $tag ] = true; |
399 | | } |
400 | | |
401 | | reset( $wp_filter[ $tag ] ); |
402 | | |
403 | | do { |
404 | | foreach ( (array) current($wp_filter[$tag]) as $the_ ) |
405 | | if ( !is_null($the_['function']) ) |
406 | | call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args'])); |
407 | | |
408 | | } while ( next($wp_filter[$tag]) !== false ); |
409 | | |
410 | | array_pop($wp_current_filter); |
411 | | } |
412 | | |
413 | | /** |
414 | | * Retrieve the number of times an action is fired. |
415 | | * |
416 | | * @package WordPress |
417 | | * @subpackage Plugin |
418 | | * @since 2.1 |
419 | | * @global array $wp_actions Increments the amount of times action was triggered. |
420 | | * |
421 | | * @param string $tag The name of the action hook. |
422 | | * @return int The number of times action hook <tt>$tag</tt> is fired |
423 | | */ |
424 | | function did_action($tag) { |
425 | | global $wp_actions; |
426 | | |
427 | | if ( ! isset( $wp_actions ) || ! isset( $wp_actions[$tag] ) ) |
428 | | return 0; |
429 | | |
430 | | return $wp_actions[$tag]; |
431 | | } |
432 | | |
433 | | /** |
434 | | * Execute functions hooked on a specific action hook, specifying arguments in an array. |
435 | | * |
436 | | * @see do_action() This function is identical, but the arguments passed to the |
437 | | * functions hooked to <tt>$tag</tt> are supplied using an array. |
438 | | * |
439 | | * @package WordPress |
440 | | * @subpackage Plugin |
441 | | * @since 2.1 |
442 | | * @global array $wp_filter Stores all of the filters |
443 | | * @global array $wp_actions Increments the amount of times action was triggered. |
444 | | * |
445 | | * @param string $tag The name of the action to be executed. |
446 | | * @param array $args The arguments supplied to the functions hooked to <tt>$tag</tt> |
447 | | * @return null Will return null if $tag does not exist in $wp_filter array |
448 | | */ |
449 | | function do_action_ref_array($tag, $args) { |
450 | | global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter; |
451 | | |
452 | | if ( ! isset($wp_actions) ) |
453 | | $wp_actions = array(); |
454 | | |
455 | | if ( ! isset($wp_actions[$tag]) ) |
456 | | $wp_actions[$tag] = 1; |
457 | | else |
458 | | ++$wp_actions[$tag]; |
459 | | |
460 | | // Do 'all' actions first |
461 | | if ( isset($wp_filter['all']) ) { |
462 | | $wp_current_filter[] = $tag; |
463 | | $all_args = func_get_args(); |
464 | | _wp_call_all_hook($all_args); |
465 | | } |
466 | | |
467 | | if ( !isset($wp_filter[$tag]) ) { |
468 | | if ( isset($wp_filter['all']) ) |
469 | | array_pop($wp_current_filter); |
470 | | return; |
471 | | } |
472 | | |
473 | | if ( !isset($wp_filter['all']) ) |
474 | | $wp_current_filter[] = $tag; |
475 | | |
476 | | // Sort |
477 | | if ( !isset( $merged_filters[ $tag ] ) ) { |
478 | | ksort($wp_filter[$tag]); |
479 | | $merged_filters[ $tag ] = true; |
480 | | } |
481 | | |
482 | | reset( $wp_filter[ $tag ] ); |
483 | | |
484 | | do { |
485 | | foreach( (array) current($wp_filter[$tag]) as $the_ ) |
486 | | if ( !is_null($the_['function']) ) |
487 | | call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args'])); |
488 | | |
489 | | } while ( next($wp_filter[$tag]) !== false ); |
490 | | |
491 | | array_pop($wp_current_filter); |
492 | | } |
493 | | |
494 | | /** |
495 | | * Check if any action has been registered for a hook. |
496 | | * |
497 | | * @package WordPress |
498 | | * @subpackage Plugin |
499 | | * @since 2.5 |
500 | | * @see has_filter() has_action() is an alias of has_filter(). |
501 | | * |
502 | | * @param string $tag The name of the action hook. |
503 | | * @param callback $function_to_check optional. |
504 | | * @return mixed If $function_to_check is omitted, returns boolean for whether the hook has anything registered. |
505 | | * When checking a specific function, the priority of that hook is returned, or false if the function is not attached. |
506 | | * When using the $function_to_check argument, this function may return a non-boolean value that evaluates to false |
507 | | * (e.g.) 0, so use the === operator for testing the return value. |
508 | | */ |
509 | | function has_action($tag, $function_to_check = false) { |
510 | | return has_filter($tag, $function_to_check); |
511 | | } |
512 | | |
513 | | /** |
514 | | * Removes a function from a specified action hook. |
515 | | * |
516 | | * This function removes a function attached to a specified action hook. This |
517 | | * method can be used to remove default functions attached to a specific filter |
518 | | * hook and possibly replace them with a substitute. |
519 | | * |
520 | | * @package WordPress |
521 | | * @subpackage Plugin |
522 | | * @since 1.2 |
523 | | * |
524 | | * @param string $tag The action hook to which the function to be removed is hooked. |
525 | | * @param callback $function_to_remove The name of the function which should be removed. |
526 | | * @param int $priority optional The priority of the function (default: 10). |
527 | | * @return boolean Whether the function is removed. |
528 | | */ |
529 | | function remove_action( $tag, $function_to_remove, $priority = 10 ) { |
530 | | return remove_filter( $tag, $function_to_remove, $priority ); |
531 | | } |
532 | | |
533 | | /** |
534 | | * Remove all of the hooks from an action. |
535 | | * |
536 | | * @since 2.7 |
537 | | * |
538 | | * @param string $tag The action to remove hooks from. |
539 | | * @param int $priority The priority number to remove them from. |
540 | | * @return bool True when finished. |
541 | | */ |
542 | | function remove_all_actions($tag, $priority = false) { |
543 | | return remove_all_filters($tag, $priority); |
544 | | } |
545 | | |