Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deleting a metadata without passing an object id now updates all associated posts #2525

Merged
merged 3 commits into from
Dec 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 75 additions & 24 deletions includes/classes/Indexable/Post/SyncManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ class SyncManager extends SyncManagerAbstract {
*/
public $indexable_slug = 'post';

/**
* Delete all post meta from other posts associated with a deleted post. Useful for attachments.
*
* @var bool
*/
public $delete_all_meta = false;

/**
* Setup actions and filters
*
Expand All @@ -51,13 +58,31 @@ public function setup() {
add_action( 'delete_post', array( $this, 'action_delete_post' ) );
add_action( 'updated_post_meta', array( $this, 'action_queue_meta_sync' ), 10, 4 );
add_action( 'added_post_meta', array( $this, 'action_queue_meta_sync' ), 10, 4 );
// Called just because we need to know somehow if $delete_all is set before action_queue_meta_sync() runs.
add_filter( 'delete_post_metadata', array( $this, 'maybe_delete_meta_for_all' ), 10, 5 );
add_action( 'deleted_post_meta', array( $this, 'action_queue_meta_sync' ), 10, 4 );
add_action( 'wp_initialize_site', array( $this, 'action_create_blog_index' ) );

add_filter( 'ep_sync_insert_permissions_bypass', array( $this, 'filter_bypass_permission_checks_for_machines' ) );
add_filter( 'ep_sync_delete_permissions_bypass', array( $this, 'filter_bypass_permission_checks_for_machines' ) );
}

/**
* Whether to delete all meta from other posts that is associated with the deleted post.
*
* @param bool $check Whether to allow metadata deletion of the given type.
* @param int $object_id ID of the object metadata is for.
* @param string $meta_key Metadata key.
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
* @param bool $delete_all Whether to delete the matching metadata entries
* for all objects, ignoring the specified $object_id
* @return bool
*/
public function maybe_delete_meta_for_all( $check, $object_id, $meta_key, $meta_value, $delete_all ) {
$this->delete_all_meta = $delete_all;
return $check;
}

/**
* Filter to allow cron and WP CLI processes to index/delete documents
*
Expand Down Expand Up @@ -95,9 +120,6 @@ public function action_queue_meta_sync( $meta_id, $object_id, $meta_key, $meta_v

$indexable = Indexables::factory()->get( $this->indexable_slug );

$indexable_post_statuses = $indexable->get_indexable_post_status();
$post_type = get_post_type( $object_id );

if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
// Bypass saving if doing autosave
// @codeCoverageIgnoreStart
Expand All @@ -122,34 +144,63 @@ public function action_queue_meta_sync( $meta_id, $object_id, $meta_key, $meta_v
return;
}

$allowed_meta_to_be_indexed = $indexable->prepare_meta( $post );
if ( ! in_array( $meta_key, array_keys( $allowed_meta_to_be_indexed ), true ) ) {
return;
}
if ( empty( $object_id ) && $this->delete_all_meta ) {
add_filter( 'ep_is_integrated_request', '__return_true' );

$query = new \WP_Query(
[
'ep_integrate' => true,
'meta_key' => $meta_key,
'meta_value' => $meta_value,
'fields' => 'ids',
]
);

remove_filter( 'ep_is_integrated_request', '__return_true' );

if ( $query->have_posts() && $query->elasticsearch_success ) {
$posts_to_be_synced = array_filter(
$query->posts,
function( $object_id ) {
return ! apply_filters( 'ep_post_sync_kill', false, $object_id, $object_id );
}
);
if ( ! empty( $posts_to_be_synced ) ) {
$indexable->bulk_index( $posts_to_be_synced );
}
}
} else {
$indexable_post_statuses = $indexable->get_indexable_post_status();
$post_type = get_post_type( $object_id );

if ( in_array( $post->post_status, $indexable_post_statuses, true ) ) {
$indexable_post_types = $indexable->get_indexable_post_types();
$allowed_meta_to_be_indexed = $indexable->prepare_meta( $post );
if ( ! in_array( $meta_key, array_keys( $allowed_meta_to_be_indexed ), true ) ) {
return;
}

if ( in_array( $post_type, $indexable_post_types, true ) ) {
/**
* Filter to kill post sync
*
* @hook ep_post_sync_kill
* @param {bool} $skip True meanas kill sync for post
* @param {int} $object_id ID of post
* @param {int} $object_id ID of post
* @return {boolean} New value
*/
if ( apply_filters( 'ep_post_sync_kill', false, $object_id, $object_id ) ) {
return;
if ( in_array( $post->post_status, $indexable_post_statuses, true ) ) {
$indexable_post_types = $indexable->get_indexable_post_types();

if ( in_array( $post_type, $indexable_post_types, true ) ) {
/**
* Filter to kill post sync
*
* @hook ep_post_sync_kill
* @param {bool} $skip True meanas kill sync for post
* @param {int} $object_id ID of post
* @param {int} $object_id ID of post
* @return {boolean} New value
*/
if ( apply_filters( 'ep_post_sync_kill', false, $object_id, $object_id ) ) {
return;
}

$this->add_to_queue( $object_id );
}

$this->add_to_queue( $object_id );
}
}
}


/**
* Delete ES post when WP post is deleted
*
Expand Down
51 changes: 51 additions & 0 deletions tests/php/indexables/TestPost.php
Original file line number Diff line number Diff line change
Expand Up @@ -6447,4 +6447,55 @@ public function testTaxQueryWithCategoryId() {
$this->assertArrayHasKey( 'terms.category.term_id', $args['post_filter']['bool']['must'][0]['bool']['must'][0]['terms'] );
$this->assertContains( $cat, $args['post_filter']['bool']['must'][0]['bool']['must'][0]['terms']['terms.category.term_id'] );
}

/**
* Test if EP updates all posts when `delete_metadata()` is called with `$delete_all = true`
*
* @group post
*/
public function testDeleteAllMetadata() {
Functions\create_and_sync_post(
array( 'post_title' => 'one' ),
array(
'common_meta_one' => 'lorem',
'common_meta_two' => 'ipsum',
)
);
Functions\create_and_sync_post(
array( 'post_title' => 'two' ),
array(
'common_meta_one' => 'lorem',
'common_meta_two' => 'ipsum',
)
);

delete_metadata( 'post', null, 'common_meta_one', 'lorem', true );

ElasticPress\Indexables::factory()->get( 'post' )->sync_manager->index_sync_queue();
ElasticPress\Elasticsearch::factory()->refresh_indices();

$query = new \WP_Query(
array(
'post_type' => 'post',
'ep_integrate' => true,
'meta_key' => 'common_meta_one',
'meta_value' => 'lorem',
)
);

$this->assertTrue( $query->elasticsearch_success );
$this->assertEquals( $query->found_posts, 0 );

$query = new \WP_Query(
array(
'post_type' => 'post',
'ep_integrate' => true,
'meta_key' => 'common_meta_two',
'meta_value' => 'ipsum',
)
);

$this->assertTrue( $query->elasticsearch_success );
$this->assertEquals( $query->found_posts, 2 );
}
}