PluginProbe
ElasticPress / 4.7.1
ElasticPress v4.7.1
5.3.5 5.3.4 3.6.5 3.6.6 4.0.0 4.0.1 4.1.0 4.2.0 4.2.1 4.2.2 4.3.0 4.3.1 4.4.0 4.4.1 4.5.0 4.5.1 4.5.2 4.6.0 4.6.1 4.7.0 4.7.1 4.7.2 5.0.0 5.0.1 5.0.2 All 108 releases
elasticpress / includes / classes / Indexable / Comment / Comment.php

Comment.php in ElasticPress 4.7.1, at includes/classes/Indexable/Comment/Comment.php

1,089 lines 26.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Comment indexable
4 *
5 * @since 3.6.0
6 * @package elasticpress
7 */
8
9 namespace ElasticPress\Indexable\Comment;
10
11 use ElasticPress\Indexable as Indexable;
12 use ElasticPress\Indexables as Indexables;
13 use ElasticPress\Elasticsearch as Elasticsearch;
14 use ElasticPress\Indexable\Post\DateQuery as DateQuery;
15 use \WP_Comment_Query as WP_Comment_Query;
16 use ElasticPress\Features as Features;
17
18 if ( ! defined( 'ABSPATH' ) ) {
19 exit; // Exit if accessed directly.
20 }
21
22 /**
23 * Comment indexable class
24 */
25 class Comment extends Indexable {
26
27 /**
28 * Indexable slug
29 *
30 * @var string
31 * @since 3.6.0
32 */
33 public $slug = 'comment';
34
35 /**
36 * Create indexable and initialize dependencies
37 *
38 * @since 3.6.0
39 */
40 public function __construct() {
41 $this->labels = [
42 'plural' => esc_html__( 'Comments', 'elasticpress' ),
43 'singular' => esc_html__( 'Comment', 'elasticpress' ),
44 ];
45 }
46
47 /**
48 * Instantiate the indexable SyncManager and QueryIntegration, the main responsibles for the WP integration.
49 *
50 * @since 4.5.0
51 * @return void
52 */
53 public function setup() {
54 $this->sync_manager = new SyncManager( $this->slug );
55 $this->query_integration = new QueryIntegration();
56 }
57
58 /**
59 * Format query vars into ES query
60 *
61 * @param array $query_vars WP_Comment_Query args.
62 * @since 3.6.0
63 * @return array
64 */
65 public function format_args( $query_vars ) {
66 /**
67 * Support `number` query var
68 */
69 if ( ! empty( $query_vars['number'] ) ) {
70 $number = (int) $query_vars['number'];
71 } else {
72 /**
73 * Set the maximum results window size.
74 *
75 * The request will return a HTTP 500 Internal Error if the size of the
76 * request is larger than the [index.max_result_window] parameter in ES.
77 * See the scroll api for a more efficient way to request large data sets.
78 *
79 * @return int The max results window size.
80 *
81 * @since 2.3.0
82 */
83 $number = apply_filters( 'ep_max_results_window', 10000 );
84 }
85
86 $formatted_args = [
87 'from' => 0,
88 'size' => $number,
89 ];
90
91 /**
92 * Support `offset` query var
93 */
94 if ( isset( $query_vars['offset'] ) ) {
95 $formatted_args['from'] = (int) $query_vars['offset'];
96 if ( empty( $query_vars['number'] ) ) {
97 $formatted_args['size'] -= (int) $formatted_args['from'];
98 }
99 }
100
101 /**
102 * Support `paged` query var
103 *
104 * If `offset` is used, that takes precendence
105 * over this.
106 */
107 if ( isset( $query_vars['paged'] ) && empty( $query_vars['offset'] ) && $query_vars['paged'] > 1 ) {
108 $formatted_args['from'] = $number * ( $query_vars['paged'] - 1 );
109 }
110
111 /**
112 * Support `order` and `orderby` query vars
113 */
114
115 // Set sort order, default is 'desc'.
116 if ( ! empty( $query_vars['order'] ) ) {
117 $order = $this->parse_order( $query_vars['order'] );
118 } else {
119 $order = 'desc';
120 }
121
122 // Default sort by comment date
123 if ( empty( $query_vars['orderby'] ) ) {
124 $query_vars['orderby'] = 'comment_date_gmt';
125 }
126
127 // Set sort type.
128 $formatted_args['sort'] = $this->parse_orderby( $query_vars['orderby'], $order, $query_vars );
129
130 $filter = [
131 'bool' => [
132 'must' => [],
133 ],
134 ];
135
136 $use_filters = false;
137
138 /**
139 * Support `author_email` query var
140 */
141 if ( ! empty( $query_vars['author_email'] ) ) {
142 $filter['bool']['must'][] = [
143 'term' => [
144 'comment_author_email.raw' => $query_vars['author_email'],
145 ],
146 ];
147
148 $use_filters = true;
149 }
150
151 /**
152 * Support `author_url` query var
153 */
154 if ( ! empty( $query_vars['author_url'] ) ) {
155 $filter['bool']['must'][] = [
156 'term' => [
157 'comment_author_url.raw' => $query_vars['author_url'],
158 ],
159 ];
160
161 $use_filters = true;
162 }
163
164 /**
165 * Support `user_id` query var
166 */
167 if ( ! empty( $query_vars['user_id'] ) ) {
168 $filter['bool']['must'][] = [
169 'term' => [
170 'user_id' => (int) $query_vars['user_id'],
171 ],
172 ];
173
174 $use_filters = true;
175 }
176
177 /**
178 * Support `author__in` query var
179 */
180 if ( ! empty( $query_vars['author__in'] ) ) {
181 $filter['bool']['must'][]['bool']['must'] = [
182 'terms' => [
183 'user_id' => array_values( (array) $query_vars['author__in'] ),
184 ],
185 ];
186
187 $use_filters = true;
188 }
189
190 /**
191 * Support `author__not_in` query var
192 */
193 if ( ! empty( $query_vars['author__not_in'] ) ) {
194 $filter['bool']['must'][]['bool']['must_not'] = [
195 'terms' => [
196 'user_id' => array_values( (array) $query_vars['author__not_in'] ),
197 ],
198 ];
199
200 $use_filters = true;
201 }
202
203 /**
204 * Support `comment__in` query var
205 */
206 if ( ! empty( $query_vars['comment__in'] ) ) {
207 $filter['bool']['must'][]['bool']['must'] = [
208 'terms' => [
209 'comment_ID' => array_values( (array) $query_vars['comment__in'] ),
210 ],
211 ];
212
213 $use_filters = true;
214 }
215
216 /**
217 * Support `comment__not_in` query var
218 */
219 if ( ! empty( $query_vars['comment__not_in'] ) ) {
220 $filter['bool']['must'][]['bool']['must_not'] = [
221 'terms' => [
222 'comment_ID' => array_values( (array) $query_vars['comment__not_in'] ),
223 ],
224 ];
225
226 $use_filters = true;
227 }
228
229 /**
230 * Support `date_query` query var
231 */
232 if ( ! empty( $query_vars['date_query'] ) ) {
233 $date_query = new DateQuery( $query_vars['date_query'] );
234 $date_filter = $date_query->get_es_filter();
235
236 if ( array_key_exists( 'and', $date_filter ) ) {
237 $filter['bool']['must'][] = $date_filter['and'];
238 $use_filters = true;
239 }
240 }
241
242 /**
243 * Support `fields` query var.
244 */
245 if ( isset( $query_vars['fields'] ) ) {
246 switch ( $query_vars['fields'] ) {
247 case 'ids':
248 $formatted_args['_source'] = [
249 'includes' => [
250 'comment_ID',
251 ],
252 ];
253 break;
254 }
255 }
256
257 /**
258 * Support `karma` query var.
259 */
260 if ( ! empty( $query_vars['karma'] ) || 0 === $query_vars['karma'] ) {
261 $filter['bool']['must'][]['bool']['must'] = [
262 'term' => [
263 'comment_karma' => $query_vars['karma'],
264 ],
265 ];
266
267 $use_filters = true;
268 }
269
270 $meta_queries = [];
271
272 /**
273 * Support `meta_key` and `meta_value` query args
274 */
275 if ( ! empty( $query_vars['meta_key'] ) ) {
276 $meta_query_array = [
277 'key' => $query_vars['meta_key'],
278 ];
279
280 if ( isset( $query_vars['meta_value'] ) ) {
281 $meta_query_array['value'] = $query_vars['meta_value'];
282 }
283
284 $meta_queries[] = $meta_query_array;
285 }
286
287 /**
288 * Support 'meta_query' query var.
289 */
290 if ( ! empty( $query_vars['meta_query'] ) ) {
291 $meta_queries = array_merge( $meta_queries, $query_vars['meta_query'] );
292 }
293
294 if ( ! empty( $meta_queries ) ) {
295 $built_meta_queries = $this->build_meta_query( $meta_queries );
296
297 if ( $built_meta_queries ) {
298 $filter['bool']['must'][] = $built_meta_queries;
299 $use_filters = true;
300 }
301 }
302
303 /**
304 * Support `hierarchical` query var
305 */
306 if ( ! empty( $query_vars['hierarchical'] ) && empty( $query_vars['parent'] ) ) {
307 $query_vars['parent'] = 0;
308 }
309
310 /**
311 * Support `parent` query var.
312 */
313 if ( ! empty( $query_vars['parent'] ) || 0 === $query_vars['parent'] ) {
314 $filter['bool']['must'][]['bool']['must'] = [
315 'term' => [
316 'comment_parent' => (int) $query_vars['parent'],
317 ],
318 ];
319
320 $use_filters = true;
321 }
322
323 /**
324 * Support `parent__in` query var
325 */
326 if ( ! empty( $query_vars['parent__in'] ) ) {
327 $filter['bool']['must'][]['bool']['must'] = [
328 'terms' => [
329 'comment_parent' => array_values( (array) $query_vars['parent__in'] ),
330 ],
331 ];
332
333 $use_filters = true;
334 }
335
336 /**
337 * Support `parent__not_in` query var
338 */
339 if ( ! empty( $query_vars['parent__not_in'] ) ) {
340 $filter['bool']['must'][]['bool']['must_not'] = [
341 'terms' => [
342 'comment_parent' => array_values( (array) $query_vars['parent__not_in'] ),
343 ],
344 ];
345
346 $use_filters = true;
347 }
348
349 /**
350 * Support `post_author` query var.
351 */
352 if ( ! empty( $query_vars['post_author'] ) ) {
353 $filter['bool']['must'][]['bool']['must'] = [
354 'term' => [
355 'comment_post_author_ID' => (int) $query_vars['post_author'],
356 ],
357 ];
358
359 $use_filters = true;
360 }
361
362 /**
363 * Support `post_author__in` query var
364 */
365 if ( ! empty( $query_vars['post_author__in'] ) ) {
366 $filter['bool']['must'][]['bool']['must'] = [
367 'terms' => [
368 'comment_post_author_ID' => array_values( (array) $query_vars['post_author__in'] ),
369 ],
370 ];
371
372 $use_filters = true;
373 }
374
375 /**
376 * Support `post_author__not_in` query var
377 */
378 if ( ! empty( $query_vars['post_author__not_in'] ) ) {
379 $filter['bool']['must'][]['bool']['must_not'] = [
380 'terms' => [
381 'comment_post_author_ID' => array_values( (array) $query_vars['post_author__not_in'] ),
382 ],
383 ];
384
385 $use_filters = true;
386 }
387
388 /**
389 * Support `post_id` query var.
390 */
391 if ( ! empty( $query_vars['post_id'] ) ) {
392 $filter['bool']['must'][]['bool']['must'] = [
393 'term' => [
394 'comment_post_ID' => (int) $query_vars['post_id'],
395 ],
396 ];
397
398 $use_filters = true;
399 }
400
401 /**
402 * Support `post__in` query var
403 */
404 if ( ! empty( $query_vars['post__in'] ) ) {
405 $filter['bool']['must'][]['bool']['must'] = [
406 'terms' => [
407 'comment_post_ID' => array_values( (array) $query_vars['post__in'] ),
408 ],
409 ];
410
411 $use_filters = true;
412 }
413
414 /**
415 * Support `post__not_in` query var
416 */
417 if ( ! empty( $query_vars['post__not_in'] ) ) {
418 $filter['bool']['must'][]['bool']['must_not'] = [
419 'terms' => [
420 'comment_post_ID' => array_values( (array) $query_vars['post__not_in'] ),
421 ],
422 ];
423
424 $use_filters = true;
425 }
426
427 /**
428 * Support `post_status` query var
429 */
430 if ( ! empty( $query_vars['post_status'] ) && 'any' !== $query_vars['post_status'] ) {
431 $post_status = (array) ( is_string( $query_vars['post_status'] ) ? explode( ',', $query_vars['post_status'] ) : $query_vars['post_status'] );
432 $post_status = array_map( 'trim', $post_status );
433 $terms_map_name = 'terms';
434
435 if ( count( $post_status ) < 2 ) {
436 $terms_map_name = 'term';
437 $post_status = $post_status[0];
438 }
439
440 $filter['bool']['must'][] = array(
441 $terms_map_name => array(
442 'comment_post_status' => $post_status,
443 ),
444 );
445
446 $use_filters = true;
447 }
448
449 /**
450 * Support `post_type` query var.
451 */
452 if ( ! empty( $query_vars['post_type'] ) ) {
453 $filter['bool']['must'][]['bool']['must'] = [
454 'terms' => [
455 'comment_post_type.raw' => array_values( (array) $query_vars['post_type'] ),
456 ],
457 ];
458
459 $use_filters = true;
460 }
461
462 /**
463 * Support `post_name` query var.
464 */
465 if ( ! empty( $query_vars['post_name'] ) ) {
466 $filter['bool']['must'][]['bool']['must'] = [
467 'term' => [
468 'comment_post_name.raw' => $query_vars['post_name'],
469 ],
470 ];
471
472 $use_filters = true;
473 }
474
475 /**
476 * Support `post_parent` query var.
477 */
478 if ( ! empty( $query_vars['post_parent'] ) ) {
479 $filter['bool']['must'][]['bool']['must'] = [
480 'term' => [
481 'comment_post_parent' => (int) $query_vars['post_parent'],
482 ],
483 ];
484
485 $use_filters = true;
486 }
487
488 /**
489 * Support `search` query_var
490 */
491 if ( ! empty( $query_vars['search'] ) ) {
492
493 $search = ! empty( $query_vars['search'] ) ? $query_vars['search'] : '';
494 $search_fields = [];
495
496 /**
497 * Allow for search field specification
498 */
499 if ( ! empty( $query_vars['search_fields'] ) ) {
500 $search_fields = $query_vars['search_fields'];
501 }
502
503 if ( ! empty( $search_fields ) ) {
504 $prepared_search_fields = [];
505
506 if ( ! empty( $search_fields['meta'] ) ) {
507 $metas = (array) $search_fields['meta'];
508
509 foreach ( $metas as $meta ) {
510 $prepared_search_fields[] = 'meta.' . $meta . '.value';
511 }
512
513 unset( $search_fields['meta'] );
514 }
515
516 $prepared_search_fields = array_merge( $search_fields, $prepared_search_fields );
517 } else {
518 $prepared_search_fields = [
519 'comment_author',
520 'comment_author_email',
521 'comment_author_url',
522 'comment_content',
523 ];
524 }
525
526 /**
527 * Filter default comment search fields
528 *
529 * If you are using the weighting engine, this filter should not be used.
530 * Instead, you should use the ep_weighting_configuration_for_search filter.
531 *
532 * @hook ep_comment_search_fields
533 * @since 3.6.0
534 * @param {array} $search_fields Default search fields
535 * @param {array} $query_vars WP_Comment_Query args
536 * @return {array} New defaults
537 */
538 $prepared_search_fields = apply_filters( 'ep_comment_search_fields', $prepared_search_fields, $query_vars );
539
540 $search_algorithm = $this->get_search_algorithm( $search, $prepared_search_fields, $query_vars );
541 $formatted_args['query'] = $search_algorithm->get_query( 'comment', $search, $prepared_search_fields, $query_vars );
542 } else {
543 $formatted_args['query']['match_all'] = [
544 'boost' => 1,
545 ];
546 }
547
548 /**
549 * Support `status` query var
550 */
551 if ( ! empty( $query_vars['status'] ) && 'all' !== $query_vars['status'] ) {
552 $comment_stati = (array) ( is_string( $query_vars['status'] ) ? explode( ',', $query_vars['status'] ) : $query_vars['status'] );
553 $comment_stati = array_map( 'trim', $comment_stati );
554
555 foreach ( $comment_stati as $key => $status ) {
556 if ( 'hold' === $status ) {
557 $comment_stati[ $key ] = 0;
558 }
559
560 if ( 'approve' === $status ) {
561 $comment_stati[ $key ] = 1;
562 }
563 }
564
565 $terms_map_name = 'terms';
566
567 if ( count( $comment_stati ) < 2 ) {
568 $terms_map_name = 'term';
569 $comment_stati = $comment_stati[0];
570 }
571
572 /**
573 * Support `include_unapproved` query var
574 */
575 if ( ! empty( $query_vars['include_unapproved'] ) ) {
576 $include_unapproved = wp_parse_list( $query_vars['include_unapproved'] );
577 $unapproved_ids = [];
578 $unapproved_emails = [];
579
580 foreach ( $include_unapproved as $unapproved_identifier ) {
581 // Numeric values are assumed to be user ids.
582 if ( is_numeric( $unapproved_identifier ) ) {
583 $unapproved_ids[] = $unapproved_identifier;
584
585 // Otherwise we assume it's an email address.
586 } else {
587 $unapproved_emails[] = $unapproved_identifier;
588 }
589 }
590
591 $filter['bool']['must'][]['bool']['should'] = [
592 [
593 $terms_map_name => [
594 'comment_approved' => $comment_stati,
595 ],
596 ],
597 [
598 'terms' => [
599 'user_id' => array_values( array_map( 'absint', $unapproved_ids ) ),
600 ],
601 ],
602 [
603 'terms' => [
604 'comment_author_email.raw' => array_values( $unapproved_emails ),
605 ],
606 ],
607 ];
608 } else {
609 $filter['bool']['must'][] = [
610 $terms_map_name => [
611 'comment_approved' => $comment_stati,
612 ],
613 ];
614 }
615
616 $use_filters = true;
617 }
618
619 /**
620 * Support `type` query var
621 */
622 if ( ! empty( $query_vars['type'] ) ) {
623 $types = (array) ( is_string( $query_vars['type'] ) ? explode( ',', $query_vars['type'] ) : $query_vars['type'] );
624 $types = array_map( 'trim', $types );
625
626 $terms_map_name = 'terms';
627
628 if ( count( $types ) < 2 ) {
629 $terms_map_name = 'term';
630 $types = $types[0];
631 }
632
633 $filter['bool']['must'][] = [
634 $terms_map_name => [
635 'comment_type.raw' => $types,
636 ],
637 ];
638
639 $use_filters = true;
640 }
641
642 /**
643 * Support `type__in` query var
644 */
645 if ( ! empty( $query_vars['type__in'] ) ) {
646 $filter['bool']['must'][]['bool']['must'] = [
647 'terms' => [
648 'comment_type.raw' => array_values( (array) $query_vars['type__in'] ),
649 ],
650 ];
651
652 $use_filters = true;
653 }
654
655 /**
656 * Support `type__not_in` query var
657 */
658 if ( ! empty( $query_vars['type__not_in'] ) ) {
659 $filter['bool']['must'][]['bool']['must_not'] = [
660 'terms' => [
661 'comment_type.raw' => array_values( (array) $query_vars['type__not_in'] ),
662 ],
663 ];
664
665 $use_filters = true;
666 }
667
668 if ( $use_filters ) {
669 $formatted_args['post_filter'] = $filter;
670 }
671
672 /**
673 * Filter formatted Elasticsearch query (entire query)
674 *
675 * @hook ep_comment_formatted_args
676 * @since 3.6.0
677 * @param {array} $formatted_args Formatted Elasticsearch query
678 * @param {array} $query_vars WP_Comment_Query args
679 * @return {array} New query
680 */
681 return apply_filters( 'ep_comment_formatted_args', $formatted_args, $query_vars );
682 }
683
684 /**
685 * Generate the mapping array
686 *
687 * @since 4.1.0
688 * @return array
689 */
690 public function generate_mapping() {
691 $es_version = Elasticsearch::factory()->get_elasticsearch_version();
692
693 if ( empty( $es_version ) ) {
694 /**
695 * Filter fallback Elasticsearch version
696 *
697 * @hook ep_fallback_elasticsearch_version
698 * @param {string} $version Fall back Elasticsearch version
699 * @return {string} New version
700 */
701 $es_version = apply_filters( 'ep_fallback_elasticsearch_version', '2.0' );
702 }
703
704 $es_version = (string) $es_version;
705
706 $mapping_file = 'initial.php';
707
708 if ( version_compare( $es_version, '5.0', '<' ) ) {
709 $mapping_file = 'pre-5-0.php';
710 } elseif ( version_compare( $es_version, '7.0', '>=' ) ) {
711 $mapping_file = '7-0.php';
712 }
713
714 /**
715 * Filter comment indexable mapping file
716 *
717 * @hook ep_comment_mapping_file
718 * @since 3.6.0
719 * @param {string} $file Path to file
720 * @return {string} New file path
721 */
722 $mapping = require apply_filters( 'ep_comment_mapping_file', __DIR__ . '/../../../mappings/comment/' . $mapping_file );
723
724 /**
725 * Filter comment indexable mapping
726 *
727 * @hook ep_comment_mapping
728 * @since 3.6.0
729 * @param {array} $mapping Mapping
730 * @return {array} New mapping
731 */
732 $mapping = apply_filters( 'ep_comment_mapping', $mapping );
733
734 return $mapping;
735 }
736
737 /**
738 * Returns indexable comment types
739 *
740 * @since 3.6.0
741 * @return array
742 */
743 public function get_indexable_comment_types() {
744 $comment_types = [ 'comment' ];
745
746 if ( Features::factory()->registered_features['woocommerce']->is_active() ) {
747 $comment_types[] = 'review';
748 }
749
750 /**
751 * Filter indexable comment types
752 *
753 * @hook ep_indexable_comment_types
754 * @since 3.6.0
755 * @param {array} $comment_types Indexable comment types
756 * @return {array} comment types
757 */
758 return apply_filters( 'ep_indexable_comment_types', $comment_types );
759 }
760
761 /**
762 * Returns indexable comment status
763 *
764 * @since 3.6.0
765 * @return array
766 */
767 public function get_indexable_comment_status() {
768 $comment_status = [ '1' ];
769
770 /**
771 * Filter indexable comment status
772 *
773 * @hook ep_indexable_comment_status
774 * @since 3.6.0
775 * @param {array} $comment_status Indexable comment status
776 * @return {array} comment status
777 */
778 return apply_filters( 'ep_indexable_comment_status', $comment_status );
779 }
780
781 /**
782 * Query DB for comments
783 *
784 * @param array $args Query arguments
785 * @since 3.6.0
786 * @return array
787 */
788 public function query_db( $args ) {
789
790 $defaults = [
791 'type' => $this->get_indexable_comment_types(),
792 'status' => $this->get_indexable_comment_status(),
793 'post_type' => Indexables::factory()->get( 'post' )->get_indexable_post_types(),
794 'post_status' => Indexables::factory()->get( 'post' )->get_indexable_post_status(),
795 'number' => $this->get_bulk_items_per_page(),
796 'offset' => 0,
797 'orderby' => 'comment_ID',
798 'order' => 'desc',
799 ];
800
801 if ( isset( $args['per_page'] ) ) {
802 $args['number'] = $args['per_page'];
803 }
804
805 /**
806 * Filter database arguments for comment query
807 *
808 * @hook ep_comment_query_db_args
809 * @param {array} $args Query arguments based to WP_Comment_Query
810 * @since 3.6.0
811 * @return {array} New arguments
812 */
813 $args = apply_filters( 'ep_comment_query_db_args', wp_parse_args( $args, $defaults ) );
814
815 $all_query_args = $args;
816
817 unset( $all_query_args['number'] );
818 unset( $all_query_args['offset'] );
819 $all_query_args['count'] = true;
820
821 /**
822 * Filter database arguments for comment count query
823 *
824 * @hook ep_comment_all_query_db_args
825 * @param {array} $args Query arguments based to WP_Comment_Query
826 * @since 3.6.0
827 * @return {array} New arguments
828 */
829 $total_objects = get_comments( apply_filters( 'ep_comment_all_query_db_args', $all_query_args, $args ) );
830
831 if ( ! empty( $args['offset'] ) ) {
832 if ( (int) $args['offset'] >= $total_objects ) {
833 $total_objects = 0;
834 }
835 }
836
837 $query = new WP_Comment_Query( $args );
838
839 if ( is_array( $query->comments ) ) {
840 array_walk( $query->comments, [ $this, 'remap_comments' ] );
841 }
842
843 return [
844 'objects' => $query->comments,
845 'total_objects' => $total_objects,
846 ];
847 }
848
849 /**
850 * Prepare a comment document for indexing
851 *
852 * @param int $comment_id Comment ID
853 * @since 3.6.0
854 * @return bool|array
855 */
856 public function prepare_document( $comment_id ) {
857 $comment = get_comment( $comment_id );
858
859 if ( ! $comment || ! is_a( $comment, 'WP_Comment' ) ) {
860 return false;
861 }
862
863 $comment_post = get_post( $comment->comment_post_ID );
864
865 $comment_args = [
866 'comment_ID' => $comment->comment_ID,
867 'ID' => $comment->comment_ID,
868 'comment_post_ID' => $comment->comment_post_ID,
869 'comment_post_author_ID' => $comment_post->post_author,
870 'comment_post_status' => $comment_post->post_status,
871 'comment_post_type' => $comment_post->post_type,
872 'comment_post_name' => $comment_post->post_name,
873 'comment_post_parent' => $comment_post->post_parent,
874 'comment_author' => $comment->comment_author,
875 'comment_author_email' => $comment->comment_author_email,
876 'comment_author_url' => $comment->comment_author_url,
877 'comment_author_IP' => $comment->comment_author_IP,
878 'comment_date' => $comment->comment_date,
879 'comment_date_gmt' => $comment->comment_date_gmt,
880 'comment_content' => $comment->comment_content,
881 'comment_karma' => $comment->comment_karma,
882 'comment_approved' => $comment->comment_approved,
883 'comment_agent' => $comment->comment_agent,
884 'comment_type' => $comment->comment_type ? $comment->comment_type : 'comment',
885 'comment_parent' => $comment->comment_parent,
886 'user_id' => $comment->user_id,
887 'meta' => $this->prepare_meta_types( $this->prepare_meta( $comment->comment_ID ) ),
888 ];
889
890 /**
891 * Filter sync arguments for a comment.
892 *
893 * @hook ep_comment_sync_args
894 * @param {array} $comment_args Comment arguments
895 * @param {int} $comment_id Comment ID
896 * @return {array} New arguments
897 */
898 $comment_args = apply_filters( 'ep_comment_sync_args', $comment_args, $comment_id );
899
900 return $comment_args;
901 }
902
903 /**
904 * Rebuild our comment objects to match the fields we need.
905 *
906 * In particular, result of WP_Comment_Query does not
907 * include an "id" field, which our index command
908 * expects.
909 *
910 * @param object $value Comment object
911 * @since 3.6.0
912 * @return void Returns by reference
913 */
914 public function remap_comments( &$value ) {
915 $value = (object) [
916 'ID' => $value->comment_ID,
917 'comment_ID' => $value->comment_ID,
918 'comment_post_ID' => $value->comment_post_ID,
919 'comment_author' => $value->comment_author,
920 'comment_author_email' => $value->comment_author_email,
921 'comment_author_url' => $value->comment_author_url,
922 'comment_author_IP' => $value->comment_author_IP,
923 'comment_date' => $value->comment_date,
924 'comment_date_gmt' => $value->comment_date_gmt,
925 'comment_content' => $value->comment_content,
926 'comment_karma' => $value->comment_karma,
927 'comment_approved' => $value->comment_approved,
928 'comment_agent' => $value->comment_agent,
929 'comment_type' => $value->comment_type,
930 'comment_parent' => $value->comment_parent,
931 'user_id' => $value->user_id,
932 ];
933 }
934
935 /**
936 * Prepare meta to send to ES
937 *
938 * @param int $comment_id Comment ID
939 * @since 3.6.0
940 * @return array
941 */
942 public function prepare_meta( $comment_id ) {
943 $meta = (array) get_comment_meta( $comment_id );
944
945 if ( empty( $meta ) ) {
946 return [];
947 }
948
949 $prepared_meta = [];
950
951 /**
952 * Filter index-able private meta
953 *
954 * Allows for specifying private meta keys that may be indexed in the same manner as public meta keys.
955 *
956 * @since 3.6.0
957 *
958 * @param array Array of index-able private meta keys.
959 * @param int $comment_id Comment ID.
960 */
961 $allowed_protected_keys = apply_filters(
962 'ep_prepare_comment_meta_allowed_protected_keys',
963 [],
964 $comment_id
965 );
966
967 /**
968 * Filter non-indexed public meta
969 *
970 * Allows for specifying public meta keys that should be excluded from the ElasticPress index.
971 *
972 * @since 3.6.0
973 *
974 * @param array Array of public meta keys to exclude from index.
975 * @param int $comment_id Comment ID.
976 */
977 $excluded_public_keys = apply_filters(
978 'ep_prepare_comment_meta_excluded_public_keys',
979 [],
980 $comment_id
981 );
982
983 foreach ( $meta as $key => $value ) {
984
985 $allow_index = false;
986
987 if ( is_protected_meta( $key ) ) {
988
989 if ( true === $allowed_protected_keys || in_array( $key, $allowed_protected_keys, true ) ) {
990 $allow_index = true;
991 }
992 } else {
993
994 if ( true !== $excluded_public_keys && ! in_array( $key, $excluded_public_keys, true ) ) {
995 $allow_index = true;
996 }
997 }
998
999 /**
1000 * Filter force allow a meta key
1001 *
1002 * @hook ep_prepare_comment_meta_allowed_key
1003 * @since 3.6.0
1004 * @param {bool} $allowed True to allow the key
1005 * @param {string} $key Meta key
1006 * @param {int} $comment_id Comment ID
1007 * @return {bool} New allowed value
1008 */
1009 if ( true === $allow_index || apply_filters( 'ep_prepare_comment_meta_allowed_key', false, $key, $comment_id ) ) {
1010 $prepared_meta[ $key ] = maybe_unserialize( $value );
1011 }
1012 }
1013
1014 return $prepared_meta;
1015 }
1016
1017 /**
1018 * Parse an 'order' query variable and cast it to asc or desc as necessary.
1019 *
1020 * @access protected
1021 *
1022 * @param string $order The 'order' query variable.
1023 * @since 3.6.0
1024 * @return string The sanitized 'order' query variable.
1025 */
1026 protected function parse_order( $order ) {
1027 if ( ! is_string( $order ) || empty( $order ) ) {
1028 return 'desc';
1029 }
1030
1031 if ( 'ASC' === strtoupper( $order ) ) {
1032 return 'asc';
1033 } else {
1034 return 'desc';
1035 }
1036 }
1037
1038 /**
1039 * Convert the alias to a properly-prefixed sort value.
1040 *
1041 * @access protected
1042 *
1043 * @param string $orderby Alias or path for the field to order by.
1044 * @param string $order Order direction
1045 * @param array $args Query args
1046 * @since 3.6.0
1047 * @return array
1048 */
1049 protected function parse_orderby( $orderby, $order, $args ) {
1050 $sort = [];
1051
1052 if ( empty( $orderby ) ) {
1053 return $sort;
1054 }
1055
1056 $from_to = [
1057 'comment_agent' => 'comment_agent.raw',
1058 'comment_approved' => 'comment_approved.raw',
1059 'comment_author' => 'comment_author.raw',
1060 'comment_author_email' => 'comment_author_email.raw',
1061 'comment_author_IP' => 'comment_author_IP.raw',
1062 'comment_author_url' => 'comment_author_url.raw',
1063 'comment_content' => 'comment_content.raw',
1064 'comment_type' => 'comment_type.raw',
1065 'comment_post_type' => 'comment_post_type.raw',
1066 ];
1067
1068 if ( in_array( $orderby, [ 'meta_value', 'meta_value_num' ], true ) ) {
1069 if ( empty( $args['meta_key'] ) ) {
1070 return $sort;
1071 } else {
1072 $from_to['meta_value'] = 'meta.' . $args['meta_key'] . '.raw';
1073 $from_to['meta_value_num'] = 'meta.' . $args['meta_key'] . '.long';
1074 }
1075 }
1076
1077 $orderby = $from_to[ $orderby ] ?? $orderby;
1078
1079 $sort[] = array(
1080 $orderby => array(
1081 'order' => $order,
1082 ),
1083 );
1084
1085 return $sort;
1086 }
1087
1088 }
1089