PluginProbe
Post Grid Gutenberg Blocks – PostX / trunk
Post Grid Gutenberg Blocks – PostX vtrunk
5.0.39 5.0.38 5.0.37 5.0.36 5.0.35 5.0.34 5.0.33 5.0.32 5.0.31 5.0.30 5.0.29 5.0.28 5.0.27 5.0.26 5.0.25 5.0.23 5.0.24 5.0.22 5.0.21 5.0.20 5.0.19 5.0.18 5.0.17 2.1.1 2.1.2 All 237 releases
ultimate-post / classes / REST_API.php

REST_API.php in Post Grid Gutenberg Blocks – PostX trunk, at classes/REST_API.php

828 lines 25.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * REST API Action.
4 *
5 * @package ULTP\REST_API
6 * @since v.1.0.0
7 */
8
9 namespace ULTP;
10
11 defined( 'ABSPATH' ) || exit;
12
13 /**
14 * REST API class.
15 *
16 * Handles custom REST API endpoints for Ultimate Post plugin.
17 *
18 * @package ULTP\REST_API
19 * @since 4.0.0
20 */
21 class REST_API {
22
23 /**
24 * Upper bound for the search endpoint's postPerPage. Matches the max of the
25 * Search block's "Show Initial Post" slider, so no UI value is ever capped.
26 * This is the same max range of the slider in gutenburg editor.
27 * 100 is enough for search bar result.
28 *
29 * @since v.5.0.35
30 */
31 const SEARCH_POSTS_PER_PAGE_MAX = 100;
32
33 /**
34 * Longest accepted search term. Longer strings only widen the LIKE pattern
35 * scanned against every row; no real query needs more.
36 *
37 * @since v.5.0.35
38 */
39 const SEARCH_TEXT_MAX_LENGTH = 200;
40
41 /**
42 * Upper bound for excerptLimit. Also keeps $num_words + 1 inside integer range
43 * in wp_trim_words(), which otherwise overflows to float on a huge value.
44 *
45 * @since v.5.0.35
46 */
47 const SEARCH_EXCERPT_WORDS_MAX = 400;
48
49 /**
50 * Setup class.
51 *
52 * @since v.1.0.0
53 */
54 public function __construct() {
55 add_action( 'rest_api_init', array( $this, 'ultp_register_route' ) );
56 }
57
58 /**
59 * REST API Action
60 *
61 * @since v.1.0.0
62 * @return void
63 */
64 public function ultp_register_route() {
65 register_rest_route(
66 'ultp',
67 'common_data',
68 array(
69 'methods' => \WP_REST_Server::READABLE,
70 'args' => array( 'wpnonce' => array() ),
71 'callback' => array( $this, 'ultp_route_common_data' ),
72 'permission_callback' => function () {
73 return current_user_can( 'edit_posts' );
74 },
75 )
76 );
77 register_rest_route(
78 'ultp',
79 '/fetch_posts/',
80 array(
81 array(
82 'methods' => 'POST',
83 'args' => array(),
84 'callback' => array( $this, 'ultp_route_post_data' ),
85 'permission_callback' => function () {
86 return current_user_can( 'edit_posts' );
87 },
88 ),
89 )
90 );
91 register_rest_route(
92 'ultp',
93 '/specific_taxonomy/',
94 array(
95 array(
96 'methods' => 'POST',
97 'args' => array(),
98 'callback' => array( $this, 'ultp_route_taxonomy_info_data' ),
99 'permission_callback' => function () {
100 return current_user_can( 'edit_others_posts' );
101 },
102 ),
103 )
104 );
105 register_rest_route(
106 'ultp/v1',
107 '/search/',
108 array(
109 array(
110 'methods' => 'POST',
111 'callback' => array( $this, 'search_settings_action' ),
112 'permission_callback' => function () {
113 return current_user_can( 'edit_others_posts' );
114 },
115 'args' => array(),
116 ),
117 )
118 );
119 register_rest_route(
120 'ultp/v2',
121 '/premade_wishlist_save/',
122 array(
123 array(
124 'methods' => 'POST',
125 'callback' => array( $this, 'premade_wishlist_save' ),
126 'permission_callback' => function () {
127 return current_user_can( 'edit_others_posts' );
128 },
129 'args' => array(),
130 ),
131 )
132 );
133 register_rest_route(
134 'ultp',
135 '/ultp_search_data/',
136 array(
137 array(
138 'methods' => 'POST',
139 'callback' => array( $this, 'ultp_search_result' ),
140 'permission_callback' => '__return_true',
141 ),
142 )
143 );
144 register_rest_route(
145 'ultp/v2',
146 '/custom_tax/',
147 array(
148 array(
149 'methods' => 'POST',
150 'callback' => array( $this, 'custom_tax_callback' ),
151 'permission_callback' => function () {
152 return current_user_can( 'manage_options' );
153 },
154 'args' => array(),
155 ),
156 )
157 );
158 register_rest_route(
159 'ultp/v2',
160 '/init_site_dark_logo/',
161 array(
162 array(
163 'methods' => 'POST',
164 'callback' => array( $this, 'init_site_dark_logo_callback' ),
165 'permission_callback' => function () {
166 return current_user_can( 'edit_others_posts' );
167 },
168 'args' => array(),
169 ),
170 )
171 );
172 register_rest_route(
173 'ultp/v2',
174 '/get_ultp_image_size/',
175 array(
176 array(
177 'methods' => 'POST',
178 'callback' => array( $this, 'get_custom_image_size' ),
179 'permission_callback' => function () {
180 return current_user_can( 'edit_posts' );
181 },
182 'args' => array(),
183 ),
184 )
185 );
186 }
187
188 /**
189 * Save and get premade_wishlist_save
190 *
191 * Handle REST API request.
192 *
193 * @since 4.0.0
194 * @param ARRAY $server $request The REST request object.
195 * @return array The response data.
196 */
197 public function premade_wishlist_save( $server ) {
198 $post = $server->get_params();
199 $id = isset( $post['id'] ) ? ultimate_post()->ultp_rest_sanitize_params( $post['id'] ) : '';
200 $action = isset( $post['action'] ) ? ultimate_post()->ultp_rest_sanitize_params( $post['action'] ) : '';
201 $wishListArr = get_option( 'ultp_premade_wishlist', array() );
202 $request_type = isset( $post['type'] ) ? ultimate_post()->ultp_rest_sanitize_params( $post['type'] ) : '';
203
204 if ( $id && $request_type != 'fetchData' ) {
205 if ( $action == 'remove' ) {
206 $index = array_search( $id, $wishListArr );
207 if ( $index !== false ) {
208 unset( $wishListArr[ $index ] );
209 }
210 } elseif ( ! in_array( $id, $wishListArr ) ) {
211 array_push( $wishListArr, $id );
212 }
213 update_option( 'ultp_premade_wishlist', $wishListArr );
214 }
215 return rest_ensure_response(
216 array(
217 'success' => true,
218 'message' => $action == 'remove' ? __( 'Item has been removed from wishlist.', 'ultimate-post' ) : __( 'Item added to wishlist.', 'ultimate-post' ),
219 'wishListArr' => wp_json_encode( $wishListArr ),
220 )
221 );
222 }
223
224
225
226 /**
227 * Search_settings_action
228 *
229 * @param mixed $server .
230 * @return array
231 */
232 public function search_settings_action( $server ) {
233 global $wpdb;
234 $post = $server->get_params();
235 $request_type = isset( $post['type'] ) ? ultimate_post()->ultp_rest_sanitize_params( $post['type'] ) : '';
236 $condition_type = isset( $post['condition'] ) ? ultimate_post()->ultp_rest_sanitize_params( $post['condition'] ) : '';
237 $term_type = isset( $post['term'] ) ? ultimate_post()->ultp_rest_sanitize_params( $post['term'] ) : '';
238 // get post type
239 $get_multiple_post_type = isset( $post['postType'] ) ? ultimate_post()->ultp_rest_sanitize_params( $post['postType'] ) : array();
240 $multiple_post_type = is_array( $get_multiple_post_type ) ? $get_multiple_post_type : json_decode( $get_multiple_post_type, true );
241 $split = explode( '###', $condition_type );
242 $post_type_condition = array();
243 if ( $split[0] == 'customPostType' && count( $multiple_post_type ) ) {
244 $post_type_condition = get_object_taxonomies( $multiple_post_type );
245 }
246
247 switch ( $request_type ) {
248 case 'posts':
249 case 'allpost':
250 case 'postExclude':
251 $post_type = array( 'post' );
252 if ( $request_type == 'allpost' || $condition_type == 'customPostType' ) {
253 $post_type = array_keys( ultimate_post()->get_post_type() );
254 } elseif ( $request_type == 'postExclude' && $condition_type != 'customPostType' ) {
255 $post_type = array( $condition_type );
256 }
257 $args = array(
258 'post_type' => $post_type,
259 'post_status' => 'publish',
260 'posts_per_page' => 10,
261 );
262 if ( is_numeric( $term_type ) ) {
263 $args['p'] = $term_type;
264 } else {
265 $args['s'] = $term_type;
266 }
267
268 $post_results = new \WP_Query( $args );
269 $data = array();
270 if ( ! empty( $post_results ) ) {
271 while ( $post_results->have_posts() ) {
272 $post_results->the_post();
273 $id = get_the_ID();
274 $title = html_entity_decode( get_the_title() );
275 $data[] = array(
276 'value' => $id,
277 'title' => ( $title ? '[ID: ' . $id . '] ' . $title : ( '[ID: ' . $id . ']' ) ),
278 );
279 }
280 wp_reset_postdata();
281 }
282 return array(
283 'success' => true,
284 'data' => $data,
285 );
286 break;
287
288 case 'author':
289 $term = '%' . $wpdb->esc_like( $term_type ) . '%';
290 $post_results = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
291 $wpdb->prepare(
292 "SELECT ID, display_name
293 FROM $wpdb->users
294 WHERE user_login LIKE %s OR ID LIKE %s OR user_nicename LIKE %s OR user_email LIKE %s OR display_name LIKE %s LIMIT 10",
295 $term,
296 $term,
297 $term,
298 $term,
299 $term
300 )
301 );
302 $data = array();
303 if ( ! empty( $post_results ) ) {
304 foreach ( $post_results as $key => $val ) {
305 $data[] = array(
306 'value' => $val->ID,
307 'title' => '[ID: ' . $val->ID . '] ' . $val->display_name,
308 );
309 }
310 }
311 return array(
312 'success' => true,
313 'data' => $data,
314 );
315 break;
316
317 case 'taxvalue':
318 $split = explode( '###', $condition_type );
319 $condition = $split[1] != 'multiTaxonomy' ? array( $split[1] ) : get_object_taxonomies( $split[0] );
320
321 if ( $post_type_condition && count( $post_type_condition ) ) {
322 $condition = $post_type_condition;
323 }
324
325 $args = array(
326 'taxonomy' => $condition,
327 'fields' => 'all',
328 'orderby' => 'id',
329 'order' => 'ASC',
330 'name__like' => $term_type,
331 );
332 if ( is_numeric( $term_type ) ) {
333 unset( $args['name__like'] );
334 $args['include'] = array( $term_type );
335 }
336
337 $post_results = get_terms( $args );
338 $data = array();
339 if ( ! empty( $post_results ) ) {
340 foreach ( $post_results as $key => $val ) {
341 if ( $split[1] == 'multiTaxonomy' ) {
342 $data[] = array(
343 'value' => $val->taxonomy . '###' . $val->slug,
344 'title' => '[ID: ' . $val->term_id . '] ' . $val->taxonomy . ': ' . $val->name,
345 );
346 } else {
347 $data[] = array(
348 'value' => urldecode( $val->slug ),
349 'title' => '[ID: ' . $val->term_id . '] ' . $val->name,
350 'live_title' => $val->name,
351 );
352 }
353 }
354 }
355 return array(
356 'success' => true,
357 'data' => $data,
358 );
359 break;
360
361 case 'taxExclude':
362 $condition = get_object_taxonomies( $condition_type );
363 if ( $post_type_condition && count( $post_type_condition ) ) {
364 $condition = $post_type_condition;
365 }
366 $args = array(
367 'taxonomy' => $condition,
368 'fields' => 'all',
369 'orderby' => 'id',
370 'order' => 'ASC',
371 'name__like' => $term_type,
372 );
373 if ( is_numeric( $term_type ) ) {
374 unset( $args['name__like'] );
375 $args['include'] = array( $term_type );
376 }
377 $post_results = get_terms( $args );
378 $data = array();
379 if ( ! empty( $post_results ) ) {
380 foreach ( $post_results as $key => $val ) {
381 $data[] = array(
382 'value' => $val->taxonomy . '###' . $val->slug,
383 'title' => '[ID: ' . $val->term_id . '] ' . $val->taxonomy . ': ' . $val->name,
384 );
385 }
386 }
387 return array(
388 'success' => true,
389 'data' => $data,
390 );
391 break;
392 // allPostType
393 case 'allPostType':
394 $all_types = array_values( get_post_types( array( 'public' => true ), 'names' ) );
395 $postType = array();
396 foreach ( $all_types as $type ) {
397 $postType[] = array(
398 'title' => $type,
399 'value' => $type,
400 );
401 }
402
403 return array(
404 'success' => true,
405 'data' => $postType,
406 );
407 default:
408 return array(
409 'success' => true,
410 'data' => array(
411 array(
412 'value' => '',
413 'title' => '- Select -',
414 ),
415 ),
416 );
417 break;
418 }
419 }
420
421 /**
422 * Post Data Response of REST API
423 *
424 * @since v.1.0.0
425 * @param MIXED | $prams (ARRAY), Local (BOOLEAN).
426 * @return ARRAY | Response Image Size as Array
427 */
428 public function ultp_route_post_data( $prams ) {
429 $prams = $prams->get_params();
430 if ( ! ( isset( $prams['wpnonce'] ) && wp_verify_nonce( sanitize_key( wp_unslash( $prams['wpnonce'] ) ), 'ultp-nonce' ) ) ) {
431 die();
432 }
433 $data = array();
434 $loop = new \WP_Query( ultimate_post()->get_query( ultimate_post()->ultp_rest_sanitize_params( $prams ) ) );
435 $max_tax = isset( $prams['maxTaxonomy'] ) && $prams['maxTaxonomy'] ? ( ultimate_post()->ultp_rest_sanitize_params( $prams['maxTaxonomy'] ) == '0' ? 0 : ultimate_post()->ultp_rest_sanitize_params( $prams['maxTaxonomy'] ) ) : 30;
436
437 if ( $loop->have_posts() ) {
438 while ( $loop->have_posts() ) {
439 $loop->the_post();
440 $var = array();
441 $post_id = get_the_ID();
442 $user_id = get_the_author_meta( 'ID' );
443 $content_data = get_the_content();
444 $var['ID'] = $post_id;
445 $var['title'] = get_the_title();
446 $var['permalink'] = get_permalink();
447 $var['seo_meta'] = ultimate_post()->get_excerpt( $post_id, 1 );
448 $var['excerpt'] = wp_strip_all_tags( get_the_excerpt() );
449 $var['excerpt_full'] = wp_strip_all_tags( get_the_excerpt() );
450 $var['time'] = (int) get_the_date( 'U' ) * 1000;
451 $var['timeModified'] = (int) get_the_modified_date( 'U' ) * 1000;
452 $var['post_time'] = human_time_diff( get_the_time( 'U' ), current_time( 'U' ) );
453 $var['view'] = get_post_meta( get_the_ID(), '__post_views_count', true );
454 $var['comments'] = get_comments_number();
455 $var['author_link'] = get_author_posts_url( $user_id );
456 $var['avatar_url'] = get_avatar_url( $user_id );
457 $var['display_name'] = get_the_author_meta( 'display_name' );
458 $var['reading_time'] = ceil( strlen( $content_data ) / 1200 );
459 $var['acf'] = null;
460
461 if ( function_exists( 'get_field_objects' ) ) {
462 $var['acf'] = get_field_objects();
463 }
464
465 $post_video = get_post_meta( $post_id, '__builder_feature_video', true );
466 // Video.
467 if ( $post_video ) {
468 $var['has_video'] = ultimate_post()->get_youtube_id( $post_video );
469 }
470 // image.
471 $image_sizes = ultimate_post()->get_image_size();
472 $image_src = array();
473 if ( has_post_thumbnail() ) {
474 $thumb_id = get_post_thumbnail_id( $post_id );
475 foreach ( $image_sizes as $key => $value ) {
476 $image = wp_get_attachment_image_src( $thumb_id, $key, false );
477 if ( $image && is_array( $image ) ) {
478 $image_src[ $key ] = $image[0];
479 }
480 }
481 $var['image'] = $image_src;
482 } elseif ( isset( $prams['fallbackImg']['id'] ) ) {
483 foreach ( $image_sizes as $key => $value ) {
484 $image_src[ $key ] = wp_get_attachment_image_src( esc_attr( $prams['fallbackImg']['id'] ), $key, false )[0];
485 }
486 $var['image'] = $image_src;
487 $var['is_fallback'] = true;
488 }
489
490 // tag.
491 $tag = get_the_terms( $post_id, ( isset( $prams['tag'] ) ? esc_attr( $prams['tag'] ) : 'post_tag' ) );
492 if ( ! empty( $tag ) ) {
493 $v = array();
494 foreach ( $tag as $k => $val ) {
495 if ( $k >= $max_tax ) {
496 break; }
497 $v[] = array(
498 'slug' => $val->slug,
499 'name' => $val->name,
500 'url' => get_term_link( $val->term_id ),
501 );
502 }
503 $var['tag'] = $v;
504 }
505
506 // Taxonomy.
507 $cat = get_the_terms( $post_id, ( isset( $prams['taxonomy'] ) ? esc_attr( $prams['taxonomy'] ) : 'category' ) );
508
509 if ( ! empty( $cat ) ) {
510 $v = array();
511 foreach ( $cat as $k => $val ) {
512 if ( $k >= $max_tax ) {
513 break; }
514 $v[] = array(
515 'slug' => $val->slug,
516 'name' => $val->name,
517 'url' => get_term_link( $val->term_id ),
518 'color' => get_term_meta( $val->term_id, 'ultp_category_color', true ),
519 );
520 }
521 $var['category'] = $v;
522 }
523 $data[] = $var;
524 }
525 wp_reset_postdata();
526 }
527 return rest_ensure_response( $data );
528 }
529
530
531 /**
532 * STaxonomy Data Response of REST API
533 *
534 * @since v.1.0.0
535 * @param ARRAY | $prams (ARRAY).
536 * @return ARRAY | Response Taxonomy List as Array
537 */
538 public function ultp_route_common_data( $prams ) {
539 if ( ! ( isset( $_REQUEST['wpnonce'] ) && wp_verify_nonce( sanitize_key( wp_unslash( $_REQUEST['wpnonce'] ) ), 'ultp-nonce' ) ) ) {
540 return rest_ensure_response( array() );
541 }
542
543 $all_post_type = ultimate_post()->get_post_type();
544 $data = array();
545 foreach ( $all_post_type as $post_type_slug => $post_type ) {
546 $data_term = array();
547 $taxonomies = get_object_taxonomies( $post_type_slug );
548 foreach ( $taxonomies as $key => $taxonomy_slug ) {
549 $taxonomy_value = get_terms(
550 array(
551 'taxonomy' => $taxonomy_slug,
552 'hide_empty' => false,
553 )
554 );
555 if ( ! is_wp_error( $taxonomy_value ) ) {
556 $data_tax = array();
557 foreach ( $taxonomy_value as $k => $taxonomy ) {
558 $data_tax[ urldecode_deep( $taxonomy->slug ) ] = $taxonomy->name;
559 }
560 if ( count( $data_tax ) > 0 ) {
561 $data_term[ $taxonomy_slug ] = $data_tax;
562 }
563 }
564 }
565 $data[ $post_type_slug ] = $data_term;
566 }
567 // Global Customizer.
568 $global = get_option( 'postx_global', array() );
569 // Image Size.
570 $image_sizes = ultimate_post()->get_image_size();
571
572 return rest_ensure_response(
573 array(
574 'taxonomy' => $data,
575 'global' => $global,
576 'image' => wp_json_encode( $image_sizes ),
577 'posttype' => wp_json_encode( $all_post_type ),
578 )
579 );
580 }
581
582 /**
583 * Specific Taxonomy Data Response of REST API
584 *
585 * @since v.1.0.0
586 * @param ARRAY | $prams .
587 * @return ARRAY | Response Taxonomy List as Array
588 */
589 public function ultp_route_taxonomy_info_data( $prams ) {
590 $prams = $prams->get_params();
591 if ( ! ( isset( $prams['wpnonce'] ) && wp_verify_nonce( sanitize_key( wp_unslash( $prams['wpnonce'] ) ), 'ultp-nonce' ) ) ) {
592 return rest_ensure_response( array() );
593 }
594 $taxValue = isset( $prams['taxValue'] ) ? ultimate_post()->ultp_rest_sanitize_params( $prams['taxValue'] ) : '';
595 $queryNumber = isset( $prams['queryNumber'] ) ? ultimate_post()->ultp_rest_sanitize_params( $prams['queryNumber'] ) : '';
596 $taxType = isset( $prams['taxType'] ) ? ultimate_post()->ultp_rest_sanitize_params( $prams['taxType'] ) : '';
597 $taxSlug = isset( $prams['taxSlug'] ) ? ultimate_post()->ultp_rest_sanitize_params( $prams['taxSlug'] ) : '';
598 $archiveBuilder = isset( $prams['archiveBuilder'] ) ? ultimate_post()->ultp_rest_sanitize_params( $prams['archiveBuilder'] ) : '';
599
600 return rest_ensure_response( ultimate_post()->get_category_data( json_decode( $taxValue ), $queryNumber, $taxType, $taxSlug, $archiveBuilder ) );
601 }
602
603 /**
604 * Get Taxonomies for Custom Post Type
605 *
606 * @since v.3.2.8
607 * @param array $prams .
608 * @return array
609 */
610 public function custom_tax_callback( $prams ) {
611
612 $post_types = isset( $prams['postTypes'] ) ? ultimate_post()->ultp_rest_sanitize_params( $prams['postTypes'] ) : array();
613
614 if ( is_string( $post_types ) ) {
615 $post_types = json_decode( $post_types, true );
616 if ( ! is_array( $post_types ) ) {
617 $post_types = array();
618 }
619 }
620
621 $data = array(
622 array(
623 'id' => '_all',
624 'name' => __( 'All', 'ultimate-post' ),
625 ),
626 );
627
628 foreach ( $post_types as $post_type ) {
629 $taxonomies = get_object_taxonomies( $post_type );
630 foreach ( $taxonomies as $taxonomy ) {
631 if ( 'category' !== $taxonomy && 'post_tag' !== $taxonomy ) {
632 $terms = get_terms(
633 array(
634 'taxonomy' => $taxonomy,
635 'hide_empty' => false,
636 )
637 );
638 foreach ( $terms as $term ) {
639 $data[] = array(
640 'id' => $term->slug,
641 'name' => $term->name,
642 );
643 }
644 }
645 }
646 }
647
648 return rest_ensure_response( $data );
649 }
650
651 /**
652 * Search Block Data Showing
653 *
654 * @since v.2.9.9
655 * @param STRING | $server .
656 * @return ARRAY | Inserted Post Url
657 */
658 public function ultp_search_result( $server ) {
659 $post = $server->get_params();
660 $searchText = isset( $post['searchText'] ) ? ultimate_post()->ultp_rest_sanitize_params( $post['searchText'] ) : '';
661 $paged = isset( $post['paged'] ) ? ultimate_post()->ultp_rest_sanitize_params( $post['paged'] ) : '';
662 $postPerPage = isset( $post['postPerPage'] ) ? ultimate_post()->ultp_rest_sanitize_params( $post['postPerPage'] ) : '';
663
664 // Public route: cap posts_per_page so -1 can never mean "unlimited".
665 // 0 survives the cap, and WP_Query resolves it to the posts_per_page option.
666 $postPerPage = min( absint( $postPerPage ), self::SEARCH_POSTS_PER_PAGE_MAX );
667 // is_scalar first: searchText arrives as an array if the caller sends one, and
668 // casting that to string is an "Array to string conversion" warning.
669 $searchText = is_scalar( $searchText ) ? mb_substr( (string) $searchText, 0, self::SEARCH_TEXT_MAX_LENGTH ) : '';
670
671 $query_args = array(
672 's' => $searchText,
673 'paged' => $paged,
674 'orderby' => 'relevance',
675 'posts_per_page' => $postPerPage,
676 );
677 if ( isset( $post['exclude'] ) && is_array( $post['exclude'] ) && count( $post['exclude'] ) > 0 ) {
678 $all_types = get_post_types( array( 'public' => true ), 'names' );
679 $post_exclude = array();
680
681 // Bound before sanitising: this route is public, and sanitising an array
682 // whose length the caller picks is itself the attack. Excluding more post
683 // types than exist is meaningless, so nothing valid is dropped.
684 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Length is bounded here only; every element is sanitized below before use.
685 $exclude_input = array_slice( $post['exclude'], 0, count( $all_types ) );
686
687 foreach ( $exclude_input as $data ) {
688 // A flat array of strings would index a string here and warn.
689 if ( ! is_array( $data ) || ! isset( $data['title'] ) || ! is_scalar( $data['title'] ) ) {
690 continue;
691 }
692 $exclude_type = sanitize_text_field( $data['title'] );
693 $post_exclude[ $exclude_type ] = $exclude_type;
694 }
695
696 $query_args['post_type'] = array_diff_key( $all_types, $post_exclude );
697 }
698 $output = '';
699 $query_result = new \WP_Query( $query_args );
700
701 /**
702 * Resolved once here rather than guarded at each use, since the request may
703 * omit any of them. The loose == is deliberate: the two callers disagree on
704 * type -- the editor sends real booleans, the frontend sends 1/0 parsed out
705 * of data attributes -- and both must keep working.
706 */
707 $show_image = isset( $post['image'] ) && $post['image'] == 1;
708 $show_category = isset( $post['category'] ) && $post['category'] == 1;
709 $show_author = isset( $post['author'] ) && $post['author'] == 1;
710 $show_date = isset( $post['date'] ) && $post['date'] == 1;
711 $show_excerpt = isset( $post['excerpt'] ) && $post['excerpt'] == 1;
712 $excerpt_limit = isset( $post['excerptLimit'] )
713 ? min( absint( $post['excerptLimit'] ), self::SEARCH_EXCERPT_WORDS_MAX )
714 : 55;
715
716 if ( $query_result->have_posts() ) {
717 while ( $query_result->have_posts() ) {
718 $query_result->the_post();
719 $post_id = get_the_ID();
720 $title = get_the_title();
721
722 $output .= '<div class="ultp-search-result__item">';
723
724 if ( $show_image && has_post_thumbnail() ) {
725 // has_post_thumbnail() only proves the _thumbnail_id meta exists.
726 // If the attachment behind it was deleted, src() returns false.
727 $thumb = wp_get_attachment_image_src( get_post_thumbnail_id( $post_id ), 'thumbnail', false );
728 if ( ! empty( $thumb[0] ) ) {
729 $output .= '<img class="ultp-searchresult-image" src="' . esc_url( $thumb[0] ) . '" alt="' . esc_attr( $title ) . '"/>';
730 }
731 }
732
733 $output .= '<div class="ultp-searchresult-content">';
734 $output .= '<div class="ultp-rescontent-meta">';
735
736 // Category.
737 $post_cat = get_the_terms( $post_id, 'category' );
738 if ( $show_category && $post_cat && ! is_wp_error( $post_cat ) ) {
739 $output .= '<div class="ultp-searchresult-category">';
740 foreach ( $post_cat as $cat ) {
741 $term_link = get_term_link( $cat->term_id );
742 if ( is_wp_error( $term_link ) ) {
743 continue;
744 }
745 $output .= '<a href="' . esc_url( $term_link ) . '">' . esc_html( $cat->name ) . '</a>';
746 }
747 $output .= '</div>';
748 }
749
750 // Author.
751 if ( $show_author ) {
752 $user_id = get_the_author_meta( 'ID' );
753 $output .= '<a href="' . esc_url( get_author_posts_url( $user_id ) ) . '" class="ultp-searchresult-author">' . esc_html( get_the_author_meta( 'display_name' ) ) . '</a>';
754 }
755
756 // Date.
757 if ( $show_date ) {
758 $output .= '<div class="ultp-searchresult-publishdate">' . esc_html( get_the_date( 'F j, Y' ) ) . '</div>';
759 }
760
761 $output .= '</div>';
762 $output .= '<a href="' . esc_url( get_permalink() ) . '" class="ultp-searchresult-title">' . esc_html( $title ) . '</a>';
763
764 if ( $show_excerpt ) {
765 // wp_trim_words() strips tags, so what comes back is plain text.
766 $output .= '<div class="ultp-searchresult-excerpt">' . esc_html( wp_trim_words( get_the_excerpt(), $excerpt_limit ) ) . '</div>';
767 }
768
769 $output .= '</div>';
770 $output .= '</div>';
771 }
772 // the_post() overwrote the global $post; hand it back.
773 wp_reset_postdata();
774 }
775
776 return array(
777 'post_data' => $output,
778 'post_count' => $query_result->found_posts,
779 );
780 }
781
782 /**
783 * PostX Site Dark Logo Init
784 *
785 * @since v.3.1.9
786 * @param ARRAY | $server .
787 * @return BOOOLEAN | Inserted Post Url
788 */
789 public function init_site_dark_logo_callback( $server ) {
790 $logo_data = $server->get_params();
791 $success = true;
792 if ( isset( $logo_data['logo']['url'] ) ) {
793 update_option( 'ultp_site_dark_logo', $logo_data['logo']['url'] );
794 } else {
795 $success = false;
796 }
797 return rest_ensure_response(
798 array(
799 'success' => $success,
800 )
801 );
802 }
803
804
805 /**
806 * Getting Image Size
807 *
808 * @since v.4.0.1
809 * @param ARRAY | $server (number) .
810 * @return ARRAY | Image Size List as Array
811 */
812 public function get_custom_image_size( $server ) {
813 $img = $server->get_params();
814 $image_src = array();
815 $image_sizes = ultimate_post()->get_image_size();
816 foreach ( $image_sizes as $key => $value ) {
817 $image_src[ $key ] = wp_get_attachment_image_src( $img['id'], $key, false )[0];
818 }
819 return rest_ensure_response(
820 array(
821 'success' => true,
822 'size' => $image_src,
823 'id' => $img,
824 )
825 );
826 }
827 }
828