PluginProbe
ElasticPress / 5.3.5
ElasticPress v5.3.5
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
← All changes | includes/classes/Indexable/Comment/Comment.php +179 -46 4.7.05.3.5 View file →
@@ -7,14 +7,14 @@
7 7 */
8 8
9 9 namespace ElasticPress\Indexable\Comment;
10 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;
11 +use WP_Comment_Query;
12 +use ElasticPress\Elasticsearch;
13 +use ElasticPress\Features;
14 +use ElasticPress\Indexable;
15 +use ElasticPress\Indexable\Post\DateQuery;
16 +use ElasticPress\Indexables;
17 17
18 18 if ( ! defined( 'ABSPATH' ) ) {
19 19 exit; // Exit if accessed directly.
20 20 }
@@ -32,18 +32,15 @@
32 32 */
33 33 public $slug = 'comment';
34 34
35 35 /**
36 - * Create indexable and initialize dependencies
36 + * Flag to indicate if the indexable has support for
37 + * `id_range` pagination method during a sync.
37 38 *
38 - * @since 3.6.0
39 + * @var boolean
40 + * @since 5.2.0
39 41 */
40 - public function __construct() {
41 - $this->labels = [
42 - 'plural' => esc_html__( 'Comments', 'elasticpress' ),
43 - 'singular' => esc_html__( 'Comment', 'elasticpress' ),
44 - ];
45 - }
42 + public $support_indexing_advanced_pagination = true;
46 43
47 44 /**
48 45 * Instantiate the indexable SyncManager and QueryIntegration, the main responsibles for the WP integration.
49 46 *
@@ -50,8 +47,13 @@
50 47 * @since 4.5.0
51 48 * @return void
52 49 */
53 50 public function setup() {
51 + $this->labels = [
52 + 'plural' => esc_html__( 'Comments', 'elasticpress' ),
53 + 'singular' => esc_html__( 'Comment', 'elasticpress' ),
54 + ];
55 +
54 56 $this->sync_manager = new SyncManager( $this->slug );
55 57 $this->query_integration = new QueryIntegration();
56 58 }
57 59
@@ -100,9 +102,9 @@
100 102
101 103 /**
102 104 * Support `paged` query var
103 105 *
104 - * If `offset` is used, that takes precendence
106 + * If `offset` is used, that takes precedence
105 107 * over this.
106 108 */
107 109 if ( isset( $query_vars['paged'] ) && empty( $query_vars['offset'] ) && $query_vars['paged'] > 1 ) {
108 110 $formatted_args['from'] = $number * ( $query_vars['paged'] - 1 );
@@ -702,14 +704,12 @@
702 704 }
703 705
704 706 $es_version = (string) $es_version;
705 707
706 - $mapping_file = 'initial.php';
708 + $mapping_file = '7-0.php';
707 709
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';
710 + if ( version_compare( $es_version, '7.0', '<' ) ) {
711 + $mapping_file = 'initial.php';
712 712 }
713 713
714 714 /**
715 715 * Filter comment indexable mapping file
@@ -785,18 +785,19 @@
785 785 * @since 3.6.0
786 786 * @return array
787 787 */
788 788 public function query_db( $args ) {
789 -
790 789 $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',
790 + 'type' => $this->get_indexable_comment_types(),
791 + 'status' => $this->get_indexable_comment_status(),
792 + 'post_type' => Indexables::factory()->get( 'post' )->get_indexable_post_types(),
793 + 'post_status' => Indexables::factory()->get( 'post' )->get_indexable_post_status(),
794 + 'number' => $this->get_bulk_items_per_page(),
795 + 'offset' => 0,
796 + 'orderby' => 'comment_ID',
797 + 'order' => 'desc',
798 + 'ep_indexing_advanced_pagination' => true,
799 + 'no_found_rows' => false,
799 800 ];
800 801
801 802 if ( isset( $args['per_page'] ) ) {
802 803 $args['number'] = $args['per_page'];
@@ -801,8 +802,16 @@
801 802 if ( isset( $args['per_page'] ) ) {
802 803 $args['number'] = $args['per_page'];
803 804 }
804 805
806 + if ( isset( $args['include'] ) ) {
807 + $args['comment__in'] = $args['include'];
808 + }
809 +
810 + if ( isset( $args['exclude'] ) ) {
811 + $args['comment__not_in'] = $args['exclude'];
812 + }
813 +
805 814 /**
806 815 * Filter database arguments for comment query
807 816 *
808 817 * @hook ep_comment_query_db_args
@@ -817,25 +826,44 @@
817 826 unset( $all_query_args['number'] );
818 827 unset( $all_query_args['offset'] );
819 828 $all_query_args['count'] = true;
820 829
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 + if ( isset( $args['comment__in'] ) || 0 < $args['offset'] ) {
831 + // Disable advanced pagination. Not useful if only indexing specific IDs.
832 + $args['ep_indexing_advanced_pagination'] = false;
833 + }
830 834
831 - if ( ! empty( $args['offset'] ) ) {
832 - if ( (int) $args['offset'] >= $total_objects ) {
833 - $total_objects = 0;
834 - }
835 + // Explicitly set the orderby to ID to prevent accidental modifications by other code.
836 + add_filter( 'comments_clauses', [ $this, 'set_orderby' ], 9999, 2 );
837 +
838 + // Enforce the following query args during advanced pagination to ensure things work correctly.
839 + if ( $args['ep_indexing_advanced_pagination'] ) {
840 + $args = array_merge(
841 + $args,
842 + [
843 + 'suppress_filters' => false,
844 + 'orderby' => 'comment_ID',
845 + 'order' => 'desc',
846 + 'paged' => 1,
847 + 'offset' => 0,
848 + ]
849 + );
850 +
851 + // It's important to pass a custom cache domain. By default, WordPress caches results based on the default query arguments and doesn't account for custom arguments. @see \WP_Comment_Query::get_comments()
852 + $cache_key = md5( get_current_blog_id() . wp_json_encode( $args ) );
853 + $args['cache_domain'] = 'elasticpress-comment-indexable-' . $cache_key;
854 +
855 + add_filter( 'comments_clauses', array( $this, 'bulk_indexing_filter_comments_where' ), 9999, 2 );
856 +
857 + $query = new WP_Comment_Query( $args );
858 + $total_objects = $this->get_total_objects_for_query( $args );
859 + remove_filter( 'comments_clauses', array( $this, 'bulk_indexing_filter_comments_where' ), 9999, 2 );
860 + } else {
861 + $query = new WP_Comment_Query( $args );
862 + $total_objects = $query->found_comments;
835 863 }
836 864
837 - $query = new WP_Comment_Query( $args );
865 + remove_filter( 'comments_clauses', [ $this, 'set_orderby' ], 9999, 2 );
838 866
839 867 if ( is_array( $query->comments ) ) {
840 868 array_walk( $query->comments, [ $this, 'remap_comments' ] );
841 869 }
@@ -846,8 +874,79 @@
846 874 ];
847 875 }
848 876
849 877 /**
878 + * Filters the WHERE clause of the SQL query used for bulk indexing comments by modifying it to include a range
879 + * of comment IDs based on advanced pagination parameters.
880 + *
881 + * @param array $clauses Associative array of the clauses for the query.
882 + * @param \WP_Comment_Query $query The current WP_Comment_Query instance.
883 + *
884 + * @return array Modified SQL query clauses.
885 + */
886 + public function bulk_indexing_filter_comments_where( $clauses, $query ) {
887 + global $wpdb;
888 +
889 + $using_advanced_pagination = $this->get_query_var( $query, 'ep_indexing_advanced_pagination', false );
890 +
891 + if ( $using_advanced_pagination ) {
892 + $requested_upper_limit_id = $this->get_query_var( $query, 'ep_indexing_upper_limit_object_id', PHP_INT_MAX );
893 + $requested_lower_limit_object_id = $this->get_query_var( $query, 'ep_indexing_lower_limit_object_id', 0 );
894 + $last_processed_id = $this->get_query_var( $query, 'ep_indexing_last_processed_object_id', null );
895 +
896 + // On the first loopthrough we begin with the requested upper limit ID. Afterwards, use the last processed ID to paginate.
897 + $upper_limit_range_object_id = $requested_upper_limit_id;
898 + if ( is_numeric( $last_processed_id ) ) {
899 + $upper_limit_range_object_id = $last_processed_id - 1;
900 + }
901 +
902 + // Sanitize. Abort if unexpected data at this point.
903 + if ( ! is_numeric( $upper_limit_range_object_id ) || ! is_numeric( $requested_lower_limit_object_id ) ) {
904 + return $clauses;
905 + }
906 +
907 + $range = [
908 + 'upper_limit' => "{$wpdb->comments}.comment_ID <= {$upper_limit_range_object_id}",
909 + 'lower_limit' => "{$wpdb->comments}.comment_ID >= {$requested_lower_limit_object_id}",
910 + ];
911 +
912 + // Skip the end range if it's unnecessary.
913 + $skip_ending_range = 0 === $requested_lower_limit_object_id;
914 + $where = $clauses['where'];
915 + $where = $skip_ending_range ? " {$range['upper_limit']} AND {$where}" : " {$range['upper_limit']} AND {$range['lower_limit']} AND {$where}";
916 +
917 + $clauses['where'] = $where;
918 + }
919 +
920 + return $clauses;
921 + }
922 +
923 + /**
924 + * Get the total number of comments for a given query.
925 + *
926 + * @param array $query_args The query args.
927 + * @return int The query result's found_comments.
928 + */
929 + protected function get_total_objects_for_query( $query_args ) {
930 + $normalized_query_args = array_merge(
931 + $query_args,
932 + [
933 + 'offset' => 0,
934 + 'paged' => 1,
935 + 'posts_per_page' => 1,
936 + 'no_found_rows' => false,
937 + 'ep_indexing_last_processed_object_id' => null,
938 + ]
939 + );
940 +
941 + $cache_key = md5( get_current_blog_id() . wp_json_encode( $normalized_query_args ) );
942 +
943 + $normalized_query_args['cache_domain'] = 'elasticpress-comment-indexable-' . $cache_key;
944 +
945 + return ( new WP_Comment_Query( $normalized_query_args ) )->found_comments;
946 + }
947 +
948 + /**
850 949 * Prepare a comment document for indexing
851 950 *
852 951 * @param int $comment_id Comment ID
853 952 * @since 3.6.0
@@ -988,13 +1087,11 @@
988 1087
989 1088 if ( true === $allowed_protected_keys || in_array( $key, $allowed_protected_keys, true ) ) {
990 1089 $allow_index = true;
991 1090 }
992 - } else {
1091 + } elseif ( true !== $excluded_public_keys && ! in_array( $key, $excluded_public_keys, true ) ) {
993 1092
994 - if ( true !== $excluded_public_keys && ! in_array( $key, $excluded_public_keys, true ) ) {
995 1093 $allow_index = true;
996 - }
997 1094 }
998 1095
999 1096 /**
1000 1097 * Filter force allow a meta key
@@ -1073,8 +1170,17 @@
1073 1170 $from_to['meta_value_num'] = 'meta.' . $args['meta_key'] . '.long';
1074 1171 }
1075 1172 }
1076 1173
1174 + /**
1175 + * If `orderby` is 'none', WordPress will let the database decide on what should be used to order.
1176 + * It will use the primary key ASC.
1177 + */
1178 + if ( 'none' === $orderby ) {
1179 + $orderby = 'ID';
1180 + $order = 'asc';
1181 + }
1182 +
1077 1183 $orderby = $from_to[ $orderby ] ?? $orderby;
1078 1184
1079 1185 $sort[] = array(
1080 1186 $orderby => array(
@@ -1084,5 +1190,32 @@
1084 1190
1085 1191 return $sort;
1086 1192 }
1087 1193
1194 + /**
1195 + * Retrieve a specific query variable from the query object.
1196 + *
1197 + * @param \WP_Comment_Query $query The query object.
1198 + * @param string $query_var The name of the query variable to retrieve.
1199 + * @param string $default_value The default value to return if the query variable is not set. Default is an empty string.
1200 + *
1201 + * @return mixed The value of the query variable if set, otherwise the default value.
1202 + */
1203 + public function get_query_var( $query, $query_var, $default_value = '' ) {
1204 + return $query->query_vars[ $query_var ] ?? $default_value;
1205 + }
1206 +
1207 + /**
1208 + * Sets the ORDER BY clause for comment queries to order comments by their ID.
1209 + *
1210 + * @param array $clauses The SQL clauses array to modify.
1211 + * @return array The modified SQL clauses array with the ORDER BY clause set.
1212 + *
1213 + * @since 5.2.0
1214 + */
1215 + public function set_orderby( $clauses ) {
1216 + global $wpdb;
1217 +
1218 + $clauses['orderby'] = "{$wpdb->comments}.comment_ID DESC";
1219 + return $clauses;
1220 + }
1088 1221 }