prepare_item_for_response()   F
last analyzed

Complexity

Conditions 11
Paths 1024

Size

Total Lines 64
Code Lines 27

Duplication

Lines 3
Ratio 4.69 %

Importance

Changes 0
Metric Value
cc 11
eloc 27
nc 1024
nop 2
dl 3
loc 64
rs 3.913
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * REST API: WP_REST_Terms_Controller class
4
 *
5
 * @package WordPress
6
 * @subpackage REST_API
7
 * @since 4.7.0
8
 */
9
10
/**
11
 * Core class used to managed terms associated with a taxonomy via the REST API.
12
 *
13
 * @since 4.7.0
14
 *
15
 * @see WP_REST_Controller
16
 */
17
class WP_REST_Terms_Controller extends WP_REST_Controller {
18
19
	/**
20
	 * Taxonomy key.
21
	 *
22
	 * @since 4.7.0
23
	 * @access protected
24
	 * @var string
25
	 */
26
	protected $taxonomy;
27
28
	/**
29
	 * Instance of a term meta fields object.
30
	 *
31
	 * @since 4.7.0
32
	 * @access protected
33
	 * @var WP_REST_Term_Meta_Fields
34
	 */
35
	protected $meta;
36
37
	/**
38
	 * Column to have the terms be sorted by.
39
	 *
40
	 * @since 4.7.0
41
	 * @access protected
42
	 * @var string
43
	 */
44
	protected $sort_column;
45
46
	/**
47
	 * Number of terms that were found.
48
	 *
49
	 * @since 4.7.0
50
	 * @access protected
51
	 * @var int
52
	 */
53
	protected $total_terms;
54
55
	/**
56
	 * Constructor.
57
	 *
58
	 * @since 4.7.0
59
	 * @access public
60
	 *
61
	 * @param string $taxonomy Taxonomy key.
62
	 */
63 View Code Duplication
	public function __construct( $taxonomy ) {
64
		$this->taxonomy = $taxonomy;
65
		$this->namespace = 'wp/v2';
66
		$tax_obj = get_taxonomy( $taxonomy );
67
		$this->rest_base = ! empty( $tax_obj->rest_base ) ? $tax_obj->rest_base : $tax_obj->name;
68
69
		$this->meta = new WP_REST_Term_Meta_Fields( $taxonomy );
70
	}
71
72
	/**
73
	 * Registers the routes for the objects of the controller.
74
	 *
75
	 * @since 4.7.0
76
	 * @access public
77
	 *
78
	 * @see register_rest_route()
79
	 */
80
	public function register_routes() {
81
82
		register_rest_route( $this->namespace, '/' . $this->rest_base, array(
83
			array(
84
				'methods'             => WP_REST_Server::READABLE,
85
				'callback'            => array( $this, 'get_items' ),
86
				'permission_callback' => array( $this, 'get_items_permissions_check' ),
87
				'args'                => $this->get_collection_params(),
88
			),
89
			array(
90
				'methods'             => WP_REST_Server::CREATABLE,
91
				'callback'            => array( $this, 'create_item' ),
92
				'permission_callback' => array( $this, 'create_item_permissions_check' ),
93
				'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
94
			),
95
			'schema' => array( $this, 'get_public_item_schema' ),
96
		) );
97
98
		register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array(
99
			'args' => array(
100
				'id' => array(
101
					'description' => __( 'Unique identifier for the term.' ),
102
					'type'        => 'integer',
103
				),
104
			),
105
			array(
106
				'methods'             => WP_REST_Server::READABLE,
107
				'callback'            => array( $this, 'get_item' ),
108
				'permission_callback' => array( $this, 'get_item_permissions_check' ),
109
				'args'                => array(
110
					'context' => $this->get_context_param( array( 'default' => 'view' ) ),
111
				),
112
			),
113
			array(
114
				'methods'             => WP_REST_Server::EDITABLE,
115
				'callback'            => array( $this, 'update_item' ),
116
				'permission_callback' => array( $this, 'update_item_permissions_check' ),
117
				'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
118
			),
119
			array(
120
				'methods'             => WP_REST_Server::DELETABLE,
121
				'callback'            => array( $this, 'delete_item' ),
122
				'permission_callback' => array( $this, 'delete_item_permissions_check' ),
123
				'args'                => array(
124
					'force' => array(
125
						'type'        => 'boolean',
126
						'default'     => false,
127
						'description' => __( 'Required to be true, as terms do not support trashing.' ),
128
					),
129
				),
130
			),
131
			'schema' => array( $this, 'get_public_item_schema' ),
132
		) );
133
	}
134
135
	/**
136
	 * Checks if a request has access to read terms in the specified taxonomy.
137
	 *
138
	 * @since 4.7.0
139
	 * @access public
140
	 *
141
	 * @param WP_REST_Request $request Full details about the request.
142
	 * @return bool|WP_Error True if the request has read access, otherwise false or WP_Error object.
143
	 */
