Make WordPress Core

Ticket #21412: hookable-dropins.diff

File hookable-dropins.diff, 21.6 KB (added by mikeschinkel, 12 years ago)

hookable-dropins.diff

  • wp-includes/plugin.php

     
    1919 * @since 1.5
    2020 */
    2121
    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 
    54622//
    54723// Functions for handling plugins.
    54824//
     
    720196
    721197        } while ( next($wp_filter['all']) !== false );
    722198}
    723 
    724 /**
    725  * Build Unique ID for storage and retrieval.
    726  *
    727  * The old way to serialize the callback caused issues and this function is the
    728  * solution. It works by checking for objects and creating an a new property in
    729  * the class to keep track of the object and new objects of the same class that
    730  * need to be added.
    731  *
    732  * It also allows for the removal of actions and filters for objects after they
    733  * change class properties. It is possible to include the property $wp_filter_id
    734  * in your class and set it to "null" or a number to bypass the workaround.
    735  * However this will prevent you from adding new classes and any new classes
    736  * will overwrite the previous hook by the same class.
    737  *
    738  * Functions and static method callbacks are just returned as strings and
    739  * shouldn't have any speed penalty.
    740  *
    741  * @package WordPress
    742  * @subpackage Plugin
    743  * @access private
    744  * @since 2.2.3
    745  * @link http://trac.wordpress.org/ticket/3875
    746  *
    747  * @global array $wp_filter Storage for all of the filters and actions
    748  * @param string $tag Used in counting how many hooks were applied
    749  * @param callback $function Used for creating unique id
    750  * @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.
    751  * @return string|bool Unique ID for usage as array key or false if $priority === false and $function is an object reference, and it does not already have a unique id.
    752  */
    753 function _wp_filter_build_unique_id($tag, $function, $priority) {
    754         global $wp_filter;
    755         static $filter_id_count = 0;
    756 
    757         if ( is_string($function) )
    758                 return $function;
    759 
    760         if ( is_object($function) ) {
    761                 // Closures are currently implemented as objects
    762                 $function = array( $function, '' );
    763         } else {
    764                 $function = (array) $function;
    765         }
    766 
    767         if (is_object($function[0]) ) {
    768                 // Object Class Calling
    769                 if ( function_exists('spl_object_hash') ) {
    770                         return spl_object_hash($function[0]) . $function[1];
    771                 } else {
    772                         $obj_idx = get_class($function[0]).$function[1];
    773                         if ( !isset($function[0]->wp_filter_id) ) {
    774                                 if ( false === $priority )
    775                                         return false;
    776                                 $obj_idx .= isset($wp_filter[$tag][$priority]) ? count((array)$wp_filter[$tag][$priority]) : $filter_id_count;
    777                                 $function[0]->wp_filter_id = $filter_id_count;
    778                                 ++$filter_id_count;
    779                         } else {
    780                                 $obj_idx .= $function[0]->wp_filter_id;
    781                         }
    782 
    783                         return $obj_idx;
    784                 }
    785         } else if ( is_string($function[0]) ) {
    786                 // Static Calling
    787                 return $function[0].$function[1];
    788         }
    789 }
  • wp-settings.php

     
    2121require( ABSPATH . WPINC . '/load.php' );
    2222require( ABSPATH . WPINC . '/default-constants.php' );
    2323require( ABSPATH . WPINC . '/version.php' );
     24require( ABSPATH . WPINC . '/hooks.php' );
     25require( ABSPATH . WPINC . '/dropins.php' );
    2426
    2527// Set initial default constants including WP_MEMORY_LIMIT, WP_MAX_MEMORY_LIMIT, WP_DEBUG, WP_CONTENT_DIR and WP_CACHE.
    2628wp_initial_constants( );
     
    5456// Check if we're in WP_DEBUG mode.
    5557wp_debug_mode();
    5658
     59// Load any potential dropins found /wp-content/dropins/
     60wp_load_dropins();
     61
     62// Run the hook-based page cache.
     63do_action( 'page_cache' );
     64
    5765// For an advanced caching plugin to use. Uses a static drop-in because you would only want one.
    5866if ( WP_CACHE )
    5967        WP_DEBUG ? include( WP_CONTENT_DIR . '/advanced-cache.php' ) : @include( WP_CONTENT_DIR . '/advanced-cache.php' );