wp/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php
changeset 9 177826044cd9
parent 7 cf61fcea0001
child 16 a86126ab1dd4
--- a/wp/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php	Mon Oct 14 18:06:33 2019 +0200
+++ b/wp/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php	Mon Oct 14 18:28:13 2019 +0200
@@ -56,9 +56,9 @@
 	 * @param string $taxonomy Taxonomy key.
 	 */
 	public function __construct( $taxonomy ) {
-		$this->taxonomy = $taxonomy;
+		$this->taxonomy  = $taxonomy;
 		$this->namespace = 'wp/v2';
-		$tax_obj = get_taxonomy( $taxonomy );
+		$tax_obj         = get_taxonomy( $taxonomy );
 		$this->rest_base = ! empty( $tax_obj->rest_base ) ? $tax_obj->rest_base : $tax_obj->name;
 
 		$this->meta = new WP_REST_Term_Meta_Fields( $taxonomy );
@@ -73,57 +73,65 @@
 	 */
 	public function register_routes() {
 
-		register_rest_route( $this->namespace, '/' . $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(),
-			),
+		register_rest_route(
+			$this->namespace,
+			'/' . $this->rest_base,
 			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->rest_base . '/(?P<id>[\d]+)', array(
-			'args' => array(
-				'id' => array(
-					'description' => __( 'Unique identifier for the term.' ),
-					'type'        => 'integer',
+				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::READABLE,
-				'callback'            => array( $this, 'get_item' ),
-				'permission_callback' => array( $this, 'get_item_permissions_check' ),
-				'args'                => array(
-					'context' => $this->get_context_param( array( 'default' => 'view' ) ),
+				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->rest_base . '/(?P<id>[\d]+)',
 			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( WP_REST_Server::EDITABLE ),
-			),
-			array(
-				'methods'             => WP_REST_Server::DELETABLE,
-				'callback'            => array( $this, 'delete_item' ),
-				'permission_callback' => array( $this, 'delete_item_permissions_check' ),
-				'args'                => array(
-					'force' => array(
-						'type'        => 'boolean',
-						'default'     => false,
-						'description' => __( 'Required to be true, as terms do not support trashing.' ),
+				'args'   => array(
+					'id' => array(
+						'description' => __( 'Unique identifier for the term.' ),
+						'type'        => 'integer',
 					),
 				),
-			),
-			'schema' => array( $this, 'get_public_item_schema' ),
-		) );
+				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' => 'view' ) ),
+					),
+				),
+				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( WP_REST_Server::EDITABLE ),
+				),
+				array(
+					'methods'             => WP_REST_Server::DELETABLE,
+					'callback'            => array( $this, 'delete_item' ),
+					'permission_callback' => array( $this, 'delete_item_permissions_check' ),
+					'args'                => array(
+						'force' => array(
+							'type'        => 'boolean',
+							'default'     => false,
+							'description' => __( 'Required to be true, as terms do not support trashing.' ),
+						),
+					),
+				),
+				'schema' => array( $this, 'get_public_item_schema' ),
+			)
+		);
 	}
 
 	/**
@@ -235,7 +243,7 @@
 		 */
 		$prepared_args = apply_filters( "rest_{$this->taxonomy}_query", $prepared_args, $request );
 