144
	public function get_items_permissions_check( $request ) {
145
		$tax_obj = get_taxonomy( $this->taxonomy );
146
		if ( ! $tax_obj || ! $this->check_is_taxonomy_allowed( $this->taxonomy ) ) {
147
			return false;
148
		}
149
		if ( 'edit' === $request['context'] && ! current_user_can( $tax_obj->cap->edit_terms ) ) {
150
			return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit terms in this taxonomy.' ), array( 'status' => rest_authorization_required_code() ) );
151
		}
152
		return true;
153
	}
154
155
	/**
156
	 * Retrieves terms associated with a taxonomy.
157
	 *
158
	 * @since 4.7.0
159
	 * @access public
160
	 *
161
	 * @param WP_REST_Request $request Full details about the request.
162
	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
163
	 */
164
	public function get_items( $request ) {
165
166
		// Retrieve the list of registered collection query parameters.
167
		$registered = $this->get_collection_params();
168
169
		/*
170
		 * This array defines mappings between public API query parameters whose
171
		 * values are accepted as-passed, and their internal WP_Query parameter
172
		 * name equivalents (some are the same). Only values which are also
173
		 * present in $registered will be set.
174
		 */
175
		$parameter_mappings = array(
176
			'exclude'    => 'exclude',
177
			'include'    => 'include',
178
			'order'      => 'order',
179
			'orderby'    => 'orderby',
180
			'post'       => 'post',
181
			'hide_empty' => 'hide_empty',
182
			'per_page'   => 'number',
183
			'search'     => 'search',
184
			'slug'       => 'slug',
185
		);
186
187
		$prepared_args = array();
188
189
		/*
190
		 * For each known parameter which is both registered and present in the request,
191
		 * set the parameter's value on the query $prepared_args.
192
		 */
193 View Code Duplication
		foreach ( $parameter_mappings as $api_param => $wp_param ) {
194
			if ( isset( $registered[ $api_param ], $request[ $api_param ] ) ) {
195
				$prepared_args[ $wp_param ] = $request[ $api_param ];
196
			}
197
		}
198
199 View Code Duplication
		if ( isset( $registered['offset'] ) && ! empty( $request['offset'] ) ) {
200
			$prepared_args['offset'] = $request['offset'];
201
		} else {
202
			$prepared_args['offset'] = ( $request['page'] - 1 ) * $prepared_args['number'];
203
		}
204
205
		$taxonomy_obj = get_taxonomy( $this->taxonomy );
206
207
		if ( $taxonomy_obj->hierarchical && isset( $registered['parent'], $request['parent'] ) ) {
208
			if ( 0 === $request['parent'] ) {
209
				// Only query top-level terms.
210
				$prepared_args['parent'] = 0;
211
			} else {
212
				if ( $request['parent'] ) {
213
					$prepared_args['parent'] = $request['parent'];
214
				}
215
			}
216
		}
217
218
		/**
219
		 * Filters the query arguments before passing them to get_terms().
220
		 *
221
		 * The dynamic portion of the hook name, `$this->taxonomy`, refers to the taxonomy slug.
222
		 *
223
		 * Enables adding extra arguments or setting defaults for a terms
224
		 * collection request.
225
		 *
226
		 * @since 4.7.0
227
		 *
228
		 * @link https://developer.wordpress.org/reference/functions/get_terms/
229
		 *
230
		 * @param array           $prepared_args Array of arguments to be
231
		 *                                       passed to get_terms().
232
		 * @param WP_REST_Request $request       The current request.
233
		 */
234
		$prepared_args = apply_filters( "rest_{$this->taxonomy}_query", $prepared_args, $request );
235
236
		if ( ! empty( $prepared_args['post'] )  ) {
237
			$query_result = wp_get_object_terms( $prepared_args['post'], $this->taxonomy, $prepared_args );
238
239
			// Used when calling wp_count_terms() below.
240
			$prepared_args['object_ids'] = $prepared_args['post'];
241
		} else {
242
			$query_result = get_terms( $this->taxonomy, $prepared_args );
243
		}
244
245
		$count_args = $prepared_args;
246
247
		unset( $count_args['number'], $count_args['offset'] );
248
249
		$total_terms = wp_count_terms( $this->taxonomy, $count_args );
250
251
		// wp_count_terms can return a falsy value when the term has no children.
252
		if ( ! $total_terms ) {
253
			$total_terms = 0;
254
		}
255
256
		$response = array();
257
258
		foreach ( $query_result as $term ) {
0 ignored issues
show
Bug introduced by
The expression $query_result of type array|object<WP_Error>|integer is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
259
			$data = $this->prepare_item_for_response( $term, $request );
260
			$response[] = $this->prepare_response_for_collection( $data );
261
		}
262
263
		$response = rest_ensure_response( $response );
264
265
		// Store pagination values for headers.
266
		$per_page = (int) $prepared_args['number'];
267
		$page     = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 );
268
269
		$response->header( 'X-WP-Total', (int) $total_terms );
270
271
		$max_pages = ceil( $total_terms / $per_page );
272
273
		$response->header( 'X-WP-TotalPages', (int) $max_pages );
