Theme Installer: Revert to proxying through PHP for WordPress.org API requests.
This is to ensure we have valid installation nonces, though we've run into this as a problem previously (see #27639, #27581, #27055). A tad slower, but we gained speed in 3.9 by simplifying the request made to the API. props ocean90. fixes #27798. Built from https://develop.svn.wordpress.org/trunk@28126 git-svn-id: http://core.svn.wordpress.org/trunk@27957 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
d1e72b8e20
commit
9f81d0526e
|
@ -58,7 +58,7 @@ $core_actions_post = array(
|
||||||
'wp-remove-post-lock', 'dismiss-wp-pointer', 'upload-attachment', 'get-attachment',
|
'wp-remove-post-lock', 'dismiss-wp-pointer', 'upload-attachment', 'get-attachment',
|
||||||
'query-attachments', 'save-attachment', 'save-attachment-compat', 'send-link-to-editor',
|
'query-attachments', 'save-attachment', 'save-attachment-compat', 'send-link-to-editor',
|
||||||
'send-attachment-to-editor', 'save-attachment-order', 'heartbeat', 'get-revision-diffs',
|
'send-attachment-to-editor', 'save-attachment-order', 'heartbeat', 'get-revision-diffs',
|
||||||
'save-user-color-scheme', 'update-widget',
|
'save-user-color-scheme', 'update-widget', 'query-themes',
|
||||||
);
|
);
|
||||||
|
|
||||||
// Register core Ajax calls.
|
// Register core Ajax calls.
|
||||||
|
|
|
@ -2204,3 +2204,48 @@ function wp_ajax_save_user_color_scheme() {
|
||||||
update_user_meta( get_current_user_id(), 'admin_color', $color_scheme );
|
update_user_meta( get_current_user_id(), 'admin_color', $color_scheme );
|
||||||
wp_send_json_success();
|
wp_send_json_success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get themes from themes_api().
|
||||||
|
*
|
||||||
|
* @since 3.9.0
|
||||||
|
*/
|
||||||
|
function wp_ajax_query_themes() {
|
||||||
|
global $themes_allowedtags, $theme_field_defaults;
|
||||||
|
|
||||||
|
if ( ! current_user_can( 'install_themes' ) ) {
|
||||||
|
wp_send_json_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
$args = wp_parse_args( wp_unslash( $_REQUEST['request'] ), array(
|
||||||
|
'per_page' => 20,
|
||||||
|
'fields' => $theme_field_defaults
|
||||||
|
) );
|
||||||
|
|
||||||
|
$old_filter = isset( $args['browse'] ) ? $args['browse'] : 'search';
|
||||||
|
|
||||||
|
/** This filter is documented in wp-admin/includes/class-wp-theme-install-list-table.php */
|
||||||
|
$args = apply_filters( 'install_themes_table_api_args_' . $old_filter, $args );
|
||||||
|
|
||||||
|
$api = themes_api( 'query_themes', $args );
|
||||||
|
|
||||||
|
if ( is_wp_error( $api ) ) {
|
||||||
|
wp_send_json_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
$update_php = self_admin_url( 'update.php?action=install-theme' );
|
||||||
|
foreach ( $api->themes as &$theme ) {
|
||||||
|
$theme->install_url = add_query_arg( array(
|
||||||
|
'theme' => $theme->slug,
|
||||||
|
'_wpnonce' => wp_create_nonce( 'install-theme_' . $theme->slug )
|
||||||
|
), $update_php );
|
||||||
|
|
||||||
|
$theme->name = wp_kses( $theme->name, $themes_allowedtags );
|
||||||
|
$theme->author = wp_kses( $theme->author, $themes_allowedtags );
|
||||||
|
$theme->version = wp_kses( $theme->version, $themes_allowedtags );
|
||||||
|
$theme->description = wp_kses( $theme->description, $themes_allowedtags );
|
||||||
|
$theme->num_ratings = sprintf( _n( '(based on %s rating)', '(based on %s ratings)', $theme->num_ratings ), number_format_i18n( $theme->num_ratings ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_send_json_success( $api );
|
||||||
|
}
|
||||||
|
|
|
@ -346,7 +346,9 @@ function themes_api( $action, $args = null ) {
|
||||||
$request = wp_remote_post( $url, $args );
|
$request = wp_remote_post( $url, $args );
|
||||||
|
|
||||||
if ( $ssl && is_wp_error( $request ) ) {
|
if ( $ssl && is_wp_error( $request ) ) {
|
||||||
|
if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) {
|
||||||
trigger_error( __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="https://wordpress.org/support/">support forums</a>.' ) . ' ' . '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)', headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE );
|
trigger_error( __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="https://wordpress.org/support/">support forums</a>.' ) . ' ' . '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)', headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE );
|
||||||
|
}
|
||||||
$request = wp_remote_post( $http_url, $args );
|
$request = wp_remote_post( $http_url, $args );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,18 +22,7 @@ themes.Model = Backbone.Model.extend({
|
||||||
// Adds attributes to the default data coming through the .org themes api
|
// Adds attributes to the default data coming through the .org themes api
|
||||||
// Map `id` to `slug` for shared code
|
// Map `id` to `slug` for shared code
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
var install, description;
|
var description;
|
||||||
|
|
||||||
// Install url for the theme
|
|
||||||
// using the install nonce
|
|
||||||
install = {
|
|
||||||
action: 'install-theme',
|
|
||||||
theme: this.get( 'slug' ),
|
|
||||||
_wpnonce: themes.data.settings._nonceInstall
|
|
||||||
};
|
|
||||||
|
|
||||||
// Build the url query
|
|
||||||
install = themes.data.settings.updateURI + '?' + $.param( install );
|
|
||||||
|
|
||||||
// If theme is already installed, set an attribute.
|
// If theme is already installed, set an attribute.
|
||||||
if ( _.indexOf( themes.data.installedThemes, this.get( 'slug' ) ) !== -1 ) {
|
if ( _.indexOf( themes.data.installedThemes, this.get( 'slug' ) ) !== -1 ) {
|
||||||
|
@ -42,7 +31,6 @@ themes.Model = Backbone.Model.extend({
|
||||||
|
|
||||||
// Set the attributes
|
// Set the attributes
|
||||||
this.set({
|
this.set({
|
||||||
installURI: ( this.get( 'slug' ) ) ? install : false,
|
|
||||||
// slug is for installation, id is for existing.
|
// slug is for installation, id is for existing.
|
||||||
id: this.get( 'slug' ) || this.get( 'id' )
|
id: this.get( 'slug' ) || this.get( 'id' )
|
||||||
});
|
});
|
||||||
|
@ -225,7 +213,7 @@ themes.Collection = Backbone.Collection.extend({
|
||||||
//
|
//
|
||||||
// When we are missing a cache object we fire an apiCall()
|
// When we are missing a cache object we fire an apiCall()
|
||||||
// which triggers events of `query:success` or `query:fail`
|
// which triggers events of `query:success` or `query:fail`
|
||||||
query: function( request, action ) {
|
query: function( request ) {
|
||||||
/**
|
/**
|
||||||
* @static
|
* @static
|
||||||
* @type Array
|
* @type Array
|
||||||
|
@ -254,7 +242,7 @@ themes.Collection = Backbone.Collection.extend({
|
||||||
|
|
||||||
// Otherwise, send a new API call and add it to the cache.
|
// Otherwise, send a new API call and add it to the cache.
|
||||||
if ( ! query && ! isPaginated ) {
|
if ( ! query && ! isPaginated ) {
|
||||||
query = this.apiCall( request, action ).done( function( data ) {
|
query = this.apiCall( request ).done( function( data ) {
|
||||||
|
|
||||||
// Update the collection with the queried data.
|
// Update the collection with the queried data.
|
||||||
if ( data.themes ) {
|
if ( data.themes ) {
|
||||||
|
@ -262,11 +250,6 @@ themes.Collection = Backbone.Collection.extend({
|
||||||
count = data.info.results;
|
count = data.info.results;
|
||||||
// Store the results and the query request
|
// Store the results and the query request
|
||||||
queries.push( { themes: data.themes, request: request, total: count } );
|
queries.push( { themes: data.themes, request: request, total: count } );
|
||||||
|
|
||||||
} else if ( action ) {
|
|
||||||
self.reset( data );
|
|
||||||
count = 1;
|
|
||||||
self.trigger( 'query:theme' );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger a collection refresh event
|
// Trigger a collection refresh event
|
||||||
|
@ -284,7 +267,7 @@ themes.Collection = Backbone.Collection.extend({
|
||||||
} else {
|
} else {
|
||||||
// If it's a paginated request we need to fetch more themes...
|
// If it's a paginated request we need to fetch more themes...
|
||||||
if ( isPaginated ) {
|
if ( isPaginated ) {
|
||||||
return this.apiCall( request, action, isPaginated ).done( function( data ) {
|
return this.apiCall( request, isPaginated ).done( function( data ) {
|
||||||
// Add the new themes to the current collection
|
// Add the new themes to the current collection
|
||||||
// @todo update counter
|
// @todo update counter
|
||||||
self.add( data.themes );
|
self.add( data.themes );
|
||||||
|
@ -310,12 +293,13 @@ themes.Collection = Backbone.Collection.extend({
|
||||||
this.count = query.total;
|
this.count = query.total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.reset( query.themes );
|
||||||
if ( ! query.total ) {
|
if ( ! query.total ) {
|
||||||
this.count = this.length;
|
this.count = this.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.reset( query.themes );
|
|
||||||
this.trigger( 'update' );
|
this.trigger( 'update' );
|
||||||
|
this.trigger( 'query:success', this.count );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -329,30 +313,23 @@ themes.Collection = Backbone.Collection.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
// Send request to api.wordpress.org/themes
|
// Send request to api.wordpress.org/themes
|
||||||
apiCall: function( request, action, paginated ) {
|
apiCall: function( request, paginated ) {
|
||||||
|
return wp.ajax.send( 'query-themes', {
|
||||||
// Send tags (and fields) as comma-separated to keep the JSONP query string short.
|
|
||||||
if ( request.tag && _.isArray( request.tag ) ) {
|
|
||||||
request.tag = request.tag.join( ',' );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set request action
|
|
||||||
if ( ! action ) {
|
|
||||||
action = 'query_themes'
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONP request to .org API
|
|
||||||
return $.ajax({
|
|
||||||
url: 'https://api.wordpress.org/themes/info/1.1/?callback=?',
|
|
||||||
dataType: 'jsonp',
|
|
||||||
timeout: 15000, // 15 seconds
|
|
||||||
|
|
||||||
// Request data
|
|
||||||
data: {
|
data: {
|
||||||
action: action,
|
// Request data
|
||||||
request: _.extend({
|
request: _.extend({
|
||||||
per_page: 72,
|
per_page: 100,
|
||||||
fields: 'description,tested,requires,rating,downloaded,downloadLink,last_updated,homepage,num_ratings'
|
fields: {
|
||||||
|
description: true,
|
||||||
|
tested: true,
|
||||||
|
requires: true,
|
||||||
|
rating: true,
|
||||||
|
downloaded: true,
|
||||||
|
downloadLink: true,
|
||||||
|
last_updated: true,
|
||||||
|
homepage: true,
|
||||||
|
num_ratings: true
|
||||||
|
}
|
||||||
}, request)
|
}, request)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1567,7 +1544,11 @@ themes.view.Installer = themes.view.Appearance.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
backToFilters: function() {
|
backToFilters: function( event ) {
|
||||||
|
if ( event ) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
$( 'body' ).removeClass( 'filters-applied' );
|
$( 'body' ).removeClass( 'filters-applied' );
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1634,8 +1615,8 @@ themes.RunInstaller = {
|
||||||
// Handles `theme` route event
|
// Handles `theme` route event
|
||||||
// Queries the API for the passed theme slug
|
// Queries the API for the passed theme slug
|
||||||
themes.router.on( 'route:preview', function( slug ) {
|
themes.router.on( 'route:preview', function( slug ) {
|
||||||
request.slug = slug;
|
request.theme = slug;
|
||||||
self.view.collection.query( request, 'theme_information' );
|
self.view.collection.query( request );
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handles sorting / browsing routes
|
// Handles sorting / browsing routes
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -46,9 +46,7 @@ wp_localize_script( 'theme', '_wpThemeSettings', array(
|
||||||
'isInstall' => true,
|
'isInstall' => true,
|
||||||
'canInstall' => current_user_can( 'install_themes' ),
|
'canInstall' => current_user_can( 'install_themes' ),
|
||||||
'installURI' => current_user_can( 'install_themes' ) ? self_admin_url( 'theme-install.php' ) : null,
|
'installURI' => current_user_can( 'install_themes' ) ? self_admin_url( 'theme-install.php' ) : null,
|
||||||
'adminUrl' => parse_url( self_admin_url(), PHP_URL_PATH ),
|
'adminUrl' => parse_url( self_admin_url(), PHP_URL_PATH )
|
||||||
'updateURI' => self_admin_url( 'update.php' ),
|
|
||||||
'_nonceInstall' => wp_create_nonce( 'install-theme' )
|
|
||||||
),
|
),
|
||||||
'l10n' => array(
|
'l10n' => array(
|
||||||
'addNew' => __( 'Add New Theme' ),
|
'addNew' => __( 'Add New Theme' ),
|
||||||
|
@ -56,7 +54,7 @@ wp_localize_script( 'theme', '_wpThemeSettings', array(
|
||||||
'searchPlaceholder' => __( 'Search themes...' ), // placeholder (no ellipsis)
|
'searchPlaceholder' => __( 'Search themes...' ), // placeholder (no ellipsis)
|
||||||
'upload' => __( 'Upload Theme' ),
|
'upload' => __( 'Upload Theme' ),
|
||||||
'back' => __( 'Back' ),
|
'back' => __( 'Back' ),
|
||||||
'error' => sprintf( __( 'An unexpected error occurred and we can᾿t reach WordPress.org. If you continue to have problems, please try the <a href="%s">support forums</a>.' ), __( 'https://wordpress.org/support/' ) )
|
'error' => __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="https://wordpress.org/support/">support forums</a>.' )
|
||||||
),
|
),
|
||||||
'installedThemes' => array_keys( $installed_themes ),
|
'installedThemes' => array_keys( $installed_themes ),
|
||||||
'browse' => array(
|
'browse' => array(
|
||||||
|
@ -199,7 +197,7 @@ if ( $tab ) {
|
||||||
<h3 class="theme-name">{{ data.name }}</h3>
|
<h3 class="theme-name">{{ data.name }}</h3>
|
||||||
|
|
||||||
<div class="theme-actions">
|
<div class="theme-actions">
|
||||||
<a class="button button-primary" href="{{ data.installURI }}"><?php esc_html_e( 'Install' ); ?></a>
|
<a class="button button-primary" href="{{ data.install_url }}"><?php esc_html_e( 'Install' ); ?></a>
|
||||||
<a class="button button-secondary preview install-theme-preview" href="#"><?php esc_html_e( 'Preview' ); ?></a>
|
<a class="button button-secondary preview install-theme-preview" href="#"><?php esc_html_e( 'Preview' ); ?></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -215,7 +213,7 @@ if ( $tab ) {
|
||||||
<# if ( data.installed ) { #>
|
<# if ( data.installed ) { #>
|
||||||
<a href="#" class="button button-primary theme-install disabled"><?php _e( 'Installed' ); ?></a>
|
<a href="#" class="button button-primary theme-install disabled"><?php _e( 'Installed' ); ?></a>
|
||||||
<# } else { #>
|
<# } else { #>
|
||||||
<a href="{{ data.installURI }}" class="button button-primary theme-install"><?php _e( 'Install' ); ?></a>
|
<a href="{{ data.install_url }}" class="button button-primary theme-install"><?php _e( 'Install' ); ?></a>
|
||||||
<# } #>
|
<# } #>
|
||||||
</div>
|
</div>
|
||||||
<div class="wp-full-overlay-sidebar-content">
|
<div class="wp-full-overlay-sidebar-content">
|
||||||
|
@ -233,7 +231,7 @@ if ( $tab ) {
|
||||||
<span class="four"></span>
|
<span class="four"></span>
|
||||||
<span class="five"></span>
|
<span class="five"></span>
|
||||||
<# if ( data.num_ratings ) { #>
|
<# if ( data.num_ratings ) { #>
|
||||||
<p class="ratings">({{ data.num_ratings }})</p>
|
<p class="ratings">{{ data.num_ratings }}</p>
|
||||||
<# } else { #>
|
<# } else { #>
|
||||||
<p class="ratings"><?php _e( 'No ratings.' ); ?></p>
|
<p class="ratings"><?php _e( 'No ratings.' ); ?></p>
|
||||||
<# } #>
|
<# } #>
|
||||||
|
|
|
@ -202,7 +202,7 @@ if ( isset($_GET['action']) ) {
|
||||||
|
|
||||||
include_once ABSPATH . 'wp-admin/includes/theme-install.php'; //for themes_api..
|
include_once ABSPATH . 'wp-admin/includes/theme-install.php'; //for themes_api..
|
||||||
|
|
||||||
check_admin_referer( 'install-theme' );
|
check_admin_referer( 'install-theme_' . $theme );
|
||||||
$api = themes_api('theme_information', array('slug' => $theme, 'fields' => array('sections' => false, 'tags' => false) ) ); //Save on a bit of bandwidth.
|
$api = themes_api('theme_information', array('slug' => $theme, 'fields' => array('sections' => false, 'tags' => false) ) ); //Save on a bit of bandwidth.
|
||||||
|
|
||||||
if ( is_wp_error($api) )
|
if ( is_wp_error($api) )
|
||||||
|
|
Loading…
Reference in New Issue