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 | */ |
---|
72 | function 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 | */ |
---|
115 | function _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 | */ |
---|
185 | function 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 and |
---|
223 | * 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 | */ |
---|
237 | function 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 | */ |
---|
307 | function 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 | */ |
---|
354 | function _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 | */ |
---|
364 | function 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 | */ |
---|
409 | function _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 | */ |
---|
437 | function 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 | */ |
---|
452 | function 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 | */ |
---|
464 | function 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 | */ |
---|
487 | function 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 | */ |
---|
521 | function 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[$plugin] = time(); |
---|
580 | update_site_option( 'active_sitewide_plugins', $current ); |
---|
581 | } else { |
---|
582 | $current[] = $plugin; |
---|
583 | sort($current); |
---|
584 | update_option('active_plugins', $current); |
---|
585 | } |
---|
586 | |
---|
587 | if ( ! $silent ) { |
---|
588 | /** |
---|
589 | * Fires after a plugin has been activated. |
---|
590 | * |
---|
591 | * If a plugin is silently activated (such as during an update), |
---|
592 | * this hook does not fire. |
---|
593 | * |
---|
594 | * @since 2.9.0 |
---|
595 | * |
---|
596 | * @param string $plugin Plugin path to main plugin file with plugin data. |
---|
597 | * @param bool $network_wide Whether to enable the plugin for all sites in the network |
---|
598 | * or just the current site. Multisite only. Default is false. |
---|
599 | */ |
---|
600 | do_action( 'activated_plugin', $plugin, $network_wide ); |
---|
601 | } |
---|
602 | |
---|
603 | if ( ob_get_length() > 0 ) { |
---|
604 | $output = ob_get_clean(); |
---|
605 | return new WP_Error('unexpected_output', __('The plugin generated unexpected output.'), $output); |
---|
606 | } |
---|
607 | ob_end_clean(); |
---|
608 | } |
---|
609 | |
---|
610 | return null; |
---|
611 | } |
---|
612 | |
---|
613 | /** |
---|
614 | * Deactivate a single plugin or multiple plugins. |
---|
615 | * |
---|
616 | * The deactivation hook is disabled by the plugin upgrader by using the $silent |
---|
617 | * parameter. |
---|
618 | * |
---|
619 | * @since 2.5.0 |
---|
620 | * |
---|
621 | * @param string|array $plugins Single plugin or list of plugins to deactivate. |
---|
622 | * @param bool $silent Prevent calling deactivation hooks. Default is false. |
---|
623 | * @param mixed $network_wide Whether to deactivate the plugin for all sites in the network. |
---|
624 | * A value of null (the default) will deactivate plugins for both the site and the network. |
---|
625 | */ |
---|
626 | function deactivate_plugins( $plugins, $silent = false, $network_wide = null ) { |
---|
627 | if ( is_multisite() ) |
---|
628 | $network_current = get_site_option( 'active_sitewide_plugins', array() ); |
---|
629 | $current = get_option( 'active_plugins', array() ); |
---|
630 | $do_blog = $do_network = false; |
---|
631 | |
---|
632 | foreach ( (array) $plugins as $plugin ) { |
---|
633 | $plugin = plugin_basename( trim( $plugin ) ); |
---|
634 | if ( ! is_plugin_active($plugin) ) |
---|
635 | continue; |
---|
636 | |
---|
637 | $network_deactivating = false !== $network_wide && is_plugin_active_for_network( $plugin ); |
---|
638 | |
---|
639 | if ( ! $silent ) { |
---|
640 | /** |
---|
641 | * Fires before a plugin is deactivated. |
---|
642 | * |
---|
643 | * If a plugin is silently deactivated (such as during an update), |
---|
644 | * this hook does not fire. |
---|
645 | * |
---|
646 | * @since 2.9.0 |
---|
647 | * |
---|
648 | * @param string $plugin Plugin path to main plugin file with plugin data. |
---|
649 | * @param bool $network_deactivating Whether the plugin is deactivated for all sites in the network |
---|
650 | * or just the current site. Multisite only. Default is false. |
---|
651 | */ |
---|
652 | do_action( 'deactivate_plugin', $plugin, $network_deactivating ); |
---|
653 | } |
---|
654 | |
---|
655 | if ( false !== $network_wide ) { |
---|
656 | if ( is_plugin_active_for_network( $plugin ) ) { |
---|
657 | $do_network = true; |
---|
658 | unset( $network_current[ $plugin ] ); |
---|
659 | } elseif ( $network_wide ) { |
---|
660 | continue; |
---|
661 | } |
---|
662 | } |
---|
663 | |
---|
664 | if ( true !== $network_wide ) { |
---|
665 | $key = array_search( $plugin, $current ); |
---|
666 | if ( false !== $key ) { |
---|
667 | $do_blog = true; |
---|
668 | unset( $current[ $key ] ); |
---|
669 | } |
---|
670 | } |
---|
671 | |
---|
672 | if ( ! $silent ) { |
---|
673 | /** |
---|
674 | * Fires as a specific plugin is being deactivated. |
---|
675 | * |
---|
676 | * This hook is the "deactivation" hook used internally by |
---|
677 | * {@see register_deactivation_hook()}. The dynamic portion of the |
---|
678 | * hook name, `$plugin`, refers to the plugin basename. |
---|
679 | * |
---|
680 | * If a plugin is silently deactivated (such as during an update), |
---|
681 | * this hook does not fire. |
---|
682 | * |
---|
683 | * @since 2.0.0 |
---|
684 | * |
---|
685 | * @param bool $network_deactivating Whether the plugin is deactivated for all sites in the network |
---|
686 | * or just the current site. Multisite only. Default is false. |
---|
687 | */ |
---|
688 | do_action( 'deactivate_' . $plugin, $network_deactivating ); |
---|
689 | |
---|
690 | /** |
---|
691 | * Fires after a plugin is deactivated. |
---|
692 | * |
---|
693 | * If a plugin is silently deactivated (such as during an update), |
---|
694 | * this hook does not fire. |
---|
695 | * |
---|
696 | * @since 2.9.0 |
---|
697 | * |
---|
698 | * @param string $plugin Plugin basename. |
---|
699 | * @param bool $network_deactivating Whether the plugin is deactivated for all sites in the network |
---|
700 | * or just the current site. Multisite only. Default false. |
---|
701 | */ |
---|
702 | do_action( 'deactivated_plugin', $plugin, $network_deactivating ); |
---|
703 | } |
---|
704 | } |
---|
705 | |
---|
706 | if ( $do_blog ) |
---|
707 | update_option('active_plugins', $current); |
---|
708 | if ( $do_network ) |
---|
709 | update_site_option( 'active_sitewide_plugins', $network_current ); |
---|
710 | } |
---|
711 | |
---|
712 | /** |
---|
713 | * Activate multiple plugins. |
---|
714 | * |
---|
715 | * When WP_Error is returned, it does not mean that one of the plugins had |
---|
716 | * errors. It means that one or more of the plugins file path was invalid. |
---|
717 | * |
---|
718 | * The execution will be halted as soon as one of the plugins has an error. |
---|
719 | * |
---|
720 | * @since 2.6.0 |
---|
721 | * |
---|
722 | * @param string|array $plugins Single plugin or list of plugins to activate. |
---|
723 | * @param string $redirect Redirect to page after successful activation. |
---|
724 | * @param bool $network_wide Whether to enable the plugin for all sites in the network. |
---|
725 | * @param bool $silent Prevent calling activation hooks. Default is false. |
---|
726 | * @return bool|WP_Error True when finished or WP_Error if there were errors during a plugin activation. |
---|
727 | */ |
---|
728 | function activate_plugins( $plugins, $redirect = '', $network_wide = false, $silent = false ) { |
---|
729 | if ( !is_array($plugins) ) |
---|
730 | $plugins = array($plugins); |
---|
731 | |
---|
732 | $errors = array(); |
---|
733 | foreach ( $plugins as $plugin ) { |
---|
734 | if ( !empty($redirect) ) |
---|
735 | $redirect = add_query_arg('plugin', $plugin, $redirect); |
---|
736 | $result = activate_plugin($plugin, $redirect, $network_wide, $silent); |
---|
737 | if ( is_wp_error($result) ) |
---|
738 | $errors[$plugin] = $result; |
---|
739 | } |
---|
740 | |
---|
741 | if ( !empty($errors) ) |
---|
742 | return new WP_Error('plugins_invalid', __('One of the plugins is invalid.'), $errors); |
---|
743 | |
---|
744 | return true; |
---|
745 | } |
---|
746 | |
---|
747 | /** |
---|
748 | * Remove directory and files of a plugin for a list of plugins. |
---|
749 | * |
---|
750 | * @since 2.6.0 |
---|
751 | * |
---|
752 | * @param array $plugins List of plugins to delete. |
---|
753 | * @param string $deprecated Deprecated. |
---|
754 | * @return bool|null|WP_Error True on success, false is $plugins is empty, WP_Error on failure. |
---|
755 | * Null if filesystem credentials are required to proceed. |
---|
756 | */ |
---|
757 | function delete_plugins( $plugins, $deprecated = '' ) { |
---|
758 | global $wp_filesystem; |
---|
759 | |
---|
760 | if ( empty($plugins) ) |
---|
761 | return false; |
---|
762 | |
---|
763 | $checked = array(); |
---|
764 | foreach( $plugins as $plugin ) |
---|
765 | $checked[] = 'checked[]=' . $plugin; |
---|
766 | |
---|
767 | ob_start(); |
---|
768 | $url = wp_nonce_url('plugins.php?action=delete-selected&verify-delete=1&' . implode('&', $checked), 'bulk-plugins'); |
---|
769 | if ( false === ($credentials = request_filesystem_credentials($url)) ) { |
---|
770 | $data = ob_get_contents(); |
---|
771 | ob_end_clean(); |
---|
772 | if ( ! empty($data) ){ |
---|
773 | include_once( ABSPATH . 'wp-admin/admin-header.php'); |
---|
774 | echo $data; |
---|
775 | include( ABSPATH . 'wp-admin/admin-footer.php'); |
---|
776 | exit; |
---|
777 | } |
---|
778 | return; |
---|
779 | } |
---|
780 | |
---|
781 | if ( ! WP_Filesystem($credentials) ) { |
---|
782 | request_filesystem_credentials($url, '', true); //Failed to connect, Error and request again |
---|
783 | $data = ob_get_contents(); |
---|
784 | ob_end_clean(); |
---|
785 | if ( ! empty($data) ){ |
---|
786 | include_once( ABSPATH . 'wp-admin/admin-header.php'); |
---|
787 | echo $data; |
---|
788 | include( ABSPATH . 'wp-admin/admin-footer.php'); |
---|
789 | exit; |
---|
790 | } |
---|
791 | return; |
---|
792 | } |
---|
793 | |
---|
794 | if ( ! is_object($wp_filesystem) ) |
---|
795 | return new WP_Error('fs_unavailable', __('Could not access filesystem.')); |
---|
796 | |
---|
797 | if ( is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code() ) |
---|
798 | return new WP_Error('fs_error', __('Filesystem error.'), $wp_filesystem->errors); |
---|
799 | |
---|
800 | // Get the base plugin folder. |
---|
801 | $plugins_dir = $wp_filesystem->wp_plugins_dir(); |
---|
802 | if ( empty( $plugins_dir ) ) { |
---|
803 | return new WP_Error( 'fs_no_plugins_dir', __( 'Unable to locate WordPress Plugin directory.' ) ); |
---|
804 | } |
---|
805 | |
---|
806 | $plugins_dir = trailingslashit( $plugins_dir ); |
---|
807 | |
---|
808 | $plugin_translations = wp_get_installed_translations( 'plugins' ); |
---|
809 | |
---|
810 | $errors = array(); |
---|
811 | |
---|
812 | foreach( $plugins as $plugin_file ) { |
---|
813 | // Run Uninstall hook. |
---|
814 | if ( is_uninstallable_plugin( $plugin_file ) ) { |
---|
815 | uninstall_plugin($plugin_file); |
---|
816 | } |
---|
817 | |
---|
818 | $this_plugin_dir = trailingslashit( dirname( $plugins_dir . $plugin_file ) ); |
---|
819 | // If plugin is in its own directory, recursively delete the directory. |
---|
820 | 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 |
---|
821 | $deleted = $wp_filesystem->delete( $this_plugin_dir, true ); |
---|
822 | } else { |
---|
823 | $deleted = $wp_filesystem->delete( $plugins_dir . $plugin_file ); |
---|
824 | } |
---|
825 | |
---|
826 | if ( ! $deleted ) { |
---|
827 | $errors[] = $plugin_file; |
---|
828 | continue; |
---|
829 | } |
---|
830 | |
---|
831 | // Remove language files, silently. |
---|
832 | $plugin_slug = dirname( $plugin_file ); |
---|
833 | if ( '.' !== $plugin_slug && ! empty( $plugin_translations[ $plugin_slug ] ) ) { |
---|
834 | $translations = $plugin_translations[ $plugin_slug ]; |
---|
835 | |
---|
836 | foreach ( $translations as $translation => $data ) { |
---|
837 | $wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.po' ); |
---|
838 | $wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.mo' ); |
---|
839 | } |
---|
840 | } |
---|
841 | } |
---|
842 | |
---|
843 | // Remove deleted plugins from the plugin updates list. |
---|
844 | if ( $current = get_site_transient('update_plugins') ) { |
---|
845 | // Don't remove the plugins that weren't deleted. |
---|
846 | $deleted = array_diff( $plugins, $errors ); |
---|
847 | |
---|
848 | foreach ( $deleted as $plugin_file ) { |
---|
849 | unset( $current->response[ $plugin_file ] ); |
---|
850 | } |
---|
851 | |
---|
852 | set_site_transient( 'update_plugins', $current ); |
---|
853 | } |
---|
854 | |
---|
855 | if ( ! empty($errors) ) |
---|
856 | return new WP_Error('could_not_remove_plugin', sprintf(__('Could not fully remove the plugin(s) %s.'), implode(', ', $errors)) ); |
---|
857 | |
---|
858 | return true; |
---|
859 | } |
---|
860 | |
---|
861 | /** |
---|
862 | * Validate active plugins |
---|
863 | * |
---|
864 | * Validate all active plugins, deactivates invalid and |
---|
865 | * returns an array of deactivated ones. |
---|
866 | * |
---|
867 | * @since 2.5.0 |
---|
868 | * @return array invalid plugins, plugin as key, error as value |
---|
869 | */ |
---|
870 | function validate_active_plugins() { |
---|
871 | $plugins = get_option( 'active_plugins', array() ); |
---|
872 | // Validate vartype: array. |
---|
873 | if ( ! is_array( $plugins ) ) { |
---|
874 | update_option( 'active_plugins', array() ); |
---|
875 | $plugins = array(); |
---|
876 | } |
---|
877 | |
---|
878 | if ( is_multisite() && current_user_can( 'manage_network_plugins' ) ) { |
---|
879 | $network_plugins = (array) get_site_option( 'active_sitewide_plugins', array() ); |
---|
880 | $plugins = array_merge( $plugins, array_keys( $network_plugins ) ); |
---|
881 | } |
---|
882 | |
---|
883 | if ( empty( $plugins ) ) |
---|
884 | return array(); |
---|
885 | |
---|
886 | $invalid = array(); |
---|
887 | |
---|
888 | // Invalid plugins get deactivated. |
---|
889 | foreach ( $plugins as $plugin ) { |
---|
890 | $result = validate_plugin( $plugin ); |
---|
891 | if ( is_wp_error( $result ) ) { |
---|
892 | $invalid[$plugin] = $result; |
---|
893 | deactivate_plugins( $plugin, true ); |
---|
894 | } |
---|
895 | } |
---|
896 | return $invalid; |
---|
897 | } |
---|
898 | |
---|
899 | /** |
---|
900 | * Validate the plugin path. |
---|
901 | * |
---|
902 | * Checks that the file exists and {@link validate_file() is valid file}. |
---|
903 | * |
---|
904 | * @since 2.5.0 |
---|
905 | * |
---|
906 | * @param string $plugin Plugin Path |
---|
907 | * @return WP_Error|int 0 on success, WP_Error on failure. |
---|
908 | */ |
---|
909 | function validate_plugin($plugin) { |
---|
910 | if ( validate_file($plugin) ) |
---|
911 | return new WP_Error('plugin_invalid', __('Invalid plugin path.')); |
---|
912 | if ( ! file_exists(WP_PLUGIN_DIR . '/' . $plugin) ) |
---|
913 | return new WP_Error('plugin_not_found', __('Plugin file does not exist.')); |
---|
914 | |
---|
915 | $installed_plugins = get_plugins(); |
---|
916 | if ( ! isset($installed_plugins[$plugin]) ) |
---|
917 | return new WP_Error('no_plugin_header', __('The plugin does not have a valid header.')); |
---|
918 | return 0; |
---|
919 | } |
---|
920 | |
---|
921 | /** |
---|
922 | * Whether the plugin can be uninstalled. |
---|
923 | * |
---|
924 | * @since 2.7.0 |
---|
925 | * |
---|
926 | * @param string $plugin Plugin path to check. |
---|
927 | * @return bool Whether plugin can be uninstalled. |
---|
928 | */ |
---|
929 | function is_uninstallable_plugin($plugin) { |
---|
930 | $file = plugin_basename($plugin); |
---|
931 | |
---|
932 | $uninstallable_plugins = (array) get_option('uninstall_plugins'); |
---|
933 | if ( isset( $uninstallable_plugins[$file] ) || file_exists( WP_PLUGIN_DIR . '/' . dirname($file) . '/uninstall.php' ) ) |
---|
934 | return true; |
---|
935 | |
---|
936 | return false; |
---|
937 | } |
---|
938 | |
---|
939 | /** |
---|
940 | * Uninstall a single plugin. |
---|
941 | * |
---|
942 | * Calls the uninstall hook, if it is available. |
---|
943 | * |
---|
944 | * @since 2.7.0 |
---|
945 | * |
---|
946 | * @param string $plugin Relative plugin path from Plugin Directory. |
---|
947 | */ |
---|
948 | function uninstall_plugin($plugin) { |
---|
949 | $file = plugin_basename($plugin); |
---|
950 | |
---|
951 | $uninstallable_plugins = (array) get_option('uninstall_plugins'); |
---|
952 | if ( file_exists( WP_PLUGIN_DIR . '/' . dirname($file) . '/uninstall.php' ) ) { |
---|
953 | if ( isset( $uninstallable_plugins[$file] ) ) { |
---|
954 | unset($uninstallable_plugins[$file]); |
---|
955 | update_option('uninstall_plugins', $uninstallable_plugins); |
---|
956 | } |
---|
957 | unset($uninstallable_plugins); |
---|
958 | |
---|
959 | define('WP_UNINSTALL_PLUGIN', $file); |
---|
960 | wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . dirname( $file ) ); |
---|
961 | include( WP_PLUGIN_DIR . '/' . dirname($file) . '/uninstall.php' ); |
---|
962 | |
---|
963 | return true; |
---|
964 | } |
---|
965 | |
---|
966 | if ( isset( $uninstallable_plugins[$file] ) ) { |
---|
967 | $callable = $uninstallable_plugins[$file]; |
---|
968 | unset($uninstallable_plugins[$file]); |
---|
969 | update_option('uninstall_plugins', $uninstallable_plugins); |
---|
970 | unset($uninstallable_plugins); |
---|
971 | |
---|
972 | wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $file ); |
---|
973 | include( WP_PLUGIN_DIR . '/' . $file ); |
---|
974 | |
---|
975 | add_action( 'uninstall_' . $file, $callable ); |
---|
976 | |
---|
977 | /** |
---|
978 | * Fires in uninstall_plugin() once the plugin has been uninstalled. |
---|
979 | * |
---|
980 | * The action concatenates the 'uninstall_' prefix with the basename of the |
---|
981 | * plugin passed to {@see uninstall_plugin()} to create a dynamically-named action. |
---|
982 | * |
---|
983 | * @since 2.7.0 |
---|
984 | */ |
---|
985 | do_action( 'uninstall_' . $file ); |
---|
986 | } |
---|
987 | } |
---|
988 | |
---|
989 | // |
---|
990 | // Menu |
---|
991 | // |
---|
992 | |
---|
993 | /** |
---|
994 | * Add a top level menu page |
---|
995 | * |
---|
996 | * This function takes a capability which will be used to determine whether |
---|
997 | * or not a page is included in the menu. |
---|
998 | * |
---|
999 | * The function which is hooked in to handle the output of the page must check |
---|
1000 | * that the user has the required capability as well. |
---|
1001 | * |
---|
1002 | * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected |
---|
1003 | * @param string $menu_title The text to be used for the menu |
---|
1004 | * @param string $capability The capability required for this menu to be displayed to the user. |
---|
1005 | * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu) |
---|
1006 | * @param callback $function The function to be called to output the content for this page. |
---|
1007 | * @param string $icon_url The url to the icon to be used for this menu. |
---|
1008 | * * Pass a base64-encoded SVG using a data URI, which will be colored to match the color scheme. |
---|
1009 | * This should begin with 'data:image/svg+xml;base64,'. |
---|
1010 | * * Pass the name of a Dashicons helper class to use a font icon, e.g. 'dashicons-chart-pie'. |
---|
1011 | * * Pass 'none' to leave div.wp-menu-image empty so an icon can be added via CSS. |
---|
1012 | * @param int $position The position in the menu order this one should appear |
---|
1013 | * |
---|
1014 | * @return string The resulting page's hook_suffix |
---|
1015 | */ |
---|
1016 | function add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $icon_url = '', $position = null ) { |
---|
1017 | global $menu, $admin_page_hooks, $_registered_pages, $_parent_pages; |
---|
1018 | |
---|
1019 | $menu_slug = plugin_basename( $menu_slug ); |
---|
1020 | |
---|
1021 | $admin_page_hooks[$menu_slug] = sanitize_title( $menu_title ); |
---|
1022 | |
---|
1023 | $hookname = get_plugin_page_hookname( $menu_slug, '' ); |
---|
1024 | |
---|
1025 | if ( !empty( $function ) && !empty( $hookname ) && current_user_can( $capability ) ) |
---|
1026 | add_action( $hookname, $function ); |
---|
1027 | |
---|
1028 | if ( empty($icon_url) ) { |
---|
1029 | $icon_url = 'dashicons-admin-generic'; |
---|
1030 | $icon_class = 'menu-icon-generic '; |
---|
1031 | } else { |
---|
1032 | $icon_url = set_url_scheme( $icon_url ); |
---|
1033 | $icon_class = ''; |
---|
1034 | } |
---|
1035 | |
---|
1036 | $new_menu = array( $menu_title, $capability, $menu_slug, $page_title, 'menu-top ' . $icon_class . $hookname, $hookname, $icon_url ); |
---|
1037 | |
---|
1038 | if ( null === $position ) |
---|
1039 | $menu[] = $new_menu; |
---|
1040 | else |
---|
1041 | $menu[$position] = $new_menu; |
---|
1042 | |
---|
1043 | $_registered_pages[$hookname] = true; |
---|
1044 | |
---|
1045 | // No parent as top level |
---|
1046 | $_parent_pages[$menu_slug] = false; |
---|
1047 | |
---|
1048 | return $hookname; |
---|
1049 | } |
---|
1050 | |
---|
1051 | /** |
---|
1052 | * Add a top level menu page in the 'objects' section |
---|
1053 | * |
---|
1054 | * This function takes a capability which will be used to determine whether |
---|
1055 | * or not a page is included in the menu. |
---|
1056 | * |
---|
1057 | * The function which is hooked in to handle the output of the page must check |
---|
1058 | * that the user has the required capability as well. |
---|
1059 | * |
---|
1060 | * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected |
---|
1061 | * @param string $menu_title The text to be used for the menu |
---|
1062 | * @param string $capability The capability required for this menu to be displayed to the user. |
---|
1063 | * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu) |
---|
1064 | * @param callback $function The function to be called to output the content for this page. |
---|
1065 | * @param string $icon_url The url to the icon to be used for this menu |
---|
1066 | * |
---|
1067 | * @return string The resulting page's hook_suffix |
---|
1068 | */ |
---|
1069 | function add_object_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $icon_url = '') { |
---|
1070 | global $_wp_last_object_menu; |
---|
1071 | |
---|
1072 | $_wp_last_object_menu++; |
---|
1073 | |
---|
1074 | return add_menu_page($page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $_wp_last_object_menu); |
---|
1075 | } |
---|
1076 | |
---|
1077 | /** |
---|
1078 | * Add a top level menu page in the 'utility' section |
---|
1079 | * |
---|
1080 | * This function takes a capability which will be used to determine whether |
---|
1081 | * or not a page is included in the menu. |
---|
1082 | * |
---|
1083 | * The function which is hooked in to handle the output of the page must check |
---|
1084 | * that the user has the required capability as well. |
---|
1085 | * |
---|
1086 | * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected |
---|
1087 | * @param string $menu_title The text to be used for the menu |
---|
1088 | * @param string $capability The capability required for this menu to be displayed to the user. |
---|
1089 | * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu) |
---|
1090 | * @param callback $function The function to be called to output the content for this page. |
---|
1091 | * @param string $icon_url The url to the icon to be used for this menu |
---|
1092 | * |
---|
1093 | * @return string The resulting page's hook_suffix |
---|
1094 | */ |
---|
1095 | function add_utility_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $icon_url = '') { |
---|
1096 | global $_wp_last_utility_menu; |
---|
1097 | |
---|
1098 | $_wp_last_utility_menu++; |
---|
1099 | |
---|
1100 | return add_menu_page($page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $_wp_last_utility_menu); |
---|
1101 | } |
---|
1102 | |
---|
1103 | /** |
---|
1104 | * Add a sub menu page |
---|
1105 | * |
---|
1106 | * This function takes a capability which will be used to determine whether |
---|
1107 | * or not a page is included in the menu. |
---|
1108 | * |
---|
1109 | * The function which is hooked in to handle the output of the page must check |
---|
1110 | * that the user has the required capability as well. |
---|
1111 | * |
---|
1112 | * @param string $parent_slug The slug name for the parent menu (or the file name of a standard WordPress admin page) |
---|
1113 | * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected |
---|
1114 | * @param string $menu_title The text to be used for the menu |
---|
1115 | * @param string $capability The capability required for this menu to be displayed to the user. |
---|
1116 | * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu) |
---|
1117 | * @param callback $function The function to be called to output the content for this page. |
---|
1118 | * |
---|
1119 | * @return false|string The resulting page's hook_suffix, or false if the user does not have the capability required. |
---|
1120 | */ |
---|
1121 | function add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $function = '' ) { |
---|
1122 | global $submenu; |
---|
1123 | global $menu; |
---|
1124 | global $_wp_real_parent_file; |
---|
1125 | global $_wp_submenu_nopriv; |
---|
1126 | global $_registered_pages; |
---|
1127 | global $_parent_pages; |
---|
1128 | |
---|
1129 | $menu_slug = plugin_basename( $menu_slug ); |
---|
1130 | $parent_slug = plugin_basename( $parent_slug); |
---|
1131 | |
---|
1132 | if ( isset( $_wp_real_parent_file[$parent_slug] ) ) |
---|
1133 | $parent_slug = $_wp_real_parent_file[$parent_slug]; |
---|
1134 | |
---|
1135 | if ( !current_user_can( $capability ) ) { |
---|
1136 | $_wp_submenu_nopriv[$parent_slug][$menu_slug] = true; |
---|
1137 | return false; |
---|
1138 | } |
---|
1139 | |
---|
1140 | /* |
---|
1141 | * If the parent doesn't already have a submenu, add a link to the parent |
---|
1142 | * as the first item in the submenu. If the submenu file is the same as the |
---|
1143 | * parent file someone is trying to link back to the parent manually. In |
---|
1144 | * this case, don't automatically add a link back to avoid duplication. |
---|
1145 | */ |
---|
1146 | if (!isset( $submenu[$parent_slug] ) && $menu_slug != $parent_slug ) { |
---|
1147 | foreach ( (array)$menu as $parent_menu ) { |
---|
1148 | if ( $parent_menu[2] == $parent_slug && current_user_can( $parent_menu[1] ) ) |
---|
1149 | $submenu[$parent_slug][] = array_slice( $parent_menu, 0, 4 ); |
---|
1150 | } |
---|
1151 | } |
---|
1152 | |
---|
1153 | $submenu[$parent_slug][] = array ( $menu_title, $capability, $menu_slug, $page_title ); |
---|
1154 | |
---|
1155 | $hookname = get_plugin_page_hookname( $menu_slug, $parent_slug); |
---|
1156 | if (!empty ( $function ) && !empty ( $hookname )) |
---|
1157 | add_action( $hookname, $function ); |
---|
1158 | |
---|
1159 | $_registered_pages[$hookname] = true; |
---|
1160 | |
---|
1161 | /* |
---|
1162 | * Backward-compatibility for plugins using add_management page. |
---|
1163 | * See wp-admin/admin.php for redirect from edit.php to tools.php |
---|
1164 | */ |
---|
1165 | if ( 'tools.php' == $parent_slug ) |
---|
1166 | $_registered_pages[get_plugin_page_hookname( $menu_slug, 'edit.php')] = true; |
---|
1167 | |
---|
1168 | // No parent as top level. |
---|
1169 | $_parent_pages[$menu_slug] = $parent_slug; |
---|
1170 | |
---|
1171 | return $hookname; |
---|
1172 | } |
---|
1173 | |
---|
1174 | /** |
---|
1175 | * Add sub menu page to the tools main menu. |
---|
1176 | * |
---|
1177 | * This function takes a capability which will be used to determine whether |
---|
1178 | * or not a page is included in the menu. |
---|
1179 | * |
---|
1180 | * The function which is hooked in to handle the output of the page must check |
---|
1181 | * that the user has the required capability as well. |
---|
1182 | * |
---|
1183 | * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected |
---|
1184 | * @param string $menu_title The text to be used for the menu |
---|
1185 | * @param string $capability The capability required for this menu to be displayed to the user. |
---|
1186 | * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu) |
---|
1187 | * @param callback $function The function to be called to output the content for this page. |
---|
1188 | * |
---|
1189 | * @return false|string The resulting page's hook_suffix, or false if the user does not have the capability required. |
---|
1190 | */ |
---|
1191 | function add_management_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) { |
---|
1192 | return add_submenu_page( 'tools.php', $page_title, $menu_title, $capability, $menu_slug, $function ); |
---|
1193 | } |
---|
1194 | |
---|
1195 | /** |
---|
1196 | * Add sub menu page to the options main menu. |
---|
1197 | * |
---|
1198 | * This function takes a capability which will be used to determine whether |
---|
1199 | * or not a page is included in the menu. |
---|
1200 | * |
---|
1201 | * The function which is hooked in to handle the output of the page must check |
---|
1202 | * that the user has the required capability as well. |
---|
1203 | * |
---|
1204 | * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected |
---|
1205 | * @param string $menu_title The text to be used for the menu |
---|
1206 | * @param string $capability The capability required for this menu to be displayed to the user. |
---|
1207 | * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu) |
---|
1208 | * @param callback $function The function to be called to output the content for this page. |
---|
1209 | * |
---|
1210 | * @return false|string The resulting page's hook_suffix, or false if the user does not have the capability required. |
---|
1211 | */ |
---|
1212 | function add_options_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) { |
---|
1213 | return add_submenu_page( 'options-general.php', $page_title, $menu_title, $capability, $menu_slug, $function ); |
---|
1214 | } |
---|
1215 | |
---|
1216 | /** |
---|
1217 | * Add sub menu page to the themes main menu. |
---|
1218 | * |
---|
1219 | * This function takes a capability which will be used to determine whether |
---|
1220 | * or not a page is included in the menu. |
---|
1221 | * |
---|
1222 | * The function which is hooked in to handle the output of the page must check |
---|
1223 | * that the user has the required capability as well. |
---|
1224 | * |
---|
1225 | * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected |
---|
1226 | * @param string $menu_title The text to be used for the menu |
---|
1227 | * @param string $capability The capability required for this menu to be displayed to the user. |
---|
1228 | * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu) |
---|
1229 | * @param callback $function The function to be called to output the content for this page. |
---|
1230 | * |
---|
1231 | * @return false|string The resulting page's hook_suffix, or false if the user does not have the capability required. |
---|
1232 | */ |
---|
1233 | function add_theme_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) { |
---|
1234 | return add_submenu_page( 'themes.php', $page_title, $menu_title, $capability, $menu_slug, $function ); |
---|
1235 | } |
---|
1236 | |
---|
1237 | /** |
---|
1238 | * Add sub menu page to the plugins main menu. |
---|
1239 | * |
---|
1240 | * This function takes a capability which will be used to determine whether |
---|
1241 | * or not a page is included in the menu. |
---|
1242 | * |
---|
1243 | * The function which is hooked in to handle the output of the page must check |
---|
1244 | * that the user has the required capability as well. |
---|
1245 | * |
---|
1246 | * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected |
---|
1247 | * @param string $menu_title The text to be used for the menu |
---|
1248 | * @param string $capability The capability required for this menu to be displayed to the user. |
---|
1249 | * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu) |
---|
1250 | * @param callback $function The function to be called to output the content for this page. |
---|
1251 | * |
---|
1252 | * @return false|string The resulting page's hook_suffix, or false if the user does not have the capability required. |
---|
1253 | */ |
---|
1254 | function add_plugins_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) { |
---|
1255 | return add_submenu_page( 'plugins.php', $page_title, $menu_title, $capability, $menu_slug, $function ); |
---|
1256 | } |
---|
1257 | |
---|
1258 | /** |
---|
1259 | * Add sub menu page to the Users/Profile main menu. |
---|
1260 | * |
---|
1261 | * This function takes a capability which will be used to determine whether |
---|
1262 | * or not a page is included in the menu. |
---|
1263 | * |
---|
1264 | * The function which is hooked in to handle the output of the page must check |
---|
1265 | * that the user has the required capability as well. |
---|
1266 | * |
---|
1267 | * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected |
---|
1268 | * @param string $menu_title The text to be used for the menu |
---|
1269 | * @param string $capability The capability required for this menu to be displayed to the user. |
---|
1270 | * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu) |
---|
1271 | * @param callback $function The function to be called to output the content for this page. |
---|
1272 | * |
---|
1273 | * @return false|string The resulting page's hook_suffix, or false if the user does not have the capability required. |
---|
1274 | */ |
---|
1275 | function add_users_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) { |
---|
1276 | if ( current_user_can('edit_users') ) |
---|
1277 | $parent = 'users.php'; |
---|
1278 | else |
---|
1279 | $parent = 'profile.php'; |
---|
1280 | return add_submenu_page( $parent, $page_title, $menu_title, $capability, $menu_slug, $function ); |
---|
1281 | } |
---|
1282 | /** |
---|
1283 | * Add sub menu page to the Dashboard main menu. |
---|
1284 | * |
---|
1285 | * This function takes a capability which will be used to determine whether |
---|
1286 | * or not a page is included in the menu. |
---|
1287 | * |
---|
1288 | * The function which is hooked in to handle the output of the page must check |
---|
1289 | * that the user has the required capability as well. |
---|
1290 | * |
---|
1291 | * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected |
---|
1292 | * @param string $menu_title The text to be used for the menu |
---|
1293 | * @param string $capability The capability required for this menu to be displayed to the user. |
---|
1294 | * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu) |
---|
1295 | * @param callback $function The function to be called to output the content for this page. |
---|
1296 | * |
---|
1297 | * @return false|string The resulting page's hook_suffix, or false if the user does not have the capability required. |
---|
1298 | */ |
---|
1299 | function add_dashboard_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) { |
---|
1300 | return add_submenu_page( 'index.php', $page_title, $menu_title, $capability, $menu_slug, $function ); |
---|
1301 | } |
---|
1302 | |
---|
1303 | /** |
---|
1304 | * Add sub menu page to the posts main menu. |
---|
1305 | * |
---|
1306 | * This function takes a capability which will be used to determine whether |
---|
1307 | * or not a page is included in the menu. |
---|
1308 | * |
---|
1309 | * The function which is hooked in to handle the output of the page must check |
---|
1310 | * that the user has the required capability as well. |
---|
1311 | * |
---|
1312 | * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected |
---|
1313 | * @param string $menu_title The text to be used for the menu |
---|
1314 | * @param string $capability The capability required for this menu to be displayed to the user. |
---|
1315 | * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu) |
---|
1316 | * @param callback $function The function to be called to output the content for this page. |
---|
1317 | * |
---|
1318 | * @return false|string The resulting page's hook_suffix, or false if the user does not have the capability required. |
---|
1319 | */ |
---|
1320 | function add_posts_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) { |
---|
1321 | return add_submenu_page( 'edit.php', $page_title, $menu_title, $capability, $menu_slug, $function ); |
---|
1322 | } |
---|
1323 | |
---|
1324 | /** |
---|
1325 | * Add sub menu page to the media main menu. |
---|
1326 | * |
---|
1327 | * This function takes a capability which will be used to determine whether |
---|
1328 | * or not a page is included in the menu. |
---|
1329 | * |
---|
1330 | * The function which is hooked in to handle the output of the page must check |
---|
1331 | * that the user has the required capability as well. |
---|
1332 | * |
---|
1333 | * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected |
---|
1334 | * @param string $menu_title The text to be used for the menu |
---|
1335 | * @param string $capability The capability required for this menu to be displayed to the user. |
---|
1336 | * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu) |
---|
1337 | * @param callback $function The function to be called to output the content for this page. |
---|
1338 | * |
---|
1339 | * @return false|string The resulting page's hook_suffix, or false if the user does not have the capability required. |
---|
1340 | */ |
---|
1341 | function add_media_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) { |
---|
1342 | return add_submenu_page( 'upload.php', $page_title, $menu_title, $capability, $menu_slug, $function ); |
---|
1343 | } |
---|
1344 | |
---|
1345 | /** |
---|
1346 | * Add sub menu page to the links main menu. |
---|
1347 | * |
---|
1348 | * This function takes a capability which will be used to determine whether |
---|
1349 | * or not a page is included in the menu. |
---|
1350 | * |
---|
1351 | * The function which is hooked in to handle the output of the page must check |
---|
1352 | * that the user has the required capability as well. |
---|
1353 | * |
---|
1354 | * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected |
---|
1355 | * @param string $menu_title The text to be used for the menu |
---|
1356 | * @param string $capability The capability required for this menu to be displayed to the user. |
---|
1357 | * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu) |
---|
1358 | * @param callback $function The function to be called to output the content for this page. |
---|
1359 | * |
---|
1360 | * @return false|string The resulting page's hook_suffix, or false if the user does not have the capability required. |
---|
1361 | */ |
---|
1362 | function add_links_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) { |
---|
1363 | return add_submenu_page( 'link-manager.php', $page_title, $menu_title, $capability, $menu_slug, $function ); |
---|
1364 | } |
---|
1365 | |
---|
1366 | /** |
---|
1367 | * Add sub menu page to the pages main menu. |
---|
1368 | * |
---|
1369 | * This function takes a capability which will be used to determine whether |
---|
1370 | * or not a page is included in the menu. |
---|
1371 | * |
---|
1372 | * The function which is hooked in to handle the output of the page must check |
---|
1373 | * that the user has the required capability as well. |
---|
1374 | * |
---|
1375 | * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected |
---|
1376 | * @param string $menu_title The text to be used for the menu |
---|
1377 | * @param string $capability The capability required for this menu to be displayed to the user. |
---|
1378 | * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu) |
---|
1379 | * @param callback $function The function to be called to output the content for this page. |
---|
1380 | * |
---|
1381 | * @return false|string The resulting page's hook_suffix, or false if the user does not have the capability required. |
---|
1382 | */ |
---|
1383 | function add_pages_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) { |
---|
1384 | return add_submenu_page( 'edit.php?post_type=page', $page_title, $menu_title, $capability, $menu_slug, $function ); |
---|
1385 | } |
---|
1386 | |
---|
1387 | /** |
---|
1388 | * Add sub menu page to the comments main menu. |
---|
1389 | * |
---|
1390 | * This function takes a capability which will be used to determine whether |
---|
1391 | * or not a page is included in the menu. |
---|
1392 | * |
---|
1393 | * The function which is hooked in to handle the output of the page must check |
---|
1394 | * that the user has the required capability as well. |
---|
1395 | * |
---|
1396 | * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected |
---|
1397 | * @param string $menu_title The text to be used for the menu |
---|
1398 | * @param string $capability The capability required for this menu to be displayed to the user. |
---|
1399 | * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu) |
---|
1400 | * @param callback $function The function to be called to output the content for this page. |
---|
1401 | * |
---|
1402 | * @return false|string The resulting page's hook_suffix, or false if the user does not have the capability required. |
---|
1403 | */ |
---|
1404 | function add_comments_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) { |
---|
1405 | return add_submenu_page( 'edit-comments.php', $page_title, $menu_title, $capability, $menu_slug, $function ); |
---|
1406 | } |
---|
1407 | |
---|
1408 | /** |
---|
1409 | * Remove a top level admin menu |
---|
1410 | * |
---|
1411 | * @since 3.1.0 |
---|
1412 | * |
---|
1413 | * @param string $menu_slug The slug of the menu |
---|
1414 | * @return array|bool The removed menu on success, False if not found |
---|
1415 | */ |
---|
1416 | function remove_menu_page( $menu_slug ) { |
---|
1417 | global $menu; |
---|
1418 | |
---|
1419 | foreach ( $menu as $i => $item ) { |
---|
1420 | if ( $menu_slug == $item[2] ) { |
---|
1421 | unset( $menu[$i] ); |
---|
1422 | return $item; |
---|
1423 | } |
---|
1424 | } |
---|
1425 | |
---|
1426 | return false; |
---|
1427 | } |
---|
1428 | |
---|
1429 | /** |
---|
1430 | * Remove an admin submenu |
---|
1431 | * |
---|
1432 | * @since 3.1.0 |
---|
1433 | * |
---|
1434 | * @param string $menu_slug The slug for the parent menu |
---|
1435 | * @param string $submenu_slug The slug of the submenu |
---|
1436 | * @return array|bool The removed submenu on success, False if not found |
---|
1437 | */ |
---|
1438 | function remove_submenu_page( $menu_slug, $submenu_slug ) { |
---|
1439 | global $submenu; |
---|
1440 | |
---|
1441 | if ( !isset( $submenu[$menu_slug] ) ) |
---|
1442 | return false; |
---|
1443 | |
---|
1444 | foreach ( $submenu[$menu_slug] as $i => $item ) { |
---|
1445 | if ( $submenu_slug == $item[2] ) { |
---|
1446 | unset( $submenu[$menu_slug][$i] ); |
---|
1447 | return $item; |
---|
1448 | } |
---|
1449 | } |
---|
1450 | |
---|
1451 | return false; |
---|
1452 | } |
---|
1453 | |
---|
1454 | /** |
---|
1455 | * Get the url to access a particular menu page based on the slug it was registered with. |
---|
1456 | * |
---|
1457 | * If the slug hasn't been registered properly no url will be returned |
---|
1458 | * |
---|
1459 | * @since 3.0.0 |
---|
1460 | * |
---|
1461 | * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu) |
---|
1462 | * @param bool $echo Whether or not to echo the url - default is true |
---|
1463 | * @return string the url |
---|
1464 | */ |
---|
1465 | function menu_page_url($menu_slug, $echo = true) { |
---|
1466 | global $_parent_pages; |
---|
1467 | |
---|
1468 | if ( isset( $_parent_pages[$menu_slug] ) ) { |
---|
1469 | $parent_slug = $_parent_pages[$menu_slug]; |
---|
1470 | if ( $parent_slug && ! isset( $_parent_pages[$parent_slug] ) ) { |
---|
1471 | $url = admin_url( add_query_arg( 'page', $menu_slug, $parent_slug ) ); |
---|
1472 | } else { |
---|
1473 | $url = admin_url( 'admin.php?page=' . $menu_slug ); |
---|
1474 | } |
---|
1475 | } else { |
---|
1476 | $url = ''; |
---|
1477 | } |
---|
1478 | |
---|
1479 | $url = esc_url($url); |
---|
1480 | |
---|
1481 | if ( $echo ) |
---|
1482 | echo $url; |
---|
1483 | |
---|
1484 | return $url; |
---|
1485 | } |
---|
1486 | |
---|
1487 | // |
---|
1488 | // Pluggable Menu Support -- Private |
---|
1489 | // |
---|
1490 | |
---|
1491 | function get_admin_page_parent( $parent = '' ) { |
---|
1492 | global $parent_file; |
---|
1493 | global $menu; |
---|
1494 | global $submenu; |
---|
1495 | global $pagenow; |
---|
1496 | global $typenow; |
---|
1497 | global $plugin_page; |
---|
1498 | global $_wp_real_parent_file; |
---|
1499 | global $_wp_menu_nopriv; |
---|
1500 | global $_wp_submenu_nopriv; |
---|
1501 | |
---|
1502 | if ( !empty ( $parent ) && 'admin.php' != $parent ) { |
---|
1503 | if ( isset( $_wp_real_parent_file[$parent] ) ) |
---|
1504 | $parent = $_wp_real_parent_file[$parent]; |
---|
1505 | return $parent; |
---|
1506 | } |
---|
1507 | |
---|
1508 | if ( $pagenow == 'admin.php' && isset( $plugin_page ) ) { |
---|
1509 | foreach ( (array)$menu as $parent_menu ) { |
---|
1510 | if ( $parent_menu[2] == $plugin_page ) { |
---|
1511 | $parent_file = $plugin_page; |
---|
1512 | if ( isset( $_wp_real_parent_file[$parent_file] ) ) |
---|
1513 | $parent_file = $_wp_real_parent_file[$parent_file]; |
---|
1514 | return $parent_file; |
---|
1515 | } |
---|
1516 | } |
---|
1517 | if ( isset( $_wp_menu_nopriv[$plugin_page] ) ) { |
---|
1518 | $parent_file = $plugin_page; |
---|
1519 | if ( isset( $_wp_real_parent_file[$parent_file] ) ) |
---|
1520 | $parent_file = $_wp_real_parent_file[$parent_file]; |
---|
1521 | return $parent_file; |
---|
1522 | } |
---|
1523 | } |
---|
1524 | |
---|
1525 | if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[$pagenow][$plugin_page] ) ) { |
---|
1526 | $parent_file = $pagenow; |
---|
1527 | if ( isset( $_wp_real_parent_file[$parent_file] ) ) |
---|
1528 | $parent_file = $_wp_real_parent_file[$parent_file]; |
---|
1529 | return $parent_file; |
---|
1530 | } |
---|
1531 | |
---|
1532 | foreach (array_keys( (array)$submenu ) as $parent) { |
---|
1533 | foreach ( $submenu[$parent] as $submenu_array ) { |
---|
1534 | if ( isset( $_wp_real_parent_file[$parent] ) ) |
---|
1535 | $parent = $_wp_real_parent_file[$parent]; |
---|
1536 | if ( !empty($typenow) && ($submenu_array[2] == "$pagenow?post_type=$typenow") ) { |
---|
1537 | $parent_file = $parent; |
---|
1538 | return $parent; |
---|
1539 | } elseif ( $submenu_array[2] == $pagenow && empty($typenow) && ( empty($parent_file) || false === strpos($parent_file, '?') ) ) { |
---|
1540 | $parent_file = $parent; |
---|
1541 | return $parent; |
---|
1542 | } elseif ( isset( $plugin_page ) && ($plugin_page == $submenu_array[2] ) ) { |
---|
1543 | $parent_file = $parent; |
---|
1544 | return $parent; |
---|
1545 | } |
---|
1546 | } |
---|
1547 | } |
---|
1548 | |
---|
1549 | if ( empty($parent_file) ) |
---|
1550 | $parent_file = ''; |
---|
1551 | return ''; |
---|
1552 | } |
---|
1553 | |
---|
1554 | function get_admin_page_title() { |
---|
1555 | global $title; |
---|
1556 | global $menu; |
---|
1557 | global $submenu; |
---|
1558 | global $pagenow; |
---|
1559 | global $plugin_page; |
---|
1560 | global $typenow; |
---|
1561 | |
---|
1562 | if ( ! empty ( $title ) ) |
---|
1563 | return $title; |
---|
1564 | |
---|
1565 | $hook = get_plugin_page_hook( $plugin_page, $pagenow ); |
---|
1566 | |
---|
1567 | $parent = $parent1 = get_admin_page_parent(); |
---|
1568 | |
---|
1569 | if ( empty ( $parent) ) { |
---|
1570 | foreach ( (array)$menu as $menu_array ) { |
---|
1571 | if ( isset( $menu_array[3] ) ) { |
---|
1572 | if ( $menu_array[2] == $pagenow ) { |
---|
1573 | $title = $menu_array[3]; |
---|
1574 | return $menu_array[3]; |
---|
1575 | } elseif ( isset( $plugin_page ) && ($plugin_page == $menu_array[2] ) && ($hook == $menu_array[3] ) ) { |
---|
1576 | $title = $menu_array[3]; |
---|
1577 | return $menu_array[3]; |
---|
1578 | } |
---|
1579 | } else { |
---|
1580 | $title = $menu_array[0]; |
---|
1581 | return $title; |
---|
1582 | } |
---|
1583 | } |
---|
1584 | } else { |
---|
1585 | foreach ( array_keys( $submenu ) as $parent ) { |
---|
1586 | foreach ( $submenu[$parent] as $submenu_array ) { |
---|
1587 | if ( isset( $plugin_page ) && |
---|
1588 | ( $plugin_page == $submenu_array[2] ) && |
---|
1589 | ( |
---|
1590 | ( $parent == $pagenow ) || |
---|
1591 | ( $parent == $plugin_page ) || |
---|
1592 | ( $plugin_page == $hook ) || |
---|
1593 | ( $pagenow == 'admin.php' && $parent1 != $submenu_array[2] ) || |
---|
1594 | ( !empty($typenow) && $parent == $pagenow . '?post_type=' . $typenow) |
---|
1595 | ) |
---|
1596 | ) { |
---|
1597 | $title = $submenu_array[3]; |
---|
1598 | return $submenu_array[3]; |
---|
1599 | } |
---|
1600 | |
---|
1601 | if ( $submenu_array[2] != $pagenow || isset( $_GET['page'] ) ) // not the current page |
---|
1602 | continue; |
---|
1603 | |
---|
1604 | if ( isset( $submenu_array[3] ) ) { |
---|
1605 | $title = $submenu_array[3]; |
---|
1606 | return $submenu_array[3]; |
---|
1607 | } else { |
---|
1608 | $title = $submenu_array[0]; |
---|
1609 | return $title; |
---|
1610 | } |
---|
1611 | } |
---|
1612 | } |
---|
1613 | if ( empty ( $title ) ) { |
---|
1614 | foreach ( $menu as $menu_array ) { |
---|
1615 | if ( isset( $plugin_page ) && |
---|
1616 | ( $plugin_page == $menu_array[2] ) && |
---|
1617 | ( $pagenow == 'admin.php' ) && |
---|
1618 | ( $parent1 == $menu_array[2] ) ) |
---|
1619 | { |
---|
1620 | $title = $menu_array[3]; |
---|
1621 | return $menu_array[3]; |
---|
1622 | } |
---|
1623 | } |
---|
1624 | } |
---|
1625 | } |
---|
1626 | |
---|
1627 | return $title; |
---|
1628 | } |
---|
1629 | |
---|
1630 | function get_plugin_page_hook( $plugin_page, $parent_page ) { |
---|
1631 | $hook = get_plugin_page_hookname( $plugin_page, $parent_page ); |
---|
1632 | if ( has_action($hook) ) |
---|
1633 | return $hook; |
---|
1634 | else |
---|
1635 | return null; |
---|
1636 | } |
---|
1637 | |
---|
1638 | function get_plugin_page_hookname( $plugin_page, $parent_page ) { |
---|
1639 | global $admin_page_hooks; |
---|
1640 | |
---|
1641 | $parent = get_admin_page_parent( $parent_page ); |
---|
1642 | |
---|
1643 | $page_type = 'admin'; |
---|
1644 | if ( empty ( $parent_page ) || 'admin.php' == $parent_page || isset( $admin_page_hooks[$plugin_page] ) ) { |
---|
1645 | if ( isset( $admin_page_hooks[$plugin_page] ) ) { |
---|
1646 | $page_type = 'toplevel'; |
---|
1647 | } elseif ( isset( $admin_page_hooks[$parent] )) { |
---|
1648 | $page_type = $admin_page_hooks[$parent]; |
---|
1649 | } |
---|
1650 | } elseif ( isset( $admin_page_hooks[$parent] ) ) { |
---|
1651 | $page_type = $admin_page_hooks[$parent]; |
---|
1652 | } |
---|
1653 | |
---|
1654 | $plugin_name = preg_replace( '!\.php!', '', $plugin_page ); |
---|
1655 | |
---|
1656 | return $page_type . '_page_' . $plugin_name; |
---|
1657 | } |
---|
1658 | |
---|
1659 | function user_can_access_admin_page() { |
---|
1660 | global $pagenow; |
---|
1661 | global $menu; |
---|
1662 | global $submenu; |
---|
1663 | global $_wp_menu_nopriv; |
---|
1664 | global $_wp_submenu_nopriv; |
---|
1665 | global $plugin_page; |
---|
1666 | global $_registered_pages; |
---|
1667 | |
---|
1668 | $parent = get_admin_page_parent(); |
---|
1669 | |
---|
1670 | if ( !isset( $plugin_page ) && isset( $_wp_submenu_nopriv[$parent][$pagenow] ) ) |
---|
1671 | return false; |
---|
1672 | |
---|
1673 | if ( isset( $plugin_page ) ) { |
---|
1674 | if ( isset( $_wp_submenu_nopriv[$parent][$plugin_page] ) ) |
---|
1675 | return false; |
---|
1676 | |
---|
1677 | $hookname = get_plugin_page_hookname($plugin_page, $parent); |
---|
1678 | |
---|
1679 | if ( !isset($_registered_pages[$hookname]) ) |
---|
1680 | return false; |
---|
1681 | } |
---|
1682 | |
---|
1683 | if ( empty( $parent) ) { |
---|
1684 | if ( isset( $_wp_menu_nopriv[$pagenow] ) ) |
---|
1685 | return false; |
---|
1686 | if ( isset( $_wp_submenu_nopriv[$pagenow][$pagenow] ) ) |
---|
1687 | return false; |
---|
1688 | if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[$pagenow][$plugin_page] ) ) |
---|
1689 | return false; |
---|
1690 | if ( isset( $plugin_page ) && isset( $_wp_menu_nopriv[$plugin_page] ) ) |
---|
1691 | return false; |
---|
1692 | foreach (array_keys( $_wp_submenu_nopriv ) as $key ) { |
---|
1693 | if ( isset( $_wp_submenu_nopriv[$key][$pagenow] ) ) |
---|
1694 | return false; |
---|
1695 | if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[$key][$plugin_page] ) ) |
---|
1696 | return false; |
---|
1697 | } |
---|
1698 | return true; |
---|
1699 | } |
---|
1700 | |
---|
1701 | if ( isset( $plugin_page ) && ( $plugin_page == $parent ) && isset( $_wp_menu_nopriv[$plugin_page] ) ) |
---|
1702 | return false; |
---|
1703 | |
---|
1704 | if ( isset( $submenu[$parent] ) ) { |
---|
1705 | foreach ( $submenu[$parent] as $submenu_array ) { |
---|
1706 | if ( isset( $plugin_page ) && ( $submenu_array[2] == $plugin_page ) ) { |
---|
1707 | if ( current_user_can( $submenu_array[1] )) |
---|
1708 | return true; |
---|
1709 | else |
---|
1710 | return false; |
---|
1711 | } elseif ( $submenu_array[2] == $pagenow ) { |
---|
1712 | if ( current_user_can( $submenu_array[1] )) |
---|
1713 | return true; |
---|
1714 | else |
---|
1715 | return false; |
---|
1716 | } |
---|
1717 | } |
---|
1718 | } |
---|
1719 | |
---|
1720 | foreach ( $menu as $menu_array ) { |
---|
1721 | if ( $menu_array[2] == $parent) { |
---|
1722 | if ( current_user_can( $menu_array[1] )) |
---|
1723 | return true; |
---|
1724 | else |
---|
1725 | return false; |
---|
1726 | } |
---|
1727 | } |
---|
1728 | |
---|
1729 | return true; |
---|
1730 | } |
---|
1731 | |
---|
1732 | /* Whitelist functions */ |
---|
1733 | |
---|
1734 | /** |
---|
1735 | * Register a setting and its sanitization callback |
---|
1736 | * |
---|
1737 | * @since 2.7.0 |
---|
1738 | * |
---|
1739 | * @param string $option_group A settings group name. Should correspond to a whitelisted option key name. |
---|
1740 | * Default whitelisted option key names include "general," "discussion," and "reading," among others. |
---|
1741 | * @param string $option_name The name of an option to sanitize and save. |
---|
1742 | * @param callable $sanitize_callback A callback function that sanitizes the option's value. |
---|
1743 | */ |
---|
1744 | function register_setting( $option_group, $option_name, $sanitize_callback = '' ) { |
---|
1745 | global $new_whitelist_options; |
---|
1746 | |
---|
1747 | if ( 'misc' == $option_group ) { |
---|
1748 | _deprecated_argument( __FUNCTION__, '3.0', sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ), 'misc' ) ); |
---|
1749 | $option_group = 'general'; |
---|
1750 | } |
---|
1751 | |
---|
1752 | if ( 'privacy' == $option_group ) { |
---|
1753 | _deprecated_argument( __FUNCTION__, '3.5', sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ), 'privacy' ) ); |
---|
1754 | $option_group = 'reading'; |
---|
1755 | } |
---|
1756 | |
---|
1757 | $new_whitelist_options[ $option_group ][] = $option_name; |
---|
1758 | if ( $sanitize_callback != '' ) |
---|
1759 | add_filter( "sanitize_option_{$option_name}", $sanitize_callback ); |
---|
1760 | } |
---|
1761 | |
---|
1762 | /** |
---|
1763 | * Unregister a setting |
---|
1764 | * |
---|
1765 | * @since 2.7.0 |
---|
1766 | * |
---|
1767 | * @param string $option_group |
---|
1768 | * @param string $option_name |
---|
1769 | * @param callable $sanitize_callback |
---|
1770 | */ |
---|
1771 | function unregister_setting( $option_group, $option_name, $sanitize_callback = '' ) { |
---|
1772 | global $new_whitelist_options; |
---|
1773 | |
---|
1774 | if ( 'misc' == $option_group ) { |
---|
1775 | _deprecated_argument( __FUNCTION__, '3.0', sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ), 'misc' ) ); |
---|
1776 | $option_group = 'general'; |
---|
1777 | } |
---|
1778 | |
---|
1779 | if ( 'privacy' == $option_group ) { |
---|
1780 | _deprecated_argument( __FUNCTION__, '3.5', sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ), 'privacy' ) ); |
---|
1781 | $option_group = 'reading'; |
---|
1782 | } |
---|
1783 | |
---|
1784 | $pos = array_search( $option_name, (array) $new_whitelist_options ); |
---|
1785 | if ( $pos !== false ) |
---|
1786 | unset( $new_whitelist_options[ $option_group ][ $pos ] ); |
---|
1787 | if ( $sanitize_callback != '' ) |
---|
1788 | remove_filter( "sanitize_option_{$option_name}", $sanitize_callback ); |
---|
1789 | } |
---|
1790 | |
---|
1791 | /** |
---|
1792 | * {@internal Missing Short Description}} |
---|
1793 | * |
---|
1794 | * @since 2.7.0 |
---|
1795 | * |
---|
1796 | * @param array $options |
---|
1797 | * @return array |
---|
1798 | */ |
---|
1799 | function option_update_filter( $options ) { |
---|
1800 | global $new_whitelist_options; |
---|
1801 | |
---|
1802 | if ( is_array( $new_whitelist_options ) ) |
---|
1803 | $options = add_option_whitelist( $new_whitelist_options, $options ); |
---|
1804 | |
---|
1805 | return $options; |
---|
1806 | } |
---|
1807 | add_filter( 'whitelist_options', 'option_update_filter' ); |
---|
1808 | |
---|
1809 | /** |
---|
1810 | * {@internal Missing Short Description}} |
---|
1811 | * |
---|
1812 | * @since 2.7.0 |
---|
1813 | * |
---|
1814 | * @param array $new_options |
---|
1815 | * @param string|array $options |
---|
1816 | * @return array |
---|
1817 | */ |
---|
1818 | function add_option_whitelist( $new_options, $options = '' ) { |
---|
1819 | if ( $options == '' ) |
---|
1820 | global $whitelist_options; |
---|
1821 | else |
---|
1822 | $whitelist_options = $options; |
---|
1823 | |
---|
1824 | foreach ( $new_options as $page => $keys ) { |
---|
1825 | foreach ( $keys as $key ) { |
---|
1826 | if ( !isset($whitelist_options[ $page ]) || !is_array($whitelist_options[ $page ]) ) { |
---|
1827 | $whitelist_options[ $page ] = array(); |
---|
1828 | $whitelist_options[ $page ][] = $key; |
---|
1829 | } else { |
---|
1830 | $pos = array_search( $key, $whitelist_options[ $page ] ); |
---|
1831 | if ( $pos === false ) |
---|
1832 | $whitelist_options[ $page ][] = $key; |
---|
1833 | } |
---|
1834 | } |
---|
1835 | } |
---|
1836 | |
---|
1837 | return $whitelist_options; |
---|
1838 | } |
---|
1839 | |
---|
1840 | /** |
---|
1841 | * {@internal Missing Short Description}} |
---|
1842 | * |
---|
1843 | * @since 2.7.0 |
---|
1844 | * |
---|
1845 | * @param array $del_options |
---|
1846 | * @param string|array $options |
---|
1847 | * @return array |
---|
1848 | */ |
---|
1849 | function remove_option_whitelist( $del_options, $options = '' ) { |
---|
1850 | if ( $options == '' ) |
---|
1851 | global $whitelist_options; |
---|
1852 | else |
---|
1853 | $whitelist_options = $options; |
---|
1854 | |
---|
1855 | foreach ( $del_options as $page => $keys ) { |
---|
1856 | foreach ( $keys as $key ) { |
---|
1857 | if ( isset($whitelist_options[ $page ]) && is_array($whitelist_options[ $page ]) ) { |
---|
1858 | $pos = array_search( $key, $whitelist_options[ $page ] ); |
---|
1859 | if ( $pos !== false ) |
---|
1860 | unset( $whitelist_options[ $page ][ $pos ] ); |
---|
1861 | } |
---|
1862 | } |
---|
1863 | } |
---|
1864 | |
---|
1865 | return $whitelist_options; |
---|
1866 | } |
---|
1867 | |
---|
1868 | /** |
---|
1869 | * Output nonce, action, and option_page fields for a settings page. |
---|
1870 | * |
---|
1871 | * @since 2.7.0 |
---|
1872 | * |
---|
1873 | * @param string $option_group A settings group name. This should match the group name used in register_setting(). |
---|
1874 | */ |
---|
1875 | function settings_fields($option_group) { |
---|
1876 | echo "<input type='hidden' name='option_page' value='" . esc_attr($option_group) . "' />"; |
---|
1877 | echo '<input type="hidden" name="action" value="update" />'; |
---|
1878 | wp_nonce_field("$option_group-options"); |
---|
1879 | } |
---|
1880 | |
---|
1881 | /** |
---|
1882 | * Clears the Plugins cache used by get_plugins() and by default, the Plugin Update cache. |
---|
1883 | * |
---|
1884 | * @since 3.7.0 |
---|
1885 | * |
---|
1886 | * @param bool $clear_update_cache Whether to clear the Plugin updates cache |
---|
1887 | */ |
---|
1888 | function wp_clean_plugins_cache( $clear_update_cache = true ) { |
---|
1889 | if ( $clear_update_cache ) |
---|
1890 | delete_site_transient( 'update_plugins' ); |
---|
1891 | wp_cache_delete( 'plugins', 'plugins' ); |
---|
1892 | } |
---|