274
275
		$base = add_query_arg( $request->get_query_params(), rest_url( $this->namespace . '/' . $this->rest_base ) );
276 View Code Duplication
		if ( $page > 1 ) {
277
			$prev_page = $page - 1;
278
279
			if ( $prev_page > $max_pages ) {
280
				$prev_page = $max_pages;
281
			}
282
283
			$prev_link = add_query_arg( 'page', $prev_page, $base );
284
			$response->link_header( 'prev', $prev_link );
285
		}
286 View Code Duplication
		if ( $max_pages > $page ) {
287
			$next_page = $page + 1;
288
			$next_link = add_query_arg( 'page', $next_page, $base );
289
290
			$response->link_header( 'next', $next_link );
291
		}
292
293
		return $response;
294
	}
295
296
	/**
297
	 * Get the term, if the ID is valid.
298
	 *
299
	 * @since 4.7.2
300
	 *
301
	 * @param int $id Supplied ID.
302
	 * @return WP_Term|WP_Error Term object if ID is valid, WP_Error otherwise.
0 ignored issues
show
Documentation introduced by
Should the return type not be WP_Error|array|WP_Term? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
303
	 */
304
	protected function get_term( $id ) {
305
		$error = new WP_Error( 'rest_term_invalid', __( 'Term does not exist.' ), array( 'status' => 404 ) );
306
307
		if ( ! $this->check_is_taxonomy_allowed( $this->taxonomy ) ) {
308
			return $error;
309
		}
310
311
		if ( (int) $id <= 0 ) {
312
			return $error;
313
		}
314
315
		$term = get_term( (int) $id, $this->taxonomy );
316
		if ( empty( $term ) || $term->taxonomy !== $this->taxonomy ) {
317
			return $error;
318
		}
319
320
		return $term;
321
	}
322
323
	/**
324
	 * Checks if a request has access to read or edit the specified term.
325
	 *
326
	 * @since 4.7.0
327
	 * @access public
328
	 *
329
	 * @param WP_REST_Request $request Full details about the request.
330
	 * @return bool|WP_Error True if the request has read access for the item, otherwise false or WP_Error object.
0 ignored issues
show
Documentation introduced by
Should the return type not be WP_Error|array|WP_Term|boolean? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
331
	 */
332 View Code Duplication
	public function get_item_permissions_check( $request ) {
333
		$term = $this->get_term( $request['id'] );
334
		if ( is_wp_error( $term ) ) {
335
			return $term;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $term; (WP_Error|array|WP_Term) is incompatible with the return type of the parent method WP_REST_Controller::get_item_permissions_check of type WP_Error|boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
336
		}
337
338
		if ( 'edit' === $request['context'] && ! current_user_can( 'edit_term', $term->term_id ) ) {
339
			return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit this term.' ), array( 'status' => rest_authorization_required_code() ) );
340
		}
341
		return true;
342
	}
343
344
	/**
345
	 * Gets a single term from a taxonomy.
346
	 *
347
	 * @since 4.7.0
348
	 * @access public
349
	 *
350
	 * @param WP_REST_Request $request Full details about the request.
351
	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
352
	 */
353 View Code Duplication
	public function get_item( $request ) {
354
		$term = $this->get_term( $request['id'] );
355
		if ( is_wp_error( $term ) ) {
356
			return $term;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $term; (WP_Error|array|WP_Term) is incompatible with the return type documented by WP_REST_Terms_Controller::get_item of type WP_REST_Response|WP_Error.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
357
		}
358
359
		$response = $this->prepare_item_for_response( $term, $request );
360
361
		return rest_ensure_response( $response );
362
	}
363
364
	/**
365
	 * Checks if a request has access to create a term.
366
	 *
367
	 * @since 4.7.0
368
	 * @access public
369
	 *
370
	 * @param WP_REST_Request $request Full details about the request.
371
	 * @return bool|WP_Error True if the request has access to create items, false or WP_Error object otherwise.
372
	 */
373
	public function create_item_permissions_check( $request ) {
374
375
		if ( ! $this->check_is_taxonomy_allowed( $this->taxonomy ) ) {
376
			return false;
377
		}
378
379
		$taxonomy_obj = get_taxonomy( $this->taxonomy );
380
		if ( ! current_user_can( $taxonomy_obj->cap->edit_terms ) ) {
381
			return new WP_Error( 'rest_cannot_create', __( 'Sorry, you are not allowed to create new terms.' ), array( 'status' => rest_authorization_required_code() ) );
382
		}
383
384
		return true;
385
	}
386
387
	/**
388
	 * Creates a single term in a taxonomy.
389
	 *
390
	 * @since 4.7.0
391
	 * @access public
392
	 *
393
	 * @param WP_REST_Request $request Full details about the request.
394
	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
395
	 */
