WordPress.org

Make WordPress Core

Ticket #48245: 48245.2.diff

File 48245.2.diff, 110.9 KB (added by stuffradio, 16 months ago)
  • wp-admin/includes/plugin.php

    diff --git a/wp-admin/includes/plugin.php b/wp-admin/includes/plugin.php
    index 3492b15ee2..7a4ea9dd94 100644
    a b  
    6767 */
    6868function get_plugin_data( $plugin_file, $markup = true, $translate = true ) {
    6969
    70         $default_headers = array(
    71                 'Name'        => 'Plugin Name',
    72                 'PluginURI'   => 'Plugin URI',
    73                 'Version'     => 'Version',
    74                 'Description' => 'Description',
    75                 'Author'      => 'Author',
    76                 'AuthorURI'   => 'Author URI',
    77                 'TextDomain'  => 'Text Domain',
    78                 'DomainPath'  => 'Domain Path',
    79                 'Network'     => 'Network',
    80                 'RequiresWP'  => 'Requires at least',
    81                 'RequiresPHP' => 'Requires PHP',
    82                 // Site Wide Only is deprecated in favor of Network.
    83                 '_sitewide'   => 'Site Wide Only',
    84         );
    85 
    86         $plugin_data = get_file_data( $plugin_file, $default_headers, 'plugin' );
    87 
    88         // Site Wide Only is the old header for Network.
    89         if ( ! $plugin_data['Network'] && $plugin_data['_sitewide'] ) {
    90                 /* translators: 1: Site Wide Only: true, 2: Network: true */
    91                 _deprecated_argument( __FUNCTION__, '3.0.0', sprintf( __( 'The %1$s plugin header is deprecated. Use %2$s instead.' ), '<code>Site Wide Only: true</code>', '<code>Network: true</code>' ) );
    92                 $plugin_data['Network'] = $plugin_data['_sitewide'];
    93         }
    94         $plugin_data['Network'] = ( 'true' === strtolower( $plugin_data['Network'] ) );
    95         unset( $plugin_data['_sitewide'] );
    96 
    97         // If no text domain is defined fall back to the plugin slug.
    98         if ( ! $plugin_data['TextDomain'] ) {
    99                 $plugin_slug = dirname( plugin_basename( $plugin_file ) );
    100                 if ( '.' !== $plugin_slug && false === strpos( $plugin_slug, '/' ) ) {
    101                         $plugin_data['TextDomain'] = $plugin_slug;
    102                 }
    103         }
    104 
    105         if ( $markup || $translate ) {
    106                 $plugin_data = _get_plugin_data_markup_translate( $plugin_file, $plugin_data, $markup, $translate );
    107         } else {
    108                 $plugin_data['Title']      = $plugin_data['Name'];
    109                 $plugin_data['AuthorName'] = $plugin_data['Author'];
    110         }
    111 
    112         return $plugin_data;
     70    $default_headers = array(
     71        'Name'        => 'Plugin Name',
     72        'PluginURI'   => 'Plugin URI',
     73        'Version'     => 'Version',
     74        'Description' => 'Description',
     75        'Author'      => 'Author',
     76        'AuthorURI'   => 'Author URI',
     77        'TextDomain'  => 'Text Domain',
     78        'DomainPath'  => 'Domain Path',
     79        'Network'     => 'Network',
     80        'RequiresWP'  => 'Requires at least',
     81        'RequiresPHP' => 'Requires PHP',
     82        // Site Wide Only is deprecated in favor of Network.
     83        '_sitewide'   => 'Site Wide Only',
     84    );
     85
     86    $plugin_data = get_file_data( $plugin_file, $default_headers, 'plugin' );
     87
     88    // Site Wide Only is the old header for Network.
     89    if ( ! $plugin_data['Network'] && $plugin_data['_sitewide'] ) {
     90        /* translators: 1: Site Wide Only: true, 2: Network: true */
     91        _deprecated_argument( __FUNCTION__, '3.0.0', sprintf( __( 'The %1$s plugin header is deprecated. Use %2$s instead.' ), '<code>Site Wide Only: true</code>', '<code>Network: true</code>' ) );
     92        $plugin_data['Network'] = $plugin_data['_sitewide'];
     93    }
     94    $plugin_data['Network'] = ( 'true' === strtolower( $plugin_data['Network'] ) );
     95    unset( $plugin_data['_sitewide'] );
     96
     97    // If no text domain is defined fall back to the plugin slug.
     98    if ( ! $plugin_data['TextDomain'] ) {
     99        $plugin_slug = dirname( plugin_basename( $plugin_file ) );
     100        if ( '.' !== $plugin_slug && false === strpos( $plugin_slug, '/' ) ) {
     101            $plugin_data['TextDomain'] = $plugin_slug;
     102        }
     103    }
     104
     105    if ( $markup || $translate ) {
     106        $plugin_data = _get_plugin_data_markup_translate( $plugin_file, $plugin_data, $markup, $translate );
     107    } else {
     108        $plugin_data['Title']      = $plugin_data['Name'];
     109        $plugin_data['AuthorName'] = $plugin_data['Author'];
     110    }
     111
     112    return $plugin_data;
    113113}
    114114
    115115/**
    function get_plugin_data( $plugin_file, $markup = true, $translate = true ) { 
    142142 */
    143143function _get_plugin_data_markup_translate( $plugin_file, $plugin_data, $markup = true, $translate = true ) {
    144144
    145         // Sanitize the plugin filename to a WP_PLUGIN_DIR relative path.
    146         $plugin_file = plugin_basename( $plugin_file );
    147 
    148         // Translate fields.
    149         if ( $translate ) {
    150                 $textdomain = $plugin_data['TextDomain'];
    151                 if ( $textdomain ) {
    152                         if ( ! is_textdomain_loaded( $textdomain ) ) {
    153                                 if ( $plugin_data['DomainPath'] ) {
    154                                         load_plugin_textdomain( $textdomain, false, dirname( $plugin_file ) . $plugin_data['DomainPath'] );
    155                                 } else {
    156                                         load_plugin_textdomain( $textdomain, false, dirname( $plugin_file ) );
    157                                 }
    158                         }
    159                 } elseif ( 'hello.php' === basename( $plugin_file ) ) {
    160                         $textdomain = 'default';
    161                 }
    162                 if ( $textdomain ) {
    163                         foreach ( array( 'Name', 'PluginURI', 'Description', 'Author', 'AuthorURI', 'Version' ) as $field ) {
    164                                 // phpcs:ignore WordPress.WP.I18n.LowLevelTranslationFunction,WordPress.WP.I18n.NonSingularStringLiteralText,WordPress.WP.I18n.NonSingularStringLiteralDomain
    165                                 $plugin_data[ $field ] = translate( $plugin_data[ $field ], $textdomain );
    166                         }
    167                 }
    168         }
    169 
    170         // Sanitize fields.
    171         $allowed_tags_in_links = array(
    172                 'abbr'    => array( 'title' => true ),
    173                 'acronym' => array( 'title' => true ),
    174                 'code'    => true,
    175                 'em'      => true,
    176                 'strong'  => true,
    177         );
    178 
    179         $allowed_tags      = $allowed_tags_in_links;
    180         $allowed_tags['a'] = array(
    181                 'href'  => true,
    182                 'title' => true,
    183         );
    184 
    185         // Name is marked up inside <a> tags. Don't allow these.
    186         // Author is too, but some plugins have used <a> here (omitting Author URI).
    187         $plugin_data['Name']   = wp_kses( $plugin_data['Name'], $allowed_tags_in_links );
    188         $plugin_data['Author'] = wp_kses( $plugin_data['Author'], $allowed_tags );
    189 
    190         $plugin_data['Description'] = wp_kses( $plugin_data['Description'], $allowed_tags );
    191         $plugin_data['Version']     = wp_kses( $plugin_data['Version'], $allowed_tags );
    192 
    193         $plugin_data['PluginURI'] = esc_url( $plugin_data['PluginURI'] );
    194         $plugin_data['AuthorURI'] = esc_url( $plugin_data['AuthorURI'] );
    195 
    196         $plugin_data['Title']      = $plugin_data['Name'];
    197         $plugin_data['AuthorName'] = $plugin_data['Author'];
    198 
    199         // Apply markup.
    200         if ( $markup ) {
    201                 if ( $plugin_data['PluginURI'] && $plugin_data['Name'] ) {
    202                         $plugin_data['Title'] = '<a href="' . $plugin_data['PluginURI'] . '">' . $plugin_data['Name'] . '</a>';
    203                 }
    204 
    205                 if ( $plugin_data['AuthorURI'] && $plugin_data['Author'] ) {
    206                         $plugin_data['Author'] = '<a href="' . $plugin_data['AuthorURI'] . '">' . $plugin_data['Author'] . '</a>';
    207                 }
    208 
    209                 $plugin_data['Description'] = wptexturize( $plugin_data['Description'] );
    210 
    211                 if ( $plugin_data['Author'] ) {
    212                         $plugin_data['Description'] .= sprintf(
    213                                 /* translators: %s: Plugin author. */
    214                                 ' <cite>' . __( 'By %s.' ) . '</cite>',
    215                                 $plugin_data['Author']
    216                         );
    217                 }
    218         }
    219 
    220         return $plugin_data;
     145    // Sanitize the plugin filename to a WP_PLUGIN_DIR relative path.
     146    $plugin_file = plugin_basename( $plugin_file );
     147
     148    // Translate fields.
     149    if ( $translate ) {
     150        $textdomain = $plugin_data['TextDomain'];
     151        if ( $textdomain ) {
     152            if ( ! is_textdomain_loaded( $textdomain ) ) {
     153                if ( $plugin_data['DomainPath'] ) {
     154                    load_plugin_textdomain( $textdomain, false, dirname( $plugin_file ) . $plugin_data['DomainPath'] );
     155                } else {
     156                    load_plugin_textdomain( $textdomain, false, dirname( $plugin_file ) );
     157                }
     158            }
     159        } elseif ( 'hello.php' === basename( $plugin_file ) ) {
     160            $textdomain = 'default';
     161        }
     162        if ( $textdomain ) {
     163            foreach ( array( 'Name', 'PluginURI', 'Description', 'Author', 'AuthorURI', 'Version' ) as $field ) {
     164                // phpcs:ignore WordPress.WP.I18n.LowLevelTranslationFunction,WordPress.WP.I18n.NonSingularStringLiteralText,WordPress.WP.I18n.NonSingularStringLiteralDomain
     165                $plugin_data[ $field ] = translate( $plugin_data[ $field ], $textdomain );
     166            }
     167        }
     168    }
     169
     170    // Sanitize fields.
     171    $allowed_tags_in_links = array(
     172        'abbr'    => array( 'title' => true ),
     173        'acronym' => array( 'title' => true ),
     174        'code'    => true,
     175        'em'      => true,
     176        'strong'  => true,
     177    );
     178
     179    $allowed_tags      = $allowed_tags_in_links;
     180    $allowed_tags['a'] = array(
     181        'href'  => true,
     182        'title' => true,
     183    );
     184
     185    // Name is marked up inside <a> tags. Don't allow these.
     186    // Author is too, but some plugins have used <a> here (omitting Author URI).
     187    $plugin_data['Name']   = wp_kses( $plugin_data['Name'], $allowed_tags_in_links );
     188    $plugin_data['Author'] = wp_kses( $plugin_data['Author'], $allowed_tags );
     189
     190    $plugin_data['Description'] = wp_kses( $plugin_data['Description'], $allowed_tags );
     191    $plugin_data['Version']     = wp_kses( $plugin_data['Version'], $allowed_tags );
     192
     193    $plugin_data['PluginURI'] = esc_url( $plugin_data['PluginURI'] );
     194    $plugin_data['AuthorURI'] = esc_url( $plugin_data['AuthorURI'] );
     195
     196    $plugin_data['Title']      = $plugin_data['Name'];
     197    $plugin_data['AuthorName'] = $plugin_data['Author'];
     198
     199    // Apply markup.
     200    if ( $markup ) {
     201        if ( $plugin_data['PluginURI'] && $plugin_data['Name'] ) {
     202            $plugin_data['Title'] = '<a href="' . $plugin_data['PluginURI'] . '">' . $plugin_data['Name'] . '</a>';
     203        }
     204
     205        if ( $plugin_data['AuthorURI'] && $plugin_data['Author'] ) {
     206            $plugin_data['Author'] = '<a href="' . $plugin_data['AuthorURI'] . '">' . $plugin_data['Author'] . '</a>';
     207        }
     208
     209        $plugin_data['Description'] = wptexturize( $plugin_data['Description'] );
     210
     211        if ( $plugin_data['Author'] ) {
     212            $plugin_data['Description'] .= sprintf(
     213            /* translators: %s: Plugin author. */
     214                ' <cite>' . __( 'By %s.' ) . '</cite>',
     215                $plugin_data['Author']
     216            );
     217        }
     218    }
     219
     220    return $plugin_data;
    221221}
    222222
    223223/**
    function _get_plugin_data_markup_translate( $plugin_file, $plugin_data, $markup 
    229229 * @return string[] Array of file names relative to the plugin root.
    230230 */
    231231function get_plugin_files( $plugin ) {
    232         $plugin_file = WP_PLUGIN_DIR . '/' . $plugin;
    233         $dir         = dirname( $plugin_file );
     232    $plugin_file = WP_PLUGIN_DIR . '/' . $plugin;
     233    $dir         = dirname( $plugin_file );
    234234
    235         $plugin_files = array( plugin_basename( $plugin_file ) );
     235    $plugin_files = array( plugin_basename( $plugin_file ) );
    236236
    237         if ( is_dir( $dir ) && WP_PLUGIN_DIR !== $dir ) {
     237    if ( is_dir( $dir ) && WP_PLUGIN_DIR !== $dir ) {
    238238
    239                 /**
    240                 * Filters the array of excluded directories and files while scanning the folder.
    241                 *
    242                 * @since 4.9.0
    243                 *
    244                 * @param string[] $exclusions Array of excluded directories and files.
    245                 */
    246                 $exclusions = (array) apply_filters( 'plugin_files_exclusions', array( 'CVS', 'node_modules', 'vendor', 'bower_components' ) );
     239        /**
     240        * Filters the array of excluded directories and files while scanning the folder.
     241        *
     242        * @since 4.9.0
     243        *
     244        * @param string[] $exclusions Array of excluded directories and files.
     245        */
     246        $exclusions = (array) apply_filters( 'plugin_files_exclusions', array( 'CVS', 'node_modules', 'vendor', 'bower_components' ) );
    247247
    248                 $list_files = list_files( $dir, 100, $exclusions );
    249                 $list_files = array_map( 'plugin_basename', $list_files );
     248        $list_files = list_files( $dir, 100, $exclusions );
     249        $list_files = array_map( 'plugin_basename', $list_files );
    250250
    251                 $plugin_files = array_merge( $plugin_files, $list_files );
    252                 $plugin_files = array_values( array_unique( $plugin_files ) );
    253         }
     251        $plugin_files = array_merge( $plugin_files, $list_files );
     252        $plugin_files = array_values( array_unique( $plugin_files ) );
     253    }
    254254
    255         return $plugin_files;
     255    return $plugin_files;
    256256}
    257257
    258258/**
    function get_plugin_files( $plugin ) { 
    277277 */
    278278function get_plugins( $plugin_folder = '' ) {
    279279
    280         $cache_plugins = wp_cache_get( 'plugins', 'plugins' );
    281         if ( ! $cache_plugins ) {
    282                 $cache_plugins = array();
    283         }
    284 
    285         if ( isset( $cache_plugins[ $plugin_folder ] ) ) {
    286                 return $cache_plugins[ $plugin_folder ];
    287         }
    288 
    289         $wp_plugins  = array();
    290         $plugin_root = WP_PLUGIN_DIR;
    291         if ( ! empty( $plugin_folder ) ) {
    292                 $plugin_root .= $plugin_folder;
    293         }
    294 
    295         // Files in wp-content/plugins directory.
    296         $plugins_dir  = @ opendir( $plugin_root );
    297         $plugin_files = array();
    298 
    299         if ( $plugins_dir ) {
    300                 while ( ( $file = readdir( $plugins_dir ) ) !== false ) {
    301                         if ( '.' === substr( $file, 0, 1 ) ) {
    302                                 continue;
    303                         }
    304 
    305                         if ( is_dir( $plugin_root . '/' . $file ) ) {
    306                                 $plugins_subdir = @ opendir( $plugin_root . '/' . $file );
    307 
    308                                 if ( $plugins_subdir ) {
    309                                         while ( ( $subfile = readdir( $plugins_subdir ) ) !== false ) {
    310                                                 if ( '.' === substr( $subfile, 0, 1 ) ) {
    311                                                         continue;
    312                                                 }
    313 
    314                                                 if ( '.php' === substr( $subfile, -4 ) ) {
    315                                                         $plugin_files[] = "$file/$subfile";
    316                                                 }
    317                                         }
    318 
    319                                         closedir( $plugins_subdir );
    320                                 }
    321                         } else {
    322                                 if ( '.php' === substr( $file, -4 ) ) {
    323                                         $plugin_files[] = $file;
    324                                 }
    325                         }
    326                 }
    327 
    328                 closedir( $plugins_dir );
    329         }
    330 
    331         if ( empty( $plugin_files ) ) {
    332                 return $wp_plugins;
    333         }
    334 
    335         foreach ( $plugin_files as $plugin_file ) {
    336                 if ( ! is_readable( "$plugin_root/$plugin_file" ) ) {
    337                         continue;
    338                 }
    339 
    340                 // Do not apply markup/translate as it will be cached.
    341                 $plugin_data = get_plugin_data( "$plugin_root/$plugin_file", false, false );
    342 
    343                 if ( empty( $plugin_data['Name'] ) ) {
    344                         continue;
    345                 }
    346 
    347                 $wp_plugins[ plugin_basename( $plugin_file ) ] = $plugin_data;
    348         }
    349 
    350         uasort( $wp_plugins, '_sort_uname_callback' );
    351 
    352         $cache_plugins[ $plugin_folder ] = $wp_plugins;
    353         wp_cache_set( 'plugins', $cache_plugins, 'plugins' );
    354 
    355         return $wp_plugins;
     280    $cache_plugins = wp_cache_get( 'plugins', 'plugins' );
     281    if ( ! $cache_plugins ) {
     282        $cache_plugins = array();
     283    }
     284
     285    if ( isset( $cache_plugins[ $plugin_folder ] ) ) {
     286        return $cache_plugins[ $plugin_folder ];
     287    }
     288
     289    $wp_plugins  = array();
     290    $plugin_root = WP_PLUGIN_DIR;
     291    if ( ! empty( $plugin_folder ) ) {
     292        $plugin_root .= $plugin_folder;
     293    }
     294
     295    // Files in wp-content/plugins directory.
     296    $plugins_dir  = @ opendir( $plugin_root );
     297    $plugin_files = array();
     298
     299    if ( $plugins_dir ) {
     300        while ( ( $file = readdir( $plugins_dir ) ) !== false ) {
     301            if ( '.' === substr( $file, 0, 1 ) ) {
     302                continue;
     303            }
     304
     305            if ( is_dir( $plugin_root . '/' . $file ) ) {
     306                $plugins_subdir = @ opendir( $plugin_root . '/' . $file );
     307
     308                if ( $plugins_subdir ) {
     309                    while ( ( $subfile = readdir( $plugins_subdir ) ) !== false ) {
     310                        if ( '.' === substr( $subfile, 0, 1 ) ) {
     311                            continue;
     312                        }
     313
     314                        if ( '.php' === substr( $subfile, -4 ) ) {
     315                            $plugin_files[] = "$file/$subfile";
     316                        }
     317                    }
     318
     319                    closedir( $plugins_subdir );
     320                }
     321            } else {
     322                if ( '.php' === substr( $file, -4 ) ) {
     323                    $plugin_files[] = $file;
     324                }
     325            }
     326        }
     327
     328        closedir( $plugins_dir );
     329    }
     330
     331    if ( empty( $plugin_files ) ) {
     332        return $wp_plugins;
     333    }
     334
     335    foreach ( $plugin_files as $plugin_file ) {
     336        if ( ! is_readable( "$plugin_root/$plugin_file" ) ) {
     337            continue;
     338        }
     339
     340        // Do not apply markup/translate as it will be cached.
     341        $plugin_data = get_plugin_data( "$plugin_root/$plugin_file", false, false );
     342
     343        if ( empty( $plugin_data['Name'] ) ) {
     344            continue;
     345        }
     346
     347        $wp_plugins[ plugin_basename( $plugin_file ) ] = $plugin_data;
     348    }
     349
     350    uasort( $wp_plugins, '_sort_uname_callback' );
     351
     352    $cache_plugins[ $plugin_folder ] = $wp_plugins;
     353    wp_cache_set( 'plugins', $cache_plugins, 'plugins' );
     354
     355    return $wp_plugins;
    356356}
    357357
    358358/**
    function get_plugins( $plugin_folder = '' ) { 
    364364 * @return array[] Array of arrays of mu-plugin data, keyed by plugin file name. See `get_plugin_data()`.
    365365 */
    366366function get_mu_plugins() {
    367         $wp_plugins   = array();
    368         $plugin_files = array();
    369 
    370         if ( ! is_dir( WPMU_PLUGIN_DIR ) ) {
    371                 return $wp_plugins;
    372         }
    373 
    374         // Files in wp-content/mu-plugins directory.
    375         $plugins_dir = @opendir( WPMU_PLUGIN_DIR );
    376         if ( $plugins_dir ) {
    377                 while ( ( $file = readdir( $plugins_dir ) ) !== false ) {
    378                         if ( '.php' === substr( $file, -4 ) ) {
    379                                 $plugin_files[] = $file;
    380                         }
    381                 }
    382         } else {
    383                 return $wp_plugins;
    384         }
    385 
    386         closedir( $plugins_dir );
    387 
    388         if ( empty( $plugin_files ) ) {
    389                 return $wp_plugins;
    390         }
    391 
    392         foreach ( $plugin_files as $plugin_file ) {
    393                 if ( ! is_readable( WPMU_PLUGIN_DIR . "/$plugin_file" ) ) {
    394                         continue;
    395                 }
    396 
    397                 // Do not apply markup/translate as it will be cached.
    398                 $plugin_data = get_plugin_data( WPMU_PLUGIN_DIR . "/$plugin_file", false, false );
    399 
    400                 if ( empty( $plugin_data['Name'] ) ) {
    401                         $plugin_data['Name'] = $plugin_file;
    402                 }
    403 
    404                 $wp_plugins[ $plugin_file ] = $plugin_data;
    405         }
    406 
    407         if ( isset( $wp_plugins['index.php'] ) && filesize( WPMU_PLUGIN_DIR . '/index.php' ) <= 30 ) {
    408                 // Silence is golden.
    409                 unset( $wp_plugins['index.php'] );
    410         }
    411 
    412         uasort( $wp_plugins, '_sort_uname_callback' );
    413 
    414         return $wp_plugins;
     367    $wp_plugins   = array();
     368    $plugin_files = array();
     369
     370    if ( ! is_dir( WPMU_PLUGIN_DIR ) ) {
     371        return $wp_plugins;
     372    }
     373
     374    // Files in wp-content/mu-plugins directory.
     375    $plugins_dir = @opendir( WPMU_PLUGIN_DIR );
     376    if ( $plugins_dir ) {
     377        while ( ( $file = readdir( $plugins_dir ) ) !== false ) {
     378            if ( '.php' === substr( $file, -4 ) ) {
     379                $plugin_files[] = $file;
     380            }
     381        }
     382    } else {
     383        return $wp_plugins;
     384    }
     385
     386    closedir( $plugins_dir );
     387
     388    if ( empty( $plugin_files ) ) {
     389        return $wp_plugins;
     390    }
     391
     392    foreach ( $plugin_files as $plugin_file ) {
     393        if ( ! is_readable( WPMU_PLUGIN_DIR . "/$plugin_file" ) ) {
     394            continue;
     395        }
     396
     397        // Do not apply markup/translate as it will be cached.
     398        $plugin_data = get_plugin_data( WPMU_PLUGIN_DIR . "/$plugin_file", false, false );
     399
     400        if ( empty( $plugin_data['Name'] ) ) {
     401            $plugin_data['Name'] = $plugin_file;
     402        }
     403
     404        $wp_plugins[ $plugin_file ] = $plugin_data;
     405    }
     406
     407    if ( isset( $wp_plugins['index.php'] ) && filesize( WPMU_PLUGIN_DIR . '/index.php' ) <= 30 ) {
     408        // Silence is golden.
     409        unset( $wp_plugins['index.php'] );
     410    }
     411
     412    uasort( $wp_plugins, '_sort_uname_callback' );
     413
     414    return $wp_plugins;
    415415}
    416416
    417417/**
    function get_mu_plugins() { 
    426426 * @return int Return 0 or 1 based on two string comparison.
    427427 */
    428428function _sort_uname_callback( $a, $b ) {
    429         return strnatcasecmp( $a['Name'], $b['Name'] );
     429    return strnatcasecmp( $a['Name'], $b['Name'] );
    430430}
    431431
    432432/**
    function _sort_uname_callback( $a, $b ) { 
    436436 * @return array[] Array of arrays of dropin plugin data, keyed by plugin file name. See `get_plugin_data()`.
    437437 */
    438438function get_dropins() {
    439         $dropins      = array();
    440         $plugin_files = array();
     439    $dropins      = array();
     440    $plugin_files = array();
    441441
    442         $_dropins = _get_dropins();
     442    $_dropins = _get_dropins();
    443443
    444         // Files in wp-content directory.
    445         $plugins_dir = @opendir( WP_CONTENT_DIR );
    446         if ( $plugins_dir ) {
    447                 while ( ( $file = readdir( $plugins_dir ) ) !== false ) {
    448                         if ( isset( $_dropins[ $file ] ) ) {
    449                                 $plugin_files[] = $file;
    450                         }
    451                 }
    452         } else {
    453                 return $dropins;
    454         }
     444    // Files in wp-content directory.
     445    $plugins_dir = @opendir( WP_CONTENT_DIR );
     446    if ( $plugins_dir ) {
     447        while ( ( $file = readdir( $plugins_dir ) ) !== false ) {
     448            if ( isset( $_dropins[ $file ] ) ) {
     449                $plugin_files[] = $file;
     450            }
     451        }
     452    } else {
     453        return $dropins;
     454    }
    455455
    456         closedir( $plugins_dir );
     456    closedir( $plugins_dir );
    457457
    458         if ( empty( $plugin_files ) ) {
    459                 return $dropins;
    460         }
     458    if ( empty( $plugin_files ) ) {
     459        return $dropins;
     460    }
    461461
    462         foreach ( $plugin_files as $plugin_file ) {
    463                 if ( ! is_readable( WP_CONTENT_DIR . "/$plugin_file" ) ) {
    464                         continue;
    465                 }
     462    foreach ( $plugin_files as $plugin_file ) {
     463        if ( ! is_readable( WP_CONTENT_DIR . "/$plugin_file" ) ) {
     464            continue;
     465        }
    466466
    467                 // Do not apply markup/translate as it will be cached.
    468                 $plugin_data = get_plugin_data( WP_CONTENT_DIR . "/$plugin_file", false, false );
     467        // Do not apply markup/translate as it will be cached.
     468        $plugin_data = get_plugin_data( WP_CONTENT_DIR . "/$plugin_file", false, false );
    469469
    470                 if ( empty( $plugin_data['Name'] ) ) {
    471                         $plugin_data['Name'] = $plugin_file;
    472                 }
     470        if ( empty( $plugin_data['Name'] ) ) {
     471            $plugin_data['Name'] = $plugin_file;
     472        }
    473473
    474                 $dropins[ $plugin_file ] = $plugin_data;
    475         }
     474        $dropins[ $plugin_file ] = $plugin_data;
     475    }
    476476
    477         uksort( $dropins, 'strnatcasecmp' );
     477    uksort( $dropins, 'strnatcasecmp' );
    478478
    479         return $dropins;
     479    return $dropins;
    480480}
    481481
    482482/**
    function get_dropins() { 
    490490 *  true for the drop-in to be used, or true if no constant is required.
    491491 */
    492492function _get_dropins() {
    493         $dropins = array(
    494                 'advanced-cache.php'      => array( __( 'Advanced caching plugin.' ), 'WP_CACHE' ),  // WP_CACHE
    495                 'db.php'                  => array( __( 'Custom database class.' ), true ),          // Auto on load.
    496                 'db-error.php'            => array( __( 'Custom database error message.' ), true ),  // Auto on error.
    497                 'install.php'             => array( __( 'Custom installation script.' ), true ),     // Auto on installation.
    498                 'maintenance.php'         => array( __( 'Custom maintenance message.' ), true ),     // Auto on maintenance.
    499                 'object-cache.php'        => array( __( 'External object cache.' ), true ),          // Auto on load.
    500                 'php-error.php'           => array( __( 'Custom PHP error message.' ), true ),       // Auto on error.
    501                 'fatal-error-handler.php' => array( __( 'Custom PHP fatal error handler.' ), true ), // Auto on error.
    502         );
    503 
    504         if ( is_multisite() ) {
    505                 $dropins['sunrise.php']        = array( __( 'Executed before Multisite is loaded.' ), 'SUNRISE' ); // SUNRISE
    506                 $dropins['blog-deleted.php']   = array( __( 'Custom site deleted message.' ), true );   // Auto on deleted blog.
    507                 $dropins['blog-inactive.php']  = array( __( 'Custom site inactive message.' ), true );  // Auto on inactive blog.
    508                 $dropins['blog-suspended.php'] = array( __( 'Custom site suspended message.' ), true ); // Auto on archived or spammed blog.
    509         }
    510 
    511         return $dropins;
     493    $dropins = array(
     494        'advanced-cache.php'      => array( __( 'Advanced caching plugin.' ), 'WP_CACHE' ),  // WP_CACHE
     495        'db.php'                  => array( __( 'Custom database class.' ), true ),          // Auto on load.
     496        'db-error.php'            => array( __( 'Custom database error message.' ), true ),  // Auto on error.
     497        'install.php'             => array( __( 'Custom installation script.' ), true ),     // Auto on installation.
     498        'maintenance.php'         => array( __( 'Custom maintenance message.' ), true ),     // Auto on maintenance.
     499        'object-cache.php'        => array( __( 'External object cache.' ), true ),          // Auto on load.
     500        'php-error.php'           => array( __( 'Custom PHP error message.' ), true ),       // Auto on error.
     501        'fatal-error-handler.php' => array( __( 'Custom PHP fatal error handler.' ), true ), // Auto on error.
     502    );
     503
     504    if ( is_multisite() ) {
     505        $dropins['sunrise.php']        = array( __( 'Executed before Multisite is loaded.' ), 'SUNRISE' ); // SUNRISE
     506        $dropins['blog-deleted.php']   = array( __( 'Custom site deleted message.' ), true );   // Auto on deleted blog.
     507        $dropins['blog-inactive.php']  = array( __( 'Custom site inactive message.' ), true );  // Auto on inactive blog.
     508        $dropins['blog-suspended.php'] = array( __( 'Custom site suspended message.' ), true ); // Auto on archived or spammed blog.
     509    }
     510
     511    return $dropins;
    512512}
    513513
    514514/**
    function _get_dropins() { 
    529529 * @return bool True, if in the active plugins list. False, not in the list.
    530530 */
    531531function is_plugin_active( $plugin ) {
    532         return in_array( $plugin, (array) get_option( 'active_plugins', array() ), true ) || is_plugin_active_for_network( $plugin );
     532    return in_array( $plugin, (array) get_option( 'active_plugins', array() ), true ) || is_plugin_active_for_network( $plugin );
    533533}
    534534
    535535/**
    function is_plugin_active( $plugin ) { 
    549549 * @return bool True if inactive. False if active.
    550550 */
    551551function is_plugin_inactive( $plugin ) {
    552         return ! is_plugin_active( $plugin );
     552    return ! is_plugin_active( $plugin );
    553553}
    554554
    555555/**
    function is_plugin_inactive( $plugin ) { 
    570570 * @return bool True if active for the network, otherwise false.
    571571 */
    572572function is_plugin_active_for_network( $plugin ) {
    573         if ( ! is_multisite() ) {
    574                 return false;
    575         }
     573    if ( ! is_multisite() ) {
     574        return false;
     575    }
    576576
    577         $plugins = get_site_option( 'active_sitewide_plugins' );
    578         if ( isset( $plugins[ $plugin ] ) ) {
    579                 return true;
    580         }
     577    $plugins = get_site_option( 'active_sitewide_plugins' );
     578    if ( isset( $plugins[ $plugin ] ) ) {
     579        return true;
     580    }
    581581
    582         return false;
     582    return false;
    583583}
    584584
    585585/**
    function is_plugin_active_for_network( $plugin ) { 
    595595 * @return bool True if plugin is network only, false otherwise.
    596596 */
    597597function is_network_only_plugin( $plugin ) {
    598         $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
    599         if ( $plugin_data ) {
    600                 return $plugin_data['Network'];
    601         }
    602         return false;
     598    $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
     599    if ( $plugin_data ) {
     600        return $plugin_data['Network'];
     601    }
     602    return false;
    603603}
    604604
    605605/**
    function is_network_only_plugin( $plugin ) { 
    631631 * @return null|WP_Error Null on success, WP_Error on invalid file.
    632632 */
    633633function activate_plugin( $plugin, $redirect = '', $network_wide = false, $silent = false ) {
    634         $plugin = plugin_basename( trim( $plugin ) );
    635 
    636         if ( is_multisite() && ( $network_wide || is_network_only_plugin( $plugin ) ) ) {
    637                 $network_wide        = true;
    638                 $current             = get_site_option( 'active_sitewide_plugins', array() );
    639                 $_GET['networkwide'] = 1; // Back compat for plugins looking for this value.
    640         } else {
    641                 $current = get_option( 'active_plugins', array() );
    642         }
    643 
    644         $valid = validate_plugin( $plugin );
    645         if ( is_wp_error( $valid ) ) {
    646                 return $valid;
    647         }
    648 
    649         $requirements = validate_plugin_requirements( $plugin );
    650         if ( is_wp_error( $requirements ) ) {
    651                 return $requirements;
    652         }
    653 
    654         if ( ( $network_wide && ! isset( $current[ $plugin ] ) ) || ( ! $network_wide && ! in_array( $plugin, $current, true ) ) ) {
    655                 if ( ! empty( $redirect ) ) {
    656                         // We'll override this later if the plugin can be included without fatal error.
    657                         wp_redirect( add_query_arg( '_error_nonce', wp_create_nonce( 'plugin-activation-error_' . $plugin ), $redirect ) );
    658                 }
    659 
    660                 ob_start();
    661                 wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $plugin );
    662                 $_wp_plugin_file = $plugin;
    663                 if ( ! defined( 'WP_SANDBOX_SCRAPING' ) ) {
    664                         define( 'WP_SANDBOX_SCRAPING', true );
    665                 }
    666                 include_once WP_PLUGIN_DIR . '/' . $plugin;
    667                 $plugin = $_wp_plugin_file; // Avoid stomping of the $plugin variable in a plugin.
    668 
    669                 if ( ! $silent ) {
    670                         /**
    671                         * Fires before a plugin is activated.
    672                         *
    673                         * If a plugin is silently activated (such as during an update),
    674                         * this hook does not fire.
    675                         *
    676                         * @since 2.9.0
    677                         *
    678                         * @param string $plugin       Path to the plugin file relative to the plugins directory.
    679                         * @param bool   $network_wide Whether to enable the plugin for all sites in the network
    680                         *                             or just the current site. Multisite only. Default false.
    681                         */
    682                         do_action( 'activate_plugin', $plugin, $network_wide );
    683 
    684                         /**
    685                         * Fires as a specific plugin is being activated.
    686                         *
    687                         * This hook is the "activation" hook used internally by register_activation_hook().
    688                         * The dynamic portion of the hook name, `$plugin`, refers to the plugin basename.
    689                         *
    690                         * If a plugin is silently activated (such as during an update), this hook does not fire.
    691                         *
    692                         * @since 2.0.0
    693                         *
    694                         * @param bool $network_wide Whether to enable the plugin for all sites in the network
    695                         *                           or just the current site. Multisite only. Default false.
    696                         */
    697                         do_action( "activate_{$plugin}", $network_wide );
    698                 }
    699 
    700                 if ( $network_wide ) {
    701                         $current            = get_site_option( 'active_sitewide_plugins', array() );
    702                         $current[ $plugin ] = time();
    703                         update_site_option( 'active_sitewide_plugins', $current );
    704                 } else {
    705                         $current   = get_option( 'active_plugins', array() );
    706                         $current[] = $plugin;
    707                         sort( $current );
    708                         update_option( 'active_plugins', $current );
    709                 }
    710 
    711                 if ( ! $silent ) {
    712                         /**
    713                         * Fires after a plugin has been activated.
    714                         *
    715                         * If a plugin is silently activated (such as during an update),
    716                         * this hook does not fire.
    717                         *
    718                         * @since 2.9.0
    719                         *
    720                         * @param string $plugin       Path to the plugin file relative to the plugins directory.
    721                         * @param bool   $network_wide Whether to enable the plugin for all sites in the network
    722                         *                             or just the current site. Multisite only. Default false.
    723                         */
    724                         do_action( 'activated_plugin', $plugin, $network_wide );
    725                 }
    726 
    727                 if ( ob_get_length() > 0 ) {
    728                         $output = ob_get_clean();
    729                         return new WP_Error( 'unexpected_output', __( 'The plugin generated unexpected output.' ), $output );
    730                 }
    731                 ob_end_clean();
    732         }
    733 
    734         return null;
     634    $plugin = plugin_basename( trim( $plugin ) );
     635
     636    if ( is_multisite() && ( $network_wide || is_network_only_plugin( $plugin ) ) ) {
     637        $network_wide        = true;
     638        $current             = get_site_option( 'active_sitewide_plugins', array() );
     639        $_GET['networkwide'] = 1; // Back compat for plugins looking for this value.
     640    } else {
     641        $current = get_option( 'active_plugins', array() );
     642    }
     643
     644    $valid = validate_plugin( $plugin );
     645    if ( is_wp_error( $valid ) ) {
     646        return $valid;
     647    }
     648
     649    $requirements = validate_plugin_requirements( $plugin );
     650    if ( is_wp_error( $requirements ) ) {
     651        return $requirements;
     652    }
     653
     654    if ( ( $network_wide && ! isset( $current[ $plugin ] ) ) || ( ! $network_wide && ! in_array( $plugin, $current, true ) ) ) {
     655        if ( ! empty( $redirect ) ) {
     656            // We'll override this later if the plugin can be included without fatal error.
     657            wp_redirect( add_query_arg( '_error_nonce', wp_create_nonce( 'plugin-activation-error_' . $plugin ), $redirect ) );
     658        }
     659
     660        ob_start();
     661        wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $plugin );
     662        $_wp_plugin_file = $plugin;
     663        if ( ! defined( 'WP_SANDBOX_SCRAPING' ) ) {
     664            define( 'WP_SANDBOX_SCRAPING', true );
     665        }
     666        include_once WP_PLUGIN_DIR . '/' . $plugin;
     667        $plugin = $_wp_plugin_file; // Avoid stomping of the $plugin variable in a plugin.
     668
     669        if ( ! $silent ) {
     670            /**
     671            * Fires before a plugin is activated.
     672            *
     673            * If a plugin is silently activated (such as during an update),
     674            * this hook does not fire.
     675            *
     676            * @since 2.9.0
     677            *
     678            * @param string $plugin       Path to the plugin file relative to the plugins directory.
     679            * @param bool   $network_wide Whether to enable the plugin for all sites in the network
     680            *                             or just the current site. Multisite only. Default false.
     681            */
     682            do_action( 'activate_plugin', $plugin, $network_wide );
     683
     684            /**
     685            * Fires as a specific plugin is being activated.
     686            *
     687            * This hook is the "activation" hook used internally by register_activation_hook().
     688            * The dynamic portion of the hook name, `$plugin`, refers to the plugin basename.
     689            *
     690            * If a plugin is silently activated (such as during an update), this hook does not fire.
     691            *
     692            * @since 2.0.0
     693            *
     694            * @param bool $network_wide Whether to enable the plugin for all sites in the network
     695            *                           or just the current site. Multisite only. Default false.
     696            */
     697            do_action( "activate_{$plugin}", $network_wide );
     698        }
     699
     700        if ( $network_wide ) {
     701            $current            = get_site_option( 'active_sitewide_plugins', array() );
     702            $current[ $plugin ] = time();
     703            update_site_option( 'active_sitewide_plugins', $current );
     704        } else {
     705            $current   = get_option( 'active_plugins', array() );
     706            $current[] = $plugin;
     707            sort( $current );
     708            update_option( 'active_plugins', $current );
     709        }
     710
     711        if ( ! $silent ) {
     712            /**
     713            * Fires after a plugin has been activated.
     714            *
     715            * If a plugin is silently activated (such as during an update),
     716            * this hook does not fire.
     717            *
     718            * @since 2.9.0
     719            *
     720            * @param string $plugin       Path to the plugin file relative to the plugins directory.
     721            * @param bool   $network_wide Whether to enable the plugin for all sites in the network
     722            *                             or just the current site. Multisite only. Default false.
     723            */
     724            do_action( 'activated_plugin', $plugin, $network_wide );
     725        }
     726
     727        if ( ob_get_length() > 0 ) {
     728            $output = ob_get_clean();
     729            return new WP_Error( 'unexpected_output', __( 'The plugin generated unexpected output.' ), $output );
     730        }
     731        ob_end_clean();
     732    }
     733
     734    return null;
    735735}
    736736
    737737/**
    function activate_plugin( $plugin, $redirect = '', $network_wide = false, $silen 
    749749 *                                      and the current site. Multisite only. Default null.
    750750 */
    751751function deactivate_plugins( $plugins, $silent = false, $network_wide = null ) {
    752         if ( is_multisite() ) {
    753                 $network_current = get_site_option( 'active_sitewide_plugins', array() );
    754         }
    755         $current    = get_option( 'active_plugins', array() );
    756         $do_blog    = false;
    757         $do_network = false;
    758 
    759         foreach ( (array) $plugins as $plugin ) {
    760                 $plugin = plugin_basename( trim( $plugin ) );
    761                 if ( ! is_plugin_active( $plugin ) ) {
    762                         continue;
    763                 }
    764 
    765                 $network_deactivating = false !== $network_wide && is_plugin_active_for_network( $plugin );
    766 
    767                 if ( ! $silent ) {
    768                         /**
    769                         * Fires before a plugin is deactivated.
    770                         *
    771                         * If a plugin is silently deactivated (such as during an update),
    772                         * this hook does not fire.
    773                         *
    774                         * @since 2.9.0
    775                         *
    776                         * @param string $plugin               Path to the plugin file relative to the plugins directory.
    777                         * @param bool   $network_deactivating Whether the plugin is deactivated for all sites in the network
    778                         *                                     or just the current site. Multisite only. Default false.
    779                         */
    780                         do_action( 'deactivate_plugin', $plugin, $network_deactivating );
    781                 }
    782 
    783                 if ( false !== $network_wide ) {
    784                         if ( is_plugin_active_for_network( $plugin ) ) {
    785                                 $do_network = true;
    786                                 unset( $network_current[ $plugin ] );
    787                         } elseif ( $network_wide ) {
    788                                 continue;
    789                         }
    790                 }
    791 
    792                 if ( true !== $network_wide ) {
    793                         $key = array_search( $plugin, $current, true );
    794                         if ( false !== $key ) {
    795                                 $do_blog = true;
    796                                 unset( $current[ $key ] );
    797                         }
    798                 }
    799 
    800                 if ( $do_blog && wp_is_recovery_mode() ) {
    801                         list( $extension ) = explode( '/', $plugin );
    802                         wp_paused_plugins()->delete( $extension );
    803                 }
    804 
    805                 if ( ! $silent ) {
    806                         /**
    807                         * Fires as a specific plugin is being deactivated.
    808                         *
    809                         * This hook is the "deactivation" hook used internally by register_deactivation_hook().
    810                         * The dynamic portion of the hook name, `$plugin`, refers to the plugin basename.
    811                         *
    812                         * If a plugin is silently deactivated (such as during an update), this hook does not fire.
    813                         *
    814                         * @since 2.0.0
    815                         *
    816                         * @param bool $network_deactivating Whether the plugin is deactivated for all sites in the network
    817                         *                                   or just the current site. Multisite only. Default false.
    818                         */
    819                         do_action( "deactivate_{$plugin}", $network_deactivating );
    820 
    821                         /**
    822                         * Fires after a plugin is deactivated.
    823                         *
    824                         * If a plugin is silently deactivated (such as during an update),
    825                         * this hook does not fire.
    826                         *
    827                         * @since 2.9.0
    828                         *
    829                         * @param string $plugin               Path to the plugin file relative to the plugins directory.
    830                         * @param bool   $network_deactivating Whether the plugin is deactivated for all sites in the network
    831                         *                                     or just the current site. Multisite only. Default false.
    832                         */
    833                         do_action( 'deactivated_plugin', $plugin, $network_deactivating );
    834                 }
    835         }
    836 
    837         if ( $do_blog ) {
    838                 update_option( 'active_plugins', $current );
    839         }
    840         if ( $do_network ) {
    841                 update_site_option( 'active_sitewide_plugins', $network_current );
    842         }
     752    if ( is_multisite() ) {
     753        $network_current = get_site_option( 'active_sitewide_plugins', array() );
     754    }
     755    $current    = get_option( 'active_plugins', array() );
     756    $do_blog    = false;
     757    $do_network = false;
     758
     759    foreach ( (array) $plugins as $plugin ) {
     760        $plugin = plugin_basename( trim( $plugin ) );
     761        if ( ! is_plugin_active( $plugin ) ) {
     762            continue;
     763        }
     764
     765        $network_deactivating = false !== $network_wide && is_plugin_active_for_network( $plugin );
     766
     767        if ( ! $silent ) {
     768            /**
     769            * Fires before a plugin is deactivated.
     770            *
     771            * If a plugin is silently deactivated (such as during an update),
     772            * this hook does not fire.
     773            *
     774            * @since 2.9.0
     775            *
     776            * @param string $plugin               Path to the plugin file relative to the plugins directory.
     777            * @param bool   $network_deactivating Whether the plugin is deactivated for all sites in the network
     778            *                                     or just the current site. Multisite only. Default false.
     779            */
     780            do_action( 'deactivate_plugin', $plugin, $network_deactivating );
     781        }
     782
     783        if ( false !== $network_wide ) {
     784            if ( is_plugin_active_for_network( $plugin ) ) {
     785                $do_network = true;
     786                unset( $network_current[ $plugin ] );
     787            } elseif ( $network_wide ) {
     788                continue;
     789            }
     790        }
     791
     792        if ( true !== $network_wide ) {
     793            $key = array_search( $plugin, $current, true );
     794            if ( false !== $key ) {
     795                $do_blog = true;
     796                unset( $current[ $key ] );
     797            }
     798        }
     799
     800        if ( $do_blog && wp_is_recovery_mode() ) {
     801            list( $extension ) = explode( '/', $plugin );
     802            wp_paused_plugins()->delete( $extension );
     803        }
     804
     805        if ( ! $silent ) {
     806            /**
     807            * Fires as a specific plugin is being deactivated.
     808            *
     809            * This hook is the "deactivation" hook used internally by register_deactivation_hook().
     810            * The dynamic portion of the hook name, `$plugin`, refers to the plugin basename.
     811            *
     812            * If a plugin is silently deactivated (such as during an update), this hook does not fire.
     813            *
     814            * @since 2.0.0
     815            *
     816            * @param bool $network_deactivating Whether the plugin is deactivated for all sites in the network
     817            *                                   or just the current site. Multisite only. Default false.
     818            */
     819            do_action( "deactivate_{$plugin}", $network_deactivating );
     820
     821            /**
     822            * Fires after a plugin is deactivated.
     823            *
     824            * If a plugin is silently deactivated (such as during an update),
     825            * this hook does not fire.
     826            *
     827            * @since 2.9.0
     828            *
     829            * @param string $plugin               Path to the plugin file relative to the plugins directory.
     830            * @param bool   $network_deactivating Whether the plugin is deactivated for all sites in the network
     831            *                                     or just the current site. Multisite only. Default false.
     832            */
     833            do_action( 'deactivated_plugin', $plugin, $network_deactivating );
     834        }
     835    }
     836
     837    if ( $do_blog ) {
     838        update_option( 'active_plugins', $current );
     839    }
     840    if ( $do_network ) {
     841        update_site_option( 'active_sitewide_plugins', $network_current );
     842    }
    843843}
    844844
    845845/**
    function deactivate_plugins( $plugins, $silent = false, $network_wide = null ) { 
    860860 * @return bool|WP_Error True when finished or WP_Error if there were errors during a plugin activation.
    861861 */
    862862function activate_plugins( $plugins, $redirect = '', $network_wide = false, $silent = false ) {
    863         if ( ! is_array( $plugins ) ) {
    864                 $plugins = array( $plugins );
    865         }
    866 
    867         $errors = array();
    868         foreach ( $plugins as $plugin ) {
    869                 if ( ! empty( $redirect ) ) {
    870                         $redirect = add_query_arg( 'plugin', $plugin, $redirect );
    871                 }
    872                 $result = activate_plugin( $plugin, $redirect, $network_wide, $silent );
    873                 if ( is_wp_error( $result ) ) {
    874                         $errors[ $plugin ] = $result;
    875                 }
    876         }
    877 
    878         if ( ! empty( $errors ) ) {
    879                 return new WP_Error( 'plugins_invalid', __( 'One of the plugins is invalid.' ), $errors );
    880         }
    881 
    882         return true;
     863    if ( ! is_array( $plugins ) ) {
     864        $plugins = array( $plugins );
     865    }
     866
     867    $errors = array();
     868    foreach ( $plugins as $plugin ) {
     869        if ( ! empty( $redirect ) ) {
     870            $redirect = add_query_arg( 'plugin', $plugin, $redirect );
     871        }
     872        $result = activate_plugin( $plugin, $redirect, $network_wide, $silent );
     873        if ( is_wp_error( $result ) ) {
     874            $errors[ $plugin ] = $result;
     875        }
     876    }
     877
     878    if ( ! empty( $errors ) ) {
     879        return new WP_Error( 'plugins_invalid', __( 'One of the plugins is invalid.' ), $errors );
     880    }
     881
     882    return true;
    883883}
    884884
    885885/**
    function activate_plugins( $plugins, $redirect = '', $network_wide = false, $sil 
    895895 *                            `null` if filesystem credentials are required to proceed.
    896896 */
    897897function delete_plugins( $plugins, $deprecated = '' ) {
    898         global $wp_filesystem;
    899 
    900         if ( empty( $plugins ) ) {
    901                 return false;
    902         }
    903 
    904         $checked = array();
    905         foreach ( $plugins as $plugin ) {
    906                 $checked[] = 'checked[]=' . $plugin;
    907         }
    908 
    909         $url = wp_nonce_url( 'plugins.php?action=delete-selected&verify-delete=1&' . implode( '&', $checked ), 'bulk-plugins' );
    910 
    911         ob_start();
    912         $credentials = request_filesystem_credentials( $url );
    913         $data        = ob_get_clean();
    914 
    915         if ( false === $credentials ) {
    916                 if ( ! empty( $data ) ) {
    917                         require_once ABSPATH . 'wp-admin/admin-header.php';
    918                         echo $data;
    919                         require_once ABSPATH . 'wp-admin/admin-footer.php';
    920                         exit;
    921                 }
    922                 return;
    923         }
    924 
    925         if ( ! WP_Filesystem( $credentials ) ) {
    926                 ob_start();
    927                 // Failed to connect. Error and request again.
    928                 request_filesystem_credentials( $url, '', true );
    929                 $data = ob_get_clean();
    930 
    931                 if ( ! empty( $data ) ) {
    932                         require_once ABSPATH . 'wp-admin/admin-header.php';
    933                         echo $data;
    934                         require_once ABSPATH . 'wp-admin/admin-footer.php';
    935                         exit;
    936                 }
    937                 return;
    938         }
    939 
    940         if ( ! is_object( $wp_filesystem ) ) {
    941                 return new WP_Error( 'fs_unavailable', __( 'Could not access filesystem.' ) );
    942         }
    943 
    944         if ( is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() ) {
    945                 return new WP_Error( 'fs_error', __( 'Filesystem error.' ), $wp_filesystem->errors );
    946         }
    947 
    948         // Get the base plugin folder.
    949         $plugins_dir = $wp_filesystem->wp_plugins_dir();
    950         if ( empty( $plugins_dir ) ) {
    951                 return new WP_Error( 'fs_no_plugins_dir', __( 'Unable to locate WordPress plugin directory.' ) );
    952         }
    953 
    954         $plugins_dir = trailingslashit( $plugins_dir );
    955 
    956         $plugin_translations = wp_get_installed_translations( 'plugins' );
    957 
    958         $errors = array();
    959 
    960         foreach ( $plugins as $plugin_file ) {
    961                 // Run Uninstall hook.
    962                 if ( is_uninstallable_plugin( $plugin_file ) ) {
    963                         uninstall_plugin( $plugin_file );
    964                 }
    965 
    966                 /**
    967                 * Fires immediately before a plugin deletion attempt.
    968                 *
    969                 * @since 4.4.0
    970                 *
    971                 * @param string $plugin_file Path to the plugin file relative to the plugins directory.
    972                 */
    973                 do_action( 'delete_plugin', $plugin_file );
    974 
    975                 $this_plugin_dir = trailingslashit( dirname( $plugins_dir . $plugin_file ) );
    976 
    977                 // If plugin is in its own directory, recursively delete the directory.
    978                 // Base check on if plugin includes directory separator AND that it's not the root plugin folder.
    979                 if ( strpos( $plugin_file, '/' ) && $this_plugin_dir != $plugins_dir ) {
    980                         $deleted = $wp_filesystem->delete( $this_plugin_dir, true );
    981                 } else {
    982                         $deleted = $wp_filesystem->delete( $plugins_dir . $plugin_file );
    983                 }
    984 
    985                 /**
    986                 * Fires immediately after a plugin deletion attempt.
    987                 *
    988                 * @since 4.4.0
    989                 *
    990                 * @param string $plugin_file Path to the plugin file relative to the plugins directory.
    991                 * @param bool   $deleted     Whether the plugin deletion was successful.
    992                 */
    993                 do_action( 'deleted_plugin', $plugin_file, $deleted );
    994 
    995                 if ( ! $deleted ) {
    996                         $errors[] = $plugin_file;
    997                         continue;
    998                 }
    999 
    1000                 // Remove language files, silently.
    1001                 $plugin_slug = dirname( $plugin_file );
    1002                 if ( '.' !== $plugin_slug && ! empty( $plugin_translations[ $plugin_slug ] ) ) {
    1003                         $translations = $plugin_translations[ $plugin_slug ];
    1004 
    1005                         foreach ( $translations as $translation => $data ) {
    1006                                 $wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.po' );
    1007                                 $wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.mo' );
    1008 
    1009                                 $json_translation_files = glob( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '-*.json' );
    1010                                 if ( $json_translation_files ) {
    1011                                         array_map( array( $wp_filesystem, 'delete' ), $json_translation_files );
    1012                                 }
    1013                         }
    1014                 }
    1015         }
    1016 
    1017         // Remove deleted plugins from the plugin updates list.
    1018         $current = get_site_transient( 'update_plugins' );
    1019         if ( $current ) {
    1020                 // Don't remove the plugins that weren't deleted.
    1021                 $deleted = array_diff( $plugins, $errors );
    1022 
    1023                 foreach ( $deleted as $plugin_file ) {
    1024                         unset( $current->response[ $plugin_file ] );
    1025                 }
    1026 
    1027                 set_site_transient( 'update_plugins', $current );
    1028         }
    1029 
    1030         if ( ! empty( $errors ) ) {
    1031                 if ( 1 === count( $errors ) ) {
    1032                         /* translators: %s: Plugin filename. */
    1033                         $message = __( 'Could not fully remove the plugin %s.' );
    1034                 } else {
    1035                         /* translators: %s: Comma-separated list of plugin filenames. */
    1036                         $message = __( 'Could not fully remove the plugins %s.' );
    1037                 }
    1038 
    1039                 return new WP_Error( 'could_not_remove_plugin', sprintf( $message, implode( ', ', $errors ) ) );
    1040         }
    1041 
    1042         return true;
     898    global $wp_filesystem;
     899
     900    if ( empty( $plugins ) ) {
     901        return false;
     902    }
     903
     904    $checked = array();
     905    foreach ( $plugins as $plugin ) {
     906        $checked[] = 'checked[]=' . $plugin;
     907    }
     908
     909    $url = wp_nonce_url( 'plugins.php?action=delete-selected&verify-delete=1&' . implode( '&', $checked ), 'bulk-plugins' );
     910
     911    ob_start();
     912    $credentials = request_filesystem_credentials( $url );
     913    $data        = ob_get_clean();
     914
     915    if ( false === $credentials ) {
     916        if ( ! empty( $data ) ) {
     917            require_once ABSPATH . 'wp-admin/admin-header.php';
     918            echo $data;
     919            require_once ABSPATH . 'wp-admin/admin-footer.php';
     920            exit;
     921        }
     922        return;
     923    }
     924
     925    if ( ! WP_Filesystem( $credentials ) ) {
     926        ob_start();
     927        // Failed to connect. Error and request again.
     928        request_filesystem_credentials( $url, '', true );
     929        $data = ob_get_clean();
     930
     931        if ( ! empty( $data ) ) {
     932            require_once ABSPATH . 'wp-admin/admin-header.php';
     933            echo $data;
     934            require_once ABSPATH . 'wp-admin/admin-footer.php';
     935            exit;
     936        }
     937        return;
     938    }
     939
     940    if ( ! is_object( $wp_filesystem ) ) {
     941        return new WP_Error( 'fs_unavailable', __( 'Could not access filesystem.' ) );
     942    }
     943
     944    if ( is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() ) {
     945        return new WP_Error( 'fs_error', __( 'Filesystem error.' ), $wp_filesystem->errors );
     946    }
     947
     948    // Get the base plugin folder.
     949    $plugins_dir = $wp_filesystem->wp_plugins_dir();
     950    if ( empty( $plugins_dir ) ) {
     951        return new WP_Error( 'fs_no_plugins_dir', __( 'Unable to locate WordPress plugin directory.' ) );
     952    }
     953
     954    $plugins_dir = trailingslashit( $plugins_dir );
     955
     956    $plugin_translations = wp_get_installed_translations( 'plugins' );
     957
     958    $errors = array();
     959
     960    foreach ( $plugins as $plugin_file ) {
     961        // Run Uninstall hook.
     962        if ( is_uninstallable_plugin( $plugin_file ) ) {
     963            uninstall_plugin( $plugin_file );
     964        }
     965
     966        /**
     967        * Fires immediately before a plugin deletion attempt.
     968        *
     969        * @since 4.4.0
     970        *
     971        * @param string $plugin_file Path to the plugin file relative to the plugins directory.
     972        */
     973        do_action( 'delete_plugin', $plugin_file );
     974
     975        $this_plugin_dir = trailingslashit( dirname( $plugins_dir . $plugin_file ) );
     976
     977        // If plugin is in its own directory, recursively delete the directory.
     978        // Base check on if plugin includes directory separator AND that it's not the root plugin folder.
     979        if ( strpos( $plugin_file, '/' ) && $this_plugin_dir != $plugins_dir ) {
     980            $deleted = $wp_filesystem->delete( $this_plugin_dir, true );
     981        } else {
     982            $deleted = $wp_filesystem->delete( $plugins_dir . $plugin_file );
     983        }
     984
     985        /**
     986        * Fires immediately after a plugin deletion attempt.
     987        *
     988        * @since 4.4.0
     989        *
     990        * @param string $plugin_file Path to the plugin file relative to the plugins directory.
     991        * @param bool   $deleted     Whether the plugin deletion was successful.
     992        */
     993        do_action( 'deleted_plugin', $plugin_file, $deleted );
     994
     995        if ( ! $deleted ) {
     996            $errors[] = $plugin_file;
     997            continue;
     998        }
     999
     1000        // Remove language files, silently.
     1001        $plugin_slug = dirname( $plugin_file );
     1002        if ( '.' !== $plugin_slug && ! empty( $plugin_translations[ $plugin_slug ] ) ) {
     1003            $translations = $plugin_translations[ $plugin_slug ];
     1004
     1005            foreach ( $translations as $translation => $data ) {
     1006                $wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.po' );
     1007                $wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.mo' );
     1008
     1009                $json_translation_files = glob( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '-*.json' );
     1010                if ( $json_translation_files ) {
     1011                    array_map( array( $wp_filesystem, 'delete' ), $json_translation_files );
     1012                }
     1013            }
     1014        }
     1015    }
     1016
     1017    // Remove deleted plugins from the plugin updates list.
     1018    $current = get_site_transient( 'update_plugins' );
     1019    if ( $current ) {
     1020        // Don't remove the plugins that weren't deleted.
     1021        $deleted = array_diff( $plugins, $errors );
     1022
     1023        foreach ( $deleted as $plugin_file ) {
     1024            unset( $current->response[ $plugin_file ] );
     1025        }
     1026
     1027        set_site_transient( 'update_plugins', $current );
     1028    }
     1029
     1030    if ( ! empty( $errors ) ) {
     1031        if ( 1 === count( $errors ) ) {
     1032            /* translators: %s: Plugin filename. */
     1033            $message = __( 'Could not fully remove the plugin %s.' );
     1034        } else {
     1035            /* translators: %s: Comma-separated list of plugin filenames. */
     1036            $message = __( 'Could not fully remove the plugins %s.' );
     1037        }
     1038
     1039        return new WP_Error( 'could_not_remove_plugin', sprintf( $message, implode( ', ', $errors ) ) );
     1040    }
     1041
     1042    return true;
    10431043}
    10441044
    10451045/**
    function delete_plugins( $plugins, $deprecated = '' ) { 
    10521052 * @return WP_Error[] Array of plugin errors keyed by plugin file name.
    10531053 */
    10541054function validate_active_plugins() {
    1055         $plugins = get_option( 'active_plugins', array() );
    1056         // Validate vartype: array.
    1057         if ( ! is_array( $plugins ) ) {
    1058                 update_option( 'active_plugins', array() );
    1059                 $plugins = array();
    1060         }
    1061 
    1062         if ( is_multisite() && current_user_can( 'manage_network_plugins' ) ) {
    1063                 $network_plugins = (array) get_site_option( 'active_sitewide_plugins', array() );
    1064                 $plugins         = array_merge( $plugins, array_keys( $network_plugins ) );
    1065         }
    1066 
    1067         if ( empty( $plugins ) ) {
    1068                 return array();
    1069         }
    1070 
    1071         $invalid = array();
    1072 
    1073         // Invalid plugins get deactivated.
    1074         foreach ( $plugins as $plugin ) {
    1075                 $result = validate_plugin( $plugin );
    1076                 if ( is_wp_error( $result ) ) {
    1077                         $invalid[ $plugin ] = $result;
    1078                         deactivate_plugins( $plugin, true );
    1079                 }
    1080         }
    1081         return $invalid;
     1055    $plugins = get_option( 'active_plugins', array() );
     1056    // Validate vartype: array.
     1057    if ( ! is_array( $plugins ) ) {
     1058        update_option( 'active_plugins', array() );
     1059        $plugins = array();
     1060    }
     1061
     1062    if ( is_multisite() && current_user_can( 'manage_network_plugins' ) ) {
     1063        $network_plugins = (array) get_site_option( 'active_sitewide_plugins', array() );
     1064        $plugins         = array_merge( $plugins, array_keys( $network_plugins ) );
     1065    }
     1066
     1067    if ( empty( $plugins ) ) {
     1068        return array();
     1069    }
     1070
     1071    $invalid = array();
     1072
     1073    // Invalid plugins get deactivated.
     1074    foreach ( $plugins as $plugin ) {
     1075        $result = validate_plugin( $plugin );
     1076        if ( is_wp_error( $result ) ) {
     1077            $invalid[ $plugin ] = $result;
     1078            deactivate_plugins( $plugin, true );
     1079        }
     1080    }
     1081    return $invalid;
    10821082}
    10831083
    10841084/**
    function validate_active_plugins() { 
    10921092 * @return int|WP_Error 0 on success, WP_Error on failure.
    10931093 */
    10941094function validate_plugin( $plugin ) {
    1095         if ( validate_file( $plugin ) ) {
    1096                 return new WP_Error( 'plugin_invalid', __( 'Invalid plugin path.' ) );
    1097         }
    1098         if ( ! file_exists( WP_PLUGIN_DIR . '/' . $plugin ) ) {
    1099                 return new WP_Error( 'plugin_not_found', __( 'Plugin file does not exist.' ) );
    1100         }
    1101 
    1102         $installed_plugins = get_plugins();
    1103         if ( ! isset( $installed_plugins[ $plugin ] ) ) {
    1104                 return new WP_Error( 'no_plugin_header', __( 'The plugin does not have a valid header.' ) );
    1105         }
    1106         return 0;
     1095    if ( validate_file( $plugin ) ) {
     1096        return new WP_Error( 'plugin_invalid', __( 'Invalid plugin path.' ) );
     1097    }
     1098    if ( ! file_exists( WP_PLUGIN_DIR . '/' . $plugin ) ) {
     1099        return new WP_Error( 'plugin_not_found', __( 'Plugin file does not exist.' ) );
     1100    }
     1101
     1102    $installed_plugins = get_plugins();
     1103    if ( ! isset( $installed_plugins[ $plugin ] ) ) {
     1104        return new WP_Error( 'no_plugin_header', __( 'The plugin does not have a valid header.' ) );
     1105    }
     1106    return 0;
    11071107}
    11081108
    11091109/**
    function validate_plugin( $plugin ) { 
    11231123 * @return true|WP_Error True if requirements are met, WP_Error on failure.
    11241124 */
    11251125function validate_plugin_requirements( $plugin ) {
    1126         $plugin_headers = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
    1127 
    1128         $requirements = array(
    1129                 'requires'     => ! empty( $plugin_headers['RequiresWP'] ) ? $plugin_headers['RequiresWP'] : '',
    1130                 'requires_php' => ! empty( $plugin_headers['RequiresPHP'] ) ? $plugin_headers['RequiresPHP'] : '',
    1131         );
    1132 
    1133         $readme_file = WP_PLUGIN_DIR . '/' . dirname( $plugin ) . '/readme.txt';
    1134 
    1135         if ( file_exists( $readme_file ) ) {
    1136                 $readme_headers = get_file_data(
    1137                         $readme_file,
    1138                         array(
    1139                                 'requires'     => 'Requires at least',
    1140                                 'requires_php' => 'Requires PHP',
    1141                         ),
    1142                         'plugin'
    1143                 );
    1144 
    1145                 $requirements = array_merge( $readme_headers, $requirements );
    1146         }
    1147 
    1148         $compatible_wp  = is_wp_version_compatible( $requirements['requires'] );
    1149         $compatible_php = is_php_version_compatible( $requirements['requires_php'] );
    1150 
    1151         if ( ! $compatible_wp && ! $compatible_php ) {
    1152                 return new WP_Error(
    1153                         'plugin_wp_php_incompatible',
    1154                         sprintf(
    1155                                 /* translators: %s: Plugin name. */
    1156                                 _x( '<strong>Error:</strong> Current WordPress and PHP versions do not meet minimum requirements for %s.', 'plugin' ),
    1157                                 $plugin_headers['Name']
    1158                         )
    1159                 );
    1160         } elseif ( ! $compatible_php ) {
    1161                 return new WP_Error(
    1162                         'plugin_php_incompatible',
    1163                         sprintf(
    1164                                 /* translators: %s: Plugin name. */
    1165                                 _x( '<strong>Error:</strong> Current PHP version does not meet minimum requirements for %s.', 'plugin' ),
    1166                                 $plugin_headers['Name']
    1167                         )
    1168                 );
    1169         } elseif ( ! $compatible_wp ) {
    1170                 return new WP_Error(
    1171                         'plugin_wp_incompatible',
    1172                         sprintf(
    1173                                 /* translators: %s: Plugin name. */
    1174                                 _x( '<strong>Error:</strong> Current WordPress version does not meet minimum requirements for %s.', 'plugin' ),
    1175                                 $plugin_headers['Name']
    1176                         )
    1177                 );
    1178         }
    1179 
    1180         return true;
     1126    $plugin_headers = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
     1127
     1128    $requirements = array(
     1129        'requires'     => ! empty( $plugin_headers['RequiresWP'] ) ? $plugin_headers['RequiresWP'] : '',
     1130        'requires_php' => ! empty( $plugin_headers['RequiresPHP'] ) ? $plugin_headers['RequiresPHP'] : '',
     1131    );
     1132
     1133    $php_compat = version_compare( phpversion(), $plugin_headers['RequiresPHP'], '>=' );
     1134
     1135    $readme_file = WP_PLUGIN_DIR . '/' . dirname( $plugin ) . '/readme.txt';
     1136
     1137    if ( file_exists( $readme_file ) ) {
     1138        $readme_headers = get_file_data(
     1139            $readme_file,
     1140            array(
     1141                'requires'     => 'Requires at least',
     1142                'requires_php' => 'Requires PHP',
     1143            ),
     1144            'plugin'
     1145        );
     1146
     1147        $requirements = array_merge( $readme_headers, $requirements );
     1148    }
     1149
     1150
     1151    /* translators: %s: URL to Update PHP page. */
     1152    $php_update_message = ( !$php_compat ) ? '<p>' . sprintf( __( '<a href="%s">Learn more about updating PHP</a>.' ), esc_url( wp_get_update_php_url() ) ) : '';
     1153
     1154    $annotation = ( !$php_compat ) ? wp_get_update_php_annotation() : false;
     1155
     1156    if ( $annotation ) {
     1157        $php_update_message .= '</p><p><em>' . $annotation . '</em>';
     1158    }
     1159
     1160
     1161    $compatible_wp  = is_wp_version_compatible( $requirements['requires'] );
     1162    $compatible_php = is_php_version_compatible( $requirements['requires_php'] );
     1163
     1164    if ( ! $compatible_wp && ! $compatible_php ) {
     1165        return new WP_Error(
     1166            'plugin_wp_php_incompatible',
     1167            sprintf(
     1168            /* translators: 1: WordPress version, 2: PHP version, 3: Plugin name, 4: Current WordPress version 5: Current PHP version. */
     1169                _x( 'Current WordPress and PHP versions do not meet minimum requirements of %1$s and %2$s for %3$s.
     1170                Your current versions of WordPress and PHP are %4$s and %5$s respectively.', 'plugin' ),
     1171                $requirements['requires'],
     1172                $requirements['requires_php'],
     1173                $plugin_headers['Name'],
     1174                get_bloginfo('version'),
     1175                phpversion()
     1176            ) . $php_update_message
     1177        );
     1178    } elseif ( ! $compatible_php ) {
     1179        return new WP_Error(
     1180            'plugin_php_incompatible',
     1181            sprintf(
     1182            /* translators: 1: PHP version, 2: Current PHP Version, 3: Plugin name. */
     1183                _x( 'Your current PHP version is %2$s. The current PHP version does not meet minimum requirements of %1$s for 3$s.', 'plugin' ),
     1184                $requirements['requires_php'],
     1185                phpversion(),
     1186                $plugin_headers['Name']
     1187            ) . $php_update_message
     1188        );
     1189    } elseif ( ! $compatible_wp ) {
     1190        return new WP_Error(
     1191            'plugin_wp_incompatible',
     1192            sprintf(
     1193            /* translators: 1: WordPress version, 2: Current WordPress version, 3: Plugin name. */
     1194                _x( 'Your current WordPress version is: %2$s. The current WordPress version does not meet minimum requirements of %1$s for %3$s.', 'plugin' ),
     1195                $requirements['requires'],
     1196                get_bloginfo('version'),
     1197                $plugin_headers['Name']
     1198            ) . $php_update_message
     1199        );
     1200    }
     1201
     1202    return true;
    11811203}
    11821204
    11831205/**
    function validate_plugin_requirements( $plugin ) { 
    11891211 * @return bool Whether plugin can be uninstalled.
    11901212 */
    11911213function is_uninstallable_plugin( $plugin ) {
    1192         $file = plugin_basename( $plugin );
     1214    $file = plugin_basename( $plugin );
    11931215
    1194         $uninstallable_plugins = (array) get_option( 'uninstall_plugins' );
    1195         if ( isset( $uninstallable_plugins[ $file ] ) || file_exists( WP_PLUGIN_DIR . '/' . dirname( $file ) . '/uninstall.php' ) ) {
    1196                 return true;
    1197         }
     1216    $uninstallable_plugins = (array) get_option( 'uninstall_plugins' );
     1217    if ( isset( $uninstallable_plugins[ $file ] ) || file_exists( WP_PLUGIN_DIR . '/' . dirname( $file ) . '/uninstall.php' ) ) {
     1218        return true;
     1219    }
    11981220
    1199         return false;
     1221    return false;
    12001222}
    12011223
    12021224/**
    function is_uninstallable_plugin( $plugin ) { 
    12101232 * @return true True if a plugin's uninstall.php file has been found and included.
    12111233 */
    12121234function uninstall_plugin( $plugin ) {
    1213         $file = plugin_basename( $plugin );
    1214 
    1215         $uninstallable_plugins = (array) get_option( 'uninstall_plugins' );
    1216 
    1217         /**
    1218         * Fires in uninstall_plugin() immediately before the plugin is uninstalled.
    1219         *
    1220         * @since 4.5.0
    1221         *
    1222         * @param string $plugin                Path to the plugin file relative to the plugins directory.
    1223         * @param array  $uninstallable_plugins Uninstallable plugins.
    1224         */
    1225         do_action( 'pre_uninstall_plugin', $plugin, $uninstallable_plugins );
    1226 
    1227         if ( file_exists( WP_PLUGIN_DIR . '/' . dirname( $file ) . '/uninstall.php' ) ) {
    1228                 if ( isset( $uninstallable_plugins[ $file ] ) ) {
    1229                         unset( $uninstallable_plugins[ $file ] );
    1230                         update_option( 'uninstall_plugins', $uninstallable_plugins );
    1231                 }
    1232                 unset( $uninstallable_plugins );
    1233 
    1234                 define( 'WP_UNINSTALL_PLUGIN', $file );
    1235                 wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $file );
    1236                 include WP_PLUGIN_DIR . '/' . dirname( $file ) . '/uninstall.php';
    1237 
    1238                 return true;
    1239         }
    1240 
    1241         if ( isset( $uninstallable_plugins[ $file ] ) ) {
    1242                 $callable = $uninstallable_plugins[ $file ];
    1243                 unset( $uninstallable_plugins[ $file ] );
    1244                 update_option( 'uninstall_plugins', $uninstallable_plugins );
    1245                 unset( $uninstallable_plugins );
    1246 
    1247                 wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $file );
    1248                 include WP_PLUGIN_DIR . '/' . $file;
    1249 
    1250                 add_action( "uninstall_{$file}", $callable );
    1251 
    1252                 /**
    1253                 * Fires in uninstall_plugin() once the plugin has been uninstalled.
    1254                 *
    1255                 * The action concatenates the 'uninstall_' prefix with the basename of the
    1256                 * plugin passed to uninstall_plugin() to create a dynamically-named action.
    1257                 *
    1258                 * @since 2.7.0
    1259                 */
    1260                 do_action( "uninstall_{$file}" );
    1261         }
     1235    $file = plugin_basename( $plugin );
     1236
     1237    $uninstallable_plugins = (array) get_option( 'uninstall_plugins' );
     1238
     1239    /**
     1240    * Fires in uninstall_plugin() immediately before the plugin is uninstalled.
     1241    *
     1242    * @since 4.5.0
     1243    *
     1244    * @param string $plugin                Path to the plugin file relative to the plugins directory.
     1245    * @param array  $uninstallable_plugins Uninstallable plugins.
     1246    */
     1247    do_action( 'pre_uninstall_plugin', $plugin, $uninstallable_plugins );
     1248
     1249    if ( file_exists( WP_PLUGIN_DIR . '/' . dirname( $file ) . '/uninstall.php' ) ) {
     1250        if ( isset( $uninstallable_plugins[ $file ] ) ) {
     1251            unset( $uninstallable_plugins[ $file ] );
     1252            update_option( 'uninstall_plugins', $uninstallable_plugins );
     1253        }
     1254        unset( $uninstallable_plugins );
     1255
     1256        define( 'WP_UNINSTALL_PLUGIN', $file );
     1257        wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $file );
     1258        include WP_PLUGIN_DIR . '/' . dirname( $file ) . '/uninstall.php';
     1259
     1260        return true;
     1261    }
     1262
     1263    if ( isset( $uninstallable_plugins[ $file ] ) ) {
     1264        $callable = $uninstallable_plugins[ $file ];
     1265        unset( $uninstallable_plugins[ $file ] );
     1266        update_option( 'uninstall_plugins', $uninstallable_plugins );
     1267        unset( $uninstallable_plugins );
     1268
     1269        wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $file );
     1270        include WP_PLUGIN_DIR . '/' . $file;
     1271
     1272        add_action( "uninstall_{$file}", $callable );
     1273
     1274        /**
     1275        * Fires in uninstall_plugin() once the plugin has been uninstalled.
     1276        *
     1277        * The action concatenates the 'uninstall_' prefix with the basename of the
     1278        * plugin passed to uninstall_plugin() to create a dynamically-named action.
     1279        *
     1280        * @since 2.7.0
     1281        */
     1282        do_action( "uninstall_{$file}" );
     1283    }
    12621284}
    12631285
    12641286//
    function uninstall_plugin( $plugin ) { 
    12981320 * @return string The resulting page's hook_suffix.
    12991321 */
    13001322function add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $icon_url = '', $position = null ) {
    1301         global $menu, $admin_page_hooks, $_registered_pages, $_parent_pages;
     1323    global $menu, $admin_page_hooks, $_registered_pages, $_parent_pages;
    13021324
    1303         $menu_slug = plugin_basename( $menu_slug );
     1325    $menu_slug = plugin_basename( $menu_slug );
    13041326
    1305         $admin_page_hooks[ $menu_slug ] = sanitize_title( $menu_title );
     1327    $admin_page_hooks[ $menu_slug ] = sanitize_title( $menu_title );
    13061328
    1307         $hookname = get_plugin_page_hookname( $menu_slug, '' );
     1329    $hookname = get_plugin_page_hookname( $menu_slug, '' );
    13081330
    1309         if ( ! empty( $function ) && ! empty( $hookname ) && current_user_can( $capability ) ) {
    1310                 add_action( $hookname, $function );
    1311         }
     1331    if ( ! empty( $function ) && ! empty( $hookname ) && current_user_can( $capability ) ) {
     1332        add_action( $hookname, $function );
     1333    }
    13121334
    1313         if ( empty( $icon_url ) ) {
    1314                 $icon_url   = 'dashicons-admin-generic';
    1315                 $icon_class = 'menu-icon-generic ';
    1316         } else {
    1317                 $icon_url   = set_url_scheme( $icon_url );
    1318                 $icon_class = '';
    1319         }
     1335    if ( empty( $icon_url ) ) {
     1336        $icon_url   = 'dashicons-admin-generic';
     1337        $icon_class = 'menu-icon-generic ';
     1338    } else {
     1339        $icon_url   = set_url_scheme( $icon_url );
     1340        $icon_class = '';
     1341    }
    13201342
    1321         $new_menu = array( $menu_title, $capability, $menu_slug, $page_title, 'menu-top ' . $icon_class . $hookname, $hookname, $icon_url );
     1343    $new_menu = array( $menu_title, $capability, $menu_slug, $page_title, 'menu-top ' . $icon_class . $hookname, $hookname, $icon_url );
    13221344
    1323         if ( null === $position ) {
    1324                 $menu[] = $new_menu;
    1325         } elseif ( isset( $menu[ "$position" ] ) ) {
    1326                 $position            = $position + substr( base_convert( md5( $menu_slug . $menu_title ), 16, 10 ), -5 ) * 0.00001;
    1327                 $menu[ "$position" ] = $new_menu;
    1328         } else {
    1329                 $menu[ $position ] = $new_menu;
    1330         }
     1345    if ( null === $position ) {
     1346        $menu[] = $new_menu;
     1347    } elseif ( isset( $menu[ "$position" ] ) ) {
     1348        $position            = $position + substr( base_convert( md5( $menu_slug . $menu_title ), 16, 10 ), -5 ) * 0.00001;
     1349        $menu[ "$position" ] = $new_menu;
     1350    } else {
     1351        $menu[ $position ] = $new_menu;
     1352    }
    13311353
    1332         $_registered_pages[ $hookname ] = true;
     1354    $_registered_pages[ $hookname ] = true;
    13331355
    1334         // No parent as top level.
    1335         $_parent_pages[ $menu_slug ] = false;
     1356    // No parent as top level.
     1357    $_parent_pages[ $menu_slug ] = false;
    13361358
    1337         return $hookname;
     1359    return $hookname;
    13381360}
    13391361
    13401362/**
    function add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $func 
    13701392 * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required.
    13711393 */
    13721394function add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $function = '', $position = null ) {
    1373         global $submenu, $menu, $_wp_real_parent_file, $_wp_submenu_nopriv,
    1374                 $_registered_pages, $_parent_pages;
    1375 
    1376         $menu_slug   = plugin_basename( $menu_slug );
    1377         $parent_slug = plugin_basename( $parent_slug );
    1378 
    1379         if ( isset( $_wp_real_parent_file[ $parent_slug ] ) ) {
    1380                 $parent_slug = $_wp_real_parent_file[ $parent_slug ];
    1381         }
    1382 
    1383         if ( ! current_user_can( $capability ) ) {
    1384                 $_wp_submenu_nopriv[ $parent_slug ][ $menu_slug ] = true;
    1385                 return false;
    1386         }
    1387 
    1388         /*
    1389         * If the parent doesn't already have a submenu, add a link to the parent
    1390         * as the first item in the submenu. If the submenu file is the same as the
    1391         * parent file someone is trying to link back to the parent manually. In
    1392         * this case, don't automatically add a link back to avoid duplication.
    1393         */
    1394         if ( ! isset( $submenu[ $parent_slug ] ) && $menu_slug != $parent_slug ) {
    1395                 foreach ( (array) $menu as $parent_menu ) {
    1396                         if ( $parent_menu[2] == $parent_slug && current_user_can( $parent_menu[1] ) ) {
    1397                                 $submenu[ $parent_slug ][] = array_slice( $parent_menu, 0, 4 );
    1398                         }
    1399                 }
    1400         }
    1401 
    1402         $new_sub_menu = array( $menu_title, $capability, $menu_slug, $page_title );
    1403         if ( ! is_int( $position ) ) {
    1404                 if ( null !== $position ) {
    1405                         _doing_it_wrong(
    1406                                 __FUNCTION__,
    1407                                 sprintf(
    1408                                         /* translators: %s: add_submenu_page() */
    1409                                         __( 'The seventh parameter passed to %s should be an integer representing menu position.' ),
    1410                                         '<code>add_submenu_page()</code>'
    1411                                 ),
    1412                                 '5.3.0'
    1413                         );
    1414                 }
    1415 
    1416                 $submenu[ $parent_slug ][] = $new_sub_menu;
    1417         } else {
    1418                 // Append the submenu if the parent item is not present in the submenu,
    1419                 // or if position is equal or higher than the number of items in the array.
    1420                 if ( ! isset( $submenu[ $parent_slug ] ) || $position >= count( $submenu[ $parent_slug ] ) ) {
    1421                         $submenu[ $parent_slug ][] = $new_sub_menu;
    1422                 } else {
    1423                         // Test for a negative position.
    1424                         $position = max( $position, 0 );
    1425                         if ( 0 === $position ) {
    1426                                 // For negative or `0` positions, prepend the submenu.
    1427                                 array_unshift( $submenu[ $parent_slug ], $new_sub_menu );
    1428                         } else {
    1429                                 // Grab all of the items before the insertion point.
    1430                                 $before_items = array_slice( $submenu[ $parent_slug ], 0, $position, true );
    1431                                 // Grab all of the items after the insertion point.
    1432                                 $after_items = array_slice( $submenu[ $parent_slug ], $position, null, true );
    1433                                 // Add the new item.
    1434                                 $before_items[] = $new_sub_menu;
    1435                                 // Merge the items.
    1436                                 $submenu[ $parent_slug ] = array_merge( $before_items, $after_items );
    1437                         }
    1438                 }
    1439         }
    1440         // Sort the parent array.
    1441         ksort( $submenu[ $parent_slug ] );
    1442 
    1443         $hookname = get_plugin_page_hookname( $menu_slug, $parent_slug );
    1444         if ( ! empty( $function ) && ! empty( $hookname ) ) {
    1445                 add_action( $hookname, $function );
    1446         }
    1447 
    1448         $_registered_pages[ $hookname ] = true;
    1449 
    1450         /*
    1451         * Backward-compatibility for plugins using add_management_page().
    1452         * See wp-admin/admin.php for redirect from edit.php to tools.php.
    1453         */
    1454         if ( 'tools.php' === $parent_slug ) {
    1455                 $_registered_pages[ get_plugin_page_hookname( $menu_slug, 'edit.php' ) ] = true;
    1456         }
    1457 
    1458         // No parent as top level.
    1459         $_parent_pages[ $menu_slug ] = $parent_slug;
    1460 
    1461         return $hookname;
     1395    global $submenu, $menu, $_wp_real_parent_file, $_wp_submenu_nopriv,
     1396           $_registered_pages, $_parent_pages;
     1397
     1398    $menu_slug   = plugin_basename( $menu_slug );
     1399    $parent_slug = plugin_basename( $parent_slug );
     1400
     1401    if ( isset( $_wp_real_parent_file[ $parent_slug ] ) ) {
     1402        $parent_slug = $_wp_real_parent_file[ $parent_slug ];
     1403    }
     1404
     1405    if ( ! current_user_can( $capability ) ) {
     1406        $_wp_submenu_nopriv[ $parent_slug ][ $menu_slug ] = true;
     1407        return false;
     1408    }
     1409
     1410    /*
     1411    * If the parent doesn't already have a submenu, add a link to the parent
     1412    * as the first item in the submenu. If the submenu file is the same as the
     1413    * parent file someone is trying to link back to the parent manually. In
     1414    * this case, don't automatically add a link back to avoid duplication.
     1415    */
     1416    if ( ! isset( $submenu[ $parent_slug ] ) && $menu_slug != $parent_slug ) {
     1417        foreach ( (array) $menu as $parent_menu ) {
     1418            if ( $parent_menu[2] == $parent_slug && current_user_can( $parent_menu[1] ) ) {
     1419                $submenu[ $parent_slug ][] = array_slice( $parent_menu, 0, 4 );
     1420            }
     1421        }
     1422    }
     1423
     1424    $new_sub_menu = array( $menu_title, $capability, $menu_slug, $page_title );
     1425    if ( ! is_int( $position ) ) {
     1426        if ( null !== $position ) {
     1427            _doing_it_wrong(
     1428                __FUNCTION__,
     1429                sprintf(
     1430                /* translators: %s: add_submenu_page() */
     1431                    __( 'The seventh parameter passed to %s should be an integer representing menu position.' ),
     1432                    '<code>add_submenu_page()</code>'
     1433                ),
     1434                '5.3.0'
     1435            );
     1436        }
     1437
     1438        $submenu[ $parent_slug ][] = $new_sub_menu;
     1439    } else {
     1440        // Append the submenu if the parent item is not present in the submenu,
     1441        // or if position is equal or higher than the number of items in the array.
     1442        if ( ! isset( $submenu[ $parent_slug ] ) || $position >= count( $submenu[ $parent_slug ] ) ) {
     1443            $submenu[ $parent_slug ][] = $new_sub_menu;
     1444        } else {
     1445            // Test for a negative position.
     1446            $position = max( $position, 0 );
     1447            if ( 0 === $position ) {
     1448                // For negative or `0` positions, prepend the submenu.
     1449                array_unshift( $submenu[ $parent_slug ], $new_sub_menu );
     1450            } else {
     1451                // Grab all of the items before the insertion point.
     1452                $before_items = array_slice( $submenu[ $parent_slug ], 0, $position, true );
     1453                // Grab all of the items after the insertion point.
     1454                $after_items = array_slice( $submenu[ $parent_slug ], $position, null, true );
     1455                // Add the new item.
     1456                $before_items[] = $new_sub_menu;
     1457                // Merge the items.
     1458                $submenu[ $parent_slug ] = array_merge( $before_items, $after_items );
     1459            }
     1460        }
     1461    }
     1462    // Sort the parent array.
     1463    ksort( $submenu[ $parent_slug ] );
     1464
     1465    $hookname = get_plugin_page_hookname( $menu_slug, $parent_slug );
     1466    if ( ! empty( $function ) && ! empty( $hookname ) ) {
     1467        add_action( $hookname, $function );
     1468    }
     1469
     1470    $_registered_pages[ $hookname ] = true;
     1471
     1472    /*
     1473    * Backward-compatibility for plugins using add_management_page().
     1474    * See wp-admin/admin.php for redirect from edit.php to tools.php.
     1475    */
     1476    if ( 'tools.php' === $parent_slug ) {
     1477        $_registered_pages[ get_plugin_page_hookname( $menu_slug, 'edit.php' ) ] = true;
     1478    }
     1479
     1480    // No parent as top level.
     1481    $_parent_pages[ $menu_slug ] = $parent_slug;
     1482
     1483    return $hookname;
    14621484}
    14631485
    14641486/**
    function add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, 
    14821504 * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required.
    14831505 */
    14841506function add_management_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $position = null ) {
    1485         return add_submenu_page( 'tools.php', $page_title, $menu_title, $capability, $menu_slug, $function, $position );
     1507    return add_submenu_page( 'tools.php', $page_title, $menu_title, $capability, $menu_slug, $function, $position );
    14861508}
    14871509
    14881510/**
    function add_management_page( $page_title, $menu_title, $capability, $menu_slug, 
    15061528 * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required.
    15071529 */
    15081530function add_options_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $position = null ) {
    1509         return add_submenu_page( 'options-general.php', $page_title, $menu_title, $capability, $menu_slug, $function, $position );
     1531    return add_submenu_page( 'options-general.php', $page_title, $menu_title, $capability, $menu_slug, $function, $position );
    15101532}
    15111533
    15121534/**
    function add_options_page( $page_title, $menu_title, $capability, $menu_slug, $f 
    15301552 * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required.
    15311553 */
    15321554function add_theme_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $position = null ) {
    1533         return add_submenu_page( 'themes.php', $page_title, $menu_title, $capability, $menu_slug, $function, $position );
     1555    return add_submenu_page( 'themes.php', $page_title, $menu_title, $capability, $menu_slug, $function, $position );
    15341556}
    15351557
    15361558/**
    function add_theme_page( $page_title, $menu_title, $capability, $menu_slug, $fun 
    15541576 * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required.
    15551577 */
    15561578function add_plugins_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $position = null ) {
    1557         return add_submenu_page( 'plugins.php', $page_title, $menu_title, $capability, $menu_slug, $function, $position );
     1579    return add_submenu_page( 'plugins.php', $page_title, $menu_title, $capability, $menu_slug, $function, $position );
    15581580}
    15591581
    15601582/**
    function add_plugins_page( $page_title, $menu_title, $capability, $menu_slug, $f 
    15781600 * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required.
    15791601 */
    15801602function add_users_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $position = null ) {
    1581         if ( current_user_can( 'edit_users' ) ) {
    1582                 $parent = 'users.php';
    1583         } else {
    1584                 $parent = 'profile.php';
    1585         }
    1586         return add_submenu_page( $parent, $page_title, $menu_title, $capability, $menu_slug, $function, $position );
     1603    if ( current_user_can( 'edit_users' ) ) {
     1604        $parent = 'users.php';
     1605    } else {
     1606        $parent = 'profile.php';
     1607    }
     1608    return add_submenu_page( $parent, $page_title, $menu_title, $capability, $menu_slug, $function, $position );
    15871609}
    15881610
    15891611/**
    function add_users_page( $page_title, $menu_title, $capability, $menu_slug, $fun 
    16071629 * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required.
    16081630 */
    16091631function add_dashboard_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $position = null ) {
    1610         return add_submenu_page( 'index.php', $page_title, $menu_title, $capability, $menu_slug, $function, $position );
     1632    return add_submenu_page( 'index.php', $page_title, $menu_title, $capability, $menu_slug, $function, $position );
    16111633}
    16121634
    16131635/**
    function add_dashboard_page( $page_title, $menu_title, $capability, $menu_slug, 
    16311653 * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required.
    16321654 */
    16331655function add_posts_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $position = null ) {
    1634         return add_submenu_page( 'edit.php', $page_title, $menu_title, $capability, $menu_slug, $function, $position );
     1656    return add_submenu_page( 'edit.php', $page_title, $menu_title, $capability, $menu_slug, $function, $position );
    16351657}
    16361658
    16371659/**
    function add_posts_page( $page_title, $menu_title, $capability, $menu_slug, $fun 
    16551677 * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required.
    16561678 */
    16571679function add_media_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $position = null ) {
    1658         return add_submenu_page( 'upload.php', $page_title, $menu_title, $capability, $menu_slug, $function, $position );
     1680    return add_submenu_page( 'upload.php', $page_title, $menu_title, $capability, $menu_slug, $function, $position );
    16591681}
    16601682
    16611683/**
    function add_media_page( $page_title, $menu_title, $capability, $menu_slug, $fun 
    16791701 * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required.
    16801702 */
    16811703function add_links_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $position = null ) {
    1682         return add_submenu_page( 'link-manager.php', $page_title, $menu_title, $capability, $menu_slug, $function, $position );
     1704    return add_submenu_page( 'link-manager.php', $page_title, $menu_title, $capability, $menu_slug, $function, $position );
    16831705}
    16841706
    16851707/**
    function add_links_page( $page_title, $menu_title, $capability, $menu_slug, $fun 
    17031725 * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required.
    17041726 */
    17051727function add_pages_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $position = null ) {
    1706         return add_submenu_page( 'edit.php?post_type=page', $page_title, $menu_title, $capability, $menu_slug, $function, $position );
     1728    return add_submenu_page( 'edit.php?post_type=page', $page_title, $menu_title, $capability, $menu_slug, $function, $position );
    17071729}
    17081730
    17091731/**
    function add_pages_page( $page_title, $menu_title, $capability, $menu_slug, $fun 
    17271749 * @return string|false The resulting page's hook_suffix, or false if the user does not have the capability required.
    17281750 */
    17291751function add_comments_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $position = null ) {
    1730         return add_submenu_page( 'edit-comments.php', $page_title, $menu_title, $capability, $menu_slug, $function, $position );
     1752    return add_submenu_page( 'edit-comments.php', $page_title, $menu_title, $capability, $menu_slug, $function, $position );
    17311753}
    17321754
    17331755/**
    function add_comments_page( $page_title, $menu_title, $capability, $menu_slug, $ 
    17411763 * @return array|bool The removed menu on success, false if not found.
    17421764 */
    17431765function remove_menu_page( $menu_slug ) {
    1744         global $menu;
     1766    global $menu;
    17451767
    1746         foreach ( $menu as $i => $item ) {
    1747                 if ( $menu_slug == $item[2] ) {
    1748                         unset( $menu[ $i ] );
    1749                         return $item;
    1750                 }
    1751         }
     1768    foreach ( $menu as $i => $item ) {
     1769        if ( $menu_slug == $item[2] ) {
     1770            unset( $menu[ $i ] );
     1771            return $item;
     1772        }
     1773    }
    17521774
    1753         return false;
     1775    return false;
    17541776}
    17551777
    17561778/**
    function remove_menu_page( $menu_slug ) { 
    17651787 * @return array|bool The removed submenu on success, false if not found.
    17661788 */
    17671789function remove_submenu_page( $menu_slug, $submenu_slug ) {
    1768         global $submenu;
     1790    global $submenu;
    17691791
    1770         if ( ! isset( $submenu[ $menu_slug ] ) ) {
    1771                 return false;
    1772         }
     1792    if ( ! isset( $submenu[ $menu_slug ] ) ) {
     1793        return false;
     1794    }
    17731795
    1774         foreach ( $submenu[ $menu_slug ] as $i => $item ) {
    1775                 if ( $submenu_slug == $item[2] ) {
    1776                         unset( $submenu[ $menu_slug ][ $i ] );
    1777                         return $item;
    1778                 }
    1779         }
     1796    foreach ( $submenu[ $menu_slug ] as $i => $item ) {
     1797        if ( $submenu_slug == $item[2] ) {
     1798            unset( $submenu[ $menu_slug ][ $i ] );
     1799            return $item;
     1800        }
     1801    }
    17801802
    1781         return false;
     1803    return false;
    17821804}
    17831805
    17841806/**
    function remove_submenu_page( $menu_slug, $submenu_slug ) { 
    17951817 * @return string The menu page URL.
    17961818 */
    17971819function menu_page_url( $menu_slug, $echo = true ) {
    1798         global $_parent_pages;
    1799 
    1800         if ( isset( $_parent_pages[ $menu_slug ] ) ) {
    1801                 $parent_slug = $_parent_pages[ $menu_slug ];
    1802                 if ( $parent_slug && ! isset( $_parent_pages[ $parent_slug ] ) ) {
    1803                         $url = admin_url( add_query_arg( 'page', $menu_slug, $parent_slug ) );
    1804                 } else {
    1805                         $url = admin_url( 'admin.php?page=' . $menu_slug );
    1806                 }
    1807         } else {
    1808                 $url = '';
    1809         }
    1810 
    1811         $url = esc_url( $url );
    1812 
    1813         if ( $echo ) {
    1814                 echo $url;
    1815         }
    1816 
    1817         return $url;
     1820    global $_parent_pages;
     1821
     1822    if ( isset( $_parent_pages[ $menu_slug ] ) ) {
     1823        $parent_slug = $_parent_pages[ $menu_slug ];
     1824        if ( $parent_slug && ! isset( $_parent_pages[ $parent_slug ] ) ) {
     1825            $url = admin_url( add_query_arg( 'page', $menu_slug, $parent_slug ) );
     1826        } else {
     1827            $url = admin_url( 'admin.php?page=' . $menu_slug );
     1828        }
     1829    } else {
     1830        $url = '';
     1831    }
     1832
     1833    $url = esc_url( $url );
     1834
     1835    if ( $echo ) {
     1836        echo $url;
     1837    }
     1838
     1839    return $url;
    18181840}
    18191841
    18201842//
    function menu_page_url( $menu_slug, $echo = true ) { 
    18401862 * @return string The parent file of the current admin page.
    18411863 */
    18421864function get_admin_page_parent( $parent = '' ) {
    1843         global $parent_file, $menu, $submenu, $pagenow, $typenow,
    1844                 $plugin_page, $_wp_real_parent_file, $_wp_menu_nopriv, $_wp_submenu_nopriv;
    1845 
    1846         if ( ! empty( $parent ) && 'admin.php' !== $parent ) {
    1847                 if ( isset( $_wp_real_parent_file[ $parent ] ) ) {
    1848                         $parent = $_wp_real_parent_file[ $parent ];
    1849                 }
    1850                 return $parent;
    1851         }
    1852 
    1853         if ( 'admin.php' === $pagenow && isset( $plugin_page ) ) {
    1854                 foreach ( (array) $menu as $parent_menu ) {
    1855                         if ( $parent_menu[2] == $plugin_page ) {
    1856                                 $parent_file = $plugin_page;
    1857                                 if ( isset( $_wp_real_parent_file[ $parent_file ] ) ) {
    1858                                         $parent_file = $_wp_real_parent_file[ $parent_file ];
    1859                                 }
    1860                                 return $parent_file;
    1861                         }
    1862                 }
    1863                 if ( isset( $_wp_menu_nopriv[ $plugin_page ] ) ) {
    1864                         $parent_file = $plugin_page;
    1865                         if ( isset( $_wp_real_parent_file[ $parent_file ] ) ) {
    1866                                         $parent_file = $_wp_real_parent_file[ $parent_file ];
    1867                         }
    1868                         return $parent_file;
    1869                 }
    1870         }
    1871 
    1872         if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $pagenow ][ $plugin_page ] ) ) {
    1873                 $parent_file = $pagenow;
    1874                 if ( isset( $_wp_real_parent_file[ $parent_file ] ) ) {
    1875                         $parent_file = $_wp_real_parent_file[ $parent_file ];
    1876                 }
    1877                 return $parent_file;
    1878         }
    1879 
    1880         foreach ( array_keys( (array) $submenu ) as $parent ) {
    1881                 foreach ( $submenu[ $parent ] as $submenu_array ) {
    1882                         if ( isset( $_wp_real_parent_file[ $parent ] ) ) {
    1883                                 $parent = $_wp_real_parent_file[ $parent ];
    1884                         }
    1885                         if ( ! empty( $typenow ) && ( "$pagenow?post_type=$typenow" === $submenu_array[2] ) ) {
    1886                                 $parent_file = $parent;
    1887                                 return $parent;
    1888                         } elseif ( $submenu_array[2] == $pagenow && empty( $typenow ) && ( empty( $parent_file ) || false === strpos( $parent_file, '?' ) ) ) {
    1889                                 $parent_file = $parent;
    1890                                 return $parent;
    1891                         } elseif ( isset( $plugin_page ) && ( $plugin_page == $submenu_array[2] ) ) {
    1892                                 $parent_file = $parent;
    1893                                 return $parent;
    1894                         }
    1895                 }
    1896         }
    1897 
    1898         if ( empty( $parent_file ) ) {
    1899                 $parent_file = '';
    1900         }
    1901         return '';
     1865    global $parent_file, $menu, $submenu, $pagenow, $typenow,
     1866           $plugin_page, $_wp_real_parent_file, $_wp_menu_nopriv, $_wp_submenu_nopriv;
     1867
     1868    if ( ! empty( $parent ) && 'admin.php' !== $parent ) {
     1869        if ( isset( $_wp_real_parent_file[ $parent ] ) ) {
     1870            $parent = $_wp_real_parent_file[ $parent ];
     1871        }
     1872        return $parent;
     1873    }
     1874
     1875    if ( 'admin.php' === $pagenow && isset( $plugin_page ) ) {
     1876        foreach ( (array) $menu as $parent_menu ) {
     1877            if ( $parent_menu[2] == $plugin_page ) {
     1878                $parent_file = $plugin_page;
     1879                if ( isset( $_wp_real_parent_file[ $parent_file ] ) ) {
     1880                    $parent_file = $_wp_real_parent_file[ $parent_file ];
     1881                }
     1882                return $parent_file;
     1883            }
     1884        }
     1885        if ( isset( $_wp_menu_nopriv[ $plugin_page ] ) ) {
     1886            $parent_file = $plugin_page;
     1887            if ( isset( $_wp_real_parent_file[ $parent_file ] ) ) {
     1888                $parent_file = $_wp_real_parent_file[ $parent_file ];
     1889            }
     1890            return $parent_file;
     1891        }
     1892    }
     1893
     1894    if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $pagenow ][ $plugin_page ] ) ) {
     1895        $parent_file = $pagenow;
     1896        if ( isset( $_wp_real_parent_file[ $parent_file ] ) ) {
     1897            $parent_file = $_wp_real_parent_file[ $parent_file ];
     1898        }
     1899        return $parent_file;
     1900    }
     1901
     1902    foreach ( array_keys( (array) $submenu ) as $parent ) {
     1903        foreach ( $submenu[ $parent ] as $submenu_array ) {
     1904            if ( isset( $_wp_real_parent_file[ $parent ] ) ) {
     1905                $parent = $_wp_real_parent_file[ $parent ];
     1906            }
     1907            if ( ! empty( $typenow ) && ( "$pagenow?post_type=$typenow" === $submenu_array[2] ) ) {
     1908                $parent_file = $parent;
     1909                return $parent;
     1910            } elseif ( $submenu_array[2] == $pagenow && empty( $typenow ) && ( empty( $parent_file ) || false === strpos( $parent_file, '?' ) ) ) {
     1911                $parent_file = $parent;
     1912                return $parent;
     1913            } elseif ( isset( $plugin_page ) && ( $plugin_page == $submenu_array[2] ) ) {
     1914                $parent_file = $parent;
     1915                return $parent;
     1916            }
     1917        }
     1918    }
     1919
     1920    if ( empty( $parent_file ) ) {
     1921        $parent_file = '';
     1922    }
     1923    return '';
    19021924}
    19031925
    19041926/**
    function get_admin_page_parent( $parent = '' ) { 
    19161938 * @return string The title of the current admin page.
    19171939 */
    19181940function get_admin_page_title() {
    1919         global $title, $menu, $submenu, $pagenow, $plugin_page, $typenow;
    1920 
    1921         if ( ! empty( $title ) ) {
    1922                 return $title;
    1923         }
    1924 
    1925         $hook = get_plugin_page_hook( $plugin_page, $pagenow );
    1926 
    1927         $parent  = get_admin_page_parent();
    1928         $parent1 = $parent;
    1929 
    1930         if ( empty( $parent ) ) {
    1931                 foreach ( (array) $menu as $menu_array ) {
    1932                         if ( isset( $menu_array[3] ) ) {
    1933                                 if ( $menu_array[2] == $pagenow ) {
    1934                                         $title = $menu_array[3];
    1935                                         return $menu_array[3];
    1936                                 } elseif ( isset( $plugin_page ) && ( $plugin_page == $menu_array[2] ) && ( $hook == $menu_array[3] ) ) {
    1937                                         $title = $menu_array[3];
    1938                                         return $menu_array[3];
    1939                                 }
    1940                         } else {
    1941                                 $title = $menu_array[0];
    1942                                 return $title;
    1943                         }
    1944                 }
    1945         } else {
    1946                 foreach ( array_keys( $submenu ) as $parent ) {
    1947                         foreach ( $submenu[ $parent ] as $submenu_array ) {
    1948                                 if ( isset( $plugin_page ) &&
    1949                                         ( $plugin_page == $submenu_array[2] ) &&
    1950                                         (
    1951                                                 ( $parent == $pagenow ) ||
    1952                                                 ( $parent == $plugin_page ) ||
    1953                                                 ( $plugin_page == $hook ) ||
    1954                                                 ( 'admin.php' === $pagenow && $parent1 != $submenu_array[2] ) ||
    1955                                                 ( ! empty( $typenow ) && $parent == $pagenow . '?post_type=' . $typenow )
    1956                                         )
    1957                                         ) {
    1958                                                 $title = $submenu_array[3];
    1959                                                 return $submenu_array[3];
    1960                                 }
    1961 
    1962                                 if ( $submenu_array[2] != $pagenow || isset( $_GET['page'] ) ) { // Not the current page.
    1963                                         continue;
    1964                                 }
    1965 
    1966                                 if ( isset( $submenu_array[3] ) ) {
    1967                                         $title = $submenu_array[3];
    1968                                         return $submenu_array[3];
    1969                                 } else {
    1970                                         $title = $submenu_array[0];
    1971                                         return $title;
    1972                                 }
    1973                         }
    1974                 }
    1975                 if ( empty( $title ) ) {
    1976                         foreach ( $menu as $menu_array ) {
    1977                                 if ( isset( $plugin_page ) &&
    1978                                         ( $plugin_page == $menu_array[2] ) &&
    1979                                         ( 'admin.php' === $pagenow ) &&
    1980                                         ( $parent1 == $menu_array[2] ) ) {
    1981                                                 $title = $menu_array[3];
    1982                                                 return $menu_array[3];
    1983                                 }
    1984                         }
    1985                 }
    1986         }
    1987 
    1988         return $title;
     1941    global $title, $menu, $submenu, $pagenow, $plugin_page, $typenow;
     1942
     1943    if ( ! empty( $title ) ) {
     1944        return $title;
     1945    }
     1946
     1947    $hook = get_plugin_page_hook( $plugin_page, $pagenow );
     1948
     1949    $parent  = get_admin_page_parent();
     1950    $parent1 = $parent;
     1951
     1952    if ( empty( $parent ) ) {
     1953        foreach ( (array) $menu as $menu_array ) {
     1954            if ( isset( $menu_array[3] ) ) {
     1955                if ( $menu_array[2] == $pagenow ) {
     1956                    $title = $menu_array[3];
     1957                    return $menu_array[3];
     1958                } elseif ( isset( $plugin_page ) && ( $plugin_page == $menu_array[2] ) && ( $hook == $menu_array[3] ) ) {
     1959                    $title = $menu_array[3];
     1960                    return $menu_array[3];
     1961                }
     1962            } else {
     1963                $title = $menu_array[0];
     1964                return $title;
     1965            }
     1966        }
     1967    } else {
     1968        foreach ( array_keys( $submenu ) as $parent ) {
     1969            foreach ( $submenu[ $parent ] as $submenu_array ) {
     1970                if ( isset( $plugin_page ) &&
     1971                    ( $plugin_page == $submenu_array[2] ) &&
     1972                    (
     1973                        ( $parent == $pagenow ) ||
     1974                        ( $parent == $plugin_page ) ||
     1975                        ( $plugin_page == $hook ) ||
     1976                        ( 'admin.php' === $pagenow && $parent1 != $submenu_array[2] ) ||
     1977                        ( ! empty( $typenow ) && $parent == $pagenow . '?post_type=' . $typenow )
     1978                    )
     1979                ) {
     1980                    $title = $submenu_array[3];
     1981                    return $submenu_array[3];
     1982                }
     1983
     1984                if ( $submenu_array[2] != $pagenow || isset( $_GET['page'] ) ) { // Not the current page.
     1985                    continue;
     1986                }
     1987
     1988                if ( isset( $submenu_array[3] ) ) {
     1989                    $title = $submenu_array[3];
     1990                    return $submenu_array[3];
     1991                } else {
     1992                    $title = $submenu_array[0];
     1993                    return $title;
     1994                }
     1995            }
     1996        }
     1997        if ( empty( $title ) ) {
     1998            foreach ( $menu as $menu_array ) {
     1999                if ( isset( $plugin_page ) &&
     2000                    ( $plugin_page == $menu_array[2] ) &&
     2001                    ( 'admin.php' === $pagenow ) &&
     2002                    ( $parent1 == $menu_array[2] ) ) {
     2003                    $title = $menu_array[3];
     2004                    return $menu_array[3];
     2005                }
     2006            }
     2007        }
     2008    }
     2009
     2010    return $title;
    19892011}
    19902012
    19912013/**
    function get_admin_page_title() { 
    19992021 * @return string|null Hook attached to the plugin page, null otherwise.
    20002022 */
    20012023function get_plugin_page_hook( $plugin_page, $parent_page ) {
    2002         $hook = get_plugin_page_hookname( $plugin_page, $parent_page );
    2003         if ( has_action( $hook ) ) {
    2004                 return $hook;
    2005         } else {
    2006                 return null;
    2007         }
     2024    $hook = get_plugin_page_hookname( $plugin_page, $parent_page );
     2025    if ( has_action( $hook ) ) {
     2026        return $hook;
     2027    } else {
     2028        return null;
     2029    }
    20082030}
    20092031
    20102032/**
    function get_plugin_page_hook( $plugin_page, $parent_page ) { 
    20202042 * @return string Hook name for the plugin page.
    20212043 */
    20222044function get_plugin_page_hookname( $plugin_page, $parent_page ) {
    2023         global $admin_page_hooks;
     2045    global $admin_page_hooks;
    20242046
    2025         $parent = get_admin_page_parent( $parent_page );
     2047    $parent = get_admin_page_parent( $parent_page );
    20262048
    2027         $page_type = 'admin';
    2028         if ( empty( $parent_page ) || 'admin.php' === $parent_page || isset( $admin_page_hooks[ $plugin_page ] ) ) {
    2029                 if ( isset( $admin_page_hooks[ $plugin_page ] ) ) {
    2030                         $page_type = 'toplevel';
    2031                 } elseif ( isset( $admin_page_hooks[ $parent ] ) ) {
    2032                         $page_type = $admin_page_hooks[ $parent ];
    2033                 }
    2034         } elseif ( isset( $admin_page_hooks[ $parent ] ) ) {
    2035                 $page_type = $admin_page_hooks[ $parent ];
    2036         }
     2049    $page_type = 'admin';
     2050    if ( empty( $parent_page ) || 'admin.php' === $parent_page || isset( $admin_page_hooks[ $plugin_page ] ) ) {
     2051        if ( isset( $admin_page_hooks[ $plugin_page ] ) ) {
     2052            $page_type = 'toplevel';
     2053        } elseif ( isset( $admin_page_hooks[ $parent ] ) ) {
     2054            $page_type = $admin_page_hooks[ $parent ];
     2055        }
     2056    } elseif ( isset( $admin_page_hooks[ $parent ] ) ) {
     2057        $page_type = $admin_page_hooks[ $parent ];
     2058    }
    20372059
    2038         $plugin_name = preg_replace( '!\.php!', '', $plugin_page );
     2060    $plugin_name = preg_replace( '!\.php!', '', $plugin_page );
    20392061
    2040         return $page_type . '_page_' . $plugin_name;
     2062    return $page_type . '_page_' . $plugin_name;
    20412063}
    20422064
    20432065/**
    function get_plugin_page_hookname( $plugin_page, $parent_page ) { 
    20562078 * @return bool True if the current user can access the admin page, false otherwise.
    20572079 */
    20582080function user_can_access_admin_page() {
    2059         global $pagenow, $menu, $submenu, $_wp_menu_nopriv, $_wp_submenu_nopriv,
    2060                 $plugin_page, $_registered_pages;
    2061 
    2062         $parent = get_admin_page_parent();
    2063 
    2064         if ( ! isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $parent ][ $pagenow ] ) ) {
    2065                 return false;
    2066         }
    2067 
    2068         if ( isset( $plugin_page ) ) {
    2069                 if ( isset( $_wp_submenu_nopriv[ $parent ][ $plugin_page ] ) ) {
    2070                         return false;
    2071                 }
    2072 
    2073                 $hookname = get_plugin_page_hookname( $plugin_page, $parent );
    2074 
    2075                 if ( ! isset( $_registered_pages[ $hookname ] ) ) {
    2076                         return false;
    2077                 }
    2078         }
    2079 
    2080         if ( empty( $parent ) ) {
    2081                 if ( isset( $_wp_menu_nopriv[ $pagenow ] ) ) {
    2082                         return false;
    2083                 }
    2084                 if ( isset( $_wp_submenu_nopriv[ $pagenow ][ $pagenow ] ) ) {
    2085                         return false;
    2086                 }
    2087                 if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $pagenow ][ $plugin_page ] ) ) {
    2088                         return false;
    2089                 }
    2090                 if ( isset( $plugin_page ) && isset( $_wp_menu_nopriv[ $plugin_page ] ) ) {
    2091                         return false;
    2092                 }
    2093                 foreach ( array_keys( $_wp_submenu_nopriv ) as $key ) {
    2094                         if ( isset( $_wp_submenu_nopriv[ $key ][ $pagenow ] ) ) {
    2095                                 return false;
    2096                         }
    2097                         if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $key ][ $plugin_page ] ) ) {
    2098                                 return false;
    2099                         }
    2100                 }
    2101                 return true;
    2102         }
    2103 
    2104         if ( isset( $plugin_page ) && ( $plugin_page == $parent ) && isset( $_wp_menu_nopriv[ $plugin_page ] ) ) {
    2105                 return false;
    2106         }
    2107 
    2108         if ( isset( $submenu[ $parent ] ) ) {
    2109                 foreach ( $submenu[ $parent ] as $submenu_array ) {
    2110                         if ( isset( $plugin_page ) && ( $submenu_array[2] == $plugin_page ) ) {
    2111                                 if ( current_user_can( $submenu_array[1] ) ) {
    2112                                         return true;
    2113                                 } else {
    2114                                         return false;
    2115                                 }
    2116                         } elseif ( $submenu_array[2] == $pagenow ) {
    2117                                 if ( current_user_can( $submenu_array[1] ) ) {
    2118                                         return true;
    2119                                 } else {
    2120                                         return false;
    2121                                 }
    2122                         }
    2123                 }
    2124         }
    2125 
    2126         foreach ( $menu as $menu_array ) {
    2127                 if ( $menu_array[2] == $parent ) {
    2128                         if ( current_user_can( $menu_array[1] ) ) {
    2129                                 return true;
    2130                         } else {
    2131                                 return false;
    2132                         }
    2133                 }
    2134         }
    2135 
    2136         return true;
     2081    global $pagenow, $menu, $submenu, $_wp_menu_nopriv, $_wp_submenu_nopriv,
     2082           $plugin_page, $_registered_pages;
     2083
     2084    $parent = get_admin_page_parent();
     2085
     2086    if ( ! isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $parent ][ $pagenow ] ) ) {
     2087        return false;
     2088    }
     2089
     2090    if ( isset( $plugin_page ) ) {
     2091        if ( isset( $_wp_submenu_nopriv[ $parent ][ $plugin_page ] ) ) {
     2092            return false;
     2093        }
     2094
     2095        $hookname = get_plugin_page_hookname( $plugin_page, $parent );
     2096
     2097        if ( ! isset( $_registered_pages[ $hookname ] ) ) {
     2098            return false;
     2099        }
     2100    }
     2101
     2102    if ( empty( $parent ) ) {
     2103        if ( isset( $_wp_menu_nopriv[ $pagenow ] ) ) {
     2104            return false;
     2105        }
     2106        if ( isset( $_wp_submenu_nopriv[ $pagenow ][ $pagenow ] ) ) {
     2107            return false;
     2108        }
     2109        if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $pagenow ][ $plugin_page ] ) ) {
     2110            return false;
     2111        }
     2112        if ( isset( $plugin_page ) && isset( $_wp_menu_nopriv[ $plugin_page ] ) ) {
     2113            return false;
     2114        }
     2115        foreach ( array_keys( $_wp_submenu_nopriv ) as $key ) {
     2116            if ( isset( $_wp_submenu_nopriv[ $key ][ $pagenow ] ) ) {
     2117                return false;
     2118            }
     2119            if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $key ][ $plugin_page ] ) ) {
     2120                return false;
     2121            }
     2122        }
     2123        return true;
     2124    }
     2125
     2126    if ( isset( $plugin_page ) && ( $plugin_page == $parent ) && isset( $_wp_menu_nopriv[ $plugin_page ] ) ) {
     2127        return false;
     2128    }
     2129
     2130    if ( isset( $submenu[ $parent ] ) ) {
     2131        foreach ( $submenu[ $parent ] as $submenu_array ) {
     2132            if ( isset( $plugin_page ) && ( $submenu_array[2] == $plugin_page ) ) {
     2133                if ( current_user_can( $submenu_array[1] ) ) {
     2134                    return true;
     2135                } else {
     2136                    return false;
     2137                }
     2138            } elseif ( $submenu_array[2] == $pagenow ) {
     2139                if ( current_user_can( $submenu_array[1] ) ) {
     2140                    return true;
     2141                } else {
     2142                    return false;
     2143                }
     2144            }
     2145        }
     2146    }
     2147
     2148    foreach ( $menu as $menu_array ) {
     2149        if ( $menu_array[2] == $parent ) {
     2150            if ( current_user_can( $menu_array[1] ) ) {
     2151                return true;
     2152            } else {
     2153                return false;
     2154            }
     2155        }
     2156    }
     2157
     2158    return true;
    21372159}
    21382160
    21392161/* Allowed list functions */
    function user_can_access_admin_page() { 
    21512173 * @return array
    21522174 */
    21532175function option_update_filter( $options ) {
    2154         global $new_whitelist_options;
     2176    global $new_whitelist_options;
    21552177
    2156         if ( is_array( $new_whitelist_options ) ) {
    2157                 $options = add_option_allowed_list( $new_whitelist_options, $options );
    2158         }
     2178    if ( is_array( $new_whitelist_options ) ) {
     2179        $options = add_option_allowed_list( $new_whitelist_options, $options );
     2180    }
    21592181
    2160         return $options;
     2182    return $options;
    21612183}
    21622184
    21632185/**
    function option_update_filter( $options ) { 
    21722194 * @return array
    21732195 */
    21742196function add_option_allowed_list( $new_options, $options = '' ) {
    2175         if ( '' === $options ) {
    2176                 global $allowed_options;
    2177         } else {
    2178                 $allowed_options = $options;
    2179         }
    2180 
    2181         foreach ( $new_options as $page => $keys ) {
    2182                 foreach ( $keys as $key ) {
    2183                         if ( ! isset( $allowed_options[ $page ] ) || ! is_array( $allowed_options[ $page ] ) ) {
    2184                                 $allowed_options[ $page ]   = array();
    2185                                 $allowed_options[ $page ][] = $key;
    2186                         } else {
    2187                                 $pos = array_search( $key, $allowed_options[ $page ], true );
    2188                                 if ( false === $pos ) {
    2189                                         $allowed_options[ $page ][] = $key;
    2190                                 }
    2191                         }
    2192                 }
    2193         }
    2194 
    2195         return $allowed_options;
     2197    if ( '' === $options ) {
     2198        global $allowed_options;
     2199    } else {
     2200        $allowed_options = $options;
     2201    }
     2202
     2203    foreach ( $new_options as $page => $keys ) {
     2204        foreach ( $keys as $key ) {
     2205            if ( ! isset( $allowed_options[ $page ] ) || ! is_array( $allowed_options[ $page ] ) ) {
     2206                $allowed_options[ $page ]   = array();
     2207                $allowed_options[ $page ][] = $key;
     2208            } else {
     2209                $pos = array_search( $key, $allowed_options[ $page ], true );
     2210                if ( false === $pos ) {
     2211                    $allowed_options[ $page ][] = $key;
     2212                }
     2213            }
     2214        }
     2215    }
     2216
     2217    return $allowed_options;
    21962218}
    21972219
    21982220/**
    function add_option_allowed_list( $new_options, $options = '' ) { 
    22072229 * @return array
    22082230 */
    22092231function remove_option_allowed_list( $del_options, $options = '' ) {
    2210         if ( '' === $options ) {
    2211                 global $allowed_options;
    2212         } else {
    2213                 $allowed_options = $options;
    2214         }
    2215 
    2216         foreach ( $del_options as $page => $keys ) {
    2217                 foreach ( $keys as $key ) {
    2218                         if ( isset( $allowed_options[ $page ] ) && is_array( $allowed_options[ $page ] ) ) {
    2219                                 $pos = array_search( $key, $allowed_options[ $page ], true );
    2220                                 if ( false !== $pos ) {
    2221                                         unset( $allowed_options[ $page ][ $pos ] );
    2222                                 }
    2223                         }
    2224                 }
    2225         }
    2226 
    2227         return $allowed_options;
     2232    if ( '' === $options ) {
     2233        global $allowed_options;
     2234    } else {
     2235        $allowed_options = $options;
     2236    }
     2237
     2238    foreach ( $del_options as $page => $keys ) {
     2239        foreach ( $keys as $key ) {
     2240            if ( isset( $allowed_options[ $page ] ) && is_array( $allowed_options[ $page ] ) ) {
     2241                $pos = array_search( $key, $allowed_options[ $page ], true );
     2242                if ( false !== $pos ) {
     2243                    unset( $allowed_options[ $page ][ $pos ] );
     2244                }
     2245            }
     2246        }
     2247    }
     2248
     2249    return $allowed_options;
    22282250}
    22292251
    22302252/**
    function remove_option_allowed_list( $del_options, $options = '' ) { 
    22362258 *                             used in register_setting().
    22372259 */
    22382260function settings_fields( $option_group ) {
    2239         echo "<input type='hidden' name='option_page' value='" . esc_attr( $option_group ) . "' />";
    2240         echo '<input type="hidden" name="action" value="update" />';
    2241         wp_nonce_field( "$option_group-options" );
     2261    echo "<input type='hidden' name='option_page' value='" . esc_attr( $option_group ) . "' />";
     2262    echo '<input type="hidden" name="action" value="update" />';
     2263    wp_nonce_field( "$option_group-options" );
    22422264}
    22432265
    22442266/**
    function settings_fields( $option_group ) { 
    22492271 * @param bool $clear_update_cache Whether to clear the plugin updates cache. Default true.
    22502272 */
    22512273function wp_clean_plugins_cache( $clear_update_cache = true ) {
    2252         if ( $clear_update_cache ) {
    2253                 delete_site_transient( 'update_plugins' );
    2254         }
    2255         wp_cache_delete( 'plugins', 'plugins' );
     2274    if ( $clear_update_cache ) {
     2275        delete_site_transient( 'update_plugins' );
     2276    }
     2277    wp_cache_delete( 'plugins', 'plugins' );
    22562278}
    22572279
    22582280/**
    function wp_clean_plugins_cache( $clear_update_cache = true ) { 
    22642286 * @param string $plugin Path to the plugin file relative to the plugins directory.
    22652287 */
    22662288function plugin_sandbox_scrape( $plugin ) {
    2267         if ( ! defined( 'WP_SANDBOX_SCRAPING' ) ) {
    2268                 define( 'WP_SANDBOX_SCRAPING', true );
    2269         }
    2270         wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $plugin );
    2271         include WP_PLUGIN_DIR . '/' . $plugin;
     2289    if ( ! defined( 'WP_SANDBOX_SCRAPING' ) ) {
     2290        define( 'WP_SANDBOX_SCRAPING', true );
     2291    }
     2292    wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $plugin );
     2293    include WP_PLUGIN_DIR . '/' . $plugin;
    22722294}
    22732295
    22742296/**
    function plugin_sandbox_scrape( $plugin ) { 
    22982320 * @param string $policy_text The suggested content for inclusion in the policy.
    22992321 */
    23002322function wp_add_privacy_policy_content( $plugin_name, $policy_text ) {
    2301         if ( ! is_admin() ) {
    2302                 _doing_it_wrong(
    2303                         __FUNCTION__,
    2304                         sprintf(
    2305                                 /* translators: %s: admin_init */
    2306                                 __( 'The suggested privacy policy content should be added only in wp-admin by using the %s (or later) action.' ),
    2307                                 '<code>admin_init</code>'
    2308                         ),
    2309                         '4.9.7'
    2310                 );
    2311                 return;
    2312         } elseif ( ! doing_action( 'admin_init' ) && ! did_action( 'admin_init' ) ) {
    2313                 _doing_it_wrong(
    2314                         __FUNCTION__,
    2315                         sprintf(
    2316                                 /* translators: %s: admin_init */
    2317                                 __( 'The suggested privacy policy content should be added by using the %s (or later) action. Please see the inline documentation.' ),
    2318                                 '<code>admin_init</code>'
    2319                         ),
    2320                         '4.9.7'
    2321                 );
    2322                 return;
    2323         }
    2324 
    2325         if ( ! class_exists( 'WP_Privacy_Policy_Content' ) ) {
    2326                 require_once ABSPATH . 'wp-admin/includes/class-wp-privacy-policy-content.php';
    2327         }
    2328 
    2329         WP_Privacy_Policy_Content::add( $plugin_name, $policy_text );
     2323    if ( ! is_admin() ) {
     2324        _doing_it_wrong(
     2325            __FUNCTION__,
     2326            sprintf(
     2327            /* translators: %s: admin_init */
     2328                __( 'The suggested privacy policy content should be added only in wp-admin by using the %s (or later) action.' ),
     2329                '<code>admin_init</code>'
     2330            ),
     2331            '4.9.7'
     2332        );
     2333        return;
     2334    } elseif ( ! doing_action( 'admin_init' ) && ! did_action( 'admin_init' ) ) {
     2335        _doing_it_wrong(
     2336            __FUNCTION__,
     2337            sprintf(
     2338            /* translators: %s: admin_init */
     2339                __( 'The suggested privacy policy content should be added by using the %s (or later) action. Please see the inline documentation.' ),
     2340                '<code>admin_init</code>'
     2341            ),
     2342            '4.9.7'
     2343        );
     2344        return;
     2345    }
     2346
     2347    if ( ! class_exists( 'WP_Privacy_Policy_Content' ) ) {
     2348        require_once ABSPATH . 'wp-admin/includes/class-wp-privacy-policy-content.php';
     2349    }
     2350
     2351    WP_Privacy_Policy_Content::add( $plugin_name, $policy_text );
    23302352}
    23312353
    23322354/**
    function wp_add_privacy_policy_content( $plugin_name, $policy_text ) { 
    23432365 * @return bool True, if in the list of paused plugins. False, if not in the list.
    23442366 */
    23452367function is_plugin_paused( $plugin ) {
    2346         if ( ! isset( $GLOBALS['_paused_plugins'] ) ) {
    2347                 return false;
    2348         }
     2368    if ( ! isset( $GLOBALS['_paused_plugins'] ) ) {
     2369        return false;
     2370    }
    23492371
    2350         if ( ! is_plugin_active( $plugin ) ) {
    2351                 return false;
    2352         }
     2372    if ( ! is_plugin_active( $plugin ) ) {
     2373        return false;
     2374    }
    23532375
    2354         list( $plugin ) = explode( '/', $plugin );
     2376    list( $plugin ) = explode( '/', $plugin );
    23552377
    2356         return array_key_exists( $plugin, $GLOBALS['_paused_plugins'] );
     2378    return array_key_exists( $plugin, $GLOBALS['_paused_plugins'] );
    23572379}
    23582380
    23592381/**
    function is_plugin_paused( $plugin ) { 
    23662388 *                     or false if none was recorded.
    23672389 */
    23682390function wp_get_plugin_error( $plugin ) {
    2369         if ( ! isset( $GLOBALS['_paused_plugins'] ) ) {
    2370                 return false;
    2371         }
     2391    if ( ! isset( $GLOBALS['_paused_plugins'] ) ) {
     2392        return false;
     2393    }
    23722394
    2373         list( $plugin ) = explode( '/', $plugin );
     2395    list( $plugin ) = explode( '/', $plugin );
    23742396
    2375         if ( ! array_key_exists( $plugin, $GLOBALS['_paused_plugins'] ) ) {
    2376                 return false;
    2377         }
     2397    if ( ! array_key_exists( $plugin, $GLOBALS['_paused_plugins'] ) ) {
     2398        return false;
     2399    }
    23782400
    2379         return $GLOBALS['_paused_plugins'][ $plugin ];
     2401    return $GLOBALS['_paused_plugins'][ $plugin ];
    23802402}
    23812403
    23822404/**
    function wp_get_plugin_error( $plugin ) { 
    23972419 *                       `WP_Error` on failure.
    23982420 */
    23992421function resume_plugin( $plugin, $redirect = '' ) {
    2400         /*
    2401         * We'll override this later if the plugin could be resumed without
    2402         * creating a fatal error.
    2403         */
    2404         if ( ! empty( $redirect ) ) {
    2405                 wp_redirect(
    2406                         add_query_arg(
    2407                                 '_error_nonce',
    2408                                 wp_create_nonce( 'plugin-resume-error_' . $plugin ),
    2409                                 $redirect
    2410                         )
    2411                 );
    2412 
    2413                 // Load the plugin to test whether it throws a fatal error.
    2414                 ob_start();
    2415                 plugin_sandbox_scrape( $plugin );
    2416                 ob_clean();
    2417         }
    2418 
    2419         list( $extension ) = explode( '/', $plugin );
    2420 
    2421         $result = wp_paused_plugins()->delete( $extension );
    2422 
    2423         if ( ! $result ) {
    2424                 return new WP_Error(
    2425                         'could_not_resume_plugin',
    2426                         __( 'Could not resume the plugin.' )
    2427                 );
    2428         }
    2429 
    2430         return true;
     2422    /*
     2423    * We'll override this later if the plugin could be resumed without
     2424    * creating a fatal error.
     2425    */
     2426    if ( ! empty( $redirect ) ) {
     2427        wp_redirect(
     2428            add_query_arg(
     2429                '_error_nonce',
     2430                wp_create_nonce( 'plugin-resume-error_' . $plugin ),
     2431                $redirect
     2432            )
     2433        );
     2434
     2435        // Load the plugin to test whether it throws a fatal error.
     2436        ob_start();
     2437        plugin_sandbox_scrape( $plugin );
     2438        ob_clean();
     2439    }
     2440
     2441    list( $extension ) = explode( '/', $plugin );
     2442
     2443    $result = wp_paused_plugins()->delete( $extension );
     2444
     2445    if ( ! $result ) {
     2446        return new WP_Error(
     2447            'could_not_resume_plugin',
     2448            __( 'Could not resume the plugin.' )
     2449        );
     2450    }
     2451
     2452    return true;
    24312453}
    24322454
    24332455/**
    function resume_plugin( $plugin, $redirect = '' ) { 
    24362458 * @since 5.2.0
    24372459 */
    24382460function paused_plugins_notice() {
    2439         if ( 'plugins.php' === $GLOBALS['pagenow'] ) {
    2440                 return;
    2441         }
    2442 
    2443         if ( ! current_user_can( 'resume_plugins' ) ) {
    2444                 return;
    2445         }
    2446 
    2447         if ( ! isset( $GLOBALS['_paused_plugins'] ) || empty( $GLOBALS['_paused_plugins'] ) ) {
    2448                 return;
    2449         }
    2450 
    2451         printf(
    2452                 '<div class="notice notice-error"><p><strong>%s</strong><br>%s</p><p><a href="%s">%s</a></p></div>',
    2453                 __( 'One or more plugins failed to load properly.' ),
    2454                 __( 'You can find more details and make changes on the Plugins screen.' ),
    2455                 esc_url( admin_url( 'plugins.php?plugin_status=paused' ) ),
    2456                 __( 'Go to the Plugins screen' )
    2457         );
     2461    if ( 'plugins.php' === $GLOBALS['pagenow'] ) {
     2462        return;
     2463    }
     2464
     2465    if ( ! current_user_can( 'resume_plugins' ) ) {
     2466        return;
     2467    }
     2468
     2469    if ( ! isset( $GLOBALS['_paused_plugins'] ) || empty( $GLOBALS['_paused_plugins'] ) ) {
     2470        return;
     2471    }
     2472
     2473    printf(
     2474        '<div class="notice notice-error"><p><strong>%s</strong><br>%s</p><p><a href="%s">%s</a></p></div>',
     2475        __( 'One or more plugins failed to load properly.' ),
     2476        __( 'You can find more details and make changes on the Plugins screen.' ),
     2477        esc_url( admin_url( 'plugins.php?plugin_status=paused' ) ),
     2478        __( 'Go to the Plugins screen' )
     2479    );
    24582480}