diff --git a/includes/Core/Util/Reset.php b/includes/Core/Util/Reset.php index 1b33e99bc77..71b76a38cae 100644 --- a/includes/Core/Util/Reset.php +++ b/includes/Core/Util/Reset.php @@ -11,6 +11,7 @@ namespace Google\Site_Kit\Core\Util; use Google\Site_Kit\Context; +use Google\Site_Kit\Core\Email_Reporting\Email_Log; use Google\Site_Kit\Core\Authentication\Authentication; use Google\Site_Kit\Core\Permissions\Permissions; use Google\Site_Kit\Core\REST_API\REST_Route; @@ -113,12 +114,14 @@ public function all() { $this->delete_user_options( 'site' ); $this->delete_post_meta( 'site' ); $this->delete_term_meta( 'site' ); + $this->delete_posts( 'site' ); if ( $this->context->is_network_mode() ) { $this->delete_options( 'network' ); $this->delete_user_options( 'network' ); $this->delete_post_meta( 'network' ); $this->delete_term_meta( 'network' ); + $this->delete_posts( 'network' ); } wp_cache_flush(); @@ -256,6 +259,67 @@ private function delete_term_meta( $scope ) { } } + /** + * Deletes all Site Kit custom post type posts. + * + * @since n.e.x.t + * + * @param string $scope Scope of the deletion ('site' or 'network'). + */ + private function delete_posts( $scope ) { + $sites = array(); + if ( 'network' === $scope ) { + $sites = get_sites( + array( + 'fields' => 'ids', + 'number' => 9999999, + ) + ); + } elseif ( 'site' === $scope ) { + $sites[] = get_current_blog_id(); + } else { + return; + } + + foreach ( $sites as $site_id ) { + $switched = false; + + if ( get_current_blog_id() !== (int) $site_id ) { + // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.switch_to_blog_switch_to_blog + switch_to_blog( $site_id ); + $switched = true; + } + + $posts_per_batch = 100; + do { + // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.get_posts_get_posts + $post_ids = get_posts( + array( + 'post_type' => Email_Log::POST_TYPE, + 'post_status' => array( + Email_Log::STATUS_SENT, + Email_Log::STATUS_FAILED, + Email_Log::STATUS_SCHEDULED, + ), + 'fields' => 'ids', + 'posts_per_page' => $posts_per_batch, + 'no_found_rows' => true, + 'orderby' => 'ID', + 'order' => 'ASC', + ) + ); + + foreach ( $post_ids as $post_id ) { + wp_delete_post( $post_id, true ); + } + } while ( ! empty( $post_ids ) ); + + if ( $switched ) { + restore_current_blog(); + } + } + } + /** * Gets related REST routes. * diff --git a/tests/phpunit/integration/Core/Util/ResetTest.php b/tests/phpunit/integration/Core/Util/ResetTest.php index 6acc42074f6..c5b0c8a2762 100644 --- a/tests/phpunit/integration/Core/Util/ResetTest.php +++ b/tests/phpunit/integration/Core/Util/ResetTest.php @@ -11,6 +11,7 @@ namespace Google\Site_Kit\Tests\Core\Util; use Google\Site_Kit\Context; +use Google\Site_Kit\Core\Email_Reporting\Email_Log; use Google\Site_Kit\Core\Permissions\Permissions; use Google\Site_Kit\Core\Util\Reset; use Google\Site_Kit\Tests\Exception\RedirectException; @@ -36,6 +37,13 @@ class ResetTest extends TestCase { */ protected $context_with_mutable_input; + /** + * Indicates whether the email log post type and metadata were registered. + * + * @var bool + */ + protected $email_log_registered = false; + public function set_up() { parent::set_up(); @@ -46,6 +54,15 @@ public function set_up() { $this->context_with_mutable_input = new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE, new MutableInput() ); } + public function tear_down() { + if ( $this->email_log_registered ) { + $this->unregister_email_log_dependencies(); + $this->email_log_registered = false; + } + + parent::tear_down(); + } + public function test_all() { $context = new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE ); $this->assertFalse( $context->is_network_mode(), 'Context should not be in network mode by default.' ); @@ -79,6 +96,35 @@ public function test_all() { $this->assertEquals( '', get_term_meta( $term_id, 'googlesitekit_keep', true ), 'Term meta with underscore should be deleted.' ); } + public function test_all_deletes_email_log_posts() { + $this->register_email_log_dependencies(); + + $context = new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE ); + + $first_log = $this->factory()->post->create( + array( + 'post_type' => Email_Log::POST_TYPE, + 'post_status' => Email_Log::STATUS_SCHEDULED, + ) + ); + add_post_meta( $first_log, Email_Log::META_BATCH_ID, 'batch-a' ); + + $second_log = $this->factory()->post->create( + array( + 'post_type' => Email_Log::POST_TYPE, + 'post_status' => Email_Log::STATUS_FAILED, + ) + ); + add_post_meta( $second_log, Email_Log::META_SEND_ATTEMPTS, 2 ); + + $this->run_reset( $context ); + + $this->assertNull( get_post( $first_log ), 'Email log posts should be deleted after reset.' ); + $this->assertNull( get_post( $second_log ), 'Email log posts should be deleted after reset.' ); + $this->assertFalse( metadata_exists( 'post', $first_log, Email_Log::META_BATCH_ID ), 'Email log post meta should be deleted after reset.' ); + $this->assertFalse( metadata_exists( 'post', $second_log, Email_Log::META_SEND_ATTEMPTS ), 'Email log post meta should be deleted after reset.' ); + } + /** * @group ms-required */ @@ -94,6 +140,67 @@ public function test_network_mode_all() { $this->run_reset( $context ); } + /** + * @group ms-required + */ + public function test_network_mode_all_deletes_email_log_posts() { + $this->network_activate_site_kit(); + add_filter( 'googlesitekit_is_network_mode', '__return_true' ); + + $this->register_email_log_dependencies(); + + $context = new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE ); + $this->assertTrue( $context->is_network_mode(), 'Context should be in network mode when filter is enabled.' ); + + $blog_ids = array( + get_current_blog_id(), + $this->factory()->blog->create(), + ); + + $email_logs = array(); + foreach ( $blog_ids as $blog_id ) { + $switched = false; + + if ( get_current_blog_id() !== (int) $blog_id ) { + // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.switch_to_blog_switch_to_blog + switch_to_blog( $blog_id ); + $switched = true; + } + + $email_logs[ $blog_id ] = $this->factory()->post->create( + array( + 'post_type' => Email_Log::POST_TYPE, + 'post_status' => Email_Log::STATUS_FAILED, + ) + ); + add_post_meta( $email_logs[ $blog_id ], Email_Log::META_BATCH_ID, 'network-batch' ); + + if ( $switched ) { + restore_current_blog(); + } + } + + $this->run_reset( $context ); + + foreach ( $blog_ids as $blog_id ) { + $switched = false; + + if ( get_current_blog_id() !== (int) $blog_id ) { + // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.switch_to_blog_switch_to_blog + switch_to_blog( $blog_id ); + $switched = true; + } + + $log_id = $email_logs[ $blog_id ]; + $this->assertNull( get_post( $log_id ), 'Email log posts in each site should be deleted after reset.' ); + $this->assertFalse( metadata_exists( 'post', $log_id, Email_Log::META_BATCH_ID ), 'Email log post meta should be deleted for every site after reset.' ); + + if ( $switched ) { + restore_current_blog(); + } + } + } + public function test_handle_reset_action_with_bad_nonce() { remove_all_actions( 'admin_action_' . Reset::ACTION ); $reset = new Reset( $this->context_with_mutable_input ); @@ -206,4 +313,43 @@ protected function run_reset( Context $context ) { $this->assertUserOptionsDeleted( $user_id, $is_network_mode ); $this->assertTransientsDeleted( $is_network_mode ); } + + private function register_email_log_dependencies() { + if ( $this->email_log_registered ) { + return; + } + + $email_log = new Email_Log( new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE ) ); + $register_method = new \ReflectionMethod( Email_Log::class, 'register_email_log' ); + $register_method->setAccessible( true ); + $register_method->invoke( $email_log ); + + $this->email_log_registered = true; + } + + private function unregister_email_log_dependencies() { + if ( function_exists( 'unregister_post_type' ) && post_type_exists( Email_Log::POST_TYPE ) ) { + call_user_func( 'unregister_post_type', Email_Log::POST_TYPE ); + } + + if ( function_exists( 'unregister_post_status' ) ) { + foreach ( array( Email_Log::STATUS_SENT, Email_Log::STATUS_FAILED, Email_Log::STATUS_SCHEDULED ) as $status ) { + call_user_func( 'unregister_post_status', $status ); + } + } + + if ( function_exists( 'unregister_meta_key' ) ) { + foreach ( + array( + Email_Log::META_REPORT_FREQUENCY, + Email_Log::META_BATCH_ID, + Email_Log::META_SEND_ATTEMPTS, + Email_Log::META_ERROR_DETAILS, + Email_Log::META_REPORT_REFERENCE_DATES, + ) as $meta_key + ) { + call_user_func( 'unregister_meta_key', 'post', Email_Log::POST_TYPE, $meta_key ); + } + } + } }