396
	public function create_item( $request ) {
397 View Code Duplication
		if ( isset( $request['parent'] ) ) {
398
			if ( ! is_taxonomy_hierarchical( $this->taxonomy ) ) {
399
				return new WP_Error( 'rest_taxonomy_not_hierarchical', __( 'Cannot set parent term, taxonomy is not hierarchical.' ), array( 'status' => 400 ) );
400
			}
401
402
			$parent = get_term( (int) $request['parent'], $this->taxonomy );
403
404
			if ( ! $parent ) {
405
				return new WP_Error( 'rest_term_invalid', __( 'Parent term does not exist.' ), array( 'status' => 400 ) );
406
			}
407
		}
408
409
		$prepared_term = $this->prepare_item_for_database( $request );
410
411
		$term = wp_insert_term( wp_slash( $prepared_term->name ), $this->taxonomy, wp_slash( (array) $prepared_term ) );
0 ignored issues
show
Bug introduced by
It seems like wp_slash($prepared_term->name) targeting wp_slash() can also be of type array; however, wp_insert_term() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
Bug Compatibility introduced by
The expression wp_insert_term(wp_slash(...rray) $prepared_term)); of type array|WP_Error adds the type array to the return on line 422 which is incompatible with the return type documented by WP_REST_Terms_Controller::create_item of type WP_REST_Response|WP_Error.
Loading history...
412
		if ( is_wp_error( $term ) ) {
413
			/*
414
			 * If we're going to inform the client that the term already exists,
415
			 * give them the identifier for future use.
416
			 */
417
			if ( $term_id = $term->get_error_data( 'term_exists' ) ) {
418
				$existing_term = get_term( $term_id, $this->taxonomy );
419
				$term->add_data( $existing_term->term_id, 'term_exists' );
420
			}
421
422
			return $term;
423
		}
424
425
		$term = get_term( $term['term_id'], $this->taxonomy );
426
427
		/**
428
		 * Fires after a single term is created or updated via the REST API.
429
		 *
430
		 * The dynamic portion of the hook name, `$this->taxonomy`, refers to the taxonomy slug.
431
		 *
432
		 * @since 4.7.0
433
		 *
434
		 * @param WP_Term         $term     Inserted or updated term object.
435
		 * @param WP_REST_Request $request  Request object.
436
		 * @param bool            $creating True when creating a term, false when updating.
437
		 */
438
		do_action( "rest_insert_{$this->taxonomy}", $term, $request, true );
439
440
		$schema = $this->get_item_schema();
441 View Code Duplication
		if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) {
442
			$meta_update = $this->meta->update_value( $request['meta'], (int) $request['id'] );
443
444
			if ( is_wp_error( $meta_update ) ) {
445
				return $meta_update;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $meta_update; (WP_Error|boolean|true|null) is incompatible with the return type documented by WP_REST_Terms_Controller::create_item of type WP_REST_Response|WP_Error.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
446
			}
447
		}
448
449
		$fields_update = $this->update_additional_fields_for_object( $term, $request );
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->update_additional...bject($term, $request); of type boolean|WP_Error adds the type boolean to the return on line 452 which is incompatible with the return type documented by WP_REST_Terms_Controller::create_item of type WP_REST_Response|WP_Error.
Loading history...
450
451
		if ( is_wp_error( $fields_update ) ) {
452
			return $fields_update;
453
		}
454
455
		$request->set_param( 'context', 'view' );
456
457
		$response = $this->prepare_item_for_response( $term, $request );
458
		$response = rest_ensure_response( $response );
459
460
		$response->set_status( 201 );
461
		$response->header( 'Location', rest_url( $this->namespace . '/' . $this->rest_base . '/' . $term->term_id ) );
462
463
		return $response;
464
	}
465
466
	/**
467
	 * Checks if a request has access to update the specified term.
468
	 *
469
	 * @since 4.7.0
470
	 * @access public
471
	 *
472
	 * @param WP_REST_Request $request Full details about the request.
473
	 * @return bool|WP_Error True if the request has access to update the item, false or WP_Error object otherwise.
0 ignored issues
show
Documentation introduced by
Should the return type not be WP_Error|array|WP_Term|boolean? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
474
	 */
475 View Code Duplication
	public function update_item_permissions_check( $request ) {
476
		$term = $this->get_term( $request['id'] );
477
		if ( is_wp_error( $term ) ) {
478
			return $term;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $term; (WP_Error|array|WP_Term) is incompatible with the return type of the parent method WP_REST_Controller::update_item_permissions_check of type WP_Error|boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
479
		}
480
481
		if ( ! current_user_can( 'edit_term', $term->term_id ) ) {
482
			return new WP_Error( 'rest_cannot_update', __( 'Sorry, you are not allowed to edit this term.' ), array( 'status' => rest_authorization_required_code() ) );
483
		}
484
485
		return true;
486
	}
487
488
	/**
489
	 * Updates a single term from a taxonomy.
490
	 *
491
	 * @since 4.7.0
492
	 * @access public
493
	 *
494
	 * @param WP_REST_Request $request Full details about the request.
495
	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
496
	 */
