diff --git a/src/js/_enqueues/admin/application-passwords.js b/src/js/_enqueues/admin/application-passwords.js index 09e4434e2f..b1a20ceb8e 100644 --- a/src/js/_enqueues/admin/application-passwords.js +++ b/src/js/_enqueues/admin/application-passwords.js @@ -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() { @@ -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 ); @@ -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 ); diff --git a/src/js/_enqueues/admin/auth-app.js b/src/js/_enqueues/admin/auth-app.js index 4af3a05fa8..ad4403032d 100644 --- a/src/js/_enqueues/admin/auth-app.js +++ b/src/js/_enqueues/admin/auth-app.js @@ -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 ) { diff --git a/src/js/_enqueues/admin/site-health.js b/src/js/_enqueues/admin/site-health.js index d91b75e90a..9bba750094 100644 --- a/src/js/_enqueues/admin/site-health.js +++ b/src/js/_enqueues/admin/site-health.js @@ -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 ) { diff --git a/src/js/_enqueues/wp/api-request.js b/src/js/_enqueues/wp/api-request.js index 885e5b47f8..58ef531179 100644 --- a/src/js/_enqueues/wp/api-request.js +++ b/src/js/_enqueues/wp/api-request.js @@ -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 */ @@ -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' && @@ -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; } } @@ -78,6 +84,12 @@ }, headers ); } + if ( addAcceptHeader ) { + headers = $.extend( { + 'Accept': 'application/json, */*;q=0.1' + }, headers ); + } + if ( typeof method === 'string' ) { method = method.toUpperCase(); diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php index 6dbc239ec0..f790dadb04 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php @@ -171,6 +171,7 @@ class WP_REST_Site_Health_Controller extends WP_REST_Controller { * @return array */ public function test_background_updates() { + $this->load_admin_textdomain(); return $this->site_health->get_test_background_updates(); } @@ -182,6 +183,7 @@ class WP_REST_Site_Health_Controller extends WP_REST_Controller { * @return array */ public function test_dotorg_communication() { + $this->load_admin_textdomain(); return $this->site_health->get_test_dotorg_communication(); } @@ -193,6 +195,7 @@ class WP_REST_Site_Health_Controller extends WP_REST_Controller { * @return array */ public function test_loopback_requests() { + $this->load_admin_textdomain(); return $this->site_health->get_test_loopback_requests(); } @@ -204,6 +207,7 @@ class WP_REST_Site_Health_Controller extends WP_REST_Controller { * @return array */ public function test_authorization_header() { + $this->load_admin_textdomain(); return $this->site_health->get_test_authorization_header(); } @@ -219,6 +223,8 @@ class WP_REST_Site_Health_Controller extends WP_REST_Controller { 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 ); @@ -256,6 +262,22 @@ class WP_REST_Site_Health_Controller extends WP_REST_Controller { 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. * diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index f3ad2de05c..a0da5a0c4d 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -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 ); diff --git a/tests/qunit/wp-includes/js/api-request.js b/tests/qunit/wp-includes/js/api-request.js index 86d0d72cda..aa7ee1dea7 100644 --- a/tests/qunit/wp-includes/js/api-request.js +++ b/tests/qunit/wp-includes/js/api-request.js @@ -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() { @@ -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: { @@ -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 } ); } ); } ); @@ -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 } ); } ); @@ -110,7 +133,7 @@ endpoint: '/posts' } ), { url: 'http://localhost/wp-json/wp/v2/posts', - headers: nonceHeader + headers: expectedHeaders } ); } ); @@ -120,7 +143,7 @@ endpoint: '' } ), { url: 'http://localhost/wp-json/wp/v2', - headers: nonceHeader + headers: expectedHeaders } ); } ); @@ -130,7 +153,7 @@ endpoint: '' } ), { url: 'http://localhost/wp-json/', - headers: nonceHeader + headers: expectedHeaders } ); } ); @@ -143,7 +166,7 @@ endpoint: '/posts?orderby=title' } ), { url: 'http://localhost/index.php?rest_route=/wp/v2/posts&orderby=title', - headers: nonceHeader + headers: expectedHeaders } ); } ); @@ -157,7 +180,7 @@ endpoint: '' } ), { url: 'http://localhost/index.php?rest_route=/', - headers: nonceHeader + headers: expectedHeaders } ); } );