Skip to content

Commit

Permalink
Site Health, App Passwords: Ensure REST API responses are properly tr…
Browse files Browse the repository at this point in the history
…anslated.

The REST API requests in Site Health and App Passwords now include `_locale=user` in the request URL to ensure the user's locale is used instead of the site locale. Additionally, the `apiRequest` library now sends a JSON `Accept` header which is required by `determine_locale()` to respect the `_locale` query parameter.

The Site Health REST API controllers now manually load the default admin textdomain if not `is_admin()`. This allows for the Site Health tests to be translated even though the translations are part of the administration project and the REST API is not.

Props oglekler, kebbet, Clorith, TimothyBlynJacobs, ocean90, SergeyBiryukov, adamsilverstein.
Fixes #51871.


git-svn-id: https://develop.svn.wordpress.org/trunk@49716 602fd350-edb4-49c9-b593-d223f7449a82
  • Loading branch information
TimothyBlynJacobs authored and TimothyBlynJacobs committed Dec 1, 2020
1 parent 6e7a61a commit 3c0d926
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 27 deletions.
6 changes: 3 additions & 3 deletions src/js/_enqueues/admin/application-passwords.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
request = wp.hooks.applyFilters( 'wp_application_passwords_new_password_request', request, userId );

wp.apiRequest( {
path: '/wp/v2/users/' + userId + '/application-passwords',
path: '/wp/v2/users/' + userId + '/application-passwords?_locale=user',
method: 'POST',
data: request
} ).always( function() {
Expand Down Expand Up @@ -94,7 +94,7 @@
$submitButton.prop( 'disabled', true );

wp.apiRequest( {
path: '/wp/v2/users/' + userId + '/application-passwords/' + uuid,
path: '/wp/v2/users/' + userId + '/application-passwords/' + uuid + '?_locale=user',
method: 'DELETE'
} ).always( function() {
$submitButton.prop( 'disabled', false );
Expand Down Expand Up @@ -123,7 +123,7 @@
$submitButton.prop( 'disabled', true );

wp.apiRequest( {
path: '/wp/v2/users/' + userId + '/application-passwords',
path: '/wp/v2/users/' + userId + '/application-passwords?_locale=user',
method: 'DELETE'
} ).always( function() {
$submitButton.prop( 'disabled', false );
Expand Down
2 changes: 1 addition & 1 deletion src/js/_enqueues/admin/auth-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
request = wp.hooks.applyFilters( 'wp_application_passwords_approve_app_request', request, context );

wp.apiRequest( {
path: '/wp/v2/users/me/application-passwords',
path: '/wp/v2/users/me/application-passwords?_locale=user',
method: 'POST',
data: request
} ).done( function( response, textStatus, jqXHR ) {
Expand Down
2 changes: 1 addition & 1 deletion src/js/_enqueues/admin/site-health.js
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ jQuery( document ).ready( function( $ ) {

if ( 'undefined' !== typeof( this.has_rest ) && this.has_rest ) {
wp.apiRequest( {
url: this.test,
url: wp.url.addQueryArgs( this.test, { _locale: 'user' } ),
headers: this.headers
} )
.done( function( response ) {
Expand Down
34 changes: 23 additions & 11 deletions src/js/_enqueues/wp/api-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
*
* @since 4.9.0
* @since 5.6.0 Added overriding of the "PUT" and "DELETE" methods with "POST".
* Added an "application/json" Accept header to all requests.
* @output wp-includes/js/api-request.js
*/

Expand All @@ -26,7 +27,7 @@
var path = options.path;
var method = options.method;
var namespaceTrimmed, endpointTrimmed, apiRoot;
var headers, addNonceHeader, headerName;
var headers, addNonceHeader, addAcceptHeader, headerName;

if (
typeof options.namespace === 'string' &&
Expand Down Expand Up @@ -55,19 +56,24 @@

// If ?_wpnonce=... is present, no need to add a nonce header.
addNonceHeader = ! ( options.data && options.data._wpnonce );
addAcceptHeader = true;

headers = options.headers || {};

// If an 'X-WP-Nonce' header (or any case-insensitive variation
// thereof) was specified, no need to add a nonce header.
if ( addNonceHeader ) {
for ( headerName in headers ) {
if ( headers.hasOwnProperty( headerName ) ) {
if ( headerName.toLowerCase() === 'x-wp-nonce' ) {
addNonceHeader = false;
break;
}
}
for ( headerName in headers ) {
if ( ! headers.hasOwnProperty( headerName ) ) {
continue;
}

// If an 'X-WP-Nonce' or 'Accept' header (or any case-insensitive variation
// thereof) was specified, no need to add the header again.
switch ( headerName.toLowerCase() ) {
case 'x-wp-nonce':
addNonceHeader = false;
break;
case 'accept':
addAcceptHeader = false;
break;
}
}

Expand All @@ -78,6 +84,12 @@
}, headers );
}

if ( addAcceptHeader ) {
headers = $.extend( {
'Accept': 'application/json, */*;q=0.1'
}, headers );
}

if ( typeof method === 'string' ) {
method = method.toUpperCase();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ protected function validate_request_permission( $check ) {
* @return array
*/
public function test_background_updates() {
$this->load_admin_textdomain();
return $this->site_health->get_test_background_updates();
}

Expand All @@ -182,6 +183,7 @@ public function test_background_updates() {
* @return array
*/
public function test_dotorg_communication() {
$this->load_admin_textdomain();
return $this->site_health->get_test_dotorg_communication();
}

Expand All @@ -193,6 +195,7 @@ public function test_dotorg_communication() {
* @return array
*/
public function test_loopback_requests() {
$this->load_admin_textdomain();
return $this->site_health->get_test_loopback_requests();
}

Expand All @@ -204,6 +207,7 @@ public function test_loopback_requests() {
* @return array
*/
public function test_authorization_header() {
$this->load_admin_textdomain();
return $this->site_health->get_test_authorization_header();
}

Expand All @@ -219,6 +223,8 @@ public function get_directory_sizes() {
require_once ABSPATH . 'wp-admin/includes/class-wp-debug-data.php';
}

$this->load_admin_textdomain();

$sizes_data = WP_Debug_Data::get_sizes();
$all_sizes = array( 'raw' => 0 );

Expand Down Expand Up @@ -256,6 +262,22 @@ public function get_directory_sizes() {
return $all_sizes;
}

/**
* Loads the admin textdomain for Site Health tests.
*
* The {@see WP_Site_Health} class is defined in WP-Admin, while the REST API operates in a front-end context.
* This means that the translations for Site Health won't be loaded by default in {@see load_default_textdomain()}.
*
* @since 5.6.0
*/
protected function load_admin_textdomain() {
// Accounts for inner REST API requests in the admin.
if ( ! is_admin() ) {
$locale = determine_locale();
load_textdomain( 'default', WP_LANG_DIR . "/admin-$locale.mo" );
}
}

/**
* Gets the schema for each site health test.
*
Expand Down
2 changes: 1 addition & 1 deletion src/wp-includes/script-loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -1286,7 +1286,7 @@ function wp_default_scripts( $scripts ) {
$scripts->add( 'plugin-install', "/wp-admin/js/plugin-install$suffix.js", array( 'jquery', 'jquery-ui-core', 'thickbox' ), false, 1 );
$scripts->set_translations( 'plugin-install' );

$scripts->add( 'site-health', "/wp-admin/js/site-health$suffix.js", array( 'clipboard', 'jquery', 'wp-util', 'wp-a11y', 'wp-api-request' ), false, 1 );
$scripts->add( 'site-health', "/wp-admin/js/site-health$suffix.js", array( 'clipboard', 'jquery', 'wp-util', 'wp-a11y', 'wp-api-request', 'wp-url' ), false, 1 );
$scripts->set_translations( 'site-health' );

$scripts->add( 'privacy-tools', "/wp-admin/js/privacy-tools$suffix.js", array( 'jquery', 'wp-a11y' ), false, 1 );
Expand Down
43 changes: 33 additions & 10 deletions tests/qunit/wp-includes/js/api-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
( function( QUnit ) {
var originalRootUrl = window.wpApiSettings.root;

var nonceHeader = { 'X-WP-Nonce': 'not_a_real_nonce' };
var expectedHeaders = {
'X-WP-Nonce': 'not_a_real_nonce',
'Accept': 'application/json, */*;q=0.1'
};

QUnit.module( 'wp-api-request', {
afterEach: function() {
Expand Down Expand Up @@ -32,6 +35,7 @@
url: 'http://localhost/wp-json/wp/v2/posts',
headers: {
'X-WP-Nonce': 'not_a_real_nonce',
'Accept': 'application/json, */*;q=0.1',
'Header-Name': 'value'
},
data: {
Expand Down Expand Up @@ -64,11 +68,15 @@
var settings = wp.apiRequest.buildAjaxOptions( settingsOriginal );

assert.notStrictEqual( settings, settingsOriginal );
assert.strictEqual( settings.headers, settingsOriginal.headers );

var expected = {
Accept: 'application/json, */*;q=0.1'
};
expected[ headerName ] = nonceHeader[ headerName ];

assert.deepEqual( settings, {
url: 'aaaa',
headers: nonceHeader
headers: expected
} );
} );
} );
Expand All @@ -87,20 +95,35 @@

assert.deepEqual( settings, {
url: 'aaaa',
headers: {},
headers: {
'Accept': 'application/json, */*;q=0.1'
},
data: {
_wpnonce: 'definitely_not_a_real_nonce'
}
} );
} );

QUnit.test( 'does not add accept header if already present', function( assert ) {
var settingsOriginal = {
url: 'aaaa',
headers: {
'Accept': 'text/xml'
}
};

var settings = wp.apiRequest.buildAjaxOptions( settingsOriginal );

assert.strictEqual( settingsOriginal.headers.Accept, settings.headers.Accept );
} );

QUnit.test( 'accepts namespace and endpoint', function( assert ) {
assert.deepEqual( wp.apiRequest.buildAjaxOptions( {
namespace: 'wp/v2',
endpoint: 'posts'
} ), {
url: 'http://localhost/wp-json/wp/v2/posts',
headers: nonceHeader
headers: expectedHeaders
} );
} );

Expand All @@ -110,7 +133,7 @@
endpoint: '/posts'
} ), {
url: 'http://localhost/wp-json/wp/v2/posts',
headers: nonceHeader
headers: expectedHeaders
} );
} );

Expand All @@ -120,7 +143,7 @@
endpoint: ''
} ), {
url: 'http://localhost/wp-json/wp/v2',
headers: nonceHeader
headers: expectedHeaders
} );
} );

Expand All @@ -130,7 +153,7 @@
endpoint: ''
} ), {
url: 'http://localhost/wp-json/',
headers: nonceHeader
headers: expectedHeaders
} );
} );

Expand All @@ -143,7 +166,7 @@
endpoint: '/posts?orderby=title'
} ), {
url: 'http://localhost/index.php?rest_route=/wp/v2/posts&orderby=title',
headers: nonceHeader
headers: expectedHeaders
} );
}
);
Expand All @@ -157,7 +180,7 @@
endpoint: ''
} ), {
url: 'http://localhost/index.php?rest_route=/',
headers: nonceHeader
headers: expectedHeaders
} );
}
);
Expand Down

0 comments on commit 3c0d926

Please sign in to comment.