497
	public function update_item( $request ) {
498
		$term = $this->get_term( $request['id'] );
499
		if ( is_wp_error( $term ) ) {
500
			return $term;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $term; (WP_Error|array|WP_Term) is incompatible with the return type documented by WP_REST_Terms_Controller::update_item of type WP_REST_Response|WP_Error.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
501
		}
502
503 View Code Duplication
		if ( isset( $request['parent'] ) ) {
504
			if ( ! is_taxonomy_hierarchical( $this->taxonomy ) ) {
505
				return new WP_Error( 'rest_taxonomy_not_hierarchical', __( 'Cannot set parent term, taxonomy is not hierarchical.' ), array( 'status' => 400 ) );
506
			}
507
508
			$parent = get_term( (int) $request['parent'], $this->taxonomy );
509
510
			if ( ! $parent ) {
511
				return new WP_Error( 'rest_term_invalid', __( 'Parent term does not exist.' ), array( 'status' => 400 ) );
512
			}
513
		}
514
515
		$prepared_term = $this->prepare_item_for_database( $request );
516
517
		// Only update the term if we haz something to update.
518
		if ( ! empty( $prepared_term ) ) {
519
			$update = wp_update_term( $term->term_id, $term->taxonomy, wp_slash( (array) $prepared_term ) );
520
521
			if ( is_wp_error( $update ) ) {
522
				return $update;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $update; (WP_Error|array|WP_Term|null) is incompatible with the return type documented by WP_REST_Terms_Controller::update_item of type WP_REST_Response|WP_Error.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
523
			}
524
		}
525
526
		$term = get_term( $term->term_id, $this->taxonomy );
527
528
		/** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */
529
		do_action( "rest_insert_{$this->taxonomy}", $term, $request, false );
530
531
		$schema = $this->get_item_schema();
532
		if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) {
533
			$meta_update = $this->meta->update_value( $request['meta'], $term->term_id );
534
535
			if ( is_wp_error( $meta_update ) ) {
536
				return $meta_update;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $meta_update; (WP_Error|boolean|true|null) is incompatible with the return type documented by WP_REST_Terms_Controller::update_item of type WP_REST_Response|WP_Error.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
537
			}
538
		}
539
540
		$fields_update = $this->update_additional_fields_for_object( $term, $request );
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->update_additional...bject($term, $request); of type boolean|WP_Error adds the type boolean to the return on line 543 which is incompatible with the return type documented by WP_REST_Terms_Controller::update_item of type WP_REST_Response|WP_Error.
Loading history...
541
542
		if ( is_wp_error( $fields_update ) ) {
543
			return $fields_update;
544
		}
545
546
		$request->set_param( 'context', 'view' );
547
548
		$response = $this->prepare_item_for_response( $term, $request );
549
550
		return rest_ensure_response( $response );
551
	}
552
553
	/**
554
	 * Checks if a request has access to delete the specified term.
555
	 *
556
	 * @since 4.7.0
557
	 * @access public
558
	 *
559
	 * @param WP_REST_Request $request Full details about the request.
560
	 * @return bool|WP_Error True if the request has access to delete the item, otherwise false or WP_Error object.
0 ignored issues
show
Documentation introduced by
Should the return type not be WP_Error|array|WP_Term|boolean? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
561
	 */
562 View Code Duplication
	public function delete_item_permissions_check( $request ) {
563
		$term = $this->get_term( $request['id'] );
564
		if ( is_wp_error( $term ) ) {
565
			return $term;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $term; (WP_Error|array|WP_Term) is incompatible with the return type of the parent method WP_REST_Controller::delete_item_permissions_check of type WP_Error|boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
566
		}
567
568
		if ( ! current_user_can( 'delete_term', $term->term_id ) ) {
569
			return new WP_Error( 'rest_cannot_delete', __( 'Sorry, you are not allowed to delete this term.' ), array( 'status' => rest_authorization_required_code() ) );
570
		}
571
572
		return true;
573
	}
574
575
	/**
576
	 * Deletes a single term from a taxonomy.
577
	 *
578
	 * @since 4.7.0
579
	 * @access public
580
	 *
581
	 * @param WP_REST_Request $request Full details about the request.
582
	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
0 ignored issues
show
Documentation introduced by
Should the return type not be WP_Error|array|WP_Term|WP_REST_Response? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
583
	 */
