From 1832b0b594f79e67d31725e5df099511c36c2f9c Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Mon, 19 Sep 2016 18:02:50 -0400 Subject: [PATCH 01/36] Breathe life into the new meta implementation --- README.md | 71 ++- lib/class-wp-rest-comment-meta-fields.php | 21 + ...class-wp-rest-meta-comments-controller.php | 100 ---- lib/class-wp-rest-meta-controller.php | 481 ------------------ lib/class-wp-rest-meta-fields.php | 285 +++++++++++ lib/class-wp-rest-meta-posts-controller.php | 118 ----- lib/class-wp-rest-meta-terms-controller.php | 110 ---- lib/class-wp-rest-meta-users-controller.php | 99 ---- lib/class-wp-rest-post-meta-fields.php | 37 ++ lib/class-wp-rest-term-meta-fields.php | 36 ++ lib/class-wp-rest-user-meta-fields.php | 21 + plugin.php | 50 +- 12 files changed, 471 insertions(+), 958 deletions(-) create mode 100644 lib/class-wp-rest-comment-meta-fields.php delete mode 100644 lib/class-wp-rest-meta-comments-controller.php delete mode 100644 lib/class-wp-rest-meta-controller.php create mode 100644 lib/class-wp-rest-meta-fields.php delete mode 100644 lib/class-wp-rest-meta-posts-controller.php delete mode 100644 lib/class-wp-rest-meta-terms-controller.php delete mode 100644 lib/class-wp-rest-meta-users-controller.php create mode 100644 lib/class-wp-rest-post-meta-fields.php create mode 100644 lib/class-wp-rest-term-meta-fields.php create mode 100644 lib/class-wp-rest-user-meta-fields.php diff --git a/README.md b/README.md index 45836ed..3d02d1e 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,62 @@ -# WP REST API Meta Endpoints # -**Contributors:** rmccue, rachelbaker, danielbachhuber, joehoyle -**Tags:** json, rest, api, rest-api -**Requires at least:** 4.4 -**Tested up to:** 4.5-alpha -**Stable tag:** 0.1.0 -**License:** GPLv2 or later -**License URI:** http://www.gnu.org/licenses/gpl-2.0.html +# WP REST API - Meta Support -WP REST API companion plugin for post meta endpoints. +[![Build Status](https://travis-ci.org/WP-API/wp-api-meta-endpoints.svg?branch=master)](https://travis-ci.org/WP-API/wp-api-meta-endpoints) -## Description ## +Just like other parts of WordPress, the REST API fully supports custom meta on posts, comments, terms and users. Similar to custom post types and taxonomies, only meta that opts-in to API support is available through the REST API. -[![Build Status](https://travis-ci.org/WP-API/wp-api-meta-endpoints.svg?branch=master)](https://travis-ci.org/WP-API/wp-api-meta-endpoints) +This plugin is a feature plugin for the main API plugin, and is expected to be integrated in the near future. + + +## Meta registration + +For your meta fields to be exposed in the REST API, you need to register them. WordPress includes a `register_meta` function which is not usually required to get/set fields, but is required for API support. + +To register your field, simply call `register_meta` and set the `show_in_rest` flag to true. + +```php +register_meta( 'post', 'field_name', array( + 'show_in_rest' => true, +)); +``` + +Note: `register_meta` must be called separately for each meta key. + + +### Meta Options + +`register_meta` is part of WordPress core, but isn't heavily used in most parts of core, so you may not have seen it before. Here are the options relevant to the REST API: + +* `show_in_rest` - Should the field be exposed in the API? `true` for default behaviour, or an array of options to override defaults (see below). +* `description` - Human-readable description of what the field is for. The API exposes this in the schema. +* `single` - Is this field singular? WordPress allows multiple values per key on a single object, but the API needs to know whether you use this functionality. +* `sanitize_callback` - Callback to sanitize the value before it's stored in the database. [See the `"sanitize_{$object_type}_meta_{$meta_key}"` filter.](https://developer.wordpress.org/reference/hooks/sanitize_object_type_meta_meta_key/) +* `auth_callback` - Callback to determine whether the user can **write** to the field. [See the `"auth_post_{$post_type}_meta_{$meta_key}"` filter.](https://developer.wordpress.org/reference/hooks/auth_post_post_type_meta_meta_key/) + + +### API=Specific Options + +The `show_in_rest` parameter defaults to `false`, but can be set to `true` to enable API support. Out of the box, the API makes some assumptions about your meta field, but you can override these by setting `show_in_rest` to an options array instead: + +```php +register_meta( 'post', 'field_name', array( + 'show_in_rest' => array( + 'name' => 'fieldname' + ) +)); +``` + +The options you can set are: + +* `name` - The key exposed via the REST API. For example, if your meta key starts with an underscore, you may want to remove this for the API. +* `schema` - The JSON Schema options for the field. Exposed via OPTIONS requests to the post. This is generated automatically based on other parameters, but can be specified manually if you'd like to override it. + + +## Using Meta over the API + +Meta is added to existing resources as a new `meta` field. For example, to get the meta for a single post, fetch the post at `/wp/v2/posts/{id}`, then look in the `meta` field. This is a key-value map for the registered fields. -WP REST API companion plugin for post meta endpoints. +To update a field, simply send back a new value for it. -## Changelog ## +Setting a field to `null` will cause the value to be removed from the database. If a field has a default value set, this essentially "resets" the value to the default (although no default will be stored in the database). -### 0.1.0 (February 9, 2016) ### -* Initial release. +For meta fields which can hold multiple values, this field will be a JSON list. Adding or removing items from the list will create or remove the corresponding values in the database. diff --git a/lib/class-wp-rest-comment-meta-fields.php b/lib/class-wp-rest-comment-meta-fields.php new file mode 100644 index 0000000..15d89da --- /dev/null +++ b/lib/class-wp-rest-comment-meta-fields.php @@ -0,0 +1,21 @@ +parent_controller = new WP_REST_Comments_Controller(); - $this->namespace = 'wp/v2'; - $this->rest_base = 'meta'; - } - - /** - * Check if a given request has access to get meta for a comment. - * - * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - $comment_id = (int) $request['parent_id']; - $comment = get_comment( $comment_id ); - - if ( empty( $comment ) || empty( $comment->comment_ID ) ) { - return new WP_Error( 'rest_comment_invalid_id', __( 'Invalid comment id.' ), array( 'status' => 404 ) ); - } - - if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) ) { - return new WP_Error( 'rest_forbidden', __( 'Sorry, you cannot view the meta for this comment.' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } - - /** - * Check if a given request has access to get a specific meta entry for a comment. - * - * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|boolean - */ - public function get_item_permissions_check( $request ) { - return $this->get_items_permissions_check( $request ); - } - - /** - * Check if a given request has access to create a meta entry for a comment. - * - * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|boolean - */ - public function create_item_permissions_check( $request ) { - return $this->get_items_permissions_check( $request ); - } - - /** - * Check if a given request has access to update a meta entry for a comment. - * - * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|boolean - */ - public function update_item_permissions_check( $request ) { - return $this->get_items_permissions_check( $request ); - } - - /** - * Check if a given request has access to delete meta for a comment. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function delete_item_permissions_check( $request ) { - $comment_id = (int) $request['parent_id']; - $comment = get_comment( $comment_id ); - - if ( empty( $comment ) || empty( $comment->comment_ID ) ) { - return new WP_Error( 'rest_comment_invalid_id', __( 'Invalid comment id.' ), array( 'status' => 404 ) ); - } - - if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) ) { - return new WP_Error( 'rest_forbidden', __( 'Sorry, you cannot delete the meta for this comment.' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } -} diff --git a/lib/class-wp-rest-meta-controller.php b/lib/class-wp-rest-meta-controller.php deleted file mode 100644 index b196271..0000000 --- a/lib/class-wp-rest-meta-controller.php +++ /dev/null @@ -1,481 +0,0 @@ -parent_type ) ) { - _doing_it_wrong( 'WP_REST_Meta_Controller::__construct', __( 'The object type must be overridden' ), 'WPAPI-2.0' ); - return; - } - if ( empty( $this->parent_base ) ) { - _doing_it_wrong( 'WP_REST_Meta_Controller::__construct', __( 'The parent base must be overridden' ), 'WPAPI-2.0' ); - return; - } - } - - /** - * Register the meta-related routes. - */ - public function register_routes() { - register_rest_route( $this->namespace, '/' . $this->parent_base . '/(?P[\d]+)/' . $this->rest_base, array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_items' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => $this->get_collection_params(), - ), - array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_item' ), - 'permission_callback' => array( $this, 'create_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), - ), - - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - register_rest_route( $this->namespace, '/' . $this->parent_base . '/(?P[\d]+)/' . $this->rest_base . '/(?P[\d]+)', array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_item' ), - 'permission_callback' => array( $this, 'get_item_permissions_check' ), - 'args' => array( - 'context' => $this->get_context_param( array( 'default' => 'edit' ) ), - ), - ), - array( - 'methods' => WP_REST_Server::EDITABLE, - 'callback' => array( $this, 'update_item' ), - 'permission_callback' => array( $this, 'update_item_permissions_check' ), - 'args' => $this->get_endpoint_args_for_item_schema( false ), - ), - array( - 'methods' => WP_REST_Server::DELETABLE, - 'callback' => array( $this, 'delete_item' ), - 'permission_callback' => array( $this, 'delete_item_permissions_check' ), - 'args' => array( - 'force' => array( - 'default' => false, - 'description' => __( 'Required to be true, as resource does not support trashing.' ), - ), - ), - ), - - 'schema' => array( $this, 'get_public_item_schema' ), - ) ); - } - - /** - * Get the meta schema, conforming to JSON Schema - * - * @return array - */ - public function get_item_schema() { - $schema = array( - '$schema' => 'http://json-schema.org/draft-04/schema#', - 'title' => 'meta', - 'type' => 'object', - /* - * Base properties for every Post - */ - 'properties' => array( - 'id' => array( - 'description' => __( 'Unique identifier for the object.' ), - 'type' => 'integer', - 'context' => array( 'edit' ), - 'readonly' => true, - ), - 'key' => array( - 'description' => __( 'The key for the custom field.' ), - 'type' => 'string', - 'context' => array( 'edit' ), - 'required' => true, - 'arg_options' => array( - 'sanitize_callback' => 'sanitize_text_field', - ), - ), - 'value' => array( - 'description' => __( 'The value of the custom field.' ), - 'type' => 'string', - 'context' => array( 'edit' ), - ), - ), - ); - return $schema; - } - - /** - * Get the query params for collections - * - * @return array - */ - public function get_collection_params() { - $params = parent::get_collection_params(); - $new_params = array(); - $new_params['context'] = $params['context']; - $new_params['context']['default'] = 'edit'; - return $new_params; - } - - /** - * Get the meta ID column for the relevant table. - * - * @return string - */ - protected function get_id_column() { - return ( 'user' === $this->parent_type ) ? 'umeta_id' : 'meta_id'; - } - - /** - * Get the object (parent) ID column for the relevant table. - * - * @return string - */ - protected function get_parent_column() { - $parent_column = 'post_id'; - - switch ( $this->parent_type ) { - case 'user': - return 'user_id'; - case 'comment': - return 'comment_id'; - case 'term': - return 'term_id'; - default: - return $parent_column; - } - - return $parent_column; - } - - /** - * Retrieve custom fields for object. - * - * @param WP_REST_Request $request - * @return WP_REST_Request|WP_Error List of meta object data on success, WP_Error otherwise - */ - public function get_items( $request ) { - $parent_id = (int) $request['parent_id']; - - global $wpdb; - $table = _get_meta_table( $this->parent_type ); - $parent_column = $this->get_parent_column(); - $id_column = $this->get_id_column(); - - // @codingStandardsIgnoreStart - $results = $wpdb->get_results( $wpdb->prepare( "SELECT $id_column, $parent_column, meta_key, meta_value FROM $table WHERE $parent_column = %d", $parent_id ) ); - // @codingStandardsIgnoreEnd - - $meta = array(); - - foreach ( $results as $row ) { - $value = $this->prepare_item_for_response( $row, $request, true ); - - if ( is_wp_error( $value ) ) { - continue; - } - - $meta[] = $this->prepare_response_for_collection( $value ); - } - - return rest_ensure_response( $meta ); - } - - /** - * Retrieve custom field object. - * - * @param WP_REST_Request $request - * @return WP_REST_Request|WP_Error Meta object data on success, WP_Error otherwise - */ - public function get_item( $request ) { - $parent_id = (int) $request['parent_id']; - $mid = (int) $request['id']; - - $parent_column = $this->get_parent_column(); - $meta = get_metadata_by_mid( $this->parent_type, $mid ); - - if ( empty( $meta ) ) { - return new WP_Error( 'rest_meta_invalid_id', __( 'Invalid meta id.' ), array( 'status' => 404 ) ); - } - - if ( absint( $meta->$parent_column ) !== $parent_id ) { - return new WP_Error( 'rest_meta_' . $this->parent_type . '_mismatch', __( 'Meta does not belong to this object' ), array( 'status' => 400 ) ); - } - - return $this->prepare_item_for_response( $meta, $request ); - } - - /** - * Prepares meta data for return as an object. - * - * @param stdClass $data Metadata row from database - * @param WP_REST_Request $request - * @param boolean $is_raw Is the value field still serialized? (False indicates the value has been unserialized) - * @return WP_REST_Response|WP_Error Meta object data on success, WP_Error otherwise - */ - public function prepare_item_for_response( $data, $request, $is_raw = false ) { - $id_column = $this->get_id_column(); - $id = $data->$id_column; - $key = $data->meta_key; - $value = $data->meta_value; - - // Don't expose protected fields. - if ( is_protected_meta( $key ) ) { - return new WP_Error( 'rest_meta_protected', sprintf( __( '%s is marked as a protected field.' ), $key ), array( 'status' => 403 ) ); - } - - // Normalize serialized strings - if ( $is_raw && is_serialized_string( $value ) ) { - $value = unserialize( $value ); - } - - // Don't expose serialized data - if ( is_serialized( $value ) || ! is_string( $value ) ) { - return new WP_Error( 'rest_meta_protected', sprintf( __( '%s contains serialized data.' ), $key ), array( 'status' => 403 ) ); - } - - $meta = array( - 'id' => (int) $id, - 'key' => $key, - 'value' => $value, - ); - - $response = rest_ensure_response( $meta ); - $parent_column = $this->get_parent_column(); - $response->add_link( 'about', rest_url( $this->namespace . '/' . $this->parent_base . '/' . $data->$parent_column ), array( 'embeddable' => true ) ); - - /** - * Filter a meta value returned from the API. - * - * Allows modification of the meta value right before it is returned. - * - * @param array $response Key value array of meta data: id, key, value. - * @param WP_REST_Request $request Request used to generate the response. - */ - return apply_filters( 'rest_prepare_meta_value', $response, $request ); - } - - /** - * Add meta to an object. - * - * @param WP_REST_Request $request - * @return WP_REST_Response|WP_Error - */ - public function update_item( $request ) { - $parent_id = (int) $request['parent_id']; - $mid = (int) $request['id']; - - $parent_column = $this->get_parent_column(); - $current = get_metadata_by_mid( $this->parent_type, $mid ); - - if ( empty( $current ) ) { - return new WP_Error( 'rest_meta_invalid_id', __( 'Invalid meta id.' ), array( 'status' => 404 ) ); - } - - if ( absint( $current->$parent_column ) !== $parent_id ) { - return new WP_Error( 'rest_meta_' . $this->parent_type . '_mismatch', __( 'Meta does not belong to this object' ), array( 'status' => 400 ) ); - } - - if ( ! isset( $request['key'] ) && ! isset( $request['value'] ) ) { - return new WP_Error( 'rest_meta_data_invalid', __( 'Invalid meta parameters.' ), array( 'status' => 400 ) ); - } - if ( isset( $request['key'] ) ) { - $key = $request['key']; - } else { - $key = $current->meta_key; - } - - if ( isset( $request['value'] ) ) { - $value = $request['value']; - } else { - $value = $current->meta_value; - } - - if ( ! $key ) { - return new WP_Error( 'rest_meta_invalid_key', __( 'Invalid meta key.' ), array( 'status' => 400 ) ); - } - - // for now let's not allow updating of arrays, objects or serialized values. - if ( ! $this->is_valid_meta_data( $current->meta_value ) ) { - $code = ( $this->parent_type === 'post' ) ? 'rest_post_invalid_action' : 'rest_meta_invalid_action'; - return new WP_Error( $code, __( 'Invalid existing meta data for action.' ), array( 'status' => 400 ) ); - } - - if ( ! $this->is_valid_meta_data( $value ) ) { - $code = ( $this->parent_type === 'post' ) ? 'rest_post_invalid_action' : 'rest_meta_invalid_action'; - return new WP_Error( $code, __( 'Invalid provided meta data for action.' ), array( 'status' => 400 ) ); - } - - if ( is_protected_meta( $current->meta_key ) ) { - return new WP_Error( 'rest_meta_protected', sprintf( __( '%s is marked as a protected field.' ), $current->meta_key ), array( 'status' => 403 ) ); - } - - if ( is_protected_meta( $key ) ) { - return new WP_Error( 'rest_meta_protected', sprintf( __( '%s is marked as a protected field.' ), $key ), array( 'status' => 403 ) ); - } - - // update_metadata_by_mid will return false if these are equal, so check - // first and pass through - if ( (string) $value === $current->meta_value && (string) $key === $current->meta_key ) { - return $this->get_item( $request ); - } - - if ( ! update_metadata_by_mid( $this->parent_type, $mid, $value, $key ) ) { - return new WP_Error( 'rest_meta_could_not_update', __( 'Could not update meta.' ), array( 'status' => 500 ) ); - } - - $request = new WP_REST_Request( 'GET' ); - $request->set_query_params( array( - 'context' => 'edit', - 'parent_id' => $parent_id, - 'id' => $mid, - ) ); - $response = $this->get_item( $request ); - - /** - * Fires after meta is added to an object or updated via the REST API. - * - * @param array $value The inserted meta data. - * @param WP_REST_Request $request The request sent to the API. - * @param boolean $creating True when adding meta, false when updating. - */ - do_action( 'rest_insert_meta', $value, $request, false ); - - return rest_ensure_response( $response ); - } - - /** - * Check if the data provided is valid data. - * - * Excludes serialized data from being sent via the API. - * - * @see https://github.com/WP-API/WP-API/pull/68 - * @param mixed $data Data to be checked - * @return boolean Whether the data is valid or not - */ - protected function is_valid_meta_data( $data ) { - if ( is_array( $data ) || is_object( $data ) || is_serialized( $data ) ) { - return false; - } - - return true; - } - - /** - * Add meta to an object. - * - * @param WP_REST_Request $request - * @return WP_REST_Response|WP_Error - */ - public function create_item( $request ) { - $parent_id = (int) $request['parent_id']; - - if ( ! $this->is_valid_meta_data( $request['value'] ) ) { - $code = ( $this->parent_type === 'post' ) ? 'rest_post_invalid_action' : 'rest_meta_invalid_action'; - - // for now let's not allow updating of arrays, objects or serialized values. - return new WP_Error( $code, __( 'Invalid provided meta data for action.' ), array( 'status' => 400 ) ); - } - - if ( empty( $request['key'] ) ) { - return new WP_Error( 'rest_meta_invalid_key', __( 'Invalid meta key.' ), array( 'status' => 400 ) ); - } - - if ( is_protected_meta( $request['key'] ) ) { - return new WP_Error( 'rest_meta_protected', sprintf( __( '%s is marked as a protected field.' ), $request['key'] ), array( 'status' => 403 ) ); - } - - $meta_key = wp_slash( $request['key'] ); - $value = wp_slash( $request['value'] ); - - $mid = add_metadata( $this->parent_type, $parent_id, $meta_key, $value ); - if ( ! $mid ) { - return new WP_Error( 'rest_meta_could_not_add', __( 'Could not add meta.' ), array( 'status' => 400 ) ); - } - - $request = new WP_REST_Request( 'GET' ); - $request->set_query_params( array( - 'context' => 'edit', - 'parent_id' => $parent_id, - 'id' => $mid, - ) ); - $response = rest_ensure_response( $this->get_item( $request ) ); - - $response->set_status( 201 ); - $data = $response->get_data(); - $response->header( 'Location', rest_url( $this->namespace . '/' . $this->parent_base . '/' . $parent_id . '/meta/' . $data['id'] ) ); - - /* This action is documented in lib/endpoints/class-wp-rest-meta-controller.php */ - do_action( 'rest_insert_meta', $data, $request, true ); - - return $response; - } - - /** - * Delete meta from an object. - * - * @param WP_REST_Request $request - * @return WP_REST_Response|WP_Error Message on success, WP_Error otherwise - */ - public function delete_item( $request ) { - $parent_id = (int) $request['parent_id']; - $mid = (int) $request['id']; - $force = isset( $request['force'] ) ? (bool) $request['force'] : false; - - // We don't support trashing for this type, error out - if ( ! $force ) { - return new WP_Error( 'rest_trash_not_supported', __( 'Meta does not support trashing.' ), array( 'status' => 501 ) ); - } - - $parent_column = $this->get_parent_column(); - $current = get_metadata_by_mid( $this->parent_type, $mid ); - - if ( empty( $current ) ) { - return new WP_Error( 'rest_meta_invalid_id', __( 'Invalid meta id.' ), array( 'status' => 404 ) ); - } - - if ( absint( $current->$parent_column ) !== (int) $parent_id ) { - return new WP_Error( 'rest_meta_' . $this->parent_type . '_mismatch', __( 'Meta does not belong to this object' ), array( 'status' => 400 ) ); - } - - // for now let's not allow updating of arrays, objects or serialized values. - if ( ! $this->is_valid_meta_data( $current->meta_value ) ) { - $code = ( $this->parent_type === 'post' ) ? 'rest_post_invalid_action' : 'rest_meta_invalid_action'; - return new WP_Error( $code, __( 'Invalid existing meta data for action.' ), array( 'status' => 400 ) ); - } - - if ( is_protected_meta( $current->meta_key ) ) { - return new WP_Error( 'rest_meta_protected', sprintf( __( '%s is marked as a protected field.' ), $current->meta_key ), array( 'status' => 403 ) ); - } - - if ( ! delete_metadata_by_mid( $this->parent_type, $mid ) ) { - return new WP_Error( 'rest_meta_could_not_delete', __( 'Could not delete meta.' ), array( 'status' => 500 ) ); - } - - /** - * Fires after a meta value is deleted via the REST API. - * - * @param WP_REST_Request $request The request sent to the API. - */ - do_action( 'rest_delete_meta', $request ); - - return rest_ensure_response( array( 'message' => __( 'Deleted meta' ) ) ); - } -} diff --git a/lib/class-wp-rest-meta-fields.php b/lib/class-wp-rest-meta-fields.php new file mode 100644 index 0000000..e13bee6 --- /dev/null +++ b/lib/class-wp-rest-meta-fields.php @@ -0,0 +1,285 @@ +get_rest_field_type(), 'meta', array( + 'get_callback' => array( $this, 'get_value' ), + 'update_callback' => array( $this, 'update_value' ), + 'schema' => $this->get_field_schema(), + )); + } + + /** + * Get the settings. + * + * @param WP_REST_Request $request Full details about the request. + * @return WP_Error|array + */ + public function get_value( $data, $field_name, $request, $type ) { + $options = $this->get_registered_fields(); + $response = array(); + + foreach ( $options as $name => $args ) { + $all_values = get_metadata( $this->get_meta_type(), $data['id'], $name, false ); + if ( $args['single'] ) { + if ( empty( $all_values ) ) { + $value = $args['schema']['default']; + } else { + $value = $all_values[0]; + } + $value = $this->prepare_value_for_response( $value, $name, $args ); + } else { + $value = array(); + foreach ( $all_values as $row ) { + $value[] = $this->prepare_value_for_response( $row, $name, $args ); + } + } + + $response[ $name ] = $value; + } + + return (object) $response; + } + + /** + * Prepare value for response. + * + * This is required because some native types cannot be stored correctly in + * the database, such as booleans. We need to cast back to the relevant type + * before passing back to JSON. + * + * @param mixed $value Value to prepare. + * @param string $name Meta key. + * @param array $args Options for the field. + * @return mixed Prepared value. + */ + protected function prepare_value_for_response( $value, $name, $args ) { + switch ( $args['schema']['type'] ) { + case 'string': + $value = strval( $value ); + break; + case 'number': + $value = floatval( $value ); + break; + case 'boolean': + $value = (bool) $value; + break; + } + + return $value; + } + + /** + * Update settings for the settings object. + * + * @param WP_REST_Request $request Full detail about the request. + * @return WP_Error|array + */ + public function update_value( $params, $data, $field_name, $request ) { + $options = $this->get_registered_fields(); + + foreach ( $options as $name => $args ) { + if ( ! array_key_exists( $name, $params ) ) { + continue; + } + + // a null value means reset the option, which is essentially deleting it + // from the database and then relying on the default value. + if ( is_null( $params[ $name ] ) ) { + $result = $this->delete_meta_value( $request['id'], $name ); + } elseif ( $args['single'] ) { + $result = $this->update_meta_value( $request['id'], $name, $params[ $name ] ); + } else { + $result = $this->update_multi_meta_value( $request['id'], $name, $params[ $name ] ); + } + + if ( is_wp_error( $result ) ) { + return $result; + } + } + + return null; + } + + /** + * Delete meta value for an object. + * + * @param int $object Object ID the field belongs to. + * @param string $name Key for the field. + * @return bool|WP_Error True if meta field is deleted, error otherwise. + */ + protected function delete_meta_value( $object, $name ) { + if ( ! current_user_can( 'delete_post_meta', $object, $name ) ) { + return new WP_Error( + 'rest_cannot_delete', + sprintf( __( 'You do not have permission to edit the %s custom field.' ), $name ), + array( 'key' => $name, 'status' => rest_authorization_required_code() ) + ); + } + + if ( ! delete_metadata( $this->get_meta_type(), $object, wp_slash( $name ) ) ) { + return new WP_Error( + 'rest_meta_database_error', + __( 'Could not delete meta value from database.' ), + array( 'key' => $name, 'status' => WP_HTTP::INTERNAL_SERVER_ERROR ) + ); + } + + return true; + } + + /** + * Update multiple meta values for an object. + * + * Alters the list of values in the database to match the list of provided values. + * + * @param int $object Object ID. + * @param string $name Key for the custom field. + * @param array $values List of values to update to. + * @return bool|WP_Error True if meta fields are updated, error otherwise. + */ + protected function update_multi_meta_value( $object, $name, $values ) { + if ( ! current_user_can( 'edit_post_meta', $object, $name ) ) { + return new WP_Error( + 'rest_cannot_update', + sprintf( __( 'You do not have permission to edit the %s custom field.' ), $name ), + array( 'key' => $name, 'status' => rest_authorization_required_code() ) + ); + } + + $current = get_metadata( $this->get_meta_type(), $object, $name, false ); + $to_add = array_diff( $values, $current ); + $to_remove = array_diff( $current, $values ); + + foreach ( $to_add as $value ) { + if ( ! add_metadata( $this->get_meta_type(), $object, wp_slash( $name ), wp_slash( $value ) ) ) { + return new WP_Error( + 'rest_meta_database_error', + __( 'Could not update meta value in database.' ), + array( 'key' => $name, 'status' => WP_HTTP::INTERNAL_SERVER_ERROR ) + ); + } + } + foreach ( $to_remove as $value ) { + if ( ! delete_metadata( $this->get_meta_type(), $object, wp_slash( $name ), wp_slash( $value ) ) ) { + return new WP_Error( + 'rest_meta_database_error', + __( 'Could not update meta value in database.' ), + array( 'key' => $name, 'status' => WP_HTTP::INTERNAL_SERVER_ERROR ) + ); + } + } + + return true; + } + + /** + * Update meta value for an object. + * + * @param int $object Object ID. + * @param string $name Key for the custom field. + * @return bool|WP_Error True if meta field is deleted, error otherwise. + */ + protected function update_meta_value( $object, $name, $value ) { + if ( ! current_user_can( 'edit_post_meta', $object, $name ) ) { + return new WP_Error( + 'rest_cannot_update', + sprintf( __( 'You do not have permission to edit the %s custom field.' ), $name ), + array( 'key' => $name, 'status' => rest_authorization_required_code() ) + ); + } + + if ( ! update_metadata( $this->get_meta_type(), $object, wp_slash( $name ), wp_slash( $value ) ) ) { + return new WP_Error( + 'rest_meta_database_error', + __( 'Could not update meta value in database.' ), + array( 'key' => $name, 'status' => WP_HTTP::INTERNAL_SERVER_ERROR ) + ); + } + + return true; + } + + /** + * Get all the registered options for the Settings API + * + * @return array + */ + protected function get_registered_fields() { + $rest_options = array(); + + foreach ( get_registered_meta_keys( $this->get_meta_type() ) as $name => $args ) { + if ( empty( $args['show_in_rest'] ) ) { + continue; + } + + $rest_args = array(); + if ( is_array( $args['show_in_rest'] ) ) { + $rest_args = $args['show_in_rest']; + } + + $default_args = array( + 'name' => $name, + 'single' => $args['single'], + 'schema' => array( + 'type' => empty( $args['type'] ) ? null : $args['type'], + 'description' => empty( $args['description'] ) ? '' : $args['description'], + 'default' => isset( $args['default'] ) ? $args['default'] : null, + ), + ); + $rest_args = array_merge( $default_args, $rest_args ); + + // skip over settings that don't have a defined type in the schema + if ( empty( $rest_args['schema']['type'] ) ) { + continue; + } + + $rest_options[ $rest_args['name'] ] = $rest_args; + } + + return $rest_options; + } + + /** + * Get the site setting schema, conforming to JSON Schema. + * + * @return array + */ + public function get_field_schema() { + $fields = $this->get_registered_fields(); + + $schema = array( + 'description' => __( 'Post meta fields.' ), + 'type' => 'object', + 'context' => array( 'view', 'edit' ), + 'properties' => array(), + ); + + foreach ( $fields as $key => $args ) { + $schema['properties'][ $key ] = $args['schema']; + } + + return $schema; + } +} diff --git a/lib/class-wp-rest-meta-posts-controller.php b/lib/class-wp-rest-meta-posts-controller.php deleted file mode 100644 index feeef6e..0000000 --- a/lib/class-wp-rest-meta-posts-controller.php +++ /dev/null @@ -1,118 +0,0 @@ -parent_post_type = $parent_post_type; - $this->parent_controller = new WP_REST_Posts_Controller( $this->parent_post_type ); - $obj = get_post_type_object( $this->parent_post_type ); - $this->parent_base = ! empty( $obj->rest_base ) ? $obj->rest_base : $obj->name; - $this->namespace = 'wp/v2'; - $this->rest_base = 'meta'; - } - - /** - * Check if a given request has access to get meta for a post. - * - * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - $parent = get_post( (int) $request['parent_id'] ); - - if ( empty( $parent ) || empty( $parent->ID ) ) { - return new WP_Error( 'rest_post_invalid_id', __( 'Invalid post id.' ), array( 'status' => 404 ) ); - } - - if ( ! $this->parent_controller->check_read_permission( $parent ) ) { - return new WP_Error( 'rest_forbidden', __( 'Sorry, you cannot view this post.' ), array( 'status' => rest_authorization_required_code() ) ); - } - - $post_type = get_post_type_object( $parent->post_type ); - if ( ! current_user_can( $post_type->cap->edit_post, $parent->ID ) ) { - return new WP_Error( 'rest_forbidden', __( 'Sorry, you cannot view the meta for this post.' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } - - /** - * Check if a given request has access to get a specific meta entry for a post. - * - * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|boolean - */ - public function get_item_permissions_check( $request ) { - return $this->get_items_permissions_check( $request ); - } - - /** - * Check if a given request has access to create a meta entry for a post. - * - * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|boolean - */ - public function create_item_permissions_check( $request ) { - return $this->get_items_permissions_check( $request ); - } - - /** - * Check if a given request has access to update a meta entry for a post. - * - * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|boolean - */ - public function update_item_permissions_check( $request ) { - return $this->get_items_permissions_check( $request ); - } - - /** - * Check if a given request has access to delete meta for a post. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function delete_item_permissions_check( $request ) { - $parent = get_post( (int) $request['parent_id'] ); - - if ( empty( $parent ) || empty( $parent->ID ) ) { - return new WP_Error( 'rest_post_invalid_id', __( 'Invalid post id.' ), array( 'status' => 404 ) ); - } - - if ( ! $this->parent_controller->check_read_permission( $parent ) ) { - return new WP_Error( 'rest_forbidden', __( 'Sorry, you cannot view this post.' ), array( 'status' => rest_authorization_required_code() ) ); - } - - $post_type = get_post_type_object( $parent->post_type ); - if ( ! current_user_can( $post_type->cap->delete_post, $parent->ID ) ) { - return new WP_Error( 'rest_forbidden', __( 'Sorry, you cannot delete the meta for this post.' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } -} diff --git a/lib/class-wp-rest-meta-terms-controller.php b/lib/class-wp-rest-meta-terms-controller.php deleted file mode 100644 index c4b9fe4..0000000 --- a/lib/class-wp-rest-meta-terms-controller.php +++ /dev/null @@ -1,110 +0,0 @@ -parent_taxonomy = $parent_taxonomy; - $this->parent_controller = new WP_REST_Terms_Controller( $this->parent_taxonomy ); - $tax_obj = get_taxonomy( $this->parent_taxonomy ); - $this->parent_base = ! empty( $tax_obj->rest_base ) ? $tax_obj->rest_base : $tax_obj->name; - $this->namespace = 'wp/v2'; - $this->rest_base = 'meta'; - } - - /** - * Check if a given request has access to get meta for a taxonomy. - * - * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - $tax_obj = get_taxonomy( $this->parent_taxonomy ); - $parent = get_term( (int) $request['parent_id'], $this->parent_taxonomy ); - - if ( empty( $parent ) || empty( $parent->term_id ) ) { - return new WP_Error( 'rest_term_invalid_id', __( 'Invalid term id.' ), array( 'status' => 404 ) ); - } - - if ( ! current_user_can( $tax_obj->cap->edit_terms ) ) { - return new WP_Error( 'rest_forbidden', __( 'Sorry, you cannot view the meta for this taxonomy.' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } - - /** - * Check if a given request has access to get a specific meta entry for a taxonomy. - * - * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|boolean - */ - public function get_item_permissions_check( $request ) { - return $this->get_items_permissions_check( $request ); - } - - /** - * Check if a given request has access to create a meta entry for a taxonomy. - * - * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|boolean - */ - public function create_item_permissions_check( $request ) { - return $this->get_items_permissions_check( $request ); - } - - /** - * Check if a given request has access to update a meta entry for a taxonomy. - * - * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|boolean - */ - public function update_item_permissions_check( $request ) { - return $this->get_items_permissions_check( $request ); - } - - /** - * Check if a given request has access to delete meta for a taxonomy. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function delete_item_permissions_check( $request ) { - $tax_obj = get_taxonomy( $this->parent_taxonomy ); - $parent = get_term( (int) $request['parent_id'], $this->parent_taxonomy ); - - if ( empty( $parent ) || empty( $parent->term_id ) ) { - return new WP_Error( 'rest_term_invalid_id', __( 'Invalid term id.' ), array( 'status' => 404 ) ); - } - - if ( ! current_user_can( $tax_obj->cap->delete_terms ) ) { - return new WP_Error( 'rest_forbidden', __( 'Sorry, you cannot view the meta for this taxonomy.' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } -} diff --git a/lib/class-wp-rest-meta-users-controller.php b/lib/class-wp-rest-meta-users-controller.php deleted file mode 100644 index 8cd1475..0000000 --- a/lib/class-wp-rest-meta-users-controller.php +++ /dev/null @@ -1,99 +0,0 @@ -parent_controller = new WP_REST_Users_Controller(); - $this->namespace = 'wp/v2'; - $this->rest_base = 'meta'; - } - - /** - * Check if a given request has access to get meta for a user. - * - * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|boolean - */ - public function get_items_permissions_check( $request ) { - $user = get_user_by( 'id', (int) $request['parent_id'] ); - - if ( empty( $user ) || empty( $user->ID ) ) { - return new WP_Error( 'rest_user_invalid_id', __( 'Invalid user id.' ), array( 'status' => 404 ) ); - } - - if ( ! current_user_can( 'edit_user', $user->ID ) ) { - return new WP_Error( 'rest_forbidden', __( 'Sorry, you cannot view the meta for this user.' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } - - /** - * Check if a given request has access to get a specific meta entry for a user. - * - * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|boolean - */ - public function get_item_permissions_check( $request ) { - return $this->get_items_permissions_check( $request ); - } - - /** - * Check if a given request has access to create a meta entry for a user. - * - * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|boolean - */ - public function create_item_permissions_check( $request ) { - return $this->get_items_permissions_check( $request ); - } - - /** - * Check if a given request has access to update a meta entry for a user. - * - * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|boolean - */ - public function update_item_permissions_check( $request ) { - return $this->get_items_permissions_check( $request ); - } - - /** - * Check if a given request has access to delete meta for a user. - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_Error|boolean - */ - public function delete_item_permissions_check( $request ) { - $user = get_user_by( 'id', (int) $request['parent_id'] ); - - if ( empty( $user ) || empty( $user->ID ) ) { - return new WP_Error( 'rest_user_invalid_id', __( 'Invalid user id.' ), array( 'status' => 404 ) ); - } - - if ( ! current_user_can( 'delete_user', $user->ID ) ) { - return new WP_Error( 'rest_forbidden', __( 'Sorry, you cannot delete the meta for this user.' ), array( 'status' => rest_authorization_required_code() ) ); - } - return true; - } -} diff --git a/lib/class-wp-rest-post-meta-fields.php b/lib/class-wp-rest-post-meta-fields.php new file mode 100644 index 0000000..c164603 --- /dev/null +++ b/lib/class-wp-rest-post-meta-fields.php @@ -0,0 +1,37 @@ +post_type = $post_type; + } + + /** + * Get the object type for meta. + * + * @return string + */ + protected function get_meta_type() { + return 'post'; + } + + /** + * Get the type for `register_rest_field`. + * + * @return string Custom post type slug. + */ + public function get_rest_field_type() { + return $this->post_type; + } +} diff --git a/lib/class-wp-rest-term-meta-fields.php b/lib/class-wp-rest-term-meta-fields.php new file mode 100644 index 0000000..6c4e962 --- /dev/null +++ b/lib/class-wp-rest-term-meta-fields.php @@ -0,0 +1,36 @@ +taxonomy = $taxonomy; + } + + /** + * Get the object type for meta. + * + * @return string + */ + protected function get_meta_type() { + return 'term'; + } + + /** + * Get the type for `register_rest_field`. + * + * @return string + */ + public function get_rest_field_type() { + return 'post_tag' === $this->taxonomy ? 'tag' : $this->taxonomy; + } +} diff --git a/lib/class-wp-rest-user-meta-fields.php b/lib/class-wp-rest-user-meta-fields.php new file mode 100644 index 0000000..2e25c7e --- /dev/null +++ b/lib/class-wp-rest-user-meta-fields.php @@ -0,0 +1,21 @@ + true ), 'objects' ) as $post_type ) { if ( post_type_supports( $post_type->name, 'custom-fields' ) ) { - $meta_controller = new WP_REST_Meta_Posts_Controller( $post_type->name ); - $meta_controller->register_routes(); + $post_meta = new WP_REST_Post_Meta_Fields( $post_type->name ); + $post_meta->register_field(); } } foreach ( get_taxonomies( array( 'show_in_rest' => true ), 'objects' ) as $taxonomy ) { - $terms_meta_controller = new WP_REST_Meta_Terms_Controller( $taxonomy->name ); - $terms_meta_controller->register_routes(); + $terms_meta = new WP_REST_Term_Meta_Fields( $taxonomy->name ); + $terms_meta->register_field(); } - $user_meta_controller = new WP_REST_Meta_Users_Controller(); - $user_meta_controller->register_routes(); - - $comment_meta_controller = new WP_REST_Meta_Comments_Controller(); - $comment_meta_controller->register_routes(); + $user_meta = new WP_REST_User_Meta_Fields(); + $user_meta->register_field(); + $comment_meta = new WP_REST_Comment_Meta_Fields(); + $comment_meta->register_field(); } add_action( 'rest_api_init', 'meta_rest_api_init', 11 ); From 8719aa92df9bfb79637d98c36dcece8762512393 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 22 Sep 2016 21:34:04 -0400 Subject: [PATCH 02/36] Merge the default schema into the supplied one --- lib/class-wp-rest-meta-fields.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/class-wp-rest-meta-fields.php b/lib/class-wp-rest-meta-fields.php index e13bee6..408890c 100644 --- a/lib/class-wp-rest-meta-fields.php +++ b/lib/class-wp-rest-meta-fields.php @@ -240,15 +240,17 @@ protected function get_registered_fields() { } $default_args = array( - 'name' => $name, - 'single' => $args['single'], - 'schema' => array( - 'type' => empty( $args['type'] ) ? null : $args['type'], - 'description' => empty( $args['description'] ) ? '' : $args['description'], - 'default' => isset( $args['default'] ) ? $args['default'] : null, - ), + 'name' => $name, + 'single' => $args['single'], + 'schema' => array(), + ); + $default_schema = array( + 'type' => empty( $args['type'] ) ? null : $args['type'], + 'description' => empty( $args['description'] ) ? '' : $args['description'], + 'default' => isset( $args['default'] ) ? $args['default'] : null, ); $rest_args = array_merge( $default_args, $rest_args ); + $rest_args['schema'] = array_merge( $default_schema, $rest_args['schema'] ); // skip over settings that don't have a defined type in the schema if ( empty( $rest_args['schema']['type'] ) ) { From bbf8bad7cd9a6a271feb7fb08b7388c0c356f699 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Mon, 26 Sep 2016 16:30:06 -0400 Subject: [PATCH 03/36] Add prepare_callback for meta values --- lib/class-wp-rest-meta-fields.php | 27 ++++++++++----------------- plugin.php | 27 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/lib/class-wp-rest-meta-fields.php b/lib/class-wp-rest-meta-fields.php index 408890c..30b9f7d 100644 --- a/lib/class-wp-rest-meta-fields.php +++ b/lib/class-wp-rest-meta-fields.php @@ -48,11 +48,11 @@ public function get_value( $data, $field_name, $request, $type ) { } else { $value = $all_values[0]; } - $value = $this->prepare_value_for_response( $value, $name, $args ); + $value = $this->prepare_value_for_response( $value, $request, $args ); } else { $value = array(); foreach ( $all_values as $row ) { - $value[] = $this->prepare_value_for_response( $row, $name, $args ); + $value[] = $this->prepare_value_for_response( $row, $request, $args ); } } @@ -70,21 +70,13 @@ public function get_value( $data, $field_name, $request, $type ) { * before passing back to JSON. * * @param mixed $value Value to prepare. - * @param string $name Meta key. + * @param WP_REST_Request $request Current request object. * @param array $args Options for the field. * @return mixed Prepared value. */ - protected function prepare_value_for_response( $value, $name, $args ) { - switch ( $args['schema']['type'] ) { - case 'string': - $value = strval( $value ); - break; - case 'number': - $value = floatval( $value ); - break; - case 'boolean': - $value = (bool) $value; - break; + protected function prepare_value_for_response( $value, $request, $args ) { + if ( ! empty( $args['prepare_callback'] ) ) { + $value = call_user_func( $args['prepare_callback'], $value, $request, $args ); } return $value; @@ -240,9 +232,10 @@ protected function get_registered_fields() { } $default_args = array( - 'name' => $name, - 'single' => $args['single'], - 'schema' => array(), + 'name' => $name, + 'single' => $args['single'], + 'schema' => array(), + 'prepare_callback' => 'meta_rest_api_prepare_value', ); $default_schema = array( 'type' => empty( $args['type'] ) ? null : $args['type'], diff --git a/plugin.php b/plugin.php index 82e24a8..fe846ca 100644 --- a/plugin.php +++ b/plugin.php @@ -37,3 +37,30 @@ function meta_rest_api_init() { } add_action( 'rest_api_init', 'meta_rest_api_init', 11 ); + +/** + * Prepare a meta value for output. + * + * Default preparation for meta fields. Override by passing the + * `prepare_callback` in your `show_in_rest` options. + * + * @param mixed $value Meta value from the database. + * @param WP_REST_Request $request Request object. + * @param array $args REST-specific options for the meta key. + * @return mixed Value prepared for output. + */ +function meta_rest_api_prepare_value( $value, $request, $args ) { + switch ( $args['schema']['type'] ) { + case 'string': + $value = strval( $value ); + break; + case 'number': + $value = floatval( $value ); + break; + case 'boolean': + $value = (bool) $value; + break; + } + + return $value; +} From 4313e3453079f61c2cb49fa2143acf947e1e0348 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Wed, 28 Sep 2016 16:23:51 -0400 Subject: [PATCH 04/36] Update tests --- tests/test-rest-meta-posts-controller.php | 1033 --------------------- 1 file changed, 1033 deletions(-) delete mode 100644 tests/test-rest-meta-posts-controller.php diff --git a/tests/test-rest-meta-posts-controller.php b/tests/test-rest-meta-posts-controller.php deleted file mode 100644 index 2be6374..0000000 --- a/tests/test-rest-meta-posts-controller.php +++ /dev/null @@ -1,1033 +0,0 @@ -user = $this->factory->user->create(); - wp_set_current_user( $this->user ); - $this->user_obj = wp_get_current_user(); - $this->user_obj->add_role( 'author' ); - } - - public function test_register_routes() { - $routes = $this->server->get_routes(); - - $this->assertArrayHasKey( '/wp/v2/posts/(?P[\d]+)/meta', $routes ); - $this->assertCount( 2, $routes['/wp/v2/posts/(?P[\d]+)/meta'] ); - $this->assertArrayHasKey( '/wp/v2/posts/(?P[\d]+)/meta/(?P[\d]+)', $routes ); - $this->assertCount( 3, $routes['/wp/v2/posts/(?P[\d]+)/meta/(?P[\d]+)'] ); - } - - public function test_context_param() { - $post_id = $this->factory->post->create(); - // Collection - $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts/' . $post_id . '/meta' ); - $response = $this->server->dispatch( $request ); - $data = $response->get_data(); - $this->assertEquals( 'edit', $data['endpoints'][0]['args']['context']['default'] ); - $this->assertEquals( array( 'edit' ), $data['endpoints'][0]['args']['context']['enum'] ); - // Single - $meta_id_basic = add_post_meta( $post_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts/' . $post_id . '/meta/' . $meta_id_basic ); - $response = $this->server->dispatch( $request ); - $data = $response->get_data(); - $this->assertEquals( 'edit', $data['endpoints'][0]['args']['context']['default'] ); - $this->assertEquals( array( 'edit' ), $data['endpoints'][0]['args']['context']['enum'] ); - } - - public function test_get_items() { - $post_id = $this->factory->post->create(); - $meta_id_basic = add_post_meta( $post_id, 'testkey', 'testvalue' ); - $meta_id_other1 = add_post_meta( $post_id, 'testotherkey', 'testvalue1' ); - $meta_id_other2 = add_post_meta( $post_id, 'testotherkey', 'testvalue2' ); - $value = array( 'testvalue1', 'testvalue2' ); - // serialized - add_post_meta( $post_id, 'testkey', $value ); - $value = (object) array( 'testvalue' => 'test' ); - // serialized object - add_post_meta( $post_id, 'testkey', $value ); - $value = serialize( array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ) ); - // serialized string - add_post_meta( $post_id, 'testkey', $value ); - // protected - add_post_meta( $post_id, '_testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/meta', $post_id ) ); - $response = $this->server->dispatch( $request ); - - $this->assertEquals( 200, $response->get_status() ); - - $data = $response->get_data(); - $this->assertCount( 3, $data ); - - foreach ( $data as $row ) { - $row = (array) $row; - $this->assertArrayHasKey( 'id', $row ); - $this->assertArrayHasKey( 'key', $row ); - $this->assertArrayHasKey( 'value', $row ); - - $this->assertTrue( in_array( $row['id'], array( $meta_id_basic, $meta_id_other1, $meta_id_other2 ) ) ); - - if ( $row['id'] === $meta_id_basic ) { - $this->assertEquals( 'testkey', $row['key'] ); - $this->assertEquals( 'testvalue', $row['value'] ); - } elseif ( $row['id'] === $meta_id_other1 ) { - $this->assertEquals( 'testotherkey', $row['key'] ); - $this->assertEquals( 'testvalue1', $row['value'] ); - } elseif ( $row['id'] === $meta_id_other2 ) { - $this->assertEquals( 'testotherkey', $row['key'] ); - $this->assertEquals( 'testvalue2', $row['value'] ); - } else { - $this->fail(); - } - } - } - - public function test_get_item_schema() { - // No-op - } - - public function test_prepare_item() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - - $data = $response->get_data(); - $this->assertEquals( $meta_id, $data['id'] ); - $this->assertEquals( 'testkey', $data['key'] ); - $this->assertEquals( 'testvalue', $data['value'] ); - } - - public function test_get_item() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - - $response = $this->server->dispatch( $request ); - - $this->assertEquals( 200, $response->get_status() ); - - $data = $response->get_data(); - $this->assertEquals( $meta_id, $data['id'] ); - $this->assertEquals( 'testkey', $data['key'] ); - $this->assertEquals( 'testvalue', $data['value'] ); - } - - public function test_get_item_no_post_id() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - // Use the real URL to ensure routing succeeds - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - // Override the id parameter to ensure meta is checking it - $request['parent_id'] = 0; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 ); - } - - public function test_get_item_invalid_post_id() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - // Use the real URL to ensure routing succeeds - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - // Override the id parameter to ensure meta is checking it - $request['parent_id'] = -1; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 ); - } - - public function test_get_item_no_meta_id() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - // Override the mid parameter to ensure meta is checking it - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/meta/%d', 0, $meta_id ) ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 ); - } - - public function test_get_item_invalid_meta_id() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - // Use the real URL to ensure routing succeeds - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - // Override the mid parameter to ensure meta is checking it - $request['id'] = -1; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_id', $response, 404 ); - } - - public function test_get_item_protected() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, '_testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - } - - public function test_get_item_serialized_array() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', array( 'testvalue' => 'test' ) ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - } - - public function test_get_item_serialized_object() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', (object) array( 'testvalue' => 'test' ) ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - } - - public function test_get_item_unauthenticated() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - wp_set_current_user( 0 ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_forbidden', $response, 401 ); - } - - public function test_get_item_wrong_post() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $post_id_two = $this->factory->post->create(); - $meta_id_two = add_post_meta( $post_id_two, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id_two, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_post_mismatch', $response, 400 ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id_two ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_post_mismatch', $response, 400 ); - } - - public function test_get_items_no_post_id() { - $post_id = $this->factory->post->create(); - add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/meta', $post_id ) ); - $request['parent_id'] = 0; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_id', $response ); - } - - public function test_get_items_invalid_post_id() { - $post_id = $this->factory->post->create(); - add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/meta', $post_id ) ); - $request['parent_id'] = -1; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_id', $response ); - } - - public function test_get_items_unauthenticated() { - $post_id = $this->factory->post->create(); - add_post_meta( $post_id, 'testkey', 'testvalue' ); - - wp_set_current_user( 0 ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d/meta', $post_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_forbidden', $response ); - } - - public function test_create_item() { - $post_id = $this->factory->post->create(); - $data = array( - 'key' => 'testkey', - 'value' => 'testvalue', - ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d/meta', $post_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - - $meta = get_post_meta( $post_id, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( 'testvalue', $meta[0] ); - - $data = $response->get_data(); - $this->assertArrayHasKey( 'id', $data ); - $this->assertEquals( 'testkey', $data['key'] ); - $this->assertEquals( 'testvalue', $data['value'] ); - } - - public function test_create_item_no_post_id() { - $post_id = $this->factory->post->create(); - $data = array( - 'key' => 'testkey', - 'value' => 'testvalue', - ); - - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d/meta', $post_id ) ); - $request->set_body_params( $data ); - - $request['parent_id'] = 0; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 ); - } - - public function test_create_item_invalid_post_id() { - $post_id = $this->factory->post->create(); - $data = array( - 'key' => 'testkey', - 'value' => 'testvalue', - ); - - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d/meta', $post_id ) ); - $request->set_body_params( $data ); - - $request['parent_id'] = -1; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 ); - } - - public function test_create_item_no_value() { - $post_id = $this->factory->post->create(); - $data = array( - 'key' => 'testkey', - ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d/meta', $post_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - - $data = $response->get_data(); - $this->assertArrayHasKey( 'id', $data ); - $this->assertEquals( 'testkey', $data['key'] ); - $this->assertEquals( '', $data['value'] ); - } - - public function test_create_item_no_key() { - $post_id = $this->factory->post->create(); - $data = array( - 'value' => 'testvalue', - ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d/meta', $post_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_missing_callback_param', $response, 400 ); - } - - public function test_create_item_empty_string_key() { - $post_id = $this->factory->post->create(); - $data = array( - 'key' => '', - 'value' => 'testvalue', - ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d/meta', $post_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_key', $response, 400 ); - } - - public function test_create_item_invalid_key() { - $post_id = $this->factory->post->create(); - $data = array( - 'key' => false, - 'value' => 'testvalue', - ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d/meta', $post_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_key', $response, 400 ); - } - - public function test_create_item_unauthenticated() { - $post_id = $this->factory->post->create(); - $data = array( - 'key' => 'testkey', - 'value' => 'testvalue', - ); - - wp_set_current_user( 0 ); - - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d/meta', $post_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_forbidden', $response, 401 ); - $this->assertEmpty( get_post_meta( $post_id, 'testkey' ) ); - } - - public function test_create_item_serialized_array() { - $post_id = $this->factory->post->create(); - $data = array( - 'key' => 'testkey', - 'value' => array( 'testvalue1', 'testvalue2' ), - ); - - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d/meta', $post_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - $this->assertEmpty( get_post_meta( $post_id, 'testkey' ) ); - } - - public function test_create_item_serialized_object() { - $post_id = $this->factory->post->create(); - $data = array( - 'key' => 'testkey', - 'value' => (object) array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ), - ); - - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d/meta', $post_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - $this->assertEmpty( get_post_meta( $post_id, 'testkey' ) ); - } - - public function test_create_item_serialized_string() { - $post_id = $this->factory->post->create(); - $data = array( - 'key' => 'testkey', - 'value' => serialize( array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ) ), - ); - - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d/meta', $post_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_action', $response, 400 ); - $this->assertEmpty( get_post_meta( $post_id, 'testkey' ) ); - } - - public function test_create_item_failed_get() { - $this->markTestSkipped(); - - $this->endpoint = $this->getMock( 'WP_REST_Meta_Posts', array( 'get_meta' ), array( $this->fake_server ) ); - - $test_error = new WP_Error( 'rest_test_error', 'Test error' ); - $this->endpoint->expects( $this->any() )->method( 'get_meta' )->will( $this->returnValue( $test_error ) ); - - $post_id = $this->factory->post->create(); - $data = array( - 'key' => 'testkey', - 'value' => 'testvalue', - ); - - $response = $this->endpoint->add_meta( $post_id, $data ); - $this->assertErrorResponse( 'rest_test_error', $response ); - } - - public function test_create_item_protected() { - $post_id = $this->factory->post->create(); - $data = array( - 'key' => '_testkey', - 'value' => 'testvalue', - ); - - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d/meta', $post_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - $this->assertEmpty( get_post_meta( $post_id, '_testkey' ) ); - } - - /** - * Ensure slashes aren't added - */ - public function test_create_item_unslashed() { - $post_id = $this->factory->post->create(); - $data = array( - 'key' => 'testkey', - 'value' => "test unslashed ' value", - ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d/meta', $post_id ) ); - $request->set_body_params( $data ); - - $this->server->dispatch( $request ); - - $meta = get_post_meta( $post_id, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( "test unslashed ' value", $meta[0] ); - } - - /** - * Ensure slashes aren't touched in data - */ - public function test_create_item_slashed() { - $post_id = $this->factory->post->create(); - $data = array( - 'key' => 'testkey', - 'value' => "test slashed \\' value", - ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d/meta', $post_id ) ); - $request->set_body_params( $data ); - - $this->server->dispatch( $request ); - - $meta = get_post_meta( $post_id, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( "test slashed \\' value", $meta[0] ); - } - - public function test_update_item() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $data = array( - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - - $this->assertEquals( 200, $response->get_status() ); - - $data = $response->get_data(); - $this->assertEquals( $meta_id, $data['id'] ); - $this->assertEquals( 'testkey', $data['key'] ); - $this->assertEquals( 'testnewvalue', $data['value'] ); - - $meta = get_post_meta( $post_id, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( 'testnewvalue', $meta[0] ); - } - - public function test_update_meta_key() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $data = array( - 'key' => 'testnewkey', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - - $this->assertEquals( 200, $response->get_status() ); - - $data = $response->get_data(); - $this->assertEquals( $meta_id, $data['id'] ); - $this->assertEquals( 'testnewkey', $data['key'] ); - $this->assertEquals( 'testvalue', $data['value'] ); - - $meta = get_post_meta( $post_id, 'testnewkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( 'testvalue', $meta[0] ); - - // Ensure it was actually renamed, not created - $meta = get_post_meta( $post_id, 'testkey', false ); - $this->assertEmpty( $meta ); - } - - public function test_update_meta_key_and_value() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $data = array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - - $this->assertEquals( 200, $response->get_status() ); - - $data = $response->get_data(); - $this->assertEquals( $meta_id, $data['id'] ); - $this->assertEquals( 'testnewkey', $data['key'] ); - $this->assertEquals( 'testnewvalue', $data['value'] ); - - $meta = get_post_meta( $post_id, 'testnewkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( 'testnewvalue', $meta[0] ); - - // Ensure it was actually renamed, not created - $meta = get_post_meta( $post_id, 'testkey', false ); - $this->assertEmpty( $meta ); - } - - public function test_update_meta_empty() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $data = array(); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_data_invalid', $response, 400 ); - } - - public function test_update_meta_no_post_id() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $data = array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d/meta/%d', 0, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 ); - } - - public function test_update_meta_invalid_post_id() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $data = array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d/meta/%d', REST_TESTS_IMPOSSIBLY_HIGH_NUMBER, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 ); - } - - public function test_update_meta_no_meta_id() { - $post_id = $this->factory->post->create(); - add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $data = array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, 0 ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_id', $response, 404 ); - $this->assertEquals( array( 'testvalue' ), get_post_meta( $post_id, 'testkey' ) ); - } - - public function test_update_meta_invalid_meta_id() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $data = array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request['id'] = -1; - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_id', $response, 404 ); - $this->assertEquals( array( 'testvalue' ), get_post_meta( $post_id, 'testkey' ) ); - } - - public function test_update_meta_unauthenticated() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - wp_set_current_user( 0 ); - - $data = array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_forbidden', $response, 401 ); - $this->assertEquals( array( 'testvalue' ), get_post_meta( $post_id, 'testkey' ) ); - } - - public function test_update_meta_wrong_post() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $post_id_two = $this->factory->post->create(); - $meta_id_two = add_post_meta( $post_id_two, 'testkey', 'testvalue' ); - - $data = array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id_two, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_post_mismatch', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_post_meta( $post_id_two, 'testkey' ) ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id_two ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_post_mismatch', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_post_meta( $post_id, 'testkey' ) ); - } - - public function test_update_meta_serialized_array() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $data = array( - 'value' => array( 'testvalue1', 'testvalue2' ), - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_post_meta( $post_id, 'testkey' ) ); - } - - public function test_update_meta_serialized_object() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $data = array( - 'value' => (object) array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ), - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_post_meta( $post_id, 'testkey' ) ); - } - - public function test_update_meta_serialized_string() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $data = array( - 'value' => serialize( array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ) ), - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_action', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_post_meta( $post_id, 'testkey' ) ); - } - - public function test_update_meta_existing_serialized() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', array( 'testvalue1', 'testvalue2' ) ); - - $data = array( - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_action', $response, 400 ); - $this->assertEquals( array( array( 'testvalue1', 'testvalue2' ) ), get_post_meta( $post_id, 'testkey' ) ); - } - - public function test_update_meta_protected() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, '_testkey', 'testvalue' ); - - $data = array( - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - $this->assertEquals( array( 'testvalue' ), get_post_meta( $post_id, '_testkey' ) ); - } - - public function test_update_meta_protected_new() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $data = array( - 'key' => '_testnewkey', - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - $this->assertEquals( array( 'testvalue' ), get_post_meta( $post_id, 'testkey' ) ); - $this->assertEmpty( get_post_meta( $post_id, '_testnewkey' ) ); - } - - public function test_update_meta_invalid_key() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $data = array( - 'key' => false, - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_key', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_post_meta( $post_id, 'testkey' ) ); - } - - /** - * Ensure slashes aren't added - */ - public function test_update_meta_unslashed() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $data = array( - 'key' => 'testkey', - 'value' => "test unslashed ' value", - ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request->set_body_params( $data ); - - $this->server->dispatch( $request ); - - $meta = get_post_meta( $post_id, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( "test unslashed ' value", $meta[0] ); - } - - /** - * Ensure slashes aren't touched in data - */ - public function test_update_meta_slashed() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $data = array( - 'key' => 'testkey', - 'value' => "test slashed \\' value", - ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request->set_body_params( $data ); - - $this->server->dispatch( $request ); - - $meta = get_post_meta( $post_id, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( "test slashed \\' value", $meta[0] ); - } - - public function test_delete_item() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request['force'] = true; - $response = $this->server->dispatch( $request ); - - $this->assertEquals( 200, $response->get_status() ); - - $data = $response->get_data(); - $this->assertArrayHasKey( 'message', $data ); - $this->assertNotEmpty( $data['message'] ); - - $meta = get_post_meta( $post_id, 'testkey', false ); - $this->assertEmpty( $meta ); - } - - public function test_delete_item_no_trash() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_trash_not_supported', $response, 501 ); - - // Ensure the meta still exists - $meta = get_metadata_by_mid( 'post', $meta_id ); - $this->assertNotEmpty( $meta ); - } - - public function test_delete_item_no_post_id() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request['force'] = true; - $request['parent_id'] = 0; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 ); - - $this->assertEquals( array( 'testvalue' ), get_post_meta( $post_id, 'testkey', false ) ); - } - - public function test_delete_item_invalid_post_id() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request['force'] = true; - $request['parent_id'] = -1; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 ); - - $this->assertEquals( array( 'testvalue' ), get_post_meta( $post_id, 'testkey', false ) ); - } - - public function test_delete_item_no_meta_id() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request['force'] = true; - $request['id'] = 0; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_id', $response, 404 ); - - $this->assertEquals( array( 'testvalue' ), get_post_meta( $post_id, 'testkey', false ) ); - } - - public function test_delete_item_invalid_meta_id() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request['force'] = true; - $request['id'] = -1; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_id', $response, 404 ); - - $this->assertEquals( array( 'testvalue' ), get_post_meta( $post_id, 'testkey', false ) ); - } - - public function test_delete_item_unauthenticated() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - wp_set_current_user( 0 ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_forbidden', $response, 401 ); - - $this->assertEquals( array( 'testvalue' ), get_post_meta( $post_id, 'testkey', false ) ); - } - - public function test_delete_item_wrong_post() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, 'testkey', 'testvalue' ); - - $post_id_two = $this->factory->post->create(); - $meta_id_two = add_post_meta( $post_id_two, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id_two, $meta_id ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_post_mismatch', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_post_meta( $post_id_two, 'testkey' ) ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id_two ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_post_mismatch', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_post_meta( $post_id, 'testkey' ) ); - } - - public function test_delete_item_serialized_array() { - $post_id = $this->factory->post->create(); - $value = array( 'testvalue1', 'testvalue2' ); - $meta_id = add_post_meta( $post_id, 'testkey', $value ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_action', $response, 400 ); - $this->assertEquals( array( $value ), get_post_meta( $post_id, 'testkey' ) ); - } - - public function test_delete_item_serialized_object() { - $post_id = $this->factory->post->create(); - $value = (object) array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ); - $meta_id = add_post_meta( $post_id, 'testkey', $value ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_action', $response, 400 ); - $this->assertEquals( array( $value ), get_post_meta( $post_id, 'testkey' ) ); - } - - public function test_delete_item_serialized_string() { - $post_id = $this->factory->post->create(); - $value = serialize( array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ) ); - $meta_id = add_post_meta( $post_id, 'testkey', $value ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_post_invalid_action', $response, 400 ); - $this->assertEquals( array( $value ), get_post_meta( $post_id, 'testkey' ) ); - } - - public function test_delete_item_protected() { - $post_id = $this->factory->post->create(); - $meta_id = add_post_meta( $post_id, '_testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/posts/%d/meta/%d', $post_id, $meta_id ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - $this->assertEquals( array( 'testvalue' ), get_post_meta( $post_id, '_testkey' ) ); - } -} From af85a61ea1de8d8704e188e801e4e5af6402f9f2 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Wed, 28 Sep 2016 16:24:00 -0400 Subject: [PATCH 05/36] Don't allow non-serializable objects to be output --- plugin.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugin.php b/plugin.php index fe846ca..dc32c0d 100644 --- a/plugin.php +++ b/plugin.php @@ -62,5 +62,10 @@ function meta_rest_api_prepare_value( $value, $request, $args ) { break; } + // Don't allow objects to be output. + if ( is_object( $value ) && ! ( $value instanceof JsonSerializable ) ) { + return null; + } + return $value; } From b6adc9302f4d739948553dbb8af2e69fe6e53e04 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Wed, 28 Sep 2016 16:51:35 -0400 Subject: [PATCH 06/36] Remove old tests --- .../test-rest-meta-categories-controller.php | 749 ------------ tests/test-rest-meta-comments-controller.php | 784 ------------ tests/test-rest-meta-users-controller.php | 1087 ----------------- 3 files changed, 2620 deletions(-) delete mode 100644 tests/test-rest-meta-categories-controller.php delete mode 100644 tests/test-rest-meta-comments-controller.php delete mode 100644 tests/test-rest-meta-users-controller.php diff --git a/tests/test-rest-meta-categories-controller.php b/tests/test-rest-meta-categories-controller.php deleted file mode 100644 index a2e5879..0000000 --- a/tests/test-rest-meta-categories-controller.php +++ /dev/null @@ -1,749 +0,0 @@ -administrator = $this->factory->user->create( array( - 'role' => 'administrator', - ) ); - $this->subscriber = $this->factory->user->create( array( - 'role' => 'subscriber', - ) ); - - wp_set_current_user( $this->administrator ); - - $this->category_id = $this->factory->category->create( array( 'name' => 'Test Category' ) ); - $this->category_2_id = $this->factory->category->create( array( 'name' => 'Test Category 2' ) ); - } - - public function test_register_routes() { - $routes = $this->server->get_routes(); - - $this->assertArrayHasKey( '/wp/v2/categories/(?P[\d]+)/meta', $routes ); - $this->assertCount( 2, $routes['/wp/v2/categories/(?P[\d]+)/meta'] ); - $this->assertArrayHasKey( '/wp/v2/categories/(?P[\d]+)/meta/(?P[\d]+)', $routes ); - $this->assertCount( 3, $routes['/wp/v2/categories/(?P[\d]+)/meta/(?P[\d]+)'] ); - } - - public function test_context_param() { - // Collection - $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/categories/' . $this->category_id . '/meta' ); - $response = $this->server->dispatch( $request ); - $data = $response->get_data(); - $this->assertEquals( 'edit', $data['endpoints'][0]['args']['context']['default'] ); - $this->assertEquals( array( 'edit' ), $data['endpoints'][0]['args']['context']['enum'] ); - // Single - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/categories/' . $this->category_id . '/meta/' . $meta_id ); - $response = $this->server->dispatch( $request ); - $data = $response->get_data(); - $this->assertEquals( 'edit', $data['endpoints'][0]['args']['context']['default'] ); - $this->assertEquals( array( 'edit' ), $data['endpoints'][0]['args']['context']['enum'] ); - } - - public function test_prepare_item() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - - $data = $response->get_data(); - $this->assertEquals( $meta_id, $data['id'] ); - $this->assertEquals( 'testkey', $data['key'] ); - $this->assertEquals( 'testvalue', $data['value'] ); - } - - public function test_get_items() { - $meta_id_basic = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - $meta_id_other1 = add_term_meta( $this->category_id, 'testotherkey', 'testvalue1' ); - $meta_id_other2 = add_term_meta( $this->category_id, 'testotherkey', 'testvalue2' ); - $value = array( 'testvalue1', 'testvalue2' ); - // serialized - add_term_meta( $this->category_id, 'testkey', $value ); - $value = (object) array( 'testvalue' => 'test' ); - // serialized object - add_term_meta( $this->category_id, 'testkey', $value ); - $value = serialize( array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ) ); - // serialized string - add_term_meta( $this->category_id, 'testkey', $value ); - // protected - add_term_meta( $this->category_id, '_testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/categories/%d/meta', $this->category_id ) ); - $response = $this->server->dispatch( $request ); - - $this->assertEquals( 200, $response->get_status() ); - - $data = $response->get_data(); - $this->assertCount( 3, $data ); - - foreach ( $data as $row ) { - $row = (array) $row; - $this->assertArrayHasKey( 'id', $row ); - $this->assertArrayHasKey( 'key', $row ); - $this->assertArrayHasKey( 'value', $row ); - - $this->assertTrue( in_array( $row['id'], array( $meta_id_basic, $meta_id_other1, $meta_id_other2 ) ) ); - - if ( $row['id'] === $meta_id_basic ) { - $this->assertEquals( 'testkey', $row['key'] ); - $this->assertEquals( 'testvalue', $row['value'] ); - } elseif ( $row['id'] === $meta_id_other1 ) { - $this->assertEquals( 'testotherkey', $row['key'] ); - $this->assertEquals( 'testvalue1', $row['value'] ); - } elseif ( $row['id'] === $meta_id_other2 ) { - $this->assertEquals( 'testotherkey', $row['key'] ); - $this->assertEquals( 'testvalue2', $row['value'] ); - } else { - $this->fail(); - } - } - } - - public function test_get_item() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - - $response = $this->server->dispatch( $request ); - - $this->assertEquals( 200, $response->get_status() ); - - $data = $response->get_data(); - $this->assertEquals( $meta_id, $data['id'] ); - $this->assertEquals( 'testkey', $data['key'] ); - $this->assertEquals( 'testvalue', $data['value'] ); - } - - public function test_get_item_no_term_id() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - // Use the real URL to ensure routing succeeds - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - // Override the id parameter to ensure meta is checking it - $request['parent_id'] = 0; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_term_invalid_id', $response, 404 ); - } - - public function test_get_item_invalid_term_id() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - // Use the real URL to ensure routing succeeds - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - // Override the id parameter to ensure meta is checking it - $request['parent_id'] = -1; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_term_invalid_id', $response, 404 ); - } - - public function test_get_item_no_meta_id() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - // Override the mid parameter to ensure meta is checking it - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/categories/%d/meta/%d', 0, $meta_id ) ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_term_invalid_id', $response, 404 ); - } - - public function test_get_item_invalid_meta_id() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - // Use the real URL to ensure routing succeeds - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - // Override the mid parameter to ensure meta is checking it - $request['id'] = -1; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_id', $response, 404 ); - } - - public function test_get_item_protected() { - $meta_id = add_term_meta( $this->category_id, '_testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - } - - public function test_get_item_serialized_array() { - $meta_id = add_term_meta( $this->category_id, 'testkey', array( 'testvalue' => 'test' ) ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - } - - public function test_get_item_serialized_object() { - $meta_id = add_term_meta( $this->category_id, 'testkey', (object) array( 'testvalue' => 'test' ) ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - } - - public function test_get_item_unauthenticated() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - wp_set_current_user( 0 ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_forbidden', $response, 401 ); - } - - public function test_get_item_wrong_term() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - $meta_id_two = add_term_meta( $this->category_2_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_2_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_term_mismatch', $response, 400 ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id_two ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_term_mismatch', $response, 400 ); - } - - public function test_get_items_no_term_id() { - add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/categories/%d/meta', $this->category_id ) ); - $request['parent_id'] = 0; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_term_invalid_id', $response ); - } - - public function test_get_items_invalid_term_id() { - add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/categories/%d/meta', $this->category_id ) ); - $request['parent_id'] = -1; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_term_invalid_id', $response ); - } - - public function test_get_items_unauthenticated() { - add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - wp_set_current_user( 0 ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/categories/%d/meta', $this->category_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_forbidden', $response ); - } - - public function test_create_item() { - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/categories/%d/meta', $this->category_id ) ); - $request->set_body_params( array( - 'key' => 'testkey', - 'value' => 'testvalue', - ) ); - - $response = $this->server->dispatch( $request ); - - $meta = get_term_meta( $this->category_id, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( 'testvalue', $meta[0] ); - - $data = $response->get_data(); - $this->assertArrayHasKey( 'id', $data ); - $this->assertEquals( 'testkey', $data['key'] ); - $this->assertEquals( 'testvalue', $data['value'] ); - } - - public function test_update_item() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $data = array( - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - - $this->assertEquals( 200, $response->get_status() ); - - $data = $response->get_data(); - $this->assertEquals( $meta_id, $data['id'] ); - $this->assertEquals( 'testkey', $data['key'] ); - $this->assertEquals( 'testnewvalue', $data['value'] ); - - $meta = get_term_meta( $this->category_id, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( 'testnewvalue', $meta[0] ); - } - - public function test_update_meta_key() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request->set_body_params( array( - 'key' => 'testnewkey', - ) ); - - $response = $this->server->dispatch( $request ); - - $this->assertEquals( 200, $response->get_status() ); - - $data = $response->get_data(); - $this->assertEquals( $meta_id, $data['id'] ); - $this->assertEquals( 'testnewkey', $data['key'] ); - $this->assertEquals( 'testvalue', $data['value'] ); - - $meta = get_term_meta( $this->category_id, 'testnewkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( 'testvalue', $meta[0] ); - - // Ensure it was actually renamed, not created - $meta = get_term_meta( $this->category_id, 'testkey', false ); - $this->assertEmpty( $meta ); - } - - public function test_update_meta_key_and_value() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request->set_body_params( array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ) ); - - $response = $this->server->dispatch( $request ); - - $this->assertEquals( 200, $response->get_status() ); - - $data = $response->get_data(); - $this->assertEquals( $meta_id, $data['id'] ); - $this->assertEquals( 'testnewkey', $data['key'] ); - $this->assertEquals( 'testnewvalue', $data['value'] ); - - $meta = get_term_meta( $this->category_id, 'testnewkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( 'testnewvalue', $meta[0] ); - - // Ensure it was actually renamed, not created - $meta = get_term_meta( $this->category_id, 'testkey', false ); - $this->assertEmpty( $meta ); - } - - public function test_update_meta_empty() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request->set_body_params( array() ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_data_invalid', $response, 400 ); - } - - public function test_update_meta_no_term_id() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/categories/%d/meta/%d', 0, $meta_id ) ); - $request->set_body_params( array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ) ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_term_invalid_id', $response, 404 ); - } - - public function test_update_meta_invalid_term_id() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/categories/%d/meta/%d', REST_TESTS_IMPOSSIBLY_HIGH_NUMBER, $meta_id ) ); - $request->set_body_params( array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ) ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_term_invalid_id', $response, 404 ); - } - - public function test_update_meta_no_meta_id() { - add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, 0 ) ); - $request->set_body_params( array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ) ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_id', $response, 404 ); - $this->assertEquals( array( 'testvalue' ), get_term_meta( $this->category_id, 'testkey' ) ); - } - - public function test_update_meta_invalid_meta_id() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request['id'] = 'a'; - $request->set_body_params( array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ) ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_id', $response, 404 ); - $this->assertEquals( array( 'testvalue' ), get_term_meta( $this->category_id, 'testkey' ) ); - } - - public function test_update_meta_unauthenticated() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - wp_set_current_user( 0 ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request->set_body_params( array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ) ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_forbidden', $response, 401 ); - $this->assertEquals( array( 'testvalue' ), get_term_meta( $this->category_id, 'testkey' ) ); - } - - public function test_update_meta_wrong_term() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - $meta_id_two = add_term_meta( $this->category_2_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_2_id, $meta_id ) ); - $request->set_body_params( array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ) ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_term_mismatch', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_term_meta( $this->category_2_id, 'testkey' ) ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id_two ) ); - $request->set_body_params( array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ) ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_term_mismatch', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_term_meta( $this->category_id, 'testkey' ) ); - } - - public function test_update_meta_serialized_array() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request->set_body_params( array( - 'value' => array( 'testvalue1', 'testvalue2' ), - ) ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_term_meta( $this->category_id, 'testkey' ) ); - } - - public function test_update_meta_serialized_object() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request->set_body_params( array( - 'value' => (object) array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ), - ) ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_term_meta( $this->category_id, 'testkey' ) ); - } - - public function test_update_meta_serialized_string() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request->set_body_params( array( - 'value' => serialize( array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ) ), - ) ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_action', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_term_meta( $this->category_id, 'testkey' ) ); - } - - public function test_update_meta_existing_serialized() { - $meta_id = add_term_meta( $this->category_id, 'testkey', array( 'testvalue1', 'testvalue2' ) ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request->set_body_params( array( - 'value' => 'testnewvalue', - ) ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_action', $response, 400 ); - $this->assertEquals( array( array( 'testvalue1', 'testvalue2' ) ), get_term_meta( $this->category_id, 'testkey' ) ); - } - - public function test_update_meta_protected() { - $meta_id = add_term_meta( $this->category_id, '_testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request->set_body_params( array( - 'value' => 'testnewvalue', - ) ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - $this->assertEquals( array( 'testvalue' ), get_term_meta( $this->category_id, '_testkey' ) ); - } - - public function test_update_meta_protected_new() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request->set_body_params( array( - 'key' => '_testnewkey', - 'value' => 'testnewvalue', - ) ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - $this->assertEquals( array( 'testvalue' ), get_term_meta( $this->category_id, 'testkey' ) ); - $this->assertEmpty( get_term_meta( $this->category_id, '_testnewkey' ) ); - } - - public function test_update_meta_invalid_key() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request->set_body_params( array( - 'key' => false, - 'value' => 'testnewvalue', - ) ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_key', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_term_meta( $this->category_id, 'testkey' ) ); - } - - /** - * Ensure slashes aren't added - */ - public function test_update_meta_unslashed() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request->set_body_params( array( - 'key' => 'testkey', - 'value' => "test unslashed ' value", - ) ); - - $this->server->dispatch( $request ); - - $meta = get_term_meta( $this->category_id, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( "test unslashed ' value", $meta[0] ); - } - - /** - * Ensure slashes aren't touched in data - */ - public function test_update_meta_slashed() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request->set_body_params( array( - 'key' => 'testkey', - 'value' => "test slashed \\' value", - ) ); - - $this->server->dispatch( $request ); - - $meta = get_term_meta( $this->category_id, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( "test slashed \\' value", $meta[0] ); - } - - public function test_delete_item() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request['force'] = true; - $response = $this->server->dispatch( $request ); - - $this->assertEquals( 200, $response->get_status() ); - - $data = $response->get_data(); - $this->assertArrayHasKey( 'message', $data ); - $this->assertNotEmpty( $data['message'] ); - - $meta = get_term_meta( $this->category_id, 'testkey', false ); - $this->assertEmpty( $meta ); - } - - public function test_delete_item_no_trash() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_trash_not_supported', $response, 501 ); - - // Ensure the meta still exists - $meta = get_metadata_by_mid( 'term', $meta_id ); - $this->assertNotEmpty( $meta ); - } - - public function test_delete_item_no_term_id() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request['force'] = true; - $request['parent_id'] = 0; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_term_invalid_id', $response, 404 ); - - $this->assertEquals( array( 'testvalue' ), get_term_meta( $this->category_id, 'testkey', false ) ); - } - - public function test_delete_item_invalid_term_id() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request['force'] = true; - $request['parent_id'] = -1; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_term_invalid_id', $response, 404 ); - - $this->assertEquals( array( 'testvalue' ), get_term_meta( $this->category_id, 'testkey', false ) ); - } - - public function test_delete_item_no_meta_id() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request['force'] = true; - $request['id'] = 0; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_id', $response, 404 ); - - $this->assertEquals( array( 'testvalue' ), get_term_meta( $this->category_id, 'testkey', false ) ); - } - - public function test_delete_item_invalid_meta_id() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request['force'] = true; - $request['id'] = -1; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_id', $response, 404 ); - - $this->assertEquals( array( 'testvalue' ), get_term_meta( $this->category_id, 'testkey', false ) ); - } - - public function test_delete_item_unauthenticated() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - - wp_set_current_user( 0 ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_forbidden', $response, 401 ); - - $this->assertEquals( array( 'testvalue' ), get_term_meta( $this->category_id, 'testkey', false ) ); - } - - public function test_delete_item_wrong_term() { - $meta_id = add_term_meta( $this->category_id, 'testkey', 'testvalue' ); - $meta_id_two = add_term_meta( $this->category_2_id, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_2_id, $meta_id ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_term_mismatch', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_term_meta( $this->category_2_id, 'testkey' ) ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id_two ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_term_mismatch', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_term_meta( $this->category_id, 'testkey' ) ); - } - - public function test_delete_item_serialized_array() { - $value = array( 'testvalue1', 'testvalue2' ); - $meta_id = add_term_meta( $this->category_id, 'testkey', $value ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_action', $response, 400 ); - $this->assertEquals( array( $value ), get_term_meta( $this->category_id, 'testkey' ) ); - } - - public function test_delete_item_serialized_object() { - $value = (object) array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ); - $meta_id = add_term_meta( $this->category_id, 'testkey', $value ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_action', $response, 400 ); - $this->assertEquals( array( $value ), get_term_meta( $this->category_id, 'testkey' ) ); - } - - public function test_delete_item_serialized_string() { - $value = serialize( array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ) ); - $meta_id = add_term_meta( $this->category_id, 'testkey', $value ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_action', $response, 400 ); - $this->assertEquals( array( $value ), get_term_meta( $this->category_id, 'testkey' ) ); - } - - public function test_delete_item_protected() { - $meta_id = add_term_meta( $this->category_id, '_testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/categories/%d/meta/%d', $this->category_id, $meta_id ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - $this->assertEquals( array( 'testvalue' ), get_term_meta( $this->category_id, '_testkey' ) ); - } - - public function test_get_item_schema() { - // No-op - } -} diff --git a/tests/test-rest-meta-comments-controller.php b/tests/test-rest-meta-comments-controller.php deleted file mode 100644 index 14ca26f..0000000 --- a/tests/test-rest-meta-comments-controller.php +++ /dev/null @@ -1,784 +0,0 @@ -admin_id = $this->factory->user->create( array( - 'role' => 'administrator', - )); - $this->subscriber_id = $this->factory->user->create( array( - 'role' => 'subscriber', - )); - $this->author_id = $this->factory->user->create( array( - 'role' => 'author', - )); - $this->post_id = $this->factory->post->create(); - $this->approved_id = $this->factory->comment->create( array( - 'comment_approved' => 1, - 'comment_post_ID' => $this->post_id, - 'user_id' => 0, - )); - $this->hold_id = $this->factory->comment->create( array( - 'comment_approved' => 0, - 'comment_post_ID' => $this->post_id, - 'user_id' => $this->subscriber_id, - )); - } - public function test_register_routes() { - $routes = $this->server->get_routes(); - $this->assertArrayHasKey( '/wp/v2/comments/(?P[\d]+)/meta', $routes ); - $this->assertCount( 2, $routes['/wp/v2/comments/(?P[\d]+)/meta'] ); - $this->assertArrayHasKey( '/wp/v2/comments/(?P[\d]+)/meta/(?P[\d]+)', $routes ); - $this->assertCount( 3, $routes['/wp/v2/comments/(?P[\d]+)/meta/(?P[\d]+)'] ); - } - public function test_context_param() { - // Collection - $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/comments/' . $this->approved_id . '/meta' ); - $response = $this->server->dispatch( $request ); - $data = $response->get_data(); - $this->assertEquals( 'edit', $data['endpoints'][0]['args']['context']['default'] ); - $this->assertEquals( array( 'edit' ), $data['endpoints'][0]['args']['context']['enum'] ); - // Single - $meta_id_basic = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/comments/' . $this->approved_id . '/meta/' . $meta_id_basic ); - $response = $this->server->dispatch( $request ); - $data = $response->get_data(); - $this->assertEquals( 'edit', $data['endpoints'][0]['args']['context']['default'] ); - $this->assertEquals( array( 'edit' ), $data['endpoints'][0]['args']['context']['enum'] ); - } - public function test_get_item() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertEquals( 200, $response->get_status() ); - $data = $response->get_data(); - $this->assertEquals( $meta_id, $data['id'] ); - $this->assertEquals( 'testkey', $data['key'] ); - $this->assertEquals( 'testvalue', $data['value'] ); - } - public function test_get_items() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $meta_id_basic = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $meta_id_other1 = add_comment_meta( $this->approved_id, 'testotherkey', 'testvalue1' ); - $meta_id_other2 = add_comment_meta( $this->approved_id, 'testotherkey', 'testvalue2' ); - $value = array( 'testvalue1', 'testvalue2' ); - // serialized - add_comment_meta( $this->approved_id, 'testkey', $value ); - $value = (object) array( 'testvalue' => 'test' ); - // serialized object - add_comment_meta( $this->approved_id, 'testkey', $value ); - $value = serialize( array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ) ); - // serialized string - add_comment_meta( $this->approved_id, 'testkey', $value ); - // protected - add_comment_meta( $this->approved_id, '_testkey', 'testvalue' ); - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d/meta', $this->approved_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertEquals( 200, $response->get_status() ); - $data = $response->get_data(); - foreach ( $data as $row ) { - $row = (array) $row; - $this->assertArrayHasKey( 'id', $row ); - $this->assertArrayHasKey( 'key', $row ); - $this->assertArrayHasKey( 'value', $row ); - if ( $row['id'] === $meta_id_basic ) { - $this->assertEquals( 'testkey', $row['key'] ); - $this->assertEquals( 'testvalue', $row['value'] ); - } - if ( $row['id'] === $meta_id_other1 ) { - $this->assertEquals( 'testotherkey', $row['key'] ); - $this->assertEquals( 'testvalue1', $row['value'] ); - } - if ( $row['id'] === $meta_id_other2 ) { - $this->assertEquals( 'testotherkey', $row['key'] ); - $this->assertEquals( 'testvalue2', $row['value'] ); - } - } - } - public function test_get_item_no_comment_id() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request['parent_id'] = 0; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_comment_invalid_id', $response, 404 ); - } - public function test_get_item_invalid_comment_id() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request['parent_id'] = -1; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_comment_invalid_id', $response, 404 ); - } - public function test_get_item_no_meta_id() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d/meta/%d', 0, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_comment_invalid_id', $response, 404 ); - } - public function test_get_item_invalid_meta_id() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request['id'] = 'a'; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_id', $response, 404 ); - } - public function test_get_item_protected() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, '_testkey', 'testvalue' ); - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - } - public function test_get_item_serialized_array() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', array( 'testvalue' => 'test' ) ); - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - } - public function test_get_item_serialized_object() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', (object) array( 'testvalue' => 'test' ) ); - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - } - public function test_get_item_unauthenticated() { - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - wp_set_current_user( 0 ); - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_forbidden', $response, 401 ); - } - public function test_get_item_wrong_comment() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $meta_id_two = add_comment_meta( $this->hold_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d/meta/%d', $this->hold_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_comment_mismatch', $response, 400 ); - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id_two ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_comment_mismatch', $response, 400 ); - } - public function test_get_items_no_comment_id() { - wp_set_current_user( $this->admin_id ); - add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d/meta', $this->approved_id ) ); - $request['parent_id'] = 0; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_comment_invalid_id', $response ); - } - public function test_get_items_invalid_comment_id() { - wp_set_current_user( $this->admin_id ); - add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d/meta', $this->approved_id ) ); - $request['parent_id'] = -1; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_comment_invalid_id', $response ); - } - public function test_get_items_unauthenticated() { - add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - wp_set_current_user( 0 ); - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d/meta', $this->approved_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_forbidden', $response ); - } - public function test_create_item() { - wp_set_current_user( $this->admin_id ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d/meta', $this->approved_id ) ); - $request->set_body_params( array( - 'key' => 'testkey', - 'value' => 'testvalue', - ) ); - $response = $this->server->dispatch( $request ); - $meta = get_comment_meta( $this->approved_id, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( 'testvalue', $meta[0] ); - $data = $response->get_data(); - $this->assertArrayHasKey( 'id', $data ); - $this->assertEquals( 'testkey', $data['key'] ); - $this->assertEquals( 'testvalue', $data['value'] ); - } - public function test_create_item_no_comment_id() { - wp_set_current_user( $this->admin_id ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d/meta', $this->approved_id ) ); - $request->set_body_params( array( - 'key' => 'testkey', - 'value' => 'testvalue', - ) ); - $request['parent_id'] = 0; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_comment_invalid_id', $response, 404 ); - } - public function test_create_item_invalid_comment_id() { - wp_set_current_user( $this->admin_id ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d/meta', $this->approved_id ) ); - $request->set_body_params( array( - 'key' => 'testkey', - 'value' => 'testvalue', - ) ); - $request['parent_id'] = -1; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_comment_invalid_id', $response, 404 ); - } - public function test_create_item_no_value() { - wp_set_current_user( $this->admin_id ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d/meta', $this->approved_id ) ); - $request->set_body_params( array( - 'key' => 'testkey', - ) ); - $response = $this->server->dispatch( $request ); - $data = $response->get_data(); - $this->assertArrayHasKey( 'id', $data ); - $this->assertEquals( 'testkey', $data['key'] ); - $this->assertEquals( '', $data['value'] ); - } - public function test_create_item_no_key() { - wp_set_current_user( $this->admin_id ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d/meta', $this->approved_id ) ); - $request->set_body_params( array( - 'value' => 'testvalue', - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_missing_callback_param', $response, 400 ); - } - public function test_create_item_empty_string_key() { - wp_set_current_user( $this->admin_id ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d/meta', $this->approved_id ) ); - $request->set_body_params( array( - 'key' => '', - 'value' => 'testvalue', - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_key', $response, 400 ); - } - public function test_create_item_invalid_key() { - wp_set_current_user( $this->admin_id ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d/meta', $this->approved_id ) ); - $request->set_body_params( array( - 'key' => false, - 'value' => 'testvalue', - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_key', $response, 400 ); - } - public function test_create_item_unauthenticated() { - wp_set_current_user( 0 ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d/meta', $this->approved_id ) ); - $request->set_body_params( array( - 'key' => 'testkey', - 'value' => 'testvalue', - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_forbidden', $response, 401 ); - $this->assertEmpty( get_comment_meta( $this->approved_id, 'testkey' ) ); - } - public function test_create_item_serialized_array() { - wp_set_current_user( $this->admin_id ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d/meta', $this->approved_id ) ); - $request->set_body_params( array( - 'key' => 'testkey', - 'value' => array( 'testvalue1', 'testvalue2' ), - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - $this->assertEmpty( get_comment_meta( $this->approved_id, 'testkey' ) ); - } - public function test_create_item_serialized_object() { - wp_set_current_user( $this->admin_id ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d/meta', $this->approved_id ) ); - $request->set_body_params( array( - 'key' => 'testkey', - 'value' => (object) array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ), - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - $this->assertEmpty( get_comment_meta( $this->approved_id, 'testkey' ) ); - } - public function test_create_item_serialized_string() { - wp_set_current_user( $this->admin_id ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d/meta', $this->approved_id ) ); - $request->set_body_params( array( - 'key' => 'testkey', - 'value' => serialize( array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ) ), - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_action', $response, 400 ); - $this->assertEmpty( get_comment_meta( $this->approved_id, 'testkey' ) ); - } - public function test_create_item_failed_get() { - $this->markTestSkipped(); - $this->endpoint = $this->getMock( 'WP_REST_Meta_Comments', array( 'get_meta' ), array( $this->fake_server ) ); - $test_error = new WP_Error( 'rest_test_error', 'Test error' ); - $this->endpoint->expects( $this->any() )->method( 'get_meta' )->will( $this->returnValue( $test_error ) ); - wp_set_current_user( $this->admin_id ); - $response = $this->endpoint->add_meta( $this->approved_id, array( - 'key' => 'testkey', - 'value' => 'testvalue', - ) ); - $this->assertErrorResponse( 'rest_test_error', $response ); - } - public function test_create_item_protected() { - wp_set_current_user( $this->admin_id ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d/meta', $this->approved_id ) ); - $request->set_body_params( array( - 'key' => '_testkey', - 'value' => 'testvalue', - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - $this->assertEmpty( get_comment_meta( $this->approved_id, '_testkey' ) ); - } - /** - * Ensure slashes aren't added - */ - public function test_create_item_unslashed() { - wp_set_current_user( $this->admin_id ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d/meta', $this->approved_id ) ); - $request->set_body_params( array( - 'key' => 'testkey', - 'value' => "test unslashed ' value", - ) ); - $this->server->dispatch( $request ); - $meta = get_comment_meta( $this->approved_id, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( "test unslashed ' value", $meta[0] ); - } - /** - * Ensure slashes aren't touched in data - */ - public function test_create_item_slashed() { - wp_set_current_user( $this->admin_id ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d/meta', $this->approved_id ) ); - $request->set_body_params( array( - 'key' => 'testkey', - 'value' => "test slashed \\' value", - ) ); - $this->server->dispatch( $request ); - $meta = get_comment_meta( $this->approved_id, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( "test slashed \\' value", $meta[0] ); - } - public function test_update_item() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request->set_body_params( array( - 'value' => 'testnewvalue', - ) ); - $response = $this->server->dispatch( $request ); - $this->assertEquals( 200, $response->get_status() ); - $data = $response->get_data(); - $this->assertEquals( $meta_id, $data['id'] ); - $this->assertEquals( 'testkey', $data['key'] ); - $this->assertEquals( 'testnewvalue', $data['value'] ); - $meta = get_comment_meta( $this->approved_id, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( 'testnewvalue', $meta[0] ); - } - public function test_update_meta_key() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request->set_body_params( array( - 'key' => 'testnewkey', - ) ); - $response = $this->server->dispatch( $request ); - $this->assertEquals( 200, $response->get_status() ); - $data = $response->get_data(); - $this->assertEquals( $meta_id, $data['id'] ); - $this->assertEquals( 'testnewkey', $data['key'] ); - $this->assertEquals( 'testvalue', $data['value'] ); - $meta = get_comment_meta( $this->approved_id, 'testnewkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( 'testvalue', $meta[0] ); - // Ensure it was actually renamed, not created - $meta = get_comment_meta( $this->approved_id, 'testkey', false ); - $this->assertEmpty( $meta ); - } - public function test_update_meta_key_and_value() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request->set_body_params( array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ) ); - $response = $this->server->dispatch( $request ); - $this->assertEquals( 200, $response->get_status() ); - $data = $response->get_data(); - $this->assertEquals( $meta_id, $data['id'] ); - $this->assertEquals( 'testnewkey', $data['key'] ); - $this->assertEquals( 'testnewvalue', $data['value'] ); - $meta = get_comment_meta( $this->approved_id, 'testnewkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( 'testnewvalue', $meta[0] ); - // Ensure it was actually renamed, not created - $meta = get_comment_meta( $this->approved_id, 'testkey', false ); - $this->assertEmpty( $meta ); - } - public function test_update_meta_empty() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request->set_body_params( array() ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_data_invalid', $response, 400 ); - } - public function test_update_meta_no_comment_id() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d/meta/%d', 0, $meta_id ) ); - $request->set_body_params( array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_comment_invalid_id', $response, 404 ); - } - public function test_update_meta_invalid_comment_id() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d/meta/%d', REST_TESTS_IMPOSSIBLY_HIGH_NUMBER, $meta_id ) ); - $request->set_body_params( array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_comment_invalid_id', $response, 404 ); - } - public function test_update_meta_no_meta_id() { - wp_set_current_user( $this->admin_id ); - add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, 0 ) ); - $request->set_body_params( array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_id', $response, 404 ); - $this->assertEquals( array( 'testvalue' ), get_comment_meta( $this->approved_id, 'testkey' ) ); - } - public function test_update_meta_invalid_meta_id() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request['id'] = 'a'; - $request->set_body_params( array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_id', $response, 404 ); - $this->assertEquals( array( 'testvalue' ), get_comment_meta( $this->approved_id, 'testkey' ) ); - } - public function test_update_meta_unauthenticated() { - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - wp_set_current_user( 0 ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request->set_body_params( array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_forbidden', $response, 401 ); - $this->assertEquals( array( 'testvalue' ), get_comment_meta( $this->approved_id, 'testkey' ) ); - } - public function test_update_meta_wrong_comment() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $meta_id_two = add_comment_meta( $this->hold_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d/meta/%d', $this->hold_id, $meta_id ) ); - $request->set_body_params( array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_comment_mismatch', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_comment_meta( $this->hold_id, 'testkey' ) ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id_two ) ); - $request->set_body_params( array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_comment_mismatch', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_comment_meta( $this->approved_id, 'testkey' ) ); - } - public function test_update_meta_serialized_array() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request->set_body_params( array( - 'value' => array( 'testvalue1', 'testvalue2' ), - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_comment_meta( $this->approved_id, 'testkey' ) ); - } - public function test_update_meta_serialized_object() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request->set_body_params( array( - 'value' => (object) array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ), - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_comment_meta( $this->approved_id, 'testkey' ) ); - } - public function test_update_meta_serialized_string() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request->set_body_params( array( - 'value' => serialize( array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ) ), - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_action', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_comment_meta( $this->approved_id, 'testkey' ) ); - } - public function test_update_meta_existing_serialized() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', array( 'testvalue1', 'testvalue2' ) ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request->set_body_params( array( - 'value' => 'testnewvalue', - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_action', $response, 400 ); - $this->assertEquals( array( array( 'testvalue1', 'testvalue2' ) ), get_comment_meta( $this->approved_id, 'testkey' ) ); - } - public function test_update_meta_protected() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, '_testkey', 'testvalue' ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request->set_body_params( array( - 'value' => 'testnewvalue', - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - $this->assertEquals( array( 'testvalue' ), get_comment_meta( $this->approved_id, '_testkey' ) ); - } - public function test_update_meta_protected_new() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request->set_body_params( array( - 'key' => '_testnewkey', - 'value' => 'testnewvalue', - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - $this->assertEquals( array( 'testvalue' ), get_comment_meta( $this->approved_id, 'testkey' ) ); - $this->assertEmpty( get_comment_meta( $this->approved_id, '_testnewkey' ) ); - } - public function test_update_meta_invalid_key() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request->set_body_params( array( - 'key' => false, - 'value' => 'testnewvalue', - ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_key', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_comment_meta( $this->approved_id, 'testkey' ) ); - } - /** - * Ensure slashes aren't added - */ - public function test_update_meta_unslashed() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request->set_body_params( array( - 'key' => 'testkey', - 'value' => "test unslashed ' value", - ) ); - $this->server->dispatch( $request ); - $meta = get_comment_meta( $this->approved_id, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( "test unslashed ' value", $meta[0] ); - } - /** - * Ensure slashes aren't touched in data - */ - public function test_update_meta_slashed() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request->set_body_params( array( - 'key' => 'testkey', - 'value' => "test slashed \\' value", - ) ); - $this->server->dispatch( $request ); - $meta = get_comment_meta( $this->approved_id, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( "test slashed \\' value", $meta[0] ); - } - public function test_delete_item() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request['force'] = true; - $response = $this->server->dispatch( $request ); - $this->assertEquals( 200, $response->get_status() ); - $data = $response->get_data(); - $this->assertArrayHasKey( 'message', $data ); - $this->assertNotEmpty( $data['message'] ); - $meta = get_comment_meta( $this->approved_id, 'testkey', false ); - $this->assertEmpty( $meta ); - } - public function test_delete_item_no_trash() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_trash_not_supported', $response, 501 ); - // Ensure the meta still exists - $meta = get_metadata_by_mid( 'comment', $meta_id ); - $this->assertNotEmpty( $meta ); - } - public function test_delete_item_no_comment_id() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request['force'] = true; - $request['parent_id'] = 0; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_comment_invalid_id', $response, 404 ); - $this->assertEquals( array( 'testvalue' ), get_comment_meta( $this->approved_id, 'testkey', false ) ); - } - public function test_delete_item_invalid_comment_id() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request['force'] = true; - $request['parent_id'] = -1; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_comment_invalid_id', $response, 404 ); - $this->assertEquals( array( 'testvalue' ), get_comment_meta( $this->approved_id, 'testkey', false ) ); - } - public function test_delete_item_no_meta_id() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request['force'] = true; - $request['id'] = 0; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_id', $response, 404 ); - $this->assertEquals( array( 'testvalue' ), get_comment_meta( $this->approved_id, 'testkey', false ) ); - } - public function test_delete_item_invalid_meta_id() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request['force'] = true; - $request['id'] = -1; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_id', $response, 404 ); - $this->assertEquals( array( 'testvalue' ), get_comment_meta( $this->approved_id, 'testkey', false ) ); - } - public function test_delete_item_unauthenticated() { - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - wp_set_current_user( 0 ); - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request['force'] = true; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_forbidden', $response, 401 ); - $this->assertEquals( array( 'testvalue' ), get_comment_meta( $this->approved_id, 'testkey', false ) ); - } - public function test_delete_item_wrong_comment() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $meta_id_two = add_comment_meta( $this->hold_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/comments/%d/meta/%d', $this->hold_id, $meta_id ) ); - $request['force'] = true; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_comment_mismatch', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_comment_meta( $this->hold_id, 'testkey' ) ); - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id_two ) ); - $request['force'] = true; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_comment_mismatch', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_comment_meta( $this->approved_id, 'testkey' ) ); - } - public function test_delete_item_serialized_array() { - wp_set_current_user( $this->admin_id ); - $value = array( 'testvalue1', 'testvalue2' ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', $value ); - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request['force'] = true; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_action', $response, 400 ); - $this->assertEquals( array( $value ), get_comment_meta( $this->approved_id, 'testkey' ) ); - } - public function test_delete_item_serialized_object() { - wp_set_current_user( $this->admin_id ); - $value = (object) array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', $value ); - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request['force'] = true; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_action', $response, 400 ); - $this->assertEquals( array( $value ), get_comment_meta( $this->approved_id, 'testkey' ) ); - } - public function test_delete_item_serialized_string() { - wp_set_current_user( $this->admin_id ); - $value = serialize( array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ) ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', $value ); - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request['force'] = true; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_action', $response, 400 ); - $this->assertEquals( array( $value ), get_comment_meta( $this->approved_id, 'testkey' ) ); - } - public function test_delete_item_protected() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, '_testkey', 'testvalue' ); - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $request['force'] = true; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - $this->assertEquals( array( 'testvalue' ), get_comment_meta( $this->approved_id, '_testkey' ) ); - } - public function test_prepare_item() { - wp_set_current_user( $this->admin_id ); - $meta_id = add_comment_meta( $this->approved_id, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d/meta/%d', $this->approved_id, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $data = $response->get_data(); - $this->assertEquals( $meta_id, $data['id'] ); - $this->assertEquals( 'testkey', $data['key'] ); - $this->assertEquals( 'testvalue', $data['value'] ); - } - public function test_get_item_schema() { - // No op - } -} diff --git a/tests/test-rest-meta-users-controller.php b/tests/test-rest-meta-users-controller.php deleted file mode 100644 index 1b602c8..0000000 --- a/tests/test-rest-meta-users-controller.php +++ /dev/null @@ -1,1087 +0,0 @@ -user = $this->factory->user->create( array( - 'role' => 'administrator', - ) ); - } - - public function test_register_routes() { - $routes = $this->server->get_routes(); - - $this->assertArrayHasKey( '/wp/v2/users/(?P[\d]+)/meta', $routes ); - $this->assertCount( 2, $routes['/wp/v2/users/(?P[\d]+)/meta'] ); - $this->assertArrayHasKey( '/wp/v2/users/(?P[\d]+)/meta/(?P[\d]+)', $routes ); - $this->assertCount( 3, $routes['/wp/v2/users/(?P[\d]+)/meta/(?P[\d]+)'] ); - } - - public function test_context_param() { - $this->user = $this->factory->user->create(); - // Collection - $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/users/' . $this->user . '/meta' ); - $response = $this->server->dispatch( $request ); - $data = $response->get_data(); - $this->assertEquals( 'edit', $data['endpoints'][0]['args']['context']['default'] ); - $this->assertEquals( array( 'edit' ), $data['endpoints'][0]['args']['context']['enum'] ); - // Single - $meta_id_basic = add_user_meta( $this->user, 'testkey', 'testvalue' ); - $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/users/' . $this->user . '/meta/' . $meta_id_basic ); - $response = $this->server->dispatch( $request ); - $data = $response->get_data(); - $this->assertEquals( 'edit', $data['endpoints'][0]['args']['context']['default'] ); - $this->assertEquals( array( 'edit' ), $data['endpoints'][0]['args']['context']['enum'] ); - } - - public function test_get_item() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $response = $this->server->dispatch( $request ); - - $this->assertEquals( 200, $response->get_status() ); - $data = $response->get_data(); - $this->assertCount( 3, $data ); - - if ( $data['id'] === $meta_id ) { - $this->assertEquals( 'testkey', $data['key'] ); - $this->assertEquals( 'testvalue', $data['value'] ); - } else { - $this->fail(); - } - } - - public function test_get_items() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - - $meta_id_serialized = add_user_meta( $this->user, 'testkey_serialized', array( 'testvalue1', 'testvalue2' ) ); - $meta_id_serialized_object = add_user_meta( $this->user, 'testkey_serialized_object', (object) array( 'testvalue' => 'test' ) ); - $meta_id_serialized_array = add_user_meta( $this->user, 'testkey_serialized_array', serialize( array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ) ) ); - $meta_id_protected = add_user_meta( $this->user, '_testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d/meta', $this->user ) ); - $response = $this->server->dispatch( $request ); - - $this->assertEquals( 200, $response->get_status() ); - $data = $response->get_data(); - - foreach ( $data as $row ) { - $row = (array) $row; - $this->assertArrayHasKey( 'id', $row ); - $this->assertArrayHasKey( 'key', $row ); - $this->assertArrayHasKey( 'value', $row ); - - if ( $row['id'] === $meta_id_serialized ) { - $this->assertEquals( 'testkey_serialized', $row['key'] ); - $this->assertEquals( array( 'testvalue1', 'testvalue2' ), $row['value'] ); - } - - if ( $row['id'] === $meta_id_serialized_object ) { - $this->assertEquals( 'testkey_serialized_object', $row['key'] ); - $this->assertEquals( (object) array( 'testvalue' => 'test' ), $row['value'] ); - } - - if ( $row['id'] === $meta_id_serialized_array ) { - $this->assertEquals( 'testkey_serialized_array', $row['key'] ); - $this->assertEquals( serialize( array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ) ), $row['value'] ); - } - } - } - - public function test_get_item_no_user_id() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request['parent_id'] = 0; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 ); - } - - public function test_get_item_invalid_user_id() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request['parent_id'] = -1; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 ); - } - - public function test_get_item_no_meta_id() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d/meta/%d', 0, $meta_id ) ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 ); - } - - public function test_get_item_invalid_meta_id() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request['id'] = 'a'; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_id', $response, 404 ); - } - - public function test_get_item_protected() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, '_testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - } - - public function test_get_item_serialized_array() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', array( 'testvalue' => 'test' ) ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - } - - public function test_get_item_serialized_object() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', (object) array( 'testvalue' => 'test' ) ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - } - - public function test_get_item_unauthenticated() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - wp_set_current_user( 0 ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_forbidden', $response, 401 ); - } - - public function test_get_item_wrong_user() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $this->user_two = $this->factory->user->create(); - $meta_id_two = add_user_meta( $this->user_two, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d/meta/%d', $this->user_two, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_user_mismatch', $response, 400 ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id_two ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_user_mismatch', $response, 400 ); - } - - public function test_get_items_no_user_id() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d/meta', $this->user ) ); - $request['parent_id'] = 0; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_user_invalid_id', $response ); - } - - public function test_get_items_invalid_user_id() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d/meta', $this->user ) ); - $request['parent_id'] = -1; - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_user_invalid_id', $response ); - } - - public function test_get_items_unauthenticated() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - add_user_meta( $this->user, 'testkey', 'testvalue' ); - - wp_set_current_user( 0 ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d/meta', $this->user ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_forbidden', $response ); - } - - public function test_create_item() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d/meta', $this->user ) ); - $request->set_body_params( array( - 'key' => 'testkey', - 'value' => 'testvalue', - ) ); - $response = $this->server->dispatch( $request ); - - $meta = get_user_meta( $this->user, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( 'testvalue', $meta[0] ); - - $data = $response->get_data(); - $this->assertArrayHasKey( 'id', $data ); - $this->assertEquals( 'testkey', $data['key'] ); - $this->assertEquals( 'testvalue', $data['value'] ); - } - - public function test_create_item_no_user_id() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $data = array( - 'key' => 'testkey', - 'value' => 'testvalue', - ); - - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d/meta', $this->user ) ); - $request->set_body_params( $data ); - - $request['parent_id'] = 0; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 ); - } - - public function test_create_item_invalid_user_id() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $data = array( - 'key' => 'testkey', - 'value' => 'testvalue', - ); - - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d/meta', $this->user ) ); - $request->set_body_params( $data ); - - $request['parent_id'] = -1; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 ); - } - - public function test_create_item_no_value() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $data = array( - 'key' => 'testkey', - ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d/meta', $this->user ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - - $data = $response->get_data(); - $this->assertArrayHasKey( 'id', $data ); - $this->assertEquals( 'testkey', $data['key'] ); - $this->assertEquals( '', $data['value'] ); - } - - public function test_create_item_no_key() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $data = array( - 'value' => 'testvalue', - ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d/meta', $this->user ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_missing_callback_param', $response, 400 ); - } - - public function test_create_item_empty_string_key() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $data = array( - 'key' => '', - 'value' => 'testvalue', - ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d/meta', $this->user ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_key', $response, 400 ); - } - - public function test_create_item_invalid_key() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $data = array( - 'key' => false, - 'value' => 'testvalue', - ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d/meta', $this->user ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_key', $response, 400 ); - } - - public function test_create_item_unauthenticated() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $data = array( - 'key' => 'testkey', - 'value' => 'testvalue', - ); - - wp_set_current_user( 0 ); - - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d/meta', $this->user ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_forbidden', $response, 401 ); - $this->assertEmpty( get_user_meta( $this->user, 'testkey' ) ); - } - - public function test_create_item_serialized_array() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $data = array( - 'key' => 'testkey', - 'value' => array( 'testvalue1', 'testvalue2' ), - ); - - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d/meta', $this->user ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - $this->assertEmpty( get_user_meta( $this->user, 'testkey' ) ); - } - - public function test_create_item_serialized_object() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $data = array( - 'key' => 'testkey', - 'value' => (object) array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ), - ); - - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d/meta', $this->user ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - $this->assertEmpty( get_user_meta( $this->user, 'testkey' ) ); - } - - public function test_create_item_serialized_string() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $data = array( - 'key' => 'testkey', - 'value' => serialize( array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ) ), - ); - - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d/meta', $this->user ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_action', $response, 400 ); - $this->assertEmpty( get_user_meta( $this->user, 'testkey' ) ); - } - - public function test_create_item_failed_get() { - $this->markTestSkipped(); - - $this->endpoint = $this->getMock( 'WP_REST_Meta_Posts', array( 'get_meta' ), array( $this->fake_server ) ); - - $test_error = new WP_Error( 'rest_test_error', 'Test error' ); - $this->endpoint->expects( $this->any() )->method( 'get_meta' )->will( $this->returnValue( $test_error ) ); - - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $data = array( - 'key' => 'testkey', - 'value' => 'testvalue', - ); - - $response = $this->endpoint->add_meta( $this->user, $data ); - $this->assertErrorResponse( 'rest_test_error', $response ); - } - - public function test_create_item_protected() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $data = array( - 'key' => '_testkey', - 'value' => 'testvalue', - ); - - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d/meta', $this->user ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - $this->assertEmpty( get_user_meta( $this->user, '_testkey' ) ); - } - - /** - * Ensure slashes aren't added - */ - public function test_create_item_unslashed() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $data = array( - 'key' => 'testkey', - 'value' => "test unslashed ' value", - ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d/meta', $this->user ) ); - $request->set_body_params( $data ); - - $this->server->dispatch( $request ); - - $meta = get_user_meta( $this->user, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( "test unslashed ' value", $meta[0] ); - } - - /** - * Ensure slashes aren't touched in data - */ - public function test_create_item_slashed() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $data = array( - 'key' => 'testkey', - 'value' => "test slashed \\' value", - ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d/meta', $this->user ) ); - $request->set_body_params( $data ); - - $this->server->dispatch( $request ); - - $meta = get_user_meta( $this->user, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( "test slashed \\' value", $meta[0] ); - } - - public function test_update_item() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request->set_body_params( array( - 'value' => 'testnewvalue', - ) ); - - $response = $this->server->dispatch( $request ); - - $this->assertEquals( 200, $response->get_status() ); - - $data = $response->get_data(); - $this->assertEquals( $meta_id, $data['id'] ); - $this->assertEquals( 'testkey', $data['key'] ); - $this->assertEquals( 'testnewvalue', $data['value'] ); - - $meta = get_user_meta( $this->user, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( 'testnewvalue', $meta[0] ); - } - - public function test_update_meta_key() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $data = array( - 'key' => 'testnewkey', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - - $this->assertEquals( 200, $response->get_status() ); - - $data = $response->get_data(); - $this->assertEquals( $meta_id, $data['id'] ); - $this->assertEquals( 'testnewkey', $data['key'] ); - $this->assertEquals( 'testvalue', $data['value'] ); - - $meta = get_user_meta( $this->user, 'testnewkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( 'testvalue', $meta[0] ); - - // Ensure it was actually renamed, not created - $meta = get_user_meta( $this->user, 'testkey', false ); - $this->assertEmpty( $meta ); - } - - public function test_update_meta_key_and_value() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $data = array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - - $this->assertEquals( 200, $response->get_status() ); - - $data = $response->get_data(); - $this->assertEquals( $meta_id, $data['id'] ); - $this->assertEquals( 'testnewkey', $data['key'] ); - $this->assertEquals( 'testnewvalue', $data['value'] ); - - $meta = get_user_meta( $this->user, 'testnewkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( 'testnewvalue', $meta[0] ); - - // Ensure it was actually renamed, not created - $meta = get_user_meta( $this->user, 'testkey', false ); - $this->assertEmpty( $meta ); - } - - public function test_update_meta_empty() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $data = array(); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_data_invalid', $response, 400 ); - } - - public function test_update_meta_no_user_id() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $data = array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d/meta/%d', 0, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 ); - } - - public function test_update_meta_invalid_user_id() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $data = array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d/meta/%d', REST_TESTS_IMPOSSIBLY_HIGH_NUMBER, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 ); - } - - public function test_update_meta_no_meta_id() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $data = array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, 0 ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_id', $response, 404 ); - $this->assertEquals( array( 'testvalue' ), get_user_meta( $this->user, 'testkey' ) ); - } - - public function test_update_meta_invalid_meta_id() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $data = array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request['id'] = 'a'; - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_id', $response, 404 ); - $this->assertEquals( array( 'testvalue' ), get_user_meta( $this->user, 'testkey' ) ); - } - - public function test_update_meta_unauthenticated() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - wp_set_current_user( 0 ); - - $data = array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_forbidden', $response, 401 ); - $this->assertEquals( array( 'testvalue' ), get_user_meta( $this->user, 'testkey' ) ); - } - - public function test_update_meta_wrong_user() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $this->user_two = $this->factory->user->create(); - $meta_id_two = add_user_meta( $this->user_two, 'testkey', 'testvalue' ); - - $data = array( - 'key' => 'testnewkey', - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d/meta/%d', $this->user_two, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_user_mismatch', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_user_meta( $this->user_two, 'testkey' ) ); - - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id_two ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_user_mismatch', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_user_meta( $this->user, 'testkey' ) ); - } - - public function test_update_meta_serialized_array() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $data = array( - 'value' => array( 'testvalue1', 'testvalue2' ), - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_user_meta( $this->user, 'testkey' ) ); - } - - public function test_update_meta_serialized_object() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $data = array( - 'value' => (object) array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ), - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_user_meta( $this->user, 'testkey' ) ); - } - - public function test_update_meta_serialized_string() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $data = array( - 'value' => serialize( array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ) ), - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_action', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_user_meta( $this->user, 'testkey' ) ); - } - - public function test_update_meta_existing_serialized() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', array( 'testvalue1', 'testvalue2' ) ); - - $data = array( - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_action', $response, 400 ); - $this->assertEquals( array( array( 'testvalue1', 'testvalue2' ) ), get_user_meta( $this->user, 'testkey' ) ); - } - - public function test_update_meta_protected() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, '_testkey', 'testvalue' ); - - $data = array( - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - $this->assertEquals( array( 'testvalue' ), get_user_meta( $this->user, '_testkey' ) ); - } - - public function test_update_meta_protected_new() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $data = array( - 'key' => '_testnewkey', - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - $this->assertEquals( array( 'testvalue' ), get_user_meta( $this->user, 'testkey' ) ); - $this->assertEmpty( get_user_meta( $this->user, '_testnewkey' ) ); - } - - public function test_update_meta_invalid_key() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $data = array( - 'key' => false, - 'value' => 'testnewvalue', - ); - $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request->set_body_params( $data ); - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_key', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_user_meta( $this->user, 'testkey' ) ); - } - - /** - * Ensure slashes aren't added - */ - public function test_update_meta_unslashed() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $data = array( - 'key' => 'testkey', - 'value' => "test unslashed ' value", - ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request->set_body_params( $data ); - - $this->server->dispatch( $request ); - - $meta = get_user_meta( $this->user, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( "test unslashed ' value", $meta[0] ); - } - - /** - * Ensure slashes aren't touched in data - */ - public function test_update_meta_slashed() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $data = array( - 'key' => 'testkey', - 'value' => "test slashed \\' value", - ); - $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request->set_body_params( $data ); - - $this->server->dispatch( $request ); - - $meta = get_user_meta( $this->user, 'testkey', false ); - $this->assertNotEmpty( $meta ); - $this->assertCount( 1, $meta ); - $this->assertEquals( "test slashed \\' value", $meta[0] ); - } - - public function test_delete_item() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request['force'] = true; - $response = $this->server->dispatch( $request ); - - $this->assertEquals( 200, $response->get_status() ); - - $data = $response->get_data(); - $this->assertArrayHasKey( 'message', $data ); - $this->assertNotEmpty( $data['message'] ); - - $meta = get_user_meta( $this->user, 'testkey', false ); - $this->assertEmpty( $meta ); - } - - public function test_delete_item_no_trash() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_trash_not_supported', $response, 501 ); - - // Ensure the meta still exists - $meta = get_metadata_by_mid( 'user', $meta_id ); - $this->assertNotEmpty( $meta ); - } - - public function test_delete_item_no_user_id() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request['force'] = true; - $request['parent_id'] = 0; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 ); - - $this->assertEquals( array( 'testvalue' ), get_user_meta( $this->user, 'testkey', false ) ); - } - - public function test_delete_item_invalid_user_id() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request['force'] = true; - $request['parent_id'] = -1; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_user_invalid_id', $response, 404 ); - - $this->assertEquals( array( 'testvalue' ), get_user_meta( $this->user, 'testkey', false ) ); - } - - public function test_delete_item_no_meta_id() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request['force'] = true; - $request['id'] = 0; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_id', $response, 404 ); - - $this->assertEquals( array( 'testvalue' ), get_user_meta( $this->user, 'testkey', false ) ); - } - - public function test_delete_item_invalid_meta_id() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request['force'] = true; - $request['id'] = 'a'; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_id', $response, 404 ); - - $this->assertEquals( array( 'testvalue' ), get_user_meta( $this->user, 'testkey', false ) ); - } - - public function test_delete_item_unauthenticated() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - wp_set_current_user( 0 ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_forbidden', $response, 401 ); - - $this->assertEquals( array( 'testvalue' ), get_user_meta( $this->user, 'testkey', false ) ); - } - - public function test_delete_item_wrong_user() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $this->user_two = $this->factory->user->create(); - $meta_id_two = add_user_meta( $this->user_two, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d/meta/%d', $this->user_two, $meta_id ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_user_mismatch', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_user_meta( $this->user_two, 'testkey' ) ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id_two ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_user_mismatch', $response, 400 ); - $this->assertEquals( array( 'testvalue' ), get_user_meta( $this->user, 'testkey' ) ); - } - - public function test_delete_item_serialized_array() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $value = array( 'testvalue1', 'testvalue2' ); - $meta_id = add_user_meta( $this->user, 'testkey', $value ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_action', $response, 400 ); - $this->assertEquals( array( $value ), get_user_meta( $this->user, 'testkey' ) ); - } - - public function test_delete_item_serialized_object() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $value = (object) array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ); - $meta_id = add_user_meta( $this->user, 'testkey', $value ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_action', $response, 400 ); - $this->assertEquals( array( $value ), get_user_meta( $this->user, 'testkey' ) ); - } - - public function test_delete_item_serialized_string() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $value = serialize( array( 'testkey1' => 'testvalue1', 'testkey2' => 'testvalue2' ) ); - $meta_id = add_user_meta( $this->user, 'testkey', $value ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_invalid_action', $response, 400 ); - $this->assertEquals( array( $value ), get_user_meta( $this->user, 'testkey' ) ); - } - - public function test_delete_item_protected() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - $meta_id = add_user_meta( $this->user, '_testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $request['force'] = true; - - $response = $this->server->dispatch( $request ); - $this->assertErrorResponse( 'rest_meta_protected', $response, 403 ); - $this->assertEquals( array( 'testvalue' ), get_user_meta( $this->user, '_testkey' ) ); - } - - public function test_prepare_item() { - wp_set_current_user( $this->user ); - $this->allow_user_to_manage_multisite(); - - $meta_id = add_user_meta( $this->user, 'testkey', 'testvalue' ); - - $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/users/%d/meta/%d', $this->user, $meta_id ) ); - $response = $this->server->dispatch( $request ); - - $data = $response->get_data(); - $this->assertEquals( $meta_id, $data['id'] ); - $this->assertEquals( 'testkey', $data['key'] ); - $this->assertEquals( 'testvalue', $data['value'] ); - } - - public function test_get_item_schema() { - // No op - } - - protected function allow_user_to_manage_multisite() { - wp_set_current_user( $this->user ); - $user = wp_get_current_user(); - if ( is_multisite() ) { - update_site_option( 'site_admins', array( $user->user_login ) ); - } - return; - } -} From 8aeb57385049e99bdaa41de6c640945d1878d440 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Wed, 28 Sep 2016 16:51:43 -0400 Subject: [PATCH 07/36] Add new testing --- tests/test-rest-post-meta-fields.php | 145 +++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 tests/test-rest-post-meta-fields.php diff --git a/tests/test-rest-post-meta-fields.php b/tests/test-rest-post-meta-fields.php new file mode 100644 index 0000000..db08edf --- /dev/null +++ b/tests/test-rest-post-meta-fields.php @@ -0,0 +1,145 @@ +server = $wp_rest_server = new WP_Test_Spy_REST_Server; + do_action( 'rest_api_init' ); + + register_meta( 'post', 'test_single', array( + 'show_in_rest' => true, + 'single' => true, + )); + register_meta( 'post', 'test_multi', array( + 'show_in_rest' => true, + 'single' => false, + )); + + $this->post_id = $this->factory->post->create(); + } + + public function test_get_value() { + add_post_meta( $this->post_id, 'test_single', 'testvalue' ); + + $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + $response = $this->server->dispatch( $request ); + + $this->assertEquals( 200, $response->get_status() ); + + $data = $response->get_data(); + $this->assertArrayHasKey( 'meta', $data ); + + $meta = (array) $data['meta']; + $this->assertArrayHasKey( 'test_single', $meta ); + $this->assertEquals( 'testvalue', $meta['test_single'] ); + } + + /** + * @depends test_get_value + */ + public function test_get_multi_value() { + add_post_meta( $this->post_id, 'test_multi', 'value1' ); + $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + + $response = $this->server->dispatch( $request ); + $this->assertEquals( 200, $response->get_status() ); + + $data = $response->get_data(); + $meta = (array) $data['meta']; + $this->assertArrayHasKey( 'test_multi', $meta ); + $this->assertInternalType( 'array', $meta['test_multi'] ); + $this->assertContains( 'value1', $meta['test_multi'] ); + + // Check after an update. + add_post_meta( $this->post_id, 'test_multi', 'value2' ); + + $response = $this->server->dispatch( $request ); + $this->assertEquals( 200, $response->get_status() ); + $data = $response->get_data(); + $meta = (array) $data['meta']; + $this->assertContains( 'value1', $meta['test_multi'] ); + $this->assertContains( 'value2', $meta['test_multi'] ); + } + + /** + * @depends test_get_value + */ + public function test_get_unregistered() { + add_post_meta( $this->post_id, 'test_unregistered', 'value1' ); + $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + + $response = $this->server->dispatch( $request ); + $this->assertEquals( 200, $response->get_status() ); + + $data = $response->get_data(); + $meta = (array) $data['meta']; + $this->assertArrayNotHasKey( 'test_unregistered', $meta ); + } + + /** + * @depends test_get_value + */ + public function test_set_value() { + // Ensure no data exists currently. + $values = get_post_meta( $this->post_id, 'test_single', false ); + $this->assertEmpty( $values ); + + // Ensure we have write permission. + $user = $this->factory->user->create( array( + 'role' => 'editor', + )); + wp_set_current_user( $user ); + + $data = array( + 'meta' => array( + 'test_single' => 'test_value', + ), + ); + $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + $request->set_body_params( $data ); + + $response = $this->server->dispatch( $request ); + $this->assertEquals( 200, $response->get_status() ); + + $meta = get_post_meta( $this->post_id, 'test_single', false ); + $this->assertNotEmpty( $meta ); + $this->assertCount( 1, $meta ); + $this->assertEquals( 'test_value', $meta[0] ); + + $data = $response->get_data(); + $meta = (array) $data['meta']; + $this->assertArrayHasKey( 'test_single', $meta ); + $this->assertEquals( 'test_value', $meta['test_single'] ); + } + + /** + * @depends test_set_value + */ + public function test_set_value_unauthenticated() { + $data = array( + 'meta' => array( + 'test_single' => 'test_value', + ), + ); + + wp_set_current_user( 0 ); + + $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + $request->set_body_params( $data ); + + $response = $this->server->dispatch( $request ); + $this->assertErrorResponse( 'rest_cannot_edit', $response, 401 ); + + // Check that the value wasn't actually updated. + $this->assertEmpty( get_post_meta( $this->post_id, 'test_single', false ) ); + } +} From bc185ff211c9a6a1032a47e51a3a899a554abdd2 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Wed, 28 Sep 2016 16:56:51 -0400 Subject: [PATCH 08/36] Remove duplicate blank line --- plugin.php | 1 - 1 file changed, 1 deletion(-) diff --git a/plugin.php b/plugin.php index dc32c0d..dab8145 100644 --- a/plugin.php +++ b/plugin.php @@ -16,7 +16,6 @@ function meta_rest_api_init() { require_once dirname( __FILE__ ) . '/lib/class-wp-rest-term-meta-fields.php'; require_once dirname( __FILE__ ) . '/lib/class-wp-rest-user-meta-fields.php'; - foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) { if ( post_type_supports( $post_type->name, 'custom-fields' ) ) { $post_meta = new WP_REST_Post_Meta_Fields( $post_type->name ); From e1f3a771ae6fde1971142fa548c6170cf6a7f80f Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Wed, 28 Sep 2016 16:59:26 -0400 Subject: [PATCH 09/36] Measure code coverage --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 427bf71..8e28aba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,8 @@ matrix: env: WP_TRAVISCI=travis:phpunit WP_VERSION=latest - php: 5.6 env: WP_TRAVISCI=travis:phpvalidate + - php: 5.6 + env: WP_TRAVISCI=travis:codecoverage - php: 5.5 env: WP_TRAVISCI=travis:phpunit WP_VERSION=nightly - php: 5.4 From 8e1f97e3b8caae33189d3f393aeb0e1652e67df3 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Wed, 28 Sep 2016 18:42:38 -0400 Subject: [PATCH 10/36] Add codecoverage unit test settings --- codecoverage.xml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 codecoverage.xml diff --git a/codecoverage.xml b/codecoverage.xml new file mode 100644 index 0000000..fa70f72 --- /dev/null +++ b/codecoverage.xml @@ -0,0 +1,30 @@ + + + + + + + + tests + + + + + . + + + ./lib + ./plugin.php + + + + + + From 51d408cded04bcfda61d79938ae40d7573ad971c Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Wed, 28 Sep 2016 19:21:27 -0400 Subject: [PATCH 11/36] Add test for multiple values --- tests/test-rest-post-meta-fields.php | 45 ++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/test-rest-post-meta-fields.php b/tests/test-rest-post-meta-fields.php index db08edf..073f6df 100644 --- a/tests/test-rest-post-meta-fields.php +++ b/tests/test-rest-post-meta-fields.php @@ -142,4 +142,49 @@ public function test_set_value_unauthenticated() { // Check that the value wasn't actually updated. $this->assertEmpty( get_post_meta( $this->post_id, 'test_single', false ) ); } + + public function test_set_value_multiple() { + // Ensure no data exists currently. + $values = get_post_meta( $this->post_id, 'test_multi', false ); + $this->assertEmpty( $values ); + + // Ensure we have write permission. + $user = $this->factory->user->create( array( + 'role' => 'editor', + )); + wp_set_current_user( $user ); + + $data = array( + 'meta' => array( + 'test_multi' => [ 'val1' ], + ), + ); + $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + $request->set_body_params( $data ); + + $response = $this->server->dispatch( $request ); + $this->assertEquals( 200, $response->get_status() ); + + $meta = get_post_meta( $this->post_id, 'test_multi', false ); + $this->assertNotEmpty( $meta ); + $this->assertCount( 1, $meta ); + $this->assertEquals( 'val1', $meta[0] ); + + // Add another value. + $data = array( + 'meta' => array( + 'test_multi' => [ 'val1', 'val2' ], + ), + ); + $request->set_body_params( $data ); + + $response = $this->server->dispatch( $request ); + $this->assertEquals( 200, $response->get_status() ); + + $meta = get_post_meta( $this->post_id, 'test_multi', false ); + $this->assertNotEmpty( $meta ); + $this->assertCount( 2, $meta ); + $this->assertContains( 'val1', $meta ); + $this->assertContains( 'val2', $meta ); + } } From 9d79ba3b441c7dc3b74aa9945e9d1efeb6428d25 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Wed, 28 Sep 2016 19:25:48 -0400 Subject: [PATCH 12/36] Remove "latest" as a test version --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8e28aba..e06fb8c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,6 @@ matrix: include: - php: 5.6 env: WP_TRAVISCI=travis:phpunit WP_VERSION=nightly - - php: 5.6 - env: WP_TRAVISCI=travis:phpunit WP_VERSION=latest - php: 5.6 env: WP_TRAVISCI=travis:phpvalidate - php: 5.6 From 756e22366c98dc963d2085db72a8dba55e66e81b Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Wed, 28 Sep 2016 19:26:23 -0400 Subject: [PATCH 13/36] Change array format to long-style --- tests/test-rest-post-meta-fields.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test-rest-post-meta-fields.php b/tests/test-rest-post-meta-fields.php index 073f6df..5e5cdf5 100644 --- a/tests/test-rest-post-meta-fields.php +++ b/tests/test-rest-post-meta-fields.php @@ -156,7 +156,7 @@ public function test_set_value_multiple() { $data = array( 'meta' => array( - 'test_multi' => [ 'val1' ], + 'test_multi' => array( 'val1' ), ), ); $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); @@ -173,7 +173,7 @@ public function test_set_value_multiple() { // Add another value. $data = array( 'meta' => array( - 'test_multi' => [ 'val1', 'val2' ], + 'test_multi' => array( 'val1', 'val2' ), ), ); $request->set_body_params( $data ); From 54dd8586c938be1caf3e42fdd412e8f391c39846 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 29 Sep 2016 12:03:16 -0400 Subject: [PATCH 14/36] Factor out granting of write permission --- tests/test-rest-post-meta-fields.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/test-rest-post-meta-fields.php b/tests/test-rest-post-meta-fields.php index 5e5cdf5..e85bfc4 100644 --- a/tests/test-rest-post-meta-fields.php +++ b/tests/test-rest-post-meta-fields.php @@ -27,6 +27,14 @@ public function setUp() { $this->post_id = $this->factory->post->create(); } + protected function grant_write_permission() { + // Ensure we have write permission. + $user = $this->factory->user->create( array( + 'role' => 'editor', + )); + wp_set_current_user( $user ); + } + public function test_get_value() { add_post_meta( $this->post_id, 'test_single', 'testvalue' ); @@ -93,11 +101,7 @@ public function test_set_value() { $values = get_post_meta( $this->post_id, 'test_single', false ); $this->assertEmpty( $values ); - // Ensure we have write permission. - $user = $this->factory->user->create( array( - 'role' => 'editor', - )); - wp_set_current_user( $user ); + $this->grant_write_permission(); $data = array( 'meta' => array( @@ -148,11 +152,7 @@ public function test_set_value_multiple() { $values = get_post_meta( $this->post_id, 'test_multi', false ); $this->assertEmpty( $values ); - // Ensure we have write permission. - $user = $this->factory->user->create( array( - 'role' => 'editor', - )); - wp_set_current_user( $user ); + $this->grant_write_permission(); $data = array( 'meta' => array( From 4963518af68ceafd0cee152e608ad7d8ea33167e Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 29 Sep 2016 12:07:52 -0400 Subject: [PATCH 15/36] Add deletion test --- tests/test-rest-post-meta-fields.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/test-rest-post-meta-fields.php b/tests/test-rest-post-meta-fields.php index e85bfc4..193cf1c 100644 --- a/tests/test-rest-post-meta-fields.php +++ b/tests/test-rest-post-meta-fields.php @@ -187,4 +187,26 @@ public function test_set_value_multiple() { $this->assertContains( 'val1', $meta ); $this->assertContains( 'val2', $meta ); } + + public function test_delete_value() { + add_post_meta( $this->post_id, 'test_single', 'val1' ); + $current = get_post_meta( $this->post_id, 'test_single', true ); + $this->assertEquals( 'val1', $current ); + + $this->grant_write_permission(); + + $data = array( + 'meta' => array( + 'test_single' => null, + ), + ); + $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + $request->set_body_params( $data ); + + $response = $this->server->dispatch( $request ); + $this->assertEquals( 200, $response->get_status() ); + + $meta = get_post_meta( $this->post_id, 'test_single', false ); + $this->assertEmpty( $meta ); + } } From d378ed3f373083ca28c03b654fd716b36ff67fac Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 29 Sep 2016 12:14:22 -0400 Subject: [PATCH 16/36] Test database errors --- tests/test-rest-post-meta-fields.php | 82 ++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/tests/test-rest-post-meta-fields.php b/tests/test-rest-post-meta-fields.php index 193cf1c..08e8912 100644 --- a/tests/test-rest-post-meta-fields.php +++ b/tests/test-rest-post-meta-fields.php @@ -188,6 +188,66 @@ public function test_set_value_multiple() { $this->assertContains( 'val2', $meta ); } + public function test_add_multi_value_db_error() { + // Ensure no data exists currently. + $values = get_post_meta( $this->post_id, 'test_multi', false ); + $this->assertEmpty( $values ); + + $this->grant_write_permission(); + + $data = array( + 'meta' => array( + 'test_multi' => array( 'val1' ), + ), + ); + $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + $request->set_body_params( $data ); + + /** + * Disable showing error as the below is going to intentionally + * trigger a DB error. + */ + global $wpdb; + $wpdb->suppress_errors = true; + add_filter( 'query', array( $this, 'error_insert_query' ) ); + + $response = $this->server->dispatch( $request ); + remove_filter( 'query', array( $this, 'error_insert_query' ) ); + $wpdb->show_errors = true; + + $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); + } + + public function test_remove_multi_value_db_error() { + add_post_meta( $this->post_id, 'test_multi', 'val1' ); + $values = get_post_meta( $this->post_id, 'test_multi', false ); + $this->assertEquals( array( 'val1' ), $values ); + + $this->grant_write_permission(); + + $data = array( + 'meta' => array( + 'test_multi' => array(), + ), + ); + $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + $request->set_body_params( $data ); + + /** + * Disable showing error as the below is going to intentionally + * trigger a DB error. + */ + global $wpdb; + $wpdb->suppress_errors = true; + add_filter( 'query', array( $this, 'error_delete_query' ) ); + + $response = $this->server->dispatch( $request ); + remove_filter( 'query', array( $this, 'error_delete_query' ) ); + $wpdb->show_errors = true; + + $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); + } + public function test_delete_value() { add_post_meta( $this->post_id, 'test_single', 'val1' ); $current = get_post_meta( $this->post_id, 'test_single', true ); @@ -209,4 +269,26 @@ public function test_delete_value() { $meta = get_post_meta( $this->post_id, 'test_single', false ); $this->assertEmpty( $meta ); } + + /** + * Internal function used to disable an insert query which + * will trigger a wpdb error for testing purposes. + */ + public function error_insert_query( $query ) { + if ( strpos( $query, 'INSERT' ) === 0 ) { + $query = '],'; + } + return $query; + } + + /** + * Internal function used to disable an insert query which + * will trigger a wpdb error for testing purposes. + */ + public function error_delete_query( $query ) { + if ( strpos( $query, 'DELETE' ) === 0 ) { + $query = '],'; + } + return $query; + } } From 963dd5b5361a85331d448a4bc7d1017aafe889f2 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 29 Sep 2016 12:40:15 -0400 Subject: [PATCH 17/36] Test updating multi value without authentication --- tests/test-rest-post-meta-fields.php | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/test-rest-post-meta-fields.php b/tests/test-rest-post-meta-fields.php index 08e8912..05c42eb 100644 --- a/tests/test-rest-post-meta-fields.php +++ b/tests/test-rest-post-meta-fields.php @@ -188,6 +188,31 @@ public function test_set_value_multiple() { $this->assertContains( 'val2', $meta ); } + /** + * @depends test_set_value_multiple + */ + public function test_set_value_multiple_unauthenticated() { + // Ensure no data exists currently. + $values = get_post_meta( $this->post_id, 'test_multi', false ); + $this->assertEmpty( $values ); + + wp_set_current_user( 0 ); + + $data = array( + 'meta' => array( + 'test_multi' => array( 'val1' ), + ), + ); + $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + $request->set_body_params( $data ); + + $response = $this->server->dispatch( $request ); + $this->assertErrorResponse( 'rest_cannot_edit', $response, 401 ); + + $meta = get_post_meta( $this->post_id, 'test_multi', false ); + $this->assertEmpty( $meta ); + } + public function test_add_multi_value_db_error() { // Ensure no data exists currently. $values = get_post_meta( $this->post_id, 'test_multi', false ); From 6646ff1d3b2d6afe339e70bc349a1a60532ca644 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 29 Sep 2016 12:53:24 -0400 Subject: [PATCH 18/36] Test auth callbacks are called correctly --- tests/test-rest-post-meta-fields.php | 50 ++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tests/test-rest-post-meta-fields.php b/tests/test-rest-post-meta-fields.php index 05c42eb..ee123d8 100644 --- a/tests/test-rest-post-meta-fields.php +++ b/tests/test-rest-post-meta-fields.php @@ -23,6 +23,16 @@ public function setUp() { 'show_in_rest' => true, 'single' => false, )); + register_meta( 'post', 'test_bad_auth', array( + 'show_in_rest' => true, + 'single' => true, + 'auth_callback' => '__return_false', + )); + register_meta( 'post', 'test_bad_auth_multi', array( + 'show_in_rest' => true, + 'single' => false, + 'auth_callback' => '__return_false', + )); $this->post_id = $this->factory->post->create(); } @@ -147,6 +157,26 @@ public function test_set_value_unauthenticated() { $this->assertEmpty( get_post_meta( $this->post_id, 'test_single', false ) ); } + /** + * @depends test_set_value + */ + public function test_set_value_blocked() { + $data = array( + 'meta' => array( + 'test_bad_auth' => 'test_value', + ), + ); + + $this->grant_write_permission(); + + $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + $request->set_body_params( $data ); + + $response = $this->server->dispatch( $request ); + $this->assertErrorResponse( 'rest_cannot_update', $response, 403 ); + $this->assertEmpty( get_post_meta( $this->post_id, 'test_bad_auth', false ) ); + } + public function test_set_value_multiple() { // Ensure no data exists currently. $values = get_post_meta( $this->post_id, 'test_multi', false ); @@ -213,6 +243,26 @@ public function test_set_value_multiple_unauthenticated() { $this->assertEmpty( $meta ); } + /** + * @depends test_set_value_multiple + */ + public function test_set_value_multiple_blocked() { + $data = array( + 'meta' => array( + 'test_bad_auth_multi' => array( 'test_value' ), + ), + ); + + $this->grant_write_permission(); + + $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + $request->set_body_params( $data ); + + $response = $this->server->dispatch( $request ); + $this->assertErrorResponse( 'rest_cannot_update', $response, 403 ); + $this->assertEmpty( get_post_meta( $this->post_id, 'test_bad_auth_multi', false ) ); + } + public function test_add_multi_value_db_error() { // Ensure no data exists currently. $values = get_post_meta( $this->post_id, 'test_multi', false ); From 6e3da959ec26ef12b7aa93774b2991568858c6b1 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 29 Sep 2016 12:57:00 -0400 Subject: [PATCH 19/36] Test registered meta without API access --- tests/test-rest-post-meta-fields.php | 34 ++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/test-rest-post-meta-fields.php b/tests/test-rest-post-meta-fields.php index ee123d8..5056b21 100644 --- a/tests/test-rest-post-meta-fields.php +++ b/tests/test-rest-post-meta-fields.php @@ -33,6 +33,10 @@ public function setUp() { 'single' => false, 'auth_callback' => '__return_false', )); + register_meta( 'post', 'test_no_rest', array()); + register_meta( 'post', 'test_rest_disabled', array( + 'show_in_rest' => false, + )); $this->post_id = $this->factory->post->create(); } @@ -103,6 +107,36 @@ public function test_get_unregistered() { $this->assertArrayNotHasKey( 'test_unregistered', $meta ); } + /** + * @depends test_get_value + */ + public function test_get_registered_no_api_access() { + add_post_meta( $this->post_id, 'test_no_rest', 'for_the_wicked' ); + $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + + $response = $this->server->dispatch( $request ); + $this->assertEquals( 200, $response->get_status() ); + + $data = $response->get_data(); + $meta = (array) $data['meta']; + $this->assertArrayNotHasKey( 'test_no_rest', $meta ); + } + + /** + * @depends test_get_value + */ + public function test_get_registered_api_disabled() { + add_post_meta( $this->post_id, 'test_rest_disabled', 'sleepless_nights' ); + $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + + $response = $this->server->dispatch( $request ); + $this->assertEquals( 200, $response->get_status() ); + + $data = $response->get_data(); + $meta = (array) $data['meta']; + $this->assertArrayNotHasKey( 'test_rest_disabled', $meta ); + } + /** * @depends test_get_value */ From 58a30ad40adf0a9cf44127392f57ec72005c84c7 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 29 Sep 2016 13:03:38 -0400 Subject: [PATCH 20/36] Fix coding standards error --- tests/test-rest-post-meta-fields.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-rest-post-meta-fields.php b/tests/test-rest-post-meta-fields.php index 5056b21..f7c6a1f 100644 --- a/tests/test-rest-post-meta-fields.php +++ b/tests/test-rest-post-meta-fields.php @@ -33,7 +33,7 @@ public function setUp() { 'single' => false, 'auth_callback' => '__return_false', )); - register_meta( 'post', 'test_no_rest', array()); + register_meta( 'post', 'test_no_rest', array() ); register_meta( 'post', 'test_rest_disabled', array( 'show_in_rest' => false, )); From bc81e197b33a6e8608f64052fbae3006a007c90d Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 29 Sep 2016 13:08:54 -0400 Subject: [PATCH 21/36] Test auth callbacks are called when deleting --- tests/test-rest-post-meta-fields.php | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/test-rest-post-meta-fields.php b/tests/test-rest-post-meta-fields.php index f7c6a1f..03a602f 100644 --- a/tests/test-rest-post-meta-fields.php +++ b/tests/test-rest-post-meta-fields.php @@ -379,6 +379,31 @@ public function test_delete_value() { $this->assertEmpty( $meta ); } + /** + * @depends test_delete_value + */ + public function test_delete_value_blocked() { + add_post_meta( $this->post_id, 'test_bad_auth', 'val1' ); + $current = get_post_meta( $this->post_id, 'test_bad_auth', true ); + $this->assertEquals( 'val1', $current ); + + $this->grant_write_permission(); + + $data = array( + 'meta' => array( + 'test_bad_auth' => null, + ), + ); + $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + $request->set_body_params( $data ); + + $response = $this->server->dispatch( $request ); + $this->assertErrorResponse( 'rest_cannot_delete', $response, 403 ); + + $meta = get_post_meta( $this->post_id, 'test_bad_auth', true ); + $this->assertEquals( 'val1', $meta ); + } + /** * Internal function used to disable an insert query which * will trigger a wpdb error for testing purposes. From ad637d38df3823f7022f4008410a31537ac0bc89 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 29 Sep 2016 13:19:37 -0400 Subject: [PATCH 22/36] Test database error on deletion --- tests/test-rest-post-meta-fields.php | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/test-rest-post-meta-fields.php b/tests/test-rest-post-meta-fields.php index 03a602f..a5523b7 100644 --- a/tests/test-rest-post-meta-fields.php +++ b/tests/test-rest-post-meta-fields.php @@ -404,6 +404,38 @@ public function test_delete_value_blocked() { $this->assertEquals( 'val1', $meta ); } + /** + * @depends test_delete_value + */ + public function test_delete_value_db_error() { + add_post_meta( $this->post_id, 'test_single', 'val1' ); + $current = get_post_meta( $this->post_id, 'test_single', true ); + $this->assertEquals( 'val1', $current ); + + $this->grant_write_permission(); + + $data = array( + 'meta' => array( + 'test_single' => null, + ), + ); + $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + $request->set_body_params( $data ); + /** + * Disable showing error as the below is going to intentionally + * trigger a DB error. + */ + global $wpdb; + $wpdb->suppress_errors = true; + add_filter( 'query', array( $this, 'error_delete_query' ) ); + + $response = $this->server->dispatch( $request ); + remove_filter( 'query', array( $this, 'error_delete_query' ) ); + $wpdb->show_errors = true; + + $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); + } + /** * Internal function used to disable an insert query which * will trigger a wpdb error for testing purposes. From 7913a36c62a234dcc8e53478a522fd7269f2ad56 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 29 Sep 2016 15:21:17 -0400 Subject: [PATCH 23/36] Register meta before API init --- tests/test-rest-post-meta-fields.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test-rest-post-meta-fields.php b/tests/test-rest-post-meta-fields.php index a5523b7..11f7c30 100644 --- a/tests/test-rest-post-meta-fields.php +++ b/tests/test-rest-post-meta-fields.php @@ -10,11 +10,6 @@ class WP_Test_REST_Post_Meta_Fields extends WP_Test_REST_TestCase { public function setUp() { parent::setUp(); - /** @var WP_REST_Server $wp_rest_server */ - global $wp_rest_server; - $this->server = $wp_rest_server = new WP_Test_Spy_REST_Server; - do_action( 'rest_api_init' ); - register_meta( 'post', 'test_single', array( 'show_in_rest' => true, 'single' => true, @@ -38,6 +33,11 @@ public function setUp() { 'show_in_rest' => false, )); + /** @var WP_REST_Server $wp_rest_server */ + global $wp_rest_server; + $this->server = $wp_rest_server = new WP_Test_Spy_REST_Server; + do_action( 'rest_api_init' ); + $this->post_id = $this->factory->post->create(); } From 702af8b1768dc11b60ea8d9316612e0a296ce03c Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 29 Sep 2016 15:21:29 -0400 Subject: [PATCH 24/36] Test for DB errors in updating --- tests/test-rest-post-meta-fields.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/test-rest-post-meta-fields.php b/tests/test-rest-post-meta-fields.php index 11f7c30..6536b70 100644 --- a/tests/test-rest-post-meta-fields.php +++ b/tests/test-rest-post-meta-fields.php @@ -211,6 +211,34 @@ public function test_set_value_blocked() { $this->assertEmpty( get_post_meta( $this->post_id, 'test_bad_auth', false ) ); } + /** + * @depends test_set_value + */ + public function test_set_value_db_error() { + $data = array( + 'meta' => array( + 'test_single' => 'test_value', + ), + ); + + $this->grant_write_permission(); + + $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + $request->set_body_params( $data ); + + /** + * Disable showing error as the below is going to intentionally + * trigger a DB error. + */ + global $wpdb; + $wpdb->suppress_errors = true; + add_filter( 'query', array( $this, 'error_insert_query' ) ); + + $response = $this->server->dispatch( $request ); + remove_filter( 'query', array( $this, 'error_insert_query' ) ); + $wpdb->show_errors = true; + } + public function test_set_value_multiple() { // Ensure no data exists currently. $values = get_post_meta( $this->post_id, 'test_multi', false ); From e9a0a7f3261ca9a925338d3c8b2d5bea06cd61e1 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 29 Sep 2016 16:28:48 -0400 Subject: [PATCH 25/36] Set type to array for multi-meta schema --- lib/class-wp-rest-meta-fields.php | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/class-wp-rest-meta-fields.php b/lib/class-wp-rest-meta-fields.php index 30b9f7d..a044345 100644 --- a/lib/class-wp-rest-meta-fields.php +++ b/lib/class-wp-rest-meta-fields.php @@ -238,16 +238,27 @@ protected function get_registered_fields() { 'prepare_callback' => 'meta_rest_api_prepare_value', ); $default_schema = array( - 'type' => empty( $args['type'] ) ? null : $args['type'], + 'type' => null, 'description' => empty( $args['description'] ) ? '' : $args['description'], 'default' => isset( $args['default'] ) ? $args['default'] : null, ); $rest_args = array_merge( $default_args, $rest_args ); $rest_args['schema'] = array_merge( $default_schema, $rest_args['schema'] ); - // skip over settings that don't have a defined type in the schema if ( empty( $rest_args['schema']['type'] ) ) { - continue; + // Skip over settings that don't have a defined type + if ( empty( $args['type'] ) ) { + continue; + } + + if ( $rest_args['single'] ) { + $rest_args['schema']['type'] = $args['type']; + } else { + $rest_args['schema']['type'] = 'array'; + $rest_args['schema']['items'] = array( + 'type' => $args['type'], + ); + } } $rest_options[ $rest_args['name'] ] = $rest_args; From 8f369fea1fbadbec0b2fe2a2804cbd9ff723516d Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 29 Sep 2016 16:29:04 -0400 Subject: [PATCH 26/36] Add tests for schema --- tests/test-rest-post-meta-fields.php | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/test-rest-post-meta-fields.php b/tests/test-rest-post-meta-fields.php index 6536b70..ec0f221 100644 --- a/tests/test-rest-post-meta-fields.php +++ b/tests/test-rest-post-meta-fields.php @@ -32,6 +32,20 @@ public function setUp() { register_meta( 'post', 'test_rest_disabled', array( 'show_in_rest' => false, )); + register_meta( 'post', 'test_custom_schema', array( + 'single' => true, + 'type' => 'integer', + 'show_in_rest' => array( + 'schema' => array( + 'type' => 'number', + ), + ), + )); + register_meta( 'post', 'test_invalid_type', array( + 'single' => true, + 'type' => false, + 'show_in_rest' => true, + )); /** @var WP_REST_Server $wp_rest_server */ global $wp_rest_server; @@ -464,6 +478,32 @@ public function test_delete_value_db_error() { $this->assertErrorResponse( 'rest_meta_database_error', $response, 500 ); } + public function test_get_schema() { + $request = new WP_REST_Request( 'OPTIONS', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + $response = $this->server->dispatch( $request ); + + $data = $response->get_data(); + $schema = $data['schema']; + + $this->assertArrayHasKey( 'meta', $schema['properties'] ); + $meta_schema = $schema['properties']['meta']['properties']; + + $this->assertArrayHasKey( 'test_single', $meta_schema ); + $this->assertEquals( 'string', $meta_schema['test_single']['type'] ); + + $this->assertArrayHasKey( 'test_multi', $meta_schema ); + $this->assertEquals( 'array', $meta_schema['test_multi']['type'] ); + $this->assertArrayHasKey( 'items', $meta_schema['test_multi'] ); + $this->assertEquals( 'string', $meta_schema['test_multi']['items']['type'] ); + + $this->assertArrayHasKey( 'test_custom_schema', $meta_schema ); + $this->assertEquals( 'number', $meta_schema['test_custom_schema']['type'] ); + + $this->assertArrayNotHasKey( 'test_no_rest', $meta_schema ); + $this->assertArrayNotHasKey( 'test_rest_disabled', $meta_schema ); + $this->assertArrayNotHasKey( 'test_invalid_type', $meta_schema ); + } + /** * Internal function used to disable an insert query which * will trigger a wpdb error for testing purposes. From c787eb593b1ccea3942fd0706b116773c60a9888 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 29 Sep 2016 16:48:10 -0400 Subject: [PATCH 27/36] Add testing for type coersion --- tests/test-rest-post-meta-fields.php | 46 ++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/test-rest-post-meta-fields.php b/tests/test-rest-post-meta-fields.php index ec0f221..9de32df 100644 --- a/tests/test-rest-post-meta-fields.php +++ b/tests/test-rest-post-meta-fields.php @@ -151,6 +151,52 @@ public function test_get_registered_api_disabled() { $this->assertArrayNotHasKey( 'test_rest_disabled', $meta ); } + public function test_get_value_types() { + register_meta( 'post', 'test_string', array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'string', + )); + register_meta( 'post', 'test_number', array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'number', + )); + register_meta( 'post', 'test_bool', array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'boolean', + )); + + /** @var WP_REST_Server $wp_rest_server */ + global $wp_rest_server; + $this->server = $wp_rest_server = new WP_Test_Spy_REST_Server; + do_action( 'rest_api_init' ); + + add_post_meta( $this->post_id, 'test_string', 42 ); + add_post_meta( $this->post_id, 'test_number', '42' ); + add_post_meta( $this->post_id, 'test_bool', 1 ); + + $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + $response = $this->server->dispatch( $request ); + $this->assertEquals( 200, $response->get_status() ); + + $data = $response->get_data(); + $meta = (array) $data['meta']; + + $this->assertArrayHasKey( 'test_string', $meta ); + $this->assertInternalType( 'string', $meta['test_string'] ); + $this->assertSame( '42', $meta['test_string'] ); + + $this->assertArrayHasKey( 'test_number', $meta ); + $this->assertInternalType( 'float', $meta['test_number'] ); + $this->assertSame( 42.0, $meta['test_number'] ); + + $this->assertArrayHasKey( 'test_bool', $meta ); + $this->assertInternalType( 'boolean', $meta['test_bool'] ); + $this->assertSame( true, $meta['test_bool'] ); + } + /** * @depends test_get_value */ From 5f83bf24aaf4c0e34e2e64f6e153839cbb0ac983 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Wed, 5 Oct 2016 11:07:30 -0400 Subject: [PATCH 28/36] Remove references to options/settings --- lib/class-wp-rest-meta-fields.php | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/class-wp-rest-meta-fields.php b/lib/class-wp-rest-meta-fields.php index a044345..93aacc9 100644 --- a/lib/class-wp-rest-meta-fields.php +++ b/lib/class-wp-rest-meta-fields.php @@ -1,7 +1,7 @@ get_registered_fields(); + $fields = $this->get_registered_fields(); $response = array(); - foreach ( $options as $name => $args ) { + foreach ( $fields as $name => $args ) { $all_values = get_metadata( $this->get_meta_type(), $data['id'], $name, false ); if ( $args['single'] ) { if ( empty( $all_values ) ) { @@ -83,20 +83,20 @@ protected function prepare_value_for_response( $value, $request, $args ) { } /** - * Update settings for the settings object. + * Update meta values. * * @param WP_REST_Request $request Full detail about the request. * @return WP_Error|array */ public function update_value( $params, $data, $field_name, $request ) { - $options = $this->get_registered_fields(); + $fields = $this->get_registered_fields(); - foreach ( $options as $name => $args ) { + foreach ( $fields as $name => $args ) { if ( ! array_key_exists( $name, $params ) ) { continue; } - // a null value means reset the option, which is essentially deleting it + // A null value means reset the field, which is essentially deleting it // from the database and then relying on the default value. if ( is_null( $params[ $name ] ) ) { $result = $this->delete_meta_value( $request['id'], $name ); @@ -214,12 +214,12 @@ protected function update_meta_value( $object, $name, $value ) { } /** - * Get all the registered options for the Settings API + * Get all the registered meta fields. * * @return array */ protected function get_registered_fields() { - $rest_options = array(); + $registered = array(); foreach ( get_registered_meta_keys( $this->get_meta_type() ) as $name => $args ) { if ( empty( $args['show_in_rest'] ) ) { @@ -246,7 +246,7 @@ protected function get_registered_fields() { $rest_args['schema'] = array_merge( $default_schema, $rest_args['schema'] ); if ( empty( $rest_args['schema']['type'] ) ) { - // Skip over settings that don't have a defined type + // Skip over meta fields that don't have a defined type if ( empty( $args['type'] ) ) { continue; } @@ -261,14 +261,14 @@ protected function get_registered_fields() { } } - $rest_options[ $rest_args['name'] ] = $rest_args; + $registered[ $rest_args['name'] ] = $rest_args; } - return $rest_options; + return $registered; } /** - * Get the site setting schema, conforming to JSON Schema. + * Get the object's `meta` schema, conforming to JSON Schema. * * @return array */ From 4d523cf0119c4f35e99300e6cd6535abc859615a Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Wed, 5 Oct 2016 11:09:19 -0400 Subject: [PATCH 29/36] Correct doc block --- lib/class-wp-rest-meta-fields.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/class-wp-rest-meta-fields.php b/lib/class-wp-rest-meta-fields.php index 93aacc9..2acb0c2 100644 --- a/lib/class-wp-rest-meta-fields.php +++ b/lib/class-wp-rest-meta-fields.php @@ -86,7 +86,7 @@ protected function prepare_value_for_response( $value, $request, $args ) { * Update meta values. * * @param WP_REST_Request $request Full detail about the request. - * @return WP_Error|array + * @return WP_Error|null Error if one occurs, null on success. */ public function update_value( $params, $data, $field_name, $request ) { $fields = $this->get_registered_fields(); From 8eef1b81ff474f28049c0113872f38d2ea9bbd47 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Wed, 5 Oct 2016 11:09:26 -0400 Subject: [PATCH 30/36] Post meta -> Meta --- lib/class-wp-rest-meta-fields.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/class-wp-rest-meta-fields.php b/lib/class-wp-rest-meta-fields.php index 2acb0c2..02bfc13 100644 --- a/lib/class-wp-rest-meta-fields.php +++ b/lib/class-wp-rest-meta-fields.php @@ -276,7 +276,7 @@ public function get_field_schema() { $fields = $this->get_registered_fields(); $schema = array( - 'description' => __( 'Post meta fields.' ), + 'description' => __( 'Meta fields.' ), 'type' => 'object', 'context' => array( 'view', 'edit' ), 'properties' => array(), From f17752d77655a9b721b66b2f5d10d962a066ee79 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Wed, 5 Oct 2016 12:06:05 -0400 Subject: [PATCH 31/36] Check item type for multi-value --- plugin.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plugin.php b/plugin.php index dab8145..eca239c 100644 --- a/plugin.php +++ b/plugin.php @@ -49,7 +49,14 @@ function meta_rest_api_init() { * @return mixed Value prepared for output. */ function meta_rest_api_prepare_value( $value, $request, $args ) { - switch ( $args['schema']['type'] ) { + $type = $args['schema']['type']; + + // For multi-value fields, check the item type instead. + if ( $type === 'array' && ! empty( $args['schema']['items']['type'] ) ) { + $type = $args['schema']['items']['type']; + } + + switch ( $type ) { case 'string': $value = strval( $value ); break; From d2c4126079c0d4dd85eb2ccd9f640cb3861cd299 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 6 Oct 2016 13:50:45 -0400 Subject: [PATCH 32/36] Yoda-ify a conditional I hate this rule. --- plugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.php b/plugin.php index eca239c..8299d7e 100644 --- a/plugin.php +++ b/plugin.php @@ -52,7 +52,7 @@ function meta_rest_api_prepare_value( $value, $request, $args ) { $type = $args['schema']['type']; // For multi-value fields, check the item type instead. - if ( $type === 'array' && ! empty( $args['schema']['items']['type'] ) ) { + if ( 'array' === $type && ! empty( $args['schema']['items']['type'] ) ) { $type = $args['schema']['items']['type']; } From e6404a86fc2d20d2ea251fad18899619c5db611a Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 6 Oct 2016 16:03:43 -0400 Subject: [PATCH 33/36] Use better diffing for multi-value --- lib/class-wp-rest-meta-fields.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/class-wp-rest-meta-fields.php b/lib/class-wp-rest-meta-fields.php index 02bfc13..72b0b51 100644 --- a/lib/class-wp-rest-meta-fields.php +++ b/lib/class-wp-rest-meta-fields.php @@ -161,8 +161,18 @@ protected function update_multi_meta_value( $object, $name, $values ) { } $current = get_metadata( $this->get_meta_type(), $object, $name, false ); - $to_add = array_diff( $values, $current ); - $to_remove = array_diff( $current, $values ); + + $to_remove = $current; + $to_add = $values; + foreach ( $to_remove as &$value ) { + $index = array_search( $value, $to_add ); + if ( $index === false ) { + continue; + } + + unset( $value ); + unset( $to_add[ $index ] ); + } foreach ( $to_add as $value ) { if ( ! add_metadata( $this->get_meta_type(), $object, wp_slash( $name ), wp_slash( $value ) ) ) { From 2bfb5633eb208668ee389de87c2ff7c561af12b2 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 6 Oct 2016 16:08:56 -0400 Subject: [PATCH 34/36] Use correct variable naming --- lib/class-wp-rest-meta-fields.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/class-wp-rest-meta-fields.php b/lib/class-wp-rest-meta-fields.php index 72b0b51..388bdae 100644 --- a/lib/class-wp-rest-meta-fields.php +++ b/lib/class-wp-rest-meta-fields.php @@ -164,14 +164,14 @@ protected function update_multi_meta_value( $object, $name, $values ) { $to_remove = $current; $to_add = $values; - foreach ( $to_remove as &$value ) { - $index = array_search( $value, $to_add ); - if ( $index === false ) { + foreach ( $to_remove as $remove_key => $value ) { + $add_key = array_search( $value, $to_add ); + if ( $add_key === false ) { continue; } - unset( $value ); - unset( $to_add[ $index ] ); + unset( $to_remove[ $remove_key ] ); + unset( $to_add[ $add_key ] ); } foreach ( $to_add as $value ) { From dc98102f1605ae388f741347c147b1d971aeac1c Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 6 Oct 2016 16:26:21 -0400 Subject: [PATCH 35/36] Add failing test case for delete_metadata --- tests/test-rest-post-meta-fields.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/test-rest-post-meta-fields.php b/tests/test-rest-post-meta-fields.php index 9de32df..b4c3472 100644 --- a/tests/test-rest-post-meta-fields.php +++ b/tests/test-rest-post-meta-fields.php @@ -340,6 +340,34 @@ public function test_set_value_multiple() { $this->assertContains( 'val2', $meta ); } + /** + * Test removing only one item with duplicate items. + */ + public function test_set_value_remove_one() { + add_post_meta( $this->post_id, 'test_multi', 'c' ); + add_post_meta( $this->post_id, 'test_multi', 'n' ); + add_post_meta( $this->post_id, 'test_multi', 'n' ); + + $this->grant_write_permission(); + + $data = array( + 'meta' => array( + 'test_multi' => array( 'c', 'n' ), + ), + ); + $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + $request->set_body_params( $data ); + + $response = $this->server->dispatch( $request ); + $this->assertEquals( 200, $response->get_status() ); + + $meta = get_post_meta( $this->post_id, 'test_multi', false ); + $this->assertNotEmpty( $meta ); + $this->assertCount( 2, $meta ); + $this->assertContains( 'c', $meta ); + $this->assertContains( 'n', $meta ); + } + /** * @depends test_set_value_multiple */ From 965944da648f48926554721e9caa0fa250c75cd8 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 6 Oct 2016 17:49:11 -0400 Subject: [PATCH 36/36] Only remove metadata once for multi-value --- lib/class-wp-rest-meta-fields.php | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/class-wp-rest-meta-fields.php b/lib/class-wp-rest-meta-fields.php index 388bdae..7669c33 100644 --- a/lib/class-wp-rest-meta-fields.php +++ b/lib/class-wp-rest-meta-fields.php @@ -164,18 +164,27 @@ protected function update_multi_meta_value( $object, $name, $values ) { $to_remove = $current; $to_add = $values; - foreach ( $to_remove as $remove_key => $value ) { - $add_key = array_search( $value, $to_add ); - if ( $add_key === false ) { + foreach ( $to_add as $add_key => $value ) { + $remove_keys = array_keys( $to_remove, $value, true ); + if ( $remove_keys === false ) { continue; } + if ( count( $remove_keys ) > 1 ) { + // To remove, we need to remove first, then add, so don't touch. + continue; + } + + $remove_key = $remove_keys[0]; unset( $to_remove[ $remove_key ] ); unset( $to_add[ $add_key ] ); } - foreach ( $to_add as $value ) { - if ( ! add_metadata( $this->get_meta_type(), $object, wp_slash( $name ), wp_slash( $value ) ) ) { + // `delete_metadata` removes _all_ instances of the value, so only call + // once. + $to_remove = array_unique( $to_remove ); + foreach ( $to_remove as $value ) { + if ( ! delete_metadata( $this->get_meta_type(), $object, wp_slash( $name ), wp_slash( $value ) ) ) { return new WP_Error( 'rest_meta_database_error', __( 'Could not update meta value in database.' ), @@ -183,8 +192,8 @@ protected function update_multi_meta_value( $object, $name, $values ) { ); } } - foreach ( $to_remove as $value ) { - if ( ! delete_metadata( $this->get_meta_type(), $object, wp_slash( $name ), wp_slash( $value ) ) ) { + foreach ( $to_add as $value ) { + if ( ! add_metadata( $this->get_meta_type(), $object, wp_slash( $name ), wp_slash( $value ) ) ) { return new WP_Error( 'rest_meta_database_error', __( 'Could not update meta value in database.' ),