Make WordPress Core

Changeset 51964


Ignore:
Timestamp:
11/01/2021 03:26:06 AM (5 years ago)
Author:
TimothyBlynJacobs
Message:

REST API: Support custom namespaces for taxonomies.

While a taxonomy can define a custom route by using the rest_base argument, a namespace of wp/v2 was assumed. This commit introduces support for a rest_namespace argument.

A new rest_get_route_for_taxonomy_items function has been introduced and the rest_get_route_for_term function updated to facilitate getting the correct route for taxonomies.

For maximum compatibility sticking with the default wp/v2 namespace is recommended until the API functions see wider use.

Props spacedmonkey.
Fixes #54267.
See [51962].

Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-taxonomy.php

    r50119 r51964  
    199199         */
    200200        public $rest_base;
     201
     202        /**
     203         * The namespace for this taxonomy's REST API endpoints.
     204         *
     205         * @since 5.9
     206         * @var string|bool $rest_namespace
     207         */
     208        public $rest_namespace;
    201209
    202210        /**
     
    320328                        'show_in_rest'          => false,
    321329                        'rest_base'             => false,
     330                        'rest_namespace'        => false,
    322331                        'rest_controller_class' => false,
    323332                        'default_term'          => null,
     
    383392                if ( null === $args['show_in_quick_edit'] ) {
    384393                        $args['show_in_quick_edit'] = $args['show_ui'];
     394                }
     395
     396                // If not set, default rest_namespace to wp/v2 if show_in_rest is true.
     397                if ( false === $args['rest_namespace'] && ! empty( $args['show_in_rest'] ) ) {
     398                        $args['rest_namespace'] = 'wp/v2';
    385399                }
    386400
  • trunk/src/wp-includes/rest-api.php

    r51962 r51964  
    31163116        }
    31173117
    3118         $taxonomy = get_taxonomy( $term->taxonomy );
    3119         if ( ! $taxonomy ) {
     3118        $taxonomy_route = rest_get_route_for_taxonomy_items( $term->taxonomy );
     3119        if ( ! $taxonomy_route ) {
    31203120                return '';
    31213121        }
    31223122
    3123         $controller = $taxonomy->get_rest_controller();
    3124         if ( ! $controller ) {
    3125                 return '';
    3126         }
    3127 
    3128         $route = '';
    3129 
    3130         // The only controller that works is the Terms controller.
    3131         if ( $controller instanceof WP_REST_Terms_Controller ) {
    3132                 $namespace = 'wp/v2';
    3133                 $rest_base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name;
    3134                 $route     = sprintf( '/%s/%s/%d', $namespace, $rest_base, $term->term_id );
    3135         }
     3123        $route = sprintf( '%s/%d', $taxonomy_route, $term->term_id );
    31363124
    31373125        /**
     
    31443132         */
    31453133        return apply_filters( 'rest_route_for_term', $route, $term );
     3134}
     3135
     3136/**
     3137 * Gets the REST API route for a taxonomy.
     3138 *
     3139 * @since 5.9.0
     3140 *
     3141 * @param string $taxonomy Name of taxonomy.
     3142 * @return string The route path with a leading slash for the given taxonomy.
     3143 */
     3144function rest_get_route_for_taxonomy_items( $taxonomy ) {
     3145        $taxonomy = get_taxonomy( $taxonomy );
     3146        if ( ! $taxonomy ) {
     3147                return '';
     3148        }
     3149
     3150        if ( ! $taxonomy->show_in_rest ) {
     3151                return '';
     3152        }
     3153
     3154        $namespace = ! empty( $taxonomy->rest_namespace ) ? $taxonomy->rest_namespace : 'wp/v2';
     3155        $rest_base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name;
     3156        $route     = sprintf( '/%s/%s', $namespace, $rest_base );
     3157
     3158        /**
     3159         * Filters the REST API route for a taxonomy.
     3160         *
     3161         * @since 5.9.0
     3162         *
     3163         * @param string      $route    The route path.
     3164         * @param WP_Taxonomy $taxonomy The taxonomy object.
     3165         */
     3166        return apply_filters( 'rest_route_for_taxonomy_items', $route, $taxonomy );
    31463167}
    31473168
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php

    r51962 r51964  
    20612061
    20622062                        foreach ( $taxonomies as $tax ) {
    2063                                 $taxonomy_obj = get_taxonomy( $tax );
     2063                                $taxonomy_route = rest_get_route_for_taxonomy_items( $tax );
    20642064
    20652065                                // Skip taxonomies that are not public.
    2066                                 if ( empty( $taxonomy_obj->show_in_rest ) ) {
     2066                                if ( empty( $taxonomy_route ) ) {
    20672067                                        continue;
    20682068                                }
    2069 
    2070                                 $tax_base = ! empty( $taxonomy_obj->rest_base ) ? $taxonomy_obj->rest_base : $tax;
    2071 
    20722069                                $terms_url = add_query_arg(
    20732070                                        'post',
    20742071                                        $post->ID,
    2075                                         rest_url( 'wp/v2/' . $tax_base )
     2072                                        rest_url( $taxonomy_route )
    20762073                                );
    20772074
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php

    r51786 r51964  
    251251                }
    252252
     253                if ( in_array( 'rest_namespace', $fields, true ) ) {
     254                        $data['rest_namespace'] = $taxonomy->rest_namespace;
     255                }
     256
    253257                if ( in_array( 'visibility', $fields, true ) ) {
    254258                        $data['visibility'] = array(
     
    275279                                ),
    276280                                'https://api.w.org/items' => array(
    277                                         'href' => rest_url( sprintf( 'wp/v2/%s', $base ) ),
     281                                        'href' => rest_url( rest_get_route_for_taxonomy_items( $taxonomy->name ) ),
    278282                                ),
    279283                        )
     
    311315                        'type'       => 'object',
    312316                        'properties' => array(
    313                                 'capabilities' => array(
     317                                'capabilities'   => array(
    314318                                        'description' => __( 'All capabilities used by the taxonomy.' ),
    315319                                        'type'        => 'object',
     
    317321                                        'readonly'    => true,
    318322                                ),
    319                                 'description'  => array(
     323                                'description'    => array(
    320324                                        'description' => __( 'A human-readable description of the taxonomy.' ),
    321325                                        'type'        => 'string',
     
    323327                                        'readonly'    => true,
    324328                                ),
    325                                 'hierarchical' => array(
     329                                'hierarchical'   => array(
    326330                                        'description' => __( 'Whether or not the taxonomy should have children.' ),
    327331                                        'type'        => 'boolean',
     
    329333                                        'readonly'    => true,
    330334                                ),
    331                                 'labels'       => array(
     335                                'labels'         => array(
    332336                                        'description' => __( 'Human-readable labels for the taxonomy for various contexts.' ),
    333337                                        'type'        => 'object',
     
    335339                                        'readonly'    => true,
    336340                                ),
    337                                 'name'         => array(
     341                                'name'           => array(
    338342                                        'description' => __( 'The title for the taxonomy.' ),
    339343                                        'type'        => 'string',
     
    341345                                        'readonly'    => true,
    342346                                ),
    343                                 'slug'         => array(
     347                                'slug'           => array(
    344348                                        'description' => __( 'An alphanumeric identifier for the taxonomy.' ),
    345349                                        'type'        => 'string',
     
    347351                                        'readonly'    => true,
    348352                                ),
    349                                 'show_cloud'   => array(
     353                                'show_cloud'     => array(
    350354                                        'description' => __( 'Whether or not the term cloud should be displayed.' ),
    351355                                        'type'        => 'boolean',
     
    353357                                        'readonly'    => true,
    354358                                ),
    355                                 'types'        => array(
     359                                'types'          => array(
    356360                                        'description' => __( 'Types associated with the taxonomy.' ),
    357361                                        'type'        => 'array',
     
    362366                                        'readonly'    => true,
    363367                                ),
    364                                 'rest_base'    => array(
     368                                'rest_base'      => array(
    365369                                        'description' => __( 'REST base route for the taxonomy.' ),
    366370                                        'type'        => 'string',
     
    368372                                        'readonly'    => true,
    369373                                ),
    370                                 'visibility'   => array(
     374                                'rest_namespace' => array(
     375                                        'description' => __( 'REST namespace route for the taxonomy.' ),
     376                                        'type'        => 'string',
     377                                        'context'     => array( 'view', 'edit', 'embed' ),
     378                                        'readonly'    => true,
     379                                ),
     380                                'visibility'     => array(
    371381                                        'description' => __( 'The visibility settings for the taxonomy.' ),
    372382                                        'type'        => 'object',
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php

    r51962 r51964  
    5858        public function __construct( $taxonomy ) {
    5959                $this->taxonomy  = $taxonomy;
    60                 $this->namespace = 'wp/v2';
    6160                $tax_obj         = get_taxonomy( $taxonomy );
    6261                $this->rest_base = ! empty( $tax_obj->rest_base ) ? $tax_obj->rest_base : $tax_obj->name;
     62                $this->namespace = ! empty( $tax_obj->rest_namespace ) ? $tax_obj->rest_namespace : 'wp/v2';
    6363
    6464                $this->meta = new WP_REST_Term_Meta_Fields( $taxonomy );
  • trunk/src/wp-includes/taxonomy.php

    r51885 r51964  
    388388 *                                                for the taxonomy to be available in the block editor.
    389389 *     @type string        $rest_base             To change the base url of REST API route. Default is $taxonomy.
     390 *     @type string        $rest_namespace        To change the namespace URL of REST API route. Default is wp/v2.
    390391 *     @type string        $rest_controller_class REST API Controller class name. Default is 'WP_REST_Terms_Controller'.
    391392 *     @type bool          $show_tagcloud         Whether to list the taxonomy in the Tag Cloud Widget controls. If not set,
  • trunk/tests/phpunit/tests/rest-api.php

    r51962 r51964  
    19641964
    19651965        /**
     1966         * @ticket 54267
     1967         */
     1968        public function test_rest_get_route_for_taxonomy_custom_namespace() {
     1969                register_taxonomy(
     1970                        'ct',
     1971                        'post',
     1972                        array(
     1973                                'show_in_rest'   => true,
     1974                                'rest_base'      => 'ct',
     1975                                'rest_namespace' => 'wordpress/v1',
     1976                        )
     1977                );
     1978                $term = self::factory()->term->create_and_get( array( 'taxonomy' => 'ct' ) );
     1979
     1980                $this->assertSame( '/wordpress/v1/ct/' . $term->term_id, rest_get_route_for_term( $term ) );
     1981                unregister_taxonomy( 'ct' );
     1982        }
     1983
     1984        /**
     1985         * @ticket 54267
     1986         */
     1987        public function test_rest_get_route_for_taxonomy_items() {
     1988                $this->assertSame( '/wp/v2/categories', rest_get_route_for_taxonomy_items( 'category' ) );
     1989        }
     1990
     1991        /**
     1992         * @ticket 54267
     1993         */
     1994        public function test_rest_get_route_for_taxonomy_items_custom_namespace() {
     1995                register_taxonomy(
     1996                        'ct',
     1997                        'post',
     1998                        array(
     1999                                'show_in_rest'   => true,
     2000                                'rest_base'      => 'ct',
     2001                                'rest_namespace' => 'wordpress/v1',
     2002                        )
     2003                );
     2004
     2005                $this->assertSame( '/wordpress/v1/ct', rest_get_route_for_taxonomy_items( 'ct' ) );
     2006                unregister_post_type( 'ct' );
     2007        }
     2008
     2009        /**
    19662010         * @ticket 50300
    19672011         *
  • trunk/tests/phpunit/tests/rest-api/rest-taxonomies-controller.php

    r51397 r51964  
    220220                $data       = $response->get_data();
    221221                $properties = $data['schema']['properties'];
    222                 $this->assertCount( 10, $properties );
     222                $this->assertCount( 11, $properties );
    223223                $this->assertArrayHasKey( 'capabilities', $properties );
    224224                $this->assertArrayHasKey( 'description', $properties );
     
    231231                $this->assertArrayHasKey( 'visibility', $properties );
    232232                $this->assertArrayHasKey( 'rest_base', $properties );
     233                $this->assertArrayHasKey( 'rest_namespace', $properties );
    233234        }
    234235
     
    253254                $this->assertSame( $tax_obj->hierarchical, $data['hierarchical'] );
    254255                $this->assertSame( $tax_obj->rest_base, $data['rest_base'] );
     256                $this->assertSame( $tax_obj->rest_namespace, $data['rest_namespace'] );
    255257                $this->assertSame( rest_url( 'wp/v2/taxonomies' ), $links['collection'][0]['href'] );
    256258                $this->assertArrayHasKey( 'https://api.w.org/items', $links );
  • trunk/tests/qunit/fixtures/wp-api-generated.js

    r51962 r51964  
    85908590        "hierarchical": true,
    85918591        "rest_base": "categories",
     8592        "rest_namespace": "wp/v2",
    85928593        "_links": {
    85938594            "collection": [
     
    86198620        "hierarchical": false,
    86208621        "rest_base": "tags",
     8622        "rest_namespace": "wp/v2",
    86218623        "_links": {
    86228624            "collection": [
     
    86498651    ],
    86508652    "hierarchical": true,
    8651     "rest_base": "categories"
     8653    "rest_base": "categories",
     8654    "rest_namespace": "wp/v2"
    86528655};
    86538656
Note: See TracChangeset for help on using the changeset viewer.