wp/wp-admin/includes/class-wp-plugin-install-list-table.php
changeset 9 177826044cd9
parent 7 cf61fcea0001
child 16 a86126ab1dd4
equal deleted inserted replaced
8:c7c34916027a 9:177826044cd9
    15  *
    15  *
    16  * @see WP_List_Table
    16  * @see WP_List_Table
    17  */
    17  */
    18 class WP_Plugin_Install_List_Table extends WP_List_Table {
    18 class WP_Plugin_Install_List_Table extends WP_List_Table {
    19 
    19 
    20 	public $order = 'ASC';
    20 	public $order   = 'ASC';
    21 	public $orderby = null;
    21 	public $orderby = null;
    22 	public $groups = array();
    22 	public $groups  = array();
    23 
    23 
    24 	private $error;
    24 	private $error;
    25 
    25 
    26 	/**
    26 	/**
    27 	 *
       
    28 	 * @return bool
    27 	 * @return bool
    29 	 */
    28 	 */
    30 	public function ajax_user_can() {
    29 	public function ajax_user_can() {
    31 		return current_user_can('install_plugins');
    30 		return current_user_can( 'install_plugins' );
    32 	}
    31 	}
    33 
    32 
    34 	/**
    33 	/**
    35 	 * Return the list of known plugins.
    34 	 * Return the list of known plugins.
    36 	 *
    35 	 *
    77 	protected function get_installed_plugin_slugs() {
    76 	protected function get_installed_plugin_slugs() {
    78 		return array_keys( $this->get_installed_plugins() );
    77 		return array_keys( $this->get_installed_plugins() );
    79 	}
    78 	}
    80 
    79 
    81 	/**
    80 	/**
    82 	 *
       
    83 	 * @global array  $tabs
    81 	 * @global array  $tabs
    84 	 * @global string $tab
    82 	 * @global string $tab
    85 	 * @global int    $paged
    83 	 * @global int    $paged
    86 	 * @global string $type
    84 	 * @global string $type
    87 	 * @global string $term
    85 	 * @global string $term
    93 
    91 
    94 		wp_reset_vars( array( 'tab' ) );
    92 		wp_reset_vars( array( 'tab' ) );
    95 
    93 
    96 		$paged = $this->get_pagenum();
    94 		$paged = $this->get_pagenum();
    97 
    95 
    98 		$per_page = 30;
    96 		$per_page = 36;
    99 
    97 
   100 		// These are the tabs which are shown on the page
    98 		// These are the tabs which are shown on the page
   101 		$tabs = array();
    99 		$tabs = array();
   102 
   100 
   103 		if ( 'search' === $tab ) {
   101 		if ( 'search' === $tab ) {
   121 		/**
   119 		/**
   122 		 * Filters the tabs shown on the Plugin Install screen.
   120 		 * Filters the tabs shown on the Plugin Install screen.
   123 		 *
   121 		 *
   124 		 * @since 2.7.0
   122 		 * @since 2.7.0
   125 		 *
   123 		 *
   126 		 * @param array $tabs The tabs shown on the Plugin Install screen. Defaults include 'featured', 'popular',
   124 		 * @param string[] $tabs The tabs shown on the Plugin Install screen. Defaults include 'featured', 'popular',
   127 		 *                    'recommended', 'favorites', and 'upload'.
   125 		 *                      'recommended', 'favorites', and 'upload'.
   128 		 */
   126 		 */
   129 		$tabs = apply_filters( 'install_plugins_tabs', $tabs );
   127 		$tabs = apply_filters( 'install_plugins_tabs', $tabs );
   130 
   128 
   131 		/**
   129 		/**
   132 		 * Filters tabs not associated with a menu item on the Plugin Install screen.
   130 		 * Filters tabs not associated with a menu item on the Plugin Install screen.
   133 		 *
   131 		 *
   134 		 * @since 2.7.0
   132 		 * @since 2.7.0
   135 		 *
   133 		 *
   136 		 * @param array $nonmenu_tabs The tabs that don't have a Menu item on the Plugin Install screen.
   134 		 * @param string[] $nonmenu_tabs The tabs that don't have a menu item on the Plugin Install screen.
   137 		 */
   135 		 */
   138 		$nonmenu_tabs = apply_filters( 'install_plugins_nonmenu_tabs', $nonmenu_tabs );
   136 		$nonmenu_tabs = apply_filters( 'install_plugins_nonmenu_tabs', $nonmenu_tabs );
   139 
   137 
   140 		// If a non-valid menu tab has been selected, And it's not a non-menu action.
   138 		// If a non-valid menu tab has been selected, And it's not a non-menu action.
   141 		if ( empty( $tab ) || ( !isset( $tabs[ $tab ] ) && !in_array( $tab, (array) $nonmenu_tabs ) ) )
   139 		if ( empty( $tab ) || ( ! isset( $tabs[ $tab ] ) && ! in_array( $tab, (array) $nonmenu_tabs ) ) ) {
   142 			$tab = key( $tabs );
   140 			$tab = key( $tabs );
       
   141 		}
   143 
   142 
   144 		$installed_plugins = $this->get_installed_plugins();
   143 		$installed_plugins = $this->get_installed_plugins();
   145 
   144 
   146 		$args = array(
   145 		$args = array(
   147 			'page' => $paged,
   146 			'page'     => $paged,
   148 			'per_page' => $per_page,
   147 			'per_page' => $per_page,
   149 			'fields' => array(
   148 			// Send the locale to the API so it can provide context-sensitive results.
   150 				'last_updated' => true,
   149 			'locale'   => get_user_locale(),
   151 				'icons' => true,
       
   152 				'active_installs' => true
       
   153 			),
       
   154 			// Send the locale and installed plugin slugs to the API so it can provide context-sensitive results.
       
   155 			'locale' => get_user_locale(),
       
   156 			'installed_plugins' => array_keys( $installed_plugins ),
       
   157 		);
   150 		);
   158 
   151 
   159 		switch ( $tab ) {
   152 		switch ( $tab ) {
   160 			case 'search':
   153 			case 'search':
   161 				$type = isset( $_REQUEST['type'] ) ? wp_unslash( $_REQUEST['type'] ) : 'term';
   154 				$type = isset( $_REQUEST['type'] ) ? wp_unslash( $_REQUEST['type'] ) : 'term';
   174 				}
   167 				}
   175 
   168 
   176 				break;
   169 				break;
   177 
   170 
   178 			case 'featured':
   171 			case 'featured':
   179 				$args['fields']['group'] = true;
       
   180 				$this->orderby = 'group';
       
   181 				// No break!
       
   182 			case 'popular':
   172 			case 'popular':
   183 			case 'new':
   173 			case 'new':
   184 			case 'beta':
   174 			case 'beta':
       
   175 				$args['browse'] = $tab;
       
   176 				break;
   185 			case 'recommended':
   177 			case 'recommended':
   186 				$args['browse'] = $tab;
   178 				$args['browse'] = $tab;
       
   179 				// Include the list of installed plugins so we can get relevant results.
       
   180 				$args['installed_plugins'] = array_keys( $installed_plugins );
   187 				break;
   181 				break;
   188 
   182 
   189 			case 'favorites':
   183 			case 'favorites':
   190 				$action = 'save_wporg_username_' . get_current_user_id();
   184 				$action = 'save_wporg_username_' . get_current_user_id();
   191 				if ( isset( $_GET['_wpnonce'] ) && wp_verify_nonce( wp_unslash( $_GET['_wpnonce'] ), $action ) ) {
   185 				if ( isset( $_GET['_wpnonce'] ) && wp_verify_nonce( wp_unslash( $_GET['_wpnonce'] ), $action ) ) {
   192 					$user = isset( $_GET['user'] ) ? wp_unslash( $_GET['user'] ) : get_user_option( 'wporg_favorites' );
   186 					$user = isset( $_GET['user'] ) ? wp_unslash( $_GET['user'] ) : get_user_option( 'wporg_favorites' );
   193 					update_user_meta( get_current_user_id(), 'wporg_favorites', $user );
   187 
       
   188 					// If the save url parameter is passed with a falsey value, don't save the favorite user.
       
   189 					if ( ! isset( $_GET['save'] ) || $_GET['save'] ) {
       
   190 						update_user_meta( get_current_user_id(), 'wporg_favorites', $user );
       
   191 					}
   194 				} else {
   192 				} else {
   195 					$user = get_user_option( 'wporg_favorites' );
   193 					$user = get_user_option( 'wporg_favorites' );
   196 				}
   194 				}
   197 				if ( $user )
   195 				if ( $user ) {
   198 					$args['user'] = $user;
   196 					$args['user'] = $user;
   199 				else
   197 				} else {
   200 					$args = false;
   198 					$args = false;
       
   199 				}
   201 
   200 
   202 				add_action( 'install_plugins_favorites', 'install_plugins_favorites_form', 9, 0 );
   201 				add_action( 'install_plugins_favorites', 'install_plugins_favorites_form', 9, 0 );
   203 				break;
   202 				break;
   204 
   203 
   205 			default:
   204 			default:
   217 		 *
   216 		 *
   218 		 * @param array|bool $args Plugin Install API arguments.
   217 		 * @param array|bool $args Plugin Install API arguments.
   219 		 */
   218 		 */
   220 		$args = apply_filters( "install_plugins_table_api_args_{$tab}", $args );
   219 		$args = apply_filters( "install_plugins_table_api_args_{$tab}", $args );
   221 
   220 
   222 		if ( !$args )
   221 		if ( ! $args ) {
   223 			return;
   222 			return;
       
   223 		}
   224 
   224 
   225 		$api = plugins_api( 'query_plugins', $args );
   225 		$api = plugins_api( 'query_plugins', $args );
   226 
   226 
   227 		if ( is_wp_error( $api ) ) {
   227 		if ( is_wp_error( $api ) ) {
   228 			$this->error = $api;
   228 			$this->error = $api;
   233 
   233 
   234 		if ( $this->orderby ) {
   234 		if ( $this->orderby ) {
   235 			uasort( $this->items, array( $this, 'order_callback' ) );
   235 			uasort( $this->items, array( $this, 'order_callback' ) );
   236 		}
   236 		}
   237 
   237 
   238 		$this->set_pagination_args( array(
   238 		$this->set_pagination_args(
   239 			'total_items' => $api->info['results'],
   239 			array(
   240 			'per_page' => $args['per_page'],
   240 				'total_items' => $api->info['results'],
   241 		) );
   241 				'per_page'    => $args['per_page'],
       
   242 			)
       
   243 		);
   242 
   244 
   243 		if ( isset( $api->info['groups'] ) ) {
   245 		if ( isset( $api->info['groups'] ) ) {
   244 			$this->groups = $api->info['groups'];
   246 			$this->groups = $api->info['groups'];
   245 		}
   247 		}
   246 
   248 
   255 
   257 
   256 			if ( $upgrade_plugins ) {
   258 			if ( $upgrade_plugins ) {
   257 				$js_plugins['upgrade'] = array_values( $upgrade_plugins );
   259 				$js_plugins['upgrade'] = array_values( $upgrade_plugins );
   258 			}
   260 			}
   259 
   261 
   260 			wp_localize_script( 'updates', '_wpUpdatesItemCounts', array(
   262 			wp_localize_script(
   261 				'plugins' => $js_plugins,
   263 				'updates',
   262 				'totals'  => wp_get_update_data(),
   264 				'_wpUpdatesItemCounts',
   263 			) );
   265 				array(
       
   266 					'plugins' => $js_plugins,
       
   267 					'totals'  => wp_get_update_data(),
       
   268 				)
       
   269 			);
   264 		}
   270 		}
   265 	}
   271 	}
   266 
   272 
   267 	/**
   273 	/**
   268 	 */
   274 	 */
   271 			<div class="inline error"><p><?php echo $this->error->get_error_message(); ?></p>
   277 			<div class="inline error"><p><?php echo $this->error->get_error_message(); ?></p>
   272 				<p class="hide-if-no-js"><button class="button try-again"><?php _e( 'Try Again' ); ?></button></p>
   278 				<p class="hide-if-no-js"><button class="button try-again"><?php _e( 'Try Again' ); ?></button></p>
   273 			</div>
   279 			</div>
   274 		<?php } else { ?>
   280 		<?php } else { ?>
   275 			<div class="no-plugin-results"><?php _e( 'No plugins found. Try a different search.' ); ?></div>
   281 			<div class="no-plugin-results"><?php _e( 'No plugins found. Try a different search.' ); ?></div>
   276 		<?php
   282 			<?php
   277 		}
   283 		}
   278 	}
   284 	}
   279 
   285 
   280 	/**
   286 	/**
   281 	 *
       
   282 	 * @global array $tabs
   287 	 * @global array $tabs
   283 	 * @global string $tab
   288 	 * @global string $tab
   284 	 *
   289 	 *
   285 	 * @return array
   290 	 * @return array
   286 	 */
   291 	 */
   287 	protected function get_views() {
   292 	protected function get_views() {
   288 		global $tabs, $tab;
   293 		global $tabs, $tab;
   289 
   294 
   290 		$display_tabs = array();
   295 		$display_tabs = array();
   291 		foreach ( (array) $tabs as $action => $text ) {
   296 		foreach ( (array) $tabs as $action => $text ) {
   292 			$current_link_attributes = ( $action === $tab ) ? ' class="current" aria-current="page"' : '';
   297 			$current_link_attributes                     = ( $action === $tab ) ? ' class="current" aria-current="page"' : '';
   293 			$href = self_admin_url('plugin-install.php?tab=' . $action);
   298 			$href                                        = self_admin_url( 'plugin-install.php?tab=' . $action );
   294 			$display_tabs['plugin-install-'.$action] = "<a href='$href'$current_link_attributes>$text</a>";
   299 			$display_tabs[ 'plugin-install-' . $action ] = "<a href='$href'$current_link_attributes>$text</a>";
   295 		}
   300 		}
   296 		// No longer a real tab.
   301 		// No longer a real tab.
   297 		unset( $display_tabs['plugin-install-upload'] );
   302 		unset( $display_tabs['plugin-install-upload'] );
   298 
   303 
   299 		return $display_tabs;
   304 		return $display_tabs;
   307 
   312 
   308 		/** This filter is documented in wp-admin/inclues/class-wp-list-table.php */
   313 		/** This filter is documented in wp-admin/inclues/class-wp-list-table.php */
   309 		$views = apply_filters( "views_{$this->screen->id}", $views );
   314 		$views = apply_filters( "views_{$this->screen->id}", $views );
   310 
   315 
   311 		$this->screen->render_screen_reader_content( 'heading_views' );
   316 		$this->screen->render_screen_reader_content( 'heading_views' );
   312 ?>
   317 		?>
   313 <div class="wp-filter">
   318 <div class="wp-filter">
   314 	<ul class="filter-links">
   319 	<ul class="filter-links">
   315 		<?php
   320 		<?php
   316 		if ( ! empty( $views ) ) {
   321 		if ( ! empty( $views ) ) {
   317 			foreach ( $views as $class => $view ) {
   322 			foreach ( $views as $class => $view ) {
   320 			echo implode( " </li>\n", $views ) . "</li>\n";
   325 			echo implode( " </li>\n", $views ) . "</li>\n";
   321 		}
   326 		}
   322 		?>
   327 		?>
   323 	</ul>
   328 	</ul>
   324 
   329 
   325 	<?php install_search_form(); ?>
   330 		<?php install_search_form(); ?>
   326 </div>
   331 </div>
   327 <?php
   332 		<?php
   328 	}
   333 	}
   329 
   334 
   330 	/**
   335 	/**
   331 	 * Override the parent display() so we can provide a different container.
   336 	 * Override the parent display() so we can provide a different container.
   332 	 */
   337 	 */
   339 			$data_attr = " data-wp-lists='list:$singular'";
   344 			$data_attr = " data-wp-lists='list:$singular'";
   340 		}
   345 		}
   341 
   346 
   342 		$this->display_tablenav( 'top' );
   347 		$this->display_tablenav( 'top' );
   343 
   348 
   344 ?>
   349 		?>
   345 <div class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>">
   350 <div class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>">
   346 <?php
   351 		<?php
   347 	$this->screen->render_screen_reader_content( 'heading_list' );
   352 		$this->screen->render_screen_reader_content( 'heading_list' );
   348 ?>
   353 		?>
   349 	<div id="the-list"<?php echo $data_attr; ?>>
   354 	<div id="the-list"<?php echo $data_attr; ?>>
   350 		<?php $this->display_rows_or_placeholder(); ?>
   355 		<?php $this->display_rows_or_placeholder(); ?>
   351 	</div>
   356 	</div>
   352 </div>
   357 </div>
   353 <?php
   358 		<?php
   354 		$this->display_tablenav( 'bottom' );
   359 		$this->display_tablenav( 'bottom' );
   355 	}
   360 	}
   356 
   361 
   357 	/**
   362 	/**
   358 	 * @global string $tab
   363 	 * @global string $tab
   364 			return;
   369 			return;
   365 		}
   370 		}
   366 
   371 
   367 		if ( 'top' === $which ) {
   372 		if ( 'top' === $which ) {
   368 			wp_referer_field();
   373 			wp_referer_field();
   369 		?>
   374 			?>
   370 			<div class="tablenav top">
   375 			<div class="tablenav top">
   371 				<div class="alignleft actions">
   376 				<div class="alignleft actions">
   372 					<?php
   377 					<?php
   373 					/**
   378 					/**
   374 					 * Fires before the Plugin Install table header pagination is displayed.
   379 					 * Fires before the Plugin Install table header pagination is displayed.
   375 					 *
   380 					 *
   376 					 * @since 2.7.0
   381 					 * @since 2.7.0
   377 					 */
   382 					 */
   378 					do_action( 'install_plugins_table_header' ); ?>
   383 					do_action( 'install_plugins_table_header' );
       
   384 					?>
   379 				</div>
   385 				</div>
   380 				<?php $this->pagination( $which ); ?>
   386 				<?php $this->pagination( $which ); ?>
   381 				<br class="clear" />
   387 				<br class="clear" />
   382 			</div>
   388 			</div>
   383 		<?php } else { ?>
   389 		<?php } else { ?>
   384 			<div class="tablenav bottom">
   390 			<div class="tablenav bottom">
   385 				<?php $this->pagination( $which ); ?>
   391 				<?php $this->pagination( $which ); ?>
   386 				<br class="clear" />
   392 				<br class="clear" />
   387 			</div>
   393 			</div>
   388 		<?php
   394 			<?php
   389 		}
   395 		}
   390 	}
   396 	}
   391 
   397 
   392 	/**
   398 	/**
   393 	 * @return array
   399 	 * @return array
   428 		}
   434 		}
   429 	}
   435 	}
   430 
   436 
   431 	public function display_rows() {
   437 	public function display_rows() {
   432 		$plugins_allowedtags = array(
   438 		$plugins_allowedtags = array(
   433 			'a' => array( 'href' => array(),'title' => array(), 'target' => array() ),
   439 			'a'       => array(
   434 			'abbr' => array( 'title' => array() ),'acronym' => array( 'title' => array() ),
   440 				'href'   => array(),
   435 			'code' => array(), 'pre' => array(), 'em' => array(),'strong' => array(),
   441 				'title'  => array(),
   436 			'ul' => array(), 'ol' => array(), 'li' => array(), 'p' => array(), 'br' => array()
   442 				'target' => array(),
       
   443 			),
       
   444 			'abbr'    => array( 'title' => array() ),
       
   445 			'acronym' => array( 'title' => array() ),
       
   446 			'code'    => array(),
       
   447 			'pre'     => array(),
       
   448 			'em'      => array(),
       
   449 			'strong'  => array(),
       
   450 			'ul'      => array(),
       
   451 			'ol'      => array(),
       
   452 			'li'      => array(),
       
   453 			'p'       => array(),
       
   454 			'br'      => array(),
   437 		);
   455 		);
   438 
   456 
   439 		$plugins_group_titles = array(
   457 		$plugins_group_titles = array(
   440 			'Performance' => _x( 'Performance', 'Plugin installer group title' ),
   458 			'Performance' => _x( 'Performance', 'Plugin installer group title' ),
   441 			'Social'      => _x( 'Social',      'Plugin installer group title' ),
   459 			'Social'      => _x( 'Social', 'Plugin installer group title' ),
   442 			'Tools'       => _x( 'Tools',       'Plugin installer group title' ),
   460 			'Tools'       => _x( 'Tools', 'Plugin installer group title' ),
   443 		);
   461 		);
   444 
   462 
   445 		$group = null;
   463 		$group = null;
   446 
   464 
   447 		foreach ( (array) $this->items as $plugin ) {
   465 		foreach ( (array) $this->items as $plugin ) {
   473 			}
   491 			}
   474 			$title = wp_kses( $plugin['name'], $plugins_allowedtags );
   492 			$title = wp_kses( $plugin['name'], $plugins_allowedtags );
   475 
   493 
   476 			// Remove any HTML from the description.
   494 			// Remove any HTML from the description.
   477 			$description = strip_tags( $plugin['short_description'] );
   495 			$description = strip_tags( $plugin['short_description'] );
   478 			$version = wp_kses( $plugin['version'], $plugins_allowedtags );
   496 			$version     = wp_kses( $plugin['version'], $plugins_allowedtags );
   479 
   497 
   480 			$name = strip_tags( $title . ' ' . $version );
   498 			$name = strip_tags( $title . ' ' . $version );
   481 
   499 
   482 			$author = wp_kses( $plugin['author'], $plugins_allowedtags );
   500 			$author = wp_kses( $plugin['author'], $plugins_allowedtags );
   483 			if ( ! empty( $author ) ) {
   501 			if ( ! empty( $author ) ) {
   484 				$author = ' <cite>' . sprintf( __( 'By %s' ), $author ) . '</cite>';
   502 				$author = ' <cite>' . sprintf( __( 'By %s' ), $author ) . '</cite>';
   485 			}
   503 			}
   486 
   504 
       
   505 			$requires_php = isset( $plugin['requires_php'] ) ? $plugin['requires_php'] : null;
       
   506 			$requires_wp  = isset( $plugin['requires'] ) ? $plugin['requires'] : null;
       
   507 
       
   508 			$compatible_php = is_php_version_compatible( $requires_php );
       
   509 			$compatible_wp  = is_wp_version_compatible( $requires_wp );
       
   510 			$tested_wp      = ( empty( $plugin['tested'] ) || version_compare( get_bloginfo( 'version' ), $plugin['tested'], '<=' ) );
       
   511 
   487 			$action_links = array();
   512 			$action_links = array();
   488 
   513 
   489 			if ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) {
   514 			if ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) {
   490 				$status = install_plugin_install_status( $plugin );
   515 				$status = install_plugin_install_status( $plugin );
   491 
   516 
   492 				switch ( $status['status'] ) {
   517 				switch ( $status['status'] ) {
   493 					case 'install':
   518 					case 'install':
   494 						if ( $status['url'] ) {
   519 						if ( $status['url'] ) {
   495 							/* translators: 1: Plugin name and version. */
   520 							if ( $compatible_php && $compatible_wp ) {
   496 							$action_links[] = '<a class="install-now button" data-slug="' . esc_attr( $plugin['slug'] ) . '" href="' . esc_url( $status['url'] ) . '" aria-label="' . esc_attr( sprintf( __( 'Install %s now' ), $name ) ) . '" data-name="' . esc_attr( $name ) . '">' . __( 'Install Now' ) . '</a>';
   521 								$action_links[] = sprintf(
       
   522 									'<a class="install-now button" data-slug="%s" href="%s" aria-label="%s" data-name="%s">%s</a>',
       
   523 									esc_attr( $plugin['slug'] ),
       
   524 									esc_url( $status['url'] ),
       
   525 									/* translators: %s: plugin name and version */
       
   526 									esc_attr( sprintf( __( 'Install %s now' ), $name ) ),
       
   527 									esc_attr( $name ),
       
   528 									__( 'Install Now' )
       
   529 								);
       
   530 							} else {
       
   531 								$action_links[] = sprintf(
       
   532 									'<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
       
   533 									_x( 'Cannot Install', 'plugin' )
       
   534 								);
       
   535 							}
   497 						}
   536 						}
   498 						break;
   537 						break;
   499 
   538 
   500 					case 'update_available':
   539 					case 'update_available':
   501 						if ( $status['url'] ) {
   540 						if ( $status['url'] ) {
   502 							/* translators: 1: Plugin name and version */
   541 							if ( $compatible_php && $compatible_wp ) {
   503 							$action_links[] = '<a class="update-now button aria-button-if-js" data-plugin="' . esc_attr( $status['file'] ) . '" data-slug="' . esc_attr( $plugin['slug'] ) . '" href="' . esc_url( $status['url'] ) . '" aria-label="' . esc_attr( sprintf( __( 'Update %s now' ), $name ) ) . '" data-name="' . esc_attr( $name ) . '">' . __( 'Update Now' ) . '</a>';
   542 								$action_links[] = sprintf(
       
   543 									'<a class="update-now button aria-button-if-js" data-plugin="%s" data-slug="%s" href="%s" aria-label="%s" data-name="%s">%s</a>',
       
   544 									esc_attr( $status['file'] ),
       
   545 									esc_attr( $plugin['slug'] ),
       
   546 									esc_url( $status['url'] ),
       
   547 									/* translators: %s: plugin name and version */
       
   548 									esc_attr( sprintf( __( 'Update %s now' ), $name ) ),
       
   549 									esc_attr( $name ),
       
   550 									__( 'Update Now' )
       
   551 								);
       
   552 							} else {
       
   553 								$action_links[] = sprintf(
       
   554 									'<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
       
   555 									_x( 'Cannot Update', 'plugin' )
       
   556 								);
       
   557 							}
   504 						}
   558 						}
   505 						break;
   559 						break;
   506 
   560 
   507 					case 'latest_installed':
   561 					case 'latest_installed':
   508 					case 'newer_installed':
   562 					case 'newer_installed':
   509 						if ( is_plugin_active( $status['file'] ) ) {
   563 						if ( is_plugin_active( $status['file'] ) ) {
   510 							$action_links[] = '<button type="button" class="button button-disabled" disabled="disabled">' . _x( 'Active', 'plugin' ) . '</button>';
   564 							$action_links[] = sprintf(
       
   565 								'<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
       
   566 								_x( 'Active', 'plugin' )
       
   567 							);
   511 						} elseif ( current_user_can( 'activate_plugin', $status['file'] ) ) {
   568 						} elseif ( current_user_can( 'activate_plugin', $status['file'] ) ) {
   512 							$button_text  = __( 'Activate' );
   569 							$button_text = __( 'Activate' );
   513 							/* translators: %s: Plugin name */
   570 							/* translators: %s: plugin name */
   514 							$button_label = _x( 'Activate %s', 'plugin' );
   571 							$button_label = _x( 'Activate %s', 'plugin' );
   515 							$activate_url = add_query_arg( array(
   572 							$activate_url = add_query_arg(
   516 								'_wpnonce'    => wp_create_nonce( 'activate-plugin_' . $status['file'] ),
   573 								array(
   517 								'action'      => 'activate',
   574 									'_wpnonce' => wp_create_nonce( 'activate-plugin_' . $status['file'] ),
   518 								'plugin'      => $status['file'],
   575 									'action'   => 'activate',
   519 							), network_admin_url( 'plugins.php' ) );
   576 									'plugin'   => $status['file'],
       
   577 								),
       
   578 								network_admin_url( 'plugins.php' )
       
   579 							);
   520 
   580 
   521 							if ( is_network_admin() ) {
   581 							if ( is_network_admin() ) {
   522 								$button_text  = __( 'Network Activate' );
   582 								$button_text = __( 'Network Activate' );
   523 								/* translators: %s: Plugin name */
   583 								/* translators: %s: plugin name */
   524 								$button_label = _x( 'Network Activate %s', 'plugin' );
   584 								$button_label = _x( 'Network Activate %s', 'plugin' );
   525 								$activate_url = add_query_arg( array( 'networkwide' => 1 ), $activate_url );
   585 								$activate_url = add_query_arg( array( 'networkwide' => 1 ), $activate_url );
   526 							}
   586 							}
   527 
   587 
   528 							$action_links[] = sprintf(
   588 							$action_links[] = sprintf(
   530 								esc_url( $activate_url ),
   590 								esc_url( $activate_url ),
   531 								esc_attr( sprintf( $button_label, $plugin['name'] ) ),
   591 								esc_attr( sprintf( $button_label, $plugin['name'] ) ),
   532 								$button_text
   592 								$button_text
   533 							);
   593 							);
   534 						} else {
   594 						} else {
   535 							$action_links[] = '<button type="button" class="button button-disabled" disabled="disabled">' . _x( 'Installed', 'plugin' ) . '</button>';
   595 							$action_links[] = sprintf(
       
   596 								'<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
       
   597 								_x( 'Installed', 'plugin' )
       
   598 							);
   536 						}
   599 						}
   537 						break;
   600 						break;
   538 				}
   601 				}
   539 			}
   602 			}
   540 
   603 
   541 			$details_link   = self_admin_url( 'plugin-install.php?tab=plugin-information&amp;plugin=' . $plugin['slug'] .
   604 			$details_link = self_admin_url(
   542 								'&amp;TB_iframe=true&amp;width=600&amp;height=550' );
   605 				'plugin-install.php?tab=plugin-information&amp;plugin=' . $plugin['slug'] .
   543 
   606 				'&amp;TB_iframe=true&amp;width=600&amp;height=550'
   544 			/* translators: 1: Plugin name and version. */
   607 			);
   545 			$action_links[] = '<a href="' . esc_url( $details_link ) . '" class="thickbox open-plugin-details-modal" aria-label="' . esc_attr( sprintf( __( 'More information about %s' ), $name ) ) . '" data-title="' . esc_attr( $name ) . '">' . __( 'More Details' ) . '</a>';
   608 
   546 
   609 			$action_links[] = sprintf(
   547 			if ( !empty( $plugin['icons']['svg'] ) ) {
   610 				'<a href="%s" class="thickbox open-plugin-details-modal" aria-label="%s" data-title="%s">%s</a>',
       
   611 				esc_url( $details_link ),
       
   612 				/* translators: %s: plugin name and version */
       
   613 				esc_attr( sprintf( __( 'More information about %s' ), $name ) ),
       
   614 				esc_attr( $name ),
       
   615 				__( 'More Details' )
       
   616 			);
       
   617 
       
   618 			if ( ! empty( $plugin['icons']['svg'] ) ) {
   548 				$plugin_icon_url = $plugin['icons']['svg'];
   619 				$plugin_icon_url = $plugin['icons']['svg'];
   549 			} elseif ( !empty( $plugin['icons']['2x'] ) ) {
   620 			} elseif ( ! empty( $plugin['icons']['2x'] ) ) {
   550 				$plugin_icon_url = $plugin['icons']['2x'];
   621 				$plugin_icon_url = $plugin['icons']['2x'];
   551 			} elseif ( !empty( $plugin['icons']['1x'] ) ) {
   622 			} elseif ( ! empty( $plugin['icons']['1x'] ) ) {
   552 				$plugin_icon_url = $plugin['icons']['1x'];
   623 				$plugin_icon_url = $plugin['icons']['1x'];
   553 			} else {
   624 			} else {
   554 				$plugin_icon_url = $plugin['icons']['default'];
   625 				$plugin_icon_url = $plugin['icons']['default'];
   555 			}
   626 			}
   556 
   627 
   557 			/**
   628 			/**
   558 			 * Filters the install action links for a plugin.
   629 			 * Filters the install action links for a plugin.
   559 			 *
   630 			 *
   560 			 * @since 2.7.0
   631 			 * @since 2.7.0
   561 			 *
   632 			 *
   562 			 * @param array $action_links An array of plugin action hyperlinks. Defaults are links to Details and Install Now.
   633 			 * @param string[] $action_links An array of plugin action links. Defaults are links to Details and Install Now.
   563 			 * @param array $plugin       The plugin currently being listed.
   634 			 * @param array    $plugin       The plugin currently being listed.
   564 			 */
   635 			 */
   565 			$action_links = apply_filters( 'plugin_install_action_links', $action_links, $plugin );
   636 			$action_links = apply_filters( 'plugin_install_action_links', $action_links, $plugin );
   566 
   637 
   567 			$last_updated_timestamp = strtotime( $plugin['last_updated'] );
   638 			$last_updated_timestamp = strtotime( $plugin['last_updated'] );
   568 		?>
   639 			?>
   569 		<div class="plugin-card plugin-card-<?php echo sanitize_html_class( $plugin['slug'] ); ?>">
   640 		<div class="plugin-card plugin-card-<?php echo sanitize_html_class( $plugin['slug'] ); ?>">
       
   641 			<?php
       
   642 			if ( ! $compatible_php || ! $compatible_wp ) {
       
   643 				echo '<div class="notice inline notice-error notice-alt"><p>';
       
   644 				if ( ! $compatible_php && ! $compatible_wp ) {
       
   645 					_e( 'This plugin doesn&#8217;t work with your versions of WordPress and PHP.' );
       
   646 					if ( current_user_can( 'update_core' ) && current_user_can( 'update_php' ) ) {
       
   647 						printf(
       
   648 							/* translators: 1: "Update WordPress" screen URL, 2: "Update PHP" page URL */
       
   649 							' ' . __( '<a href="%1$s">Please update WordPress</a>, and then <a href="%2$s">learn more about updating PHP</a>.' ),
       
   650 							self_admin_url( 'update-core.php' ),
       
   651 							esc_url( wp_get_update_php_url() )
       
   652 						);
       
   653 						wp_update_php_annotation( '</p><p><em>', '</em>' );
       
   654 					} elseif ( current_user_can( 'update_core' ) ) {
       
   655 						printf(
       
   656 							/* translators: %s: "Update WordPress" screen URL */
       
   657 							' ' . __( '<a href="%s">Please update WordPress</a>.' ),
       
   658 							self_admin_url( 'update-core.php' )
       
   659 						);
       
   660 					} elseif ( current_user_can( 'update_php' ) ) {
       
   661 						printf(
       
   662 							/* translators: %s: "Update PHP" page URL */
       
   663 							' ' . __( '<a href="%s">Learn more about updating PHP</a>.' ),
       
   664 							esc_url( wp_get_update_php_url() )
       
   665 						);
       
   666 						wp_update_php_annotation( '</p><p><em>', '</em>' );
       
   667 					}
       
   668 				} elseif ( ! $compatible_wp ) {
       
   669 					_e( 'This plugin doesn&#8217;t work with your version of WordPress.' );
       
   670 					if ( current_user_can( 'update_core' ) ) {
       
   671 						printf(
       
   672 							/* translators: %s: "Update WordPress" screen URL */
       
   673 							' ' . __( '<a href="%s">Please update WordPress</a>.' ),
       
   674 							self_admin_url( 'update-core.php' )
       
   675 						);
       
   676 					}
       
   677 				} elseif ( ! $compatible_php ) {
       
   678 					_e( 'This plugin doesn&#8217;t work with your version of PHP.' );
       
   679 					if ( current_user_can( 'update_php' ) ) {
       
   680 						printf(
       
   681 							/* translators: %s: "Update PHP" page URL */
       
   682 							' ' . __( '<a href="%s">Learn more about updating PHP</a>.' ),
       
   683 							esc_url( wp_get_update_php_url() )
       
   684 						);
       
   685 						wp_update_php_annotation( '</p><p><em>', '</em>' );
       
   686 					}
       
   687 				}
       
   688 				echo '</p></div>';
       
   689 			}
       
   690 			?>
   570 			<div class="plugin-card-top">
   691 			<div class="plugin-card-top">
   571 				<div class="name column-name">
   692 				<div class="name column-name">
   572 					<h3>
   693 					<h3>
   573 						<a href="<?php echo esc_url( $details_link ); ?>" class="thickbox open-plugin-details-modal">
   694 						<a href="<?php echo esc_url( $details_link ); ?>" class="thickbox open-plugin-details-modal">
   574 						<?php echo $title; ?>
   695 						<?php echo $title; ?>
   575 						<img src="<?php echo esc_attr( $plugin_icon_url ) ?>" class="plugin-icon" alt="">
   696 						<img src="<?php echo esc_attr( $plugin_icon_url ); ?>" class="plugin-icon" alt="">
   576 						</a>
   697 						</a>
   577 					</h3>
   698 					</h3>
   578 				</div>
   699 				</div>
   579 				<div class="action-links">
   700 				<div class="action-links">
   580 					<?php
   701 					<?php
   581 						if ( $action_links ) {
   702 					if ( $action_links ) {
   582 							echo '<ul class="plugin-action-buttons"><li>' . implode( '</li><li>', $action_links ) . '</li></ul>';
   703 						echo '<ul class="plugin-action-buttons"><li>' . implode( '</li><li>', $action_links ) . '</li></ul>';
   583 						}
   704 					}
   584 					?>
   705 					?>
   585 				</div>
   706 				</div>
   586 				<div class="desc column-description">
   707 				<div class="desc column-description">
   587 					<p><?php echo $description; ?></p>
   708 					<p><?php echo $description; ?></p>
   588 					<p class="authors"><?php echo $author; ?></p>
   709 					<p class="authors"><?php echo $author; ?></p>
   589 				</div>
   710 				</div>
   590 			</div>
   711 			</div>
   591 			<div class="plugin-card-bottom">
   712 			<div class="plugin-card-bottom">
   592 				<div class="vers column-rating">
   713 				<div class="vers column-rating">
   593 					<?php wp_star_rating( array( 'rating' => $plugin['rating'], 'type' => 'percent', 'number' => $plugin['num_ratings'] ) ); ?>
   714 					<?php
       
   715 					wp_star_rating(
       
   716 						array(
       
   717 							'rating' => $plugin['rating'],
       
   718 							'type'   => 'percent',
       
   719 							'number' => $plugin['num_ratings'],
       
   720 						)
       
   721 					);
       
   722 					?>
   594 					<span class="num-ratings" aria-hidden="true">(<?php echo number_format_i18n( $plugin['num_ratings'] ); ?>)</span>
   723 					<span class="num-ratings" aria-hidden="true">(<?php echo number_format_i18n( $plugin['num_ratings'] ); ?>)</span>
   595 				</div>
   724 				</div>
   596 				<div class="column-updated">
   725 				<div class="column-updated">
   597 					<strong><?php _e( 'Last Updated:' ); ?></strong> <?php printf( __( '%s ago' ), human_time_diff( $last_updated_timestamp ) ); ?>
   726 					<strong><?php _e( 'Last Updated:' ); ?></strong> <?php printf( __( '%s ago' ), human_time_diff( $last_updated_timestamp ) ); ?>
   598 				</div>
   727 				</div>
   599 				<div class="column-downloaded">
   728 				<div class="column-downloaded">
   600 					<?php
   729 					<?php
   601 					if ( $plugin['active_installs'] >= 1000000 ) {
   730 					if ( $plugin['active_installs'] >= 1000000 ) {
   602 						$active_installs_text = _x( '1+ Million', 'Active plugin installations' );
   731 						$active_installs_millions = floor( $plugin['active_installs'] / 1000000 );
       
   732 						$active_installs_text     = sprintf(
       
   733 							_nx( '%s+ Million', '%s+ Million', $active_installs_millions, 'Active plugin installations' ),
       
   734 							number_format_i18n( $active_installs_millions )
       
   735 						);
   603 					} elseif ( 0 == $plugin['active_installs'] ) {
   736 					} elseif ( 0 == $plugin['active_installs'] ) {
   604 						$active_installs_text = _x( 'Less Than 10', 'Active plugin installations' );
   737 						$active_installs_text = _x( 'Less Than 10', 'Active plugin installations' );
   605 					} else {
   738 					} else {
   606 						$active_installs_text = number_format_i18n( $plugin['active_installs'] ) . '+';
   739 						$active_installs_text = number_format_i18n( $plugin['active_installs'] ) . '+';
   607 					}
   740 					}
   608 					printf( __( '%s Active Installations' ), $active_installs_text );
   741 					printf( __( '%s Active Installations' ), $active_installs_text );
   609 					?>
   742 					?>
   610 				</div>
   743 				</div>
   611 				<div class="column-compatibility">
   744 				<div class="column-compatibility">
   612 					<?php
   745 					<?php
   613 					$wp_version = get_bloginfo( 'version' );
   746 					if ( ! $tested_wp ) {
   614 
       
   615 					if ( ! empty( $plugin['tested'] ) && version_compare( substr( $wp_version, 0, strlen( $plugin['tested'] ) ), $plugin['tested'], '>' ) ) {
       
   616 						echo '<span class="compatibility-untested">' . __( 'Untested with your version of WordPress' ) . '</span>';
   747 						echo '<span class="compatibility-untested">' . __( 'Untested with your version of WordPress' ) . '</span>';
   617 					} elseif ( ! empty( $plugin['requires'] ) && version_compare( substr( $wp_version, 0, strlen( $plugin['requires'] ) ), $plugin['requires'], '<' ) ) {
   748 					} elseif ( ! $compatible_wp ) {
   618 						echo '<span class="compatibility-incompatible">' . __( '<strong>Incompatible</strong> with your version of WordPress' ) . '</span>';
   749 						echo '<span class="compatibility-incompatible">' . __( '<strong>Incompatible</strong> with your version of WordPress' ) . '</span>';
   619 					} else {
   750 					} else {
   620 						echo '<span class="compatibility-compatible">' . __( '<strong>Compatible</strong> with your version of WordPress' ) . '</span>';
   751 						echo '<span class="compatibility-compatible">' . __( '<strong>Compatible</strong> with your version of WordPress' ) . '</span>';
   621 					}
   752 					}
   622 					?>
   753 					?>
   623 				</div>
   754 				</div>
   624 			</div>
   755 			</div>
   625 		</div>
   756 		</div>
   626 		<?php
   757 			<?php
   627 		}
   758 		}
   628 
   759 
   629 		// Close off the group divs of the last one
   760 		// Close off the group divs of the last one
   630 		if ( ! empty( $group ) ) {
   761 		if ( ! empty( $group ) ) {
   631 			echo '</div></div>';
   762 			echo '</div></div>';