PluginProbe
ElasticPress / 4.4.0
ElasticPress v4.4.0
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.4.0, at includes/classes/Indexable/Comment/Comment.php

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