diff --git a/plugins/embed-optimizer/tests/test-hooks.php b/plugins/embed-optimizer/tests/test-hooks.php index 2980927888..b9b55d8e70 100644 --- a/plugins/embed-optimizer/tests/test-hooks.php +++ b/plugins/embed-optimizer/tests/test-hooks.php @@ -18,7 +18,6 @@ public function test_embed_optimizer_add_hooks(): void { $this->assertSame( 10, has_action( 'od_init', 'embed_optimizer_init_optimization_detective' ) ); $this->assertSame( 10, has_action( 'wp_head', 'embed_optimizer_render_generator' ) ); $this->assertSame( 10, has_action( 'wp_loaded', 'embed_optimizer_add_non_optimization_detective_hooks' ) ); - $this->assertSame( 10, has_action( 'od_url_metric_stored', 'od_clean_queried_object_cache_for_stored_url_metric' ) ); } /** diff --git a/plugins/optimization-detective/hooks.php b/plugins/optimization-detective/hooks.php index b8d1073296..c0f94d148c 100644 --- a/plugins/optimization-detective/hooks.php +++ b/plugins/optimization-detective/hooks.php @@ -15,4 +15,3 @@ OD_URL_Metrics_Post_Type::add_hooks(); add_action( 'wp', 'od_maybe_add_template_output_buffer_filter' ); add_action( 'wp_head', 'od_render_generator_meta_tag' ); -add_action( 'od_url_metric_stored', 'od_clean_queried_object_cache_for_stored_url_metric' ); diff --git a/plugins/optimization-detective/storage/rest-api.php b/plugins/optimization-detective/storage/rest-api.php index b510837177..2b505e14fc 100644 --- a/plugins/optimization-detective/storage/rest-api.php +++ b/plugins/optimization-detective/storage/rest-api.php @@ -208,6 +208,16 @@ function od_handle_rest_request( WP_REST_Request $request ) { } $post_id = $result; + // Schedule an event in 10 minutes to trigger an invalidation of the page cache (hopefully). + $cache_purge_post_id = $request->get_param( 'cache_purge_post_id' ); + if ( is_int( $cache_purge_post_id ) && false === wp_next_scheduled( 'od_trigger_page_cache_invalidation', array( $cache_purge_post_id ) ) ) { + wp_schedule_single_event( + time() + 10 * MINUTE_IN_SECONDS, + 'od_trigger_page_cache_invalidation', + array( $cache_purge_post_id ) + ); + } + /** * Fires whenever a URL Metric was successfully stored. * @@ -235,30 +245,17 @@ function od_handle_rest_request( WP_REST_Request $request ) { } /** - * Cleans the cache for the queried object when it has a new URL Metric stored. + * Triggers actions for page caches to invalidate their caches related to the supplied cache purge post ID. * * This is intended to flush any page cache for the URL after the new URL Metric was submitted so that the optimizations - * which depend on that URL Metric can start to take effect. Furthermore, when a submitted URL Metric results in a full - * sample of URL Metric groups, then flushing the page cache will allow the next request to omit the detection script - * module altogether. When a page cache holds onto a cached page for a long time (e.g. a week), this will result in - * the stored URL Metrics being stale if they have the default freshness TTL of 1 day. Nevertheless, if no changes have - * been applied to a cached page then those stale URL Metrics should continue to result in an optimized page. - * - * This assumes that a page caching plugin flushes the page cache for a queried object via `clean_post_cache`, - * `clean_term_cache`, and `clean_user_cache` actions. Other actions may make sense to trigger as well as can be seen in - * {@link https://github.com/pantheon-systems/pantheon-advanced-page-cache/blob/e3b5552/README.md?plain=1#L314-L356}. + * which depend on that URL Metric can start to take effect. * * @since n.e.x.t + * @access private * - * @param OD_URL_Metric_Store_Request_Context $context Context. + * @param int $cache_purge_post_id Cache purge post ID. */ -function od_clean_queried_object_cache_for_stored_url_metric( OD_URL_Metric_Store_Request_Context $context ): void { - - $cache_purge_post_id = $context->request->get_param( 'cache_purge_post_id' ); - if ( ! is_int( $cache_purge_post_id ) ) { - return; - } - +function od_trigger_page_cache_invalidation( int $cache_purge_post_id ): void { $post = get_post( $cache_purge_post_id ); if ( ! ( $post instanceof WP_Post ) ) { return; diff --git a/plugins/optimization-detective/tests/storage/test-rest-api.php b/plugins/optimization-detective/tests/storage/test-rest-api.php index b5ac38dd5a..1d112b4337 100644 --- a/plugins/optimization-detective/tests/storage/test-rest-api.php +++ b/plugins/optimization-detective/tests/storage/test-rest-api.php @@ -71,7 +71,7 @@ static function ( array $properties ): array { * * @covers ::od_register_endpoint * @covers ::od_handle_rest_request - * @covers ::od_clean_queried_object_cache_for_stored_url_metric + * @covers ::od_trigger_page_cache_invalidation */ public function test_rest_request_good_params( Closure $set_up ): void { $stored_context = null; @@ -89,15 +89,9 @@ function ( OD_URL_Metric_Store_Request_Context $context ) use ( &$stored_context $valid_params = $set_up(); - $all_hook_callback_args = array(); - add_action( - 'all', - static function ( string $hook, ...$args ) use ( &$all_hook_callback_args ): void { - $all_hook_callback_args[ $hook ][] = $args; - }, - 10, - PHP_INT_MAX - ); + if ( isset( $valid_params['cache_purge_post_id'] ) ) { + $this->assertFalse( wp_next_scheduled( 'od_trigger_page_cache_invalidation', array( $valid_params['cache_purge_post_id'] ) ) ); + } $this->assertCount( 0, get_posts( array( 'post_type' => OD_URL_Metrics_Post_Type::SLUG ) ) ); $request = $this->create_request( $valid_params ); @@ -126,43 +120,14 @@ static function ( string $hook, ...$args ) use ( &$all_hook_callback_args ): voi $this->assertInstanceOf( OD_URL_Metric_Store_Request_Context::class, $stored_context ); - // Now check that od_clean_queried_object_cache_for_stored_url_metric() cleaned caches as expected. + // Now check that od_trigger_page_cache_invalidation() cleaned caches as expected. $this->assertSame( $url_metrics[0]->jsonSerialize(), $stored_context->url_metric->jsonSerialize() ); $cache_purge_post_id = $stored_context->request->get_param( 'cache_purge_post_id' ); - if ( null !== $cache_purge_post_id ) { - $this->assertArrayHasKey( 'clean_post_cache', $all_hook_callback_args ); - $found = false; - foreach ( $all_hook_callback_args['clean_post_cache'] as $args ) { - if ( $args[0] === $cache_purge_post_id ) { - $this->assertInstanceOf( WP_Post::class, $args[1] ); - $this->assertSame( $cache_purge_post_id, $args[1]->ID ); - $found = true; - } - } - $this->assertTrue( $found, 'Expected clean_post_cache to have been fired for the post queried object.' ); - - $this->assertArrayHasKey( 'transition_post_status', $all_hook_callback_args ); - $found = false; - foreach ( $all_hook_callback_args['transition_post_status'] as $args ) { - $this->assertInstanceOf( WP_Post::class, $args[2] ); - if ( $args[2]->ID === $cache_purge_post_id ) { - $this->assertSame( $args[2]->post_status, $args[0] ); - $this->assertSame( $args[2]->post_status, $args[1] ); - $found = true; - } - } - $this->assertTrue( $found, 'Expected transition_post_status to have been fired for the post queried object.' ); - - $this->assertArrayHasKey( 'save_post', $all_hook_callback_args ); - $found = false; - foreach ( $all_hook_callback_args['save_post'] as $args ) { - if ( $args[0] === $cache_purge_post_id ) { - $this->assertInstanceOf( WP_Post::class, $args[1] ); - $this->assertSame( $cache_purge_post_id, $args[1]->ID ); - $found = true; - } - } - $this->assertTrue( $found, 'Expected save_post to have been fired for the post queried object.' ); + + if ( isset( $valid_params['cache_purge_post_id'] ) ) { + $scheduled = wp_next_scheduled( 'od_trigger_page_cache_invalidation', array( $valid_params['cache_purge_post_id'] ) ); + $this->assertIsInt( $scheduled ); + $this->assertGreaterThan( time(), $scheduled ); } } @@ -618,6 +583,61 @@ static function () use ( $breakpoint_width ): array { $this->assertSame( 403, $response->get_status(), 'Response: ' . wp_json_encode( $response->get_data() ) ); } + /** + * Test od_trigger_page_cache_invalidation(). + * + * @covers ::od_trigger_page_cache_invalidation + */ + public function test_od_trigger_page_cache_invalidation(): void { + $cache_purge_post_id = self::factory()->post->create(); + + $all_hook_callback_args = array(); + add_action( + 'all', + static function ( string $hook, ...$args ) use ( &$all_hook_callback_args ): void { + $all_hook_callback_args[ $hook ][] = $args; + }, + 10, + PHP_INT_MAX + ); + + od_trigger_page_cache_invalidation( $cache_purge_post_id ); + + $this->assertArrayHasKey( 'clean_post_cache', $all_hook_callback_args ); + $found = false; + foreach ( $all_hook_callback_args['clean_post_cache'] as $args ) { + if ( $args[0] === $cache_purge_post_id ) { + $this->assertInstanceOf( WP_Post::class, $args[1] ); + $this->assertSame( $cache_purge_post_id, $args[1]->ID ); + $found = true; + } + } + $this->assertTrue( $found, 'Expected clean_post_cache to have been fired for the post queried object.' ); + + $this->assertArrayHasKey( 'transition_post_status', $all_hook_callback_args ); + $found = false; + foreach ( $all_hook_callback_args['transition_post_status'] as $args ) { + $this->assertInstanceOf( WP_Post::class, $args[2] ); + if ( $args[2]->ID === $cache_purge_post_id ) { + $this->assertSame( $args[2]->post_status, $args[0] ); + $this->assertSame( $args[2]->post_status, $args[1] ); + $found = true; + } + } + $this->assertTrue( $found, 'Expected transition_post_status to have been fired for the post queried object.' ); + + $this->assertArrayHasKey( 'save_post', $all_hook_callback_args ); + $found = false; + foreach ( $all_hook_callback_args['save_post'] as $args ) { + if ( $args[0] === $cache_purge_post_id ) { + $this->assertInstanceOf( WP_Post::class, $args[1] ); + $this->assertSame( $cache_purge_post_id, $args[1]->ID ); + $found = true; + } + } + $this->assertTrue( $found, 'Expected save_post to have been fired for the post queried object.' ); + } + /** * Populate URL Metrics. *