angelovcom.net

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

plugins.php (29180B)


      1 <?php
      2 /**
      3  * Plugins administration panel.
      4  *
      5  * @package WordPress
      6  * @subpackage Administration
      7  */
      8 
      9 /** WordPress Administration Bootstrap */
     10 require_once __DIR__ . '/admin.php';
     11 
     12 if ( ! current_user_can( 'activate_plugins' ) ) {
     13 	wp_die( __( 'Sorry, you are not allowed to manage plugins for this site.' ) );
     14 }
     15 
     16 $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
     17 $pagenum       = $wp_list_table->get_pagenum();
     18 
     19 $action = $wp_list_table->current_action();
     20 
     21 $plugin = isset( $_REQUEST['plugin'] ) ? wp_unslash( $_REQUEST['plugin'] ) : '';
     22 $s      = isset( $_REQUEST['s'] ) ? urlencode( wp_unslash( $_REQUEST['s'] ) ) : '';
     23 
     24 // Clean up request URI from temporary args for screen options/paging uri's to work as expected.
     25 $query_args_to_remove = array(
     26 	'error',
     27 	'deleted',
     28 	'activate',
     29 	'activate-multi',
     30 	'deactivate',
     31 	'deactivate-multi',
     32 	'enabled-auto-update',
     33 	'disabled-auto-update',
     34 	'enabled-auto-update-multi',
     35 	'disabled-auto-update-multi',
     36 	'_error_nonce',
     37 );
     38 
     39 $_SERVER['REQUEST_URI'] = remove_query_arg( $query_args_to_remove, $_SERVER['REQUEST_URI'] );
     40 
     41 wp_enqueue_script( 'updates' );
     42 
     43 if ( $action ) {
     44 
     45 	switch ( $action ) {
     46 		case 'activate':
     47 			if ( ! current_user_can( 'activate_plugin', $plugin ) ) {
     48 				wp_die( __( 'Sorry, you are not allowed to activate this plugin.' ) );
     49 			}
     50 
     51 			if ( is_multisite() && ! is_network_admin() && is_network_only_plugin( $plugin ) ) {
     52 				wp_redirect( self_admin_url( "plugins.php?plugin_status=$status&paged=$page&s=$s" ) );
     53 				exit;
     54 			}
     55 
     56 			check_admin_referer( 'activate-plugin_' . $plugin );
     57 
     58 			$result = activate_plugin( $plugin, self_admin_url( 'plugins.php?error=true&plugin=' . urlencode( $plugin ) ), is_network_admin() );
     59 			if ( is_wp_error( $result ) ) {
     60 				if ( 'unexpected_output' === $result->get_error_code() ) {
     61 					$redirect = self_admin_url( 'plugins.php?error=true&charsout=' . strlen( $result->get_error_data() ) . '&plugin=' . urlencode( $plugin ) . "&plugin_status=$status&paged=$page&s=$s" );
     62 					wp_redirect( add_query_arg( '_error_nonce', wp_create_nonce( 'plugin-activation-error_' . $plugin ), $redirect ) );
     63 					exit;
     64 				} else {
     65 					wp_die( $result );
     66 				}
     67 			}
     68 
     69 			if ( ! is_network_admin() ) {
     70 				$recent = (array) get_option( 'recently_activated' );
     71 				unset( $recent[ $plugin ] );
     72 				update_option( 'recently_activated', $recent );
     73 			} else {
     74 				$recent = (array) get_site_option( 'recently_activated' );
     75 				unset( $recent[ $plugin ] );
     76 				update_site_option( 'recently_activated', $recent );
     77 			}
     78 
     79 			if ( isset( $_GET['from'] ) && 'import' === $_GET['from'] ) {
     80 				// Overrides the ?error=true one above and redirects to the Imports page, stripping the -importer suffix.
     81 				wp_redirect( self_admin_url( 'import.php?import=' . str_replace( '-importer', '', dirname( $plugin ) ) ) );
     82 			} elseif ( isset( $_GET['from'] ) && 'press-this' === $_GET['from'] ) {
     83 				wp_redirect( self_admin_url( 'press-this.php' ) );
     84 			} else {
     85 				// Overrides the ?error=true one above.
     86 				wp_redirect( self_admin_url( "plugins.php?activate=true&plugin_status=$status&paged=$page&s=$s" ) );
     87 			}
     88 			exit;
     89 
     90 		case 'activate-selected':
     91 			if ( ! current_user_can( 'activate_plugins' ) ) {
     92 				wp_die( __( 'Sorry, you are not allowed to activate plugins for this site.' ) );
     93 			}
     94 
     95 			check_admin_referer( 'bulk-plugins' );
     96 
     97 			$plugins = isset( $_POST['checked'] ) ? (array) wp_unslash( $_POST['checked'] ) : array();
     98 
     99 			if ( is_network_admin() ) {
    100 				foreach ( $plugins as $i => $plugin ) {
    101 					// Only activate plugins which are not already network activated.
    102 					if ( is_plugin_active_for_network( $plugin ) ) {
    103 						unset( $plugins[ $i ] );
    104 					}
    105 				}
    106 			} else {
    107 				foreach ( $plugins as $i => $plugin ) {
    108 					// Only activate plugins which are not already active and are not network-only when on Multisite.
    109 					if ( is_plugin_active( $plugin ) || ( is_multisite() && is_network_only_plugin( $plugin ) ) ) {
    110 						unset( $plugins[ $i ] );
    111 					}
    112 					// Only activate plugins which the user can activate.
    113 					if ( ! current_user_can( 'activate_plugin', $plugin ) ) {
    114 						unset( $plugins[ $i ] );
    115 					}
    116 				}
    117 			}
    118 
    119 			if ( empty( $plugins ) ) {
    120 				wp_redirect( self_admin_url( "plugins.php?plugin_status=$status&paged=$page&s=$s" ) );
    121 				exit;
    122 			}
    123 
    124 			activate_plugins( $plugins, self_admin_url( 'plugins.php?error=true' ), is_network_admin() );
    125 
    126 			if ( ! is_network_admin() ) {
    127 				$recent = (array) get_option( 'recently_activated' );
    128 			} else {
    129 				$recent = (array) get_site_option( 'recently_activated' );
    130 			}
    131 
    132 			foreach ( $plugins as $plugin ) {
    133 				unset( $recent[ $plugin ] );
    134 			}
    135 
    136 			if ( ! is_network_admin() ) {
    137 				update_option( 'recently_activated', $recent );
    138 			} else {
    139 				update_site_option( 'recently_activated', $recent );
    140 			}
    141 
    142 			wp_redirect( self_admin_url( "plugins.php?activate-multi=true&plugin_status=$status&paged=$page&s=$s" ) );
    143 			exit;
    144 
    145 		case 'update-selected':
    146 			check_admin_referer( 'bulk-plugins' );
    147 
    148 			if ( isset( $_GET['plugins'] ) ) {
    149 				$plugins = explode( ',', wp_unslash( $_GET['plugins'] ) );
    150 			} elseif ( isset( $_POST['checked'] ) ) {
    151 				$plugins = (array) wp_unslash( $_POST['checked'] );
    152 			} else {
    153 				$plugins = array();
    154 			}
    155 
    156 			$title       = __( 'Update Plugins' );
    157 			$parent_file = 'plugins.php';
    158 
    159 			wp_enqueue_script( 'updates' );
    160 			require_once ABSPATH . 'wp-admin/admin-header.php';
    161 
    162 			echo '<div class="wrap">';
    163 			echo '<h1>' . esc_html( $title ) . '</h1>';
    164 
    165 			$url = self_admin_url( 'update.php?action=update-selected&amp;plugins=' . urlencode( implode( ',', $plugins ) ) );
    166 			$url = wp_nonce_url( $url, 'bulk-update-plugins' );
    167 
    168 			echo "<iframe src='$url' style='width: 100%; height:100%; min-height:850px;'></iframe>";
    169 			echo '</div>';
    170 			require_once ABSPATH . 'wp-admin/admin-footer.php';
    171 			exit;
    172 
    173 		case 'error_scrape':
    174 			if ( ! current_user_can( 'activate_plugin', $plugin ) ) {
    175 				wp_die( __( 'Sorry, you are not allowed to activate this plugin.' ) );
    176 			}
    177 
    178 			check_admin_referer( 'plugin-activation-error_' . $plugin );
    179 
    180 			$valid = validate_plugin( $plugin );
    181 			if ( is_wp_error( $valid ) ) {
    182 				wp_die( $valid );
    183 			}
    184 
    185 			if ( ! WP_DEBUG ) {
    186 				error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR );
    187 			}
    188 
    189 			ini_set( 'display_errors', true ); // Ensure that fatal errors are displayed.
    190 			// Go back to "sandbox" scope so we get the same errors as before.
    191 			plugin_sandbox_scrape( $plugin );
    192 			/** This action is documented in wp-admin/includes/plugin.php */
    193 			do_action( "activate_{$plugin}" );
    194 			exit;
    195 
    196 		case 'deactivate':
    197 			if ( ! current_user_can( 'deactivate_plugin', $plugin ) ) {
    198 				wp_die( __( 'Sorry, you are not allowed to deactivate this plugin.' ) );
    199 			}
    200 
    201 			check_admin_referer( 'deactivate-plugin_' . $plugin );
    202 
    203 			if ( ! is_network_admin() && is_plugin_active_for_network( $plugin ) ) {
    204 				wp_redirect( self_admin_url( "plugins.php?plugin_status=$status&paged=$page&s=$s" ) );
    205 				exit;
    206 			}
    207 
    208 			deactivate_plugins( $plugin, false, is_network_admin() );
    209 
    210 			if ( ! is_network_admin() ) {
    211 				update_option( 'recently_activated', array( $plugin => time() ) + (array) get_option( 'recently_activated' ) );
    212 			} else {
    213 				update_site_option( 'recently_activated', array( $plugin => time() ) + (array) get_site_option( 'recently_activated' ) );
    214 			}
    215 
    216 			if ( headers_sent() ) {
    217 				echo "<meta http-equiv='refresh' content='" . esc_attr( "0;url=plugins.php?deactivate=true&plugin_status=$status&paged=$page&s=$s" ) . "' />";
    218 			} else {
    219 				wp_redirect( self_admin_url( "plugins.php?deactivate=true&plugin_status=$status&paged=$page&s=$s" ) );
    220 			}
    221 			exit;
    222 
    223 		case 'deactivate-selected':
    224 			if ( ! current_user_can( 'deactivate_plugins' ) ) {
    225 				wp_die( __( 'Sorry, you are not allowed to deactivate plugins for this site.' ) );
    226 			}
    227 
    228 			check_admin_referer( 'bulk-plugins' );
    229 
    230 			$plugins = isset( $_POST['checked'] ) ? (array) wp_unslash( $_POST['checked'] ) : array();
    231 			// Do not deactivate plugins which are already deactivated.
    232 			if ( is_network_admin() ) {
    233 				$plugins = array_filter( $plugins, 'is_plugin_active_for_network' );
    234 			} else {
    235 				$plugins = array_filter( $plugins, 'is_plugin_active' );
    236 				$plugins = array_diff( $plugins, array_filter( $plugins, 'is_plugin_active_for_network' ) );
    237 
    238 				foreach ( $plugins as $i => $plugin ) {
    239 					// Only deactivate plugins which the user can deactivate.
    240 					if ( ! current_user_can( 'deactivate_plugin', $plugin ) ) {
    241 						unset( $plugins[ $i ] );
    242 					}
    243 				}
    244 			}
    245 			if ( empty( $plugins ) ) {
    246 				wp_redirect( self_admin_url( "plugins.php?plugin_status=$status&paged=$page&s=$s" ) );
    247 				exit;
    248 			}
    249 
    250 			deactivate_plugins( $plugins, false, is_network_admin() );
    251 
    252 			$deactivated = array();
    253 			foreach ( $plugins as $plugin ) {
    254 				$deactivated[ $plugin ] = time();
    255 			}
    256 
    257 			if ( ! is_network_admin() ) {
    258 				update_option( 'recently_activated', $deactivated + (array) get_option( 'recently_activated' ) );
    259 			} else {
    260 				update_site_option( 'recently_activated', $deactivated + (array) get_site_option( 'recently_activated' ) );
    261 			}
    262 
    263 			wp_redirect( self_admin_url( "plugins.php?deactivate-multi=true&plugin_status=$status&paged=$page&s=$s" ) );
    264 			exit;
    265 
    266 		case 'delete-selected':
    267 			if ( ! current_user_can( 'delete_plugins' ) ) {
    268 				wp_die( __( 'Sorry, you are not allowed to delete plugins for this site.' ) );
    269 			}
    270 
    271 			check_admin_referer( 'bulk-plugins' );
    272 
    273 			// $_POST = from the plugin form; $_GET = from the FTP details screen.
    274 			$plugins = isset( $_REQUEST['checked'] ) ? (array) wp_unslash( $_REQUEST['checked'] ) : array();
    275 			if ( empty( $plugins ) ) {
    276 				wp_redirect( self_admin_url( "plugins.php?plugin_status=$status&paged=$page&s=$s" ) );
    277 				exit;
    278 			}
    279 
    280 			$plugins = array_filter( $plugins, 'is_plugin_inactive' ); // Do not allow to delete activated plugins.
    281 			if ( empty( $plugins ) ) {
    282 				wp_redirect( self_admin_url( "plugins.php?error=true&main=true&plugin_status=$status&paged=$page&s=$s" ) );
    283 				exit;
    284 			}
    285 
    286 			// Bail on all if any paths are invalid.
    287 			// validate_file() returns truthy for invalid files.
    288 			$invalid_plugin_files = array_filter( $plugins, 'validate_file' );
    289 			if ( $invalid_plugin_files ) {
    290 				wp_redirect( self_admin_url( "plugins.php?plugin_status=$status&paged=$page&s=$s" ) );
    291 				exit;
    292 			}
    293 
    294 			require ABSPATH . 'wp-admin/update.php';
    295 
    296 			$parent_file = 'plugins.php';
    297 
    298 			if ( ! isset( $_REQUEST['verify-delete'] ) ) {
    299 				wp_enqueue_script( 'jquery' );
    300 				require_once ABSPATH . 'wp-admin/admin-header.php';
    301 
    302 				?>
    303 				<div class="wrap">
    304 				<?php
    305 
    306 				$plugin_info              = array();
    307 				$have_non_network_plugins = false;
    308 
    309 				foreach ( (array) $plugins as $plugin ) {
    310 					$plugin_slug = dirname( $plugin );
    311 
    312 					if ( '.' === $plugin_slug ) {
    313 						$data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
    314 						if ( $data ) {
    315 							$plugin_info[ $plugin ]                     = $data;
    316 							$plugin_info[ $plugin ]['is_uninstallable'] = is_uninstallable_plugin( $plugin );
    317 							if ( ! $plugin_info[ $plugin ]['Network'] ) {
    318 								$have_non_network_plugins = true;
    319 							}
    320 						}
    321 					} else {
    322 						// Get plugins list from that folder.
    323 						$folder_plugins = get_plugins( '/' . $plugin_slug );
    324 						if ( $folder_plugins ) {
    325 							foreach ( $folder_plugins as $plugin_file => $data ) {
    326 								$plugin_info[ $plugin_file ]                     = _get_plugin_data_markup_translate( $plugin_file, $data );
    327 								$plugin_info[ $plugin_file ]['is_uninstallable'] = is_uninstallable_plugin( $plugin );
    328 								if ( ! $plugin_info[ $plugin_file ]['Network'] ) {
    329 									$have_non_network_plugins = true;
    330 								}
    331 							}
    332 						}
    333 					}
    334 				}
    335 
    336 				$plugins_to_delete = count( $plugin_info );
    337 
    338 				?>
    339 				<?php if ( 1 === $plugins_to_delete ) : ?>
    340 					<h1><?php _e( 'Delete Plugin' ); ?></h1>
    341 					<?php if ( $have_non_network_plugins && is_network_admin() ) : ?>
    342 						<div class="error"><p><strong><?php _e( 'Caution:' ); ?></strong> <?php _e( 'This plugin may be active on other sites in the network.' ); ?></p></div>
    343 					<?php endif; ?>
    344 					<p><?php _e( 'You are about to remove the following plugin:' ); ?></p>
    345 				<?php else : ?>
    346 					<h1><?php _e( 'Delete Plugins' ); ?></h1>
    347 					<?php if ( $have_non_network_plugins && is_network_admin() ) : ?>
    348 						<div class="error"><p><strong><?php _e( 'Caution:' ); ?></strong> <?php _e( 'These plugins may be active on other sites in the network.' ); ?></p></div>
    349 					<?php endif; ?>
    350 					<p><?php _e( 'You are about to remove the following plugins:' ); ?></p>
    351 				<?php endif; ?>
    352 					<ul class="ul-disc">
    353 						<?php
    354 
    355 						$data_to_delete = false;
    356 
    357 						foreach ( $plugin_info as $plugin ) {
    358 							if ( $plugin['is_uninstallable'] ) {
    359 								/* translators: 1: Plugin name, 2: Plugin author. */
    360 								echo '<li>', sprintf( __( '%1$s by %2$s (will also <strong>delete its data</strong>)' ), '<strong>' . $plugin['Name'] . '</strong>', '<em>' . $plugin['AuthorName'] . '</em>' ), '</li>';
    361 								$data_to_delete = true;
    362 							} else {
    363 								/* translators: 1: Plugin name, 2: Plugin author. */
    364 								echo '<li>', sprintf( _x( '%1$s by %2$s', 'plugin' ), '<strong>' . $plugin['Name'] . '</strong>', '<em>' . $plugin['AuthorName'] ) . '</em>', '</li>';
    365 							}
    366 						}
    367 
    368 						?>
    369 					</ul>
    370 				<p>
    371 				<?php
    372 
    373 				if ( $data_to_delete ) {
    374 					_e( 'Are you sure you want to delete these files and data?' );
    375 				} else {
    376 					_e( 'Are you sure you want to delete these files?' );
    377 				}
    378 
    379 				?>
    380 				</p>
    381 				<form method="post" action="<?php echo esc_url( $_SERVER['REQUEST_URI'] ); ?>" style="display:inline;">
    382 					<input type="hidden" name="verify-delete" value="1" />
    383 					<input type="hidden" name="action" value="delete-selected" />
    384 					<?php
    385 
    386 					foreach ( (array) $plugins as $plugin ) {
    387 						echo '<input type="hidden" name="checked[]" value="' . esc_attr( $plugin ) . '" />';
    388 					}
    389 
    390 					?>
    391 					<?php wp_nonce_field( 'bulk-plugins' ); ?>
    392 					<?php submit_button( $data_to_delete ? __( 'Yes, delete these files and data' ) : __( 'Yes, delete these files' ), '', 'submit', false ); ?>
    393 				</form>
    394 				<?php
    395 
    396 				$referer = wp_get_referer();
    397 
    398 				?>
    399 				<form method="post" action="<?php echo $referer ? esc_url( $referer ) : ''; ?>" style="display:inline;">
    400 					<?php submit_button( __( 'No, return me to the plugin list' ), '', 'submit', false ); ?>
    401 				</form>
    402 				</div>
    403 				<?php
    404 
    405 				require_once ABSPATH . 'wp-admin/admin-footer.php';
    406 				exit;
    407 			} else {
    408 				$plugins_to_delete = count( $plugins );
    409 			} // End if verify-delete.
    410 
    411 			$delete_result = delete_plugins( $plugins );
    412 
    413 			// Store the result in a cache rather than a URL param due to object type & length.
    414 			set_transient( 'plugins_delete_result_' . $user_ID, $delete_result );
    415 			wp_redirect( self_admin_url( "plugins.php?deleted=$plugins_to_delete&plugin_status=$status&paged=$page&s=$s" ) );
    416 			exit;
    417 		case 'clear-recent-list':
    418 			if ( ! is_network_admin() ) {
    419 				update_option( 'recently_activated', array() );
    420 			} else {
    421 				update_site_option( 'recently_activated', array() );
    422 			}
    423 
    424 			break;
    425 		case 'resume':
    426 			if ( is_multisite() ) {
    427 				return;
    428 			}
    429 
    430 			if ( ! current_user_can( 'resume_plugin', $plugin ) ) {
    431 				wp_die( __( 'Sorry, you are not allowed to resume this plugin.' ) );
    432 			}
    433 
    434 			check_admin_referer( 'resume-plugin_' . $plugin );
    435 
    436 			$result = resume_plugin( $plugin, self_admin_url( "plugins.php?error=resuming&plugin_status=$status&paged=$page&s=$s" ) );
    437 
    438 			if ( is_wp_error( $result ) ) {
    439 				wp_die( $result );
    440 			}
    441 
    442 			wp_redirect( self_admin_url( "plugins.php?resume=true&plugin_status=$status&paged=$page&s=$s" ) );
    443 			exit;
    444 		case 'enable-auto-update':
    445 		case 'disable-auto-update':
    446 		case 'enable-auto-update-selected':
    447 		case 'disable-auto-update-selected':
    448 			if ( ! current_user_can( 'update_plugins' ) || ! wp_is_auto_update_enabled_for_type( 'plugin' ) ) {
    449 				wp_die( __( 'Sorry, you are not allowed to manage plugins automatic updates.' ) );
    450 			}
    451 
    452 			if ( is_multisite() && ! is_network_admin() ) {
    453 				wp_die( __( 'Please connect to your network admin to manage plugins automatic updates.' ) );
    454 			}
    455 
    456 			$redirect = self_admin_url( "plugins.php?plugin_status={$status}&paged={$page}&s={$s}" );
    457 
    458 			if ( 'enable-auto-update' === $action || 'disable-auto-update' === $action ) {
    459 				if ( empty( $plugin ) ) {
    460 					wp_redirect( $redirect );
    461 					exit;
    462 				}
    463 
    464 				check_admin_referer( 'updates' );
    465 			} else {
    466 				if ( empty( $_POST['checked'] ) ) {
    467 					wp_redirect( $redirect );
    468 					exit;
    469 				}
    470 
    471 				check_admin_referer( 'bulk-plugins' );
    472 			}
    473 
    474 			$auto_updates = (array) get_site_option( 'auto_update_plugins', array() );
    475 
    476 			if ( 'enable-auto-update' === $action ) {
    477 				$auto_updates[] = $plugin;
    478 				$auto_updates   = array_unique( $auto_updates );
    479 				$redirect       = add_query_arg( array( 'enabled-auto-update' => 'true' ), $redirect );
    480 			} elseif ( 'disable-auto-update' === $action ) {
    481 				$auto_updates = array_diff( $auto_updates, array( $plugin ) );
    482 				$redirect     = add_query_arg( array( 'disabled-auto-update' => 'true' ), $redirect );
    483 			} else {
    484 				$plugins = (array) wp_unslash( $_POST['checked'] );
    485 
    486 				if ( 'enable-auto-update-selected' === $action ) {
    487 					$new_auto_updates = array_merge( $auto_updates, $plugins );
    488 					$new_auto_updates = array_unique( $new_auto_updates );
    489 					$query_args       = array( 'enabled-auto-update-multi' => 'true' );
    490 				} else {
    491 					$new_auto_updates = array_diff( $auto_updates, $plugins );
    492 					$query_args       = array( 'disabled-auto-update-multi' => 'true' );
    493 				}
    494 
    495 				// Return early if all selected plugins already have auto-updates enabled or disabled.
    496 				// Must use non-strict comparison, so that array order is not treated as significant.
    497 				if ( $new_auto_updates == $auto_updates ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
    498 					wp_redirect( $redirect );
    499 					exit;
    500 				}
    501 
    502 				$auto_updates = $new_auto_updates;
    503 				$redirect     = add_query_arg( $query_args, $redirect );
    504 			}
    505 
    506 			/** This filter is documented in wp-admin/includes/class-wp-plugins-list-table.php */
    507 			$all_items = apply_filters( 'all_plugins', get_plugins() );
    508 
    509 			// Remove plugins that don't exist or have been deleted since the option was last updated.
    510 			$auto_updates = array_intersect( $auto_updates, array_keys( $all_items ) );
    511 
    512 			update_site_option( 'auto_update_plugins', $auto_updates );
    513 
    514 			wp_redirect( $redirect );
    515 			exit;
    516 		default:
    517 			if ( isset( $_POST['checked'] ) ) {
    518 				check_admin_referer( 'bulk-plugins' );
    519 
    520 				$screen   = get_current_screen()->id;
    521 				$sendback = wp_get_referer();
    522 				$plugins  = isset( $_POST['checked'] ) ? (array) wp_unslash( $_POST['checked'] ) : array();
    523 
    524 				/** This action is documented in wp-admin/edit.php */
    525 				$sendback = apply_filters( "handle_bulk_actions-{$screen}", $sendback, $action, $plugins ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
    526 				wp_safe_redirect( $sendback );
    527 				exit;
    528 			}
    529 			break;
    530 	}
    531 }
    532 
    533 $wp_list_table->prepare_items();
    534 
    535 wp_enqueue_script( 'plugin-install' );
    536 add_thickbox();
    537 
    538 add_screen_option( 'per_page', array( 'default' => 999 ) );
    539 
    540 get_current_screen()->add_help_tab(
    541 	array(
    542 		'id'      => 'overview',
    543 		'title'   => __( 'Overview' ),
    544 		'content' =>
    545 				'<p>' . __( 'Plugins extend and expand the functionality of WordPress. Once a plugin is installed, you may activate it or deactivate it here.' ) . '</p>' .
    546 				'<p>' . __( 'The search for installed plugins will search for terms in their name, description, or author.' ) . ' <span id="live-search-desc" class="hide-if-no-js">' . __( 'The search results will be updated as you type.' ) . '</span></p>' .
    547 				'<p>' . sprintf(
    548 					/* translators: %s: WordPress Plugin Directory URL. */
    549 					__( 'If you would like to see more plugins to choose from, click on the &#8220;Add New&#8221; button and you will be able to browse or search for additional plugins from the <a href="%s">WordPress Plugin Directory</a>. Plugins in the WordPress Plugin Directory are designed and developed by third parties, and are compatible with the license WordPress uses. Oh, and they&#8217;re free!' ),
    550 					__( 'https://wordpress.org/plugins/' )
    551 				) . '</p>',
    552 	)
    553 );
    554 get_current_screen()->add_help_tab(
    555 	array(
    556 		'id'      => 'compatibility-problems',
    557 		'title'   => __( 'Troubleshooting' ),
    558 		'content' =>
    559 				'<p>' . __( 'Most of the time, plugins play nicely with the core of WordPress and with other plugins. Sometimes, though, a plugin&#8217;s code will get in the way of another plugin, causing compatibility issues. If your site starts doing strange things, this may be the problem. Try deactivating all your plugins and re-activating them in various combinations until you isolate which one(s) caused the issue.' ) . '</p>' .
    560 				'<p>' . sprintf(
    561 					/* translators: %s: WP_PLUGIN_DIR constant value. */
    562 					__( 'If something goes wrong with a plugin and you can&#8217;t use WordPress, delete or rename that file in the %s directory and it will be automatically deactivated.' ),
    563 					'<code>' . WP_PLUGIN_DIR . '</code>'
    564 				) . '</p>',
    565 	)
    566 );
    567 
    568 $help_sidebar_autoupdates = '';
    569 
    570 if ( current_user_can( 'update_plugins' ) && wp_is_auto_update_enabled_for_type( 'plugin' ) ) {
    571 	get_current_screen()->add_help_tab(
    572 		array(
    573 			'id'      => 'plugins-themes-auto-updates',
    574 			'title'   => __( 'Auto-updates' ),
    575 			'content' =>
    576 					'<p>' . __( 'Auto-updates can be enabled or disabled for each individual plugin. Plugins with auto-updates enabled will display the estimated date of the next auto-update. Auto-updates depends on the WP-Cron task scheduling system.' ) . '</p>' .
    577 					'<p>' . __( 'Auto-updates are only available for plugins recognized by WordPress.org, or that include a compatible update system.' ) . '</p>' .
    578 					'<p>' . __( 'Please note: Third-party themes and plugins, or custom code, may override WordPress scheduling.' ) . '</p>',
    579 		)
    580 	);
    581 
    582 	$help_sidebar_autoupdates = '<p>' . __( '<a href="https://wordpress.org/support/article/plugins-themes-auto-updates/">Learn more: Auto-updates documentation</a>' ) . '</p>';
    583 }
    584 
    585 get_current_screen()->set_help_sidebar(
    586 	'<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
    587 	'<p>' . __( '<a href="https://wordpress.org/support/article/managing-plugins/">Documentation on Managing Plugins</a>' ) . '</p>' .
    588 	$help_sidebar_autoupdates .
    589 	'<p>' . __( '<a href="https://wordpress.org/support/">Support</a>' ) . '</p>'
    590 );
    591 
    592 get_current_screen()->set_screen_reader_content(
    593 	array(
    594 		'heading_views'      => __( 'Filter plugins list' ),
    595 		'heading_pagination' => __( 'Plugins list navigation' ),
    596 		'heading_list'       => __( 'Plugins list' ),
    597 	)
    598 );
    599 
    600 $title       = __( 'Plugins' );
    601 $parent_file = 'plugins.php';
    602 
    603 require_once ABSPATH . 'wp-admin/admin-header.php';
    604 
    605 $invalid = validate_active_plugins();
    606 if ( ! empty( $invalid ) ) {
    607 	foreach ( $invalid as $plugin_file => $error ) {
    608 		echo '<div id="message" class="error"><p>';
    609 		printf(
    610 			/* translators: 1: Plugin file, 2: Error message. */
    611 			__( 'The plugin %1$s has been deactivated due to an error: %2$s' ),
    612 			'<code>' . esc_html( $plugin_file ) . '</code>',
    613 			$error->get_error_message()
    614 		);
    615 		echo '</p></div>';
    616 	}
    617 }
    618 
    619 if ( isset( $_GET['error'] ) ) :
    620 
    621 	if ( isset( $_GET['main'] ) ) {
    622 		$errmsg = __( 'You cannot delete a plugin while it is active on the main site.' );
    623 	} elseif ( isset( $_GET['charsout'] ) ) {
    624 		$errmsg = sprintf(
    625 			/* translators: %d: Number of characters. */
    626 			_n(
    627 				'The plugin generated %d character of <strong>unexpected output</strong> during activation.',
    628 				'The plugin generated %d characters of <strong>unexpected output</strong> during activation.',
    629 				$_GET['charsout']
    630 			),
    631 			$_GET['charsout']
    632 		);
    633 		$errmsg .= ' ' . __( 'If you notice &#8220;headers already sent&#8221; messages, problems with syndication feeds or other issues, try deactivating or removing this plugin.' );
    634 	} elseif ( 'resuming' === $_GET['error'] ) {
    635 		$errmsg = __( 'Plugin could not be resumed because it triggered a <strong>fatal error</strong>.' );
    636 	} else {
    637 		$errmsg = __( 'Plugin could not be activated because it triggered a <strong>fatal error</strong>.' );
    638 	}
    639 
    640 	?>
    641 	<div id="message" class="error"><p><?php echo $errmsg; ?></p>
    642 	<?php
    643 
    644 	if ( ! isset( $_GET['main'] ) && ! isset( $_GET['charsout'] )
    645 		&& isset( $_GET['_error_nonce'] ) && wp_verify_nonce( $_GET['_error_nonce'], 'plugin-activation-error_' . $plugin )
    646 	) {
    647 		$iframe_url = add_query_arg(
    648 			array(
    649 				'action'   => 'error_scrape',
    650 				'plugin'   => urlencode( $plugin ),
    651 				'_wpnonce' => urlencode( $_GET['_error_nonce'] ),
    652 			),
    653 			admin_url( 'plugins.php' )
    654 		);
    655 
    656 		?>
    657 		<iframe style="border:0" width="100%" height="70px" src="<?php echo esc_url( $iframe_url ); ?>"></iframe>
    658 		<?php
    659 	}
    660 
    661 	?>
    662 	</div>
    663 	<?php
    664 elseif ( isset( $_GET['deleted'] ) ) :
    665 	$delete_result = get_transient( 'plugins_delete_result_' . $user_ID );
    666 	// Delete it once we're done.
    667 	delete_transient( 'plugins_delete_result_' . $user_ID );
    668 
    669 	if ( is_wp_error( $delete_result ) ) :
    670 		?>
    671 		<div id="message" class="error notice is-dismissible">
    672 			<p>
    673 				<?php
    674 				printf(
    675 					/* translators: %s: Error message. */
    676 					__( 'Plugin could not be deleted due to an error: %s' ),
    677 					$delete_result->get_error_message()
    678 				);
    679 				?>
    680 			</p>
    681 		</div>
    682 		<?php else : ?>
    683 		<div id="message" class="updated notice is-dismissible">
    684 			<p>
    685 				<?php
    686 				if ( 1 === (int) $_GET['deleted'] ) {
    687 					_e( 'The selected plugin has been deleted.' );
    688 				} else {
    689 					_e( 'The selected plugins have been deleted.' );
    690 				}
    691 				?>
    692 			</p>
    693 		</div>
    694 	<?php endif; ?>
    695 <?php elseif ( isset( $_GET['activate'] ) ) : ?>
    696 	<div id="message" class="updated notice is-dismissible"><p><?php _e( 'Plugin activated.' ); ?></p></div>
    697 <?php elseif ( isset( $_GET['activate-multi'] ) ) : ?>
    698 	<div id="message" class="updated notice is-dismissible"><p><?php _e( 'Selected plugins activated.' ); ?></p></div>
    699 <?php elseif ( isset( $_GET['deactivate'] ) ) : ?>
    700 	<div id="message" class="updated notice is-dismissible"><p><?php _e( 'Plugin deactivated.' ); ?></p></div>
    701 <?php elseif ( isset( $_GET['deactivate-multi'] ) ) : ?>
    702 	<div id="message" class="updated notice is-dismissible"><p><?php _e( 'Selected plugins deactivated.' ); ?></p></div>
    703 <?php elseif ( 'update-selected' === $action ) : ?>
    704 	<div id="message" class="updated notice is-dismissible"><p><?php _e( 'All selected plugins are up to date.' ); ?></p></div>
    705 <?php elseif ( isset( $_GET['resume'] ) ) : ?>
    706 	<div id="message" class="updated notice is-dismissible"><p><?php _e( 'Plugin resumed.' ); ?></p></div>
    707 <?php elseif ( isset( $_GET['enabled-auto-update'] ) ) : ?>
    708 	<div id="message" class="updated notice is-dismissible"><p><?php _e( 'Plugin will be auto-updated.' ); ?></p></div>
    709 <?php elseif ( isset( $_GET['disabled-auto-update'] ) ) : ?>
    710 	<div id="message" class="updated notice is-dismissible"><p><?php _e( 'Plugin will no longer be auto-updated.' ); ?></p></div>
    711 <?php elseif ( isset( $_GET['enabled-auto-update-multi'] ) ) : ?>
    712 	<div id="message" class="updated notice is-dismissible"><p><?php _e( 'Selected plugins will be auto-updated.' ); ?></p></div>
    713 <?php elseif ( isset( $_GET['disabled-auto-update-multi'] ) ) : ?>
    714 	<div id="message" class="updated notice is-dismissible"><p><?php _e( 'Selected plugins will no longer be auto-updated.' ); ?></p></div>
    715 <?php endif; ?>
    716 
    717 <div class="wrap">
    718 <h1 class="wp-heading-inline">
    719 <?php
    720 echo esc_html( $title );
    721 ?>
    722 </h1>
    723 
    724 <?php
    725 if ( ( ! is_multisite() || is_network_admin() ) && current_user_can( 'install_plugins' ) ) {
    726 	?>
    727 	<a href="<?php echo self_admin_url( 'plugin-install.php' ); ?>" class="page-title-action"><?php echo esc_html_x( 'Add New', 'plugin' ); ?></a>
    728 	<?php
    729 }
    730 
    731 if ( strlen( $s ) ) {
    732 	echo '<span class="subtitle">';
    733 	printf(
    734 		/* translators: %s: Search query. */
    735 		__( 'Search results for: %s' ),
    736 		'<strong>' . esc_html( urldecode( $s ) ) . '</strong>'
    737 	);
    738 	echo '</span>';
    739 }
    740 ?>
    741 
    742 <hr class="wp-header-end">
    743 
    744 <?php
    745 /**
    746  * Fires before the plugins list table is rendered.
    747  *
    748  * This hook also fires before the plugins list table is rendered in the Network Admin.
    749  *
    750  * Please note: The 'active' portion of the hook name does not refer to whether the current
    751  * view is for active plugins, but rather all plugins actively-installed.
    752  *
    753  * @since 3.0.0
    754  *
    755  * @param array[] $plugins_all An array of arrays containing information on all installed plugins.
    756  */
    757 do_action( 'pre_current_active_plugins', $plugins['all'] );
    758 ?>
    759 
    760 <?php $wp_list_table->views(); ?>
    761 
    762 <form class="search-form search-plugins" method="get">
    763 <?php $wp_list_table->search_box( __( 'Search Installed Plugins' ), 'plugin' ); ?>
    764 </form>
    765 
    766 <form method="post" id="bulk-action-form">
    767 
    768 <input type="hidden" name="plugin_status" value="<?php echo esc_attr( $status ); ?>" />
    769 <input type="hidden" name="paged" value="<?php echo esc_attr( $page ); ?>" />
    770 
    771 <?php $wp_list_table->display(); ?>
    772 </form>
    773 
    774 	<span class="spinner"></span>
    775 </div>
    776 
    777 <?php
    778 wp_print_request_filesystem_credentials_modal();
    779 wp_print_admin_notice_templates();
    780 wp_print_update_row_templates();
    781 
    782 require_once ABSPATH . 'wp-admin/admin-footer.php';