wp/wp-admin/includes/class-wp-ms-themes-list-table.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
    21 	public $is_site_themes;
    21 	public $is_site_themes;
    22 
    22 
    23 	private $has_items;
    23 	private $has_items;
    24 
    24 
    25 	/**
    25 	/**
       
    26 	 * Whether to show the auto-updates UI.
       
    27 	 *
       
    28 	 * @since 5.5.0
       
    29 	 *
       
    30 	 * @var bool True if auto-updates UI is to be shown, false otherwise.
       
    31 	 */
       
    32 	protected $show_autoupdates = true;
       
    33 
       
    34 	/**
    26 	 * Constructor.
    35 	 * Constructor.
    27 	 *
    36 	 *
    28 	 * @since 3.1.0
    37 	 * @since 3.1.0
    29 	 *
    38 	 *
    30 	 * @see WP_List_Table::__construct() for more information on default arguments.
    39 	 * @see WP_List_Table::__construct() for more information on default arguments.
    43 				'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
    52 				'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
    44 			)
    53 			)
    45 		);
    54 		);
    46 
    55 
    47 		$status = isset( $_REQUEST['theme_status'] ) ? $_REQUEST['theme_status'] : 'all';
    56 		$status = isset( $_REQUEST['theme_status'] ) ? $_REQUEST['theme_status'] : 'all';
    48 		if ( ! in_array( $status, array( 'all', 'enabled', 'disabled', 'upgrade', 'search', 'broken' ) ) ) {
    57 		if ( ! in_array( $status, array( 'all', 'enabled', 'disabled', 'upgrade', 'search', 'broken', 'auto-update-enabled', 'auto-update-disabled' ), true ) ) {
    49 			$status = 'all';
    58 			$status = 'all';
    50 		}
    59 		}
    51 
    60 
    52 		$page = $this->get_pagenum();
    61 		$page = $this->get_pagenum();
    53 
    62 
    54 		$this->is_site_themes = ( 'site-themes-network' === $this->screen->id ) ? true : false;
    63 		$this->is_site_themes = ( 'site-themes-network' === $this->screen->id ) ? true : false;
    55 
    64 
    56 		if ( $this->is_site_themes ) {
    65 		if ( $this->is_site_themes ) {
    57 			$this->site_id = isset( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : 0;
    66 			$this->site_id = isset( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : 0;
    58 		}
    67 		}
       
    68 
       
    69 		$this->show_autoupdates = wp_is_auto_update_enabled_for_type( 'theme' ) &&
       
    70 			! $this->is_site_themes && current_user_can( 'update_themes' );
    59 	}
    71 	}
    60 
    72 
    61 	/**
    73 	/**
    62 	 * @return array
    74 	 * @return array
    63 	 */
    75 	 */
    64 	protected function get_table_classes() {
    76 	protected function get_table_classes() {
    65 		// todo: remove and add CSS for .themes
    77 		// @todo Remove and add CSS for .themes.
    66 		return array( 'widefat', 'plugins' );
    78 		return array( 'widefat', 'plugins' );
    67 	}
    79 	}
    68 
    80 
    69 	/**
    81 	/**
    70 	 * @return bool
    82 	 * @return bool
   105 			'disabled' => array(),
   117 			'disabled' => array(),
   106 			'upgrade'  => array(),
   118 			'upgrade'  => array(),
   107 			'broken'   => $this->is_site_themes ? array() : wp_get_themes( array( 'errors' => true ) ),
   119 			'broken'   => $this->is_site_themes ? array() : wp_get_themes( array( 'errors' => true ) ),
   108 		);
   120 		);
   109 
   121 
       
   122 		if ( $this->show_autoupdates ) {
       
   123 			$auto_updates = (array) get_site_option( 'auto_update_themes', array() );
       
   124 
       
   125 			$themes['auto-update-enabled']  = array();
       
   126 			$themes['auto-update-disabled'] = array();
       
   127 		}
       
   128 
   110 		if ( $this->is_site_themes ) {
   129 		if ( $this->is_site_themes ) {
   111 			$themes_per_page = $this->get_items_per_page( 'site_themes_network_per_page' );
   130 			$themes_per_page = $this->get_items_per_page( 'site_themes_network_per_page' );
   112 			$allowed_where   = 'site';
   131 			$allowed_where   = 'site';
   113 		} else {
   132 		} else {
   114 			$themes_per_page = $this->get_items_per_page( 'themes_network_per_page' );
   133 			$themes_per_page = $this->get_items_per_page( 'themes_network_per_page' );
   115 			$allowed_where   = 'network';
   134 			$allowed_where   = 'network';
   116 		}
   135 		}
   117 
   136 
   118 		$maybe_update = current_user_can( 'update_themes' ) && ! $this->is_site_themes && $current = get_site_transient( 'update_themes' );
   137 		$current      = get_site_transient( 'update_themes' );
       
   138 		$maybe_update = current_user_can( 'update_themes' ) && ! $this->is_site_themes && $current;
   119 
   139 
   120 		foreach ( (array) $themes['all'] as $key => $theme ) {
   140 		foreach ( (array) $themes['all'] as $key => $theme ) {
   121 			if ( $this->is_site_themes && $theme->is_allowed( 'network' ) ) {
   141 			if ( $this->is_site_themes && $theme->is_allowed( 'network' ) ) {
   122 				unset( $themes['all'][ $key ] );
   142 				unset( $themes['all'][ $key ] );
   123 				continue;
   143 				continue;
   128 				$themes['upgrade'][ $key ]     = $themes['all'][ $key ];
   148 				$themes['upgrade'][ $key ]     = $themes['all'][ $key ];
   129 			}
   149 			}
   130 
   150 
   131 			$filter                    = $theme->is_allowed( $allowed_where, $this->site_id ) ? 'enabled' : 'disabled';
   151 			$filter                    = $theme->is_allowed( $allowed_where, $this->site_id ) ? 'enabled' : 'disabled';
   132 			$themes[ $filter ][ $key ] = $themes['all'][ $key ];
   152 			$themes[ $filter ][ $key ] = $themes['all'][ $key ];
       
   153 
       
   154 			$theme_data = array(
       
   155 				'update_supported' => isset( $theme->update_supported ) ? $theme->update_supported : true,
       
   156 			);
       
   157 
       
   158 			// Extra info if known. array_merge() ensures $theme_data has precedence if keys collide.
       
   159 			if ( isset( $current->response[ $key ] ) ) {
       
   160 				$theme_data = array_merge( (array) $current->response[ $key ], $theme_data );
       
   161 			} elseif ( isset( $current->no_update[ $key ] ) ) {
       
   162 				$theme_data = array_merge( (array) $current->no_update[ $key ], $theme_data );
       
   163 			} else {
       
   164 				$theme_data['update_supported'] = false;
       
   165 			}
       
   166 
       
   167 			$theme->update_supported = $theme_data['update_supported'];
       
   168 
       
   169 			/*
       
   170 			 * Create the expected payload for the auto_update_theme filter, this is the same data
       
   171 			 * as contained within $updates or $no_updates but used when the Theme is not known.
       
   172 			 */
       
   173 			$filter_payload = array(
       
   174 				'theme'        => $key,
       
   175 				'new_version'  => '',
       
   176 				'url'          => '',
       
   177 				'package'      => '',
       
   178 				'requires'     => '',
       
   179 				'requires_php' => '',
       
   180 			);
       
   181 
       
   182 			$filter_payload = array_merge( $filter_payload, array_intersect_key( $theme_data, $filter_payload ) );
       
   183 
       
   184 			$type = 'theme';
       
   185 			/** This filter is documented in wp-admin/includes/class-wp-automatic-updater.php */
       
   186 			$auto_update_forced = apply_filters( "auto_update_{$type}", null, (object) $filter_payload );
       
   187 
       
   188 			if ( ! is_null( $auto_update_forced ) ) {
       
   189 				$theme->auto_update_forced = $auto_update_forced;
       
   190 			}
       
   191 
       
   192 			if ( $this->show_autoupdates ) {
       
   193 				$enabled = in_array( $key, $auto_updates, true ) && $theme->update_supported;
       
   194 				if ( isset( $theme->auto_update_forced ) ) {
       
   195 					$enabled = (bool) $theme->auto_update_forced;
       
   196 				}
       
   197 
       
   198 				if ( $enabled ) {
       
   199 					$themes['auto-update-enabled'][ $key ] = $theme;
       
   200 				} else {
       
   201 					$themes['auto-update-disabled'][ $key ] = $theme;
       
   202 				}
       
   203 			}
   133 		}
   204 		}
   134 
   205 
   135 		if ( $s ) {
   206 		if ( $s ) {
   136 			$status           = 'search';
   207 			$status           = 'search';
   137 			$themes['search'] = array_filter( array_merge( $themes['all'], $themes['broken'] ), array( $this, '_search_callback' ) );
   208 			$themes['search'] = array_filter( array_merge( $themes['all'], $themes['broken'] ), array( $this, '_search_callback' ) );
   140 		$totals = array();
   211 		$totals = array();
   141 		foreach ( $themes as $type => $list ) {
   212 		foreach ( $themes as $type => $list ) {
   142 			$totals[ $type ] = count( $list );
   213 			$totals[ $type ] = count( $list );
   143 		}
   214 		}
   144 
   215 
   145 		if ( empty( $themes[ $status ] ) && ! in_array( $status, array( 'all', 'search' ) ) ) {
   216 		if ( empty( $themes[ $status ] ) && ! in_array( $status, array( 'all', 'search' ), true ) ) {
   146 			$status = 'all';
   217 			$status = 'all';
   147 		}
   218 		}
   148 
   219 
   149 		$this->items = $themes[ $status ];
   220 		$this->items = $themes[ $status ];
   150 		WP_Theme::sort_by_name( $this->items );
   221 		WP_Theme::sort_by_name( $this->items );
   163 
   234 
   164 		if ( $orderby ) {
   235 		if ( $orderby ) {
   165 			$orderby = ucfirst( $orderby );
   236 			$orderby = ucfirst( $orderby );
   166 			$order   = strtoupper( $order );
   237 			$order   = strtoupper( $order );
   167 
   238 
   168 			if ( $orderby === 'Name' ) {
   239 			if ( 'Name' === $orderby ) {
   169 				if ( 'ASC' === $order ) {
   240 				if ( 'ASC' === $order ) {
   170 					$this->items = array_reverse( $this->items );
   241 					$this->items = array_reverse( $this->items );
   171 				}
   242 				}
   172 			} else {
   243 			} else {
   173 				uasort( $this->items, array( $this, '_order_callback' ) );
   244 				uasort( $this->items, array( $this, '_order_callback' ) );
   187 			)
   258 			)
   188 		);
   259 		);
   189 	}
   260 	}
   190 
   261 
   191 	/**
   262 	/**
   192 	 * @staticvar string $term
       
   193 	 * @param WP_Theme $theme
   263 	 * @param WP_Theme $theme
   194 	 * @return bool
   264 	 * @return bool
   195 	 */
   265 	 */
   196 	public function _search_callback( $theme ) {
   266 	public function _search_callback( $theme ) {
   197 		static $term = null;
   267 		static $term = null;
   246 	 */
   316 	 */
   247 	public function no_items() {
   317 	public function no_items() {
   248 		if ( $this->has_items ) {
   318 		if ( $this->has_items ) {
   249 			_e( 'No themes found.' );
   319 			_e( 'No themes found.' );
   250 		} else {
   320 		} else {
   251 			_e( 'You do not appear to have any themes available at this time.' );
   321 			_e( 'No themes are currently available.' );
   252 		}
   322 		}
   253 	}
   323 	}
   254 
   324 
   255 	/**
   325 	/**
   256 	 * @return array
   326 	 * @return array
   257 	 */
   327 	 */
   258 	public function get_columns() {
   328 	public function get_columns() {
   259 		return array(
   329 		$columns = array(
   260 			'cb'          => '<input type="checkbox" />',
   330 			'cb'          => '<input type="checkbox" />',
   261 			'name'        => __( 'Theme' ),
   331 			'name'        => __( 'Theme' ),
   262 			'description' => __( 'Description' ),
   332 			'description' => __( 'Description' ),
   263 		);
   333 		);
       
   334 
       
   335 		if ( $this->show_autoupdates ) {
       
   336 			$columns['auto-updates'] = __( 'Automatic Updates' );
       
   337 		}
       
   338 
       
   339 		return $columns;
   264 	}
   340 	}
   265 
   341 
   266 	/**
   342 	/**
   267 	 * @return array
   343 	 * @return array
   268 	 */
   344 	 */
   297 				continue;
   373 				continue;
   298 			}
   374 			}
   299 
   375 
   300 			switch ( $type ) {
   376 			switch ( $type ) {
   301 				case 'all':
   377 				case 'all':
   302 					$text = _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $count, 'themes' );
   378 					/* translators: %s: Number of themes. */
       
   379 					$text = _nx(
       
   380 						'All <span class="count">(%s)</span>',
       
   381 						'All <span class="count">(%s)</span>',
       
   382 						$count,
       
   383 						'themes'
       
   384 					);
   303 					break;
   385 					break;
   304 				case 'enabled':
   386 				case 'enabled':
   305 					$text = _n( 'Enabled <span class="count">(%s)</span>', 'Enabled <span class="count">(%s)</span>', $count );
   387 					/* translators: %s: Number of themes. */
       
   388 					$text = _nx(
       
   389 						'Enabled <span class="count">(%s)</span>',
       
   390 						'Enabled <span class="count">(%s)</span>',
       
   391 						$count,
       
   392 						'themes'
       
   393 					);
   306 					break;
   394 					break;
   307 				case 'disabled':
   395 				case 'disabled':
   308 					$text = _n( 'Disabled <span class="count">(%s)</span>', 'Disabled <span class="count">(%s)</span>', $count );
   396 					/* translators: %s: Number of themes. */
       
   397 					$text = _nx(
       
   398 						'Disabled <span class="count">(%s)</span>',
       
   399 						'Disabled <span class="count">(%s)</span>',
       
   400 						$count,
       
   401 						'themes'
       
   402 					);
   309 					break;
   403 					break;
   310 				case 'upgrade':
   404 				case 'upgrade':
   311 					$text = _n( 'Update Available <span class="count">(%s)</span>', 'Update Available <span class="count">(%s)</span>', $count );
   405 					/* translators: %s: Number of themes. */
       
   406 					$text = _nx(
       
   407 						'Update Available <span class="count">(%s)</span>',
       
   408 						'Update Available <span class="count">(%s)</span>',
       
   409 						$count,
       
   410 						'themes'
       
   411 					);
   312 					break;
   412 					break;
   313 				case 'broken':
   413 				case 'broken':
   314 					$text = _n( 'Broken <span class="count">(%s)</span>', 'Broken <span class="count">(%s)</span>', $count );
   414 					/* translators: %s: Number of themes. */
       
   415 					$text = _nx(
       
   416 						'Broken <span class="count">(%s)</span>',
       
   417 						'Broken <span class="count">(%s)</span>',
       
   418 						$count,
       
   419 						'themes'
       
   420 					);
       
   421 					break;
       
   422 				case 'auto-update-enabled':
       
   423 					/* translators: %s: Number of themes. */
       
   424 					$text = _n(
       
   425 						'Auto-updates Enabled <span class="count">(%s)</span>',
       
   426 						'Auto-updates Enabled <span class="count">(%s)</span>',
       
   427 						$count
       
   428 					);
       
   429 					break;
       
   430 				case 'auto-update-disabled':
       
   431 					/* translators: %s: Number of themes. */
       
   432 					$text = _n(
       
   433 						'Auto-updates Disabled <span class="count">(%s)</span>',
       
   434 						'Auto-updates Disabled <span class="count">(%s)</span>',
       
   435 						$count
       
   436 					);
   315 					break;
   437 					break;
   316 			}
   438 			}
   317 
   439 
   318 			if ( $this->is_site_themes ) {
   440 			if ( $this->is_site_themes ) {
   319 				$url = 'site-themes.php?id=' . $this->site_id;
   441 				$url = 'site-themes.php?id=' . $this->site_id;
   320 			} else {
   442 			} else {
   321 				$url = 'themes.php';
   443 				$url = 'themes.php';
   322 			}
   444 			}
   323 
   445 
   324 			if ( 'search' != $type ) {
   446 			if ( 'search' !== $type ) {
   325 				$status_links[ $type ] = sprintf(
   447 				$status_links[ $type ] = sprintf(
   326 					"<a href='%s'%s>%s</a>",
   448 					"<a href='%s'%s>%s</a>",
   327 					esc_url( add_query_arg( 'theme_status', $type, $url ) ),
   449 					esc_url( add_query_arg( 'theme_status', $type, $url ) ),
   328 					( $type === $status ) ? ' class="current" aria-current="page"' : '',
   450 					( $type === $status ) ? ' class="current" aria-current="page"' : '',
   329 					sprintf( $text, number_format_i18n( $count ) )
   451 					sprintf( $text, number_format_i18n( $count ) )
   341 	 */
   463 	 */
   342 	protected function get_bulk_actions() {
   464 	protected function get_bulk_actions() {
   343 		global $status;
   465 		global $status;
   344 
   466 
   345 		$actions = array();
   467 		$actions = array();
   346 		if ( 'enabled' != $status ) {
   468 		if ( 'enabled' !== $status ) {
   347 			$actions['enable-selected'] = $this->is_site_themes ? __( 'Enable' ) : __( 'Network Enable' );
   469 			$actions['enable-selected'] = $this->is_site_themes ? __( 'Enable' ) : __( 'Network Enable' );
   348 		}
   470 		}
   349 		if ( 'disabled' != $status ) {
   471 		if ( 'disabled' !== $status ) {
   350 			$actions['disable-selected'] = $this->is_site_themes ? __( 'Disable' ) : __( 'Network Disable' );
   472 			$actions['disable-selected'] = $this->is_site_themes ? __( 'Disable' ) : __( 'Network Disable' );
   351 		}
   473 		}
   352 		if ( ! $this->is_site_themes ) {
   474 		if ( ! $this->is_site_themes ) {
   353 			if ( current_user_can( 'update_themes' ) ) {
   475 			if ( current_user_can( 'update_themes' ) ) {
   354 				$actions['update-selected'] = __( 'Update' );
   476 				$actions['update-selected'] = __( 'Update' );
   355 			}
   477 			}
   356 			if ( current_user_can( 'delete_themes' ) ) {
   478 			if ( current_user_can( 'delete_themes' ) ) {
   357 				$actions['delete-selected'] = __( 'Delete' );
   479 				$actions['delete-selected'] = __( 'Delete' );
   358 			}
   480 			}
   359 		}
   481 		}
       
   482 
       
   483 		if ( $this->show_autoupdates ) {
       
   484 			if ( 'auto-update-enabled' !== $status ) {
       
   485 				$actions['enable-auto-update-selected'] = __( 'Enable Auto-updates' );
       
   486 			}
       
   487 
       
   488 			if ( 'auto-update-disabled' !== $status ) {
       
   489 				$actions['disable-auto-update-selected'] = __( 'Disable Auto-updates' );
       
   490 			}
       
   491 		}
       
   492 
   360 		return $actions;
   493 		return $actions;
   361 	}
   494 	}
   362 
   495 
   363 	/**
   496 	/**
   364 	 */
   497 	 */
   428 					),
   561 					),
   429 					$url
   562 					$url
   430 				);
   563 				);
   431 
   564 
   432 				if ( $this->is_site_themes ) {
   565 				if ( $this->is_site_themes ) {
   433 					/* translators: %s: theme name */
   566 					/* translators: %s: Theme name. */
   434 					$aria_label = sprintf( __( 'Enable %s' ), $theme->display( 'Name' ) );
   567 					$aria_label = sprintf( __( 'Enable %s' ), $theme->display( 'Name' ) );
   435 				} else {
   568 				} else {
   436 					/* translators: %s: theme name */
   569 					/* translators: %s: Theme name. */
   437 					$aria_label = sprintf( __( 'Network Enable %s' ), $theme->display( 'Name' ) );
   570 					$aria_label = sprintf( __( 'Network Enable %s' ), $theme->display( 'Name' ) );
   438 				}
   571 				}
   439 
   572 
   440 				$actions['enable'] = sprintf(
   573 				$actions['enable'] = sprintf(
   441 					'<a href="%s" class="edit" aria-label="%s">%s</a>',
   574 					'<a href="%s" class="edit" aria-label="%s">%s</a>',
   454 				),
   587 				),
   455 				$url
   588 				$url
   456 			);
   589 			);
   457 
   590 
   458 			if ( $this->is_site_themes ) {
   591 			if ( $this->is_site_themes ) {
   459 				/* translators: %s: theme name */
   592 				/* translators: %s: Theme name. */
   460 				$aria_label = sprintf( __( 'Disable %s' ), $theme->display( 'Name' ) );
   593 				$aria_label = sprintf( __( 'Disable %s' ), $theme->display( 'Name' ) );
   461 			} else {
   594 			} else {
   462 				/* translators: %s: theme name */
   595 				/* translators: %s: Theme name. */
   463 				$aria_label = sprintf( __( 'Network Disable %s' ), $theme->display( 'Name' ) );
   596 				$aria_label = sprintf( __( 'Network Disable %s' ), $theme->display( 'Name' ) );
   464 			}
   597 			}
   465 
   598 
   466 			$actions['disable'] = sprintf(
   599 			$actions['disable'] = sprintf(
   467 				'<a href="%s" aria-label="%s">%s</a>',
   600 				'<a href="%s" aria-label="%s">%s</a>',
   469 				esc_attr( $aria_label ),
   602 				esc_attr( $aria_label ),
   470 				( $this->is_site_themes ? __( 'Disable' ) : __( 'Network Disable' ) )
   603 				( $this->is_site_themes ? __( 'Disable' ) : __( 'Network Disable' ) )
   471 			);
   604 			);
   472 		}
   605 		}
   473 
   606 
   474 		if ( ! $allowed && current_user_can( 'delete_themes' ) && ! $this->is_site_themes && $stylesheet != get_option( 'stylesheet' ) && $stylesheet != get_option( 'template' ) ) {
   607 		if ( ! $allowed && ! $this->is_site_themes
       
   608 			&& current_user_can( 'delete_themes' )
       
   609 			&& get_option( 'stylesheet' ) !== $stylesheet
       
   610 			&& get_option( 'template' ) !== $stylesheet
       
   611 		) {
   475 			$url = add_query_arg(
   612 			$url = add_query_arg(
   476 				array(
   613 				array(
   477 					'action'       => 'delete-selected',
   614 					'action'       => 'delete-selected',
   478 					'checked[]'    => $theme_key,
   615 					'checked[]'    => $theme_key,
   479 					'theme_status' => $context,
   616 					'theme_status' => $context,
   481 					's'            => $s,
   618 					's'            => $s,
   482 				),
   619 				),
   483 				'themes.php'
   620 				'themes.php'
   484 			);
   621 			);
   485 
   622 
   486 			/* translators: %s: theme name */
   623 			/* translators: %s: Theme name. */
   487 			$aria_label = sprintf( _x( 'Delete %s', 'theme' ), $theme->display( 'Name' ) );
   624 			$aria_label = sprintf( _x( 'Delete %s', 'theme' ), $theme->display( 'Name' ) );
   488 
   625 
   489 			$actions['delete'] = sprintf(
   626 			$actions['delete'] = sprintf(
   490 				'<a href="%s" class="delete" aria-label="%s">%s</a>',
   627 				'<a href="%s" class="delete" aria-label="%s">%s</a>',
   491 				esc_url( wp_nonce_url( $url, 'bulk-themes' ) ),
   628 				esc_url( wp_nonce_url( $url, 'bulk-themes' ) ),
   546 	 *
   683 	 *
   547 	 * @param WP_Theme $theme The current WP_Theme object.
   684 	 * @param WP_Theme $theme The current WP_Theme object.
   548 	 */
   685 	 */
   549 	public function column_description( $theme ) {
   686 	public function column_description( $theme ) {
   550 		global $status, $totals;
   687 		global $status, $totals;
       
   688 
   551 		if ( $theme->errors() ) {
   689 		if ( $theme->errors() ) {
   552 			$pre = $status === 'broken' ? __( 'Broken Theme:' ) . ' ' : '';
   690 			$pre = 'broken' === $status ? __( 'Broken Theme:' ) . ' ' : '';
   553 			echo '<p><strong class="error-message">' . $pre . $theme->errors()->get_error_message() . '</strong></p>';
   691 			echo '<p><strong class="error-message">' . $pre . $theme->errors()->get_error_message() . '</strong></p>';
   554 		}
   692 		}
   555 
   693 
   556 		if ( $this->is_site_themes ) {
   694 		if ( $this->is_site_themes ) {
   557 			$allowed = $theme->is_allowed( 'site', $this->site_id );
   695 			$allowed = $theme->is_allowed( 'site', $this->site_id );
   569 
   707 
   570 		$stylesheet = $theme->get_stylesheet();
   708 		$stylesheet = $theme->get_stylesheet();
   571 		$theme_meta = array();
   709 		$theme_meta = array();
   572 
   710 
   573 		if ( $theme->get( 'Version' ) ) {
   711 		if ( $theme->get( 'Version' ) ) {
       
   712 			/* translators: %s: Theme version. */
   574 			$theme_meta[] = sprintf( __( 'Version %s' ), $theme->display( 'Version' ) );
   713 			$theme_meta[] = sprintf( __( 'Version %s' ), $theme->display( 'Version' ) );
   575 		}
   714 		}
       
   715 
       
   716 		/* translators: %s: Theme author. */
   576 		$theme_meta[] = sprintf( __( 'By %s' ), $theme->display( 'Author' ) );
   717 		$theme_meta[] = sprintf( __( 'By %s' ), $theme->display( 'Author' ) );
   577 
   718 
   578 		if ( $theme->get( 'ThemeURI' ) ) {
   719 		if ( $theme->get( 'ThemeURI' ) ) {
   579 			/* translators: %s: theme name */
   720 			/* translators: %s: Theme name. */
   580 			$aria_label = sprintf( __( 'Visit %s homepage' ), $theme->display( 'Name' ) );
   721 			$aria_label = sprintf( __( 'Visit %s homepage' ), $theme->display( 'Name' ) );
   581 
   722 
   582 			$theme_meta[] = sprintf(
   723 			$theme_meta[] = sprintf(
   583 				'<a href="%s" aria-label="%s">%s</a>',
   724 				'<a href="%s" aria-label="%s">%s</a>',
   584 				$theme->display( 'ThemeURI' ),
   725 				$theme->display( 'ThemeURI' ),
   585 				esc_attr( $aria_label ),
   726 				esc_attr( $aria_label ),
   586 				__( 'Visit Theme Site' )
   727 				__( 'Visit Theme Site' )
   587 			);
   728 			);
   588 		}
   729 		}
       
   730 
   589 		/**
   731 		/**
   590 		 * Filters the array of row meta for each theme in the Multisite themes
   732 		 * Filters the array of row meta for each theme in the Multisite themes
   591 		 * list table.
   733 		 * list table.
   592 		 *
   734 		 *
   593 		 * @since 3.1.0
   735 		 * @since 3.1.0
   594 		 *
   736 		 *
   595 		 * @param string[] $theme_meta An array of the theme's metadata,
   737 		 * @param string[] $theme_meta An array of the theme's metadata, including
   596 		 *                             including the version, author, and
   738 		 *                             the version, author, and theme URI.
   597 		 *                             theme URI.
       
   598 		 * @param string   $stylesheet Directory name of the theme.
   739 		 * @param string   $stylesheet Directory name of the theme.
   599 		 * @param WP_Theme $theme      WP_Theme object.
   740 		 * @param WP_Theme $theme      WP_Theme object.
   600 		 * @param string   $status     Status of the theme.
   741 		 * @param string   $status     Status of the theme.
   601 		 */
   742 		 */
   602 		$theme_meta = apply_filters( 'theme_row_meta', $theme_meta, $stylesheet, $theme, $status );
   743 		$theme_meta = apply_filters( 'theme_row_meta', $theme_meta, $stylesheet, $theme, $status );
       
   744 
   603 		echo implode( ' | ', $theme_meta );
   745 		echo implode( ' | ', $theme_meta );
   604 
   746 
   605 		echo '</div>';
   747 		echo '</div>';
       
   748 	}
       
   749 
       
   750 	/**
       
   751 	 * Handles the auto-updates column output.
       
   752 	 *
       
   753 	 * @since 5.5.0
       
   754 	 *
       
   755 	 * @global string $status
       
   756 	 * @global int  $page
       
   757 	 *
       
   758 	 * @param WP_Theme $theme The current WP_Theme object.
       
   759 	 */
       
   760 	public function column_autoupdates( $theme ) {
       
   761 		global $status, $page;
       
   762 
       
   763 		static $auto_updates, $available_updates;
       
   764 
       
   765 		if ( ! $auto_updates ) {
       
   766 			$auto_updates = (array) get_site_option( 'auto_update_themes', array() );
       
   767 		}
       
   768 		if ( ! $available_updates ) {
       
   769 			$available_updates = get_site_transient( 'update_themes' );
       
   770 		}
       
   771 
       
   772 		$stylesheet = $theme->get_stylesheet();
       
   773 
       
   774 		if ( isset( $theme->auto_update_forced ) ) {
       
   775 			if ( $theme->auto_update_forced ) {
       
   776 				// Forced on.
       
   777 				$text = __( 'Auto-updates enabled' );
       
   778 			} else {
       
   779 				$text = __( 'Auto-updates disabled' );
       
   780 			}
       
   781 			$action     = 'unavailable';
       
   782 			$time_class = ' hidden';
       
   783 		} elseif ( empty( $theme->update_supported ) ) {
       
   784 			$text       = '';
       
   785 			$action     = 'unavailable';
       
   786 			$time_class = ' hidden';
       
   787 		} elseif ( in_array( $stylesheet, $auto_updates, true ) ) {
       
   788 			$text       = __( 'Disable auto-updates' );
       
   789 			$action     = 'disable';
       
   790 			$time_class = '';
       
   791 		} else {
       
   792 			$text       = __( 'Enable auto-updates' );
       
   793 			$action     = 'enable';
       
   794 			$time_class = ' hidden';
       
   795 		}
       
   796 
       
   797 		$query_args = array(
       
   798 			'action'       => "{$action}-auto-update",
       
   799 			'theme'        => $stylesheet,
       
   800 			'paged'        => $page,
       
   801 			'theme_status' => $status,
       
   802 		);
       
   803 
       
   804 		$url = add_query_arg( $query_args, 'themes.php' );
       
   805 
       
   806 		if ( 'unavailable' === $action ) {
       
   807 			$html[] = '<span class="label">' . $text . '</span>';
       
   808 		} else {
       
   809 			$html[] = sprintf(
       
   810 				'<a href="%s" class="toggle-auto-update aria-button-if-js" data-wp-action="%s">',
       
   811 				wp_nonce_url( $url, 'updates' ),
       
   812 				$action
       
   813 			);
       
   814 
       
   815 			$html[] = '<span class="dashicons dashicons-update spin hidden" aria-hidden="true"></span>';
       
   816 			$html[] = '<span class="label">' . $text . '</span>';
       
   817 			$html[] = '</a>';
       
   818 
       
   819 		}
       
   820 
       
   821 		if ( isset( $available_updates->response[ $stylesheet ] ) ) {
       
   822 			$html[] = sprintf(
       
   823 				'<div class="auto-update-time%s">%s</div>',
       
   824 				$time_class,
       
   825 				wp_get_auto_update_message()
       
   826 			);
       
   827 		}
       
   828 
       
   829 		$html = implode( '', $html );
       
   830 
       
   831 		/**
       
   832 		 * Filters the HTML of the auto-updates setting for each theme in the Themes list table.
       
   833 		 *
       
   834 		 * @since 5.5.0
       
   835 		 *
       
   836 		 * @param string   $html       The HTML for theme's auto-update setting, including
       
   837 		 *                             toggle auto-update action link and time to next update.
       
   838 		 * @param string   $stylesheet Directory name of the theme.
       
   839 		 * @param WP_Theme $theme      WP_Theme object.
       
   840 		 */
       
   841 		echo apply_filters( 'theme_auto_update_setting_html', $html, $stylesheet, $theme );
       
   842 
       
   843 		echo '<div class="notice notice-error notice-alt inline hidden"><p></p></div>';
   606 	}
   844 	}
   607 
   845 
   608 	/**
   846 	/**
   609 	 * Handles default column output.
   847 	 * Handles default column output.
   610 	 *
   848 	 *
   638 	public function single_row_columns( $item ) {
   876 	public function single_row_columns( $item ) {
   639 		list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
   877 		list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
   640 
   878 
   641 		foreach ( $columns as $column_name => $column_display_name ) {
   879 		foreach ( $columns as $column_name => $column_display_name ) {
   642 			$extra_classes = '';
   880 			$extra_classes = '';
   643 			if ( in_array( $column_name, $hidden ) ) {
   881 			if ( in_array( $column_name, $hidden, true ) ) {
   644 				$extra_classes .= ' hidden';
   882 				$extra_classes .= ' hidden';
   645 			}
   883 			}
   646 
   884 
   647 			switch ( $column_name ) {
   885 			switch ( $column_name ) {
   648 				case 'cb':
   886 				case 'cb':
   685 					$this->column_description( $item );
   923 					$this->column_description( $item );
   686 
   924 
   687 					echo '</td>';
   925 					echo '</td>';
   688 					break;
   926 					break;
   689 
   927 
       
   928 				case 'auto-updates':
       
   929 					echo "<td class='column-auto-updates{$extra_classes}'>";
       
   930 
       
   931 					$this->column_autoupdates( $item );
       
   932 
       
   933 					echo '</td>';
       
   934 					break;
   690 				default:
   935 				default:
   691 					echo "<td class='$column_name column-$column_name{$extra_classes}'>";
   936 					echo "<td class='$column_name column-$column_name{$extra_classes}'>";
   692 
   937 
   693 					$this->column_default( $item, $column_name );
   938 					$this->column_default( $item, $column_name );
   694 
   939