Projects : mp-wp : mp-wp_svg-screenshots-and-errorreporting-r2
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 | * <code> |
18 | * /* |
19 | * Plugin Name: Name of Plugin |
20 | * Plugin URI: Link to plugin information |
21 | * Description: Plugin Description |
22 | * Author: Plugin author's name |
23 | * Author URI: Link to the author's web site |
24 | * Version: Must be set in the plugin for WordPress 2.3+ |
25 | * Text Domain: Optional. Unique identifier, should be same as the one used in |
26 | * plugin_text_domain() |
27 | * Domain Path: Optional. Only useful if the translations are located in a |
28 | * folder above the plugin's base path. For example, if .mo files are |
29 | * located in the locale folder then Domain Path will be "/locale/" and |
30 | * must have the first slash. Defaults to the base folder the plugin is |
31 | * located in. |
32 | * * / # Remove the space to close comment |
33 | * </code> |
34 | * |
35 | * Plugin data returned array contains the following: |
36 | * 'Name' - Name of the plugin, must be unique. |
37 | * 'Title' - Title of the plugin and the link to the plugin's web site. |
38 | * 'Description' - Description of what the plugin does and/or notes |
39 | * from the author. |
40 | * 'Author' - The author's name |
41 | * 'AuthorURI' - The authors web site address. |
42 | * 'Version' - The plugin version number. |
43 | * 'PluginURI' - Plugin web site address. |
44 | * 'TextDomain' - Plugin's text domain for localization. |
45 | * 'DomainPath' - Plugin's relative directory path to .mo files. |
46 | * |
47 | * Some users have issues with opening large files and manipulating the contents |
48 | * for want is usually the first 1kiB or 2kiB. This function stops pulling in |
49 | * the plugin contents when it has all of the required plugin data. |
50 | * |
51 | * The first 8kiB of the file will be pulled in and if the plugin data is not |
52 | * within that first 8kiB, then the plugin author should correct their plugin |
53 | * and move the plugin data headers to the top. |
54 | * |
55 | * The plugin file is assumed to have permissions to allow for scripts to read |
56 | * the file. This is not checked however and the file is only opened for |
57 | * reading. |
58 | * |
59 | * @link http://trac.wordpress.org/ticket/5651 Previous Optimizations. |
60 | * @link http://trac.wordpress.org/ticket/7372 Further and better Optimizations. |
61 | * @since 1.5.0 |
62 | * |
63 | * @param string $plugin_file Path to the plugin file |
64 | * @param bool $markup If the returned data should have HTML markup applied |
65 | * @param bool $translate If the returned data should be translated |
66 | * @return array See above for description. |
67 | */ |
68 | function get_plugin_data( $plugin_file, $markup = true, $translate = true ) { |
69 | // We don't need to write to the file, so just open for reading. |
70 | $fp = fopen($plugin_file, 'r'); |
71 | |
72 | // Pull only the first 8kiB of the file in. |
73 | $plugin_data = fread( $fp, 8192 ); |
74 | |
75 | // PHP will close file handle, but we are good citizens. |
76 | fclose($fp); |
77 | |
78 | preg_match( '|Plugin Name:(.*)$|mi', $plugin_data, $name ); |
79 | preg_match( '|Plugin URI:(.*)$|mi', $plugin_data, $uri ); |
80 | preg_match( '|Version:(.*)|i', $plugin_data, $version ); |
81 | preg_match( '|Description:(.*)$|mi', $plugin_data, $description ); |
82 | preg_match( '|Author:(.*)$|mi', $plugin_data, $author_name ); |
83 | preg_match( '|Author URI:(.*)$|mi', $plugin_data, $author_uri ); |
84 | preg_match( '|Text Domain:(.*)$|mi', $plugin_data, $text_domain ); |
85 | preg_match( '|Domain Path:(.*)$|mi', $plugin_data, $domain_path ); |
86 | |
87 | foreach ( array( 'name', 'uri', 'version', 'description', 'author_name', 'author_uri', 'text_domain', 'domain_path' ) as $field ) { |
88 | if ( !empty( ${$field} ) ) |
89 | ${$field} = trim(${$field}[1]); |
90 | else |
91 | ${$field} = ''; |
92 | } |
93 | |
94 | $plugin_data = array( |
95 | 'Name' => $name, 'Title' => $name, 'PluginURI' => $uri, 'Description' => $description, |
96 | 'Author' => $author_name, 'AuthorURI' => $author_uri, 'Version' => $version, |
97 | 'TextDomain' => $text_domain, 'DomainPath' => $domain_path |
98 | ); |
99 | if ( $markup || $translate ) |
100 | $plugin_data = _get_plugin_data_markup_translate($plugin_data, $markup, $translate); |
101 | return $plugin_data; |
102 | } |
103 | |
104 | function _get_plugin_data_markup_translate($plugin_data, $markup = true, $translate = true) { |
105 | |
106 | //Translate fields |
107 | if( $translate && ! empty($plugin_data['TextDomain']) ) { |
108 | if( ! empty( $plugin_data['DomainPath'] ) ) |
109 | load_plugin_textdomain($plugin_data['TextDomain'], dirname($plugin_file). $plugin_data['DomainPath']); |
110 | else |
111 | load_plugin_textdomain($plugin_data['TextDomain'], dirname($plugin_file)); |
112 | |
113 | foreach ( array('Name', 'PluginURI', 'Description', 'Author', 'AuthorURI', 'Version') as $field ) |
114 | $plugin_data[ $field ] = translate($plugin_data[ $field ], $plugin_data['TextDomain']); |
115 | } |
116 | |
117 | //Apply Markup |
118 | if ( $markup ) { |
119 | if ( ! empty($plugin_data['PluginURI']) && ! empty($plugin_data['Name']) ) |
120 | $plugin_data['Title'] = '<a href="' . $plugin_data['PluginURI'] . '" title="' . __( 'Visit plugin homepage' ) . '">' . $plugin_data['Name'] . '</a>'; |
121 | else |
122 | $plugin_data['Title'] = $plugin_data['Name']; |
123 | |
124 | if ( ! empty($plugin_data['AuthorURI']) ) |
125 | $plugin_data['Author'] = '<a href="' . $plugin_data['AuthorURI'] . '" title="' . __( 'Visit author homepage' ) . '">' . $plugin_data['Author'] . '</a>'; |
126 | |
127 | $plugin_data['Description'] = wptexturize( $plugin_data['Description'] ); |
128 | if( ! empty($plugin_data['Author']) ) |
129 | $plugin_data['Description'] .= ' <cite>' . sprintf( __('By %s'), $plugin_data['Author'] ) . '.</cite>'; |
130 | } |
131 | |
132 | $plugins_allowedtags = array('a' => array('href' => array(),'title' => array()),'abbr' => array('title' => array()),'acronym' => array('title' => array()),'code' => array(),'em' => array(),'strong' => array()); |
133 | |
134 | // Sanitize all displayed data |
135 | $plugin_data['Title'] = wp_kses($plugin_data['Title'], $plugins_allowedtags); |
136 | $plugin_data['Version'] = wp_kses($plugin_data['Version'], $plugins_allowedtags); |
137 | $plugin_data['Description'] = wp_kses($plugin_data['Description'], $plugins_allowedtags); |
138 | $plugin_data['Author'] = wp_kses($plugin_data['Author'], $plugins_allowedtags); |
139 | |
140 | return $plugin_data; |
141 | } |
142 | |
143 | /** |
144 | * Check the plugins directory and retrieve all plugin files with plugin data. |
145 | * |
146 | * WordPress only supports plugin files in the base plugins directory |
147 | * (wp-content/plugins) and in one directory above the plugins directory |
148 | * (wp-content/plugins/my-plugin). The file it looks for has the plugin data and |
149 | * must be found in those two locations. It is recommended that do keep your |
150 | * plugin files in directories. |
151 | * |
152 | * The file with the plugin data is the file that will be included and therefore |
153 | * needs to have the main execution for the plugin. This does not mean |
154 | * everything must be contained in the file and it is recommended that the file |
155 | * be split for maintainability. Keep everything in one file for extreme |
156 | * optimization purposes. |
157 | * |
158 | * @since unknown |
159 | * |
160 | * @param string $plugin_folder Optional. Relative path to single plugin folder. |
161 | * @return array Key is the plugin file path and the value is an array of the plugin data. |
162 | */ |
163 | function get_plugins($plugin_folder = '') { |
164 | |
165 | if ( ! $cache_plugins = wp_cache_get('plugins', 'plugins') ) |
166 | $cache_plugins = array(); |
167 | |
168 | if ( isset($cache_plugins[ $plugin_folder ]) ) |
169 | return $cache_plugins[ $plugin_folder ]; |
170 | |
171 | $wp_plugins = array (); |
172 | $plugin_root = WP_PLUGIN_DIR; |
173 | if( !empty($plugin_folder) ) |
174 | $plugin_root .= $plugin_folder; |
175 | |
176 | // Files in wp-content/plugins directory |
177 | $plugins_dir = @ opendir( $plugin_root); |
178 | if ( $plugins_dir ) { |
179 | while (($file = readdir( $plugins_dir ) ) !== false ) { |
180 | if ( substr($file, 0, 1) == '.' ) |
181 | continue; |
182 | if ( is_dir( $plugin_root.'/'.$file ) ) { |
183 | $plugins_subdir = @ opendir( $plugin_root.'/'.$file ); |
184 | if ( $plugins_subdir ) { |
185 | while (($subfile = readdir( $plugins_subdir ) ) !== false ) { |
186 | if ( substr($subfile, 0, 1) == '.' ) |
187 | continue; |
188 | if ( substr($subfile, -4) == '.php' ) |
189 | $plugin_files[] = "$file/$subfile"; |
190 | } |
191 | } |
192 | } else { |
193 | if ( substr($file, -4) == '.php' ) |
194 | $plugin_files[] = $file; |
195 | } |
196 | } |
197 | } |
198 | @closedir( $plugins_dir ); |
199 | @closedir( $plugins_subdir ); |
200 | |
201 | if ( !$plugins_dir || !$plugin_files ) |
202 | return $wp_plugins; |
203 | |
204 | foreach ( $plugin_files as $plugin_file ) { |
205 | if ( !is_readable( "$plugin_root/$plugin_file" ) ) |
206 | continue; |
207 | |
208 | $plugin_data = get_plugin_data( "$plugin_root/$plugin_file", false, false ); //Do not apply markup/translate as it'll be cached. |
209 | |
210 | if ( empty ( $plugin_data['Name'] ) ) |
211 | continue; |
212 | |
213 | $wp_plugins[plugin_basename( $plugin_file )] = $plugin_data; |
214 | } |
215 | |
216 | uasort( $wp_plugins, create_function( '$a, $b', 'return strnatcasecmp( $a["Name"], $b["Name"] );' )); |
217 | |
218 | $cache_plugins[ $plugin_folder ] = $wp_plugins; |
219 | wp_cache_set('plugins', $cache_plugins, 'plugins'); |
220 | |
221 | return $wp_plugins; |
222 | } |
223 | |
224 | /** |
225 | * Check whether the plugin is active by checking the active_plugins list. |
226 | * |
227 | * @since 2.5.0 |
228 | * |
229 | * @param string $plugin Base plugin path from plugins directory. |
230 | * @return bool True, if in the active plugins list. False, not in the list. |
231 | */ |
232 | function is_plugin_active($plugin) { |
233 | return in_array($plugin, get_option('active_plugins')); |
234 | } |
235 | |
236 | /** |
237 | * Attempts activation of plugin in a "sandbox" and redirects on success. |
238 | * |
239 | * A plugin that is already activated will not attempt to be activated again. |
240 | * |
241 | * The way it works is by setting the redirection to the error before trying to |
242 | * include the plugin file. If the plugin fails, then the redirection will not |
243 | * be overwritten with the success message. Also, the options will not be |
244 | * updated and the activation hook will not be called on plugin error. |
245 | * |
246 | * It should be noted that in no way the below code will actually prevent errors |
247 | * within the file. The code should not be used elsewhere to replicate the |
248 | * "sandbox", which uses redirection to work. |
249 | * {@source 13 1} |
250 | * |
251 | * If any errors are found or text is outputted, then it will be captured to |
252 | * ensure that the success redirection will update the error redirection. |
253 | * |
254 | * @since unknown |
255 | * |
256 | * @param string $plugin Plugin path to main plugin file with plugin data. |
257 | * @param string $redirect Optional. URL to redirect to. |
258 | * @return WP_Error|null WP_Error on invalid file or null on success. |
259 | */ |
260 | function activate_plugin($plugin, $redirect = '') { |
261 | $current = get_option('active_plugins'); |
262 | $plugin = plugin_basename(trim($plugin)); |
263 | |
264 | $valid = validate_plugin($plugin); |
265 | if ( is_wp_error($valid) ) |
266 | return $valid; |
267 | |
268 | if ( !in_array($plugin, $current) ) { |
269 | if ( !empty($redirect) ) |
270 | 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 |
271 | ob_start(); |
272 | @include(WP_PLUGIN_DIR . '/' . $plugin); |
273 | $current[] = $plugin; |
274 | sort($current); |
275 | update_option('active_plugins', $current); |
276 | do_action('activate_' . $plugin); |
277 | ob_end_clean(); |
278 | } |
279 | |
280 | return null; |
281 | } |
282 | |
283 | /** |
284 | * Deactivate a single plugin or multiple plugins. |
285 | * |
286 | * The deactivation hook is disabled by the plugin upgrader by using the $silent |
287 | * parameter. |
288 | * |
289 | * @since unknown |
290 | * |
291 | * @param string|array $plugins Single plugin or list of plugins to deactivate. |
292 | * @param bool $silent Optional, default is false. Prevent calling deactivate hook. |
293 | */ |
294 | function deactivate_plugins($plugins, $silent= false) { |
295 | $current = get_option('active_plugins'); |
296 | |
297 | if ( !is_array($plugins) ) |
298 | $plugins = array($plugins); |
299 | |
300 | foreach ( $plugins as $plugin ) { |
301 | $plugin = plugin_basename($plugin); |
302 | if( ! is_plugin_active($plugin) ) |
303 | continue; |
304 | array_splice($current, array_search( $plugin, $current), 1 ); // Fixed Array-fu! |
305 | if ( ! $silent ) //Used by Plugin updater to internally deactivate plugin, however, not to notify plugins of the fact to prevent plugin output. |
306 | do_action('deactivate_' . trim( $plugin )); |
307 | } |
308 | |
309 | update_option('active_plugins', $current); |
310 | } |
311 | |
312 | /** |
313 | * Activate multiple plugins. |
314 | * |
315 | * When WP_Error is returned, it does not mean that one of the plugins had |
316 | * errors. It means that one or more of the plugins file path was invalid. |
317 | * |
318 | * The execution will be halted as soon as one of the plugins has an error. |
319 | * |
320 | * @since unknown |
321 | * |
322 | * @param string|array $plugins |
323 | * @param string $redirect Redirect to page after successful activation. |
324 | * @return bool|WP_Error True when finished or WP_Error if there were errors during a plugin activation. |
325 | */ |
326 | function activate_plugins($plugins, $redirect = '') { |
327 | if ( !is_array($plugins) ) |
328 | $plugins = array($plugins); |
329 | |
330 | $errors = array(); |
331 | foreach ( (array) $plugins as $plugin ) { |
332 | if ( !empty($redirect) ) |
333 | $redirect = add_query_arg('plugin', $plugin, $redirect); |
334 | $result = activate_plugin($plugin, $redirect); |
335 | if ( is_wp_error($result) ) |
336 | $errors[$plugin] = $result; |
337 | } |
338 | |
339 | if ( !empty($errors) ) |
340 | return new WP_Error('plugins_invalid', __('One of the plugins is invalid.'), $errors); |
341 | |
342 | return true; |
343 | } |
344 | |
345 | /** |
346 | * Remove directory and files of a plugin for a single or list of plugin(s). |
347 | * |
348 | * If the plugins parameter list is empty, false will be returned. True when |
349 | * completed. |
350 | * |
351 | * @since unknown |
352 | * |
353 | * @param array $plugins List of plugin |
354 | * @param string $redirect Redirect to page when complete. |
355 | * @return mixed |
356 | */ |
357 | function delete_plugins($plugins, $redirect = '' ) { |
358 | global $wp_filesystem; |
359 | |
360 | if( empty($plugins) ) |
361 | return false; |
362 | |
363 | $checked = array(); |
364 | foreach( $plugins as $plugin ) |
365 | $checked[] = 'checked[]=' . $plugin; |
366 | |
367 | ob_start(); |
368 | $url = wp_nonce_url('plugins.php?action=delete-selected&verify-delete=1&' . implode('&', $checked), 'bulk-manage-plugins'); |
369 | if ( false === ($credentials = request_filesystem_credentials($url)) ) { |
370 | $data = ob_get_contents(); |
371 | ob_end_clean(); |
372 | if( ! empty($data) ){ |
373 | include_once( ABSPATH . 'wp-admin/admin-header.php'); |
374 | echo $data; |
375 | include( ABSPATH . 'wp-admin/admin-footer.php'); |
376 | exit; |
377 | } |
378 | return; |
379 | } |
380 | |
381 | if ( ! WP_Filesystem($credentials) ) { |
382 | request_filesystem_credentials($url, '', true); //Failed to connect, Error and request again |
383 | $data = ob_get_contents(); |
384 | ob_end_clean(); |
385 | if( ! empty($data) ){ |
386 | include_once( ABSPATH . 'wp-admin/admin-header.php'); |
387 | echo $data; |
388 | include( ABSPATH . 'wp-admin/admin-footer.php'); |
389 | exit; |
390 | } |
391 | return; |
392 | } |
393 | |
394 | if ( $wp_filesystem->errors->get_error_code() ) { |
395 | return $wp_filesystem->errors; |
396 | } |
397 | |
398 | if ( ! is_object($wp_filesystem) ) |
399 | return new WP_Error('fs_unavailable', __('Could not access filesystem.')); |
400 | |
401 | if ( $wp_filesystem->errors->get_error_code() ) |
402 | return new WP_Error('fs_error', __('Filesystem error'), $wp_filesystem->errors); |
403 | |
404 | //Get the base plugin folder |
405 | $plugins_dir = $wp_filesystem->wp_plugins_dir(); |
406 | if ( empty($plugins_dir) ) |
407 | return new WP_Error('fs_no_plugins_dir', __('Unable to locate WordPress Plugin directory.')); |
408 | |
409 | $plugins_dir = trailingslashit( $plugins_dir ); |
410 | |
411 | $errors = array(); |
412 | |
413 | foreach( $plugins as $plugin_file ) { |
414 | // Run Uninstall hook |
415 | if ( is_uninstallable_plugin( $plugin_file ) ) |
416 | uninstall_plugin($plugin_file); |
417 | |
418 | $this_plugin_dir = trailingslashit( dirname($plugins_dir . $plugin_file) ); |
419 | // If plugin is in its own directory, recursively delete the directory. |
420 | if ( strpos($plugin_file, '/') && $this_plugin_dir != $plugins_dir ) //base check on if plugin includes directory seperator AND that its not the root plugin folder |
421 | $deleted = $wp_filesystem->delete($this_plugin_dir, true); |
422 | else |
423 | $deleted = $wp_filesystem->delete($plugins_dir . $plugin_file); |
424 | |
425 | if ( ! $deleted ) |
426 | $errors[] = $plugin_file; |
427 | } |
428 | |
429 | if ( ! empty($errors) ) |
430 | return new WP_Error('could_not_remove_plugin', sprintf(__('Could not fully remove the plugin(s) %s'), implode(', ', $errors)) ); |
431 | |
432 | // Force refresh of plugin update information |
433 | delete_option('update_plugins'); |
434 | |
435 | return true; |
436 | } |
437 | |
438 | function validate_active_plugins() { |
439 | $check_plugins = get_option('active_plugins'); |
440 | |
441 | // Sanity check. If the active plugin list is not an array, make it an |
442 | // empty array. |
443 | if ( !is_array($check_plugins) ) { |
444 | update_option('active_plugins', array()); |
445 | return; |
446 | } |
447 | |
448 | //Invalid is any plugin that is deactivated due to error. |
449 | $invalid = array(); |
450 | |
451 | // If a plugin file does not exist, remove it from the list of active |
452 | // plugins. |
453 | foreach ( $check_plugins as $check_plugin ) { |
454 | $result = validate_plugin($check_plugin); |
455 | if ( is_wp_error( $result ) ) { |
456 | $invalid[$check_plugin] = $result; |
457 | deactivate_plugins( $check_plugin, true); |
458 | } |
459 | } |
460 | return $invalid; |
461 | } |
462 | |
463 | /** |
464 | * Validate the plugin path. |
465 | * |
466 | * Checks that the file exists and {@link validate_file() is valid file}. |
467 | * |
468 | * @since unknown |
469 | * |
470 | * @param string $plugin Plugin Path |
471 | * @return WP_Error|int 0 on success, WP_Error on failure. |
472 | */ |
473 | function validate_plugin($plugin) { |
474 | if ( validate_file($plugin) ) |
475 | return new WP_Error('plugin_invalid', __('Invalid plugin path.')); |
476 | if ( ! file_exists(WP_PLUGIN_DIR . '/' . $plugin) ) |
477 | return new WP_Error('plugin_not_found', __('Plugin file does not exist.')); |
478 | |
479 | return 0; |
480 | } |
481 | |
482 | /** |
483 | * Whether the plugin can be uninstalled. |
484 | * |
485 | * @since 2.7.0 |
486 | * |
487 | * @param string $plugin Plugin path to check. |
488 | * @return bool Whether plugin can be uninstalled. |
489 | */ |
490 | function is_uninstallable_plugin($plugin) { |
491 | $file = plugin_basename($plugin); |
492 | |
493 | $uninstallable_plugins = (array) get_option('uninstall_plugins'); |
494 | if ( isset( $uninstallable_plugins[$file] ) || file_exists( WP_PLUGIN_DIR . '/' . dirname($file) . '/uninstall.php' ) ) |
495 | return true; |
496 | |
497 | return false; |
498 | } |
499 | |
500 | /** |
501 | * Uninstall a single plugin. |
502 | * |
503 | * Calls the uninstall hook, if it is available. |
504 | * |
505 | * @since 2.7.0 |
506 | * |
507 | * @param string $plugin Relative plugin path from Plugin Directory. |
508 | */ |
509 | function uninstall_plugin($plugin) { |
510 | $file = plugin_basename($plugin); |
511 | |
512 | $uninstallable_plugins = (array) get_option('uninstall_plugins'); |
513 | if ( file_exists( WP_PLUGIN_DIR . '/' . dirname($file) . '/uninstall.php' ) ) { |
514 | if ( isset( $uninstallable_plugins[$file] ) ) { |
515 | unset($uninstallable_plugins[$file]); |
516 | update_option('uninstall_plugins', $uninstallable_plugins); |
517 | } |
518 | unset($uninstallable_plugins); |
519 | |
520 | define('WP_UNINSTALL_PLUGIN', $file); |
521 | include WP_PLUGIN_DIR . '/' . dirname($file) . '/uninstall.php'; |
522 | |
523 | return true; |
524 | } |
525 | |
526 | if ( isset( $uninstallable_plugins[$file] ) ) { |
527 | $callable = $uninstallable_plugins[$file]; |
528 | unset($uninstallable_plugins[$file]); |
529 | update_option('uninstall_plugins', $uninstallable_plugins); |
530 | unset($uninstallable_plugins); |
531 | |
532 | include WP_PLUGIN_DIR . '/' . $file; |
533 | |
534 | add_action( 'uninstall_' . $file, $callable ); |
535 | do_action( 'uninstall_' . $file ); |
536 | } |
537 | } |
538 | |
539 | // |
540 | // Menu |
541 | // |
542 | |
543 | function add_menu_page( $page_title, $menu_title, $access_level, $file, $function = '', $icon_url = '' ) { |
544 | global $menu, $admin_page_hooks; |
545 | |
546 | $file = plugin_basename( $file ); |
547 | |
548 | $admin_page_hooks[$file] = sanitize_title( $menu_title ); |
549 | |
550 | $hookname = get_plugin_page_hookname( $file, '' ); |
551 | if (!empty ( $function ) && !empty ( $hookname )) |
552 | add_action( $hookname, $function ); |
553 | |
554 | if ( empty($icon_url) ) |
555 | $icon_url = 'images/generic.svg'; |
556 | |
557 | $menu[] = array ( $menu_title, $access_level, $file, $page_title, 'menu-top ' . $hookname, $hookname, $icon_url ); |
558 | |
559 | return $hookname; |
560 | } |
561 | |
562 | function add_object_page( $page_title, $menu_title, $access_level, $file, $function = '', $icon_url = '') { |
563 | global $menu, $admin_page_hooks, $_wp_last_object_menu; |
564 | |
565 | $file = plugin_basename( $file ); |
566 | |
567 | $admin_page_hooks[$file] = sanitize_title( $menu_title ); |
568 | |
569 | $hookname = get_plugin_page_hookname( $file, '' ); |
570 | if (!empty ( $function ) && !empty ( $hookname )) |
571 | add_action( $hookname, $function ); |
572 | |
573 | if ( empty($icon_url) ) |
574 | $icon_url = 'images/generic.svg'; |
575 | |
576 | $_wp_last_object_menu++; |
577 | |
578 | $menu[$_wp_last_object_menu] = array ( $menu_title, $access_level, $file, $page_title, 'menu-top ' . $hookname, $hookname, $icon_url ); |
579 | |
580 | return $hookname; |
581 | } |
582 | |
583 | function add_utility_page( $page_title, $menu_title, $access_level, $file, $function = '', $icon_url = '') { |
584 | global $menu, $admin_page_hooks, $_wp_last_utility_menu; |
585 | |
586 | $file = plugin_basename( $file ); |
587 | |
588 | $admin_page_hooks[$file] = sanitize_title( $menu_title ); |
589 | |
590 | $hookname = get_plugin_page_hookname( $file, '' ); |
591 | if (!empty ( $function ) && !empty ( $hookname )) |
592 | add_action( $hookname, $function ); |
593 | |
594 | if ( empty($icon_url) ) |
595 | $icon_url = 'images/generic.svg'; |
596 | |
597 | $_wp_last_utility_menu++; |
598 | |
599 | $menu[$_wp_last_utility_menu] = array ( $menu_title, $access_level, $file, $page_title, 'menu-top ' . $hookname, $hookname, $icon_url ); |
600 | |
601 | return $hookname; |
602 | } |
603 | |
604 | function add_submenu_page( $parent, $page_title, $menu_title, $access_level, $file, $function = '' ) { |
605 | global $submenu; |
606 | global $menu; |
607 | global $_wp_real_parent_file; |
608 | global $_wp_submenu_nopriv; |
609 | |
610 | $file = plugin_basename( $file ); |
611 | |
612 | $parent = plugin_basename( $parent); |
613 | if ( isset( $_wp_real_parent_file[$parent] ) ) |
614 | $parent = $_wp_real_parent_file[$parent]; |
615 | |
616 | if ( !current_user_can( $access_level ) ) { |
617 | $_wp_submenu_nopriv[$parent][$file] = true; |
618 | return false; |
619 | } |
620 | |
621 | // If the parent doesn't already have a submenu, add a link to the parent |
622 | // as the first item in the submenu. If the submenu file is the same as the |
623 | // parent file someone is trying to link back to the parent manually. In |
624 | // this case, don't automatically add a link back to avoid duplication. |
625 | if (!isset( $submenu[$parent] ) && $file != $parent ) { |
626 | foreach ( $menu as $parent_menu ) { |
627 | if ( $parent_menu[2] == $parent && current_user_can( $parent_menu[1] ) ) |
628 | $submenu[$parent][] = $parent_menu; |
629 | } |
630 | } |
631 | |
632 | $submenu[$parent][] = array ( $menu_title, $access_level, $file, $page_title ); |
633 | |
634 | $hookname = get_plugin_page_hookname( $file, $parent); |
635 | if (!empty ( $function ) && !empty ( $hookname )) |
636 | add_action( $hookname, $function ); |
637 | |
638 | return $hookname; |
639 | } |
640 | |
641 | /** |
642 | * Add sub menu page to the tools main menu. |
643 | * |
644 | * @param string $page_title |
645 | * @param unknown_type $menu_title |
646 | * @param unknown_type $access_level |
647 | * @param unknown_type $file |
648 | * @param unknown_type $function |
649 | * @return unknown |
650 | */ |
651 | function add_management_page( $page_title, $menu_title, $access_level, $file, $function = '' ) { |
652 | return add_submenu_page( 'tools.php', $page_title, $menu_title, $access_level, $file, $function ); |
653 | } |
654 | |
655 | function add_options_page( $page_title, $menu_title, $access_level, $file, $function = '' ) { |
656 | return add_submenu_page( 'options-general.php', $page_title, $menu_title, $access_level, $file, $function ); |
657 | } |
658 | |
659 | function add_theme_page( $page_title, $menu_title, $access_level, $file, $function = '' ) { |
660 | return add_submenu_page( 'themes.php', $page_title, $menu_title, $access_level, $file, $function ); |
661 | } |
662 | |
663 | function add_users_page( $page_title, $menu_title, $access_level, $file, $function = '' ) { |
664 | if ( current_user_can('edit_users') ) |
665 | $parent = 'users.php'; |
666 | else |
667 | $parent = 'profile.php'; |
668 | return add_submenu_page( $parent, $page_title, $menu_title, $access_level, $file, $function ); |
669 | } |
670 | |
671 | function add_dashboard_page( $page_title, $menu_title, $access_level, $file, $function = '' ) { |
672 | return add_submenu_page( 'index.php', $page_title, $menu_title, $access_level, $file, $function ); |
673 | } |
674 | |
675 | function add_posts_page( $page_title, $menu_title, $access_level, $file, $function = '' ) { |
676 | return add_submenu_page( 'edit.php', $page_title, $menu_title, $access_level, $file, $function ); |
677 | } |
678 | |
679 | function add_media_page( $page_title, $menu_title, $access_level, $file, $function = '' ) { |
680 | return add_submenu_page( 'upload.php', $page_title, $menu_title, $access_level, $file, $function ); |
681 | } |
682 | |
683 | function add_links_page( $page_title, $menu_title, $access_level, $file, $function = '' ) { |
684 | return add_submenu_page( 'link-manager.php', $page_title, $menu_title, $access_level, $file, $function ); |
685 | } |
686 | |
687 | function add_pages_page( $page_title, $menu_title, $access_level, $file, $function = '' ) { |
688 | return add_submenu_page( 'edit-pages.php', $page_title, $menu_title, $access_level, $file, $function ); |
689 | } |
690 | |
691 | function add_comments_page( $page_title, $menu_title, $access_level, $file, $function = '' ) { |
692 | return add_submenu_page( 'edit-comments.php', $page_title, $menu_title, $access_level, $file, $function ); |
693 | } |
694 | |
695 | // |
696 | // Pluggable Menu Support -- Private |
697 | // |
698 | |
699 | function get_admin_page_parent( $parent = '' ) { |
700 | global $parent_file; |
701 | global $menu; |
702 | global $submenu; |
703 | global $pagenow; |
704 | global $plugin_page; |
705 | global $_wp_real_parent_file; |
706 | global $_wp_menu_nopriv; |
707 | global $_wp_submenu_nopriv; |
708 | |
709 | if ( !empty ( $parent ) && 'admin.php' != $parent ) { |
710 | if ( isset( $_wp_real_parent_file[$parent] ) ) |
711 | $parent = $_wp_real_parent_file[$parent]; |
712 | return $parent; |
713 | } |
714 | /* |
715 | if ( !empty ( $parent_file ) ) { |
716 | if ( isset( $_wp_real_parent_file[$parent_file] ) ) |
717 | $parent_file = $_wp_real_parent_file[$parent_file]; |
718 | |
719 | return $parent_file; |
720 | } |
721 | */ |
722 | |
723 | if ( $pagenow == 'admin.php' && isset( $plugin_page ) ) { |
724 | foreach ( $menu as $parent_menu ) { |
725 | if ( $parent_menu[2] == $plugin_page ) { |
726 | $parent_file = $plugin_page; |
727 | if ( isset( $_wp_real_parent_file[$parent_file] ) ) |
728 | $parent_file = $_wp_real_parent_file[$parent_file]; |
729 | return $parent_file; |
730 | } |
731 | } |
732 | if ( isset( $_wp_menu_nopriv[$plugin_page] ) ) { |
733 | $parent_file = $plugin_page; |
734 | if ( isset( $_wp_real_parent_file[$parent_file] ) ) |
735 | $parent_file = $_wp_real_parent_file[$parent_file]; |
736 | return $parent_file; |
737 | } |
738 | } |
739 | |
740 | if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[$pagenow][$plugin_page] ) ) { |
741 | $parent_file = $pagenow; |
742 | if ( isset( $_wp_real_parent_file[$parent_file] ) ) |
743 | $parent_file = $_wp_real_parent_file[$parent_file]; |
744 | return $parent_file; |
745 | } |
746 | |
747 | foreach (array_keys( $submenu ) as $parent) { |
748 | foreach ( $submenu[$parent] as $submenu_array ) { |
749 | if ( isset( $_wp_real_parent_file[$parent] ) ) |
750 | $parent = $_wp_real_parent_file[$parent]; |
751 | if ( $submenu_array[2] == $pagenow ) { |
752 | $parent_file = $parent; |
753 | return $parent; |
754 | } else |
755 | if ( isset( $plugin_page ) && ($plugin_page == $submenu_array[2] ) ) { |
756 | $parent_file = $parent; |
757 | return $parent; |
758 | } |
759 | } |
760 | } |
761 | |
762 | if ( empty($parent_file) ) |
763 | $parent_file = ''; |
764 | return ''; |
765 | } |
766 | |
767 | function get_admin_page_title() { |
768 | global $title; |
769 | global $menu; |
770 | global $submenu; |
771 | global $pagenow; |
772 | global $plugin_page; |
773 | |
774 | if ( isset( $title ) && !empty ( $title ) ) { |
775 | return $title; |
776 | } |
777 | |
778 | $hook = get_plugin_page_hook( $plugin_page, $pagenow ); |
779 | |
780 | $parent = $parent1 = get_admin_page_parent(); |
781 | |
782 | if ( empty ( $parent) ) { |
783 | foreach ( $menu as $menu_array ) { |
784 | if ( isset( $menu_array[3] ) ) { |
785 | if ( $menu_array[2] == $pagenow ) { |
786 | $title = $menu_array[3]; |
787 | return $menu_array[3]; |
788 | } else |
789 | if ( isset( $plugin_page ) && ($plugin_page == $menu_array[2] ) && ($hook == $menu_array[3] ) ) { |
790 | $title = $menu_array[3]; |
791 | return $menu_array[3]; |
792 | } |
793 | } else { |
794 | $title = $menu_array[0]; |
795 | return $title; |
796 | } |
797 | } |
798 | } else { |
799 | foreach (array_keys( $submenu ) as $parent) { |
800 | foreach ( $submenu[$parent] as $submenu_array ) { |
801 | if ( isset( $plugin_page ) && |
802 | ($plugin_page == $submenu_array[2] ) && |
803 | (($parent == $pagenow ) || ($parent == $plugin_page ) || ($plugin_page == $hook ) || (($pagenow == 'admin.php' ) && ($parent1 != $submenu_array[2] ) ) ) |
804 | ) { |
805 | $title = $submenu_array[3]; |
806 | return $submenu_array[3]; |
807 | } |
808 | |
809 | if ( $submenu_array[2] != $pagenow || isset( $_GET['page'] ) ) // not the current page |
810 | continue; |
811 | |
812 | if ( isset( $submenu_array[3] ) ) { |
813 | $title = $submenu_array[3]; |
814 | return $submenu_array[3]; |
815 | } else { |
816 | $title = $submenu_array[0]; |
817 | return $title; |
818 | } |
819 | } |
820 | } |
821 | } |
822 | |
823 | return $title; |
824 | } |
825 | |
826 | function get_plugin_page_hook( $plugin_page, $parent_page ) { |
827 | $hook = get_plugin_page_hookname( $plugin_page, $parent_page ); |
828 | if ( has_action($hook) ) |
829 | return $hook; |
830 | else |
831 | return null; |
832 | } |
833 | |
834 | function get_plugin_page_hookname( $plugin_page, $parent_page ) { |
835 | global $admin_page_hooks; |
836 | |
837 | $parent = get_admin_page_parent( $parent_page ); |
838 | |
839 | $page_type = 'admin'; |
840 | if ( empty ( $parent_page ) || 'admin.php' == $parent_page || isset( $admin_page_hooks[$plugin_page] ) ) { |
841 | if ( isset( $admin_page_hooks[$plugin_page] ) ) |
842 | $page_type = 'toplevel'; |
843 | else |
844 | if ( isset( $admin_page_hooks[$parent] )) |
845 | $page_type = $admin_page_hooks[$parent]; |
846 | } else if ( isset( $admin_page_hooks[$parent] ) ) { |
847 | $page_type = $admin_page_hooks[$parent]; |
848 | } |
849 | |
850 | $plugin_name = preg_replace( '!\.php!', '', $plugin_page ); |
851 | |
852 | return $page_type.'_page_'.$plugin_name; |
853 | } |
854 | |
855 | function user_can_access_admin_page() { |
856 | global $pagenow; |
857 | global $menu; |
858 | global $submenu; |
859 | global $_wp_menu_nopriv; |
860 | global $_wp_submenu_nopriv; |
861 | global $plugin_page; |
862 | |
863 | $parent = get_admin_page_parent(); |
864 | |
865 | if ( isset( $_wp_submenu_nopriv[$parent][$pagenow] ) ) |
866 | return false; |
867 | |
868 | if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[$parent][$plugin_page] ) ) |
869 | return false; |
870 | |
871 | if ( empty( $parent) ) { |
872 | if ( isset( $_wp_menu_nopriv[$pagenow] ) ) |
873 | return false; |
874 | if ( isset( $_wp_submenu_nopriv[$pagenow][$pagenow] ) ) |
875 | return false; |
876 | if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[$pagenow][$plugin_page] ) ) |
877 | return false; |
878 | foreach (array_keys( $_wp_submenu_nopriv ) as $key ) { |
879 | if ( isset( $_wp_submenu_nopriv[$key][$pagenow] ) ) |
880 | return false; |
881 | if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[$key][$plugin_page] ) ) |
882 | return false; |
883 | } |
884 | return true; |
885 | } |
886 | |
887 | if ( isset( $submenu[$parent] ) ) { |
888 | foreach ( $submenu[$parent] as $submenu_array ) { |
889 | if ( isset( $plugin_page ) && ( $submenu_array[2] == $plugin_page ) ) { |
890 | if ( current_user_can( $submenu_array[1] )) |
891 | return true; |
892 | else |
893 | return false; |
894 | } else if ( $submenu_array[2] == $pagenow ) { |
895 | if ( current_user_can( $submenu_array[1] )) |
896 | return true; |
897 | else |
898 | return false; |
899 | } |
900 | } |
901 | } |
902 | |
903 | foreach ( $menu as $menu_array ) { |
904 | if ( $menu_array[2] == $parent) { |
905 | if ( current_user_can( $menu_array[1] )) |
906 | return true; |
907 | else |
908 | return false; |
909 | } |
910 | } |
911 | |
912 | return true; |
913 | } |
914 | |
915 | /* Whitelist functions */ |
916 | |
917 | /** |
918 | * Register a setting and its sanitization callback |
919 | * |
920 | * @since 2.7.0 |
921 | * |
922 | * @param string $option_group A settings group name. Can be anything. |
923 | * @param string $option_name The name of an option to sanitize and save. |
924 | * @param unknown_type $sanitize_callback A callback function that sanitizes the option's value. |
925 | * @return unknown |
926 | */ |
927 | function register_setting($option_group, $option_name, $sanitize_callback = '') { |
928 | return add_option_update_handler($option_group, $option_name, $sanitize_callback); |
929 | } |
930 | |
931 | /** |
932 | * Unregister a setting |
933 | * |
934 | * @since 2.7.0 |
935 | * |
936 | * @param unknown_type $option_group |
937 | * @param unknown_type $option_name |
938 | * @param unknown_type $sanitize_callback |
939 | * @return unknown |
940 | */ |
941 | function unregister_setting($option_group, $option_name, $sanitize_callback = '') { |
942 | return remove_option_update_handler($option_group, $option_name, $sanitize_callback); |
943 | } |
944 | |
945 | /** |
946 | * {@internal Missing Short Description}} |
947 | * |
948 | * @since unknown |
949 | * |
950 | * @param unknown_type $option_group |
951 | * @param unknown_type $option_name |
952 | * @param unknown_type $sanitize_callback |
953 | */ |
954 | function add_option_update_handler($option_group, $option_name, $sanitize_callback = '') { |
955 | global $new_whitelist_options; |
956 | $new_whitelist_options[ $option_group ][] = $option_name; |
957 | if ( $sanitize_callback != '' ) |
958 | add_filter( "sanitize_option_{$option_name}", $sanitize_callback ); |
959 | } |
960 | |
961 | /** |
962 | * {@internal Missing Short Description}} |
963 | * |
964 | * @since unknown |
965 | * |
966 | * @param unknown_type $option_group |
967 | * @param unknown_type $option_name |
968 | * @param unknown_type $sanitize_callback |
969 | */ |
970 | function remove_option_update_handler($option_group, $option_name, $sanitize_callback = '') { |
971 | global $new_whitelist_options; |
972 | $pos = array_search( $option_name, $new_whitelist_options ); |
973 | if ( $pos !== false ) |
974 | unset( $new_whitelist_options[ $option_group ][ $pos ] ); |
975 | if ( $sanitize_callback != '' ) |
976 | remove_filter( "sanitize_option_{$option_name}", $sanitize_callback ); |
977 | } |
978 | |
979 | /** |
980 | * {@internal Missing Short Description}} |
981 | * |
982 | * @since unknown |
983 | * |
984 | * @param unknown_type $options |
985 | * @return unknown |
986 | */ |
987 | function option_update_filter( $options ) { |
988 | global $new_whitelist_options; |
989 | |
990 | if ( is_array( $new_whitelist_options ) ) |
991 | $options = add_option_whitelist( $new_whitelist_options, $options ); |
992 | |
993 | return $options; |
994 | } |
995 | add_filter( 'whitelist_options', 'option_update_filter' ); |
996 | |
997 | /** |
998 | * {@internal Missing Short Description}} |
999 | * |
1000 | * @since unknown |
1001 | * |
1002 | * @param unknown_type $new_options |
1003 | * @param unknown_type $options |
1004 | * @return unknown |
1005 | */ |
1006 | function add_option_whitelist( $new_options, $options = '' ) { |
1007 | if( $options == '' ) { |
1008 | global $whitelist_options; |
1009 | } else { |
1010 | $whitelist_options = $options; |
1011 | } |
1012 | foreach( $new_options as $page => $keys ) { |
1013 | foreach( $keys as $key ) { |
1014 | if ( !isset($whitelist_options[ $page ]) || !is_array($whitelist_options[ $page ]) ) { |
1015 | $whitelist_options[ $page ] = array(); |
1016 | $whitelist_options[ $page ][] = $key; |
1017 | } else { |
1018 | $pos = array_search( $key, $whitelist_options[ $page ] ); |
1019 | if ( $pos === false ) |
1020 | $whitelist_options[ $page ][] = $key; |
1021 | } |
1022 | } |
1023 | } |
1024 | return $whitelist_options; |
1025 | } |
1026 | |
1027 | /** |
1028 | * {@internal Missing Short Description}} |
1029 | * |
1030 | * @since unknown |
1031 | * |
1032 | * @param unknown_type $del_options |
1033 | * @param unknown_type $options |
1034 | * @return unknown |
1035 | */ |
1036 | function remove_option_whitelist( $del_options, $options = '' ) { |
1037 | if( $options == '' ) { |
1038 | global $whitelist_options; |
1039 | } else { |
1040 | $whitelist_options = $options; |
1041 | } |
1042 | foreach( $del_options as $page => $keys ) { |
1043 | foreach( $keys as $key ) { |
1044 | $pos = array_search( $key, $whitelist_options[ $page ] ); |
1045 | if( $pos !== false ) |
1046 | unset( $whitelist_options[ $page ][ $pos ] ); |
1047 | } |
1048 | } |
1049 | return $whitelist_options; |
1050 | } |
1051 | |
1052 | /** |
1053 | * Output nonce, action, and option_page fields for a settings page. |
1054 | * |
1055 | * @since 2.7.0 |
1056 | * |
1057 | * @param string $option_group A settings group name. This should match the group name used in register_setting(). |
1058 | */ |
1059 | function settings_fields($option_group) { |
1060 | echo "<input type='hidden' name='option_page' value='$option_group' />"; |
1061 | echo '<input type="hidden" name="action" value="update" />'; |
1062 | wp_nonce_field("$option_group-options"); |
1063 | } |
1064 | |
1065 | ?> |