From c8bebd92edf5e5f064654c479f0dd8540b7f5054 Mon Sep 17 00:00:00 2001 From: Nicolas Lemoine Date: Thu, 31 Aug 2023 18:57:18 +0200 Subject: [PATCH 1/5] Add support for `wp embed cache clear --all` command (#67) - Removes posts (`oembed_cache`), post metas (`_oembed_{hash}`, `_oembed_time_{hash}`), transients (`_transient_oembed_{hash}`, `_transient_oembed_time_{hash}`) caches - Add tests --- composer.json | 4 +- features/cache.feature | 41 ++++++++++++++++-- src/Cache_Command.php | 98 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 127 insertions(+), 16 deletions(-) diff --git a/composer.json b/composer.json index 3bfcaf3..60968ce 100644 --- a/composer.json +++ b/composer.json @@ -15,14 +15,14 @@ }, "require-dev": { "wp-cli/entity-command": "^1.3 || ^2", + "wp-cli/cache-command": "^1.0 || ^2", "wp-cli/wp-cli-tests": "^4" }, "config": { "process-timeout": 7200, "sort-packages": true, "allow-plugins": { - "dealerdirect/phpcodesniffer-composer-installer": true, - "johnpbloch/wordpress-core-installer": true + "dealerdirect/phpcodesniffer-composer-installer": true } }, "extra": { diff --git a/features/cache.feature b/features/cache.feature index 1924d19..ce5f070 100644 --- a/features/cache.feature +++ b/features/cache.feature @@ -3,6 +3,20 @@ Feature: Manage oEmbed cache. Background: Given a WP install + Scenario: Clear oEmbed cache with no arguments + When I try `wp embed cache clear` + Then STDERR should be: + """ + Error: You must specify at least one post id or use --all + """ + + Scenario: Clear oEmbed cache with both arguments + When I try `wp embed cache clear 1 --all` + Then STDERR should be: + """ + Error: You cannot specify both a post id and use --all + """ + Scenario: Clear oEmbed cache for an empty post When I run `wp post create --post_title="Foo Bar" --porcelain` Then STDOUT should be a number @@ -11,14 +25,14 @@ Feature: Manage oEmbed cache. When I try `wp embed cache clear {POST_ID}` Then STDERR should be: """ - Error: No cache to clear! + Error: No oEmbed cache to clear! """ Scenario: Clear oEmbed cache for a post - When I run `wp post-meta add 1 _oembed_foo 'bar'` + When I run `wp post meta add 1 _oembed_foo 'bar'` Then STDOUT should not be empty - When I run `wp post-meta get 1 _oembed_foo` + When I run `wp post meta get 1 _oembed_foo` Then STDOUT should be: """ bar @@ -30,6 +44,27 @@ Feature: Manage oEmbed cache. Success: Cleared oEmbed cache. """ + Scenario: Clear all oEmbed caches + # No oEmbed caches yet + When I try `wp embed cache clear --all` + Then STDERR should be: + """ + Error: No oEmbed caches to clear! + """ + + # Generate some various oEmbed caches types + When I run `wp post generate --post_type=oembed_cache --post_date="2000-01-01" --post_title=$(wp eval 'echo md5( "foo" );') --count=10` + And I run `wp post meta add 1 _oembed_$(wp eval 'echo md5( "foo" );') foo` + And I run `wp post meta add 1 _oembed_$(wp eval 'echo md5( "bar" );') bar` + # Make sure we don't clear non-oEmbed caches + And I run `wp post meta add 1 _oembed_foo bar` + And I run `wp transient set oembed_$(wp eval 'echo md5( "bar" );') bar $(wp eval 'echo DAY_IN_SECONDS;')` + And I run `wp embed cache clear --all` + Then STDOUT should be: + """ + Success: Cleared 4 oEmbed caches: 2 post meta caches, 1 post cache, 1 transient cache. + """ + Scenario: Trigger and clear oEmbed cache for a post When I run `wp post create --post_title=Foo --post_type=post --post_status=publish --post_content="[embed]https://www.youtube.com/watch?v=dQw4w9WgXcQ[/embed]" --porcelain` Then STDOUT should be a number diff --git a/src/Cache_Command.php b/src/Cache_Command.php index 6771bc8..f5cfe21 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -3,9 +3,7 @@ namespace WP_CLI\Embeds; use WP_CLI; -use WP_CLI\Process; use WP_CLI\Utils; -use WP_CLI\Formatter; use WP_CLI_Command; /** @@ -20,34 +18,112 @@ class Cache_Command extends WP_CLI_Command { * * ## OPTIONS * - * + * [] * : ID of the post to clear the cache for. * + * [--all] + * : Clear all oEmbed caches. + * * ## EXAMPLES * * # Clear cache for a post * $ wp embed cache clear 123 * Success: Cleared oEmbed cache. + * + * # Clear all caches + * $ wp embed cache clear --all + * Success: Cleared all oEmbed caches. */ public function clear( $args, $assoc_args ) { /** @var \WP_Embed $wp_embed */ - global $wp_embed; + global $wp_embed, $wpdb; + + $all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all' ); + + $post_id = isset( $args[0] ) ? $args[0] : null; + + if ( null === $all && null === $post_id ) { + WP_CLI::error( 'You must specify at least one post id or use --all' ); + } + + if ( $post_id && $all ) { + WP_CLI::error( 'You cannot specify both a post id and use --all' ); + } + + // Delete all oEmbed caches. + if ( $all ) { + // Delete post meta oEmbed caches + $count_metas = $wpdb->query( + "DELETE FROM $wpdb->postmeta + WHERE meta_key REGEXP '^_oembed_[0-9a-f]{32}$' + OR meta_key REGEXP '^_oembed_time_[0-9a-f]{32}$'" + ); + // Delete posts oEmbed caches + $count_posts = $wpdb->query( + "DELETE FROM $wpdb->posts + WHERE post_type = 'oembed_cache' + AND post_status = 'publish' + AND post_name REGEXP '^[0-9a-f]{32}$'" + ); + // Delete transient oEmbed caches + $count_transients = $wpdb->query( + "DELETE FROM $wpdb->options + WHERE option_name REGEXP '^_transient_oembed_[0-9a-f]{32}$' + OR option_name REGEXP '^_transient_oembed_time_[0-9a-f]{32}$'" + ); + + $total = $count_metas + $count_posts + $count_transients; + + if ( empty( $total ) ) { + WP_CLI::error( 'No oEmbed caches to clear!' ); + } + + $report = array_filter( + array( + 'post meta' => $count_metas, + 'post' => $count_posts, + 'transient' => $count_transients, + ), + function ( $count ) { + return $count > 0; + } + ); - $post_id = $args[0]; + $details = array(); + foreach ( $report as $type => $count ) { + $details[] = sprintf( + '%1$d %2$s %3$s', + $count, + $type, + _n( 'cache', 'caches', $count ) + ); + } + + $message = sprintf( + 'Cleared %1$d oEmbed %2$s: %3$s.', + $total, + _n( 'cache', 'caches', $total ), + implode( ', ', $details ) + ); + + WP_CLI::success( $message ); + return; + } - $post_metas = get_post_custom_keys( $post_id ); + // Delete oEmbed caches for a given post. + $count_metas = get_post_custom_keys( $post_id ); - if ( $post_metas ) { - $post_metas = array_filter( - $post_metas, + if ( $count_metas ) { + $count_metas = array_filter( + $count_metas, function ( $v ) { return '_oembed_' === substr( $v, 0, 8 ); } ); } - if ( empty( $post_metas ) ) { - WP_CLI::error( 'No cache to clear!' ); + if ( empty( $count_metas ) ) { + WP_CLI::error( 'No oEmbed cache to clear!' ); } $wp_embed->delete_oembed_caches( $post_id ); From f653c6782f9a1d0d0e9af7bd06eda056e9a3ec69 Mon Sep 17 00:00:00 2001 From: Nicolas Lemoine Date: Wed, 27 Sep 2023 21:26:40 +0200 Subject: [PATCH 2/5] Add support for `wp embed cache clear --all` command Use WordPress functions to delete various oembed caches --- features/cache.feature | 2 +- src/Cache_Command.php | 92 +++++++++++++++++++++++++----------------- 2 files changed, 56 insertions(+), 38 deletions(-) diff --git a/features/cache.feature b/features/cache.feature index ce5f070..59ac47b 100644 --- a/features/cache.feature +++ b/features/cache.feature @@ -62,7 +62,7 @@ Feature: Manage oEmbed cache. And I run `wp embed cache clear --all` Then STDOUT should be: """ - Success: Cleared 4 oEmbed caches: 2 post meta caches, 1 post cache, 1 transient cache. + Success: Cleared 3 oEmbed caches: 1 post cache, 1 oembed post cache, 1 transient cache. """ Scenario: Trigger and clear oEmbed cache for a post diff --git a/src/Cache_Command.php b/src/Cache_Command.php index f5cfe21..37f2bec 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -52,61 +52,79 @@ public function clear( $args, $assoc_args ) { // Delete all oEmbed caches. if ( $all ) { - // Delete post meta oEmbed caches - $count_metas = $wpdb->query( - "DELETE FROM $wpdb->postmeta + // Get post meta oEmbed caches + $oembed_post_meta_post_ids = (array) $wpdb->get_col( + "SELECT DISTINCT post_id FROM $wpdb->postmeta WHERE meta_key REGEXP '^_oembed_[0-9a-f]{32}$' OR meta_key REGEXP '^_oembed_time_[0-9a-f]{32}$'" ); - // Delete posts oEmbed caches - $count_posts = $wpdb->query( - "DELETE FROM $wpdb->posts + // Get posts oEmbed caches + $oembed_post_post_ids = (array) $wpdb->get_col( + "SELECT ID FROM $wpdb->posts WHERE post_type = 'oembed_cache' AND post_status = 'publish' AND post_name REGEXP '^[0-9a-f]{32}$'" ); - // Delete transient oEmbed caches - $count_transients = $wpdb->query( - "DELETE FROM $wpdb->options - WHERE option_name REGEXP '^_transient_oembed_[0-9a-f]{32}$' - OR option_name REGEXP '^_transient_oembed_time_[0-9a-f]{32}$'" + + // Get transient oEmbed caches + $oembed_transients = $wpdb->get_col( + "SELECT option_name FROM $wpdb->options + WHERE option_name REGEXP '^_transient_oembed_[0-9a-f]{32}$'" + ); + + $oembed_caches = array( + 'post' => $oembed_post_meta_post_ids, + 'oembed post' => $oembed_post_post_ids, + 'transient' => $oembed_transients, ); - $total = $count_metas + $count_posts + $count_transients; + $total = array_sum( array_map( function( $items ) { + return count( $items ); + }, $oembed_caches ) ); - if ( empty( $total ) ) { - WP_CLI::error( 'No oEmbed caches to clear!' ); + // Delete post meta oEmbed caches + foreach ( $oembed_post_meta_post_ids as $post_id ) { + $wp_embed->delete_oembed_caches( $post_id ); } - $report = array_filter( - array( - 'post meta' => $count_metas, - 'post' => $count_posts, - 'transient' => $count_transients, - ), - function ( $count ) { - return $count > 0; + // Delete posts oEmbed caches + foreach ( $oembed_post_post_ids as $post_id ) { + wp_delete_post( $post_id, true ); + } + + // Delete transient oEmbed caches + foreach ( $oembed_transients as $option_name ) { + delete_transient( str_replace( '_transient_', '', $option_name ) ); + } + + if ( $total > 0 ) { + $details = array(); + foreach ( $oembed_caches as $type => $items ) { + $count = count( $items ); + $details[] = sprintf( + '%1$d %2$s %3$s', + $count, + $type, + Utils\pluralize( 'cache', $count ) + ); } - ); - $details = array(); - foreach ( $report as $type => $count ) { - $details[] = sprintf( - '%1$d %2$s %3$s', - $count, - $type, - _n( 'cache', 'caches', $count ) + $message = sprintf( + 'Cleared %1$d oEmbed %2$s: %3$s.', + $total, + Utils\pluralize( 'cache', $total ), + implode( ', ', $details ) ); + + WP_CLI::success( $message ); + } else { + WP_CLI::error( 'No oEmbed caches to clear!' ); } - $message = sprintf( - 'Cleared %1$d oEmbed %2$s: %3$s.', - $total, - _n( 'cache', 'caches', $total ), - implode( ', ', $details ) - ); + if ( wp_using_ext_object_cache() ) { + WP_CLI::warning( 'Oembed transients are stored in an external object cache, and this command only deletes those stored in the database. You must flush the cache to delete all transients.' ); + } - WP_CLI::success( $message ); return; } From f930f3858b177bb3b46897a5985bc7bdf3ecc135 Mon Sep 17 00:00:00 2001 From: Nicolas Lemoine Date: Wed, 4 Oct 2023 20:31:50 +0200 Subject: [PATCH 3/5] Update src/Cache_Command.php Co-authored-by: Daniel Bachhuber --- src/Cache_Command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cache_Command.php b/src/Cache_Command.php index 37f2bec..b8c1fee 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -43,7 +43,7 @@ public function clear( $args, $assoc_args ) { $post_id = isset( $args[0] ) ? $args[0] : null; if ( null === $all && null === $post_id ) { - WP_CLI::error( 'You must specify at least one post id or use --all' ); + WP_CLI::error( 'You must specify at least one post ID or use --all.' ); } if ( $post_id && $all ) { From 10ec823ca1ae3dd5429dfb8d84e9a75eca6fe170 Mon Sep 17 00:00:00 2001 From: Nicolas Lemoine Date: Wed, 4 Oct 2023 20:31:59 +0200 Subject: [PATCH 4/5] Update src/Cache_Command.php Co-authored-by: Daniel Bachhuber --- src/Cache_Command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cache_Command.php b/src/Cache_Command.php index b8c1fee..d00c779 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -47,7 +47,7 @@ public function clear( $args, $assoc_args ) { } if ( $post_id && $all ) { - WP_CLI::error( 'You cannot specify both a post id and use --all' ); + WP_CLI::error( 'You cannot specify both a post ID and use --all.' ); } // Delete all oEmbed caches. From c868ec31c65ffa1a61868a91c198a5d815b5bafa Mon Sep 17 00:00:00 2001 From: Nicolas Lemoine Date: Wed, 4 Oct 2023 20:32:08 +0200 Subject: [PATCH 5/5] Update src/Cache_Command.php Co-authored-by: Daniel Bachhuber --- src/Cache_Command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cache_Command.php b/src/Cache_Command.php index d00c779..ca7830e 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -141,7 +141,7 @@ function ( $v ) { } if ( empty( $count_metas ) ) { - WP_CLI::error( 'No oEmbed cache to clear!' ); + WP_CLI::error( 'No oEmbed cache to clear.' ); } $wp_embed->delete_oembed_caches( $post_id );