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..59ac47b 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 3 oEmbed caches: 1 post cache, 1 oembed 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..ca7830e 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,130 @@ 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 ) { + // 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}$'" + ); + // 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}$'" + ); + + // 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, + ); - $post_id = $args[0]; + $total = array_sum( array_map( function( $items ) { + return count( $items ); + }, $oembed_caches ) ); + + // Delete post meta oEmbed caches + foreach ( $oembed_post_meta_post_ids as $post_id ) { + $wp_embed->delete_oembed_caches( $post_id ); + } + + // 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 ) + ); + } + + $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!' ); + } + + 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.' ); + } + + 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 );