root/trunk/wp-includes/plugin.php

Revision 6726, 20.9 kB (checked in by ryan, 3 months ago)

Trailing whitespace cleanup

  • Property svn:eol-style set to native
Line 
1 <?php
2 /**
3  * The plugin API is located in this file, which allows for creating actions
4  * and filters and hooking functions, and methods. The functions or methods will
5  * then be run when the action or filter is called.
6  *
7  * The API callback examples reference functions, but can be methods of classes.
8  * To hook methods, you'll need to pass an array one of two ways.
9  *
10  * Any of the syntaxes explained in the PHP documentation for the
11  * {@link http://us2.php.net/manual/en/language.pseudo-types.php#language.types.callback 'callback'}
12  * type are valid.
13  *
14  * Also see the {@link http://codex.wordpress.org/Plugin_API Plugin API} for more information
15  * and examples on how to use a lot of these functions.
16  *
17  * @package WordPress
18  * @subpackage Plugin
19  * @since 1.5
20  */
21
22 /**
23  * add_filter() - 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 filter
31  * <code>
32  * function example_hook($example) { echo $example; }
33  *
34  * add_filter('example_filter', 'example_hook');
35  * </code>
36  *
37  * In WordPress 1.5.1+, hooked functions can take extra arguments that are set when
38  * the matching do_action() or apply_filters() call is run. The <tt>$accepted_args
39  * allow for calling functions only when the number of args match. Hooked functions
40  * can take extra arguments that are set when the matching <tt>do_action()</tt> or
41  * <tt>apply_filters()</tt> call is run. For example, the action <tt>comment_id_not_found</tt>
42  * will pass any functions that hook onto it the ID of the requested comment.
43  *
44  * <strong>Note:</strong> the function will return true no matter if the function was hooked
45  * fails or not. There are no checks for whether the function exists beforehand and no checks
46  * to whether the <tt>$function_to_add is even a string. It is up to you to take care and
47  * this is done for optimization purposes, so everything is as quick as possible.
48  *
49  * @package WordPress
50  * @subpackage Plugin
51  * @since 0.71
52  * @global array $wp_filter Stores all of the filters added in the form of
53  *    wp_filter['tag']['array of priorities']['array of functions serialized']['array of ['array (functions, accepted_args)]']
54  * @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.
55  *
56  * @param string $tag The name of the filter to hook the <tt>$function_to_add</tt> to.
57  * @param callback $function_to_add The name of the function to be called when the filter is applied.
58  * @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.
59  * @param int $accepted_args optional. The number of arguments the function accept (default 1).
60  * @return boolean true
61  */
62 function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
63     global $wp_filter, $merged_filters;
64
65     $idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority);
66     $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args);
67     unset( $merged_filters[ $tag ] );
68     return true;
69 }
70
71 /**
72  * has_filter() - Check if any filter has been registered for a hook.
73  *
74  * @package WordPress
75  * @subpackage Plugin
76  * @since 2.5
77  * @global array $wp_filter Stores all of the filters
78  *
79  * @param string $tag The name of the filter hook.
80  * @param callback $function_to_check optional.  If specified, return the priority of that function on this hook or false if not attached.
81  * @return int|boolean Optionally returns the priority on that hook for the specified function.
82  */
83 function has_filter($tag, $function_to_check = false) {
84     global $wp_filter;
85
86     $has = !empty($wp_filter[$tag]);
87     if ( false === $function_to_check || false == $has )
88         return $has;
89
90     if ( !$idx = _wp_filter_build_unique_id($tag, $function_to_check, false) )
91         return false;
92
93     foreach ( array_keys($wp_filter[$tag]) as $priority ) {
94         if ( isset($wp_filter[$tag][$priority][$idx]) )
95             return $priority;
96     }
97
98     return false;
99 }
100
101 /**
102  * apply_filters() - Call the functions added to a filter hook.
103  *
104  * The callback functions attached to filter hook <tt>$tag</tt> are invoked by
105  * calling this function. This function can be used to create a new filter hook
106  * by simply calling this function with the name of the new hook specified using
107  * the <tt>$tag</a> parameter.
108  *
109  * The function allows for additional arguments to be added and passed to hooks.
110  * <code>
111  * function example_hook($string, $arg1, $arg2)
112  * {
113  *        //Do stuff
114  *        return $string;
115  * }
116  * $value = apply_filters('example_filter', 'filter me', 'arg1', 'arg2');
117  * </code>
118  *
119  * @package WordPress
120  * @subpackage Plugin
121  * @since 0.71
122  * @global array $wp_filter Stores all of the filters
123  * @global array $merge_filters Merges the filter hooks using this function.
124  * @global array $wp_current_filter stores the list of current filters with the current one last
125  *
126  * @param string $tag The name of the filter hook.
127  * @param mixed $value The value on which the filters hooked to <tt>$tag</tt> are applied on.
128  * @param mixed $var,... Additional variables passed to the functions hooked to <tt>$tag</tt>.
129  * @return mixed The filtered value after all hooked functions are applied to it.
130  */
131 function apply_filters($tag, $value) {
132     global $wp_filter, $merged_filters, $wp_current_filter;
133
134     $args = array();
135     $wp_current_filter[] = $tag;
136
137     // Do 'all' actions first
138     if ( isset($wp_filter['all']) ) {
139         $args = func_get_args();
140         _wp_call_all_hook($args);
141     }
142
143     if ( !isset($wp_filter[$tag]) ) {
144         array_pop($wp_current_filter);
145         return $value;
146     }
147
148     // Sort
149     if ( !isset( $merged_filters[ $tag ] ) ) {
150         ksort($wp_filter[$tag]);
151         $merged_filters[ $tag ] = true;
152     }
153
154     reset( $wp_filter[ $tag ] );
155
156     if ( empty($args) )
157         $args = func_get_args();
158
159     do {
160         foreach( (array) current($wp_filter[$tag]) as $the_ )
161             if ( !is_null($the_['function']) ){
162                 $args[1] = $value;
163                 $value = call_user_func_array($the_['function'], array_slice($args, 1, (int) $the_['accepted_args']));
164             }
165
166     } while ( next($wp_filter[$tag]) !== false );
167
168     array_pop( $wp_current_filter );
169
170     return $value;
171 }
172
173 /**
174  * remove_filter() - Removes a function from a specified filter hook.
175  *
176  * This function removes a function attached to a specified filter hook. This
177  * method can be used to remove default functions attached to a specific filter
178  * hook and possibly replace them with a substitute.
179  *
180  * To remove a hook, the <tt>$function_to_remove</tt> and <tt>$priority</tt> arguments
181  * must match when the hook was added. This goes for both filters and actions. No warning
182  * will be given on removal failure.
183  *
184  * @package WordPress
185  * @subpackage Plugin
186  * @since 1.2
187  *
188  * @param string $tag The filter hook to which the function to be removed is hooked.
189  * @param callback $function_to_remove The name of the function which should be removed.
190  * @param int $priority optional. The priority of the function (default: 10).
191  * @param int $accepted_args optional. The number of arguments the function accpets (default: 1).
192  * @return boolean Whether the function existed before it was removed.
193  */
194 function remove_filter($tag, $function_to_remove, $priority = 10, $accepted_args = 1) {
195     $function_to_remove = _wp_filter_build_unique_id($tag, $function_to_remove, $priority);
196
197     $r = isset($GLOBALS['wp_filter'][$tag][$priority][$function_to_remove]);
198
199     if ( true === $r) {
200         unset($GLOBALS['wp_filter'][$tag][$priority][$function_to_remove]);
201         if ( empty($GLOBALS['wp_filter'][$tag][$priority]) )
202             unset($GLOBALS['wp_filter'][$tag][$priority]);
203         unset($GLOBALS['merged_filters'][$tag]);
204     }
205
206     return $r;
207 }
208
209
210 /**
211  * current_filter() - Return the name of the current filter or action.
212  *
213  * @package WordPress
214  * @subpackage Plugin
215  * @since 2.5
216  *
217  * @return string Hook name of the current filter or action.
218  */
219 function current_filter() {
220     global $wp_current_filter;
221     return end( $wp_current_filter );
222 }
223
224
225 /**
226  * add_action() - Hooks a function on to a specific action.
227  *
228  * Actions are the hooks that the WordPress core launches at specific points
229  * during execution, or when specific events occur. Plugins can specify that
230  * one or more of its PHP functions are executed at these points, using the
231  * Action API.
232  *
233  * @uses add_filter() Adds an action. Parameter list and functionality are the same.
234  *
235  * @package WordPress
236  * @subpackage Plugin
237  * @since 1.2
238  *
239  * @param string $tag The name of the action to which the <tt>$function_to-add</tt> is hooked.
240  * @param callback $function_to_add The name of the function you wish to be called.
241  * @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.
242  * @param int $accepted_args optional. The number of arguments the function accept (default 1).
243  */
244 function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
245     return add_filter($tag, $function_to_add, $priority, $accepted_args);
246 }
247
248
249 /**
250  * do_action() - Execute functions hooked on a specific action hook.
251  *
252  * This function invokes all functions attached to action hook <tt>$tag</tt>.
253  * It is possible to create new action hooks by simply calling this function,
254  * specifying the name of the new hook using the <tt>$tag</tt> parameter.
255  *
256  * You can pass extra arguments to the hooks, much like you can with apply_filters().
257  *
258  * @see apply_filters() This function works similar with the exception that nothing is
259  * returned and only the functions or methods are called.
260  *
261  * @package WordPress
262  * @subpackage Plugin
263  * @since 1.2
264  * @global array $wp_filter Stores all of the filters
265  * @global array $wp_actions Increments the amount of times action was triggered.
266  *
267  * @param string $tag The name of the action to be executed.
268  * @param mixed $arg,... Optional additional arguments which are passed on to the functions hooked to the action.
269  * @return null Will return null if $tag does not exist in $wp_filter array
270  */
271 function do_action($tag, $arg = '') {
272     global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;
273
274     if ( is_array($wp_actions) )
275         $wp_actions[] = $tag;
276     else
277         $wp_actions = array($tag);
278
279     $wp_current_filter[] = $tag;
280
281     // Do 'all' actions first
282     if ( isset($wp_filter['all']) ) {
283         $all_args = func_get_args();
284         _wp_call_all_hook($all_args);
285     }
286
287     if ( !isset($wp_filter[$tag]) ) {
288         array_pop($wp_current_filter);
289         return;
290     }
291
292     $args = array();
293     if ( is_array($arg) && 1 == count($arg) && is_object($arg[0]) ) // array(&$this)
294         $args[] =& $arg[0];
295     else
296         $args[] = $arg;
297     for ( $a = 2; $a < func_num_args(); $a++ )
298         $args[] = func_get_arg($a);
299
300     // Sort
301     if ( !isset( $merged_filters[ $tag ] ) ) {
302         ksort($wp_filter[$tag]);
303         $merged_filters[ $tag ] = true;
304     }
305
306     reset( $wp_filter[ $tag ] );
307
308     do {
309         foreach ( (array) current($wp_filter[$tag]) as $the_ )
310             if ( !is_null($the_['function']) )
311                 call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
312
313     } while ( next($wp_filter[$tag]) !== false );
314
315     array_pop($wp_current_filter);
316 }
317
318 /**
319  * did_action() - Return the number times an action is fired.
320  *
321  * @package WordPress
322  * @subpackage Plugin
323  * @since 2.1
324  * @global array $wp_actions Increments the amount of times action was triggered.
325  *
326  * @param string $tag The name of the action hook.
327  * @return int The number of times action hook <tt>$tag</tt> is fired
328  */
329 function did_action($tag) {
330     global $wp_actions;
331
332     if ( empty($wp_actions) )
333         return 0;
334
335     return count(array_keys($wp_actions, $tag));
336 }
337
338 /**
339  * do_action_ref_array() - Execute functions hooked on a specific action hook, specifying arguments in an array.
340  *
341  * @see do_action() This function is identical, but the arguments passed to
342  * the functions hooked to <tt>$tag</tt> are supplied using an array.
343  *
344  * @package WordPress
345  * @subpackage Plugin
346  * @since 2.1
347  * @global array $wp_filter Stores all of the filters
348  * @global array $wp_actions Increments the amount of times action was triggered.
349  *
350  * @param string $tag The name of the action to be executed.
351  * @param array $args The arguments supplied to the functions hooked to <tt>$tag</tt>
352  * @return null Will return null if $tag does not exist in $wp_filter array
353  */
354 function do_action_ref_array($tag, $args) {
355     global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;
356
357     if ( !is_array($wp_actions) )
358         $wp_actions = array($tag);
359     else
360         $wp_actions[] = $tag;
361
362     $wp_current_filter[] = $tag;
363
364     // Do 'all' actions first
365     if ( isset($wp_filter['all']) ) {
366         $all_args = func_get_args();
367         _wp_call_all_hook($all_args);
368     }
369
370     if ( !isset($wp_filter[$tag]) ) {
371         array_pop($wp_current_filter);
372         return;
373     }
374
375     // Sort
376     if ( !isset( $merged_filters[ $tag ] ) ) {
377         ksort($wp_filter[$tag]);
378         $merged_filters[ $tag ] = true;
379     }
380
381     reset( $wp_filter[ $tag ] );
382
383     do {
384         foreach( (array) current($wp_filter[$tag]) as $the_ )
385             if ( !is_null($the_['function']) )
386                 call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
387
388     } while ( next($wp_filter[$tag]) !== false );
389
390     array_pop($wp_current_filter);
391 }
392
393 /**
394  * has_action() - Check if any action has been registered for a hook.
395  *
396  * @package WordPress
397  * @subpackage Plugin
398  * @since 2.5
399  * @see has_filter() has_action() is an alias of has_filter().
400  *
401  * @param string $tag The name of the action hook.
402  * @param callback $function_to_check optional.  If specified, return the priority of that function on this hook or false if not attached.
403  * @return int|boolean Optionally returns the priority on that hook for the specified function.
404  */
405 function has_action($tag, $function_to_check = false) {
406     return has_filter($tag, $function_to_check);
407 }
408
409 /**
410  * remove_action() - Removes a function from a specified action hook.
411  *
412  * This function removes a function attached to a specified action hook. This
413  * method can be used to remove default functions attached to a specific filter
414  * hook and possibly replace them with a substitute.
415  *
416  * @package WordPress
417  * @subpackage Plugin
418  * @since 1.2
419  *
420  * @param string $tag The action hook to which the function to be removed is hooked.
421  * @param callback $function_to_remove The name of the function which should be removed.
422  * @param int $priority optional The priority of the function (default: 10).
423  * @param int $accepted_args optional. The number of arguments the function accpets (default: 1).
424  * @return boolean Whether the function is removed.
425  */
426 function remove_action($tag, $function_to_remove, $priority = 10, $accepted_args = 1) {
427     return remove_filter($tag, $function_to_remove, $priority, $accepted_args);
428 }
429
430 //
431 // Functions for handling plugins.
432 //
433
434 /**
435  * plugin_basename() - Gets the basename of a plugin.
436  *
437  * This method extract the name of a plugin from its filename.
438  *
439  * @package WordPress
440  * @subpackage Plugin
441  * @since 1.5
442  *
443  * @access private
444  *
445  * @param string $file The filename of plugin.
446  * @return string The name of a plugin.
447  */
448 function plugin_basename($file) {
449     $file = str_replace('\\','/',$file); // sanitize for Win32 installs
450     $file = preg_replace('|/+|','/', $file); // remove any duplicate slash
451     $file = preg_replace('|^.*/' . PLUGINDIR . '/|','',$file); // get relative path from plugins dir
452     return $file;
453 }
454
455 /**
456  * register_activation_hook() - Hook a function on a plugin activation action hook.
457  *
458  * When a plugin is activated, the action 'activate_PLUGINNAME' hook is
459  * activated. In the name of this hook, PLUGINNAME is replaced with the name of
460  * the plugin, including the optional subdirectory. For example, when the plugin
461  * is located in <tt>wp-content/plugin/sampleplugin/sample.php</tt>, then the
462  * name of this hook will become 'activate_sampleplugin/sample.php'
463  * When the plugin consists of only one file and is (as by default) located at
464  * <tt>wp-content/plugin/sample.php</tt> the name of this hook will be
465  * 'activate_sample.php'.
466  *
467  * @package WordPress
468  * @subpackage Plugin
469  * @since 2.0
470  *
471  * @access private
472  *
473  * @param string $file The filename of the plugin including the path.
474  * @param string $function the function hooked to the 'activate_PLUGIN' action.
475  */
476 function register_activation_hook($file, $function) {
477     $file = plugin_basename($file);
478     add_action('activate_' . $file, $function);
479 }
480
481 /**
482  * register_deactivation_hook() - Hook a function on a plugin deactivation action hook.
483  *
484  * When a plugin is deactivated, the action 'deactivate_PLUGINNAME' hook is
485  * deactivated. In the name of this hook, PLUGINNAME is replaced with the name of
486  * the plugin, including the optional subdirectory. For example, when the plugin
487  * is located in <tt>wp-content/plugin/sampleplugin/sample.php</tt>, then the
488  * name of this hook will become 'activate_sampleplugin/sample.php'.
489  * When the plugin consists of only one file and is (as by default) located at
490  * <tt>wp-content/plugin/sample.php</tt> the name of this hook will be
491  * 'activate_sample.php'.
492  *
493  * @package WordPress
494  * @subpackage Plugin
495  * @since 2.0
496  *
497  * @access private
498  *
499  * @param string $file The filename of the plugin including the path.
500  * @param string $function the function hooked to the 'activate_PLUGIN' action.
501  */
502 function register_deactivation_hook($file, $function) {
503     $file = plugin_basename($file);
504     add_action('deactivate_' . $file, $function);
505 }
506
507 /**
508  * _wp_call_all_hook() - Calls the 'all' hook, which will process the functions hooked into it.
509  *
510  * The 'all' hook passes all of the arguments or parameters that were used for the
511  * hook, which this function was called for.
512  *
513  * This function is used internally for apply_filters(), do_action(), and do_action_ref_array()
514  * and is not meant to be used from outside those functions. This function does not check for the
515  * existence of the all hook, so it will fail unless the all hook exists prior to this function call.
516  *
517  * @package WordPress
518  * @subpackage Plugin
519  * @since 2.5
520  * @access private
521  *
522  * @uses $wp_filter Used to process all of the functions in the 'all' hook
523  *
524  * @param array $args The collected parameters from the hook that was called.
525  * @param string $hook Optional. The hook name that was used to call the 'all' hook.
526  */
527 function _wp_call_all_hook($args) {
528     global $wp_filter;
529
530     reset( $wp_filter['all'] );
531     do {
532         foreach( (array) current($wp_filter['all']) as $the_ )
533             if ( !is_null($the_['function']) )
534                 call_user_func_array($the_['function'], $args);
535
536     } while ( next($wp_filter['all']) !== false );
537 }
538
539 /**
540  * _wp_filter_build_unique_id() - Build Unique ID for storage and retrieval
541  *
542  * The old way to serialize the callback caused issues and this function is the
543  * solution. It works by checking for objects and creating an a new property in
544  * the class to keep track of the object and new objects of the same class that
545  * need to be added.
546  *
547  * It also allows for the removal of actions and filters for objects after they
548  * change class properties. It is possible to include the property $wp_filter_id
549  * in your class and set it to "null" or a number to bypass the workaround. However
550  * this will prevent you from adding new classes and any new classes will overwrite
551  * the previous hook by the same class.
552  *
553  * Functions and static method callbacks are just returned as strings and shouldn't
554  * have any speed penalty.
555  *
556  * @package WordPress
557  * @subpackage Plugin
558  * @since 2.2.3
559  *
560  * @link http://trac.wordpress.org/ticket/3875
561  *
562  * @access private
563  *
564  * @global array $wp_filter Storage for all of the filters and actions
565  * @param string $tag Used in counting how many hooks were applied
566  * @param string|array $function Used for creating unique id
567  * @param int|bool $priority Used in counting how many hooks were applied.  If === false and $function is an object reference, we return the unique id only if it already has one, false otherwise.
568  * @param string $type filter or action
569  * @return string Unique ID for usage as array key
570  */
571 function _wp_filter_build_unique_id($tag, $function, $priority) {
572     global $wp_filter;
573
574     // If function then just skip all of the tests and not overwrite the following.
575     if ( is_string($function) )
576         return $function;
577     // Object Class Calling
578     else if (is_object($function[0]) ) {
579         $obj_idx = get_class($function[0]).$function[1];
580         if ( !isset($function[0]->wp_filter_id) ) {
581             if ( false === $priority )
582                 return false;
583             $count = count((array)$wp_filter[$tag][$priority]);
584             $function[0]->wp_filter_id = $count;
585             $obj_idx .= $count;
586             unset($count);
587         } else
588             $obj_idx .= $function[0]->wp_filter_id;
589         return $obj_idx;
590     }
591     // Static Calling
592     else if ( is_string($function[0]) )
593         return $function[0].$function[1];
594 }
595
596 ?>
597
Note: See TracBrowser for help on using the browser.