WordPress.org

Make WordPress Core

Ticket #40919: 40919.3.diff

File 40919.3.diff, 13.8 KB (added by jnylen0, 4 years ago)

Pass nonce as header; use main wpApiSettings variable; allow requests via path/namespace/endpoint; add unit tests

  • src/wp-admin/js/widgets/media-video-widget.js

    diff --git a/src/wp-admin/js/widgets/media-video-widget.js b/src/wp-admin/js/widgets/media-video-widget.js
    index 07b203f..9eb532c 100644
    a b  
    110110                                control.fetchEmbedDfd.abort();
    111111                        }
    112112
    113                         control.fetchEmbedDfd = jQuery.ajax({
     113                        control.fetchEmbedDfd = wp.apiRequest({
    114114                                url: wp.media.view.settings.oEmbedProxyUrl,
    115115                                data: {
    116116                                        url: control.model.get( 'url' ),
    117117                                        maxwidth: control.model.get( 'width' ),
    118118                                        maxheight: control.model.get( 'height' ),
    119                                         _wpnonce: wp.media.view.settings.nonce.wpRestApi,
    120119                                        discover: false
    121120                                },
    122121                                type: 'GET',
  • src/wp-admin/js/widgets/media-widgets.js

    diff --git a/src/wp-admin/js/widgets/media-widgets.js b/src/wp-admin/js/widgets/media-widgets.js
    index 598d94d..7308109 100644
    a b wp.mediaWidgets = ( function( $ ) { 
    190190                                                        return;
    191191                                                }
    192192
    193                                                 embedLinkView.dfd = $.ajax({
     193                                                embedLinkView.dfd = wp.apiRequest({
    194194                                                        url: wp.media.view.settings.oEmbedProxyUrl,
    195195                                                        data: {
    196196                                                                url: embedLinkView.model.get( 'url' ),
    197197                                                                maxwidth: embedLinkView.model.get( 'width' ),
    198198                                                                maxheight: embedLinkView.model.get( 'height' ),
    199                                                                 _wpnonce: wp.media.view.settings.nonce.wpRestApi,
    200199                                                                discover: false
    201200                                                        },
    202201                                                        type: 'GET',
  • new file src/wp-includes/js/api-request.js

    diff --git a/src/wp-includes/js/api-request.js b/src/wp-includes/js/api-request.js
    new file mode 100644
    index 0000000..464ddfa
    - +  
     1/**
     2 * Thin jQuery.ajax wrapper for REST API requests that do not use the
     3 * `wp-api.js` Backbone client library.  Serves several purposes:
     4 *
     5 * - Allows overriding these requests as needed by customized WP installations.
     6 * - Sends the REST API nonce as a request header.
     7 * - Allows specifying only an endpoint namespace/path instead of a full URL.
     8 *
     9 * @summary Wrapper around jQuery.ajax, intended for use with the WP REST API.
     10 *
     11 * @namespace wp.apiRequest
     12 * @since     4.8.1
     13 */
     14
     15( function( $ ) {
     16        var wpApiSettings = window.wpApiSettings;
     17
     18        function apiRequest( options ) {
     19                options = apiRequest.buildAjaxOptions( options );
     20                return apiRequest.transport( options );
     21        };
     22
     23        apiRequest.buildAjaxOptions = function( options ) {
     24                var url = options.url;
     25                var path = options.path;
     26                var namespaceTrimmed, endpointTrimmed;
     27
     28                if (
     29                        typeof options.namespace === 'string' &&
     30                        typeof options.endpoint === 'string'
     31                ) {
     32                        namespaceTrimmed = options.namespace.replace( /^\/|\/$/g, '' );
     33                        endpointTrimmed = options.endpoint.replace( /^\//, '' );
     34                        if ( endpointTrimmed ) {
     35                                path = namespaceTrimmed + '/' + endpointTrimmed;
     36                        } else {
     37                                path = namespaceTrimmed;
     38                        }
     39                }
     40                if ( typeof path === 'string' ) {
     41                        url = wpApiSettings.root + path.replace( /^\//, '' );
     42                }
     43
     44                // Create a new object with modified properties, but do not modify any
     45                // of the original objects.
     46
     47                var headers = $.extend( {
     48                        'X-WP-Nonce': wpApiSettings.nonce
     49                }, options.headers || {} );
     50
     51                options = $.extend( {}, options, {
     52                        headers: headers,
     53                        url: url
     54                } );
     55
     56                delete options.path;
     57                delete options.namespace;
     58                delete options.endpoint;
     59
     60                return options;
     61        };
     62
     63        apiRequest.transport = $.ajax;
     64
     65        window.wp = window.wp || {};
     66        window.wp.apiRequest = apiRequest;
     67} )( jQuery );
  • src/wp-includes/js/media-views.js

    diff --git a/src/wp-includes/js/media-views.js b/src/wp-includes/js/media-views.js
    index 29b56c6..8f84c81 100644
    a b EmbedLink = wp.media.view.Settings.extend({ 
    46344634                        this.dfd.abort();
    46354635                }
    46364636
    4637                 this.dfd = $.ajax({
     4637                this.dfd = wp.apiRequest({
    46384638                        url: wp.media.view.settings.oEmbedProxyUrl,
    46394639                        data: {
    46404640                                url: this.model.get( 'url' ),
    46414641                                maxwidth: this.model.get( 'width' ),
    4642                                 maxheight: this.model.get( 'height' ),
    4643                                 _wpnonce: wp.media.view.settings.nonce.wpRestApi
     4642                                maxheight: this.model.get( 'height' )
    46444643                        },
    46454644                        type: 'GET',
    46464645                        dataType: 'json',
  • src/wp-includes/js/media/views/embed/link.js

    diff --git a/src/wp-includes/js/media/views/embed/link.js b/src/wp-includes/js/media/views/embed/link.js
    index 1af96cf..d00be5c 100644
    a b EmbedLink = wp.media.view.Settings.extend({ 
    4545                        this.dfd.abort();
    4646                }
    4747
    48                 this.dfd = $.ajax({
     48                this.dfd = wp.apiRequest({
    4949                        url: wp.media.view.settings.oEmbedProxyUrl,
    5050                        data: {
    5151                                url: this.model.get( 'url' ),
    5252                                maxwidth: this.model.get( 'width' ),
    53                                 maxheight: this.model.get( 'height' ),
    54                                 _wpnonce: wp.media.view.settings.nonce.wpRestApi
     53                                maxheight: this.model.get( 'height' )
    5554                        },
    5655                        type: 'GET',
    5756                        dataType: 'json',
  • src/wp-includes/media.php

    diff --git a/src/wp-includes/media.php b/src/wp-includes/media.php
    index 76cc0c1..30066b1 100644
    a b function wp_enqueue_media( $args = array() ) { 
    34363436                'captions'  => ! apply_filters( 'disable_captions', '' ),
    34373437                'nonce'     => array(
    34383438                        'sendToEditor' => wp_create_nonce( 'media-send-to-editor' ),
    3439                         'wpRestApi'    => wp_create_nonce( 'wp_rest' ),
    34403439                ),
    34413440                'post'    => array(
    34423441                        'id' => 0,
  • src/wp-includes/script-loader.php

    diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php
    index 7562e28..96dda97 100644
    a b function wp_default_scripts( &$scripts ) { 
    133133                'broken' => __('An unidentified error has occurred.')
    134134        ) );
    135135
     136        $scripts->add( 'wp-api-request', "/wp-includes/js/api-request$suffix.js", array( 'jquery' ), false, 1 );
     137        // `wpApiSettings` is also used by `wp-api`, which depends on this script.
     138        did_action( 'init' ) && $scripts->localize( 'wp-api-request', 'wpApiSettings', array(
     139                'root'          => esc_url_raw( get_rest_url() ),
     140                'nonce'         => ( wp_installing() && ! is_multisite() ) ? '' : wp_create_nonce( 'wp_rest' ),
     141                'versionString' => 'wp/v2/',
     142        ) );
     143
    136144        $scripts->add( 'wp-pointer', "/wp-includes/js/wp-pointer$suffix.js", array( 'jquery-ui-widget', 'jquery-ui-position' ), '20111129a', 1 );
    137145        did_action( 'init' ) && $scripts->localize( 'wp-pointer', 'wpPointerL10n', array(
    138146                'dismiss' => __('Dismiss'),
    function wp_default_scripts( &$scripts ) { 
    499507
    500508        // To enqueue media-views or media-editor, call wp_enqueue_media().
    501509        // Both rely on numerous settings, styles, and templates to operate correctly.
    502         $scripts->add( 'media-views',  "/wp-includes/js/media-views$suffix.js",  array( 'utils', 'media-models', 'wp-plupload', 'jquery-ui-sortable', 'wp-mediaelement' ), false, 1 );
     510        $scripts->add( 'media-views',  "/wp-includes/js/media-views$suffix.js",  array( 'utils', 'media-models', 'wp-plupload', 'jquery-ui-sortable', 'wp-mediaelement', 'wp-api-request' ), false, 1 );
    503511        $scripts->add( 'media-editor', "/wp-includes/js/media-editor$suffix.js", array( 'shortcode', 'media-views' ), false, 1 );
    504512        $scripts->add( 'media-audiovideo', "/wp-includes/js/media-audiovideo$suffix.js", array( 'media-editor' ), false, 1 );
    505513        $scripts->add( 'mce-view', "/wp-includes/js/mce-view$suffix.js", array( 'shortcode', 'jquery', 'media-views', 'media-audiovideo' ), false, 1 );
    506514
    507         $scripts->add( 'wp-api', "/wp-includes/js/wp-api$suffix.js", array( 'jquery', 'backbone', 'underscore' ), false, 1 );
    508         did_action( 'init' ) && $scripts->localize( 'wp-api', 'wpApiSettings', array(
    509                 'root'          => esc_url_raw( get_rest_url() ),
    510                 'nonce'         => ( wp_installing() && ! is_multisite() ) ? '' : wp_create_nonce( 'wp_rest' ),
    511                 'versionString' => 'wp/v2/',
    512         ) );
     515        $scripts->add( 'wp-api', "/wp-includes/js/wp-api$suffix.js", array( 'jquery', 'backbone', 'underscore', 'wp-api-request' ), false, 1 );
    513516
    514517        if ( is_admin() ) {
    515518                $scripts->add( 'admin-tags', "/wp-admin/js/tags$suffix.js", array( 'jquery', 'wp-ajax-response' ), false, 1 );
    function wp_default_scripts( &$scripts ) { 
    602605                $scripts->add( 'admin-gallery', "/wp-admin/js/gallery$suffix.js", array( 'jquery-ui-sortable' ) );
    603606
    604607                $scripts->add( 'admin-widgets', "/wp-admin/js/widgets$suffix.js", array( 'jquery-ui-sortable', 'jquery-ui-draggable', 'jquery-ui-droppable' ), false, 1 );
    605                 $scripts->add( 'media-widgets', "/wp-admin/js/widgets/media-widgets$suffix.js", array( 'jquery', 'media-models', 'media-views' ) );
     608                $scripts->add( 'media-widgets', "/wp-admin/js/widgets/media-widgets$suffix.js", array( 'jquery', 'media-models', 'media-views', 'wp-api-request' ) );
    606609                $scripts->add_inline_script( 'media-widgets', 'wp.mediaWidgets.init();', 'after' );
    607610
    608611                $scripts->add( 'media-audio-widget', "/wp-admin/js/widgets/media-audio-widget$suffix.js", array( 'media-widgets', 'media-audiovideo' ) );
    609612                $scripts->add( 'media-image-widget', "/wp-admin/js/widgets/media-image-widget$suffix.js", array( 'media-widgets' ) );
    610                 $scripts->add( 'media-video-widget', "/wp-admin/js/widgets/media-video-widget$suffix.js", array( 'media-widgets', 'media-audiovideo' ) );
     613                $scripts->add( 'media-video-widget', "/wp-admin/js/widgets/media-video-widget$suffix.js", array( 'media-widgets', 'media-audiovideo', 'wp-api-request' ) );
    611614                $scripts->add( 'text-widgets', "/wp-admin/js/widgets/text-widgets$suffix.js", array( 'jquery', 'backbone', 'editor', 'wp-util' ) );
    612615                $scripts->add_inline_script( 'text-widgets', 'wp.textWidgets.init();', 'after' );
    613616
  • tests/qunit/index.html

    diff --git a/tests/qunit/index.html b/tests/qunit/index.html
    index c41fffe..29dfe79 100644
    a b  
    1919                </script>
    2020                <script>
    2121                        var wpApiSettings = {
    22                                 'root': 'http://localhost/wp-json/'
     22                                root: 'http://localhost/wp-json/',
     23                                nonce: 'not_a_nonce'
    2324                        };
    2425                </script>
    2526                <script src="../../src/wp-includes/js/wp-util.js"></script>
     
    7778                <script src="../../src/wp-includes/js/customize-models.js"></script>
    7879                <script src="../../src/wp-includes/js/shortcode.js"></script>
    7980                <script src="../../src/wp-admin/js/customize-controls.js"></script>
     81                <script src="../../src/wp-includes/js/api-request.js"></script>
    8082                <script src="../../src/wp-includes/js/wp-api.js"></script>
    8183
    8284                <script type='text/javascript' src='../../src/wp-includes/js/jquery/ui/core.js'></script>
     
    122124                <script src="wp-admin/js/customize-base.js"></script>
    123125                <script src="wp-admin/js/customize-header.js"></script>
    124126                <script src="wp-includes/js/shortcode.js"></script>
     127                <script src="wp-includes/js/api-request.js"></script>
    125128                <script src="wp-includes/js/wp-api.js"></script>
    126129                <script src="wp-admin/js/customize-controls.js"></script>
    127130                <script src="wp-admin/js/customize-controls-utils.js"></script>
  • new file tests/qunit/wp-includes/js/api-request.js

    diff --git a/tests/qunit/wp-includes/js/api-request.js b/tests/qunit/wp-includes/js/api-request.js
    new file mode 100644
    index 0000000..c52cf0a
    - +  
     1/* global wp, wpApiSettings */
     2( function( QUnit ) {
     3        var originalRootUrl = window.wpApiSettings.root;
     4
     5        var nonceHeader = { 'X-WP-Nonce': 'not_a_nonce' };
     6
     7        QUnit.module( 'wp-api-request', {
     8                afterEach: function() {
     9                        window.wpApiSettings.root = originalRootUrl;
     10                }
     11        } );
     12
     13        QUnit.test( 'does not mutate original object', function( assert ) {
     14                var settingsOriginal = {
     15                        url: 'aaaaa',
     16                        path: 'wp/v2/posts',
     17                        headers: {
     18                                'Header-Name': 'value'
     19                        },
     20                        data: {
     21                                orderby: 'something'
     22                        }
     23                };
     24
     25                var settings = wp.apiRequest.buildAjaxOptions( settingsOriginal );
     26
     27                assert.notStrictEqual( settings, settingsOriginal );
     28                assert.notStrictEqual( settings.headers, settingsOriginal.headers );
     29                assert.strictEqual( settings.data, settingsOriginal.data );
     30
     31                assert.deepEqual( settings, {
     32                        url: 'http://localhost/wp-json/wp/v2/posts',
     33                        headers: {
     34                                'X-WP-Nonce': 'not_a_nonce',
     35                                'Header-Name': 'value'
     36                        },
     37                        data: {
     38                                orderby: 'something'
     39                        }
     40                } );
     41
     42                assert.deepEqual( settingsOriginal, {
     43                        url: 'aaaaa',
     44                        path: 'wp/v2/posts',
     45                        headers: {
     46                                'Header-Name': 'value'
     47                        },
     48                        data: {
     49                                orderby: 'something'
     50                        }
     51                } );
     52        } );
     53
     54        QUnit.test( 'accepts namespace and endpoint', function( assert ) {
     55                assert.deepEqual( wp.apiRequest.buildAjaxOptions( {
     56                        namespace: 'wp/v2',
     57                        endpoint: 'posts'
     58                } ), {
     59                        url: 'http://localhost/wp-json/wp/v2/posts',
     60                        headers: nonceHeader
     61                } );
     62        } );
     63
     64        QUnit.test( 'accepts namespace and endpoint with slashes', function( assert ) {
     65                assert.deepEqual( wp.apiRequest.buildAjaxOptions( {
     66                        namespace: '/wp/v2/',
     67                        endpoint: '/posts'
     68                } ), {
     69                        url: 'http://localhost/wp-json/wp/v2/posts',
     70                        headers: nonceHeader
     71                } );
     72        } );
     73
     74        QUnit.test( 'accepts namespace and empty endpoint', function( assert ) {
     75                assert.deepEqual( wp.apiRequest.buildAjaxOptions( {
     76                        namespace: 'wp/v2',
     77                        endpoint: ''
     78                } ), {
     79                        url: 'http://localhost/wp-json/wp/v2',
     80                        headers: nonceHeader
     81                } );
     82        } );
     83
     84        QUnit.test( 'accepts empty namespace and empty endpoint', function( assert ) {
     85                assert.deepEqual( wp.apiRequest.buildAjaxOptions( {
     86                        namespace: '',
     87                        endpoint: ''
     88                } ), {
     89                        url: 'http://localhost/wp-json/',
     90                        headers: nonceHeader
     91                } );
     92        } );
     93
     94        QUnit.test(
     95                'accepts namespace and endpoint with slashes (plain permalinks)',
     96                function( assert ) {
     97                        window.wpApiSettings.root = 'http://localhost/?rest_route=/';
     98                        assert.deepEqual( wp.apiRequest.buildAjaxOptions( {
     99                                namespace: '/wp/v2/',
     100                                endpoint: '/posts'
     101                        } ), {
     102                                url: 'http://localhost/?rest_route=/wp/v2/posts',
     103                                headers: nonceHeader
     104                        } );
     105                }
     106        );
     107
     108        QUnit.test(
     109                'accepts empty namespace and empty endpoint (plain permalinks)',
     110                function( assert ) {
     111                        window.wpApiSettings.root = 'http://localhost/?rest_route=/';
     112                        assert.deepEqual( wp.apiRequest.buildAjaxOptions( {
     113                                namespace: '',
     114                                endpoint: ''
     115                        } ), {
     116                                url: 'http://localhost/?rest_route=/',
     117                                headers: nonceHeader
     118                        } );
     119                }
     120        );
     121} )( window.QUnit );