Make WordPress Core

Changeset 38832


Ignore:
Timestamp:
10/20/2016 02:54:12 AM (10 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.