Make WordPress Core


Ignore:
Timestamp:
07/02/2020 05:55:04 AM (4 years ago)
Author:
TimothyBlynJacobs
Message:

REST API: Link to the REST route for the currently queried resource.

This allows for programatically determining the REST version of the current page. The links also aid human discovery of the REST API in general.

Props dshanske, tfrommen, TimothyBlynJacobs.
Fixes #49116.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/rest-api.php

    r48242 r48273  
    235235    // Terms.
    236236    foreach ( get_taxonomies( array( 'show_in_rest' => true ), 'object' ) as $taxonomy ) {
    237         $class = ! empty( $taxonomy->rest_controller_class ) ? $taxonomy->rest_controller_class : 'WP_REST_Terms_Controller';
    238 
    239         if ( ! class_exists( $class ) ) {
    240             continue;
    241         }
    242         $controller = new $class( $taxonomy->name );
    243         if ( ! is_subclass_of( $controller, 'WP_REST_Controller' ) ) {
     237        $controller = $taxonomy->get_rest_controller();
     238
     239        if ( ! $controller ) {
    244240            continue;
    245241        }
     
    874870    }
    875871
    876     echo "<link rel='https://api.w.org/' href='" . esc_url( $api_root ) . "' />\n";
     872    printf( '<link rel="https://api.w.org/" href="%s" />', esc_url( $api_root ) );
     873
     874    $resource = rest_get_queried_resource_route();
     875
     876    if ( $resource ) {
     877        printf( '<link rel="alternate" type="application/json" href="%s" />', esc_url( rest_url( $resource ) ) );
     878    }
    877879}
    878880
     
    893895    }
    894896
    895     header( 'Link: <' . esc_url_raw( $api_root ) . '>; rel="https://api.w.org/"', false );
     897    header( sprintf( 'Link: <%s>; rel="https://api.w.org/"', esc_url_raw( $api_root ) ), false );
     898
     899    $resource = rest_get_queried_resource_route();
     900
     901    if ( $resource ) {
     902        header( sprintf( 'Link: <%s>; rel="alternate"; type="application/json"', esc_url_raw( rest_url( $resource ) ) ), false );
     903    }
    896904}
    897905
     
    18241832    return $schema;
    18251833}
     1834
     1835/**
     1836 * Gets the REST API route for a post.
     1837 *
     1838 * @since 5.5.0
     1839 *
     1840 * @param int|WP_Post $post Post ID or post object.
     1841 * @return string The route path with a leading slash for the given post, or an empty string if there is not a route.
     1842 */
     1843function rest_get_route_for_post( $post ) {
     1844    $post = get_post( $post );
     1845
     1846    if ( ! $post instanceof WP_Post ) {
     1847        return '';
     1848    }
     1849
     1850    $post_type = get_post_type_object( $post->post_type );
     1851    if ( ! $post_type ) {
     1852        return '';
     1853    }
     1854
     1855    $controller = $post_type->get_rest_controller();
     1856    if ( ! $controller ) {
     1857        return '';
     1858    }
     1859
     1860    $route = '';
     1861
     1862    // The only two controllers that we can detect are the Attachments and Posts controllers.
     1863    if ( in_array( get_class( $controller ), array( 'WP_REST_Attachments_Controller', 'WP_REST_Posts_Controller' ), true ) ) {
     1864        $namespace = 'wp/v2';
     1865        $rest_base = ! empty( $post_type->rest_base ) ? $post_type->rest_base : $post_type->name;
     1866        $route     = sprintf( '/%s/%s/%d', $namespace, $rest_base, $post->ID );
     1867    }
     1868
     1869    /**
     1870     * Filters the REST API route for a post.
     1871     *
     1872     * @since 5.5.0
     1873     *
     1874     * @param string  $route The route path.
     1875     * @param WP_Post $post  The post object.
     1876     */
     1877    return apply_filters( 'rest_route_for_post', $route, $post );
     1878}
     1879
     1880/**
     1881 * Gets the REST API route for a term.
     1882 *
     1883 * @since 5.5.0
     1884 *
     1885 * @param int|WP_Term $term Term ID or term object.
     1886 * @return string The route path with a leading slash for the given term, or an empty string if there is not a route.
     1887 */
     1888function rest_get_route_for_term( $term ) {
     1889    $term = get_term( $term );
     1890
     1891    if ( ! $term instanceof WP_Term ) {
     1892        return '';
     1893    }
     1894
     1895    $taxonomy = get_taxonomy( $term->taxonomy );
     1896    if ( ! $taxonomy ) {
     1897        return '';
     1898    }
     1899
     1900    $controller = $taxonomy->get_rest_controller();
     1901    if ( ! $controller ) {
     1902        return '';
     1903    }
     1904
     1905    $route = '';
     1906
     1907    // The only controller that works is the Terms controller.
     1908    if ( 'WP_REST_Terms_Controller' === get_class( $controller ) ) {
     1909        $namespace = 'wp/v2';
     1910        $rest_base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name;
     1911        $route     = sprintf( '/%s/%s/%d', $namespace, $rest_base, $term->term_id );
     1912    }
     1913
     1914    /**
     1915     * Filters the REST API route for a term.
     1916     *
     1917     * @since 5.5.0
     1918     *
     1919     * @param string  $route The route path.
     1920     * @param WP_Term $term  The term object.
     1921     */
     1922    return apply_filters( 'rest_route_for_term', $route, $term );
     1923}
     1924
     1925/**
     1926 * Gets the REST route for the currently queried object.
     1927 *
     1928 * @since 5.5.0
     1929 *
     1930 * @return string The REST route of the resource, or an empty string if no resource identified.
     1931 */
     1932function rest_get_queried_resource_route() {
     1933    if ( is_singular() ) {
     1934        $route = rest_get_route_for_post( get_queried_object() );
     1935    } elseif ( is_category() || is_tag() || is_tax() ) {
     1936        $route = rest_get_route_for_term( get_queried_object() );
     1937    } elseif ( is_author() ) {
     1938        $route = '/wp/v2/users/' . get_queried_object_id();
     1939    } else {
     1940        $route = '';
     1941    }
     1942
     1943    /**
     1944     * Filters the REST route for the currently queried object.
     1945     *
     1946     * @since 5.5.0
     1947     *
     1948     * @param string $link The route with a leading slash, or an empty string.
     1949     */
     1950    return apply_filters( 'rest_queried_resource_route', $route );
     1951}
Note: See TracChangeset for help on using the changeset viewer.