584
	public function delete_item( $request ) {
585
		$term = $this->get_term( $request['id'] );
586
		if ( is_wp_error( $term ) ) {
587
			return $term;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $term; (WP_Error|array|WP_Term) is incompatible with the return type of the parent method WP_REST_Controller::delete_item of type WP_Error|WP_REST_Response.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
588
		}
589
590
		$force = isset( $request['force'] ) ? (bool) $request['force'] : false;
591
592
		// We don't support trashing for terms.
593
		if ( ! $force ) {
594
			return new WP_Error( 'rest_trash_not_supported', __( 'Terms do not support trashing. Set force=true to delete.' ), array( 'status' => 501 ) );
595
		}
596
597
		$request->set_param( 'context', 'view' );
598
599
		$previous = $this->prepare_item_for_response( $term, $request );
600
601
		$retval = wp_delete_term( $term->term_id, $term->taxonomy );
602
603
		if ( ! $retval ) {
604
			return new WP_Error( 'rest_cannot_delete', __( 'The term cannot be deleted.' ), array( 'status' => 500 ) );
605
		}
606
607
		$response = new WP_REST_Response();
608
		$response->set_data( array( 'deleted' => true, 'previous' => $previous->get_data() ) );
609
610
		/**
611
		 * Fires after a single term is deleted via the REST API.
612
		 *
613
		 * The dynamic portion of the hook name, `$this->taxonomy`, refers to the taxonomy slug.
614
		 *
615
		 * @since 4.7.0
616
		 *
617
		 * @param WP_Term          $term     The deleted term.
618
		 * @param WP_REST_Response $response The response data.
619
		 * @param WP_REST_Request  $request  The request sent to the API.
620
		 */
621
		do_action( "rest_delete_{$this->taxonomy}", $term, $response, $request );
622
623
		return $response;
624
	}
625
626
	/**
627
	 * Prepares a single term for create or update.
628
	 *
629
	 * @since 4.7.0
630
	 * @access public
631
	 *
632
	 * @param WP_REST_Request $request Request object.
633
	 * @return object $prepared_term Term object.
634
	 */
635
	public function prepare_item_for_database( $request ) {
636
		$prepared_term = new stdClass;
637
638
		$schema = $this->get_item_schema();
639
		if ( isset( $request['name'] ) && ! empty( $schema['properties']['name'] ) ) {
640
			$prepared_term->name = $request['name'];
641
		}
642
643
		if ( isset( $request['slug'] ) && ! empty( $schema['properties']['slug'] ) ) {
644
			$prepared_term->slug = $request['slug'];
645
		}
646
647
		if ( isset( $request['taxonomy'] ) && ! empty( $schema['properties']['taxonomy'] ) ) {
648
			$prepared_term->taxonomy = $request['taxonomy'];
649
		}
650
651
		if ( isset( $request['description'] ) && ! empty( $schema['properties']['description'] ) ) {
652
			$prepared_term->description = $request['description'];
653
		}
654
655
		if ( isset( $request['parent'] ) && ! empty( $schema['properties']['parent'] ) ) {
656
			$parent_term_id = 0;
657
			$parent_term    = get_term( (int) $request['parent'], $this->taxonomy );
658
659
			if ( $parent_term ) {
660
				$parent_term_id = $parent_term->term_id;
661
			}
662
663
			$prepared_term->parent = $parent_term_id;
664
		}
665
666
		/**
667
		 * Filters term data before inserting term via the REST API.
668
		 *
669
		 * The dynamic portion of the hook name, `$this->taxonomy`, refers to the taxonomy slug.
670
		 *
671
		 * @since 4.7.0
672
		 *
673
		 * @param object          $prepared_term Term object.
674
		 * @param WP_REST_Request $request       Request object.
675
		 */
676
		return apply_filters( "rest_pre_insert_{$this->taxonomy}", $prepared_term, $request );
677
	}
678
679
	/**
680
	 * Prepares a single term output for response.
681
	 *
682
	 * @since 4.7.0
683
	 * @access public
684
	 *
685
	 * @param obj             $item    Term object.
686
	 * @param WP_REST_Request $request Request object.
687
	 * @return WP_REST_Response $response Response object.
688
	 */
689
	public function prepare_item_for_response( $item, $request ) {
690
691
		$schema = $this->get_item_schema();
692
		$data   = array();
693
694
		if ( ! empty( $schema['properties']['id'] ) ) {
695
			$data['id'] = (int) $item->term_id;
696
		}
697
698
		if ( ! empty( $schema['properties']['count'] ) ) {
699
			$data['count'] = (int) $item->count;
700
		}
701
702
		if ( ! empty( $schema['properties']['description'] ) ) {
703
			$data['description'] = $item->description;
704
		}
705
706
		if ( ! empty( $schema['properties']['link'] ) ) {
707
			$data['link'] = get_term_link( $item );
708
		}
709
710
		if ( ! empty( $schema['properties']['name'] ) ) {
711
			$data['name'] = $item->name;
712
		}
713
714
		if ( ! empty( $schema['properties']['slug'] ) ) {
715
			$data['slug'] = $item->slug;
716
		}
717
718
		if ( ! empty( $schema['properties']['taxonomy'] ) ) {
719
			$data['taxonomy'] = $item->taxonomy;
720
		}
721
722
		if ( ! empty( $schema['properties']['parent'] ) ) {
723
			$data['parent'] = (int) $item->parent;
724
		}
725
726 View Code Duplication
		if ( ! empty( $schema['properties']['meta'] ) ) {
727
			$data['meta'] = $this->meta->get_value( $item->term_id, $request );
728
		}
729
730
		$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
731
		$data    = $this->add_additional_fields_to_object( $data, $request );
732
		$data    = $this->filter_response_by_context( $data, $context );
733
734
		$response = rest_ensure_response( $data );
735
736
		$response->add_links( $this->prepare_links( $item ) );
737
738
		/**
739
		 * Filters a term item returned from the API.
740
		 *
741
		 * The dynamic portion of the hook name, `$this->taxonomy`, refers to the taxonomy slug.
742
		 *
743
		 * Allows modification of the term data right before it is returned.
744
		 *
745
		 * @since 4.7.0
746
		 *
747
		 * @param WP_REST_Response  $response  The response object.
748
		 * @param object            $item      The original term object.
749
		 * @param WP_REST_Request   $request   Request used to generate the response.
750
		 */
751
		return apply_filters( "rest_prepare_{$this->taxonomy}", $response, $item, $request );
752
	}
