Make WordPress Core

Ticket #40878: 40878.1.diff

File 40878.1.diff, 11.3 KB (added by schlessera, 7 years ago)

First draft implementation to start discussion.

  • src/wp-includes/rest-api.php

    diff --git src/wp-includes/rest-api.php src/wp-includes/rest-api.php
    index 697a7cc64b..7cbb8b78d6 100644
    function create_initial_rest_routes() { 
    233233        // Settings.
    234234        $controller = new WP_REST_Settings_Controller;
    235235        $controller->register_routes();
     236
     237        // Menu location.
     238        $controller = new WP_REST_Menu_Locations_Controller;
     239        $controller->register_routes();
    236240}
    237241
    238242/**
  • new file src/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php

    diff --git src/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php src/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php
    new file mode 100644
    index 0000000000..871fde0782
    - +  
     1<?php
     2/**
     3 * REST API: WP_REST_Menu_Locations_Controller class
     4 *
     5 * @package WordPress
     6 * @subpackage REST_API
     7 * @since 4.x.x
     8 */
     9
     10/**
     11 * Core class used to access menu locations via the REST API.
     12 *
     13 * @since 4.x.x
     14 *
     15 * @see WP_REST_Controller
     16 */
     17class WP_REST_Menu_Locations_Controller extends WP_REST_Controller {
     18
     19        /**
     20         * Constructor.
     21         *
     22         * @since 4.x.x
     23         */
     24        public function __construct() {
     25                $this->namespace = 'wp/v2';
     26                $this->rest_base = 'menu-locations';
     27        }
     28
     29        /**
     30         * Registers the routes for the objects of the controller.
     31         *
     32         * @since 4.x.x
     33         *
     34         * @see register_rest_route()
     35         */
     36        public function register_routes() {
     37
     38                register_rest_route( $this->namespace, '/' . $this->rest_base, array(
     39                        array(
     40                                'methods'             => WP_REST_Server::READABLE,
     41                                'callback'            => array( $this, 'get_items' ),
     42                                'permission_callback' => array( $this, 'get_items_permissions_check' ),
     43                                'args'                => $this->get_collection_params(),
     44                        ),
     45                        'schema' => array( $this, 'get_public_item_schema' ),
     46                ) );
     47
     48                register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<location>[\w-]+)', array(
     49                        'args' => array(
     50                                'location' => array(
     51                                        'description' => __( 'An alphanumeric identifier for the menu location.' ),
     52                                        'type'        => 'string',
     53                                ),
     54                        ),
     55                        array(
     56                                'methods'             => WP_REST_Server::READABLE,
     57                                'callback'            => array( $this, 'get_item' ),
     58                                'permission_callback' => array( $this, 'get_item_permissions_check' ),
     59                                'args'                => array(
     60                                        'context' => $this->get_context_param( array( 'default' => 'view' ) ),
     61                                ),
     62                        ),
     63                        'schema' => array( $this, 'get_public_item_schema' ),
     64                ) );
     65        }
     66
     67        /**
     68         * Checks whether a given request has permission to read menu locations.
     69         *
     70         * @since 4.x.x
     71         *
     72         * @param WP_REST_Request $request Full details about the request.
     73         * @return WP_Error|bool True if the request has read access, WP_Error object otherwise.
     74         */
     75        public function get_items_permissions_check( $request ) {
     76                if ( 'edit' === $request['context'] ) {
     77                        $types = get_post_types( array( 'show_in_rest' => true ), 'objects' );
     78
     79                        foreach ( $types as $type ) {
     80                                if ( current_user_can( $type->cap->edit_posts ) ) {
     81                                        return true;
     82                                }
     83                        }
     84                        return new WP_Error( 'rest_cannot_view', __( 'Sorry, you are not allowed to manage menu locations.' ), array( 'status' => rest_authorization_required_code() ) );
     85                }
     86
     87                return true;
     88        }
     89
     90        /**
     91         * Retrieves all menu locations, depending on user context.
     92         *
     93         * @since 4.x.x
     94         *
     95         * @param WP_REST_Request $request Full details about the request.
     96         * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
     97         */
     98        public function get_items( $request ) {
     99                $data = array();
     100
     101                foreach ( get_registered_nav_menus() as $name => $description ) {
     102                        $location = new stdClass();
     103                        $location->name = $name;
     104                        $location->description = $description;
     105
     106                        $location = $this->prepare_item_for_response( $location, $request );
     107                        $data[ $name ] = $this->prepare_response_for_collection( $location );
     108                }
     109
     110                return rest_ensure_response( $data );
     111        }
     112
     113        /**
     114         * Checks if a given request has access to read a menu location.
     115         *
     116         * @since 4.x.x
     117         *
     118         * @param WP_REST_Request $request Full details about the request.
     119         * @return WP_Error|bool True if the request has read access for the item, WP_Error object otherwise.
     120         */
     121        public function get_item_permissions_check( $request ) {
     122                if ( ! array_key_exists( $request['location'], get_registered_nav_menus() ) ) {
     123                        return new WP_Error( 'rest_menu_location_invalid', __( 'Invalid menu location.' ), array( 'status' => 404 ) );
     124                }
     125
     126                return true;
     127        }
     128
     129        /**
     130         * Retrieves a specific menu location.
     131         *
     132         * @since 4.x.x
     133         *
     134         * @param WP_REST_Request $request Full details about the request.
     135         * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
     136         */
     137        public function get_item( $request ) {
     138                $registered_menus = get_registered_nav_menus();
     139                if ( ! array_key_exists( $request['location'], $registered_menus ) ) {
     140                        return new WP_Error( 'rest_menu_location_invalid', __( 'Invalid menu location.' ), array( 'status' => 404 ) );
     141                }
     142
     143                $location = new stdClass();
     144                $location->name = $request['location'];
     145                $location->description = $registered_menus[ $location->name ];
     146
     147                $data = $this->prepare_item_for_response( $location, $request );
     148
     149                return rest_ensure_response( $data );
     150        }
     151
     152        /**
     153         * Prepares a menu location object for serialization.
     154         *
     155         * @since 4.x.x
     156         *
     157         * @param stdClass        $location  Post status data.
     158         * @param WP_REST_Request $request Full details about the request.
     159         * @return WP_REST_Response Post status data.
     160         */
     161        public function prepare_item_for_response( $location, $request ) {
     162
     163                $data = array(
     164                        'name'         => $location->name,
     165                        'description'  => $location->description,
     166                );
     167
     168                $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
     169                $data = $this->add_additional_fields_to_object( $data, $request );
     170                $data = $this->filter_response_by_context( $data, $context );
     171
     172                $response = rest_ensure_response( $data );
     173
     174                $response->add_links( $this->prepare_links( $location ) );
     175
     176                /**
     177                 * Filters a menu location returned from the REST API.
     178                 *
     179                 * Allows modification of the menu location data right before it is
     180                 * returned.
     181                 *
     182                 * @since 4.x.x
     183                 *
     184                 * @param WP_REST_Response $response The response object.
     185                 * @param object           $location The original status object.
     186                 * @param WP_REST_Request  $request  Request used to generate the response.
     187                 */
     188                return apply_filters( 'rest_prepare_menu_location', $response, $location, $request );
     189        }
     190
     191        /**
     192         * Retrieves the menu location's schema, conforming to JSON Schema.
     193         *
     194         * @since 4.x.x
     195         *
     196         * @return array Item schema data.
     197         */
     198        public function get_item_schema() {
     199                $schema = array(
     200                        '$schema'              => 'http://json-schema.org/draft-04/schema#',
     201                        'title'                => 'menu-location',
     202                        'type'                 => 'object',
     203                        'properties'           => array(
     204                                'name'             => array(
     205                                        'description'  => __( 'The name of the menu location.' ),
     206                                        'type'         => 'string',
     207                                        'context'      => array( 'embed', 'view', 'edit' ),
     208                                        'readonly'     => true,
     209                                ),
     210                                'description'      => array(
     211                                        'description'  => __( 'The description of the menu location.' ),
     212                                        'type'         => 'string',
     213                                        'context'      => array( 'embed', 'view', 'edit' ),
     214                                        'readonly'     => true,
     215                                ),
     216                        ),
     217                );
     218
     219                return $this->add_additional_fields_schema( $schema );
     220        }
     221
     222        /**
     223         * Retrieves the query params for collections.
     224         *
     225         * @since 4.x.x
     226         *
     227         * @return array Collection parameters.
     228         */
     229        public function get_collection_params() {
     230                return array(
     231                        'context' => $this->get_context_param( array( 'default' => 'view' ) ),
     232                );
     233        }
     234
     235        /**
     236         * Prepares links for the request.
     237         *
     238         * @since 4.x.x
     239         *
     240         * @param stdClass $location Menu location.
     241         * @return array Links for the given menu location.
     242         */
     243        protected function prepare_links( $location ) {
     244                $base = sprintf( '%s/%s', $this->namespace, $this->rest_base );
     245
     246                // Entity meta.
     247                $links = array(
     248                        'self' => array(
     249                                'href'   => rest_url( trailingslashit( $base ) . $location->name ),
     250                        ),
     251                        'collection' => array(
     252                                'href'   => rest_url( $base ),
     253                        ),
     254                );
     255
     256                $menus = get_nav_menu_locations();
     257                if ( array_key_exists( $location->name, $menus ) ) {
     258                        $id = $menus[ $location->name ];
     259                        $items_url = rest_url( "wp/v2/menus/${id}" );
     260
     261                        $links['menus'] = array(
     262                                'href'       => $items_url,
     263                                'embeddable' => true,
     264                        );
     265                }
     266
     267                return $links;
     268        }
     269}
  • new file src/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php

    diff --git src/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php src/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php
    new file mode 100644
    index 0000000000..076fa97a4c
    - +  
     1<?php
     2/**
     3 * REST API: WP_REST_Menus_Controller class
     4 *
     5 * @package WordPress
     6 * @subpackage REST_API
     7 * @since 4.x.x
     8 */
     9
     10/**
     11 * Core class used to access menus via the REST API.
     12 *
     13 * @since 4.x.x
     14 *
     15 * @see WP_REST_Controller
     16 */
     17class WP_REST_Menus_Controller extends WP_REST_Terms_Controller {
     18
     19        /**
     20         * Prepares links for the request.
     21         *
     22         * @since 4.x.x
     23         *
     24         * @param object $term Term object.
     25         * @return array Links for the given term.
     26         */
     27        protected function prepare_links( $term ) {
     28                $links = parent::prepare_links( $term );
     29
     30                // Let's make sure that menu items are embeddable for a menu collection.
     31                if ( array_key_exists( 'https://api.w.org/post_type', $links ) ) {
     32                        $post_type_links = $links['https://api.w.org/post_type'];
     33
     34                        foreach ( $post_type_links as $index => $post_type_link ) {
     35                                if ( ! array_key_exists( 'href', $post_type_link ) || strpos( $post_type_link['href'], '/menu-items?' ) === false ) {
     36                                        continue;
     37                                }
     38
     39                                $post_type_links[ $index ]['embeddable'] = true;
     40                        }
     41
     42                        $links['https://api.w.org/post_type'] = $post_type_links;
     43                }
     44
     45                return $links;
     46        }
     47}
  • src/wp-includes/taxonomy.php

    diff --git src/wp-includes/taxonomy.php src/wp-includes/taxonomy.php
    index fabe724367..1450d348e7 100644
    function create_initial_taxonomies() { 
    105105                'show_in_nav_menus' => false,
    106106                'show_in_rest' => true,
    107107                'rest_base' => 'menus',
    108                 'rest_controller_class' => 'WP_REST_Terms_Controller',
     108                'rest_controller_class' => 'WP_REST_Menus_Controller',
    109109        ) );
    110110
    111111        register_taxonomy( 'link_category', 'link', array(
  • src/wp-settings.php

    diff --git src/wp-settings.php src/wp-settings.php
    index bacf4cfddd..9557cb4041 100644
    require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-terms-controller.p 
    234234require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-users-controller.php' );
    235235require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-comments-controller.php' );
    236236require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-settings-controller.php' );
     237require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-menus-controller.php' );
     238require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-menu-locations-controller.php' );
    237239require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-meta-fields.php' );
    238240require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-comment-meta-fields.php' );
    239241require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-post-meta-fields.php' );