PageRenderTime 55ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/htdocs/wp-admin/includes/plugin.php

https://bitbucket.org/dkrzos/phc
PHP | 1763 lines | 887 code | 218 blank | 658 comment | 284 complexity | be4e90a5e87c1a61188a326c2f8693dd MD5 | raw file
Possible License(s): GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * WordPress Plugin Administration API
  4. *
  5. * @package WordPress
  6. * @subpackage Administration
  7. */
  8. /**
  9. * Parse the plugin contents to retrieve plugin's metadata.
  10. *
  11. * The metadata of the plugin's data searches for the following in the plugin's
  12. * header. All plugin data must be on its own line. For plugin description, it
  13. * must not have any newlines or only parts of the description will be displayed
  14. * and the same goes for the plugin data. The below is formatted for printing.
  15. *
  16. * <code>
  17. * /*
  18. * Plugin Name: Name of Plugin
  19. * Plugin URI: Link to plugin information
  20. * Description: Plugin Description
  21. * Author: Plugin author's name
  22. * Author URI: Link to the author's web site
  23. * Version: Must be set in the plugin for WordPress 2.3+
  24. * Text Domain: Optional. Unique identifier, should be same as the one used in
  25. * plugin_text_domain()
  26. * Domain Path: Optional. Only useful if the translations are located in a
  27. * folder above the plugin's base path. For example, if .mo files are
  28. * located in the locale folder then Domain Path will be "/locale/" and
  29. * must have the first slash. Defaults to the base folder the plugin is
  30. * located in.
  31. * Network: Optional. Specify "Network: true" to require that a plugin is activated
  32. * across all sites in an installation. This will prevent a plugin from being
  33. * activated on a single site when Multisite is enabled.
  34. * * / # Remove the space to close comment
  35. * </code>
  36. *
  37. * Plugin data returned array contains the following:
  38. * 'Name' - Name of the plugin, must be unique.
  39. * 'Title' - Title of the plugin and the link to the plugin's web site.
  40. * 'Description' - Description of what the plugin does and/or notes
  41. * from the author.
  42. * 'Author' - The author's name
  43. * 'AuthorURI' - The authors web site address.
  44. * 'Version' - The plugin version number.
  45. * 'PluginURI' - Plugin web site address.
  46. * 'TextDomain' - Plugin's text domain for localization.
  47. * 'DomainPath' - Plugin's relative directory path to .mo files.
  48. * 'Network' - Boolean. Whether the plugin can only be activated network wide.
  49. *
  50. * Some users have issues with opening large files and manipulating the contents
  51. * for want is usually the first 1kiB or 2kiB. This function stops pulling in
  52. * the plugin contents when it has all of the required plugin data.
  53. *
  54. * The first 8kiB of the file will be pulled in and if the plugin data is not
  55. * within that first 8kiB, then the plugin author should correct their plugin
  56. * and move the plugin data headers to the top.
  57. *
  58. * The plugin file is assumed to have permissions to allow for scripts to read
  59. * the file. This is not checked however and the file is only opened for
  60. * reading.
  61. *
  62. * @link http://trac.wordpress.org/ticket/5651 Previous Optimizations.
  63. * @link http://trac.wordpress.org/ticket/7372 Further and better Optimizations.
  64. * @since 1.5.0
  65. *
  66. * @param string $plugin_file Path to the plugin file
  67. * @param bool $markup Optional. If the returned data should have HTML markup applied. Defaults to true.
  68. * @param bool $translate Optional. If the returned data should be translated. Defaults to true.
  69. * @return array See above for description.
  70. */
  71. function get_plugin_data( $plugin_file, $markup = true, $translate = true ) {
  72. $default_headers = array(
  73. 'Name' => 'Plugin Name',
  74. 'PluginURI' => 'Plugin URI',
  75. 'Version' => 'Version',
  76. 'Description' => 'Description',
  77. 'Author' => 'Author',
  78. 'AuthorURI' => 'Author URI',
  79. 'TextDomain' => 'Text Domain',
  80. 'DomainPath' => 'Domain Path',
  81. 'Network' => 'Network',
  82. // Site Wide Only is deprecated in favor of Network.
  83. '_sitewide' => 'Site Wide Only',
  84. );
  85. $plugin_data = get_file_data( $plugin_file, $default_headers, 'plugin' );
  86. // Site Wide Only is the old header for Network
  87. if ( ! $plugin_data['Network'] && $plugin_data['_sitewide'] ) {
  88. _deprecated_argument( __FUNCTION__, '3.0', sprintf( __( 'The <code>%1$s</code> plugin header is deprecated. Use <code>%2$s</code> instead.' ), 'Site Wide Only: true', 'Network: true' ) );
  89. $plugin_data['Network'] = $plugin_data['_sitewide'];
  90. }
  91. $plugin_data['Network'] = ( 'true' == strtolower( $plugin_data['Network'] ) );
  92. unset( $plugin_data['_sitewide'] );
  93. if ( $markup || $translate ) {
  94. $plugin_data = _get_plugin_data_markup_translate( $plugin_file, $plugin_data, $markup, $translate );
  95. } else {
  96. $plugin_data['Title'] = $plugin_data['Name'];
  97. $plugin_data['AuthorName'] = $plugin_data['Author'];
  98. }
  99. return $plugin_data;
  100. }
  101. /**
  102. * Sanitizes plugin data, optionally adds markup, optionally translates.
  103. *
  104. * @since 2.7.0
  105. * @access private
  106. * @see get_plugin_data()
  107. */
  108. function _get_plugin_data_markup_translate( $plugin_file, $plugin_data, $markup = true, $translate = true ) {
  109. // Translate fields
  110. if ( $translate ) {
  111. if ( $textdomain = $plugin_data['TextDomain'] ) {
  112. if ( $plugin_data['DomainPath'] )
  113. load_plugin_textdomain( $textdomain, false, dirname( $plugin_file ) . $plugin_data['DomainPath'] );
  114. else
  115. load_plugin_textdomain( $textdomain, false, dirname( $plugin_file ) );
  116. } elseif ( in_array( basename( $plugin_file ), array( 'hello.php', 'akismet.php' ) ) ) {
  117. $textdomain = 'default';
  118. }
  119. if ( $textdomain ) {
  120. foreach ( array( 'Name', 'PluginURI', 'Description', 'Author', 'AuthorURI', 'Version' ) as $field )
  121. $plugin_data[ $field ] = translate( $plugin_data[ $field ], $textdomain );
  122. }
  123. }
  124. // Sanitize fields
  125. $allowed_tags = $allowed_tags_in_links = array(
  126. 'abbr' => array( 'title' => true ),
  127. 'acronym' => array( 'title' => true ),
  128. 'code' => true,
  129. 'em' => true,
  130. 'strong' => true,
  131. );
  132. $allowed_tags['a'] = array( 'href' => true, 'title' => true );
  133. // Name is marked up inside <a> tags. Don't allow these.
  134. // Author is too, but some plugins have used <a> here (omitting Author URI).
  135. $plugin_data['Name'] = wp_kses( $plugin_data['Name'], $allowed_tags_in_links );
  136. $plugin_data['Author'] = wp_kses( $plugin_data['Author'], $allowed_tags );
  137. $plugin_data['Description'] = wp_kses( $plugin_data['Description'], $allowed_tags );
  138. $plugin_data['Version'] = wp_kses( $plugin_data['Version'], $allowed_tags );
  139. $plugin_data['PluginURI'] = esc_url( $plugin_data['PluginURI'] );
  140. $plugin_data['AuthorURI'] = esc_url( $plugin_data['AuthorURI'] );
  141. $plugin_data['Title'] = $plugin_data['Name'];
  142. $plugin_data['AuthorName'] = $plugin_data['Author'];
  143. // Apply markup
  144. if ( $markup ) {
  145. if ( $plugin_data['PluginURI'] && $plugin_data['Name'] )
  146. $plugin_data['Title'] = '<a href="' . $plugin_data['PluginURI'] . '" title="' . esc_attr__( 'Visit plugin homepage' ) . '">' . $plugin_data['Name'] . '</a>';
  147. if ( $plugin_data['AuthorURI'] && $plugin_data['Author'] )
  148. $plugin_data['Author'] = '<a href="' . $plugin_data['AuthorURI'] . '" title="' . esc_attr__( 'Visit author homepage' ) . '">' . $plugin_data['Author'] . '</a>';
  149. $plugin_data['Description'] = wptexturize( $plugin_data['Description'] );
  150. if ( $plugin_data['Author'] )
  151. $plugin_data['Description'] .= ' <cite>' . sprintf( __('By %s.'), $plugin_data['Author'] ) . '</cite>';
  152. }
  153. return $plugin_data;
  154. }
  155. /**
  156. * Get a list of a plugin's files.
  157. *
  158. * @since 2.8.0
  159. *
  160. * @param string $plugin Plugin ID
  161. * @return array List of files relative to the plugin root.
  162. */
  163. function get_plugin_files($plugin) {
  164. $plugin_file = WP_PLUGIN_DIR . '/' . $plugin;
  165. $dir = dirname($plugin_file);
  166. $plugin_files = array($plugin);
  167. if ( is_dir($dir) && $dir != WP_PLUGIN_DIR ) {
  168. $plugins_dir = @ opendir( $dir );
  169. if ( $plugins_dir ) {
  170. while (($file = readdir( $plugins_dir ) ) !== false ) {
  171. if ( substr($file, 0, 1) == '.' )
  172. continue;
  173. if ( is_dir( $dir . '/' . $file ) ) {
  174. $plugins_subdir = @ opendir( $dir . '/' . $file );
  175. if ( $plugins_subdir ) {
  176. while (($subfile = readdir( $plugins_subdir ) ) !== false ) {
  177. if ( substr($subfile, 0, 1) == '.' )
  178. continue;
  179. $plugin_files[] = plugin_basename("$dir/$file/$subfile");
  180. }
  181. @closedir( $plugins_subdir );
  182. }
  183. } else {
  184. if ( plugin_basename("$dir/$file") != $plugin )
  185. $plugin_files[] = plugin_basename("$dir/$file");
  186. }
  187. }
  188. @closedir( $plugins_dir );
  189. }
  190. }
  191. return $plugin_files;
  192. }
  193. /**
  194. * Check the plugins directory and retrieve all plugin files with plugin data.
  195. *
  196. * WordPress only supports plugin files in the base plugins directory
  197. * (wp-content/plugins) and in one directory above the plugins directory
  198. * (wp-content/plugins/my-plugin). The file it looks for has the plugin data and
  199. * must be found in those two locations. It is recommended that do keep your
  200. * plugin files in directories.
  201. *
  202. * The file with the plugin data is the file that will be included and therefore
  203. * needs to have the main execution for the plugin. This does not mean
  204. * everything must be contained in the file and it is recommended that the file
  205. * be split for maintainability. Keep everything in one file for extreme
  206. * optimization purposes.
  207. *
  208. * @since 1.5.0
  209. *
  210. * @param string $plugin_folder Optional. Relative path to single plugin folder.
  211. * @return array Key is the plugin file path and the value is an array of the plugin data.
  212. */
  213. function get_plugins($plugin_folder = '') {
  214. if ( ! $cache_plugins = wp_cache_get('plugins', 'plugins') )
  215. $cache_plugins = array();
  216. if ( isset($cache_plugins[ $plugin_folder ]) )
  217. return $cache_plugins[ $plugin_folder ];
  218. $wp_plugins = array ();
  219. $plugin_root = WP_PLUGIN_DIR;
  220. if ( !empty($plugin_folder) )
  221. $plugin_root .= $plugin_folder;
  222. // Files in wp-content/plugins directory
  223. $plugins_dir = @ opendir( $plugin_root);
  224. $plugin_files = array();
  225. if ( $plugins_dir ) {
  226. while (($file = readdir( $plugins_dir ) ) !== false ) {
  227. if ( substr($file, 0, 1) == '.' )
  228. continue;
  229. if ( is_dir( $plugin_root.'/'.$file ) ) {
  230. $plugins_subdir = @ opendir( $plugin_root.'/'.$file );
  231. if ( $plugins_subdir ) {
  232. while (($subfile = readdir( $plugins_subdir ) ) !== false ) {
  233. if ( substr($subfile, 0, 1) == '.' )
  234. continue;
  235. if ( substr($subfile, -4) == '.php' )
  236. $plugin_files[] = "$file/$subfile";
  237. }
  238. closedir( $plugins_subdir );
  239. }
  240. } else {
  241. if ( substr($file, -4) == '.php' )
  242. $plugin_files[] = $file;
  243. }
  244. }
  245. closedir( $plugins_dir );
  246. }
  247. if ( empty($plugin_files) )
  248. return $wp_plugins;
  249. foreach ( $plugin_files as $plugin_file ) {
  250. if ( !is_readable( "$plugin_root/$plugin_file" ) )
  251. continue;
  252. $plugin_data = get_plugin_data( "$plugin_root/$plugin_file", false, false ); //Do not apply markup/translate as it'll be cached.
  253. if ( empty ( $plugin_data['Name'] ) )
  254. continue;
  255. $wp_plugins[plugin_basename( $plugin_file )] = $plugin_data;
  256. }
  257. uasort( $wp_plugins, '_sort_uname_callback' );
  258. $cache_plugins[ $plugin_folder ] = $wp_plugins;
  259. wp_cache_set('plugins', $cache_plugins, 'plugins');
  260. return $wp_plugins;
  261. }
  262. /**
  263. * Check the mu-plugins directory and retrieve all mu-plugin files with any plugin data.
  264. *
  265. * WordPress only includes mu-plugin files in the base mu-plugins directory (wp-content/mu-plugins).
  266. *
  267. * @since 3.0.0
  268. * @return array Key is the mu-plugin file path and the value is an array of the mu-plugin data.
  269. */
  270. function get_mu_plugins() {
  271. $wp_plugins = array();
  272. // Files in wp-content/mu-plugins directory
  273. $plugin_files = array();
  274. if ( ! is_dir( WPMU_PLUGIN_DIR ) )
  275. return $wp_plugins;
  276. if ( $plugins_dir = @ opendir( WPMU_PLUGIN_DIR ) ) {
  277. while ( ( $file = readdir( $plugins_dir ) ) !== false ) {
  278. if ( substr( $file, -4 ) == '.php' )
  279. $plugin_files[] = $file;
  280. }
  281. } else {
  282. return $wp_plugins;
  283. }
  284. @closedir( $plugins_dir );
  285. if ( empty($plugin_files) )
  286. return $wp_plugins;
  287. foreach ( $plugin_files as $plugin_file ) {
  288. if ( !is_readable( WPMU_PLUGIN_DIR . "/$plugin_file" ) )
  289. continue;
  290. $plugin_data = get_plugin_data( WPMU_PLUGIN_DIR . "/$plugin_file", false, false ); //Do not apply markup/translate as it'll be cached.
  291. if ( empty ( $plugin_data['Name'] ) )
  292. $plugin_data['Name'] = $plugin_file;
  293. $wp_plugins[ $plugin_file ] = $plugin_data;
  294. }
  295. if ( isset( $wp_plugins['index.php'] ) && filesize( WPMU_PLUGIN_DIR . '/index.php') <= 30 ) // silence is golden
  296. unset( $wp_plugins['index.php'] );
  297. uasort( $wp_plugins, '_sort_uname_callback' );
  298. return $wp_plugins;
  299. }
  300. /**
  301. * Callback to sort array by a 'Name' key.
  302. *
  303. * @since 3.1.0
  304. * @access private
  305. */
  306. function _sort_uname_callback( $a, $b ) {
  307. return strnatcasecmp( $a['Name'], $b['Name'] );
  308. }
  309. /**
  310. * Check the wp-content directory and retrieve all drop-ins with any plugin data.
  311. *
  312. * @since 3.0.0
  313. * @return array Key is the file path and the value is an array of the plugin data.
  314. */
  315. function get_dropins() {
  316. $dropins = array();
  317. $plugin_files = array();
  318. $_dropins = _get_dropins();
  319. // These exist in the wp-content directory
  320. if ( $plugins_dir = @ opendir( WP_CONTENT_DIR ) ) {
  321. while ( ( $file = readdir( $plugins_dir ) ) !== false ) {
  322. if ( isset( $_dropins[ $file ] ) )
  323. $plugin_files[] = $file;
  324. }
  325. } else {
  326. return $dropins;
  327. }
  328. @closedir( $plugins_dir );
  329. if ( empty($plugin_files) )
  330. return $dropins;
  331. foreach ( $plugin_files as $plugin_file ) {
  332. if ( !is_readable( WP_CONTENT_DIR . "/$plugin_file" ) )
  333. continue;
  334. $plugin_data = get_plugin_data( WP_CONTENT_DIR . "/$plugin_file", false, false ); //Do not apply markup/translate as it'll be cached.
  335. if ( empty( $plugin_data['Name'] ) )
  336. $plugin_data['Name'] = $plugin_file;
  337. $dropins[ $plugin_file ] = $plugin_data;
  338. }
  339. uksort( $dropins, 'strnatcasecmp' );
  340. return $dropins;
  341. }
  342. /**
  343. * Returns drop-ins that WordPress uses.
  344. *
  345. * Includes Multisite drop-ins only when is_multisite()
  346. *
  347. * @since 3.0.0
  348. * @return array Key is file name. The value is an array, with the first value the
  349. * purpose of the drop-in and the second value the name of the constant that must be
  350. * true for the drop-in to be used, or true if no constant is required.
  351. */
  352. function _get_dropins() {
  353. $dropins = array(
  354. 'advanced-cache.php' => array( __( 'Advanced caching plugin.' ), 'WP_CACHE' ), // WP_CACHE
  355. 'db.php' => array( __( 'Custom database class.' ), true ), // auto on load
  356. 'db-error.php' => array( __( 'Custom database error message.' ), true ), // auto on error
  357. 'install.php' => array( __( 'Custom install script.' ), true ), // auto on install
  358. 'maintenance.php' => array( __( 'Custom maintenance message.' ), true ), // auto on maintenance
  359. 'object-cache.php' => array( __( 'External object cache.' ), true ), // auto on load
  360. );
  361. if ( is_multisite() ) {
  362. $dropins['sunrise.php' ] = array( __( 'Executed before Multisite is loaded.' ), 'SUNRISE' ); // SUNRISE
  363. $dropins['blog-deleted.php' ] = array( __( 'Custom site deleted message.' ), true ); // auto on deleted blog
  364. $dropins['blog-inactive.php' ] = array( __( 'Custom site inactive message.' ), true ); // auto on inactive blog
  365. $dropins['blog-suspended.php'] = array( __( 'Custom site suspended message.' ), true ); // auto on archived or spammed blog
  366. }
  367. return $dropins;
  368. }
  369. /**
  370. * Check whether the plugin is active by checking the active_plugins list.
  371. *
  372. * @since 2.5.0
  373. *
  374. * @param string $plugin Base plugin path from plugins directory.
  375. * @return bool True, if in the active plugins list. False, not in the list.
  376. */
  377. function is_plugin_active( $plugin ) {
  378. return in_array( $plugin, (array) get_option( 'active_plugins', array() ) ) || is_plugin_active_for_network( $plugin );
  379. }
  380. /**
  381. * Check whether the plugin is inactive.
  382. *
  383. * Reverse of is_plugin_active(). Used as a callback.
  384. *
  385. * @since 3.1.0
  386. * @see is_plugin_active()
  387. *
  388. * @param string $plugin Base plugin path from plugins directory.
  389. * @return bool True if inactive. False if active.
  390. */
  391. function is_plugin_inactive( $plugin ) {
  392. return ! is_plugin_active( $plugin );
  393. }
  394. /**
  395. * Check whether the plugin is active for the entire network.
  396. *
  397. * @since 3.0.0
  398. *
  399. * @param string $plugin Base plugin path from plugins directory.
  400. * @return bool True, if active for the network, otherwise false.
  401. */
  402. function is_plugin_active_for_network( $plugin ) {
  403. if ( !is_multisite() )
  404. return false;
  405. $plugins = get_site_option( 'active_sitewide_plugins');
  406. if ( isset($plugins[$plugin]) )
  407. return true;
  408. return false;
  409. }
  410. /**
  411. * Checks for "Network: true" in the plugin header to see if this should
  412. * be activated only as a network wide plugin. The plugin would also work
  413. * when Multisite is not enabled.
  414. *
  415. * Checks for "Site Wide Only: true" for backwards compatibility.
  416. *
  417. * @since 3.0.0
  418. *
  419. * @param string $plugin Plugin to check
  420. * @return bool True if plugin is network only, false otherwise.
  421. */
  422. function is_network_only_plugin( $plugin ) {
  423. $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
  424. if ( $plugin_data )
  425. return $plugin_data['Network'];
  426. return false;
  427. }
  428. /**
  429. * Attempts activation of plugin in a "sandbox" and redirects on success.
  430. *
  431. * A plugin that is already activated will not attempt to be activated again.
  432. *
  433. * The way it works is by setting the redirection to the error before trying to
  434. * include the plugin file. If the plugin fails, then the redirection will not
  435. * be overwritten with the success message. Also, the options will not be
  436. * updated and the activation hook will not be called on plugin error.
  437. *
  438. * It should be noted that in no way the below code will actually prevent errors
  439. * within the file. The code should not be used elsewhere to replicate the
  440. * "sandbox", which uses redirection to work.
  441. * {@source 13 1}
  442. *
  443. * If any errors are found or text is outputted, then it will be captured to
  444. * ensure that the success redirection will update the error redirection.
  445. *
  446. * @since 2.5.0
  447. *
  448. * @param string $plugin Plugin path to main plugin file with plugin data.
  449. * @param string $redirect Optional. URL to redirect to.
  450. * @param bool $network_wide Whether to enable the plugin for all sites in the
  451. * network or just the current site. Multisite only. Default is false.
  452. * @param bool $silent Prevent calling activation hooks. Optional, default is false.
  453. * @return WP_Error|null WP_Error on invalid file or null on success.
  454. */
  455. function activate_plugin( $plugin, $redirect = '', $network_wide = false, $silent = false ) {
  456. $plugin = plugin_basename( trim( $plugin ) );
  457. if ( is_multisite() && ( $network_wide || is_network_only_plugin($plugin) ) ) {
  458. $network_wide = true;
  459. $current = get_site_option( 'active_sitewide_plugins', array() );
  460. $_GET['networkwide'] = 1; // Back compat for plugins looking for this value.
  461. } else {
  462. $current = get_option( 'active_plugins', array() );
  463. }
  464. $valid = validate_plugin($plugin);
  465. if ( is_wp_error($valid) )
  466. return $valid;
  467. if ( !in_array($plugin, $current) ) {
  468. if ( !empty($redirect) )
  469. wp_redirect(add_query_arg('_error_nonce', wp_create_nonce('plugin-activation-error_' . $plugin), $redirect)); // we'll override this later if the plugin can be included without fatal error
  470. ob_start();
  471. include_once(WP_PLUGIN_DIR . '/' . $plugin);
  472. if ( ! $silent ) {
  473. do_action( 'activate_plugin', $plugin, $network_wide );
  474. do_action( 'activate_' . $plugin, $network_wide );
  475. }
  476. if ( $network_wide ) {
  477. $current[$plugin] = time();
  478. update_site_option( 'active_sitewide_plugins', $current );
  479. } else {
  480. $current[] = $plugin;
  481. sort($current);
  482. update_option('active_plugins', $current);
  483. }
  484. if ( ! $silent ) {
  485. do_action( 'activated_plugin', $plugin, $network_wide );
  486. }
  487. if ( ob_get_length() > 0 ) {
  488. $output = ob_get_clean();
  489. return new WP_Error('unexpected_output', __('The plugin generated unexpected output.'), $output);
  490. }
  491. ob_end_clean();
  492. }
  493. return null;
  494. }
  495. /**
  496. * Deactivate a single plugin or multiple plugins.
  497. *
  498. * The deactivation hook is disabled by the plugin upgrader by using the $silent
  499. * parameter.
  500. *
  501. * @since 2.5.0
  502. *
  503. * @param string|array $plugins Single plugin or list of plugins to deactivate.
  504. * @param bool $silent Prevent calling deactivation hooks. Default is false.
  505. * @param mixed $network_wide Whether to deactivate the plugin for all sites in the network.
  506. * A value of null (the default) will deactivate plugins for both the site and the network.
  507. */
  508. function deactivate_plugins( $plugins, $silent = false, $network_wide = null ) {
  509. if ( is_multisite() )
  510. $network_current = get_site_option( 'active_sitewide_plugins', array() );
  511. $current = get_option( 'active_plugins', array() );
  512. $do_blog = $do_network = false;
  513. foreach ( (array) $plugins as $plugin ) {
  514. $plugin = plugin_basename( trim( $plugin ) );
  515. if ( ! is_plugin_active($plugin) )
  516. continue;
  517. $network_deactivating = false !== $network_wide && is_plugin_active_for_network( $plugin );
  518. if ( ! $silent )
  519. do_action( 'deactivate_plugin', $plugin, $network_deactivating );
  520. if ( false !== $network_wide ) {
  521. if ( is_plugin_active_for_network( $plugin ) ) {
  522. $do_network = true;
  523. unset( $network_current[ $plugin ] );
  524. } elseif ( $network_wide ) {
  525. continue;
  526. }
  527. }
  528. if ( true !== $network_wide ) {
  529. $key = array_search( $plugin, $current );
  530. if ( false !== $key ) {
  531. $do_blog = true;
  532. unset( $current[ $key ] );
  533. }
  534. }
  535. if ( ! $silent ) {
  536. do_action( 'deactivate_' . $plugin, $network_deactivating );
  537. do_action( 'deactivated_plugin', $plugin, $network_deactivating );
  538. }
  539. }
  540. if ( $do_blog )
  541. update_option('active_plugins', $current);
  542. if ( $do_network )
  543. update_site_option( 'active_sitewide_plugins', $network_current );
  544. }
  545. /**
  546. * Activate multiple plugins.
  547. *
  548. * When WP_Error is returned, it does not mean that one of the plugins had
  549. * errors. It means that one or more of the plugins file path was invalid.
  550. *
  551. * The execution will be halted as soon as one of the plugins has an error.
  552. *
  553. * @since 2.6.0
  554. *
  555. * @param string|array $plugins
  556. * @param string $redirect Redirect to page after successful activation.
  557. * @param bool $network_wide Whether to enable the plugin for all sites in the network.
  558. * @param bool $silent Prevent calling activation hooks. Default is false.
  559. * @return bool|WP_Error True when finished or WP_Error if there were errors during a plugin activation.
  560. */
  561. function activate_plugins( $plugins, $redirect = '', $network_wide = false, $silent = false ) {
  562. if ( !is_array($plugins) )
  563. $plugins = array($plugins);
  564. $errors = array();
  565. foreach ( $plugins as $plugin ) {
  566. if ( !empty($redirect) )
  567. $redirect = add_query_arg('plugin', $plugin, $redirect);
  568. $result = activate_plugin($plugin, $redirect, $network_wide, $silent);
  569. if ( is_wp_error($result) )
  570. $errors[$plugin] = $result;
  571. }
  572. if ( !empty($errors) )
  573. return new WP_Error('plugins_invalid', __('One of the plugins is invalid.'), $errors);
  574. return true;
  575. }
  576. /**
  577. * Remove directory and files of a plugin for a single or list of plugin(s).
  578. *
  579. * If the plugins parameter list is empty, false will be returned. True when
  580. * completed.
  581. *
  582. * @since 2.6.0
  583. *
  584. * @param array $plugins List of plugin
  585. * @param string $redirect Redirect to page when complete.
  586. * @return mixed
  587. */
  588. function delete_plugins($plugins, $redirect = '' ) {
  589. global $wp_filesystem;
  590. if ( empty($plugins) )
  591. return false;
  592. $checked = array();
  593. foreach( $plugins as $plugin )
  594. $checked[] = 'checked[]=' . $plugin;
  595. ob_start();
  596. $url = wp_nonce_url('plugins.php?action=delete-selected&verify-delete=1&' . implode('&', $checked), 'bulk-plugins');
  597. if ( false === ($credentials = request_filesystem_credentials($url)) ) {
  598. $data = ob_get_contents();
  599. ob_end_clean();
  600. if ( ! empty($data) ){
  601. include_once( ABSPATH . 'wp-admin/admin-header.php');
  602. echo $data;
  603. include( ABSPATH . 'wp-admin/admin-footer.php');
  604. exit;
  605. }
  606. return;
  607. }
  608. if ( ! WP_Filesystem($credentials) ) {
  609. request_filesystem_credentials($url, '', true); //Failed to connect, Error and request again
  610. $data = ob_get_contents();
  611. ob_end_clean();
  612. if ( ! empty($data) ){
  613. include_once( ABSPATH . 'wp-admin/admin-header.php');
  614. echo $data;
  615. include( ABSPATH . 'wp-admin/admin-footer.php');
  616. exit;
  617. }
  618. return;
  619. }
  620. if ( ! is_object($wp_filesystem) )
  621. return new WP_Error('fs_unavailable', __('Could not access filesystem.'));
  622. if ( is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code() )
  623. return new WP_Error('fs_error', __('Filesystem error.'), $wp_filesystem->errors);
  624. //Get the base plugin folder
  625. $plugins_dir = $wp_filesystem->wp_plugins_dir();
  626. if ( empty($plugins_dir) )
  627. return new WP_Error('fs_no_plugins_dir', __('Unable to locate WordPress Plugin directory.'));
  628. $plugins_dir = trailingslashit( $plugins_dir );
  629. $errors = array();
  630. foreach( $plugins as $plugin_file ) {
  631. // Run Uninstall hook
  632. if ( is_uninstallable_plugin( $plugin_file ) )
  633. uninstall_plugin($plugin_file);
  634. $this_plugin_dir = trailingslashit( dirname($plugins_dir . $plugin_file) );
  635. // If plugin is in its own directory, recursively delete the directory.
  636. if ( strpos($plugin_file, '/') && $this_plugin_dir != $plugins_dir ) //base check on if plugin includes directory separator AND that its not the root plugin folder
  637. $deleted = $wp_filesystem->delete($this_plugin_dir, true);
  638. else
  639. $deleted = $wp_filesystem->delete($plugins_dir . $plugin_file);
  640. if ( ! $deleted )
  641. $errors[] = $plugin_file;
  642. }
  643. if ( ! empty($errors) )
  644. return new WP_Error('could_not_remove_plugin', sprintf(__('Could not fully remove the plugin(s) %s.'), implode(', ', $errors)) );
  645. // Force refresh of plugin update information
  646. if ( $current = get_site_transient('update_plugins') ) {
  647. unset( $current->response[ $plugin_file ] );
  648. set_site_transient('update_plugins', $current);
  649. }
  650. return true;
  651. }
  652. /**
  653. * Validate active plugins
  654. *
  655. * Validate all active plugins, deactivates invalid and
  656. * returns an array of deactivated ones.
  657. *
  658. * @since 2.5.0
  659. * @return array invalid plugins, plugin as key, error as value
  660. */
  661. function validate_active_plugins() {
  662. $plugins = get_option( 'active_plugins', array() );
  663. // validate vartype: array
  664. if ( ! is_array( $plugins ) ) {
  665. update_option( 'active_plugins', array() );
  666. $plugins = array();
  667. }
  668. if ( is_multisite() && is_super_admin() ) {
  669. $network_plugins = (array) get_site_option( 'active_sitewide_plugins', array() );
  670. $plugins = array_merge( $plugins, array_keys( $network_plugins ) );
  671. }
  672. if ( empty( $plugins ) )
  673. return;
  674. $invalid = array();
  675. // invalid plugins get deactivated
  676. foreach ( $plugins as $plugin ) {
  677. $result = validate_plugin( $plugin );
  678. if ( is_wp_error( $result ) ) {
  679. $invalid[$plugin] = $result;
  680. deactivate_plugins( $plugin, true );
  681. }
  682. }
  683. return $invalid;
  684. }
  685. /**
  686. * Validate the plugin path.
  687. *
  688. * Checks that the file exists and {@link validate_file() is valid file}.
  689. *
  690. * @since 2.5.0
  691. *
  692. * @param string $plugin Plugin Path
  693. * @return WP_Error|int 0 on success, WP_Error on failure.
  694. */
  695. function validate_plugin($plugin) {
  696. if ( validate_file($plugin) )
  697. return new WP_Error('plugin_invalid', __('Invalid plugin path.'));
  698. if ( ! file_exists(WP_PLUGIN_DIR . '/' . $plugin) )
  699. return new WP_Error('plugin_not_found', __('Plugin file does not exist.'));
  700. $installed_plugins = get_plugins();
  701. if ( ! isset($installed_plugins[$plugin]) )
  702. return new WP_Error('no_plugin_header', __('The plugin does not have a valid header.'));
  703. return 0;
  704. }
  705. /**
  706. * Whether the plugin can be uninstalled.
  707. *
  708. * @since 2.7.0
  709. *
  710. * @param string $plugin Plugin path to check.
  711. * @return bool Whether plugin can be uninstalled.
  712. */
  713. function is_uninstallable_plugin($plugin) {
  714. $file = plugin_basename($plugin);
  715. $uninstallable_plugins = (array) get_option('uninstall_plugins');
  716. if ( isset( $uninstallable_plugins[$file] ) || file_exists( WP_PLUGIN_DIR . '/' . dirname($file) . '/uninstall.php' ) )
  717. return true;
  718. return false;
  719. }
  720. /**
  721. * Uninstall a single plugin.
  722. *
  723. * Calls the uninstall hook, if it is available.
  724. *
  725. * @since 2.7.0
  726. *
  727. * @param string $plugin Relative plugin path from Plugin Directory.
  728. */
  729. function uninstall_plugin($plugin) {
  730. $file = plugin_basename($plugin);
  731. $uninstallable_plugins = (array) get_option('uninstall_plugins');
  732. if ( file_exists( WP_PLUGIN_DIR . '/' . dirname($file) . '/uninstall.php' ) ) {
  733. if ( isset( $uninstallable_plugins[$file] ) ) {
  734. unset($uninstallable_plugins[$file]);
  735. update_option('uninstall_plugins', $uninstallable_plugins);
  736. }
  737. unset($uninstallable_plugins);
  738. define('WP_UNINSTALL_PLUGIN', $file);
  739. include WP_PLUGIN_DIR . '/' . dirname($file) . '/uninstall.php';
  740. return true;
  741. }
  742. if ( isset( $uninstallable_plugins[$file] ) ) {
  743. $callable = $uninstallable_plugins[$file];
  744. unset($uninstallable_plugins[$file]);
  745. update_option('uninstall_plugins', $uninstallable_plugins);
  746. unset($uninstallable_plugins);
  747. include WP_PLUGIN_DIR . '/' . $file;
  748. add_action( 'uninstall_' . $file, $callable );
  749. do_action( 'uninstall_' . $file );
  750. }
  751. }
  752. //
  753. // Menu
  754. //
  755. /**
  756. * Add a top level menu page
  757. *
  758. * This function takes a capability which will be used to determine whether
  759. * or not a page is included in the menu.
  760. *
  761. * The function which is hooked in to handle the output of the page must check
  762. * that the user has the required capability as well.
  763. *
  764. * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
  765. * @param string $menu_title The text to be used for the menu
  766. * @param string $capability The capability required for this menu to be displayed to the user.
  767. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
  768. * @param callback $function The function to be called to output the content for this page.
  769. * @param string $icon_url The url to the icon to be used for this menu. Using 'none' would leave div.wp-menu-image empty
  770. * so an icon can be added as background with CSS.
  771. * @param int $position The position in the menu order this one should appear
  772. *
  773. * @return string The resulting page's hook_suffix
  774. */
  775. function add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $icon_url = '', $position = null ) {
  776. global $menu, $admin_page_hooks, $_registered_pages, $_parent_pages;
  777. $menu_slug = plugin_basename( $menu_slug );
  778. $admin_page_hooks[$menu_slug] = sanitize_title( $menu_title );
  779. $hookname = get_plugin_page_hookname( $menu_slug, '' );
  780. if ( !empty( $function ) && !empty( $hookname ) && current_user_can( $capability ) )
  781. add_action( $hookname, $function );
  782. if ( empty($icon_url) ) {
  783. $icon_url = 'none';
  784. $icon_class = 'menu-icon-generic ';
  785. } else {
  786. $icon_url = set_url_scheme( $icon_url );
  787. $icon_class = '';
  788. }
  789. $new_menu = array( $menu_title, $capability, $menu_slug, $page_title, 'menu-top ' . $icon_class . $hookname, $hookname, $icon_url );
  790. if ( null === $position )
  791. $menu[] = $new_menu;
  792. else
  793. $menu[$position] = $new_menu;
  794. $_registered_pages[$hookname] = true;
  795. // No parent as top level
  796. $_parent_pages[$menu_slug] = false;
  797. return $hookname;
  798. }
  799. /**
  800. * Add a top level menu page in the 'objects' section
  801. *
  802. * This function takes a capability which will be used to determine whether
  803. * or not a page is included in the menu.
  804. *
  805. * The function which is hooked in to handle the output of the page must check
  806. * that the user has the required capability as well.
  807. *
  808. * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
  809. * @param string $menu_title The text to be used for the menu
  810. * @param string $capability The capability required for this menu to be displayed to the user.
  811. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
  812. * @param callback $function The function to be called to output the content for this page.
  813. * @param string $icon_url The url to the icon to be used for this menu
  814. *
  815. * @return string The resulting page's hook_suffix
  816. */
  817. function add_object_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $icon_url = '') {
  818. global $_wp_last_object_menu;
  819. $_wp_last_object_menu++;
  820. return add_menu_page($page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $_wp_last_object_menu);
  821. }
  822. /**
  823. * Add a top level menu page in the 'utility' section
  824. *
  825. * This function takes a capability which will be used to determine whether
  826. * or not a page is included in the menu.
  827. *
  828. * The function which is hooked in to handle the output of the page must check
  829. * that the user has the required capability as well.
  830. *
  831. * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
  832. * @param string $menu_title The text to be used for the menu
  833. * @param string $capability The capability required for this menu to be displayed to the user.
  834. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
  835. * @param callback $function The function to be called to output the content for this page.
  836. * @param string $icon_url The url to the icon to be used for this menu
  837. *
  838. * @return string The resulting page's hook_suffix
  839. */
  840. function add_utility_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $icon_url = '') {
  841. global $_wp_last_utility_menu;
  842. $_wp_last_utility_menu++;
  843. return add_menu_page($page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $_wp_last_utility_menu);
  844. }
  845. /**
  846. * Add a sub menu page
  847. *
  848. * This function takes a capability which will be used to determine whether
  849. * or not a page is included in the menu.
  850. *
  851. * The function which is hooked in to handle the output of the page must check
  852. * that the user has the required capability as well.
  853. *
  854. * @param string $parent_slug The slug name for the parent menu (or the file name of a standard WordPress admin page)
  855. * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
  856. * @param string $menu_title The text to be used for the menu
  857. * @param string $capability The capability required for this menu to be displayed to the user.
  858. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
  859. * @param callback $function The function to be called to output the content for this page.
  860. *
  861. * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
  862. */
  863. function add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
  864. global $submenu;
  865. global $menu;
  866. global $_wp_real_parent_file;
  867. global $_wp_submenu_nopriv;
  868. global $_registered_pages;
  869. global $_parent_pages;
  870. $menu_slug = plugin_basename( $menu_slug );
  871. $parent_slug = plugin_basename( $parent_slug);
  872. if ( isset( $_wp_real_parent_file[$parent_slug] ) )
  873. $parent_slug = $_wp_real_parent_file[$parent_slug];
  874. if ( !current_user_can( $capability ) ) {
  875. $_wp_submenu_nopriv[$parent_slug][$menu_slug] = true;
  876. return false;
  877. }
  878. // If the parent doesn't already have a submenu, add a link to the parent
  879. // as the first item in the submenu. If the submenu file is the same as the
  880. // parent file someone is trying to link back to the parent manually. In
  881. // this case, don't automatically add a link back to avoid duplication.
  882. if (!isset( $submenu[$parent_slug] ) && $menu_slug != $parent_slug ) {
  883. foreach ( (array)$menu as $parent_menu ) {
  884. if ( $parent_menu[2] == $parent_slug && current_user_can( $parent_menu[1] ) )
  885. $submenu[$parent_slug][] = $parent_menu;
  886. }
  887. }
  888. $submenu[$parent_slug][] = array ( $menu_title, $capability, $menu_slug, $page_title );
  889. $hookname = get_plugin_page_hookname( $menu_slug, $parent_slug);
  890. if (!empty ( $function ) && !empty ( $hookname ))
  891. add_action( $hookname, $function );
  892. $_registered_pages[$hookname] = true;
  893. // backwards-compatibility for plugins using add_management page. See wp-admin/admin.php for redirect from edit.php to tools.php
  894. if ( 'tools.php' == $parent_slug )
  895. $_registered_pages[get_plugin_page_hookname( $menu_slug, 'edit.php')] = true;
  896. // No parent as top level
  897. $_parent_pages[$menu_slug] = $parent_slug;
  898. return $hookname;
  899. }
  900. /**
  901. * Add sub menu page to the tools main menu.
  902. *
  903. * This function takes a capability which will be used to determine whether
  904. * or not a page is included in the menu.
  905. *
  906. * The function which is hooked in to handle the output of the page must check
  907. * that the user has the required capability as well.
  908. *
  909. * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
  910. * @param string $menu_title The text to be used for the menu
  911. * @param string $capability The capability required for this menu to be displayed to the user.
  912. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
  913. * @param callback $function The function to be called to output the content for this page.
  914. *
  915. * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
  916. */
  917. function add_management_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
  918. return add_submenu_page( 'tools.php', $page_title, $menu_title, $capability, $menu_slug, $function );
  919. }
  920. /**
  921. * Add sub menu page to the options main menu.
  922. *
  923. * This function takes a capability which will be used to determine whether
  924. * or not a page is included in the menu.
  925. *
  926. * The function which is hooked in to handle the output of the page must check
  927. * that the user has the required capability as well.
  928. *
  929. * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
  930. * @param string $menu_title The text to be used for the menu
  931. * @param string $capability The capability required for this menu to be displayed to the user.
  932. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
  933. * @param callback $function The function to be called to output the content for this page.
  934. *
  935. * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
  936. */
  937. function add_options_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
  938. return add_submenu_page( 'options-general.php', $page_title, $menu_title, $capability, $menu_slug, $function );
  939. }
  940. /**
  941. * Add sub menu page to the themes main menu.
  942. *
  943. * This function takes a capability which will be used to determine whether
  944. * or not a page is included in the menu.
  945. *
  946. * The function which is hooked in to handle the output of the page must check
  947. * that the user has the required capability as well.
  948. *
  949. * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
  950. * @param string $menu_title The text to be used for the menu
  951. * @param string $capability The capability required for this menu to be displayed to the user.
  952. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
  953. * @param callback $function The function to be called to output the content for this page.
  954. *
  955. * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
  956. */
  957. function add_theme_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
  958. return add_submenu_page( 'themes.php', $page_title, $menu_title, $capability, $menu_slug, $function );
  959. }
  960. /**
  961. * Add sub menu page to the plugins main menu.
  962. *
  963. * This function takes a capability which will be used to determine whether
  964. * or not a page is included in the menu.
  965. *
  966. * The function which is hooked in to handle the output of the page must check
  967. * that the user has the required capability as well.
  968. *
  969. * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
  970. * @param string $menu_title The text to be used for the menu
  971. * @param string $capability The capability required for this menu to be displayed to the user.
  972. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
  973. * @param callback $function The function to be called to output the content for this page.
  974. *
  975. * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
  976. */
  977. function add_plugins_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
  978. return add_submenu_page( 'plugins.php', $page_title, $menu_title, $capability, $menu_slug, $function );
  979. }
  980. /**
  981. * Add sub menu page to the Users/Profile main menu.
  982. *
  983. * This function takes a capability which will be used to determine whether
  984. * or not a page is included in the menu.
  985. *
  986. * The function which is hooked in to handle the output of the page must check
  987. * that the user has the required capability as well.
  988. *
  989. * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
  990. * @param string $menu_title The text to be used for the menu
  991. * @param string $capability The capability required for this menu to be displayed to the user.
  992. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
  993. * @param callback $function The function to be called to output the content for this page.
  994. *
  995. * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
  996. */
  997. function add_users_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
  998. if ( current_user_can('edit_users') )
  999. $parent = 'users.php';
  1000. else
  1001. $parent = 'profile.php';
  1002. return add_submenu_page( $parent, $page_title, $menu_title, $capability, $menu_slug, $function );
  1003. }
  1004. /**
  1005. * Add sub menu page to the Dashboard main menu.
  1006. *
  1007. * This function takes a capability which will be used to determine whether
  1008. * or not a page is included in the menu.
  1009. *
  1010. * The function which is hooked in to handle the output of the page must check
  1011. * that the user has the required capability as well.
  1012. *
  1013. * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
  1014. * @param string $menu_title The text to be used for the menu
  1015. * @param string $capability The capability required for this menu to be displayed to the user.
  1016. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
  1017. * @param callback $function The function to be called to output the content for this page.
  1018. *
  1019. * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
  1020. */
  1021. function add_dashboard_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
  1022. return add_submenu_page( 'index.php', $page_title, $menu_title, $capability, $menu_slug, $function );
  1023. }
  1024. /**
  1025. * Add sub menu page to the posts main menu.
  1026. *
  1027. * This function takes a capability which will be used to determine whether
  1028. * or not a page is included in the menu.
  1029. *
  1030. * The function which is hooked in to handle the output of the page must check
  1031. * that the user has the required capability as well.
  1032. *
  1033. * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
  1034. * @param string $menu_title The text to be used for the menu
  1035. * @param string $capability The capability required for this menu to be displayed to the user.
  1036. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
  1037. * @param callback $function The function to be called to output the content for this page.
  1038. *
  1039. * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
  1040. */
  1041. function add_posts_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
  1042. return add_submenu_page( 'edit.php', $page_title, $menu_title, $capability, $menu_slug, $function );
  1043. }
  1044. /**
  1045. * Add sub menu page to the media main menu.
  1046. *
  1047. * This function takes a capability which will be used to determine whether
  1048. * or not a page is included in the menu.
  1049. *
  1050. * The function which is hooked in to handle the output of the page must check
  1051. * that the user has the required capability as well.
  1052. *
  1053. * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
  1054. * @param string $menu_title The text to be used for the menu
  1055. * @param string $capability The capability required for this menu to be displayed to the user.
  1056. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
  1057. * @param callback $function The function to be called to output the content for this page.
  1058. *
  1059. * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
  1060. */
  1061. function add_media_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
  1062. return add_submenu_page( 'upload.php', $page_title, $menu_title, $capability, $menu_slug, $function );
  1063. }
  1064. /**
  1065. * Add sub menu page to the links main menu.
  1066. *
  1067. * This function takes a capability which will be used to determine whether
  1068. * or not a page is included in the menu.
  1069. *
  1070. * The function which is hooked in to handle the output of the page must check
  1071. * that the user has the required capability as well.
  1072. *
  1073. * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
  1074. * @param string $menu_title The text to be used for the menu
  1075. * @param string $capability The capability required for this menu to be displayed to the user.
  1076. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
  1077. * @param callback $function The function to be called to output the content for this page.
  1078. *
  1079. * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
  1080. */
  1081. function add_links_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
  1082. return add_submenu_page( 'link-manager.php', $page_title, $menu_title, $capability, $menu_slug, $function );
  1083. }
  1084. /**
  1085. * Add sub menu page to the pages main menu.
  1086. *
  1087. * This function takes a capability which will be used to determine whether
  1088. * or not a page is included in the menu.
  1089. *
  1090. * The function which is hooked in to handle the output of the page must check
  1091. * that the user has the required capability as well.
  1092. *
  1093. * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
  1094. * @param string $menu_title The text to be used for the menu
  1095. * @param string $capability The capability required for this menu to be displayed to the user.
  1096. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
  1097. * @param callback $function The function to be called to output the content for this page.
  1098. *
  1099. * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
  1100. */
  1101. function add_pages_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
  1102. return add_submenu_page( 'edit.php?post_type=page', $page_title, $menu_title, $capability, $menu_slug, $function );
  1103. }
  1104. /**
  1105. * Add sub menu page to the comments main menu.
  1106. *
  1107. * This function takes a capability which will be used to determine whether
  1108. * or not a page is included in the menu.
  1109. *
  1110. * The function which is hooked in to handle the output of the page must check
  1111. * that the user has the required capability as well.
  1112. *
  1113. * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
  1114. * @param string $menu_title The text to be used for the menu
  1115. * @param string $capability The capability required for this menu to be displayed to the user.
  1116. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
  1117. * @param callback $function The function to be called to output the content for this page.
  1118. *
  1119. * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
  1120. */
  1121. function add_comments_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
  1122. return add_submenu_page( 'edit-comments.php', $page_title, $menu_title, $capability, $menu_slug, $function );
  1123. }
  1124. /**
  1125. * Remove a top level admin menu
  1126. *
  1127. * @since 3.1.0
  1128. *
  1129. * @param string $menu_slug The slug of the menu
  1130. * @return array|bool The removed menu on success, False if not found
  1131. */
  1132. function remove_menu_page( $menu_slug ) {
  1133. global $menu;
  1134. foreach ( $menu as $i => $item ) {
  1135. if ( $menu_slug == $item[2] ) {
  1136. unset( $menu[$i] );
  1137. return $item;
  1138. }
  1139. }
  1140. return false;
  1141. }
  1142. /**
  1143. * Remove an admin submenu
  1144. *
  1145. * @since 3.1.0
  1146. *
  1147. * @param string $menu_slug The slug for the parent menu
  1148. * @param string $submenu_slug The slug of the submenu
  1149. * @return array|bool The removed submenu on success, False if not found
  1150. */
  1151. function remove_submenu_page( $menu_slug, $submenu_slug ) {
  1152. global $submenu;
  1153. if ( !isset( $submenu[$menu_slug] ) )
  1154. return false;
  1155. foreach ( $submenu[$menu_slug] as $i => $item ) {
  1156. if ( $submenu_slug == $item[2] ) {
  1157. unset( $submenu[$menu_slug][$i] );
  1158. return $item;
  1159. }
  1160. }
  1161. return false;
  1162. }
  1163. /**
  1164. * Get the url to access a particular menu page based on the slug it was registered with.
  1165. *
  1166. * If the slug hasn't been registered properly no url will be returned
  1167. *
  1168. * @since 3.0
  1169. *
  1170. * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
  1171. * @param bool $echo Whether or not to echo the url - default is true
  1172. * @return string the url
  1173. */
  1174. function menu_page_url($menu_slug, $echo = true) {
  1175. global $_parent_pages;
  1176. if ( isset( $_parent_pages[$menu_slug] ) ) {
  1177. $parent_slug = $_parent_pages[$menu_slug];
  1178. if ( $parent_slug && ! isset( $_parent_pages[$parent_slug] ) ) {
  1179. $url = admin_url( add_query_arg( 'page', $menu_slug, $parent_slug ) );
  1180. } else {
  1181. $url = admin_url( 'admin.php?page=' . $menu_slug );
  1182. }
  1183. } else {
  1184. $url = '';
  1185. }
  1186. $ur

Large files files are truncated, but you can click here to view the full file