753
754
	/**
755
	 * Prepares links for the request.
756
	 *
757
	 * @since 4.7.0
758
	 * @access protected
759
	 *
760
	 * @param object $term Term object.
761
	 * @return array Links for the given term.
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
762
	 */
763
	protected function prepare_links( $term ) {
764
		$base = $this->namespace . '/' . $this->rest_base;
765
		$links = array(
766
			'self'       => array(
767
				'href' => rest_url( trailingslashit( $base ) . $term->term_id ),
768
			),
769
			'collection' => array(
770
				'href' => rest_url( $base ),
771
			),
772
			'about'      => array(
773
				'href' => rest_url( sprintf( 'wp/v2/taxonomies/%s', $this->taxonomy ) ),
774
			),
775
		);
776
777
		if ( $term->parent ) {
778
			$parent_term = get_term( (int) $term->parent, $term->taxonomy );
779
780
			if ( $parent_term ) {
781
				$links['up'] = array(
782
					'href'       => rest_url( trailingslashit( $base ) . $parent_term->term_id ),
783
					'embeddable' => true,
784
				);
785
			}
786
		}
787
788
		$taxonomy_obj = get_taxonomy( $term->taxonomy );
789
790
		if ( empty( $taxonomy_obj->object_type ) ) {
791
			return $links;
792
		}
793
794
		$post_type_links = array();
795
796
		foreach ( $taxonomy_obj->object_type as $type ) {
797
			$post_type_object = get_post_type_object( $type );
798
799
			if ( empty( $post_type_object->show_in_rest ) ) {
800
				continue;
801
			}
802
803
			$rest_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name;
804
			$post_type_links[] = array(
805
				'href' => add_query_arg( $this->rest_base, $term->term_id, rest_url( sprintf( 'wp/v2/%s', $rest_base ) ) ),
806
			);
807
		}
808
809
		if ( ! empty( $post_type_links ) ) {
810
			$links['https://api.w.org/post_type'] = $post_type_links;
811
		}
812
813
		return $links;
814
	}
815
816
	/**
817
	 * Retrieves the term's schema, conforming to JSON Schema.
818
	 *
819
	 * @since 4.7.0
820
	 * @access public
821
	 *
822
	 * @return array Item schema data.
823
	 */
824
	public function get_item_schema() {
825
		$schema = array(
826
			'$schema'    => 'http://json-schema.org/schema#',
827
			'title'      => 'post_tag' === $this->taxonomy ? 'tag' : $this->taxonomy,
828
			'type'       => 'object',
829
			'properties' => array(
830
				'id'          => array(
831
					'description'  => __( 'Unique identifier for the term.' ),
832
					'type'         => 'integer',
833
					'context'      => array( 'view', 'embed', 'edit' ),
834
					'readonly'     => true,
835
				),
836
				'count'       => array(
837
					'description'  => __( 'Number of published posts for the term.' ),
838
					'type'         => 'integer',
839
					'context'      => array( 'view', 'edit' ),
840
					'readonly'     => true,
841
				),
842
				'description' => array(
843
					'description'  => __( 'HTML description of the term.' ),
844
					'type'         => 'string',
845
					'context'      => array( 'view', 'edit' ),
846
				),
847
				'link'        => array(
848
					'description'  => __( 'URL of the term.' ),
849
					'type'         => 'string',
850
					'format'       => 'uri',
851
					'context'      => array( 'view', 'embed', 'edit' ),
852
					'readonly'     => true,
853
				),
854
				'name'        => array(
855
					'description'  => __( 'HTML title for the term.' ),
856
					'type'         => 'string',
857
					'context'      => array( 'view', 'embed', 'edit' ),
858
					'arg_options'  => array(
859
						'sanitize_callback' => 'sanitize_text_field',
860
					),
861
					'required'     => true,
862
				),
863
				'slug'        => array(
864
					'description'  => __( 'An alphanumeric identifier for the term unique to its type.' ),
865
					'type'         => 'string',
866
					'context'      => array( 'view', 'embed', 'edit' ),
867
					'arg_options'  => array(
868
						'sanitize_callback' => array( $this, 'sanitize_slug' ),
869
					),
870
				),
871
				'taxonomy'    => array(
872
					'description'  => __( 'Type attribution for the term.' ),
873
					'type'         => 'string',
874
					'enum'         => array_keys( get_taxonomies() ),
875
					'context'      => array( 'view', 'embed', 'edit' ),
876
					'readonly'     => true,
877
				),
878
			),
879
		);
880
881
		$taxonomy = get_taxonomy( $this->taxonomy );
882
883 View Code Duplication
		if ( $taxonomy->hierarchical ) {
884
			$schema['properties']['parent'] = array(
885
				'description'  => __( 'The parent term ID.' ),
886
				'type'         => 'integer',
887
				'context'      => array( 'view', 'edit' ),
888
			);
889
		}
890
891
		$schema['properties']['meta'] = $this->meta->get_field_schema();
892
893
		return $this->add_additional_fields_schema( $schema );
894
	}
