Make WordPress Core


Ignore:
Timestamp:
01/28/2025 04:07:07 AM (5 months ago)
Author:
spacedmonkey
Message:

REST API: Introduce filter for controlling menu read access.

The menu, menu item, and menu location endpoints were added to the REST API in [52079]. In that commit, menu data was treated as private and restricted to logged-in users with the edit_theme_options capability. However, in many cases, this data can be considered public. Previously, there was no simple way for developers to allow this data to be exposed via the REST API.

This commit introduces the rest_menu_read_access filter, enabling developers to control read access to menus, menu items, and menu locations in the REST API. The same filter is applied across all three REST API classes, simplifying the process of opting into exposing this data.

Each instance of the filter provides the current request and the relevant class instance as context, allowing developers to selectively or globally enable access to the data.

Props spacedmonkey, antonvlasenko, kadamwhite, julianmar, masteradhoc.
Fixes #54304.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php

    r58704 r59718  
    8181     */
    8282    public function get_items_permissions_check( $request ) {
     83        return $this->check_has_read_only_access( $request );
     84    }
     85
     86    /**
     87     * Retrieves all menu locations, depending on user context.
     88     *
     89     * @since 5.9.0
     90     *
     91     * @param WP_REST_Request $request Full details about the request.
     92     * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
     93     */
     94    public function get_items( $request ) {
     95        $data = array();
     96
     97        foreach ( get_registered_nav_menus() as $name => $description ) {
     98            $location              = new stdClass();
     99            $location->name        = $name;
     100            $location->description = $description;
     101
     102            $location      = $this->prepare_item_for_response( $location, $request );
     103            $data[ $name ] = $this->prepare_response_for_collection( $location );
     104        }
     105
     106        return rest_ensure_response( $data );
     107    }
     108
     109    /**
     110     * Checks if a given request has access to read a menu location.
     111     *
     112     * @since 5.9.0
     113     *
     114     * @param WP_REST_Request $request Full details about the request.
     115     * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise.
     116     */
     117    public function get_item_permissions_check( $request ) {
     118        return $this->check_has_read_only_access( $request );
     119    }
     120
     121    /**
     122     * Retrieves a specific menu location.
     123     *
     124     * @since 5.9.0
     125     *
     126     * @param WP_REST_Request $request Full details about the request.
     127     * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
     128     */
     129    public function get_item( $request ) {
     130        $registered_menus = get_registered_nav_menus();
     131        if ( ! array_key_exists( $request['location'], $registered_menus ) ) {
     132            return new WP_Error( 'rest_menu_location_invalid', __( 'Invalid menu location.' ), array( 'status' => 404 ) );
     133        }
     134
     135        $location              = new stdClass();
     136        $location->name        = $request['location'];
     137        $location->description = $registered_menus[ $location->name ];
     138
     139        $data = $this->prepare_item_for_response( $location, $request );
     140
     141        return rest_ensure_response( $data );
     142    }
     143
     144    /**
     145     * Checks whether the current user has read permission for the endpoint.
     146     *
     147     * @since 6.8.0
     148     *
     149     * @param WP_REST_Request $request Full details about the request.
     150     * @return true|WP_Error True if the current user has permission, WP_Error object otherwise.
     151     */
     152    protected function check_has_read_only_access( $request ) {
     153        /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php */
     154        $read_only_access = apply_filters( 'rest_menu_read_access', false, $request, $this );
     155        if ( $read_only_access ) {
     156            return true;
     157        }
     158
    83159        if ( ! current_user_can( 'edit_theme_options' ) ) {
    84160            return new WP_Error(
     
    90166
    91167        return true;
    92     }
    93 
    94     /**
    95      * Retrieves all menu locations, depending on user context.
    96      *
    97      * @since 5.9.0
    98      *
    99      * @param WP_REST_Request $request Full details about the request.
    100      * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
    101      */
    102     public function get_items( $request ) {
    103         $data = array();
    104 
    105         foreach ( get_registered_nav_menus() as $name => $description ) {
    106             $location              = new stdClass();
    107             $location->name        = $name;
    108             $location->description = $description;
    109 
    110             $location      = $this->prepare_item_for_response( $location, $request );
    111             $data[ $name ] = $this->prepare_response_for_collection( $location );
    112         }
    113 
    114         return rest_ensure_response( $data );
    115     }
    116 
    117     /**
    118      * Checks if a given request has access to read a menu location.
    119      *
    120      * @since 5.9.0
    121      *
    122      * @param WP_REST_Request $request Full details about the request.
    123      * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise.
    124      */
    125     public function get_item_permissions_check( $request ) {
    126         if ( ! current_user_can( 'edit_theme_options' ) ) {
    127             return new WP_Error(
    128                 'rest_cannot_view',
    129                 __( 'Sorry, you are not allowed to view menu locations.' ),
    130                 array( 'status' => rest_authorization_required_code() )
    131             );
    132         }
    133 
    134         return true;
    135     }
    136 
    137     /**
    138      * Retrieves a specific menu location.
    139      *
    140      * @since 5.9.0
    141      *
    142      * @param WP_REST_Request $request Full details about the request.
    143      * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
    144      */
    145     public function get_item( $request ) {
    146         $registered_menus = get_registered_nav_menus();
    147         if ( ! array_key_exists( $request['location'], $registered_menus ) ) {
    148             return new WP_Error( 'rest_menu_location_invalid', __( 'Invalid menu location.' ), array( 'status' => 404 ) );
    149         }
    150 
    151         $location              = new stdClass();
    152         $location->name        = $request['location'];
    153         $location->description = $registered_menus[ $location->name ];
    154 
    155         $data = $this->prepare_item_for_response( $location, $request );
    156 
    157         return rest_ensure_response( $data );
    158168    }
    159169
Note: See TracChangeset for help on using the changeset viewer.