Make WordPress Core

Changeset 38832


Ignore:
Timestamp:
10/20/2016 02:54:12 AM (7 years ago)
Author:
rachelbaker
Message:

REST API: Introduce the Content API endpoints.

REST API endpoints for your WordPress content. These endpoints provide machine-readable external access to your WordPress site with a clear, standards-driven interface, allowing new and innovative apps for interacting with your site. These endpoints support all of the following:

  • Posts: Read and write access to all post data, for all types of post-based data, including pages and media.
  • Comments: Read and write access to all comment data. This includes pingbacks and trackbacks.
  • Terms: Read and write access to all term data.
  • Users: Read and write access to all user data. This includes public access to some data for post authors.
  • Meta: Read and write access to metadata for posts, comments, terms, and users, on an opt-in basis from plugins.
  • Settings: Read and write access to settings, on an opt-in basis from plugins and core. This enables API management of key site content values that are technically stored in options, such as site title and byline.

Love your REST API, WordPress! The infrastructure says, "Let's do lunch!" but the content API endpoints say, "You're paying!"

Props rmccue, rachelbaker, danielbachhuber, joehoyle, adamsilverstein, afurculita, ahmadawais, airesvsg, alisspers, antisilent, apokalyptik, artoliukkonen, attitude, boonebgorges, bradyvercher, brianhogg, caseypatrickdriscoll, chopinbach, chredd, christianesperar, chrisvanpatten, claudiolabarbera, claudiosmweb, cmmarslender, codebykat, coderkevin, codfish, codonnell822, daggerhart, danielpunkass, davidbhayes, delphinus, desrosj, dimadin, dotancohen, DrewAPicture, Dudo1985, duncanjbrown, eherman24, eivhyl, eliorivero, elyobo, en-alis, ericandrewlewis, ericpedia, evansobkowicz, fjarrett, frozzare, georgestephanis, greatislander, guavaworks, hideokamoto, hkdobrev, hubdotcom, hurtige, iandunn, ircrash, ironpaperweight, iseulde, Japh, jaredcobb, JDGrimes, jdolan, jdoubleu, jeremyfelt, jimt, jjeaton, jmusal, jnylen0, johanmynhardt, johnbillion, jonathanbardo, jorbin, joshkadis, JPry, jshreve, jtsternberg, JustinSainton, kacperszurek, kadamwhite, kalenjohnson, kellbot, kjbenk, kokarn, krogsgard, kuchenundkakao, kuldipem, kwight, lgedeon, lukepettway, mantismamita, markoheijnen, matrixik, mattheu, mauteri, maxcutler, mayukojpn, michael-arestad, miyauchi, mjbanks, modemlooper, mrbobbybryant, NateWr, nathanrice, netweb, NikV, nullvariable, oskosk, oso96_2000, oxymoron, pcfreak30, pento, peterwilsoncc, Pezzab, phh, pippinsplugins, pjgalbraith, pkevan, pollyplummer, pushred, quasel, QWp6t, schlessera, schrapel, Shelob9, shprink, simonlampen, Soean, solal, tapsboy, tfrommen, tharsheblows, thenbrent, tierra, tlovett1, tnegri, tobych, Toddses, toro_unit, traversal, vanillalounge, vishalkakadiya, wanecek, web2style, webbgaraget, websupporter, westonruter, whyisjake, wonderboymusic, wpsmith, xknown, zyphonic.
Fixes #38373.