895
896
	/**
897
	 * Retrieves the query params for collections.
898
	 *
899
	 * @since 4.7.0
900
	 * @access public
901
	 *
902
	 * @return array Collection parameters.
903
	 */
904
	public function get_collection_params() {
905
		$query_params = parent::get_collection_params();
906
		$taxonomy = get_taxonomy( $this->taxonomy );
907
908
		$query_params['context']['default'] = 'view';
909
910
		$query_params['exclude'] = array(
911
			'description'       => __( 'Ensure result set excludes specific IDs.' ),
912
			'type'              => 'array',
913
			'items'             => array(
914
				'type'          => 'integer',
915
			),
916
			'default'           => array(),
917
		);
918
919
		$query_params['include'] = array(
920
			'description'       => __( 'Limit result set to specific IDs.' ),
921
			'type'              => 'array',
922
			'items'             => array(
923
				'type'          => 'integer',
924
			),
925
			'default'           => array(),
926
		);
927
928 View Code Duplication
		if ( ! $taxonomy->hierarchical ) {
929
			$query_params['offset'] = array(
930
				'description'       => __( 'Offset the result set by a specific number of items.' ),
931
				'type'              => 'integer',
932
			);
933
		}
934
935
		$query_params['order'] = array(
936
			'description'       => __( 'Order sort attribute ascending or descending.' ),
937
			'type'              => 'string',
938
			'default'           => 'asc',
939
			'enum'              => array(
940
				'asc',
941
				'desc',
942
			),
943
		);
944
945
		$query_params['orderby'] = array(
946
			'description'       => __( 'Sort collection by term attribute.' ),
947
			'type'              => 'string',
948
			'default'           => 'name',
949
			'enum'              => array(
950
				'id',
951
				'include',
952
				'name',
953
				'slug',
954
				'term_group',
955
				'description',
956
				'count',
957
			),
958
		);
959
960
		$query_params['hide_empty'] = array(
961
			'description'       => __( 'Whether to hide terms not assigned to any posts.' ),
962
			'type'              => 'boolean',
963
			'default'           => false,
964
		);
965
966 View Code Duplication
		if ( $taxonomy->hierarchical ) {
967
			$query_params['parent'] = array(
968
				'description'       => __( 'Limit result set to terms assigned to a specific parent.' ),
969
				'type'              => 'integer',
970
			);
971
		}
972
973
		$query_params['post'] = array(
974
			'description'       => __( 'Limit result set to terms assigned to a specific post.' ),
975
			'type'              => 'integer',
976
			'default'           => null,
977
		);
978
979
		$query_params['slug'] = array(
980
			'description'       => __( 'Limit result set to terms with one or more specific slugs.' ),
981
			'type'              => 'array',
982
			'items'             => array(
983
				'type'          => 'string'
984
			),
985
		);
986
987
		/**
988
		 * Filter collection parameters for the terms controller.
989
		 *
990
		 * The dynamic part of the filter `$this->taxonomy` refers to the taxonomy
991
		 * slug for the controller.
992
		 *
993
		 * This filter registers the collection parameter, but does not map the
994
		 * collection parameter to an internal WP_Term_Query parameter.  Use the
995
		 * `rest_{$this->taxonomy}_query` filter to set WP_Term_Query parameters.
996
		 *
997
		 * @since 4.7.0
998
		 *
999
		 * @param array       $query_params JSON Schema-formatted collection parameters.
1000
		 * @param WP_Taxonomy $taxonomy     Taxonomy object.
1001
		 */
1002
		return apply_filters( "rest_{$this->taxonomy}_collection_params", $query_params, $taxonomy );
1003
	}
1004
1005
	/**
1006
	 * Checks that the taxonomy is valid.
1007
	 *
1008
	 * @since 4.7.0
1009
	 * @access protected
1010
	 *
1011
	 * @param string $taxonomy Taxonomy to check.
1012
	 * @return bool Whether the taxonomy is allowed for REST management.
1013
	 */
1014
	protected function check_is_taxonomy_allowed( $taxonomy ) {
1015
		$taxonomy_obj = get_taxonomy( $taxonomy );
1016
		if ( $taxonomy_obj && ! empty( $taxonomy_obj->show_in_rest ) ) {
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return $taxonomy_obj && ...omy_obj->show_in_rest);.
Loading history...
1017
			return true;
1018
		}
1019
		return false;
1020
	}
1021
}
1022