Make WordPress Core

Changeset 51964


Ignore:
Timestamp:
11/01/2021 03:26:06 AM (3 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.