Skip to content

Commit

Permalink
Merge pull request #4074 from 10up/fix/3654
Browse files Browse the repository at this point in the history
Add include, lower_limit_object_id and higher_limit_object_id for com…
  • Loading branch information
felipeelia authored Feb 26, 2025
2 parents 377fb88 + 53246dc commit 42b11f8
Show file tree
Hide file tree
Showing 5 changed files with 351 additions and 79 deletions.
135 changes: 111 additions & 24 deletions includes/classes/Indexable/Comment/Comment.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ class Comment extends Indexable {
*/
public $slug = 'comment';

/**
* Flag to indicate if the indexable has support for
* `id_range` pagination method during a sync.
*
* @var boolean
* @since 5.2.0
*/
public $support_indexing_advanced_pagination = true;

/**
* Instantiate the indexable SyncManager and QueryIntegration, the main responsibles for the WP integration.
*
Expand Down Expand Up @@ -777,22 +786,31 @@ public function get_indexable_comment_status() {
* @return array
*/
public function query_db( $args ) {

$defaults = [
'type' => $this->get_indexable_comment_types(),
'status' => $this->get_indexable_comment_status(),
'post_type' => Indexables::factory()->get( 'post' )->get_indexable_post_types(),
'post_status' => Indexables::factory()->get( 'post' )->get_indexable_post_status(),
'number' => $this->get_bulk_items_per_page(),
'offset' => 0,
'orderby' => 'comment_ID',
'order' => 'desc',
'type' => $this->get_indexable_comment_types(),
'status' => $this->get_indexable_comment_status(),
'post_type' => Indexables::factory()->get( 'post' )->get_indexable_post_types(),
'post_status' => Indexables::factory()->get( 'post' )->get_indexable_post_status(),
'number' => $this->get_bulk_items_per_page(),
'offset' => 0,
'orderby' => 'comment_ID',
'order' => 'desc',
'ep_indexing_advanced_pagination' => true,
'no_found_rows' => false,
];

if ( isset( $args['per_page'] ) ) {
$args['number'] = $args['per_page'];
}

if ( isset( $args['include'] ) ) {
$args['comment__in'] = $args['include'];
}

if ( isset( $args['exclude'] ) ) {
$args['comment__not_in'] = $args['exclude'];
}

/**
* Filter database arguments for comment query
*
Expand All @@ -809,23 +827,33 @@ public function query_db( $args ) {
unset( $all_query_args['offset'] );
$all_query_args['count'] = true;

/**
* Filter database arguments for comment count query
*
* @hook ep_comment_all_query_db_args
* @param {array} $args Query arguments based to WP_Comment_Query
* @since 3.6.0
* @return {array} New arguments
*/
$total_objects = get_comments( apply_filters( 'ep_comment_all_query_db_args', $all_query_args, $args ) );

if ( ! empty( $args['offset'] ) ) {
if ( (int) $args['offset'] >= $total_objects ) {
$total_objects = 0;
}
if ( isset( $args['comment__in'] ) || 0 < $args['offset'] ) {
// Disable advanced pagination. Not useful if only indexing specific IDs.
$args['ep_indexing_advanced_pagination'] = false;
}

$query = new WP_Comment_Query( $args );
// Enforce the following query args during advanced pagination to ensure things work correctly.
if ( $args['ep_indexing_advanced_pagination'] ) {
$args = array_merge(
$args,
[
'suppress_filters' => false,
'orderby' => 'ID',
'order' => 'DESC',
'paged' => 1,
'offset' => 0,
]
);
add_filter( 'comments_clauses', array( $this, 'bulk_indexing_filter_comments_where' ), 9999, 2 );

$query = new WP_Comment_Query( $args );
$total_objects = $query->found_comments;

remove_filter( 'comments_clauses', array( $this, 'bulk_indexing_filter_comments_where' ), 9999, 2 );
} else {
$query = new WP_Comment_Query( $args );
$total_objects = $query->found_comments;
}

if ( is_array( $query->comments ) ) {
array_walk( $query->comments, [ $this, 'remap_comments' ] );
Expand All @@ -837,6 +865,52 @@ public function query_db( $args ) {
];
}

/**
* Filters the WHERE clause of the SQL query used for bulk indexing comments by modifying it to include a range
* of comment IDs based on advanced pagination parameters.
*
* @param array $clauses Associative array of the clauses for the query.
* @param \WP_Comment_Query $query The current WP_Comment_Query instance.
*
* @return array Modified SQL query clauses.
*/
public function bulk_indexing_filter_comments_where( $clauses, $query ) {
global $wpdb;

$using_advanced_pagination = $this->get_query_var( $query, 'ep_indexing_advanced_pagination', false );

if ( $using_advanced_pagination ) {
$requested_upper_limit_id = $this->get_query_var( $query, 'ep_indexing_upper_limit_object_id', PHP_INT_MAX );
$requested_lower_limit_object_id = $this->get_query_var( $query, 'ep_indexing_lower_limit_object_id', 0 );
$last_processed_id = $this->get_query_var( $query, 'ep_indexing_last_processed_object_id', null );

// On the first loopthrough we begin with the requested upper limit ID. Afterwards, use the last processed ID to paginate.
$upper_limit_range_object_id = $requested_upper_limit_id;
if ( is_numeric( $last_processed_id ) ) {
$upper_limit_range_object_id = $last_processed_id - 1;
}

// Sanitize. Abort if unexpected data at this point.
if ( ! is_numeric( $upper_limit_range_object_id ) || ! is_numeric( $requested_lower_limit_object_id ) ) {
return $clauses;
}

$range = [
'upper_limit' => "{$wpdb->comments}.comment_ID <= {$upper_limit_range_object_id}",
'lower_limit' => "{$wpdb->comments}.comment_ID >= {$requested_lower_limit_object_id}",
];

// Skip the end range if it's unnecessary.
$skip_ending_range = 0 === $requested_lower_limit_object_id;
$where = $clauses['where'];
$where = $skip_ending_range ? " {$range['upper_limit']} AND {$where}" : " {$range['upper_limit']} AND {$range['lower_limit']} AND {$where}";

$clauses['where'] = $where;
}

return $clauses;
}

/**
* Prepare a comment document for indexing
*
Expand Down Expand Up @@ -1073,4 +1147,17 @@ protected function parse_orderby( $orderby, $order, $args ) {

return $sort;
}

/**
* Retrieve a specific query variable from the query object.
*
* @param \WP_Comment_Query $query The query object.
* @param string $query_var The name of the query variable to retrieve.
* @param string $default_value The default value to return if the query variable is not set. Default is an empty string.
*
* @return mixed The value of the query variable if set, otherwise the default value.
*/
public function get_query_var( $query, $query_var, $default_value = '' ) {
return $query->query_vars[ $query_var ] ?? $default_value;
}
}
20 changes: 11 additions & 9 deletions includes/classes/Indexable/Post/Post.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,16 @@ public function query_db( $args ) {
];
}

/**
* Manipulate the WHERE clause of the bulk indexing query to paginate by ID in order to avoid performance issues with SQL offset.
*
* @param string $where The current $where clause.
* @param WP_Query $query WP_Query object.
* @return string WHERE clause with our pagination added if needed.
*/
/**
* Manipulate the WHERE clause of the bulk indexing query to paginate by ID in order to avoid performance issues with SQL offset.
*
* @param string $where The current $where clause.
* @param WP_Query $query WP_Query object.
* @return string WHERE clause with our pagination added if needed.
*/
public function bulk_indexing_filter_posts_where( $where, $query ) {
global $wpdb;

$using_advanced_pagination = $query->get( 'ep_indexing_advanced_pagination', false );

if ( $using_advanced_pagination ) {
Expand All @@ -161,8 +163,8 @@ public function bulk_indexing_filter_posts_where( $where, $query ) {
}

$range = [
'upper_limit' => "{$GLOBALS['wpdb']->posts}.ID <= {$upper_limit_range_post_id}",
'lower_limit' => "{$GLOBALS['wpdb']->posts}.ID >= {$requested_lower_limit_post_id}",
'upper_limit' => "{$wpdb->posts}.ID <= {$upper_limit_range_post_id}",
'lower_limit' => "{$wpdb->posts}.ID >= {$requested_lower_limit_post_id}",
];

// Skip the end range if it's unnecessary.
Expand Down
Loading

0 comments on commit 42b11f8

Please sign in to comment.