/inc/backpress/functions.plugin-api.php

http://php-twitter.googlecode.com/ · PHP · 697 lines · 213 code · 70 blank · 414 comment · 44 complexity · 84b12c755a5de6a65871385e2a6ff169 MD5 · raw file

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