2019-03-12 09:27:46 +00:00
< ? php
/**
* REST API : WP_REST_Terms_Controller class
*
* @ package WordPress
* @ subpackage REST_API
* @ since 4.7 . 0
*/
/**
* Core class used to managed terms associated with a taxonomy via the REST API .
*
* @ since 4.7 . 0
*
* @ see WP_REST_Controller
*/
class WP_REST_Terms_Controller extends WP_REST_Controller {
/**
* Taxonomy key .
*
* @ since 4.7 . 0
* @ var string
*/
protected $taxonomy ;
/**
* Instance of a term meta fields object .
*
* @ since 4.7 . 0
* @ var WP_REST_Term_Meta_Fields
*/
protected $meta ;
/**
* Column to have the terms be sorted by .
*
* @ since 4.7 . 0
* @ var string
*/
protected $sort_column ;
/**
* Number of terms that were found .
*
* @ since 4.7 . 0
* @ var int
*/
protected $total_terms ;
/**
* Constructor .
*
* @ since 4.7 . 0
*
* @ param string $taxonomy Taxonomy key .
*/
public function __construct ( $taxonomy ) {
2019-04-16 19:56:22 +00:00
$this -> taxonomy = $taxonomy ;
2019-03-12 09:27:46 +00:00
$this -> namespace = 'wp/v2' ;
2019-04-16 19:56:22 +00:00
$tax_obj = get_taxonomy ( $taxonomy );
2019-03-12 09:27:46 +00:00
$this -> rest_base = ! empty ( $tax_obj -> rest_base ) ? $tax_obj -> rest_base : $tax_obj -> name ;
$this -> meta = new WP_REST_Term_Meta_Fields ( $taxonomy );
}
/**
* Registers the routes for the objects of the controller .
*
* @ since 4.7 . 0
*
* @ see register_rest_route ()
*/
public function register_routes () {
2019-04-16 19:56:22 +00:00
register_rest_route (
$this -> namespace ,
'/' . $this -> rest_base ,
2019-03-12 09:27:46 +00:00
array (
2019-04-16 19:56:22 +00:00
array (
'methods' => WP_REST_Server :: READABLE ,
'callback' => array ( $this , 'get_items' ),
'permission_callback' => array ( $this , 'get_items_permissions_check' ),
'args' => $this -> get_collection_params (),
2019-03-12 09:27:46 +00:00
),
2019-04-16 19:56:22 +00:00
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 ),
2019-03-12 09:27:46 +00:00
),
2019-04-16 19:56:22 +00:00
'schema' => array ( $this , 'get_public_item_schema' ),
)
);
register_rest_route (
$this -> namespace ,
'/' . $this -> rest_base . '/(?P<id>[\d]+)' ,
2019-03-12 09:27:46 +00:00
array (
2019-04-16 19:56:22 +00:00
'args' => array (
'id' => array (
'description' => __ ( 'Unique identifier for the term.' ),
'type' => 'integer' ,
2019-03-12 09:27:46 +00:00
),
),
2019-04-16 19:56:22 +00:00
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' ),
)
);
2019-03-12 09:27:46 +00:00
}
/**
* Checks if a request has access to read terms in the specified taxonomy .
*
* @ since 4.7 . 0
*
* @ param WP_REST_Request $request Full details about the request .
* @ return bool | WP_Error True if the request has read access , otherwise false or WP_Error object .
*/
public function get_items_permissions_check ( $request ) {
$tax_obj = get_taxonomy ( $this -> taxonomy );
if ( ! $tax_obj || ! $this -> check_is_taxonomy_allowed ( $this -> taxonomy ) ) {
return false ;
}
if ( 'edit' === $request [ 'context' ] && ! current_user_can ( $tax_obj -> cap -> edit_terms ) ) {
return new WP_Error ( 'rest_forbidden_context' , __ ( 'Sorry, you are not allowed to edit terms in this taxonomy.' ), array ( 'status' => rest_authorization_required_code () ) );
}
return true ;
}
/**
* Retrieves terms associated with a taxonomy .
*
* @ since 4.7 . 0
*
* @ param WP_REST_Request $request Full details about the request .
* @ return WP_REST_Response | WP_Error Response object on success , or WP_Error object on failure .
*/
public function get_items ( $request ) {
// Retrieve the list of registered collection query parameters.
$registered = $this -> get_collection_params ();
/*
* This array defines mappings between public API query parameters whose
* values are accepted as - passed , and their internal WP_Query parameter
* name equivalents ( some are the same ) . Only values which are also
* present in $registered will be set .
*/
$parameter_mappings = array (
'exclude' => 'exclude' ,
'include' => 'include' ,
'order' => 'order' ,
'orderby' => 'orderby' ,
'post' => 'post' ,
'hide_empty' => 'hide_empty' ,
'per_page' => 'number' ,
'search' => 'search' ,
'slug' => 'slug' ,
);
$prepared_args = array ();
/*
* For each known parameter which is both registered and present in the request ,
* set the parameter ' s value on the query $prepared_args .
*/
foreach ( $parameter_mappings as $api_param => $wp_param ) {
if ( isset ( $registered [ $api_param ], $request [ $api_param ] ) ) {
$prepared_args [ $wp_param ] = $request [ $api_param ];
}
}
if ( isset ( $prepared_args [ 'orderby' ] ) && isset ( $request [ 'orderby' ] ) ) {
$orderby_mappings = array (
'include_slugs' => 'slug__in' ,
);
if ( isset ( $orderby_mappings [ $request [ 'orderby' ] ] ) ) {
$prepared_args [ 'orderby' ] = $orderby_mappings [ $request [ 'orderby' ] ];
}
}
if ( isset ( $registered [ 'offset' ] ) && ! empty ( $request [ 'offset' ] ) ) {
$prepared_args [ 'offset' ] = $request [ 'offset' ];
} else {
$prepared_args [ 'offset' ] = ( $request [ 'page' ] - 1 ) * $prepared_args [ 'number' ];
}
$taxonomy_obj = get_taxonomy ( $this -> taxonomy );
if ( $taxonomy_obj -> hierarchical && isset ( $registered [ 'parent' ], $request [ 'parent' ] ) ) {
if ( 0 === $request [ 'parent' ] ) {
// Only query top-level terms.
$prepared_args [ 'parent' ] = 0 ;
} else {
if ( $request [ 'parent' ] ) {
$prepared_args [ 'parent' ] = $request [ 'parent' ];
}
}
}
/**
* Filters the query arguments before passing them to get_terms () .
*
* The dynamic portion of the hook name , `$this->taxonomy` , refers to the taxonomy slug .
*
* Enables adding extra arguments or setting defaults for a terms
* collection request .
*
* @ since 4.7 . 0
*
* @ link https :// developer . wordpress . org / reference / functions / get_terms /
*
* @ param array $prepared_args Array of arguments to be
* passed to get_terms () .
* @ param WP_REST_Request $request The current request .
*/
$prepared_args = apply_filters ( " rest_ { $this -> taxonomy } _query " , $prepared_args , $request );
2019-04-16 19:56:22 +00:00
if ( ! empty ( $prepared_args [ 'post' ] ) ) {
2019-03-12 09:27:46 +00:00
$query_result = wp_get_object_terms ( $prepared_args [ 'post' ], $this -> taxonomy , $prepared_args );
// Used when calling wp_count_terms() below.
$prepared_args [ 'object_ids' ] = $prepared_args [ 'post' ];
} else {
$query_result = get_terms ( $this -> taxonomy , $prepared_args );
}
$count_args = $prepared_args ;
unset ( $count_args [ 'number' ], $count_args [ 'offset' ] );
$total_terms = wp_count_terms ( $this -> taxonomy , $count_args );
// wp_count_terms can return a falsy value when the term has no children.
if ( ! $total_terms ) {
$total_terms = 0 ;
}
$response = array ();
foreach ( $query_result as $term ) {
2019-04-16 19:56:22 +00:00
$data = $this -> prepare_item_for_response ( $term , $request );
2019-03-12 09:27:46 +00:00
$response [] = $this -> prepare_response_for_collection ( $data );
}
$response = rest_ensure_response ( $response );
// Store pagination values for headers.
$per_page = ( int ) $prepared_args [ 'number' ];
$page = ceil ( ( ( ( int ) $prepared_args [ 'offset' ] ) / $per_page ) + 1 );
$response -> header ( 'X-WP-Total' , ( int ) $total_terms );
$max_pages = ceil ( $total_terms / $per_page );
$response -> header ( 'X-WP-TotalPages' , ( int ) $max_pages );
$base = add_query_arg ( $request -> get_query_params (), rest_url ( $this -> namespace . '/' . $this -> rest_base ) );
if ( $page > 1 ) {
$prev_page = $page - 1 ;
if ( $prev_page > $max_pages ) {
$prev_page = $max_pages ;
}
$prev_link = add_query_arg ( 'page' , $prev_page , $base );
$response -> link_header ( 'prev' , $prev_link );
}
if ( $max_pages > $page ) {
$next_page = $page + 1 ;
$next_link = add_query_arg ( 'page' , $next_page , $base );
$response -> link_header ( 'next' , $next_link );
}
return $response ;
}
/**
* Get the term , if the ID is valid .
*
* @ since 4.7 . 2
*
* @ param int $id Supplied ID .
* @ return WP_Term | WP_Error Term object if ID is valid , WP_Error otherwise .
*/
protected function get_term ( $id ) {
$error = new WP_Error ( 'rest_term_invalid' , __ ( 'Term does not exist.' ), array ( 'status' => 404 ) );
if ( ! $this -> check_is_taxonomy_allowed ( $this -> taxonomy ) ) {
return $error ;
}
if ( ( int ) $id <= 0 ) {
return $error ;
}
$term = get_term ( ( int ) $id , $this -> taxonomy );
if ( empty ( $term ) || $term -> taxonomy !== $this -> taxonomy ) {
return $error ;
}
return $term ;
}
/**
* Checks if a request has access to read or edit the specified term .
*
* @ since 4.7 . 0
*
* @ param WP_REST_Request $request Full details about the request .
* @ return bool | WP_Error True if the request has read access for the item , otherwise false or WP_Error object .
*/
public function get_item_permissions_check ( $request ) {
$term = $this -> get_term ( $request [ 'id' ] );
if ( is_wp_error ( $term ) ) {
return $term ;
}
if ( 'edit' === $request [ 'context' ] && ! current_user_can ( 'edit_term' , $term -> term_id ) ) {
return new WP_Error ( 'rest_forbidden_context' , __ ( 'Sorry, you are not allowed to edit this term.' ), array ( 'status' => rest_authorization_required_code () ) );
}
return true ;
}
/**
* Gets a single term from a taxonomy .
*
* @ since 4.7 . 0
*
* @ param WP_REST_Request $request Full details about the request .
* @ return WP_REST_Response | WP_Error Response object on success , or WP_Error object on failure .
*/
public function get_item ( $request ) {
$term = $this -> get_term ( $request [ 'id' ] );
if ( is_wp_error ( $term ) ) {
return $term ;
}
$response = $this -> prepare_item_for_response ( $term , $request );
return rest_ensure_response ( $response );
}
/**
* Checks if a request has access to create a term .
*
* @ since 4.7 . 0
*
* @ param WP_REST_Request $request Full details about the request .
* @ return bool | WP_Error True if the request has access to create items , false or WP_Error object otherwise .
*/
public function create_item_permissions_check ( $request ) {
if ( ! $this -> check_is_taxonomy_allowed ( $this -> taxonomy ) ) {
return false ;
}
$taxonomy_obj = get_taxonomy ( $this -> taxonomy );
if ( ( is_taxonomy_hierarchical ( $this -> taxonomy )
&& ! current_user_can ( $taxonomy_obj -> cap -> edit_terms ) )
|| ( ! is_taxonomy_hierarchical ( $this -> taxonomy )
&& ! current_user_can ( $taxonomy_obj -> cap -> assign_terms ) ) ) {
return new WP_Error ( 'rest_cannot_create' , __ ( 'Sorry, you are not allowed to create new terms.' ), array ( 'status' => rest_authorization_required_code () ) );
}
return true ;
}
/**
* Creates a single term in a taxonomy .
*
* @ since 4.7 . 0
*
* @ param WP_REST_Request $request Full details about the request .
* @ return WP_REST_Response | WP_Error Response object on success , or WP_Error object on failure .
*/
public function create_item ( $request ) {
if ( isset ( $request [ 'parent' ] ) ) {
if ( ! is_taxonomy_hierarchical ( $this -> taxonomy ) ) {
return new WP_Error ( 'rest_taxonomy_not_hierarchical' , __ ( 'Cannot set parent term, taxonomy is not hierarchical.' ), array ( 'status' => 400 ) );
}
$parent = get_term ( ( int ) $request [ 'parent' ], $this -> taxonomy );
if ( ! $parent ) {
return new WP_Error ( 'rest_term_invalid' , __ ( 'Parent term does not exist.' ), array ( 'status' => 400 ) );
}
}
$prepared_term = $this -> prepare_item_for_database ( $request );
$term = wp_insert_term ( wp_slash ( $prepared_term -> name ), $this -> taxonomy , wp_slash ( ( array ) $prepared_term ) );
if ( is_wp_error ( $term ) ) {
/*
* If we ' re going to inform the client that the term already exists ,
* give them the identifier for future use .
*/
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' );
2019-04-16 19:56:22 +00:00
$term -> add_data (
array (
'status' => 400 ,
'term_id' => $term_id ,
)
);
2019-03-12 09:27:46 +00:00
}
return $term ;
}
$term = get_term ( $term [ 'term_id' ], $this -> taxonomy );
/**
* Fires after a single term is created or updated via the REST API .
*
* The dynamic portion of the hook name , `$this->taxonomy` , refers to the taxonomy slug .
*
* @ since 4.7 . 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_insert_ { $this -> taxonomy } " , $term , $request , true );
$schema = $this -> get_item_schema ();
if ( ! empty ( $schema [ 'properties' ][ 'meta' ] ) && isset ( $request [ 'meta' ] ) ) {
$meta_update = $this -> meta -> update_value ( $request [ 'meta' ], $term -> term_id );
if ( is_wp_error ( $meta_update ) ) {
return $meta_update ;
}
}
$fields_update = $this -> update_additional_fields_for_object ( $term , $request );
if ( is_wp_error ( $fields_update ) ) {
return $fields_update ;
}
$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 );
$response -> set_status ( 201 );
$response -> header ( 'Location' , rest_url ( $this -> namespace . '/' . $this -> rest_base . '/' . $term -> term_id ) );
return $response ;
}
/**
* Checks if a request has access to update the specified term .
*
* @ since 4.7 . 0
*
* @ param WP_REST_Request $request Full details about the request .
* @ return bool | WP_Error True if the request has access to update the item , false or WP_Error object otherwise .
*/
public function update_item_permissions_check ( $request ) {
$term = $this -> get_term ( $request [ 'id' ] );
if ( is_wp_error ( $term ) ) {
return $term ;
}
if ( ! current_user_can ( 'edit_term' , $term -> term_id ) ) {
return new WP_Error ( 'rest_cannot_update' , __ ( 'Sorry, you are not allowed to edit this term.' ), array ( 'status' => rest_authorization_required_code () ) );
}
return true ;
}
/**
* Updates a single term from a taxonomy .
*
* @ since 4.7 . 0
*
* @ param WP_REST_Request $request Full details about the request .
* @ return WP_REST_Response | WP_Error Response object on success , or WP_Error object on failure .
*/
public function update_item ( $request ) {
$term = $this -> get_term ( $request [ 'id' ] );
if ( is_wp_error ( $term ) ) {
return $term ;
}
if ( isset ( $request [ 'parent' ] ) ) {
if ( ! is_taxonomy_hierarchical ( $this -> taxonomy ) ) {
return new WP_Error ( 'rest_taxonomy_not_hierarchical' , __ ( 'Cannot set parent term, taxonomy is not hierarchical.' ), array ( 'status' => 400 ) );
}
$parent = get_term ( ( int ) $request [ 'parent' ], $this -> taxonomy );
if ( ! $parent ) {
return new WP_Error ( 'rest_term_invalid' , __ ( 'Parent term does not exist.' ), array ( 'status' => 400 ) );
}
}
$prepared_term = $this -> prepare_item_for_database ( $request );
// Only update the term if we haz something to update.
if ( ! empty ( $prepared_term ) ) {
$update = wp_update_term ( $term -> term_id , $term -> taxonomy , wp_slash ( ( array ) $prepared_term ) );
if ( is_wp_error ( $update ) ) {
return $update ;
}
}
$term = get_term ( $term -> term_id , $this -> taxonomy );
/** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */
do_action ( " rest_insert_ { $this -> taxonomy } " , $term , $request , false );
$schema = $this -> get_item_schema ();
if ( ! empty ( $schema [ 'properties' ][ 'meta' ] ) && isset ( $request [ 'meta' ] ) ) {
$meta_update = $this -> meta -> update_value ( $request [ 'meta' ], $term -> term_id );
if ( is_wp_error ( $meta_update ) ) {
return $meta_update ;
}
}
$fields_update = $this -> update_additional_fields_for_object ( $term , $request );
if ( is_wp_error ( $fields_update ) ) {
return $fields_update ;
}
$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 );
}
/**
* Checks if a request has access to delete the specified term .
*
* @ since 4.7 . 0
*
* @ param WP_REST_Request $request Full details about the request .
* @ return bool | WP_Error True if the request has access to delete the item , otherwise false or WP_Error object .
*/
public function delete_item_permissions_check ( $request ) {
$term = $this -> get_term ( $request [ 'id' ] );
if ( is_wp_error ( $term ) ) {
return $term ;
}
if ( ! current_user_can ( 'delete_term' , $term -> term_id ) ) {
return new WP_Error ( 'rest_cannot_delete' , __ ( 'Sorry, you are not allowed to delete this term.' ), array ( 'status' => rest_authorization_required_code () ) );
}
return true ;
}
/**
* Deletes a single term from a taxonomy .
*
* @ since 4.7 . 0
*
* @ param WP_REST_Request $request Full details about the request .
* @ return WP_REST_Response | WP_Error Response object on success , or WP_Error object on failure .
*/
public function delete_item ( $request ) {
$term = $this -> get_term ( $request [ 'id' ] );
if ( is_wp_error ( $term ) ) {
return $term ;
}
$force = isset ( $request [ 'force' ] ) ? ( bool ) $request [ 'force' ] : false ;
// We don't support trashing for terms.
if ( ! $force ) {
/* translators: %s: force=true */
return new WP_Error ( 'rest_trash_not_supported' , sprintf ( __ ( " Terms do not support trashing. Set '%s' to delete. " ), 'force=true' ), array ( 'status' => 501 ) );
}
$request -> set_param ( 'context' , 'view' );
$previous = $this -> prepare_item_for_response ( $term , $request );
$retval = wp_delete_term ( $term -> term_id , $term -> taxonomy );
if ( ! $retval ) {
return new WP_Error ( 'rest_cannot_delete' , __ ( 'The term cannot be deleted.' ), array ( 'status' => 500 ) );
}
$response = new WP_REST_Response ();
2019-04-16 19:56:22 +00:00
$response -> set_data (
array (
'deleted' => true ,
'previous' => $previous -> get_data (),
)
);
2019-03-12 09:27:46 +00:00
/**
* Fires after a single term is deleted via the REST API .
*
* The dynamic portion of the hook name , `$this->taxonomy` , refers to the taxonomy slug .
*
* @ since 4.7 . 0
*
* @ param WP_Term $term The deleted term .
* @ param WP_REST_Response $response The response data .
* @ param WP_REST_Request $request The request sent to the API .
*/
do_action ( " rest_delete_ { $this -> taxonomy } " , $term , $response , $request );
return $response ;
}
/**
* Prepares a single term for create or update .
*
* @ since 4.7 . 0
*
* @ param WP_REST_Request $request Request object .
* @ return object $prepared_term Term object .
*/
public function prepare_item_for_database ( $request ) {
$prepared_term = new stdClass ;
$schema = $this -> get_item_schema ();
if ( isset ( $request [ 'name' ] ) && ! empty ( $schema [ 'properties' ][ 'name' ] ) ) {
$prepared_term -> name = $request [ 'name' ];
}
if ( isset ( $request [ 'slug' ] ) && ! empty ( $schema [ 'properties' ][ 'slug' ] ) ) {
$prepared_term -> slug = $request [ 'slug' ];
}
if ( isset ( $request [ 'taxonomy' ] ) && ! empty ( $schema [ 'properties' ][ 'taxonomy' ] ) ) {
$prepared_term -> taxonomy = $request [ 'taxonomy' ];
}
if ( isset ( $request [ 'description' ] ) && ! empty ( $schema [ 'properties' ][ 'description' ] ) ) {
$prepared_term -> description = $request [ 'description' ];
}
if ( isset ( $request [ 'parent' ] ) && ! empty ( $schema [ 'properties' ][ 'parent' ] ) ) {
$parent_term_id = 0 ;
$parent_term = get_term ( ( int ) $request [ 'parent' ], $this -> taxonomy );
if ( $parent_term ) {
$parent_term_id = $parent_term -> term_id ;
}
$prepared_term -> parent = $parent_term_id ;
}
/**
* Filters term data before inserting term via the REST API .
*
* The dynamic portion of the hook name , `$this->taxonomy` , refers to the taxonomy slug .
*
* @ since 4.7 . 0
*
* @ param object $prepared_term Term object .
* @ param WP_REST_Request $request Request object .
*/
return apply_filters ( " rest_pre_insert_ { $this -> taxonomy } " , $prepared_term , $request );
}
/**
* Prepares a single term output for response .
*
* @ since 4.7 . 0
*
* @ param obj $item Term object .
* @ param WP_REST_Request $request Request object .
* @ return WP_REST_Response $response Response object .
*/
public function prepare_item_for_response ( $item , $request ) {
$fields = $this -> get_fields_for_response ( $request );
$data = array ();
if ( in_array ( 'id' , $fields , true ) ) {
$data [ 'id' ] = ( int ) $item -> term_id ;
}
if ( in_array ( 'count' , $fields , true ) ) {
$data [ 'count' ] = ( int ) $item -> count ;
}
if ( in_array ( 'description' , $fields , true ) ) {
$data [ 'description' ] = $item -> description ;
}
if ( in_array ( 'link' , $fields , true ) ) {
$data [ 'link' ] = get_term_link ( $item );
}
if ( in_array ( 'name' , $fields , true ) ) {
$data [ 'name' ] = $item -> name ;
}
if ( in_array ( 'slug' , $fields , true ) ) {
$data [ 'slug' ] = $item -> slug ;
}
if ( in_array ( 'taxonomy' , $fields , true ) ) {
$data [ 'taxonomy' ] = $item -> taxonomy ;
}
if ( in_array ( 'parent' , $fields , true ) ) {
$data [ 'parent' ] = ( int ) $item -> parent ;
}
if ( in_array ( 'meta' , $fields , true ) ) {
$data [ 'meta' ] = $this -> meta -> get_value ( $item -> term_id , $request );
}
$context = ! empty ( $request [ 'context' ] ) ? $request [ 'context' ] : 'view' ;
$data = $this -> add_additional_fields_to_object ( $data , $request );
$data = $this -> filter_response_by_context ( $data , $context );
$response = rest_ensure_response ( $data );
$response -> add_links ( $this -> prepare_links ( $item ) );
/**
* Filters a term item returned from the API .
*
* The dynamic portion of the hook name , `$this->taxonomy` , refers to the taxonomy slug .
*
* Allows modification of the term data right before it is returned .
*
* @ since 4.7 . 0
*
* @ param WP_REST_Response $response The response object .
* @ param object $item The original term object .
* @ param WP_REST_Request $request Request used to generate the response .
*/
return apply_filters ( " rest_prepare_ { $this -> taxonomy } " , $response , $item , $request );
}
/**
* Prepares links for the request .
*
* @ since 4.7 . 0
*
* @ param object $term Term object .
* @ return array Links for the given term .
*/
protected function prepare_links ( $term ) {
2019-04-16 19:56:22 +00:00
$base = $this -> namespace . '/' . $this -> rest_base ;
2019-03-12 09:27:46 +00:00
$links = array (
'self' => array (
'href' => rest_url ( trailingslashit ( $base ) . $term -> term_id ),
),
'collection' => array (
'href' => rest_url ( $base ),
),
'about' => array (
'href' => rest_url ( sprintf ( 'wp/v2/taxonomies/%s' , $this -> taxonomy ) ),
),
);
if ( $term -> parent ) {
$parent_term = get_term ( ( int ) $term -> parent , $term -> taxonomy );
if ( $parent_term ) {
$links [ 'up' ] = array (
'href' => rest_url ( trailingslashit ( $base ) . $parent_term -> term_id ),
'embeddable' => true ,
);
}
}
$taxonomy_obj = get_taxonomy ( $term -> taxonomy );
if ( empty ( $taxonomy_obj -> object_type ) ) {
return $links ;
}
$post_type_links = array ();
foreach ( $taxonomy_obj -> object_type as $type ) {
$post_type_object = get_post_type_object ( $type );
if ( empty ( $post_type_object -> show_in_rest ) ) {
continue ;
}
2019-04-16 19:56:22 +00:00
$rest_base = ! empty ( $post_type_object -> rest_base ) ? $post_type_object -> rest_base : $post_type_object -> name ;
2019-03-12 09:27:46 +00:00
$post_type_links [] = array (
'href' => add_query_arg ( $this -> rest_base , $term -> term_id , rest_url ( sprintf ( 'wp/v2/%s' , $rest_base ) ) ),
);
}
if ( ! empty ( $post_type_links ) ) {
$links [ 'https://api.w.org/post_type' ] = $post_type_links ;
}
return $links ;
}
/**
* Retrieves the term ' s schema , conforming to JSON Schema .
*
* @ since 4.7 . 0
*
* @ return array Item schema data .
*/
public function get_item_schema () {
$schema = array (
'$schema' => 'http://json-schema.org/draft-04/schema#' ,
'title' => 'post_tag' === $this -> taxonomy ? 'tag' : $this -> taxonomy ,
'type' => 'object' ,
'properties' => array (
'id' => array (
2019-04-16 19:56:22 +00:00
'description' => __ ( 'Unique identifier for the term.' ),
'type' => 'integer' ,
'context' => array ( 'view' , 'embed' , 'edit' ),
'readonly' => true ,
2019-03-12 09:27:46 +00:00
),
'count' => array (
2019-04-16 19:56:22 +00:00
'description' => __ ( 'Number of published posts for the term.' ),
'type' => 'integer' ,
'context' => array ( 'view' , 'edit' ),
'readonly' => true ,
2019-03-12 09:27:46 +00:00
),
'description' => array (
2019-04-16 19:56:22 +00:00
'description' => __ ( 'HTML description of the term.' ),
'type' => 'string' ,
'context' => array ( 'view' , 'edit' ),
2019-03-12 09:27:46 +00:00
),
'link' => array (
2019-04-16 19:56:22 +00:00
'description' => __ ( 'URL of the term.' ),
'type' => 'string' ,
'format' => 'uri' ,
'context' => array ( 'view' , 'embed' , 'edit' ),
'readonly' => true ,
2019-03-12 09:27:46 +00:00
),
'name' => array (
2019-04-16 19:56:22 +00:00
'description' => __ ( 'HTML title for the term.' ),
'type' => 'string' ,
'context' => array ( 'view' , 'embed' , 'edit' ),
'arg_options' => array (
2019-03-12 09:27:46 +00:00
'sanitize_callback' => 'sanitize_text_field' ,
),
2019-04-16 19:56:22 +00:00
'required' => true ,
2019-03-12 09:27:46 +00:00
),
'slug' => array (
2019-04-16 19:56:22 +00:00
'description' => __ ( 'An alphanumeric identifier for the term unique to its type.' ),
'type' => 'string' ,
'context' => array ( 'view' , 'embed' , 'edit' ),
'arg_options' => array (
2019-03-12 09:27:46 +00:00
'sanitize_callback' => array ( $this , 'sanitize_slug' ),
),
),
'taxonomy' => array (
2019-04-16 19:56:22 +00:00
'description' => __ ( 'Type attribution for the term.' ),
'type' => 'string' ,
'enum' => array_keys ( get_taxonomies () ),
'context' => array ( 'view' , 'embed' , 'edit' ),
'readonly' => true ,
2019-03-12 09:27:46 +00:00
),
),
);
$taxonomy = get_taxonomy ( $this -> taxonomy );
if ( $taxonomy -> hierarchical ) {
$schema [ 'properties' ][ 'parent' ] = array (
2019-04-16 19:56:22 +00:00
'description' => __ ( 'The parent term ID.' ),
'type' => 'integer' ,
'context' => array ( 'view' , 'edit' ),
2019-03-12 09:27:46 +00:00
);
}
$schema [ 'properties' ][ 'meta' ] = $this -> meta -> get_field_schema ();
return $this -> add_additional_fields_schema ( $schema );
}
/**
* Retrieves the query params for collections .
*
* @ since 4.7 . 0
*
* @ return array Collection parameters .
*/
public function get_collection_params () {
$query_params = parent :: get_collection_params ();
2019-04-16 19:56:22 +00:00
$taxonomy = get_taxonomy ( $this -> taxonomy );
2019-03-12 09:27:46 +00:00
$query_params [ 'context' ][ 'default' ] = 'view' ;
$query_params [ 'exclude' ] = array (
2019-04-16 19:56:22 +00:00
'description' => __ ( 'Ensure result set excludes specific IDs.' ),
'type' => 'array' ,
'items' => array (
'type' => 'integer' ,
2019-03-12 09:27:46 +00:00
),
2019-04-16 19:56:22 +00:00
'default' => array (),
2019-03-12 09:27:46 +00:00
);
$query_params [ 'include' ] = array (
2019-04-16 19:56:22 +00:00
'description' => __ ( 'Limit result set to specific IDs.' ),
'type' => 'array' ,
'items' => array (
'type' => 'integer' ,
2019-03-12 09:27:46 +00:00
),
2019-04-16 19:56:22 +00:00
'default' => array (),
2019-03-12 09:27:46 +00:00
);
if ( ! $taxonomy -> hierarchical ) {
$query_params [ 'offset' ] = array (
2019-04-16 19:56:22 +00:00
'description' => __ ( 'Offset the result set by a specific number of items.' ),
'type' => 'integer' ,
2019-03-12 09:27:46 +00:00
);
}
$query_params [ 'order' ] = array (
2019-04-16 19:56:22 +00:00
'description' => __ ( 'Order sort attribute ascending or descending.' ),
'type' => 'string' ,
'default' => 'asc' ,
'enum' => array (
2019-03-12 09:27:46 +00:00
'asc' ,
'desc' ,
),
);
$query_params [ 'orderby' ] = array (
2019-04-16 19:56:22 +00:00
'description' => __ ( 'Sort collection by term attribute.' ),
'type' => 'string' ,
'default' => 'name' ,
'enum' => array (
2019-03-12 09:27:46 +00:00
'id' ,
'include' ,
'name' ,
'slug' ,
'include_slugs' ,
'term_group' ,
'description' ,
'count' ,
),
);
$query_params [ 'hide_empty' ] = array (
2019-04-16 19:56:22 +00:00
'description' => __ ( 'Whether to hide terms not assigned to any posts.' ),
'type' => 'boolean' ,
'default' => false ,
2019-03-12 09:27:46 +00:00
);
if ( $taxonomy -> hierarchical ) {
$query_params [ 'parent' ] = array (
2019-04-16 19:56:22 +00:00
'description' => __ ( 'Limit result set to terms assigned to a specific parent.' ),
'type' => 'integer' ,
2019-03-12 09:27:46 +00:00
);
}
$query_params [ 'post' ] = array (
2019-04-16 19:56:22 +00:00
'description' => __ ( 'Limit result set to terms assigned to a specific post.' ),
'type' => 'integer' ,
'default' => null ,
2019-03-12 09:27:46 +00:00
);
$query_params [ 'slug' ] = array (
2019-04-16 19:56:22 +00:00
'description' => __ ( 'Limit result set to terms with one or more specific slugs.' ),
'type' => 'array' ,
'items' => array (
'type' => 'string' ,
2019-03-12 09:27:46 +00:00
),
);
/**
* Filter collection parameters for the terms controller .
*
* The dynamic part of the filter `$this->taxonomy` refers to the taxonomy
* slug for the controller .
*
* This filter registers the collection parameter , but does not map the
* collection parameter to an internal WP_Term_Query parameter . Use the
* `rest_{$this->taxonomy}_query` filter to set WP_Term_Query parameters .
*
* @ since 4.7 . 0
*
* @ param array $query_params JSON Schema - formatted collection parameters .
* @ param WP_Taxonomy $taxonomy Taxonomy object .
*/
return apply_filters ( " rest_ { $this -> taxonomy } _collection_params " , $query_params , $taxonomy );
}
/**
* Checks that the taxonomy is valid .
*
* @ since 4.7 . 0
*
* @ param string $taxonomy Taxonomy to check .
* @ return bool Whether the taxonomy is allowed for REST management .
*/
protected function check_is_taxonomy_allowed ( $taxonomy ) {
$taxonomy_obj = get_taxonomy ( $taxonomy );
if ( $taxonomy_obj && ! empty ( $taxonomy_obj -> show_in_rest ) ) {
return true ;
}
return false ;
}
}