PageRenderTime 92ms CodeModel.GetById 25ms app.highlight 50ms RepoModel.GetById 1ms app.codeStats 1ms

/wp-admin/includes/plugin.php

https://gitlab.com/geyson/geyson
PHP | 1950 lines | 892 code | 229 blank | 829 comment | 284 complexity | dfa1b141111487e6ed0cdf28c4f9b50d MD5 | raw file

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

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