PageRenderTime 62ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-admin/includes/plugin.php

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