wp/wp-admin/includes/theme.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
    33 	$credentials = request_filesystem_credentials( $redirect );
    33 	$credentials = request_filesystem_credentials( $redirect );
    34 	$data        = ob_get_clean();
    34 	$data        = ob_get_clean();
    35 
    35 
    36 	if ( false === $credentials ) {
    36 	if ( false === $credentials ) {
    37 		if ( ! empty( $data ) ) {
    37 		if ( ! empty( $data ) ) {
    38 			include_once( ABSPATH . 'wp-admin/admin-header.php' );
    38 			require_once ABSPATH . 'wp-admin/admin-header.php';
    39 			echo $data;
    39 			echo $data;
    40 			include( ABSPATH . 'wp-admin/admin-footer.php' );
    40 			require_once ABSPATH . 'wp-admin/admin-footer.php';
    41 			exit;
    41 			exit;
    42 		}
    42 		}
    43 		return;
    43 		return;
    44 	}
    44 	}
    45 
    45 
    46 	if ( ! WP_Filesystem( $credentials ) ) {
    46 	if ( ! WP_Filesystem( $credentials ) ) {
    47 		ob_start();
    47 		ob_start();
    48 		request_filesystem_credentials( $redirect, '', true ); // Failed to connect, Error and request again.
    48 		// Failed to connect. Error and request again.
       
    49 		request_filesystem_credentials( $redirect, '', true );
    49 		$data = ob_get_clean();
    50 		$data = ob_get_clean();
    50 
    51 
    51 		if ( ! empty( $data ) ) {
    52 		if ( ! empty( $data ) ) {
    52 			include_once( ABSPATH . 'wp-admin/admin-header.php' );
    53 			require_once ABSPATH . 'wp-admin/admin-header.php';
    53 			echo $data;
    54 			echo $data;
    54 			include( ABSPATH . 'wp-admin/admin-footer.php' );
    55 			require_once ABSPATH . 'wp-admin/admin-footer.php';
    55 			exit;
    56 			exit;
    56 		}
    57 		}
    57 		return;
    58 		return;
    58 	}
    59 	}
    59 
    60 
    74 	$themes_dir = trailingslashit( $themes_dir );
    75 	$themes_dir = trailingslashit( $themes_dir );
    75 	$theme_dir  = trailingslashit( $themes_dir . $stylesheet );
    76 	$theme_dir  = trailingslashit( $themes_dir . $stylesheet );
    76 	$deleted    = $wp_filesystem->delete( $theme_dir, true );
    77 	$deleted    = $wp_filesystem->delete( $theme_dir, true );
    77 
    78 
    78 	if ( ! $deleted ) {
    79 	if ( ! $deleted ) {
    79 		return new WP_Error( 'could_not_remove_theme', sprintf( __( 'Could not fully remove the theme %s.' ), $stylesheet ) );
    80 		return new WP_Error(
       
    81 			'could_not_remove_theme',
       
    82 			/* translators: %s: Theme name. */
       
    83 			sprintf( __( 'Could not fully remove the theme %s.' ), $stylesheet )
       
    84 		);
    80 	}
    85 	}
    81 
    86 
    82 	$theme_translations = wp_get_installed_translations( 'themes' );
    87 	$theme_translations = wp_get_installed_translations( 'themes' );
    83 
    88 
    84 	// Remove language files, silently.
    89 	// Remove language files, silently.
   106 
   111 
   107 	return true;
   112 	return true;
   108 }
   113 }
   109 
   114 
   110 /**
   115 /**
   111  * Get the Page Templates available in this theme
   116  * Gets the page templates available in this theme.
   112  *
   117  *
   113  * @since 1.5.0
   118  * @since 1.5.0
   114  * @since 4.7.0 Added the `$post_type` parameter.
   119  * @since 4.7.0 Added the `$post_type` parameter.
   115  *
   120  *
   116  * @param WP_Post|null $post      Optional. The post being edited, provided for context.
   121  * @param WP_Post|null $post      Optional. The post being edited, provided for context.
   117  * @param string       $post_type Optional. Post type to get the templates for. Default 'page'.
   122  * @param string       $post_type Optional. Post type to get the templates for. Default 'page'.
   118  * @return array Key is the template name, value is the filename of the template
   123  * @return string[] Array of template file names keyed by the template header name.
   119  */
   124  */
   120 function get_page_templates( $post = null, $post_type = 'page' ) {
   125 function get_page_templates( $post = null, $post_type = 'page' ) {
   121 	return array_flip( wp_get_theme()->get_page_templates( $post, $post_type ) );
   126 	return array_flip( wp_get_theme()->get_page_templates( $post, $post_type ) );
   122 }
   127 }
   123 
   128 
   139  * Check if there is an update for a theme available.
   144  * Check if there is an update for a theme available.
   140  *
   145  *
   141  * Will display link, if there is an update available.
   146  * Will display link, if there is an update available.
   142  *
   147  *
   143  * @since 2.7.0
   148  * @since 2.7.0
       
   149  *
   144  * @see get_theme_update_available()
   150  * @see get_theme_update_available()
   145  *
   151  *
   146  * @param WP_Theme $theme Theme data object.
   152  * @param WP_Theme $theme Theme data object.
   147  */
   153  */
   148 function theme_update_available( $theme ) {
   154 function theme_update_available( $theme ) {
   154  *
   160  *
   155  * Will return a link if there is an update available.
   161  * Will return a link if there is an update available.
   156  *
   162  *
   157  * @since 3.8.0
   163  * @since 3.8.0
   158  *
   164  *
   159  * @staticvar object $themes_update
       
   160  *
       
   161  * @param WP_Theme $theme WP_Theme object.
   165  * @param WP_Theme $theme WP_Theme object.
   162  * @return false|string HTML for the update link, or false if invalid info was passed.
   166  * @return string|false HTML for the update link, or false if invalid info was passed.
   163  */
   167  */
   164 function get_theme_update_available( $theme ) {
   168 function get_theme_update_available( $theme ) {
   165 	static $themes_update = null;
   169 	static $themes_update = null;
   166 
   170 
   167 	if ( ! current_user_can( 'update_themes' ) ) {
   171 	if ( ! current_user_can( 'update_themes' ) ) {
   188 				'TB_iframe' => 'true',
   192 				'TB_iframe' => 'true',
   189 				'width'     => 1024,
   193 				'width'     => 1024,
   190 				'height'    => 800,
   194 				'height'    => 800,
   191 			),
   195 			),
   192 			$update['url']
   196 			$update['url']
   193 		); //Theme browser inside WP? replace this, Also, theme preview JS will override this on the available list.
   197 		); // Theme browser inside WP? Replace this. Also, theme preview JS will override this on the available list.
   194 		$update_url  = wp_nonce_url( admin_url( 'update.php?action=upgrade-theme&theme=' . urlencode( $stylesheet ) ), 'upgrade-theme_' . $stylesheet );
   198 		$update_url  = wp_nonce_url( admin_url( 'update.php?action=upgrade-theme&theme=' . urlencode( $stylesheet ) ), 'upgrade-theme_' . $stylesheet );
   195 
   199 
   196 		if ( ! is_multisite() ) {
   200 		if ( ! is_multisite() ) {
   197 			if ( ! current_user_can( 'update_themes' ) ) {
   201 			if ( ! current_user_can( 'update_themes' ) ) {
   198 				/* translators: 1: theme name, 2: theme details URL, 3: additional link attributes, 4: version number */
       
   199 				$html = sprintf(
   202 				$html = sprintf(
       
   203 					/* translators: 1: Theme name, 2: Theme details URL, 3: Additional link attributes, 4: Version number. */
   200 					'<p><strong>' . __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>.' ) . '</strong></p>',
   204 					'<p><strong>' . __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>.' ) . '</strong></p>',
   201 					$theme_name,
   205 					$theme_name,
   202 					esc_url( $details_url ),
   206 					esc_url( $details_url ),
   203 					sprintf(
   207 					sprintf(
   204 						'class="thickbox open-plugin-details-modal" aria-label="%s"',
   208 						'class="thickbox open-plugin-details-modal" aria-label="%s"',
   205 						/* translators: 1: theme name, 2: version number */
   209 						/* translators: 1: Theme name, 2: Version number. */
   206 						esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme_name, $update['new_version'] ) )
   210 						esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme_name, $update['new_version'] ) )
   207 					),
   211 					),
   208 					$update['new_version']
   212 					$update['new_version']
   209 				);
   213 				);
   210 			} elseif ( empty( $update['package'] ) ) {
   214 			} elseif ( empty( $update['package'] ) ) {
   211 				/* translators: 1: theme name, 2: theme details URL, 3: additional link attributes, 4: version number */
       
   212 				$html = sprintf(
   215 				$html = sprintf(
       
   216 					/* translators: 1: Theme name, 2: Theme details URL, 3: Additional link attributes, 4: Version number. */
   213 					'<p><strong>' . __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>. <em>Automatic update is unavailable for this theme.</em>' ) . '</strong></p>',
   217 					'<p><strong>' . __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>. <em>Automatic update is unavailable for this theme.</em>' ) . '</strong></p>',
   214 					$theme_name,
   218 					$theme_name,
   215 					esc_url( $details_url ),
   219 					esc_url( $details_url ),
   216 					sprintf(
   220 					sprintf(
   217 						'class="thickbox open-plugin-details-modal" aria-label="%s"',
   221 						'class="thickbox open-plugin-details-modal" aria-label="%s"',
   218 						/* translators: 1: theme name, 2: version number */
   222 						/* translators: 1: Theme name, 2: Version number. */
   219 						esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme_name, $update['new_version'] ) )
   223 						esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme_name, $update['new_version'] ) )
   220 					),
   224 					),
   221 					$update['new_version']
   225 					$update['new_version']
   222 				);
   226 				);
   223 			} else {
   227 			} else {
   224 				/* translators: 1: theme name, 2: theme details URL, 3: additional link attributes, 4: version number, 5: update URL, 6: additional link attributes */
       
   225 				$html = sprintf(
   228 				$html = sprintf(
       
   229 					/* translators: 1: Theme name, 2: Theme details URL, 3: Additional link attributes, 4: Version number, 5: Update URL, 6: Additional link attributes. */
   226 					'<p><strong>' . __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a> or <a href="%5$s" %6$s>update now</a>.' ) . '</strong></p>',
   230 					'<p><strong>' . __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a> or <a href="%5$s" %6$s>update now</a>.' ) . '</strong></p>',
   227 					$theme_name,
   231 					$theme_name,
   228 					esc_url( $details_url ),
   232 					esc_url( $details_url ),
   229 					sprintf(
   233 					sprintf(
   230 						'class="thickbox open-plugin-details-modal" aria-label="%s"',
   234 						'class="thickbox open-plugin-details-modal" aria-label="%s"',
   231 						/* translators: 1: theme name, 2: version number */
   235 						/* translators: 1: Theme name, 2: Version number. */
   232 						esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme_name, $update['new_version'] ) )
   236 						esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme_name, $update['new_version'] ) )
   233 					),
   237 					),
   234 					$update['new_version'],
   238 					$update['new_version'],
   235 					$update_url,
   239 					$update_url,
   236 					sprintf(
   240 					sprintf(
   237 						'aria-label="%s" id="update-theme" data-slug="%s"',
   241 						'aria-label="%s" id="update-theme" data-slug="%s"',
   238 						/* translators: %s: theme name */
   242 						/* translators: %s: Theme name. */
   239 						esc_attr( sprintf( __( 'Update %s now' ), $theme_name ) ),
   243 						esc_attr( sprintf( _x( 'Update %s now', 'theme' ), $theme_name ) ),
   240 						$stylesheet
   244 						$stylesheet
   241 					)
   245 					)
   242 				);
   246 				);
   243 			}
   247 			}
   244 		}
   248 		}
   249 
   253 
   250 /**
   254 /**
   251  * Retrieve list of WordPress theme features (aka theme tags).
   255  * Retrieve list of WordPress theme features (aka theme tags).
   252  *
   256  *
   253  * @since 3.1.0
   257  * @since 3.1.0
       
   258  * @since 3.2.0 Added 'Gray' color and 'Featured Image Header', 'Featured Images',
       
   259  *              'Full Width Template', and 'Post Formats' features.
       
   260  * @since 3.5.0 Added 'Flexible Header' feature.
       
   261  * @since 3.8.0 Renamed 'Width' filter to 'Layout'.
       
   262  * @since 3.8.0 Renamed 'Fixed Width' and 'Flexible Width' options
       
   263  *              to 'Fixed Layout' and 'Fluid Layout'.
       
   264  * @since 3.8.0 Added 'Accessibility Ready' feature and 'Responsive Layout' option.
       
   265  * @since 3.9.0 Combined 'Layout' and 'Columns' filters.
       
   266  * @since 4.6.0 Removed 'Colors' filter.
       
   267  * @since 4.6.0 Added 'Grid Layout' option.
       
   268  *              Removed 'Fixed Layout', 'Fluid Layout', and 'Responsive Layout' options.
       
   269  * @since 4.6.0 Added 'Custom Logo' and 'Footer Widgets' features.
       
   270  *              Removed 'Blavatar' feature.
       
   271  * @since 4.6.0 Added 'Blog', 'E-Commerce', 'Education', 'Entertainment', 'Food & Drink',
       
   272  *              'Holiday', 'News', 'Photography', and 'Portfolio' subjects.
       
   273  *              Removed 'Photoblogging' and 'Seasonal' subjects.
       
   274  * @since 4.9.0 Reordered the filters from 'Layout', 'Features', 'Subject'
       
   275  *              to 'Subject', 'Features', 'Layout'.
       
   276  * @since 4.9.0 Removed 'BuddyPress', 'Custom Menu', 'Flexible Header',
       
   277  *              'Front Page Posting', 'Microformats', 'RTL Language Support',
       
   278  *              'Threaded Comments', and 'Translation Ready' features.
       
   279  * @since 5.5.0 Added 'Block Editor Patterns', 'Block Editor Styles',
       
   280  *              and 'Full Site Editing' features.
       
   281  * @since 5.5.0 Added 'Wide Blocks' layout option.
   254  *
   282  *
   255  * @param bool $api Optional. Whether try to fetch tags from the WordPress.org API. Defaults to true.
   283  * @param bool $api Optional. Whether try to fetch tags from the WordPress.org API. Defaults to true.
   256  * @return array Array of features keyed by category with translations keyed by slug.
   284  * @return array Array of features keyed by category with translations keyed by slug.
   257  */
   285  */
   258 function get_theme_feature_list( $api = true ) {
   286 function get_theme_feature_list( $api = true ) {
   259 	// Hard-coded list is used if api not accessible.
   287 	// Hard-coded list is used if API is not accessible.
   260 	$features = array(
   288 	$features = array(
   261 
   289 
   262 		__( 'Subject' )  => array(
   290 		__( 'Subject' )  => array(
   263 			'blog'           => __( 'Blog' ),
   291 			'blog'           => __( 'Blog' ),
   264 			'e-commerce'     => __( 'E-Commerce' ),
   292 			'e-commerce'     => __( 'E-Commerce' ),
   271 			'portfolio'      => __( 'Portfolio' ),
   299 			'portfolio'      => __( 'Portfolio' ),
   272 		),
   300 		),
   273 
   301 
   274 		__( 'Features' ) => array(
   302 		__( 'Features' ) => array(
   275 			'accessibility-ready'   => __( 'Accessibility Ready' ),
   303 			'accessibility-ready'   => __( 'Accessibility Ready' ),
       
   304 			'block-patterns'        => __( 'Block Editor Patterns' ),
       
   305 			'block-styles'          => __( 'Block Editor Styles' ),
   276 			'custom-background'     => __( 'Custom Background' ),
   306 			'custom-background'     => __( 'Custom Background' ),
   277 			'custom-colors'         => __( 'Custom Colors' ),
   307 			'custom-colors'         => __( 'Custom Colors' ),
   278 			'custom-header'         => __( 'Custom Header' ),
   308 			'custom-header'         => __( 'Custom Header' ),
   279 			'custom-logo'           => __( 'Custom Logo' ),
   309 			'custom-logo'           => __( 'Custom Logo' ),
   280 			'editor-style'          => __( 'Editor Style' ),
   310 			'editor-style'          => __( 'Editor Style' ),
   281 			'featured-image-header' => __( 'Featured Image Header' ),
   311 			'featured-image-header' => __( 'Featured Image Header' ),
   282 			'featured-images'       => __( 'Featured Images' ),
   312 			'featured-images'       => __( 'Featured Images' ),
   283 			'footer-widgets'        => __( 'Footer Widgets' ),
   313 			'footer-widgets'        => __( 'Footer Widgets' ),
       
   314 			'full-site-editing'     => __( 'Full Site Editing' ),
   284 			'full-width-template'   => __( 'Full Width Template' ),
   315 			'full-width-template'   => __( 'Full Width Template' ),
   285 			'post-formats'          => __( 'Post Formats' ),
   316 			'post-formats'          => __( 'Post Formats' ),
   286 			'sticky-post'           => __( 'Sticky Post' ),
   317 			'sticky-post'           => __( 'Sticky Post' ),
   287 			'theme-options'         => __( 'Theme Options' ),
   318 			'theme-options'         => __( 'Theme Options' ),
   288 		),
   319 		),
   293 			'two-columns'   => __( 'Two Columns' ),
   324 			'two-columns'   => __( 'Two Columns' ),
   294 			'three-columns' => __( 'Three Columns' ),
   325 			'three-columns' => __( 'Three Columns' ),
   295 			'four-columns'  => __( 'Four Columns' ),
   326 			'four-columns'  => __( 'Four Columns' ),
   296 			'left-sidebar'  => __( 'Left Sidebar' ),
   327 			'left-sidebar'  => __( 'Left Sidebar' ),
   297 			'right-sidebar' => __( 'Right Sidebar' ),
   328 			'right-sidebar' => __( 'Right Sidebar' ),
       
   329 			'wide-blocks'   => __( 'Wide Blocks' ),
   298 		),
   330 		),
   299 
   331 
   300 	);
   332 	);
   301 
   333 
   302 	if ( ! $api || ! current_user_can( 'install_themes' ) ) {
   334 	if ( ! $api || ! current_user_can( 'install_themes' ) ) {
   303 		return $features;
   335 		return $features;
   304 	}
   336 	}
   305 
   337 
   306 	if ( ! $feature_list = get_site_transient( 'wporg_theme_feature_list' ) ) {
   338 	$feature_list = get_site_transient( 'wporg_theme_feature_list' );
       
   339 	if ( ! $feature_list ) {
   307 		set_site_transient( 'wporg_theme_feature_list', array(), 3 * HOUR_IN_SECONDS );
   340 		set_site_transient( 'wporg_theme_feature_list', array(), 3 * HOUR_IN_SECONDS );
   308 	}
   341 	}
   309 
   342 
   310 	if ( ! $feature_list ) {
   343 	if ( ! $feature_list ) {
   311 		$feature_list = themes_api( 'feature_list', array() );
   344 		$feature_list = themes_api( 'feature_list', array() );
   324 		'Layout'   => __( 'Layout' ),
   357 		'Layout'   => __( 'Layout' ),
   325 		'Features' => __( 'Features' ),
   358 		'Features' => __( 'Features' ),
   326 		'Subject'  => __( 'Subject' ),
   359 		'Subject'  => __( 'Subject' ),
   327 	);
   360 	);
   328 
   361 
   329 	// Loop over the wporg canonical list and apply translations
       
   330 	$wporg_features = array();
   362 	$wporg_features = array();
       
   363 
       
   364 	// Loop over the wp.org canonical list and apply translations.
   331 	foreach ( (array) $feature_list as $feature_category => $feature_items ) {
   365 	foreach ( (array) $feature_list as $feature_category => $feature_items ) {
   332 		if ( isset( $category_translations[ $feature_category ] ) ) {
   366 		if ( isset( $category_translations[ $feature_category ] ) ) {
   333 			$feature_category = $category_translations[ $feature_category ];
   367 			$feature_category = $category_translations[ $feature_category ];
   334 		}
   368 		}
       
   369 
   335 		$wporg_features[ $feature_category ] = array();
   370 		$wporg_features[ $feature_category ] = array();
   336 
   371 
   337 		foreach ( $feature_items as $feature ) {
   372 		foreach ( $feature_items as $feature ) {
   338 			if ( isset( $features[ $feature_category ][ $feature ] ) ) {
   373 			if ( isset( $features[ $feature_category ][ $feature ] ) ) {
   339 				$wporg_features[ $feature_category ][ $feature ] = $features[ $feature_category ][ $feature ];
   374 				$wporg_features[ $feature_category ][ $feature ] = $features[ $feature_category ][ $feature ];
   426  * @return object|array|WP_Error Response object or array on success, WP_Error on failure. See the
   461  * @return object|array|WP_Error Response object or array on success, WP_Error on failure. See the
   427  *         {@link https://developer.wordpress.org/reference/functions/themes_api/ function reference article}
   462  *         {@link https://developer.wordpress.org/reference/functions/themes_api/ function reference article}
   428  *         for more information on the make-up of possible return objects depending on the value of `$action`.
   463  *         for more information on the make-up of possible return objects depending on the value of `$action`.
   429  */
   464  */
   430 function themes_api( $action, $args = array() ) {
   465 function themes_api( $action, $args = array() ) {
   431 	// include an unmodified $wp_version
   466 	// Include an unmodified $wp_version.
   432 	include( ABSPATH . WPINC . '/version.php' );
   467 	require ABSPATH . WPINC . '/version.php';
   433 
   468 
   434 	if ( is_array( $args ) ) {
   469 	if ( is_array( $args ) ) {
   435 		$args = (object) $args;
   470 		$args = (object) $args;
   436 	}
   471 	}
   437 
   472 
   438 	if ( 'query_themes' == $action ) {
   473 	if ( 'query_themes' === $action ) {
   439 		if ( ! isset( $args->per_page ) ) {
   474 		if ( ! isset( $args->per_page ) ) {
   440 			$args->per_page = 24;
   475 			$args->per_page = 24;
   441 		}
   476 		}
   442 	}
   477 	}
   443 
   478 
   444 	if ( ! isset( $args->locale ) ) {
   479 	if ( ! isset( $args->locale ) ) {
   445 		$args->locale = get_user_locale();
   480 		$args->locale = get_user_locale();
   446 	}
   481 	}
   447 
   482 
   448 	if ( ! isset( $args->wp_version ) ) {
   483 	if ( ! isset( $args->wp_version ) ) {
   449 		$args->wp_version = substr( $wp_version, 0, 3 ); // X.y
   484 		$args->wp_version = substr( $wp_version, 0, 3 ); // x.y
   450 	}
   485 	}
   451 
   486 
   452 	/**
   487 	/**
   453 	 * Filters arguments used to query for installer pages from the WordPress.org Themes API.
   488 	 * Filters arguments used to query for installer pages from the WordPress.org Themes API.
   454 	 *
   489 	 *
   488 			),
   523 			),
   489 			$url
   524 			$url
   490 		);
   525 		);
   491 
   526 
   492 		$http_url = $url;
   527 		$http_url = $url;
   493 		if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) {
   528 		$ssl      = wp_http_supports( array( 'ssl' ) );
       
   529 		if ( $ssl ) {
   494 			$url = set_url_scheme( $url, 'https' );
   530 			$url = set_url_scheme( $url, 'https' );
   495 		}
   531 		}
   496 
   532 
   497 		$http_args = array(
   533 		$http_args = array(
   498 			'user-agent' => 'WordPress/' . $wp_version . '; ' . home_url( '/' ),
   534 			'user-agent' => 'WordPress/' . $wp_version . '; ' . home_url( '/' ),
   501 
   537 
   502 		if ( $ssl && is_wp_error( $request ) ) {
   538 		if ( $ssl && is_wp_error( $request ) ) {
   503 			if ( ! wp_doing_ajax() ) {
   539 			if ( ! wp_doing_ajax() ) {
   504 				trigger_error(
   540 				trigger_error(
   505 					sprintf(
   541 					sprintf(
   506 						/* translators: %s: support forums URL */
   542 						/* translators: %s: Support forums URL. */
   507 						__( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ),
   543 						__( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ),
   508 						__( 'https://wordpress.org/support/' )
   544 						__( 'https://wordpress.org/support/forums/' )
   509 					) . ' ' . __( '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' ),
   545 					) . ' ' . __( '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' ),
   510 					headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE
   546 					headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE
   511 				);
   547 				);
   512 			}
   548 			}
   513 			$request = wp_remote_get( $http_url, $http_args );
   549 			$request = wp_remote_get( $http_url, $http_args );
   515 
   551 
   516 		if ( is_wp_error( $request ) ) {
   552 		if ( is_wp_error( $request ) ) {
   517 			$res = new WP_Error(
   553 			$res = new WP_Error(
   518 				'themes_api_failed',
   554 				'themes_api_failed',
   519 				sprintf(
   555 				sprintf(
   520 					/* translators: %s: support forums URL */
   556 					/* translators: %s: Support forums URL. */
   521 					__( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ),
   557 					__( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ),
   522 					__( 'https://wordpress.org/support/' )
   558 					__( 'https://wordpress.org/support/forums/' )
   523 				),
   559 				),
   524 				$request->get_error_message()
   560 				$request->get_error_message()
   525 			);
   561 			);
   526 		} else {
   562 		} else {
   527 			$res = json_decode( wp_remote_retrieve_body( $request ), true );
   563 			$res = json_decode( wp_remote_retrieve_body( $request ), true );
   530 				$res = (object) $res;
   566 				$res = (object) $res;
   531 			} elseif ( null === $res ) {
   567 			} elseif ( null === $res ) {
   532 				$res = new WP_Error(
   568 				$res = new WP_Error(
   533 					'themes_api_failed',
   569 					'themes_api_failed',
   534 					sprintf(
   570 					sprintf(
   535 						/* translators: %s: support forums URL */
   571 						/* translators: %s: Support forums URL. */
   536 						__( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ),
   572 						__( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ),
   537 						__( 'https://wordpress.org/support/' )
   573 						__( 'https://wordpress.org/support/forums/' )
   538 					),
   574 					),
   539 					wp_remote_retrieve_body( $request )
   575 					wp_remote_retrieve_body( $request )
   540 				);
   576 				);
   541 			}
   577 			}
   542 
   578 
   544 				$res = new WP_Error( 'themes_api_failed', $res->error );
   580 				$res = new WP_Error( 'themes_api_failed', $res->error );
   545 			}
   581 			}
   546 		}
   582 		}
   547 
   583 
   548 		// Back-compat for info/1.2 API, upgrade the theme objects in query_themes to objects.
   584 		// Back-compat for info/1.2 API, upgrade the theme objects in query_themes to objects.
   549 		if ( 'query_themes' == $action ) {
   585 		if ( 'query_themes' === $action ) {
   550 			foreach ( $res->themes as $i => $theme ) {
   586 			foreach ( $res->themes as $i => $theme ) {
   551 				$res->themes[ $i ] = (object) $theme;
   587 				$res->themes[ $i ] = (object) $theme;
   552 			}
   588 			}
   553 		}
   589 		}
   554 		// Back-compat for info/1.2 API, downgrade the feature_list result back to an array.
   590 		// Back-compat for info/1.2 API, downgrade the feature_list result back to an array.
   555 		if ( 'feature_list' == $action ) {
   591 		if ( 'feature_list' === $action ) {
   556 			$res = (array) $res;
   592 			$res = (array) $res;
   557 		}
   593 		}
   558 	}
   594 	}
   559 
   595 
   560 	/**
   596 	/**
   609 		if ( ! isset( $themes[ $current_theme ] ) ) {
   645 		if ( ! isset( $themes[ $current_theme ] ) ) {
   610 			$themes[ $current_theme ] = wp_get_theme();
   646 			$themes[ $current_theme ] = wp_get_theme();
   611 		}
   647 		}
   612 	}
   648 	}
   613 
   649 
   614 	$updates = array();
   650 	$updates    = array();
       
   651 	$no_updates = array();
   615 	if ( current_user_can( 'update_themes' ) ) {
   652 	if ( current_user_can( 'update_themes' ) ) {
   616 		$updates_transient = get_site_transient( 'update_themes' );
   653 		$updates_transient = get_site_transient( 'update_themes' );
   617 		if ( isset( $updates_transient->response ) ) {
   654 		if ( isset( $updates_transient->response ) ) {
   618 			$updates = $updates_transient->response;
   655 			$updates = $updates_transient->response;
   619 		}
   656 		}
       
   657 		if ( isset( $updates_transient->no_update ) ) {
       
   658 			$no_updates = $updates_transient->no_update;
       
   659 		}
   620 	}
   660 	}
   621 
   661 
   622 	WP_Theme::sort_by_name( $themes );
   662 	WP_Theme::sort_by_name( $themes );
   623 
   663 
   624 	$parents = array();
   664 	$parents = array();
       
   665 
       
   666 	$auto_updates = (array) get_site_option( 'auto_update_themes', array() );
   625 
   667 
   626 	foreach ( $themes as $theme ) {
   668 	foreach ( $themes as $theme ) {
   627 		$slug         = $theme->get_stylesheet();
   669 		$slug         = $theme->get_stylesheet();
   628 		$encoded_slug = urlencode( $slug );
   670 		$encoded_slug = urlencode( $slug );
   629 
   671 
   644 					wp_customize_url( $slug )
   686 					wp_customize_url( $slug )
   645 				)
   687 				)
   646 			);
   688 			);
   647 		}
   689 		}
   648 
   690 
       
   691 		$update_requires_wp  = isset( $updates[ $slug ]['requires'] ) ? $updates[ $slug ]['requires'] : null;
       
   692 		$update_requires_php = isset( $updates[ $slug ]['requires_php'] ) ? $updates[ $slug ]['requires_php'] : null;
       
   693 
       
   694 		$auto_update        = in_array( $slug, $auto_updates, true );
       
   695 		$auto_update_action = $auto_update ? 'disable-auto-update' : 'enable-auto-update';
       
   696 
       
   697 		if ( isset( $updates[ $slug ] ) ) {
       
   698 			$auto_update_supported      = true;
       
   699 			$auto_update_filter_payload = (object) $updates[ $slug ];
       
   700 		} elseif ( isset( $no_updates[ $slug ] ) ) {
       
   701 			$auto_update_supported      = true;
       
   702 			$auto_update_filter_payload = (object) $no_updates[ $slug ];
       
   703 		} else {
       
   704 			$auto_update_supported = false;
       
   705 			/*
       
   706 			 * Create the expected payload for the auto_update_theme filter, this is the same data
       
   707 			 * as contained within $updates or $no_updates but used when the Theme is not known.
       
   708 			 */
       
   709 			$auto_update_filter_payload = (object) array(
       
   710 				'theme'        => $slug,
       
   711 				'new_version'  => $theme->get( 'Version' ),
       
   712 				'url'          => '',
       
   713 				'package'      => '',
       
   714 				'requires'     => $theme->get( 'RequiresWP' ),
       
   715 				'requires_php' => $theme->get( 'RequiresPHP' ),
       
   716 			);
       
   717 		}
       
   718 
       
   719 		$type = 'theme';
       
   720 		/** This filter is documented in wp-admin/includes/class-wp-automatic-updater.php */
       
   721 		$auto_update_forced = apply_filters( "auto_update_{$type}", null, $auto_update_filter_payload );
       
   722 
   649 		$prepared_themes[ $slug ] = array(
   723 		$prepared_themes[ $slug ] = array(
   650 			'id'           => $slug,
   724 			'id'             => $slug,
   651 			'name'         => $theme->display( 'Name' ),
   725 			'name'           => $theme->display( 'Name' ),
   652 			'screenshot'   => array( $theme->get_screenshot() ), // @todo multiple
   726 			'screenshot'     => array( $theme->get_screenshot() ), // @todo Multiple screenshots.
   653 			'description'  => $theme->display( 'Description' ),
   727 			'description'    => $theme->display( 'Description' ),
   654 			'author'       => $theme->display( 'Author', false, true ),
   728 			'author'         => $theme->display( 'Author', false, true ),
   655 			'authorAndUri' => $theme->display( 'Author' ),
   729 			'authorAndUri'   => $theme->display( 'Author' ),
   656 			'version'      => $theme->display( 'Version' ),
   730 			'tags'           => $theme->display( 'Tags' ),
   657 			'tags'         => $theme->display( 'Tags' ),
   731 			'version'        => $theme->get( 'Version' ),
   658 			'parent'       => $parent,
   732 			'compatibleWP'   => is_wp_version_compatible( $theme->get( 'RequiresWP' ) ),
   659 			'active'       => $slug === $current_theme,
   733 			'compatiblePHP'  => is_php_version_compatible( $theme->get( 'RequiresPHP' ) ),
   660 			'hasUpdate'    => isset( $updates[ $slug ] ),
   734 			'updateResponse' => array(
   661 			'hasPackage'   => isset( $updates[ $slug ] ) && ! empty( $updates[ $slug ]['package'] ),
   735 				'compatibleWP'  => is_wp_version_compatible( $update_requires_wp ),
   662 			'update'       => get_theme_update_available( $theme ),
   736 				'compatiblePHP' => is_php_version_compatible( $update_requires_php ),
   663 			'actions'      => array(
   737 			),
   664 				'activate'  => current_user_can( 'switch_themes' ) ? wp_nonce_url( admin_url( 'themes.php?action=activate&amp;stylesheet=' . $encoded_slug ), 'switch-theme_' . $slug ) : null,
   738 			'parent'         => $parent,
   665 				'customize' => $customize_action,
   739 			'active'         => $slug === $current_theme,
   666 				'delete'    => current_user_can( 'delete_themes' ) ? wp_nonce_url( admin_url( 'themes.php?action=delete&amp;stylesheet=' . $encoded_slug ), 'delete-theme_' . $slug ) : null,
   740 			'hasUpdate'      => isset( $updates[ $slug ] ),
       
   741 			'hasPackage'     => isset( $updates[ $slug ] ) && ! empty( $updates[ $slug ]['package'] ),
       
   742 			'update'         => get_theme_update_available( $theme ),
       
   743 			'autoupdate'     => array(
       
   744 				'enabled'   => $auto_update || $auto_update_forced,
       
   745 				'supported' => $auto_update_supported,
       
   746 				'forced'    => $auto_update_forced,
       
   747 			),
       
   748 			'actions'        => array(
       
   749 				'activate'   => current_user_can( 'switch_themes' ) ? wp_nonce_url( admin_url( 'themes.php?action=activate&amp;stylesheet=' . $encoded_slug ), 'switch-theme_' . $slug ) : null,
       
   750 				'customize'  => $customize_action,
       
   751 				'delete'     => current_user_can( 'delete_themes' ) ? wp_nonce_url( admin_url( 'themes.php?action=delete&amp;stylesheet=' . $encoded_slug ), 'delete-theme_' . $slug ) : null,
       
   752 				'autoupdate' => wp_is_auto_update_enabled_for_type( 'theme' ) && ! is_multisite() && current_user_can( 'update_themes' )
       
   753 					? wp_nonce_url( admin_url( 'themes.php?action=' . $auto_update_action . '&amp;stylesheet=' . $encoded_slug ), 'updates' )
       
   754 					: null,
   667 			),
   755 			),
   668 		);
   756 		);
   669 	}
   757 	}
   670 
   758 
   671 	// Remove 'delete' action if theme has an active child
   759 	// Remove 'delete' action if theme has an active child.
   672 	if ( ! empty( $parents ) && array_key_exists( $current_theme, $parents ) ) {
   760 	if ( ! empty( $parents ) && array_key_exists( $current_theme, $parents ) ) {
   673 		unset( $prepared_themes[ $parents[ $current_theme ] ]['actions']['delete'] );
   761 		unset( $prepared_themes[ $parents[ $current_theme ] ]['actions']['delete'] );
   674 	}
   762 	}
   675 
   763 
   676 	/**
   764 	/**
   678 	 *
   766 	 *
   679 	 * Could be useful for changing the order, which is by name by default.
   767 	 * Could be useful for changing the order, which is by name by default.
   680 	 *
   768 	 *
   681 	 * @since 3.8.0
   769 	 * @since 3.8.0
   682 	 *
   770 	 *
   683 	 * @param array $prepared_themes Array of themes.
   771 	 * @param array $prepared_themes Array of theme data.
   684 	 */
   772 	 */
   685 	$prepared_themes = apply_filters( 'wp_prepare_themes_for_js', $prepared_themes );
   773 	$prepared_themes = apply_filters( 'wp_prepare_themes_for_js', $prepared_themes );
   686 	$prepared_themes = array_values( $prepared_themes );
   774 	$prepared_themes = array_values( $prepared_themes );
   687 	return array_filter( $prepared_themes );
   775 	return array_filter( $prepared_themes );
   688 }
   776 }
   713 
   801 
   714 				<div class="theme-info">
   802 				<div class="theme-info">
   715 					<# if ( data.active ) { #>
   803 					<# if ( data.active ) { #>
   716 						<span class="current-label"><?php _e( 'Current Theme' ); ?></span>
   804 						<span class="current-label"><?php _e( 'Current Theme' ); ?></span>
   717 					<# } #>
   805 					<# } #>
   718 					<h2 class="theme-name">{{{ data.name }}}<span class="theme-version"><?php printf( __( 'Version: %s' ), '{{ data.version }}' ); ?></span></h2>
   806 					<h2 class="theme-name">{{{ data.name }}}<span class="theme-version">
   719 					<h3 class="theme-author"><?php printf( __( 'By %s' ), '{{{ data.authorAndUri }}}' ); ?></h3>
   807 						<?php
       
   808 						/* translators: %s: Theme version. */
       
   809 						printf( __( 'Version: %s' ), '{{ data.version }}' );
       
   810 						?>
       
   811 					</span></h2>
       
   812 					<h3 class="theme-author">
       
   813 						<?php
       
   814 						/* translators: %s: Theme author link. */
       
   815 						printf( __( 'By %s' ), '{{{ data.authorAndUri }}}' );
       
   816 						?>
       
   817 					</h3>
   720 
   818 
   721 					<# if ( data.stars && 0 != data.num_ratings ) { #>
   819 					<# if ( data.stars && 0 != data.num_ratings ) { #>
   722 						<div class="theme-rating">
   820 						<div class="theme-rating">
   723 							{{{ data.stars }}}
   821 							{{{ data.stars }}}
   724 							<a class="num-ratings" target="_blank" href="{{ data.reviews_url }}">
   822 							<a class="num-ratings" target="_blank" href="{{ data.reviews_url }}">
   725 								<?php
   823 								<?php
   726 								printf(
   824 								printf(
   727 									'%1$s <span class="screen-reader-text">%2$s</span>',
   825 									'%1$s <span class="screen-reader-text">%2$s</span>',
   728 									/* translators: %s: number of ratings */
   826 									/* translators: %s: Number of ratings. */
   729 									sprintf( __( '(%s ratings)' ), '{{ data.num_ratings }}' ),
   827 									sprintf( __( '(%s ratings)' ), '{{ data.num_ratings }}' ),
   730 									/* translators: accessibility text */
   828 									/* translators: Accessibility text. */
   731 									__( '(opens in a new tab)' )
   829 									__( '(opens in a new tab)' )
   732 								);
   830 								);
   733 								?>
   831 								?>
   734 							</a>
   832 							</a>
   735 						</div>
   833 						</div>
   736 					<# } #>
   834 					<# } #>
   737 
   835 
   738 					<# if ( data.hasUpdate ) { #>
   836 					<# if ( data.hasUpdate ) { #>
   739 						<div class="notice notice-warning notice-alt notice-large" data-slug="{{ data.id }}">
   837 						<# if ( data.updateResponse.compatibleWP && data.updateResponse.compatiblePHP ) { #>
   740 							<h3 class="notice-title"><?php _e( 'Update Available' ); ?></h3>
   838 							<div class="notice notice-warning notice-alt notice-large" data-slug="{{ data.id }}">
   741 							{{{ data.update }}}
   839 								<h3 class="notice-title"><?php _e( 'Update Available' ); ?></h3>
   742 						</div>
   840 								{{{ data.update }}}
       
   841 							</div>
       
   842 						<# } else { #>
       
   843 							<div class="notice notice-error notice-alt notice-large" data-slug="{{ data.id }}">
       
   844 								<h3 class="notice-title"><?php _e( 'Update Incompatible' ); ?></h3>
       
   845 								<p>
       
   846 									<# if ( ! data.updateResponse.compatibleWP && ! data.updateResponse.compatiblePHP ) { #>
       
   847 										<?php
       
   848 										printf(
       
   849 											/* translators: %s: Theme name. */
       
   850 											__( 'There is a new version of %s available, but it doesn&#8217;t work with your versions of WordPress and PHP.' ),
       
   851 											'{{{ data.name }}}'
       
   852 										);
       
   853 										if ( current_user_can( 'update_core' ) && current_user_can( 'update_php' ) ) {
       
   854 											printf(
       
   855 												/* translators: 1: URL to WordPress Updates screen, 2: URL to Update PHP page. */
       
   856 												' ' . __( '<a href="%1$s">Please update WordPress</a>, and then <a href="%2$s">learn more about updating PHP</a>.' ),
       
   857 												self_admin_url( 'update-core.php' ),
       
   858 												esc_url( wp_get_update_php_url() )
       
   859 											);
       
   860 											wp_update_php_annotation( '</p><p><em>', '</em>' );
       
   861 										} elseif ( current_user_can( 'update_core' ) ) {
       
   862 											printf(
       
   863 												/* translators: %s: URL to WordPress Updates screen. */
       
   864 												' ' . __( '<a href="%s">Please update WordPress</a>.' ),
       
   865 												self_admin_url( 'update-core.php' )
       
   866 											);
       
   867 										} elseif ( current_user_can( 'update_php' ) ) {
       
   868 											printf(
       
   869 												/* translators: %s: URL to Update PHP page. */
       
   870 												' ' . __( '<a href="%s">Learn more about updating PHP</a>.' ),
       
   871 												esc_url( wp_get_update_php_url() )
       
   872 											);
       
   873 											wp_update_php_annotation( '</p><p><em>', '</em>' );
       
   874 										}
       
   875 										?>
       
   876 									<# } else if ( ! data.updateResponse.compatibleWP ) { #>
       
   877 										<?php
       
   878 										printf(
       
   879 											/* translators: %s: Theme name. */
       
   880 											__( 'There is a new version of %s available, but it doesn&#8217;t work with your version of WordPress.' ),
       
   881 											'{{{ data.name }}}'
       
   882 										);
       
   883 										if ( current_user_can( 'update_core' ) ) {
       
   884 											printf(
       
   885 												/* translators: %s: URL to WordPress Updates screen. */
       
   886 												' ' . __( '<a href="%s">Please update WordPress</a>.' ),
       
   887 												self_admin_url( 'update-core.php' )
       
   888 											);
       
   889 										}
       
   890 										?>
       
   891 									<# } else if ( ! data.updateResponse.compatiblePHP ) { #>
       
   892 										<?php
       
   893 										printf(
       
   894 											/* translators: %s: Theme name. */
       
   895 											__( 'There is a new version of %s available, but it doesn&#8217;t work with your version of PHP.' ),
       
   896 											'{{{ data.name }}}'
       
   897 										);
       
   898 										if ( current_user_can( 'update_php' ) ) {
       
   899 											printf(
       
   900 												/* translators: %s: URL to Update PHP page. */
       
   901 												' ' . __( '<a href="%s">Learn more about updating PHP</a>.' ),
       
   902 												esc_url( wp_get_update_php_url() )
       
   903 											);
       
   904 											wp_update_php_annotation( '</p><p><em>', '</em>' );
       
   905 										}
       
   906 										?>
       
   907 									<# } #>
       
   908 								</p>
       
   909 							</div>
       
   910 						<# } #>
   743 					<# } #>
   911 					<# } #>
   744 
   912 
   745 					<# if ( data.parent ) { #>
   913 					<# if ( data.parent ) { #>
   746 						<p class="parent-theme"><?php printf( __( 'This is a child theme of %s.' ), '<strong>{{{ data.parent }}}</strong>' ); ?></p>
   914 						<p class="parent-theme">
       
   915 							<?php
       
   916 							printf(
       
   917 								/* translators: %s: Theme name. */
       
   918 								__( 'This is a child theme of %s.' ),
       
   919 								'<strong>{{{ data.parent }}}</strong>'
       
   920 							);
       
   921 							?>
       
   922 						</p>
       
   923 					<# } #>
       
   924 
       
   925 					<# if ( ! data.compatibleWP || ! data.compatiblePHP ) { #>
       
   926 						<div class="notice notice-error notice-alt notice-large"><p>
       
   927 							<# if ( ! data.compatibleWP && ! data.compatiblePHP ) { #>
       
   928 								<?php
       
   929 								_e( 'This theme doesn&#8217;t work with your versions of WordPress and PHP.' );
       
   930 								if ( current_user_can( 'update_core' ) && current_user_can( 'update_php' ) ) {
       
   931 									printf(
       
   932 										/* translators: 1: URL to WordPress Updates screen, 2: URL to Update PHP page. */
       
   933 										' ' . __( '<a href="%1$s">Please update WordPress</a>, and then <a href="%2$s">learn more about updating PHP</a>.' ),
       
   934 										self_admin_url( 'update-core.php' ),
       
   935 										esc_url( wp_get_update_php_url() )
       
   936 									);
       
   937 									wp_update_php_annotation( '</p><p><em>', '</em>' );
       
   938 								} elseif ( current_user_can( 'update_core' ) ) {
       
   939 									printf(
       
   940 										/* translators: %s: URL to WordPress Updates screen. */
       
   941 										' ' . __( '<a href="%s">Please update WordPress</a>.' ),
       
   942 										self_admin_url( 'update-core.php' )
       
   943 									);
       
   944 								} elseif ( current_user_can( 'update_php' ) ) {
       
   945 									printf(
       
   946 										/* translators: %s: URL to Update PHP page. */
       
   947 										' ' . __( '<a href="%s">Learn more about updating PHP</a>.' ),
       
   948 										esc_url( wp_get_update_php_url() )
       
   949 									);
       
   950 									wp_update_php_annotation( '</p><p><em>', '</em>' );
       
   951 								}
       
   952 								?>
       
   953 							<# } else if ( ! data.compatibleWP ) { #>
       
   954 								<?php
       
   955 								_e( 'This theme doesn&#8217;t work with your version of WordPress.' );
       
   956 								if ( current_user_can( 'update_core' ) ) {
       
   957 									printf(
       
   958 										/* translators: %s: URL to WordPress Updates screen. */
       
   959 										' ' . __( '<a href="%s">Please update WordPress</a>.' ),
       
   960 										self_admin_url( 'update-core.php' )
       
   961 									);
       
   962 								}
       
   963 								?>
       
   964 							<# } else if ( ! data.compatiblePHP ) { #>
       
   965 								<?php
       
   966 								_e( 'This theme doesn&#8217;t work with your version of PHP.' );
       
   967 								if ( current_user_can( 'update_php' ) ) {
       
   968 									printf(
       
   969 										/* translators: %s: URL to Update PHP page. */
       
   970 										' ' . __( '<a href="%s">Learn more about updating PHP</a>.' ),
       
   971 										esc_url( wp_get_update_php_url() )
       
   972 									);
       
   973 									wp_update_php_annotation( '</p><p><em>', '</em>' );
       
   974 								}
       
   975 								?>
       
   976 							<# } #>
       
   977 						</p></div>
   747 					<# } #>
   978 					<# } #>
   748 
   979 
   749 					<p class="theme-description">{{{ data.description }}}</p>
   980 					<p class="theme-description">{{{ data.description }}}</p>
   750 
   981 
   751 					<# if ( data.tags ) { #>
   982 					<# if ( data.tags ) { #>
   761 					<?php if ( current_user_can( 'delete_themes' ) ) { ?>
   992 					<?php if ( current_user_can( 'delete_themes' ) ) { ?>
   762 						<# if ( data.actions && data.actions['delete'] ) { #>
   993 						<# if ( data.actions && data.actions['delete'] ) { #>
   763 							<a href="{{{ data.actions['delete'] }}}" data-slug="{{ data.id }}" class="button button-secondary delete-theme"><?php _e( 'Delete' ); ?></a>
   994 							<a href="{{{ data.actions['delete'] }}}" data-slug="{{ data.id }}" class="button button-secondary delete-theme"><?php _e( 'Delete' ); ?></a>
   764 						<# } #>
   995 						<# } #>
   765 					<?php } ?>
   996 					<?php } ?>
   766 					<button type="button" class="button button-primary preview-theme" data-slug="{{ data.id }}"><?php _e( 'Live Preview' ); ?></button>
   997 
       
   998 					<# if ( data.compatibleWP && data.compatiblePHP ) { #>
       
   999 						<button type="button" class="button button-primary preview-theme" data-slug="{{ data.id }}"><?php _e( 'Live Preview' ); ?></button>
       
  1000 					<# } else { #>
       
  1001 						<button class="button button-primary disabled"><?php _e( 'Live Preview' ); ?></button>
       
  1002 					<# } #>
   767 				<# } else { #>
  1003 				<# } else { #>
   768 					<button type="button" class="button theme-install" data-slug="{{ data.id }}"><?php _e( 'Install' ); ?></button>
  1004 					<# if ( data.compatibleWP && data.compatiblePHP ) { #>
   769 					<button type="button" class="button button-primary theme-install preview" data-slug="{{ data.id }}"><?php _e( 'Install &amp; Preview' ); ?></button>
  1005 						<button type="button" class="button theme-install" data-slug="{{ data.id }}"><?php _e( 'Install' ); ?></button>
       
  1006 						<button type="button" class="button button-primary theme-install preview" data-slug="{{ data.id }}"><?php _e( 'Install &amp; Preview' ); ?></button>
       
  1007 					<# } else { #>
       
  1008 						<button type="button" class="button disabled"><?php _ex( 'Cannot Install', 'theme' ); ?></button>
       
  1009 						<button type="button" class="button button-primary disabled"><?php _e( 'Install &amp; Preview' ); ?></button>
       
  1010 					<# } #>
   770 				<# } #>
  1011 				<# } #>
   771 			</div>
  1012 			</div>
   772 		</div>
  1013 		</div>
   773 	</script>
  1014 	</script>
   774 	<?php
  1015 	<?php