Location:
trunk
Files:
38 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/default-filters.php

    r38829 r38832  
    375375// REST API actions.
    376376add_action( 'init',          'rest_api_init' );
    377 add_action( 'rest_api_init', 'rest_api_default_filters', 10, 1 );
     377add_action( 'rest_api_init', 'rest_api_default_filters',   10, 1 );
     378add_action( 'rest_api_init', 'register_initial_settings',  10 );
     379add_action( 'rest_api_init', 'create_initial_rest_routes', 99 );
    378380add_action( 'parse_request', 'rest_api_loaded' );
    379381
  • trunk/src/wp-includes/functions.php

    r38814 r38832  
    34313431
    34323432/**
     3433 * Clean up an array, comma- or space-separated list of slugs.
     3434 *
     3435 * @since 4.7.0
     3436 *
     3437 * @param  array|string $list List of slugs.
     3438 * @return array Sanitized array of slugs.
     3439 */
     3440function wp_parse_slug_list( $list ) {
     3441    if ( ! is_array( $list ) ) {
     3442        $list = preg_split( '/[\s,]+/', $list );
     3443    }
     3444
     3445    foreach ( $list as $key => $value ) {
     3446        $list[ $key ] = sanitize_title( $value );
     3447    }
     3448
     3449    return array_unique( $list );
     3450}
     3451
     3452/**
    34333453 * Extract a slice of an array, given a list of keys.
    34343454 *
  • trunk/src/wp-includes/option.php

    r38818 r38832  
    17091709
    17101710/**
     1711 * Register default settings available in WordPress.
     1712 *
     1713 * The settings registered here are primarily useful for the REST API, so this
     1714 * does not encompass all settings available in WordPress.
     1715 *
     1716 * @since 4.7.0
     1717 */
     1718function register_initial_settings() {
     1719    register_setting( 'general', 'blogname', array(
     1720        'show_in_rest' => array(
     1721            'name' => 'title',
     1722        ),
     1723        'type'         => 'string',
     1724        'description'  => __( 'Site title.' ),
     1725    ) );
     1726
     1727    register_setting( 'general', 'blogdescription', array(
     1728        'show_in_rest' => array(
     1729            'name' => 'description',
     1730        ),
     1731        'type'         => 'string',
     1732        'description'  => __( 'Site description.' ),
     1733    ) );
     1734
     1735    register_setting( 'general', 'siteurl', array(
     1736        'show_in_rest' => array(
     1737            'name'    => 'url',
     1738            'schema'  => array(
     1739                'format' => 'uri',
     1740            ),
     1741        ),
     1742        'type'         => 'string',
     1743        'description'  => __( 'Site URL.' ),
     1744    ) );
     1745
     1746    register_setting( 'general', 'admin_email', array(
     1747        'show_in_rest' => array(
     1748            'name'    => 'email',
     1749            'schema'  => array(
     1750                'format' => 'email',
     1751            ),
     1752        ),
     1753        'type'         => 'string',
     1754        'description'  => __( 'This address is used for admin purposes. If you change this we will send you an email at your new address to confirm it. The new address will not become active until confirmed.' ),
     1755    ) );
     1756
     1757    register_setting( 'general', 'timezone_string', array(
     1758        'show_in_rest' => array(
     1759            'name' => 'timezone',
     1760        ),
     1761        'type'         => 'string',
     1762        'description'  => __( 'A city in the same timezone as you.' ),
     1763    ) );
     1764
     1765    register_setting( 'general', 'date_format', array(
     1766        'show_in_rest' => true,
     1767        'type'         => 'string',
     1768        'description'  => __( 'A date format for all date strings.' ),
     1769    ) );
     1770
     1771    register_setting( 'general', 'time_format', array(
     1772        'show_in_rest' => true,
     1773        'type'         => 'string',
     1774        'description'  => __( 'A time format for all time strings.' ),
     1775    ) );
     1776
     1777    register_setting( 'general', 'start_of_week', array(
     1778        'show_in_rest' => true,
     1779        'type'         => 'number',
     1780        'description'  => __( 'A day number of the week that the week should start on.' ),
     1781    ) );
     1782
     1783    register_setting( 'general', 'WPLANG', array(
     1784        'show_in_rest' => array(
     1785            'name' => 'language',
     1786        ),
     1787        'type'         => 'string',
     1788        'description'  => __( 'WordPress locale code.' ),
     1789        'default'      => 'en_US',
     1790    ) );
     1791
     1792    register_setting( 'writing', 'use_smilies', array(
     1793        'show_in_rest' => true,
     1794        'type'         => 'boolean',
     1795        'description'  => __( 'Convert emoticons like :-) and :-P to graphics on display.' ),
     1796        'default'      => true,
     1797    ) );
     1798
     1799    register_setting( 'writing', 'default_category', array(
     1800        'show_in_rest' => true,
     1801        'type'         => 'number',
     1802        'description'  => __( 'Default category.' ),
     1803    ) );
     1804
     1805    register_setting( 'writing', 'default_post_format', array(
     1806        'show_in_rest' => true,
     1807        'type'         => 'string',
     1808        'description'  => __( 'Default post format.' ),
     1809    ) );
     1810
     1811    register_setting( 'reading', 'posts_per_page', array(
     1812        'show_in_rest' => true,
     1813        'type'         => 'number',
     1814        'description'  => __( 'Blog pages show at most.' ),
     1815        'default'      => 10,
     1816    ) );
     1817}
     1818
     1819/**
    17111820 * Register a setting and its data.
    17121821 *
  • trunk/src/wp-includes/post.php

    r38829 r38832  
    3434        'delete_with_user' => true,
    3535        'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'trackbacks', 'custom-fields', 'comments', 'revisions', 'post-formats' ),
     36        'show_in_rest' => true,
     37        'rest_base' => 'posts',
     38        'rest_controller_class' => 'WP_REST_Posts_Controller',
    3639    ) );
    3740
     
    5255        'delete_with_user' => true,
    5356        'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'page-attributes', 'custom-fields', 'comments', 'revisions' ),
     57        'show_in_rest' => true,
     58        'rest_base' => 'pages',
     59        'rest_controller_class' => 'WP_REST_Posts_Controller',
    5460    ) );
    5561
     
    7783        'delete_with_user' => true,
    7884        'supports' => array( 'title', 'author', 'comments' ),
     85        'show_in_rest' => true,
     86        'rest_base' => 'media',
     87        'rest_controller_class' => 'WP_REST_Attachments_Controller',
    7988    ) );
    8089    add_post_type_support( 'attachment:audio', 'thumbnail' );
  • trunk/src/wp-includes/rest-api.php

    r38806 r38832  
    7272
    7373/**
     74 * Registers a new field on an existing WordPress object type.
     75 *
     76 * @since 4.7.0
     77 *
     78 * @global array $wp_rest_additional_fields Holds registered fields, organized
     79 *                                          by object type.
     80 *
     81 * @param string|array $object_type Object(s) the field is being registered
     82 *                                  to, "post"|"term"|"comment" etc.
     83 * @param string $attribute         The attribute name.
     84 * @param array  $args {
     85 *     Optional. An array of arguments used to handle the registered field.
     86 *
     87 *     @type string|array|null $get_callback    Optional. The callback function used to retrieve the field
     88 *                                              value. Default is 'null', the field will not be returned in
     89 *                                              the response.
     90 *     @type string|array|null $update_callback Optional. The callback function used to set and update the
     91 *                                              field value. Default is 'null', the value cannot be set or
     92 *                                              updated.
     93 *     @type string|array|null $schema          Optional. The callback function used to create the schema for
     94 *                                              this field. Default is 'null', no schema entry will be returned.
     95 * }
     96 */
     97function register_rest_field( $object_type, $attribute, $args = array() ) {
     98    $defaults = array(
     99        'get_callback'    => null,
     100        'update_callback' => null,
     101        'schema'          => null,
     102    );
     103
     104    $args = wp_parse_args( $args, $defaults );
     105
     106    global $wp_rest_additional_fields;
     107
     108    $object_types = (array) $object_type;
     109
     110    foreach ( $object_types as $object_type ) {
     111        $wp_rest_additional_fields[ $object_type ][ $attribute ] = $args;
     112    }
     113}
     114
     115/**
    74116 * Registers rewrite rules for the API.
    75117 *
     
    123165
    124166    add_filter( 'rest_pre_dispatch', 'rest_handle_options_request', 10, 3 );
     167}
     168
     169/**
     170 * Registers default REST API routes.
     171 *
     172 * @since 4.7.0
     173 */
     174function create_initial_rest_routes() {
     175    foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) {
     176        $class = ! empty( $post_type->rest_controller_class ) ? $post_type->rest_controller_class : 'WP_REST_Posts_Controller';
     177
     178        if ( ! class_exists( $class ) ) {
     179            continue;
     180        }
     181        $controller = new $class( $post_type->name );
     182        if ( ! is_subclass_of( $controller, 'WP_REST_Controller' ) ) {
     183            continue;
     184        }
     185
     186        $controller->register_routes();
     187
     188        if ( post_type_supports( $post_type->name, 'revisions' ) ) {
     189            $revisions_controller = new WP_REST_Revisions_Controller( $post_type->name );
     190            $revisions_controller->register_routes();
     191        }
     192    }
     193
     194    // Post types.
     195    $controller = new WP_REST_Post_Types_Controller;
     196    $controller->register_routes();
     197
     198    // Post statuses.
     199    $controller = new WP_REST_Post_Statuses_Controller;
     200    $controller->register_routes();
     201
     202    // Taxonomies.
     203    $controller = new WP_REST_Taxonomies_Controller;
     204    $controller->register_routes();
     205
     206    // Terms.
     207    foreach ( get_taxonomies( array( 'show_in_rest' => true ), 'object' ) as $taxonomy ) {
     208        $class = ! empty( $taxonomy->rest_controller_class ) ? $taxonomy->rest_controller_class : 'WP_REST_Terms_Controller';
     209
     210        if ( ! class_exists( $class ) ) {
     211            continue;
     212        }
     213        $controller = new $class( $taxonomy->name );
     214        if ( ! is_subclass_of( $controller, 'WP_REST_Controller' ) ) {
     215            continue;
     216        }
     217
     218        $controller->register_routes();
     219    }
     220
     221    // Users.
     222    $controller = new WP_REST_Users_Controller;
     223    $controller->register_routes();
     224
     225    // Comments.
     226    $controller = new WP_REST_Comments_Controller;
     227    $controller->register_routes();
     228
     229    // Settings.
     230    $controller = new WP_REST_Settings_Controller;
     231    $controller->register_routes();
    125232}
    126233
     
    684791    return array( $local, $utc );
    685792}
     793
     794/**
     795 * Returns a contextual HTTP error code for authorization failure.
     796 *
     797 * @since 4.7.0
     798 *
     799 * @return integer 401 if the user is not logged in, 403 if the user is logged in.
     800 */
     801function rest_authorization_required_code() {
     802    return is_user_logged_in() ? 403 : 401;
     803}
     804
     805/**
     806 * Validate a request argument based on details registered to the route.
     807 *
     808 * @since 4.7.0
     809 *
     810 * @param  mixed            $value
     811 * @param  WP_REST_Request  $request
     812 * @param  string           $param
     813 * @return WP_Error|boolean
     814 */
     815function rest_validate_request_arg( $value, $request, $param ) {
     816    $attributes = $request->get_attributes();
     817    if ( ! isset( $attributes['args'][ $param ] ) || ! is_array( $attributes['args'][ $param ] ) ) {
     818        return true;
     819    }
     820    $args = $attributes['args'][ $param ];
     821
     822    if ( ! empty( $args['enum'] ) ) {
     823        if ( ! in_array( $value, $args['enum'], true ) ) {
     824            return new WP_Error( 'rest_invalid_param', sprintf( /* translators: 1: parameter, 2: list of valid values */ __( '%1$s is not one of %2$s.' ), $param, implode( ', ', $args['enum'] ) ) );
     825        }
     826    }
     827
     828    if ( 'integer' === $args['type'] && ! is_numeric( $value ) ) {
     829        return new WP_Error( 'rest_invalid_param', sprintf( /* translators: 1: parameter, 2: type name */ __( '%1$s is not of type %2$s.' ), $param, 'integer' ) );
     830    }
     831
     832    if ( 'boolean' === $args['type'] && ! rest_is_boolean( $value ) ) {
     833        return new WP_Error( 'rest_invalid_param', sprintf( /* translators: 1: parameter, 2: type name */ __( '%1$s is not of type %2$s.' ), $value, 'boolean' ) );
     834    }
     835
     836    if ( 'string' === $args['type'] && ! is_string( $value ) ) {
     837        return new WP_Error( 'rest_invalid_param', sprintf( /* translators: 1: parameter, 2: type name */ __( '%1$s is not of type %2$s.' ), $param, 'string' ) );
     838    }
     839
     840    if ( isset( $args['format'] ) ) {
     841        switch ( $args['format'] ) {
     842            case 'date-time' :
     843                if ( ! rest_parse_date( $value ) ) {
     844                    return new WP_Error( 'rest_invalid_date', __( 'The date you provided is invalid.' ) );
     845                }
     846                break;
     847
     848            case 'email' :
     849                if ( ! is_email( $value ) ) {
     850                    return new WP_Error( 'rest_invalid_email', __( 'The email address you provided is invalid.' ) );
     851                }
     852                break;
     853            case 'ipv4' :
     854                if ( ! rest_is_ip_address( $value ) ) {
     855                    return new WP_Error( 'rest_invalid_param', sprintf( __( '%s is not a valid IP address.' ), $value ) );
     856                }
     857                break;
     858        }
     859    }
     860
     861    if ( in_array( $args['type'], array( 'numeric', 'integer' ), true ) && ( isset( $args['minimum'] ) || isset( $args['maximum'] ) ) ) {
     862        if ( isset( $args['minimum'] ) && ! isset( $args['maximum'] ) ) {
     863            if ( ! empty( $args['exclusiveMinimum'] ) && $value <= $args['minimum'] ) {
     864                return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be greater than %2$d (exclusive)' ), $param, $args['minimum'] ) );
     865            } elseif ( empty( $args['exclusiveMinimum'] ) && $value < $args['minimum'] ) {
     866                return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be greater than %2$d (inclusive)' ), $param, $args['minimum'] ) );
     867            }
     868        } elseif ( isset( $args['maximum'] ) && ! isset( $args['minimum'] ) ) {
     869            if ( ! empty( $args['exclusiveMaximum'] ) && $value >= $args['maximum'] ) {
     870                return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be less than %2$d (exclusive)' ), $param, $args['maximum'] ) );
     871            } elseif ( empty( $args['exclusiveMaximum'] ) && $value > $args['maximum'] ) {
     872                return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be less than %2$d (inclusive)' ), $param, $args['maximum'] ) );
     873            }
     874        } elseif ( isset( $args['maximum'] ) && isset( $args['minimum'] ) ) {
     875            if ( ! empty( $args['exclusiveMinimum'] ) && ! empty( $args['exclusiveMaximum'] ) ) {
     876                if ( $value >= $args['maximum'] || $value <= $args['minimum'] ) {
     877                    return new WP_Error( 'rest_invalid_param', sprintf( /* translators: 1: parameter, 2: minimum number, 3: maximum number */ __( '%1$s must be between %2$d (exclusive) and %3$d (exclusive)' ), $param, $args['minimum'], $args['maximum'] ) );
     878                }
     879            } elseif ( empty( $args['exclusiveMinimum'] ) && ! empty( $args['exclusiveMaximum'] ) ) {
     880                if ( $value >= $args['maximum'] || $value < $args['minimum'] ) {
     881                    return new WP_Error( 'rest_invalid_param', sprintf( /* translators: 1: parameter, 2: minimum number, 3: maximum number */ __( '%1$s must be between %2$d (inclusive) and %3$d (exclusive)' ), $param, $args['minimum'], $args['maximum'] ) );
     882                }
     883            } elseif ( ! empty( $args['exclusiveMinimum'] ) && empty( $args['exclusiveMaximum'] ) ) {
     884                if ( $value > $args['maximum'] || $value <= $args['minimum'] ) {
     885                    return new WP_Error( 'rest_invalid_param', sprintf( /* translators: 1: parameter, 2: minimum number, 3: maximum number */ __( '%1$s must be between %2$d (exclusive) and %3$d (inclusive)' ), $param, $args['minimum'], $args['maximum'] ) );
     886                }
     887            } elseif ( empty( $args['exclusiveMinimum'] ) && empty( $args['exclusiveMaximum'] ) ) {
     888                if ( $value > $args['maximum'] || $value < $args['minimum'] ) {
     889                    return new WP_Error( 'rest_invalid_param', sprintf( /* translators: 1: parameter, 2: minimum number, 3: maximum number */ __( '%1$s must be between %2$d (inclusive) and %3$d (inclusive)' ), $param, $args['minimum'], $args['maximum'] ) );
     890                }
     891            }
     892        }
     893    }
     894
     895    return true;
     896}
     897
     898/**
     899 * Sanitize a request argument based on details registered to the route.
     900 *
     901 * @since 4.7.0
     902 *
     903 * @param  mixed            $value
     904 * @param  WP_REST_Request  $request
     905 * @param  string           $param
     906 * @return mixed
     907 */
     908function rest_sanitize_request_arg( $value, $request, $param ) {
     909    $attributes = $request->get_attributes();
     910    if ( ! isset( $attributes['args'][ $param ] ) || ! is_array( $attributes['args'][ $param ] ) ) {
     911        return $value;
     912    }
     913    $args = $attributes['args'][ $param ];
     914
     915    if ( 'integer' === $args['type'] ) {
     916        return (int) $value;
     917    }
     918
     919    if ( 'boolean' === $args['type'] ) {
     920        return rest_sanitize_boolean( $value );
     921    }
     922
     923    if ( isset( $args['format'] ) ) {
     924        switch ( $args['format'] ) {
     925            case 'date-time' :
     926                return sanitize_text_field( $value );
     927
     928            case 'email' :
     929                /*
     930                 * sanitize_email() validates, which would be unexpected
     931                 */
     932                return sanitize_text_field( $value );
     933
     934            case 'uri' :
     935                return esc_url_raw( $value );
     936
     937            case 'ipv4' :
     938                return sanitize_text_field( $value );
     939        }
     940    }
     941
     942    return $value;
     943}
     944
     945/**
     946 * Parse a request argument based on details registered to the route.
     947 *
     948 * Runs a validation check and sanitizes the value, primarily to be used via
     949 * the `sanitize_callback` arguments in the endpoint args registration.
     950 *
     951 * @since 4.7.0
     952 *
     953 * @param  mixed            $value
     954 * @param  WP_REST_Request  $request
     955 * @param  string           $param
     956 * @return mixed
     957 */
     958function rest_parse_request_arg( $value, $request, $param ) {
     959    $is_valid = rest_validate_request_arg( $value, $request, $param );
     960
     961    if ( is_wp_error( $is_valid ) ) {
     962        return $is_valid;
     963    }
     964
     965    $value = rest_sanitize_request_arg( $value, $request, $param );
     966
     967    return $value;
     968}
     969
     970/**
     971 * Determines if a IPv4 address is valid.
     972 *
     973 * Does not handle IPv6 addresses.
     974 *
     975 * @since 4.7.0
     976 *
     977 * @param  string $ipv4 IP 32-bit address.
     978 * @return string|false The valid IPv4 address, otherwise false.
     979 */
     980function rest_is_ip_address( $ipv4 ) {
     981    $pattern = '/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/';
     982
     983    if ( ! preg_match( $pattern, $ipv4 ) ) {
     984        return false;
     985    }
     986
     987    return $ipv4;
     988}
     989
     990/**
     991 * Changes a boolean-like value into the proper boolean value.
     992 *
     993 * @since 4.7.0
     994 *
     995 * @param bool|string|int $value The value being evaluated.
     996 * @return boolean Returns the proper associated boolean value.
     997 */
     998function rest_sanitize_boolean( $value ) {
     999    // String values are translated to `true`; make sure 'false' is false.
     1000    if ( is_string( $value )  ) {
     1001        $value = strtolower( $value );
     1002        if ( in_array( $value, array( 'false', '0' ), true ) ) {
     1003            $value = false;
     1004        }
     1005    }
     1006
     1007    // Everything else will map nicely to boolean.
     1008    return (boolean) $value;
     1009}
     1010
     1011/**
     1012 * Determines if a given value is boolean-like.
     1013 *
     1014 * @since 4.7.0
     1015 *
     1016 * @param bool|string $maybe_bool The value being evaluated.
     1017 * @return boolean True if a boolean, otherwise false.
     1018 */
     1019function rest_is_boolean( $maybe_bool ) {
     1020    if ( is_bool( $maybe_bool ) ) {
     1021        return true;
     1022    }
     1023
     1024    if ( is_string( $maybe_bool ) ) {
     1025        $maybe_bool = strtolower( $maybe_bool );
     1026
     1027        $valid_boolean_values = array(
     1028            'false',
     1029            'true',
     1030            '0',
     1031            '1',
     1032        );
     1033
     1034        return in_array( $maybe_bool, $valid_boolean_values, true );
     1035    }
     1036
     1037    if ( is_int( $maybe_bool ) ) {
     1038        return in_array( $maybe_bool, array( 0, 1 ), true );
     1039    }
     1040
     1041    return false;
     1042}
     1043
     1044/**
     1045 * Retrieves the avatar urls in various sizes based on a given email address.
     1046 *
     1047 * @since 4.7.0
     1048 *
     1049 * @see get_avatar_url()
     1050 *
     1051 * @param string $email Email address.
     1052 * @return array $urls Gravatar url for each size.
     1053 */
     1054function rest_get_avatar_urls( $email ) {
     1055    $avatar_sizes = rest_get_avatar_sizes();
     1056
     1057    $urls = array();
     1058    foreach ( $avatar_sizes as $size ) {
     1059        $urls[ $size ] = get_avatar_url( $email, array( 'size' => $size ) );
     1060    }
     1061
     1062    return $urls;
     1063}
     1064
     1065/**
     1066 * Retrieves the pixel sizes for avatars.
     1067 *
     1068 * @since 4.7.0
     1069 *
     1070 * @return array List of pixel sizes for avatars. Default `[ 24, 48, 96 ]`.
     1071 */
     1072function rest_get_avatar_sizes() {
     1073    /**
     1074     * Filter the REST avatar sizes.
     1075     *
     1076     * Use this filter to adjust the array of sizes returned by the
     1077     * `rest_get_avatar_sizes` function.
     1078     *
     1079     * @since 4.4.0
     1080     *
     1081     * @param array $sizes An array of int values that are the pixel sizes for avatars.
     1082     *                     Default `[ 24, 48, 96 ]`.
     1083     */
     1084    return apply_filters( 'rest_avatar_sizes', array( 24, 48, 96 ) );
     1085}
  • trunk/src/wp-includes/script-loader.php

    r38827 r38832  
    499499    $scripts->add( 'media-audiovideo', "/wp-includes/js/media-audiovideo$suffix.js", array( 'media-editor' ), false, 1 );
    500500    $scripts->add( 'mce-view', "/wp-includes/js/mce-view$suffix.js", array( 'shortcode', 'jquery', 'media-views', 'media-audiovideo' ), false, 1 );
     501
     502    $scripts->add( 'wp-api', "/wp-includes/js/wp-api$suffix.js", array( 'jquery', 'backbone', 'underscore' ), false, 1 );
     503    did_action( 'init' ) && $scripts->localize( 'wp-api', 'wpApiSettings', array(
     504        'root'          => esc_url_raw( get_rest_url() ),
     505        'nonce'         => wp_create_nonce( 'wp_rest' ),
     506        'versionString' => 'wp/v2/',
     507    ) );
    501508
    502509    if ( is_admin() ) {
  • trunk/src/wp-includes/taxonomy.php

    r38779 r38832  
    6868            'assign_terms' => 'assign_categories',
    6969        ),
     70        'show_in_rest' => true,
     71        'rest_base' => 'categories',
     72        'rest_controller_class' => 'WP_REST_Terms_Controller',
    7073    ) );
    7174
     
    8487            'assign_terms' => 'assign_post_tags',
    8588        ),
     89        'show_in_rest' => true,
     90        'rest_base' => 'tags',
     91        'rest_controller_class' => 'WP_REST_Terms_Controller',
    8692    ) );
    8793
  • trunk/src/wp-settings.php

    r38747 r38832  
    219219require( ABSPATH . WPINC . '/rest-api/class-wp-rest-response.php' );
    220220require( ABSPATH . WPINC . '/rest-api/class-wp-rest-request.php' );
     221require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-controller.php' );
     222require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-posts-controller.php' );
     223require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-attachments-controller.php' );
     224require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-post-types-controller.php' );
     225require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-post-statuses-controller.php' );
     226require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-revisions-controller.php' );
     227require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-taxonomies-controller.php' );
     228require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-terms-controller.php' );
     229require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-users-controller.php' );
     230require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-comments-controller.php' );
     231require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-settings-controller.php' );
     232require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-meta-fields.php' );
     233require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-comment-meta-fields.php' );
     234require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-post-meta-fields.php' );
     235require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-term-meta-fields.php' );
     236require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-user-meta-fields.php' );
    221237
    222238$GLOBALS['wp_embed'] = new WP_Embed();
  • trunk/tests/phpunit/includes/bootstrap.php

    r38454 r38832  
    4040define( 'WP_MEMORY_LIMIT', -1 );
    4141define( 'WP_MAX_MEMORY_LIMIT', -1 );
     42
     43define( 'REST_TESTS_IMPOSSIBLY_HIGH_NUMBER', 99999999 );
    4244
    4345$PHP_SELF = $GLOBALS['PHP_SELF'] = $_SERVER['PHP_SELF'] = '/index.php';
     
    8991require dirname( __FILE__ ) . '/testcase.php';
    9092require dirname( __FILE__ ) . '/testcase-rest-api.php';
     93require dirname( __FILE__ ) . '/testcase-rest-controller.php';
     94require dirname( __FILE__ ) . '/testcase-rest-post-type-controller.php';
    9195require dirname( __FILE__ ) . '/testcase-xmlrpc.php';
    9296require dirname( __FILE__ ) . '/testcase-ajax.php';
  • trunk/tests/phpunit/includes/utils.php

    r36525 r38832  
    454454    return $i;
    455455}
     456
     457function test_rest_expand_compact_links( $links ) {
     458    if ( empty( $links['curies'] ) ) {
     459        return $links;
     460    }
     461    foreach ( $links as $rel => $links_array ) {
     462        if ( ! strpos( $rel, ':' ) ) {
     463            continue;
     464        }
     465
     466        $name = explode( ':', $rel );
     467
     468        $curie = wp_list_filter( $links['curies'], array( 'name' => $name[0] ) );
     469        $full_uri = str_replace( '{rel}', $name[1], $curie[0]['href'] );
     470        $links[ $full_uri ] = $links_array;
     471        unset( $links[ $rel ] );
     472    }
     473    return $links;
     474}
  • trunk/tests/phpunit/tests/rest-api.php

    r38790 r38832  
    2727        $this->assertTrue( class_exists( 'WP_REST_Request' ) );
    2828        $this->assertTrue( class_exists( 'WP_REST_Response' ) );
     29        $this->assertTrue( class_exists( 'WP_REST_Posts_Controller' ) );
    2930    }
    3031
     
    3536    function test_init_action_added() {
    3637        $this->assertEquals( 10, has_action( 'init', 'rest_api_init' ) );
     38    }
     39
     40    public function test_add_extra_api_taxonomy_arguments() {
     41        $taxonomy = get_taxonomy( 'category' );
     42        $this->assertTrue( $taxonomy->show_in_rest );
     43        $this->assertEquals( 'categories', $taxonomy->rest_base );
     44        $this->assertEquals( 'WP_REST_Terms_Controller', $taxonomy->rest_controller_class );
     45
     46        $taxonomy = get_taxonomy( 'post_tag' );
     47        $this->assertTrue( $taxonomy->show_in_rest );
     48        $this->assertEquals( 'tags', $taxonomy->rest_base );
     49        $this->assertEquals( 'WP_REST_Terms_Controller', $taxonomy->rest_controller_class );
     50    }
     51
     52    public function test_add_extra_api_post_type_arguments() {
     53        $post_type = get_post_type_object( 'post' );
     54        $this->assertTrue( $post_type->show_in_rest );
     55        $this->assertEquals( 'posts', $post_type->rest_base );
     56        $this->assertEquals( 'WP_REST_Posts_Controller', $post_type->rest_controller_class );
     57
     58        $post_type = get_post_type_object( 'page' );
     59        $this->assertTrue( $post_type->show_in_rest );
     60        $this->assertEquals( 'pages', $post_type->rest_base );
     61        $this->assertEquals( 'WP_REST_Posts_Controller', $post_type->rest_controller_class );
     62
     63        $post_type = get_post_type_object( 'attachment' );
     64        $this->assertTrue( $post_type->show_in_rest );
     65        $this->assertEquals( 'media', $post_type->rest_base );
     66        $this->assertEquals( 'WP_REST_Attachments_Controller', $post_type->rest_controller_class );
    3767    }
    3868
Note: See TracChangeset for help on using the changeset viewer.