-		if ( ! empty( $prepared_args['post'] )  ) {
+		if ( ! empty( $prepared_args['post'] ) ) {
 			$query_result = wp_get_object_terms( $prepared_args['post'], $this->taxonomy, $prepared_args );
 
 			// Used when calling wp_count_terms() below.
@@ -258,7 +266,7 @@
 		$response = array();
 
 		foreach ( $query_result as $term ) {
-			$data = $this->prepare_item_for_response( $term, $request );
+			$data       = $this->prepare_item_for_response( $term, $request );
 			$response[] = $this->prepare_response_for_collection( $data );
 		}
 
@@ -274,7 +282,7 @@
 
 		$response->header( 'X-WP-TotalPages', (int) $max_pages );
 
-		$base = add_query_arg( $request->get_query_params(), rest_url( $this->namespace . '/' . $this->rest_base ) );
+		$base = add_query_arg( urlencode_deep( $request->get_query_params() ), rest_url( $this->namespace . '/' . $this->rest_base ) );
 		if ( $page > 1 ) {
 			$prev_page = $page - 1;
 
@@ -418,7 +426,12 @@
 			if ( $term_id = $term->get_error_data( 'term_exists' ) ) {
 				$existing_term = get_term( $term_id, $this->taxonomy );
 				$term->add_data( $existing_term->term_id, 'term_exists' );
-				$term->add_data( array( 'status' => 409, 'term_id' => $term_id ) );
+				$term->add_data(
+					array(
+						'status'  => 400,
+						'term_id' => $term_id,
+					)
+				);
 			}
 
 			return $term;
@@ -441,7 +454,7 @@
 
 		$schema = $this->get_item_schema();
 		if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) {
-			$meta_update = $this->meta->update_value( $request['meta'], (int) $request['id'] );
+			$meta_update = $this->meta->update_value( $request['meta'], $term->term_id );
 
 			if ( is_wp_error( $meta_update ) ) {
 				return $meta_update;
@@ -456,6 +469,19 @@
 
 		$request->set_param( 'context', 'view' );
 
+		/**
+		 * Fires after a single term is completely created or updated via the REST API.
+		 *
+		 * The dynamic portion of the hook name, `$this->taxonomy`, refers to the taxonomy slug.
+		 *
+		 * @since 5.0.0
+		 *
+		 * @param WP_Term         $term     Inserted or updated term object.
+		 * @param WP_REST_Request $request  Request object.
+		 * @param bool            $creating True when creating a term, false when updating.
+		 */
+		do_action( "rest_after_insert_{$this->taxonomy}", $term, $request, true );
+
 		$response = $this->prepare_item_for_response( $term, $request );
 		$response = rest_ensure_response( $response );
 
@@ -545,6 +571,9 @@
 
 		$request->set_param( 'context', 'view' );
 
+		/** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */
+		do_action( "rest_after_insert_{$this->taxonomy}", $term, $request, false );
+
 		$response = $this->prepare_item_for_response( $term, $request );
 
 		return rest_ensure_response( $response );
@@ -604,7 +633,12 @@
 		}
 
 		$response = new WP_REST_Response();
-		$response->set_data( array( 'deleted' => true, 'previous' => $previous->get_data() ) );
+		$response->set_data(
+			array(
+				'deleted'  => true,
+				'previous' => $previous->get_data(),
+			)
+		);
 
 		/**
 		 * Fires after a single term is deleted via the REST API.
@@ -651,11 +685,15 @@
 		}
 
 		if ( isset( $request['parent'] ) && ! empty( $schema['properties']['parent'] ) ) {
-			$parent_term_id = 0;
-			$parent_term    = get_term( (int) $request['parent'], $this->taxonomy );
+			$parent_term_id   = 0;
+			$requested_parent = (int) $request['parent'];
 
-			if ( $parent_term ) {
-				$parent_term_id = $parent_term->term_id;
+			if ( $requested_parent ) {
+				$parent_term = get_term( $requested_parent, $this->taxonomy );
+
+				if ( $parent_term instanceof WP_Term ) {
+					$parent_term_id = $parent_term->term_id;
+				}
 			}
 
 			$prepared_term->parent = $parent_term_id;
@@ -757,7 +795,7 @@
 	 * @return array Links for the given term.
 	 */
 	protected function prepare_links( $term ) {
-		$base = $this->namespace . '/' . $this->rest_base;
+		$base  = $this->namespace . '/' . $this->rest_base;
 		$links = array(
 			'self'       => array(
 				'href' => rest_url( trailingslashit( $base ) . $term->term_id ),
@@ -796,7 +834,7 @@
 				continue;
 			}
 
-			$rest_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name;
+			$rest_base         = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name;
 			$post_type_links[] = array(
 				'href' => add_query_arg( $this->rest_base, $term->term_id, rest_url( sprintf( 'wp/v2/%s', $rest_base ) ) ),
 			);
@@ -823,52 +861,52 @@
 			'type'       => 'object',
 			'properties' => array(
 				'id'          => array(
-					'description'  => __( 'Unique identifier for the term.' ),
-					'type'         => 'integer',
-					'context'      => array( 'view', 'embed', 'edit' ),
-					'readonly'     => true,
+					'description' => __( 'Unique identifier for the term.' ),
+					'type'        => 'integer',
+					'context'     => array( 'view', 'embed', 'edit' ),
+					'readonly'    => true,
 				),
 				'count'       => array(
-					'description'  => __( 'Number of published posts for the term.' ),
-					'type'         => 'integer',
-					'context'      => array( 'view', 'edit' ),
-					'readonly'     => true,
+					'description' => __( 'Number of published posts for the term.' ),
+					'type'        => 'integer',
+					'context'     => array( 'view', 'edit' ),
+					'readonly'    => true,
 				),
 				'description' => array(
-					'description'  => __( 'HTML description of the term.' ),
-					'type'         => 'string',
-					'context'      => array( 'view', 'edit' ),
+					'description' => __( 'HTML description of the term.' ),
+					'type'        => 'string',
+					'context'     => array( 'view', 'edit' ),
 				),
 				'link'        => array(
-					'description'  => __( 'URL of the term.' ),
-					'type'         => 'string',
-					'format'       => 'uri',
-					'context'      => array( 'view', 'embed', 'edit' ),
-					'readonly'     => true,
+					'description' => __( 'URL of the term.' ),
+					'type'        => 'string',
+					'format'      => 'uri',
+					'context'     => array( 'view', 'embed', 'edit' ),
+					'readonly'    => true,
 				),
 				'name'        => array(
-					'description'  => __( 'HTML title for the term.' ),
-					'type'         => 'string',
-					'context'      => array( 'view', 'embed', 'edit' ),
-					'arg_options'  => array(
+					'description' => __( 'HTML title for the term.' ),
+					'type'        => 'string',
+					'context'     => array( 'view', 'embed', 'edit' ),
+					'arg_options' => array(
 						'sanitize_callback' => 'sanitize_text_field',
 					),
-					'required'     => true,
+					'required'    => true,
 				),
 				'slug'        => array(
-					'description'  => __( 'An alphanumeric identifier for the term unique to its type.' ),
-					'type'         => 'string',
-					'context'      => array( 'view', 'embed', 'edit' ),
-					'arg_options'  => array(
+					'description' => __( 'An alphanumeric identifier for the term unique to its type.' ),
+					'type'        => 'string',
+					'context'     => array( 'view', 'embed', 'edit' ),
+					'arg_options' => array(
 						'sanitize_callback' => array( $this, 'sanitize_slug' ),
 					),
 				),
 				'taxonomy'    => array(
-					'description'  => __( 'Type attribution for the term.' ),
-					'type'         => 'string',
-					'enum'         => array_keys( get_taxonomies() ),
-					'context'      => array( 'view', 'embed', 'edit' ),
-					'readonly'     => true,
+					'description' => __( 'Type attribution for the term.' ),
+					'type'        => 'string',
+					'enum'        => array_keys( get_taxonomies() ),
+					'context'     => array( 'view', 'embed', 'edit' ),
+					'readonly'    => true,
 				),
 			),
 		);
@@ -877,9 +915,9 @@
 
 		if ( $taxonomy->hierarchical ) {
 			$schema['properties']['parent'] = array(
-				'description'  => __( 'The parent term ID.' ),
-				'type'         => 'integer',
-				'context'      => array( 'view', 'edit' ),
+				'description' => __( 'The parent term ID.' ),
+				'type'        => 'integer',
+				'context'     => array( 'view', 'edit' ),
 			);
 		}
 
@@ -897,50 +935,50 @@
 	 */
 	public function get_collection_params() {
 		$query_params = parent::get_collection_params();
-		$taxonomy = get_taxonomy( $this->taxonomy );
+		$taxonomy     = get_taxonomy( $this->taxonomy );
 
 		$query_params['context']['default'] = 'view';
 
 		$query_params['exclude'] = array(
-			'description'       => __( 'Ensure result set excludes specific IDs.' ),
-			'type'              => 'array',
-			'items'             => array(
-				'type'          => 'integer',
+			'description' => __( 'Ensure result set excludes specific IDs.' ),
+			'type'        => 'array',
+			'items'       => array(
+				'type' => 'integer',
 			),
-			'default'           => array(),
+			'default'     => array(),
 		);
 
 		$query_params['include'] = array(
-			'description'       => __( 'Limit result set to specific IDs.' ),
-			'type'              => 'array',
-			'items'             => array(
-				'type'          => 'integer',
+			'description' => __( 'Limit result set to specific IDs.' ),
+			'type'        => 'array',
+			'items'       => array(
+				'type' => 'integer',
 			),
-			'default'           => array(),
+			'default'     => array(),
 		);
 
 		if ( ! $taxonomy->hierarchical ) {
 			$query_params['offset'] = array(
-				'description'       => __( 'Offset the result set by a specific number of items.' ),
-				'type'              => 'integer',
+				'description' => __( 'Offset the result set by a specific number of items.' ),
+				'type'        => 'integer',
 			);
 		}
 
 		$query_params['order'] = array(
-			'description'       => __( 'Order sort attribute ascending or descending.' ),
-			'type'              => 'string',
-			'default'           => 'asc',
-			'enum'              => array(
+			'description' => __( 'Order sort attribute ascending or descending.' ),
+			'type'        => 'string',
+			'default'     => 'asc',
+			'enum'        => array(
 				'asc',
 				'desc',
 			),
 		);
 
 		$query_params['orderby'] = array(
-			'description'       => __( 'Sort collection by term attribute.' ),
-			'type'              => 'string',
-			'default'           => 'name',
-			'enum'              => array(
+			'description' => __( 'Sort collection by term attribute.' ),
+			'type'        => 'string',
+			'default'     => 'name',
+			'enum'        => array(
 				'id',
 				'include',
 				'name',
@@ -953,29 +991,29 @@
 		);
 
 		$query_params['hide_empty'] = array(
-			'description'       => __( 'Whether to hide terms not assigned to any posts.' ),
-			'type'              => 'boolean',
-			'default'           => false,
+			'description' => __( 'Whether to hide terms not assigned to any posts.' ),
+			'type'        => 'boolean',
+			'default'     => false,
 		);
 
 		if ( $taxonomy->hierarchical ) {
 			$query_params['parent'] = array(
-				'description'       => __( 'Limit result set to terms assigned to a specific parent.' ),
-				'type'              => 'integer',
+				'description' => __( 'Limit result set to terms assigned to a specific parent.' ),
+				'type'        => 'integer',
 			);
 		}
 
 		$query_params['post'] = array(
-			'description'       => __( 'Limit result set to terms assigned to a specific post.' ),
-			'type'              => 'integer',
-			'default'           => null,
+			'description' => __( 'Limit result set to terms assigned to a specific post.' ),
+			'type'        => 'integer',
+			'default'     => null,
 		);
 
 		$query_params['slug'] = array(
-			'description'       => __( 'Limit result set to terms with one or more specific slugs.' ),
-			'type'              => 'array',
-			'items'             => array(
-				'type'          => 'string'
+			'description' => __( 'Limit result set to terms with one or more specific slugs.' ),
+			'type'        => 'array',
+			'items'       => array(
+				'type' => 'string',
 			),
 		);