PluginProbe
Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More / trunk
Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More vtrunk
trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.10 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 2.0.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 47 releases
content-control / classes / RestAPI / ObjectSearch.php

ObjectSearch.php in Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More trunk, at classes/RestAPI/ObjectSearch.php

444 lines 11.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * RestAPI Global Settings Endpoint.
4 *
5 * @copyright (c) 2021, Code Atlantic LLC.
6 * @package ContentControl
7 */
8
9 namespace ContentControl\RestAPI;
10
11 use WP_User_Query, WP_REST_Controller, WP_REST_Response, WP_REST_Server, WP_Error;
12
13 use function ContentControl\plugin;
14
15 defined( 'ABSPATH' ) || exit;
16
17 /**
18 * Rest API Object Search Controller Class.
19 */
20 class ObjectSearch extends WP_REST_Controller {
21
22 /**
23 * Endpoint namespace.
24 *
25 * @var string
26 */
27 protected $namespace = 'content-control/v2';
28
29 /**
30 * Route base.
31 *
32 * @var string
33 */
34 protected $base = 'objectSearch';
35
36 /**
37 * Register API endpoint routes.
38 *
39 * @return void
40 */
41 public function register_routes() {
42 register_rest_route(
43 $this->namespace,
44 '/' . $this->base,
45 [
46 [
47 'methods' => WP_REST_Server::READABLE,
48 'callback' => [ $this, 'object_search' ],
49 'permission_callback' => [ $this, 'object_search_permissions' ],
50 'args' => [
51 'nonce' => [
52 'description' => __( 'Nonce', 'content-control' ),
53 'type' => 'string',
54 'required' => true,
55 ],
56 'hash' => [
57 'description' => __( 'Hash', 'content-control' ),
58 'type' => 'string',
59 'required' => true,
60 ],
61 'entityKind' => [
62 'description' => __( 'Object kind, (postType, taxonomy)', 'content-control' ),
63 'type' => 'string',
64 'required' => true,
65 ],
66 'entityType' => [
67 'description' => __( 'Object type (post, category)', 'content-control' ),
68 'type' => 'string',
69 'required' => true,
70 ],
71 'paged' => [
72 'description' => __( 'Page number', 'content-control' ),
73 'type' => 'integer',
74 'required' => false,
75 ],
76 's' => [
77 'description' => __( 'Search term', 'content-control' ),
78 'type' => 'string',
79 'required' => false,
80 ],
81 'include' => [
82 'description' => __( 'Include IDs', 'content-control' ),
83 'type' => 'string',
84 'required' => false,
85 ],
86 'exclude' => [
87 'description' => __( 'Exclude IDs', 'content-control' ),
88 'type' => 'string',
89 'required' => false,
90 ],
91 ],
92 ],
93 ]
94 );
95 }
96
97 /**
98 * Check whether the current user may search objects used by plugin settings.
99 *
100 * @return bool
101 */
102 public function object_search_permissions() {
103 return current_user_can( plugin()->get_permission( 'manage_settings' ) );
104 }
105
106 /**
107 * Get block type list.
108 *
109 * @param \WP_REST_Request<array<string,mixed>> $request Request object.
110 *
111 * @return WP_Error|WP_REST_Response
112 */
113 public function object_search( $request ) {
114 $nonce = $request->get_param( 'nonce' );
115 $params = $request->get_params();
116
117 if ( ! isset( $nonce ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $nonce ) ), 'content_control_object_search_nonce' ) ) {
118 wp_send_json_error();
119 }
120
121 try {
122 $results = [
123 'hash' => $request->get_param( 'hash' ),
124 'items' => [],
125 'totalCount' => 0,
126 ];
127
128 $object_kind = isset( $params['entityKind'] ) ? sanitize_text_field( wp_unslash( $params['entityKind'] ) ) : '';
129 $object_type = isset( $params['entityType'] ) ? sanitize_text_field( wp_unslash( $params['entityType'] ) ) : '';
130 $include = ! empty( $params['include'] ) ? wp_parse_id_list( wp_unslash( $params['include'] ) ) : [];
131 $exclude = ! empty( $params['exclude'] ) ? wp_parse_id_list( wp_unslash( $params['exclude'] ) ) : [];
132
133 if ( ! empty( $include ) ) {
134 $exclude = array_merge( $include, $exclude );
135 }
136
137 switch ( $object_kind ) {
138 case 'post_type':
139 $post_type = ! empty( $object_type ) ? $object_type : 'post';
140
141 if ( ! empty( $include ) ) {
142 $include_query = $this->post_type_selectlist_query(
143 $post_type,
144 [
145 'post__in' => $include,
146 'posts_per_page' => - 1,
147 ],
148 true
149 );
150
151 foreach ( $include_query['items'] as $id => $name ) {
152 $results['items'][] = [
153 'id' => $id,
154 'text' => "$name (ID: $id)",
155 ];
156 }
157
158 $results['totalCount'] += (int) $include_query['totalCount'];
159 }
160
161 $query = $this->post_type_selectlist_query(
162 $post_type,
163 [
164 's' => ! empty( $params['s'] ) ? sanitize_text_field( wp_unslash( $params['s'] ) ) : null,
165 'paged' => ! empty( $params['paged'] ) ? absint( $params['paged'] ) : null,
166 'post__not_in' => $exclude,
167 'posts_per_page' => 10,
168 ],
169 true
170 );
171
172 foreach ( $query['items'] as $id => $name ) {
173 $results['items'][] = [
174 'id' => $id,
175 'text' => "$name (ID: $id)",
176 ];
177 }
178
179 $results['totalCount'] += (int) $query['totalCount'];
180 break;
181
182 case 'taxonomy':
183 $taxonomy = ! empty( $params['object_key'] ) ? sanitize_text_field( wp_unslash( $params['object_key'] ) ) : 'category';
184
185 if ( ! empty( $include ) ) {
186 $include_query = $this->taxonomy_selectlist_query(
187 $taxonomy,
188 [
189 'include' => $include,
190 'number' => 0,
191 ],
192 true
193 );
194
195 foreach ( $include_query['items'] as $id => $name ) {
196 $results['items'][] = [
197 'id' => $id,
198 'text' => "$name (ID: $id)",
199 ];
200 }
201
202 $results['totalCount'] += (int) $include_query['totalCount'];
203 }
204
205 $query = $this->taxonomy_selectlist_query(
206 $taxonomy,
207 [
208 'search' => ! empty( $params['s'] ) ? sanitize_text_field( wp_unslash( $params['s'] ) ) : null,
209 'paged' => ! empty( $params['paged'] ) ? absint( $params['paged'] ) : null,
210 'exclude' => $exclude,
211 'number' => 10,
212 ],
213 true
214 );
215
216 foreach ( $query['items'] as $id => $name ) {
217 $results['items'][] = [
218 'id' => $id,
219 'text' => "$name (ID: $id)",
220 ];
221 }
222
223 $results['totalCount'] += (int) $query['totalCount'];
224 break;
225 case 'user':
226 if ( ! current_user_can( 'list_users' ) ) {
227 wp_send_json_error();
228 }
229
230 $user_role = ! empty( $params['object_key'] ) ? sanitize_text_field( wp_unslash( $params['object_key'] ) ) : null;
231
232 if ( ! empty( $include ) ) {
233 $include_query = $this->user_selectlist_query(
234 [
235 'role' => $user_role,
236 'include' => $include,
237 'number' => - 1,
238 ],
239 true
240 );
241
242 foreach ( $include_query['items'] as $id => $name ) {
243 $results['items'][] = [
244 'id' => $id,
245 'text' => "$name (ID: $id)",
246 ];
247 }
248
249 $results['totalCount'] += (int) $include_query['totalCount'];
250 }
251
252 $query = $this->user_selectlist_query(
253 [
254 'role' => $user_role,
255 'search' => ! empty( $params['s'] ) ? '*' . sanitize_text_field( wp_unslash( $params['s'] ) ) . '*' : null,
256 'paged' => ! empty( $params['paged'] ) ? absint( $params['paged'] ) : null,
257 'exclude' => $exclude,
258 'number' => 10,
259 ],
260 true
261 );
262
263 foreach ( $query['items'] as $id => $name ) {
264 $results['items'][] = [
265 'id' => $id,
266 'text' => "$name (ID: $id)",
267 ];
268 }
269
270 $results['totalCount'] += (int) $query['totalCount'];
271 break;
272 }
273
274 return new WP_REST_Response( $results, 200 );
275 } catch ( \Exception $e ) {
276 return new WP_Error( '500', __( 'Something went wrong, the results could not be returned.', 'content-control' ), [ 'status' => 500 ] );
277 }
278 }
279
280
281 /**
282 * Get a list of posts for a select list.
283 *
284 * @param string $post_type Post type(s) to query.
285 * @param array<string,mixed> $args Query arguments.
286 * @param boolean $include_total Whether to include the total count in the response.
287 * @return array{items:array<int,string>,totalCount:int}|array<int,string>
288 */
289 public function post_type_selectlist_query( $post_type, $args = [], $include_total = false ) {
290 if ( empty( $post_type ) ) {
291 $post_type = [ 'any' ];
292 }
293
294 $args = wp_parse_args( $args, [
295 'posts_per_page' => 10,
296 'post_type' => $post_type,
297 'post__in' => null,
298 'post__not_in' => null,
299 'post_status' => null,
300 'page' => 1,
301 // Performance Optimization.
302 'no_found_rows' => ! $include_total ? true : false,
303 'update_post_term_cache' => false,
304 'update_post_meta_cache' => false,
305 ] );
306
307 // $post_type should always be single string?
308 if ( 'attachment' === $post_type ) {
309 $args['post_status'] = 'inherit';
310 }
311
312 // Query Caching.
313 static $queries = [];
314
315 $key = md5( maybe_serialize( $args ) );
316
317 if ( ! isset( $queries[ $key ] ) ) {
318 $query = new \WP_Query( $args );
319
320 $posts = [];
321 foreach ( $query->posts as $post ) {
322 /**
323 * The post object.
324 *
325 * @var \WP_Post $post
326 */
327 $posts[ $post->ID ] = $post->post_title;
328 }
329
330 $results = [
331 'items' => $posts,
332 'totalCount' => $query->found_posts,
333 ];
334
335 $queries[ $key ] = $results;
336 } else {
337 $results = $queries[ $key ];
338 }
339
340 return ! $include_total ? $results['items'] : $results;
341 }
342
343 /**
344 * Get a list of terms for a select list.
345 *
346 * @param string $taxonomy Taxonomy(s) to query.
347 * @param array<string,mixed> $args Query arguments.
348 * @param boolean $include_total Whether to include the total count in the response.
349 * @return array{items:array<int,string>,totalCount:int}|array<int,string>
350 */
351 public function taxonomy_selectlist_query( $taxonomy, $args = [], $include_total = false ) {
352 if ( empty( $taxonomy ) ) {
353 $taxonomy = [ 'category' ];
354 }
355
356 $args = wp_parse_args( $args, [
357 'hide_empty' => false,
358 'number' => 10,
359 'search' => '',
360 'include' => null,
361 'exclude' => null,
362 'offset' => 0,
363 'page' => null,
364 'taxonomy' => $taxonomy,
365 ] );
366
367 if ( $args['page'] ) {
368 $args['offset'] = ( $args['page'] - 1 ) * $args['number'];
369 }
370
371 // Query Caching.
372 static $queries = [];
373
374 $key = md5( maybe_serialize( $args ) );
375
376 if ( ! isset( $queries[ $key ] ) ) {
377 $terms = [];
378
379 foreach ( get_terms( $args ) as $term ) {
380 $terms[ $term->term_id ] = $term->name;
381 }
382
383 $total_args = $args;
384 $total_args['fields'] = 'count';
385 unset( $total_args['number'] );
386 unset( $total_args['offset'] );
387
388 $results = [
389 'items' => $terms,
390 'totalCount' => $include_total ? get_terms( $total_args ) : null,
391 ];
392
393 $queries[ $key ] = $results;
394 } else {
395 $results = $queries[ $key ];
396 }
397
398 return ! $include_total ? $results['items'] : $results;
399 }
400
401 /**
402 * Get a list of users for a select list.
403 *
404 * @param array<string,mixed> $args Query arguments.
405 * @param bool $include_total Whether to include the total count in the response.
406 *
407 * @return array{items:array<int,string>,totalCount:int}|array<int,string>
408 */
409 public function user_selectlist_query( $args = [], $include_total = false ) {
410 $args = wp_parse_args(
411 $args,
412 [
413 'role' => null,
414 'count_total' => ! $include_total ? true : false,
415 ]
416 );
417
418 // Query Caching.
419 static $queries = [];
420
421 $key = md5( maybe_serialize( $args ) );
422
423 if ( ! isset( $queries[ $key ] ) ) {
424 $query = new WP_User_Query( $args );
425
426 $users = [];
427 foreach ( $query->get_results() as $user ) {
428 $users[ $user->ID ] = $user->display_name;
429 }
430
431 $results = [
432 'items' => $users,
433 'totalCount' => $query->get_total(),
434 ];
435
436 $queries[ $key ] = $results;
437 } else {
438 $results = $queries[ $key ];
439 }
440
441 return ! $include_total ? $results['items'] : $results;
442 }
443 }
444