wp/wp-includes/plugin.php
changeset 7 cf61fcea0001
parent 5 5e2f62d02dcd
child 9 177826044cd9
equal deleted inserted replaced
6:490d5cc509ed 7:cf61fcea0001
     6  *
     6  *
     7  * The API callback examples reference functions, but can be methods of classes.
     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.
     8  * To hook methods, you'll need to pass an array one of two ways.
     9  *
     9  *
    10  * Any of the syntaxes explained in the PHP documentation for the
    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'}
    11  * {@link https://secure.php.net/manual/en/language.pseudo-types.php#language.types.callback 'callback'}
    12  * type are valid.
    12  * type are valid.
    13  *
    13  *
    14  * Also see the {@link https://codex.wordpress.org/Plugin_API Plugin API} for
    14  * Also see the {@link https://codex.wordpress.org/Plugin_API Plugin API} for
    15  * more information and examples on how to use a lot of these functions.
    15  * more information and examples on how to use a lot of these functions.
       
    16  *
       
    17  * This file should have no external dependencies.
    16  *
    18  *
    17  * @package WordPress
    19  * @package WordPress
    18  * @subpackage Plugin
    20  * @subpackage Plugin
    19  * @since 1.5.0
    21  * @since 1.5.0
    20  */
    22  */
    21 
    23 
    22 // Initialize the filter globals.
    24 // Initialize the filter globals.
    23 global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;
    25 require( dirname( __FILE__ ) . '/class-wp-hook.php' );
    24 
    26 
    25 if ( ! isset( $wp_filter ) )
    27 /** @var WP_Hook[] $wp_filter */
       
    28 global $wp_filter, $wp_actions, $wp_current_filter;
       
    29 
       
    30 if ( $wp_filter ) {
       
    31 	$wp_filter = WP_Hook::build_preinitialized_hooks( $wp_filter );
       
    32 } else {
    26 	$wp_filter = array();
    33 	$wp_filter = array();
       
    34 }
    27 
    35 
    28 if ( ! isset( $wp_actions ) )
    36 if ( ! isset( $wp_actions ) )
    29 	$wp_actions = array();
    37 	$wp_actions = array();
    30 
       
    31 if ( ! isset( $merged_filters ) )
       
    32 	$merged_filters = array();
       
    33 
    38 
    34 if ( ! isset( $wp_current_filter ) )
    39 if ( ! isset( $wp_current_filter ) )
    35 	$wp_current_filter = array();
    40 	$wp_current_filter = array();
    36 
    41 
    37 /**
    42 /**
    48  *
    53  *
    49  * Note that `$example` is passed to the callback, (maybe) modified, then returned:
    54  * Note that `$example` is passed to the callback, (maybe) modified, then returned:
    50  *
    55  *
    51  *     function example_callback( $example ) {
    56  *     function example_callback( $example ) {
    52  *         // Maybe modify $example in some way.
    57  *         // Maybe modify $example in some way.
    53  *     	   return $example;
    58  *         return $example;
    54  *     }
    59  *     }
    55  *     add_filter( 'example_filter', 'example_callback' );
    60  *     add_filter( 'example_filter', 'example_callback' );
    56  *
    61  *
    57  * Since WordPress 1.5.1, bound callbacks can take as many arguments as are
    62  * Bound callbacks can accept from none to the total number of arguments passed as parameters
    58  * passed as parameters in the corresponding apply_filters() call. The `$accepted_args`
    63  * in the corresponding apply_filters() call.
    59  * parameter allows for calling functions only when the number of args match.
    64  *
    60  *
    65  * In other words, if an apply_filters() call passes four total arguments, callbacks bound to
    61  * *Note:* the function will return true whether or not the callback is valid.
    66  * it can accept none (the same as 1) of the arguments or up to four. The important part is that
    62  * It is up to you to take care. This is done for optimization purposes,
    67  * the `$accepted_args` value must reflect the number of arguments the bound callback *actually*
    63  * so everything is as quick as possible.
    68  * opted to accept. If no arguments were accepted by the callback that is considered to be the
       
    69  * same as accepting 1 argument. For example:
       
    70  *
       
    71  *     // Filter call.
       
    72  *     $value = apply_filters( 'hook', $value, $arg2, $arg3 );
       
    73  *
       
    74  *     // Accepting zero/one arguments.
       
    75  *     function example_callback() {
       
    76  *         ...
       
    77  *         return 'some value';
       
    78  *     }
       
    79  *     add_filter( 'hook', 'example_callback' ); // Where $priority is default 10, $accepted_args is default 1.
       
    80  *
       
    81  *     // Accepting two arguments (three possible).
       
    82  *     function example_callback( $value, $arg2 ) {
       
    83  *         ...
       
    84  *         return $maybe_modified_value;
       
    85  *     }
       
    86  *     add_filter( 'hook', 'example_callback', 10, 2 ); // Where $priority is 10, $accepted_args is 2.
       
    87  *
       
    88  * *Note:* The function will return true whether or not the callback is valid.
       
    89  * It is up to you to take care. This is done for optimization purposes, so
       
    90  * everything is as quick as possible.
    64  *
    91  *
    65  * @since 0.71
    92  * @since 0.71
    66  *
    93  *
    67  * @global array $wp_filter      A multidimensional array of all hooks and the callbacks hooked to them.
    94  * @global array $wp_filter      A multidimensional array of all hooks and the callbacks hooked to them.
    68  * @global array $merged_filters Tracks the tags that need to be merged for later. If the hook is added,
       
    69  *                               it doesn't need to run through that process.
       
    70  *
    95  *
    71  * @param string   $tag             The name of the filter to hook the $function_to_add callback to.
    96  * @param string   $tag             The name of the filter to hook the $function_to_add callback to.
    72  * @param callback $function_to_add The callback to be run when the filter is applied.
    97  * @param callable $function_to_add The callback to be run when the filter is applied.
    73  * @param int      $priority        Optional. Used to specify the order in which the functions
    98  * @param int      $priority        Optional. Used to specify the order in which the functions
    74  *                                  associated with a particular action are executed. Default 10.
    99  *                                  associated with a particular action are executed. Default 10.
    75  *                                  Lower numbers correspond with earlier execution,
   100  *                                  Lower numbers correspond with earlier execution,
    76  *                                  and functions with the same priority are executed
   101  *                                  and functions with the same priority are executed
    77  *                                  in the order in which they were added to the action.
   102  *                                  in the order in which they were added to the action.
    78  * @param int      $accepted_args   Optional. The number of arguments the function accepts. Default 1.
   103  * @param int      $accepted_args   Optional. The number of arguments the function accepts. Default 1.
    79  * @return boolean true
   104  * @return true
    80  */
   105  */
    81 function add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
   106 function add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
    82 	global $wp_filter, $merged_filters;
   107 	global $wp_filter;
    83 
   108 	if ( ! isset( $wp_filter[ $tag ] ) ) {
    84 	$idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority);
   109 		$wp_filter[ $tag ] = new WP_Hook();
    85 	$wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args);
   110 	}
    86 	unset( $merged_filters[ $tag ] );
   111 	$wp_filter[ $tag ]->add_filter( $tag, $function_to_add, $priority, $accepted_args );
    87 	return true;
   112 	return true;
    88 }
   113 }
    89 
   114 
    90 /**
   115 /**
    91  * Check if any filter has been registered for a hook.
   116  * Check if any filter has been registered for a hook.
    93  * @since 2.5.0
   118  * @since 2.5.0
    94  *
   119  *
    95  * @global array $wp_filter Stores all of the filters.
   120  * @global array $wp_filter Stores all of the filters.
    96  *
   121  *
    97  * @param string        $tag               The name of the filter hook.
   122  * @param string        $tag               The name of the filter hook.
    98  * @param callback|bool $function_to_check Optional. The callback to check for. Default false.
   123  * @param callable|bool $function_to_check Optional. The callback to check for. Default false.
    99  * @return bool|int If $function_to_check is omitted, returns boolean for whether the hook has
   124  * @return false|int If $function_to_check is omitted, returns boolean for whether the hook has
   100  *                  anything registered. When checking a specific function, the priority of that
   125  *                   anything registered. When checking a specific function, the priority of that
   101  *                  hook is returned, or false if the function is not attached. When using the
   126  *                   hook is returned, or false if the function is not attached. When using the
   102  *                  $function_to_check argument, this function may return a non-boolean value
   127  *                   $function_to_check argument, this function may return a non-boolean value
   103  *                  that evaluates to false (e.g.) 0, so use the === operator for testing the
   128  *                   that evaluates to false (e.g.) 0, so use the === operator for testing the
   104  *                  return value.
   129  *                   return value.
   105  */
   130  */
   106 function has_filter($tag, $function_to_check = false) {
   131 function has_filter($tag, $function_to_check = false) {
   107 	// Don't reset the internal array pointer
   132 	global $wp_filter;
   108 	$wp_filter = $GLOBALS['wp_filter'];
   133 
   109 
   134 	if ( ! isset( $wp_filter[ $tag ] ) ) {
   110 	$has = ! empty( $wp_filter[ $tag ] );
       
   111 
       
   112 	// Make sure at least one priority has a filter callback
       
   113 	if ( $has ) {
       
   114 		$exists = false;
       
   115 		foreach ( $wp_filter[ $tag ] as $callbacks ) {
       
   116 			if ( ! empty( $callbacks ) ) {
       
   117 				$exists = true;
       
   118 				break;
       
   119 			}
       
   120 		}
       
   121 
       
   122 		if ( ! $exists ) {
       
   123 			$has = false;
       
   124 		}
       
   125 	}
       
   126 
       
   127 	if ( false === $function_to_check || false == $has )
       
   128 		return $has;
       
   129 
       
   130 	if ( !$idx = _wp_filter_build_unique_id($tag, $function_to_check, false) )
       
   131 		return false;
   135 		return false;
   132 
   136 	}
   133 	foreach ( (array) array_keys($wp_filter[$tag]) as $priority ) {
   137 
   134 		if ( isset($wp_filter[$tag][$priority][$idx]) )
   138 	return $wp_filter[ $tag ]->has_filter( $tag, $function_to_check );
   135 			return $priority;
       
   136 	}
       
   137 
       
   138 	return false;
       
   139 }
   139 }
   140 
   140 
   141 /**
   141 /**
   142  * Call the functions added to a filter hook.
   142  * Call the functions added to a filter hook.
   143  *
   143  *
   164  *     $value = apply_filters( 'example_filter', 'filter me', $arg1, $arg2 );
   164  *     $value = apply_filters( 'example_filter', 'filter me', $arg1, $arg2 );
   165  *
   165  *
   166  * @since 0.71
   166  * @since 0.71
   167  *
   167  *
   168  * @global array $wp_filter         Stores all of the filters.
   168  * @global array $wp_filter         Stores all of the filters.
   169  * @global array $merged_filters    Merges the filter hooks using this function.
       
   170  * @global array $wp_current_filter Stores the list of current filters with the current one last.
   169  * @global array $wp_current_filter Stores the list of current filters with the current one last.
   171  *
   170  *
   172  * @param string $tag   The name of the filter hook.
   171  * @param string $tag     The name of the filter hook.
   173  * @param mixed  $value The value on which the filters hooked to `$tag` are applied on.
   172  * @param mixed  $value   The value on which the filters hooked to `$tag` are applied on.
   174  * @param mixed  $var   Additional variables passed to the functions hooked to `$tag`.
   173  * @param mixed  $var,... Additional variables passed to the functions hooked to `$tag`.
   175  * @return mixed The filtered value after all hooked functions are applied to it.
   174  * @return mixed The filtered value after all hooked functions are applied to it.
   176  */
   175  */
   177 function apply_filters( $tag, $value ) {
   176 function apply_filters( $tag, $value ) {
   178 	global $wp_filter, $merged_filters, $wp_current_filter;
   177 	global $wp_filter, $wp_current_filter;
   179 
   178 
   180 	$args = array();
   179 	$args = array();
   181 
   180 
   182 	// Do 'all' actions first.
   181 	// Do 'all' actions first.
   183 	if ( isset($wp_filter['all']) ) {
   182 	if ( isset($wp_filter['all']) ) {
   193 	}
   192 	}
   194 
   193 
   195 	if ( !isset($wp_filter['all']) )
   194 	if ( !isset($wp_filter['all']) )
   196 		$wp_current_filter[] = $tag;
   195 		$wp_current_filter[] = $tag;
   197 
   196 
   198 	// Sort.
       
   199 	if ( !isset( $merged_filters[ $tag ] ) ) {
       
   200 		ksort($wp_filter[$tag]);
       
   201 		$merged_filters[ $tag ] = true;
       
   202 	}
       
   203 
       
   204 	reset( $wp_filter[ $tag ] );
       
   205 
       
   206 	if ( empty($args) )
   197 	if ( empty($args) )
   207 		$args = func_get_args();
   198 		$args = func_get_args();
   208 
   199 
   209 	do {
   200 	// don't pass the tag name to WP_Hook
   210 		foreach( (array) current($wp_filter[$tag]) as $the_ )
   201 	array_shift( $args );
   211 			if ( !is_null($the_['function']) ){
   202 
   212 				$args[1] = $value;
   203 	$filtered = $wp_filter[ $tag ]->apply_filters( $value, $args );
   213 				$value = call_user_func_array($the_['function'], array_slice($args, 1, (int) $the_['accepted_args']));
       
   214 			}
       
   215 
       
   216 	} while ( next($wp_filter[$tag]) !== false );
       
   217 
   204 
   218 	array_pop( $wp_current_filter );
   205 	array_pop( $wp_current_filter );
   219 
   206 
   220 	return $value;
   207 	return $filtered;
   221 }
   208 }
   222 
   209 
   223 /**
   210 /**
   224  * Execute functions hooked on a specific filter hook, specifying arguments in an array.
   211  * Execute functions hooked on a specific filter hook, specifying arguments in an array.
   225  *
   212  *
   226  * @see 3.0.0
   213  * @since 3.0.0
   227  *
   214  *
   228  * @see apply_filters() This function is identical, but the arguments passed to the
   215  * @see apply_filters() This function is identical, but the arguments passed to the
   229  * functions hooked to `$tag` are supplied using an array.
   216  * functions hooked to `$tag` are supplied using an array.
   230  *
   217  *
   231  * @global array $wp_filter         Stores all of the filters
   218  * @global array $wp_filter         Stores all of the filters
   232  * @global array $merged_filters    Merges the filter hooks using this function.
       
   233  * @global array $wp_current_filter Stores the list of current filters with the current one last
   219  * @global array $wp_current_filter Stores the list of current filters with the current one last
   234  *
   220  *
   235  * @param string $tag  The name of the filter hook.
   221  * @param string $tag  The name of the filter hook.
   236  * @param array  $args The arguments supplied to the functions hooked to $tag.
   222  * @param array  $args The arguments supplied to the functions hooked to $tag.
   237  * @return mixed The filtered value after all hooked functions are applied to it.
   223  * @return mixed The filtered value after all hooked functions are applied to it.
   238  */
   224  */
   239 function apply_filters_ref_array($tag, $args) {
   225 function apply_filters_ref_array($tag, $args) {
   240 	global $wp_filter, $merged_filters, $wp_current_filter;
   226 	global $wp_filter, $wp_current_filter;
   241 
   227 
   242 	// Do 'all' actions first
   228 	// Do 'all' actions first
   243 	if ( isset($wp_filter['all']) ) {
   229 	if ( isset($wp_filter['all']) ) {
   244 		$wp_current_filter[] = $tag;
   230 		$wp_current_filter[] = $tag;
   245 		$all_args = func_get_args();
   231 		$all_args = func_get_args();
   253 	}
   239 	}
   254 
   240 
   255 	if ( !isset($wp_filter['all']) )
   241 	if ( !isset($wp_filter['all']) )
   256 		$wp_current_filter[] = $tag;
   242 		$wp_current_filter[] = $tag;
   257 
   243 
   258 	// Sort
   244 	$filtered = $wp_filter[ $tag ]->apply_filters( $args[0], $args );
   259 	if ( !isset( $merged_filters[ $tag ] ) ) {
       
   260 		ksort($wp_filter[$tag]);
       
   261 		$merged_filters[ $tag ] = true;
       
   262 	}
       
   263 
       
   264 	reset( $wp_filter[ $tag ] );
       
   265 
       
   266 	do {
       
   267 		foreach( (array) current($wp_filter[$tag]) as $the_ )
       
   268 			if ( !is_null($the_['function']) )
       
   269 				$args[0] = call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
       
   270 
       
   271 	} while ( next($wp_filter[$tag]) !== false );
       
   272 
   245 
   273 	array_pop( $wp_current_filter );
   246 	array_pop( $wp_current_filter );
   274 
   247 
   275 	return $args[0];
   248 	return $filtered;
   276 }
   249 }
   277 
   250 
   278 /**
   251 /**
   279  * Removes a function from a specified filter hook.
   252  * Removes a function from a specified filter hook.
   280  *
   253  *
   286  * when the hook was added. This goes for both filters and actions. No warning
   259  * when the hook was added. This goes for both filters and actions. No warning
   287  * will be given on removal failure.
   260  * will be given on removal failure.
   288  *
   261  *
   289  * @since 1.2.0
   262  * @since 1.2.0
   290  *
   263  *
       
   264  * @global array $wp_filter         Stores all of the filters
       
   265  *
   291  * @param string   $tag                The filter hook to which the function to be removed is hooked.
   266  * @param string   $tag                The filter hook to which the function to be removed is hooked.
   292  * @param callback $function_to_remove The name of the function which should be removed.
   267  * @param callable $function_to_remove The name of the function which should be removed.
   293  * @param int      $priority           Optional. The priority of the function. Default 10.
   268  * @param int      $priority           Optional. The priority of the function. Default 10.
   294  * @return boolean Whether the function existed before it was removed.
   269  * @return bool    Whether the function existed before it was removed.
   295  */
   270  */
   296 function remove_filter( $tag, $function_to_remove, $priority = 10 ) {
   271 function remove_filter( $tag, $function_to_remove, $priority = 10 ) {
   297 	$function_to_remove = _wp_filter_build_unique_id( $tag, $function_to_remove, $priority );
   272 	global $wp_filter;
   298 
   273 
   299 	$r = isset( $GLOBALS['wp_filter'][ $tag ][ $priority ][ $function_to_remove ] );
   274 	$r = false;
   300 
   275 	if ( isset( $wp_filter[ $tag ] ) ) {
   301 	if ( true === $r ) {
   276 		$r = $wp_filter[ $tag ]->remove_filter( $tag, $function_to_remove, $priority );
   302 		unset( $GLOBALS['wp_filter'][ $tag ][ $priority ][ $function_to_remove ] );
   277 		if ( ! $wp_filter[ $tag ]->callbacks ) {
   303 		if ( empty( $GLOBALS['wp_filter'][ $tag ][ $priority ] ) ) {
   278 			unset( $wp_filter[ $tag ] );
   304 			unset( $GLOBALS['wp_filter'][ $tag ][ $priority ] );
       
   305 		}
   279 		}
   306 		if ( empty( $GLOBALS['wp_filter'][ $tag ] ) ) {
       
   307 			$GLOBALS['wp_filter'][ $tag ] = array();
       
   308 		}
       
   309 		unset( $GLOBALS['merged_filters'][ $tag ] );
       
   310 	}
   280 	}
   311 
   281 
   312 	return $r;
   282 	return $r;
   313 }
   283 }
   314 
   284 
   315 /**
   285 /**
   316  * Remove all of the hooks from a filter.
   286  * Remove all of the hooks from a filter.
   317  *
   287  *
   318  * @since 2.7.0
   288  * @since 2.7.0
       
   289  *
       
   290  * @global array $wp_filter  Stores all of the filters
   319  *
   291  *
   320  * @param string   $tag      The filter to remove hooks from.
   292  * @param string   $tag      The filter to remove hooks from.
   321  * @param int|bool $priority Optional. The priority number to remove. Default false.
   293  * @param int|bool $priority Optional. The priority number to remove. Default false.
   322  * @return bool True when finished.
   294  * @return true True when finished.
   323  */
   295  */
   324 function remove_all_filters( $tag, $priority = false ) {
   296 function remove_all_filters( $tag, $priority = false ) {
   325 	global $wp_filter, $merged_filters;
   297 	global $wp_filter;
   326 
   298 
   327 	if ( isset( $wp_filter[ $tag ]) ) {
   299 	if ( isset( $wp_filter[ $tag ]) ) {
   328 		if ( false === $priority ) {
   300 		$wp_filter[ $tag ]->remove_all_filters( $priority );
   329 			$wp_filter[ $tag ] = array();
   301 		if ( ! $wp_filter[ $tag ]->has_filters() ) {
   330 		} elseif ( isset( $wp_filter[ $tag ][ $priority ] ) ) {
   302 			unset( $wp_filter[ $tag ] );
   331 			$wp_filter[ $tag ][ $priority ] = array();
       
   332 		}
   303 		}
   333 	}
   304 	}
   334 
   305 
   335 	if ( isset( $merged_filters[ $tag ] ) ) {
       
   336 		unset( $merged_filters[ $tag ] );
       
   337 	}
       
   338 
       
   339 	return true;
   306 	return true;
   340 }
   307 }
   341 
   308 
   342 /**
   309 /**
   343  * Retrieve the name of the current filter or action.
   310  * Retrieve the name of the current filter or action.
   344  *
   311  *
   345  * @since 2.5.0
   312  * @since 2.5.0
       
   313  *
       
   314  * @global array $wp_current_filter Stores the list of current filters with the current one last
   346  *
   315  *
   347  * @return string Hook name of the current filter or action.
   316  * @return string Hook name of the current filter or action.
   348  */
   317  */
   349 function current_filter() {
   318 function current_filter() {
   350 	global $wp_current_filter;
   319 	global $wp_current_filter;
   415  * Action API.
   384  * Action API.
   416  *
   385  *
   417  * @since 1.2.0
   386  * @since 1.2.0
   418  *
   387  *
   419  * @param string   $tag             The name of the action to which the $function_to_add is hooked.
   388  * @param string   $tag             The name of the action to which the $function_to_add is hooked.
   420  * @param callback $function_to_add The name of the function you wish to be called.
   389  * @param callable $function_to_add The name of the function you wish to be called.
   421  * @param int      $priority        Optional. Used to specify the order in which the functions
   390  * @param int      $priority        Optional. Used to specify the order in which the functions
   422  *                                  associated with a particular action are executed. Default 10.
   391  *                                  associated with a particular action are executed. Default 10.
   423  *                                  Lower numbers correspond with earlier execution,
   392  *                                  Lower numbers correspond with earlier execution,
   424  *                                  and functions with the same priority are executed
   393  *                                  and functions with the same priority are executed
   425  *                                  in the order in which they were added to the action.
   394  *                                  in the order in which they were added to the action.
   426  * @param int      $accepted_args   Optional. The number of arguments the function accept. Default 1.
   395  * @param int      $accepted_args   Optional. The number of arguments the function accepts. Default 1.
   427  * @return bool Will always return true.
   396  * @return true Will always return true.
   428  */
   397  */
   429 function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
   398 function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
   430 	return add_filter($tag, $function_to_add, $priority, $accepted_args);
   399 	return add_filter($tag, $function_to_add, $priority, $accepted_args);
   431 }
   400 }
   432 
   401 
   435  *
   404  *
   436  * This function invokes all functions attached to action hook `$tag`. It is
   405  * This function invokes all functions attached to action hook `$tag`. It is
   437  * possible to create new action hooks by simply calling this function,
   406  * possible to create new action hooks by simply calling this function,
   438  * specifying the name of the new hook using the `$tag` parameter.
   407  * specifying the name of the new hook using the `$tag` parameter.
   439  *
   408  *
   440  * You can pass extra arguments to the hooks, much like you can with
   409  * You can pass extra arguments to the hooks, much like you can with apply_filters().
   441  * {@see apply_filters()}.
       
   442  *
   410  *
   443  * @since 1.2.0
   411  * @since 1.2.0
   444  *
   412  *
   445  * @global array $wp_filter  Stores all of the filters
   413  * @global array $wp_filter         Stores all of the filters
   446  * @global array $wp_actions Increments the amount of times action was triggered.
   414  * @global array $wp_actions        Increments the amount of times action was triggered.
   447  *
   415  * @global array $wp_current_filter Stores the list of current filters with the current one last
   448  * @param string $tag The name of the action to be executed.
   416  *
   449  * @param mixed  $arg Optional. Additional arguments which are passed on to the
   417  * @param string $tag     The name of the action to be executed.
   450  *                    functions hooked to the action. Default empty.
   418  * @param mixed  $arg,... Optional. Additional arguments which are passed on to the
   451  * @return null Will return null if $tag does not exist in $wp_filter array.
   419  *                        functions hooked to the action. Default empty.
   452  */
   420  */
   453 function do_action($tag, $arg = '') {
   421 function do_action($tag, $arg = '') {
   454 	global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;
   422 	global $wp_filter, $wp_actions, $wp_current_filter;
   455 
   423 
   456 	if ( ! isset($wp_actions[$tag]) )
   424 	if ( ! isset($wp_actions[$tag]) )
   457 		$wp_actions[$tag] = 1;
   425 		$wp_actions[$tag] = 1;
   458 	else
   426 	else
   459 		++$wp_actions[$tag];
   427 		++$wp_actions[$tag];
   480 	else
   448 	else
   481 		$args[] = $arg;
   449 		$args[] = $arg;
   482 	for ( $a = 2, $num = func_num_args(); $a < $num; $a++ )
   450 	for ( $a = 2, $num = func_num_args(); $a < $num; $a++ )
   483 		$args[] = func_get_arg($a);
   451 		$args[] = func_get_arg($a);
   484 
   452 
   485 	// Sort
   453 	$wp_filter[ $tag ]->do_action( $args );
   486 	if ( !isset( $merged_filters[ $tag ] ) ) {
       
   487 		ksort($wp_filter[$tag]);
       
   488 		$merged_filters[ $tag ] = true;
       
   489 	}
       
   490 
       
   491 	reset( $wp_filter[ $tag ] );
       
   492 
       
   493 	do {
       
   494 		foreach ( (array) current($wp_filter[$tag]) as $the_ )
       
   495 			if ( !is_null($the_['function']) )
       
   496 				call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
       
   497 
       
   498 	} while ( next($wp_filter[$tag]) !== false );
       
   499 
   454 
   500 	array_pop($wp_current_filter);
   455 	array_pop($wp_current_filter);
   501 }
   456 }
   502 
   457 
   503 /**
   458 /**
   524  *
   479  *
   525  * @since 2.1.0
   480  * @since 2.1.0
   526  *
   481  *
   527  * @see do_action() This function is identical, but the arguments passed to the
   482  * @see do_action() This function is identical, but the arguments passed to the
   528  *                  functions hooked to $tag< are supplied using an array.
   483  *                  functions hooked to $tag< are supplied using an array.
   529  * @global array $wp_filter  Stores all of the filters
   484  * @global array $wp_filter         Stores all of the filters
   530  * @global array $wp_actions Increments the amount of times action was triggered.
   485  * @global array $wp_actions        Increments the amount of times action was triggered.
       
   486  * @global array $wp_current_filter Stores the list of current filters with the current one last
   531  *
   487  *
   532  * @param string $tag  The name of the action to be executed.
   488  * @param string $tag  The name of the action to be executed.
   533  * @param array  $args The arguments supplied to the functions hooked to `$tag`.
   489  * @param array  $args The arguments supplied to the functions hooked to `$tag`.
   534  * @return null Will return null if `$tag` does not exist in `$wp_filter` array.
       
   535  */
   490  */
   536 function do_action_ref_array($tag, $args) {
   491 function do_action_ref_array($tag, $args) {
   537 	global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;
   492 	global $wp_filter, $wp_actions, $wp_current_filter;
   538 
   493 
   539 	if ( ! isset($wp_actions[$tag]) )
   494 	if ( ! isset($wp_actions[$tag]) )
   540 		$wp_actions[$tag] = 1;
   495 		$wp_actions[$tag] = 1;
   541 	else
   496 	else
   542 		++$wp_actions[$tag];
   497 		++$wp_actions[$tag];
   555 	}
   510 	}
   556 
   511 
   557 	if ( !isset($wp_filter['all']) )
   512 	if ( !isset($wp_filter['all']) )
   558 		$wp_current_filter[] = $tag;
   513 		$wp_current_filter[] = $tag;
   559 
   514 
   560 	// Sort
   515 	$wp_filter[ $tag ]->do_action( $args );
   561 	if ( !isset( $merged_filters[ $tag ] ) ) {
       
   562 		ksort($wp_filter[$tag]);
       
   563 		$merged_filters[ $tag ] = true;
       
   564 	}
       
   565 
       
   566 	reset( $wp_filter[ $tag ] );
       
   567 
       
   568 	do {
       
   569 		foreach( (array) current($wp_filter[$tag]) as $the_ )
       
   570 			if ( !is_null($the_['function']) )
       
   571 				call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
       
   572 
       
   573 	} while ( next($wp_filter[$tag]) !== false );
       
   574 
   516 
   575 	array_pop($wp_current_filter);
   517 	array_pop($wp_current_filter);
   576 }
   518 }
   577 
   519 
   578 /**
   520 /**
   581  * @since 2.5.0
   523  * @since 2.5.0
   582  *
   524  *
   583  * @see has_filter() has_action() is an alias of has_filter().
   525  * @see has_filter() has_action() is an alias of has_filter().
   584  *
   526  *
   585  * @param string        $tag               The name of the action hook.
   527  * @param string        $tag               The name of the action hook.
   586  * @param callback|bool $function_to_check Optional. The callback to check for. Default false.
   528  * @param callable|bool $function_to_check Optional. The callback to check for. Default false.
   587  * @return bool|int If $function_to_check is omitted, returns boolean for whether the hook has
   529  * @return bool|int If $function_to_check is omitted, returns boolean for whether the hook has
   588  *                  anything registered. When checking a specific function, the priority of that
   530  *                  anything registered. When checking a specific function, the priority of that
   589  *                  hook is returned, or false if the function is not attached. When using the
   531  *                  hook is returned, or false if the function is not attached. When using the
   590  *                  $function_to_check argument, this function may return a non-boolean value
   532  *                  $function_to_check argument, this function may return a non-boolean value
   591  *                  that evaluates to false (e.g.) 0, so use the === operator for testing the
   533  *                  that evaluates to false (e.g.) 0, so use the === operator for testing the
   603  * hook and possibly replace them with a substitute.
   545  * hook and possibly replace them with a substitute.
   604  *
   546  *
   605  * @since 1.2.0
   547  * @since 1.2.0
   606  *
   548  *
   607  * @param string   $tag                The action hook to which the function to be removed is hooked.
   549  * @param string   $tag                The action hook to which the function to be removed is hooked.
   608  * @param callback $function_to_remove The name of the function which should be removed.
   550  * @param callable $function_to_remove The name of the function which should be removed.
   609  * @param int      $priority           Optional. The priority of the function. Default 10.
   551  * @param int      $priority           Optional. The priority of the function. Default 10.
   610  * @return boolean Whether the function is removed.
   552  * @return bool Whether the function is removed.
   611  */
   553  */
   612 function remove_action( $tag, $function_to_remove, $priority = 10 ) {
   554 function remove_action( $tag, $function_to_remove, $priority = 10 ) {
   613 	return remove_filter( $tag, $function_to_remove, $priority );
   555 	return remove_filter( $tag, $function_to_remove, $priority );
   614 }
   556 }
   615 
   557 
   618  *
   560  *
   619  * @since 2.7.0
   561  * @since 2.7.0
   620  *
   562  *
   621  * @param string   $tag      The action to remove hooks from.
   563  * @param string   $tag      The action to remove hooks from.
   622  * @param int|bool $priority The priority number to remove them from. Default false.
   564  * @param int|bool $priority The priority number to remove them from. Default false.
   623  * @return bool True when finished.
   565  * @return true True when finished.
   624  */
   566  */
   625 function remove_all_actions($tag, $priority = false) {
   567 function remove_all_actions($tag, $priority = false) {
   626 	return remove_all_filters($tag, $priority);
   568 	return remove_all_filters($tag, $priority);
       
   569 }
       
   570 
       
   571 /**
       
   572  * Fires functions attached to a deprecated filter hook.
       
   573  *
       
   574  * When a filter hook is deprecated, the apply_filters() call is replaced with
       
   575  * apply_filters_deprecated(), which triggers a deprecation notice and then fires
       
   576  * the original filter hook.
       
   577  *
       
   578  * Note: the value and extra arguments passed to the original apply_filters() call
       
   579  * must be passed here to `$args` as an array. For example:
       
   580  *
       
   581  *     // Old filter.
       
   582  *     return apply_filters( 'wpdocs_filter', $value, $extra_arg );
       
   583  *
       
   584  *     // Deprecated.
       
   585  *     return apply_filters_deprecated( 'wpdocs_filter', array( $value, $extra_arg ), '4.9', 'wpdocs_new_filter' );
       
   586  *
       
   587  * @since 4.6.0
       
   588  *
       
   589  * @see _deprecated_hook()
       
   590  *
       
   591  * @param string $tag         The name of the filter hook.
       
   592  * @param array  $args        Array of additional function arguments to be passed to apply_filters().
       
   593  * @param string $version     The version of WordPress that deprecated the hook.
       
   594  * @param string $replacement Optional. The hook that should have been used. Default false.
       
   595  * @param string $message     Optional. A message regarding the change. Default null.
       
   596  */
       
   597 function apply_filters_deprecated( $tag, $args, $version, $replacement = false, $message = null ) {
       
   598 	if ( ! has_filter( $tag ) ) {
       
   599 		return $args[0];
       
   600 	}
       
   601 
       
   602 	_deprecated_hook( $tag, $version, $replacement, $message );
       
   603 
       
   604 	return apply_filters_ref_array( $tag, $args );
       
   605 }
       
   606 
       
   607 /**
       
   608  * Fires functions attached to a deprecated action hook.
       
   609  *
       
   610  * When an action hook is deprecated, the do_action() call is replaced with
       
   611  * do_action_deprecated(), which triggers a deprecation notice and then fires
       
   612  * the original hook.
       
   613  *
       
   614  * @since 4.6.0
       
   615  *
       
   616  * @see _deprecated_hook()
       
   617  *
       
   618  * @param string $tag         The name of the action hook.
       
   619  * @param array  $args        Array of additional function arguments to be passed to do_action().
       
   620  * @param string $version     The version of WordPress that deprecated the hook.
       
   621  * @param string $replacement Optional. The hook that should have been used.
       
   622  * @param string $message     Optional. A message regarding the change.
       
   623  */
       
   624 function do_action_deprecated( $tag, $args, $version, $replacement = false, $message = null ) {
       
   625 	if ( ! has_action( $tag ) ) {
       
   626 		return;
       
   627 	}
       
   628 
       
   629 	_deprecated_hook( $tag, $version, $replacement, $message );
       
   630 
       
   631 	do_action_ref_array( $tag, $args );
   627 }
   632 }
   628 
   633 
   629 //
   634 //
   630 // Functions for handling plugins.
   635 // Functions for handling plugins.
   631 //
   636 //
   635  *
   640  *
   636  * This method extracts the name of a plugin from its filename.
   641  * This method extracts the name of a plugin from its filename.
   637  *
   642  *
   638  * @since 1.5.0
   643  * @since 1.5.0
   639  *
   644  *
       
   645  * @global array $wp_plugin_paths
       
   646  *
   640  * @param string $file The filename of plugin.
   647  * @param string $file The filename of plugin.
   641  * @return string The name of a plugin.
   648  * @return string The name of a plugin.
   642  */
   649  */
   643 function plugin_basename( $file ) {
   650 function plugin_basename( $file ) {
   644 	global $wp_plugin_paths;
   651 	global $wp_plugin_paths;
   645 
   652 
       
   653 	// $wp_plugin_paths contains normalized paths.
       
   654 	$file = wp_normalize_path( $file );
       
   655 
       
   656 	arsort( $wp_plugin_paths );
   646 	foreach ( $wp_plugin_paths as $dir => $realdir ) {
   657 	foreach ( $wp_plugin_paths as $dir => $realdir ) {
   647 		if ( strpos( $file, $realdir ) === 0 ) {
   658 		if ( strpos( $file, $realdir ) === 0 ) {
   648 			$file = $dir . substr( $file, strlen( $realdir ) );
   659 			$file = $dir . substr( $file, strlen( $realdir ) );
   649 		}
   660 		}
   650 	}
   661 	}
   651 
   662 
   652 	$file = wp_normalize_path( $file );
       
   653 	$plugin_dir = wp_normalize_path( WP_PLUGIN_DIR );
   663 	$plugin_dir = wp_normalize_path( WP_PLUGIN_DIR );
   654 	$mu_plugin_dir = wp_normalize_path( WPMU_PLUGIN_DIR );
   664 	$mu_plugin_dir = wp_normalize_path( WPMU_PLUGIN_DIR );
   655 
   665 
   656 	$file = preg_replace('#^' . preg_quote($plugin_dir, '#') . '/|^' . preg_quote($mu_plugin_dir, '#') . '/#','',$file); // get relative path from plugins dir
   666 	$file = preg_replace('#^' . preg_quote($plugin_dir, '#') . '/|^' . preg_quote($mu_plugin_dir, '#') . '/#','',$file); // get relative path from plugins dir
   657 	$file = trim($file, '/');
   667 	$file = trim($file, '/');
   663  *
   673  *
   664  * This is used in plugin_basename() to resolve symlinked paths.
   674  * This is used in plugin_basename() to resolve symlinked paths.
   665  *
   675  *
   666  * @since 3.9.0
   676  * @since 3.9.0
   667  *
   677  *
   668  * @see plugin_basename()
   678  * @see wp_normalize_path()
       
   679  *
       
   680  * @global array $wp_plugin_paths
       
   681  *
       
   682  * @staticvar string $wp_plugin_path
       
   683  * @staticvar string $wpmu_plugin_path
   669  *
   684  *
   670  * @param string $file Known path to the file.
   685  * @param string $file Known path to the file.
   671  * @return bool Whether the path was able to be registered.
   686  * @return bool Whether the path was able to be registered.
   672  */
   687  */
   673 function wp_register_plugin_realpath( $file ) {
   688 function wp_register_plugin_realpath( $file ) {
   674 	global $wp_plugin_paths;
   689 	global $wp_plugin_paths;
   675 
   690 
   676 	// Normalize, but store as static to avoid recalculation of a constant value
   691 	// Normalize, but store as static to avoid recalculation of a constant value
   677 	static $wp_plugin_path, $wpmu_plugin_path;
   692 	static $wp_plugin_path = null, $wpmu_plugin_path = null;
   678 	if ( ! isset( $wp_plugin_path ) ) {
   693 	if ( ! isset( $wp_plugin_path ) ) {
   679 		$wp_plugin_path   = wp_normalize_path( WP_PLUGIN_DIR   );
   694 		$wp_plugin_path   = wp_normalize_path( WP_PLUGIN_DIR   );
   680 		$wpmu_plugin_path = wp_normalize_path( WPMU_PLUGIN_DIR );
   695 		$wpmu_plugin_path = wp_normalize_path( WPMU_PLUGIN_DIR );
   681 	}
   696 	}
   682 
   697 
   732  * 'activate_sample.php'.
   747  * 'activate_sample.php'.
   733  *
   748  *
   734  * @since 2.0.0
   749  * @since 2.0.0
   735  *
   750  *
   736  * @param string   $file     The filename of the plugin including the path.
   751  * @param string   $file     The filename of the plugin including the path.
   737  * @param callback $function The function hooked to the 'activate_PLUGIN' action.
   752  * @param callable $function The function hooked to the 'activate_PLUGIN' action.
   738  */
   753  */
   739 function register_activation_hook($file, $function) {
   754 function register_activation_hook($file, $function) {
   740 	$file = plugin_basename($file);
   755 	$file = plugin_basename($file);
   741 	add_action('activate_' . $file, $function);
   756 	add_action('activate_' . $file, $function);
   742 }
   757 }
   755  * 'deactivate_sample.php'.
   770  * 'deactivate_sample.php'.
   756  *
   771  *
   757  * @since 2.0.0
   772  * @since 2.0.0
   758  *
   773  *
   759  * @param string   $file     The filename of the plugin including the path.
   774  * @param string   $file     The filename of the plugin including the path.
   760  * @param callback $function The function hooked to the 'deactivate_PLUGIN' action.
   775  * @param callable $function The function hooked to the 'deactivate_PLUGIN' action.
   761  */
   776  */
   762 function register_deactivation_hook($file, $function) {
   777 function register_deactivation_hook($file, $function) {
   763 	$file = plugin_basename($file);
   778 	$file = plugin_basename($file);
   764 	add_action('deactivate_' . $file, $function);
   779 	add_action('deactivate_' . $file, $function);
   765 }
   780 }
   772  * be active unless the plugin hooks into the action.
   787  * be active unless the plugin hooks into the action.
   773  *
   788  *
   774  * The plugin should not run arbitrary code outside of functions, when
   789  * The plugin should not run arbitrary code outside of functions, when
   775  * registering the uninstall hook. In order to run using the hook, the plugin
   790  * registering the uninstall hook. In order to run using the hook, the plugin
   776  * will have to be included, which means that any code laying outside of a
   791  * will have to be included, which means that any code laying outside of a
   777  * function will be run during the uninstall process. The plugin should not
   792  * function will be run during the uninstallation process. The plugin should not
   778  * hinder the uninstall process.
   793  * hinder the uninstallation process.
   779  *
   794  *
   780  * If the plugin can not be written without running code within the plugin, then
   795  * If the plugin can not be written without running code within the plugin, then
   781  * the plugin should create a file named 'uninstall.php' in the base plugin
   796  * the plugin should create a file named 'uninstall.php' in the base plugin
   782  * folder. This file will be called, if it exists, during the uninstall process
   797  * folder. This file will be called, if it exists, during the uninstallation process
   783  * bypassing the uninstall hook. The plugin, when using the 'uninstall.php'
   798  * bypassing the uninstall hook. The plugin, when using the 'uninstall.php'
   784  * should always check for the 'WP_UNINSTALL_PLUGIN' constant, before
   799  * should always check for the 'WP_UNINSTALL_PLUGIN' constant, before
   785  * executing.
   800  * executing.
   786  *
   801  *
   787  * @since 2.7.0
   802  * @since 2.7.0
   788  *
   803  *
   789  * @param string   $file     Plugin file.
   804  * @param string   $file     Plugin file.
   790  * @param callback $callback The callback to run when the hook is called. Must be
   805  * @param callable $callback The callback to run when the hook is called. Must be
   791  *                           a static method or function.
   806  *                           a static method or function.
   792  */
   807  */
   793 function register_uninstall_hook( $file, $callback ) {
   808 function register_uninstall_hook( $file, $callback ) {
   794 	if ( is_array( $callback ) && is_object( $callback[0] ) ) {
   809 	if ( is_array( $callback ) && is_object( $callback[0] ) ) {
   795 		_doing_it_wrong( __FUNCTION__, __( 'Only a static class method or function can be used in an uninstall hook.' ), '3.1' );
   810 		_doing_it_wrong( __FUNCTION__, __( 'Only a static class method or function can be used in an uninstall hook.' ), '3.1.0' );
   796 		return;
   811 		return;
   797 	}
   812 	}
   798 
   813 
   799 	/*
   814 	/*
   800 	 * The option should not be autoloaded, because it is not needed in most
   815 	 * The option should not be autoloaded, because it is not needed in most
   819  * it will fail unless the all hook exists prior to this function call.
   834  * it will fail unless the all hook exists prior to this function call.
   820  *
   835  *
   821  * @since 2.5.0
   836  * @since 2.5.0
   822  * @access private
   837  * @access private
   823  *
   838  *
       
   839  * @global array $wp_filter  Stores all of the filters
       
   840  *
   824  * @param array $args The collected parameters from the hook that was called.
   841  * @param array $args The collected parameters from the hook that was called.
   825  */
   842  */
   826 function _wp_call_all_hook($args) {
   843 function _wp_call_all_hook($args) {
   827 	global $wp_filter;
   844 	global $wp_filter;
   828 
   845 
   829 	reset( $wp_filter['all'] );
   846 	$wp_filter['all']->do_all_hook( $args );
   830 	do {
       
   831 		foreach( (array) current($wp_filter['all']) as $the_ )
       
   832 			if ( !is_null($the_['function']) )
       
   833 				call_user_func_array($the_['function'], $args);
       
   834 
       
   835 	} while ( next($wp_filter['all']) !== false );
       
   836 }
   847 }
   837 
   848 
   838 /**
   849 /**
   839  * Build Unique ID for storage and retrieval.
   850  * Build Unique ID for storage and retrieval.
   840  *
   851  *
   856  *
   867  *
   857  * @since 2.2.3
   868  * @since 2.2.3
   858  * @access private
   869  * @access private
   859  *
   870  *
   860  * @global array $wp_filter Storage for all of the filters and actions.
   871  * @global array $wp_filter Storage for all of the filters and actions.
       
   872  * @staticvar int $filter_id_count
   861  *
   873  *
   862  * @param string   $tag      Used in counting how many hooks were applied
   874  * @param string   $tag      Used in counting how many hooks were applied
   863  * @param callback $function Used for creating unique id
   875  * @param callable $function Used for creating unique id
   864  * @param int|bool $priority Used in counting how many hooks were applied. If === false
   876  * @param int|bool $priority Used in counting how many hooks were applied. If === false
   865  *                           and $function is an object reference, we return the unique
   877  *                           and $function is an object reference, we return the unique
   866  *                           id only if it already has one, false otherwise.
   878  *                           id only if it already has one, false otherwise.
   867  * @return string|bool Unique ID for usage as array key or false if $priority === false
   879  * @return string|false Unique ID for usage as array key or false if $priority === false
   868  *                     and $function is an object reference, and it does not already have
   880  *                      and $function is an object reference, and it does not already have
   869  *                     a unique id.
   881  *                      a unique id.
   870  */
   882  */
   871 function _wp_filter_build_unique_id($tag, $function, $priority) {
   883 function _wp_filter_build_unique_id($tag, $function, $priority) {
   872 	global $wp_filter;
   884 	global $wp_filter;
   873 	static $filter_id_count = 0;
   885 	static $filter_id_count = 0;
   874 
   886