From bcdeeca524b4fe6a9f2da195fb6022dbcaf057a1 Mon Sep 17 00:00:00 2001 From: Al-Amin Firdows Date: Sat, 27 Jun 2026 09:57:55 +0600 Subject: [PATCH 01/10] feat: Add granular cache flushing commands Adds granular cache flushing for posts, terms, comments, users, and options. Implements CLI equivalents for WordPress cache-clearing functions: - wp cache flush-post [ID] - wp cache flush-term [ID] - wp cache flush-comment [ID] - wp cache flush-user [ID] - wp cache flush-option [name] Addresses #108: Allow selective cache clearing instead of flushing entire cache. Without IDs/names, clears all cache groups for that type. With IDs/names, clears specific items using WordPress core functions. --- composer.json | 5 + features/cache-flush-granular.feature | 126 +++++++++++++++++++ src/Cache_Command.php | 175 ++++++++++++++++++++++++++ 3 files changed, 306 insertions(+) create mode 100644 features/cache-flush-granular.feature diff --git a/composer.json b/composer.json index aba06a05..e48a0f05 100644 --- a/composer.json +++ b/composer.json @@ -39,7 +39,12 @@ "cache decr", "cache delete", "cache flush", + "cache flush-comment", "cache flush-group", + "cache flush-option", + "cache flush-post", + "cache flush-term", + "cache flush-user", "cache get", "cache incr", "cache patch", diff --git a/features/cache-flush-granular.feature b/features/cache-flush-granular.feature new file mode 100644 index 00000000..9e08ee47 --- /dev/null +++ b/features/cache-flush-granular.feature @@ -0,0 +1,126 @@ +Feature: Granular cache flushing operations + + @skip-object-cache + Scenario: Flush post cache + Given a WP install + And a wp-content/mu-plugins/test-harness.php file: + """ + 123, 'post_title' => 'Test' ), 'posts' ); + wp_cache_set( 'meta_123', array( 'key' => 'value' ), 'post_meta' ); + }; + WP_CLI::add_hook( 'before_invoke:cache flush-post', $cache_post ); + """ + + When I run `wp cache flush-post` + Then STDOUT should contain: + """ + Success: Post caches cleared. + """ + + When I run `wp cache flush-post 123` + Then STDOUT should contain: + """ + Success: Post cache for ID 123 cleared. + """ + + @skip-object-cache + Scenario: Flush term cache + Given a WP install + And a wp-content/mu-plugins/test-harness.php file: + """ + 5 ), 'terms' ); + wp_cache_set( 'term_meta_5', array(), 'term_meta' ); + }; + WP_CLI::add_hook( 'before_invoke:cache flush-term', $cache_term ); + """ + + When I run `wp cache flush-term` + Then STDOUT should contain: + """ + Success: Term caches cleared. + """ + + When I run `wp cache flush-term 5` + Then STDOUT should contain: + """ + Success: Term cache for ID 5 cleared. + """ + + @skip-object-cache + Scenario: Flush comment cache + Given a WP install + And a wp-content/mu-plugins/test-harness.php file: + """ + 1 ), 'users' ); + wp_cache_set( 'user_meta_1', array(), 'user_meta' ); + }; + WP_CLI::add_hook( 'before_invoke:cache flush-user', $cache_user ); + """ + + When I run `wp cache flush-user` + Then STDOUT should contain: + """ + Success: User caches cleared. + """ + + When I run `wp cache flush-user 1` + Then STDOUT should contain: + """ + Success: User cache for ID 1 cleared. + """ + + @skip-object-cache + Scenario: Flush option cache + Given a WP install + And a wp-content/mu-plugins/test-harness.php file: + """ + 'value' ), 'options' ); + }; + WP_CLI::add_hook( 'before_invoke:cache flush-option', $cache_option ); + """ + + When I run `wp cache flush-option` + Then STDOUT should contain: + """ + Success: Option caches cleared. + """ + + When I run `wp cache flush-option my_option` + Then STDOUT should contain: + """ + Success: Option cache for 'my_option' cleared. + """ diff --git a/src/Cache_Command.php b/src/Cache_Command.php index ab5c8b56..df6e425e 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -611,4 +611,179 @@ function ( $key ) { } } } + + /** + * Clears post related caches. + * + * @subcommand flush-post + * + * ## OPTIONS + * + * [] + * : Post ID. If not specified, clears all post caches. + * + * ## EXAMPLES + * + * # Clear all post caches. + * $ wp cache flush-post + * Success: Post caches cleared. + * + * # Clear cache for a specific post. + * $ wp cache flush-post 123 + * Success: Post cache for ID 123 cleared. + * + * @param array $args Positional arguments. + */ + public function flush_post( $args ) { + $post_id = ! empty( $args ) ? (int) $args[0] : null; + + if ( $post_id ) { + clean_post_cache( $post_id ); + WP_CLI::success( "Post cache for ID $post_id cleared." ); + } else { + wp_cache_flush_group( 'posts' ); + wp_cache_flush_group( 'post_meta' ); + WP_CLI::success( 'Post caches cleared.' ); + } + } + + /** + * Clears term related caches. + * + * @subcommand flush-term + * + * ## OPTIONS + * + * [] + * : Term ID. If not specified, clears all term caches. + * + * ## EXAMPLES + * + * # Clear all term caches. + * $ wp cache flush-term + * Success: Term caches cleared. + * + * # Clear cache for a specific term. + * $ wp cache flush-term 5 + * Success: Term cache for ID 5 cleared. + * + * @param array $args Positional arguments. + */ + public function flush_term( $args ) { + $term_id = ! empty( $args ) ? (int) $args[0] : null; + + if ( $term_id ) { + clean_term_cache( $term_id ); + WP_CLI::success( "Term cache for ID $term_id cleared." ); + } else { + wp_cache_flush_group( 'terms' ); + wp_cache_flush_group( 'term_meta' ); + WP_CLI::success( 'Term caches cleared.' ); + } + } + + /** + * Clears comment related caches. + * + * @subcommand flush-comment + * + * ## OPTIONS + * + * [] + * : Comment ID. If not specified, clears all comment caches. + * + * ## EXAMPLES + * + * # Clear all comment caches. + * $ wp cache flush-comment + * Success: Comment caches cleared. + * + * # Clear cache for a specific comment. + * $ wp cache flush-comment 42 + * Success: Comment cache for ID 42 cleared. + * + * @param array $args Positional arguments. + */ + public function flush_comment( $args ) { + $comment_id = ! empty( $args ) ? (int) $args[0] : null; + + if ( $comment_id ) { + clean_comment_cache( $comment_id ); + WP_CLI::success( "Comment cache for ID $comment_id cleared." ); + } else { + wp_cache_flush_group( 'comment' ); + wp_cache_flush_group( 'comment_meta' ); + WP_CLI::success( 'Comment caches cleared.' ); + } + } + + /** + * Clears user related caches. + * + * @subcommand flush-user + * + * ## OPTIONS + * + * [] + * : User ID. If not specified, clears all user caches. + * + * ## EXAMPLES + * + * # Clear all user caches. + * $ wp cache flush-user + * Success: User caches cleared. + * + * # Clear cache for a specific user. + * $ wp cache flush-user 1 + * Success: User cache for ID 1 cleared. + * + * @param array $args Positional arguments. + */ + public function flush_user( $args ) { + $user_id = ! empty( $args ) ? (int) $args[0] : null; + + if ( $user_id ) { + clean_user_cache( $user_id ); + WP_CLI::success( "User cache for ID $user_id cleared." ); + } else { + wp_cache_flush_group( 'users' ); + wp_cache_flush_group( 'user_meta' ); + WP_CLI::success( 'User caches cleared.' ); + } + } + + /** + * Clears option related caches. + * + * @subcommand flush-option + * + * ## OPTIONS + * + * [] + * : Option name. If not specified, clears all option caches. + * + * ## EXAMPLES + * + * # Clear all option caches. + * $ wp cache flush-option + * Success: Option caches cleared. + * + * # Clear cache for a specific option. + * $ wp cache flush-option my_option + * Success: Option cache for 'my_option' cleared. + * + * @param array $args Positional arguments. + */ + public function flush_option( $args ) { + $option_name = ! empty( $args ) ? $args[0] : null; + + if ( $option_name ) { + wp_cache_delete( 'alloptions', 'options' ); + wp_cache_delete( $option_name, 'options' ); + WP_CLI::success( "Option cache for '$option_name' cleared." ); + } else { + wp_cache_flush_group( 'options' ); + WP_CLI::success( 'Option caches cleared.' ); + } + } } From fdc5c326f3c666a6e7e574212567efe4f18d2d77 Mon Sep 17 00:00:00 2001 From: Al-Amin Firdows Date: Sat, 27 Jun 2026 10:28:08 +0600 Subject: [PATCH 02/10] fix: Add type hints to granular cache flush methods Add array type hints to method parameters for PHPStan compliance. --- src/Cache_Command.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Cache_Command.php b/src/Cache_Command.php index df6e425e..79a7e8f4 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -632,7 +632,7 @@ function ( $key ) { * $ wp cache flush-post 123 * Success: Post cache for ID 123 cleared. * - * @param array $args Positional arguments. + * @param array $args Positional arguments. */ public function flush_post( $args ) { $post_id = ! empty( $args ) ? (int) $args[0] : null; @@ -667,7 +667,7 @@ public function flush_post( $args ) { * $ wp cache flush-term 5 * Success: Term cache for ID 5 cleared. * - * @param array $args Positional arguments. + * @param array $args Positional arguments. */ public function flush_term( $args ) { $term_id = ! empty( $args ) ? (int) $args[0] : null; @@ -702,7 +702,7 @@ public function flush_term( $args ) { * $ wp cache flush-comment 42 * Success: Comment cache for ID 42 cleared. * - * @param array $args Positional arguments. + * @param array $args Positional arguments. */ public function flush_comment( $args ) { $comment_id = ! empty( $args ) ? (int) $args[0] : null; @@ -737,7 +737,7 @@ public function flush_comment( $args ) { * $ wp cache flush-user 1 * Success: User cache for ID 1 cleared. * - * @param array $args Positional arguments. + * @param array $args Positional arguments. */ public function flush_user( $args ) { $user_id = ! empty( $args ) ? (int) $args[0] : null; @@ -772,7 +772,7 @@ public function flush_user( $args ) { * $ wp cache flush-option my_option * Success: Option cache for 'my_option' cleared. * - * @param array $args Positional arguments. + * @param array $args Positional arguments. */ public function flush_option( $args ) { $option_name = ! empty( $args ) ? $args[0] : null; From fe5e6098221ea887da57cbbc8043eea80873dfdb Mon Sep 17 00:00:00 2001 From: Al-Amin Firdows Date: Sat, 27 Jun 2026 10:33:00 +0600 Subject: [PATCH 03/10] fix: Add feature detection for group flushing Add wp_cache_supports() checks before calling wp_cache_flush_group(). Requires WordPress 6.1+ or persistent object cache with group flushing support. Specific item flushing works on all WordPress versions. Update tests to validate specific item flushing and expect errors when group flushing not supported. --- features/cache-flush-granular.feature | 81 +++++++++++++++++---------- src/Cache_Command.php | 15 +++++ 2 files changed, 66 insertions(+), 30 deletions(-) diff --git a/features/cache-flush-granular.feature b/features/cache-flush-granular.feature index 9e08ee47..2793fd6a 100644 --- a/features/cache-flush-granular.feature +++ b/features/cache-flush-granular.feature @@ -1,7 +1,7 @@ Feature: Granular cache flushing operations @skip-object-cache - Scenario: Flush post cache + Scenario: Flush specific post cache Given a WP install And a wp-content/mu-plugins/test-harness.php file: """ @@ -13,20 +13,24 @@ Feature: Granular cache flushing operations WP_CLI::add_hook( 'before_invoke:cache flush-post', $cache_post ); """ - When I run `wp cache flush-post` + When I run `wp cache flush-post 123` Then STDOUT should contain: """ - Success: Post caches cleared. + Success: Post cache for ID 123 cleared. """ - When I run `wp cache flush-post 123` - Then STDOUT should contain: + @skip-object-cache + Scenario: Flush all posts cache requires support + Given a WP install + + When I try `wp cache flush-post` + Then STDERR should contain: """ - Success: Post cache for ID 123 cleared. + Flushing all post caches requires WordPress 6.1+ """ @skip-object-cache - Scenario: Flush term cache + Scenario: Flush specific term cache Given a WP install And a wp-content/mu-plugins/test-harness.php file: """ @@ -38,20 +42,24 @@ Feature: Granular cache flushing operations WP_CLI::add_hook( 'before_invoke:cache flush-term', $cache_term ); """ - When I run `wp cache flush-term` + When I run `wp cache flush-term 5` Then STDOUT should contain: """ - Success: Term caches cleared. + Success: Term cache for ID 5 cleared. """ - When I run `wp cache flush-term 5` - Then STDOUT should contain: + @skip-object-cache + Scenario: Flush all terms cache requires support + Given a WP install + + When I try `wp cache flush-term` + Then STDERR should contain: """ - Success: Term cache for ID 5 cleared. + Flushing all term caches requires WordPress 6.1+ """ @skip-object-cache - Scenario: Flush comment cache + Scenario: Flush specific comment cache Given a WP install And a wp-content/mu-plugins/test-harness.php file: """ @@ -63,20 +71,24 @@ Feature: Granular cache flushing operations WP_CLI::add_hook( 'before_invoke:cache flush-comment', $cache_comment ); """ - When I run `wp cache flush-comment` + When I run `wp cache flush-comment 42` Then STDOUT should contain: """ - Success: Comment caches cleared. + Success: Comment cache for ID 42 cleared. """ - When I run `wp cache flush-comment 42` - Then STDOUT should contain: + @skip-object-cache + Scenario: Flush all comments cache requires support + Given a WP install + + When I try `wp cache flush-comment` + Then STDERR should contain: """ - Success: Comment cache for ID 42 cleared. + Flushing all comment caches requires WordPress 6.1+ """ @skip-object-cache - Scenario: Flush user cache + Scenario: Flush specific user cache Given a WP install And a wp-content/mu-plugins/test-harness.php file: """ @@ -88,20 +100,24 @@ Feature: Granular cache flushing operations WP_CLI::add_hook( 'before_invoke:cache flush-user', $cache_user ); """ - When I run `wp cache flush-user` + When I run `wp cache flush-user 1` Then STDOUT should contain: """ - Success: User caches cleared. + Success: User cache for ID 1 cleared. """ - When I run `wp cache flush-user 1` - Then STDOUT should contain: + @skip-object-cache + Scenario: Flush all users cache requires support + Given a WP install + + When I try `wp cache flush-user` + Then STDERR should contain: """ - Success: User cache for ID 1 cleared. + Flushing all user caches requires WordPress 6.1+ """ @skip-object-cache - Scenario: Flush option cache + Scenario: Flush specific option cache Given a WP install And a wp-content/mu-plugins/test-harness.php file: """ @@ -113,14 +129,19 @@ Feature: Granular cache flushing operations WP_CLI::add_hook( 'before_invoke:cache flush-option', $cache_option ); """ - When I run `wp cache flush-option` + When I run `wp cache flush-option my_option` Then STDOUT should contain: """ - Success: Option caches cleared. + Success: Option cache for 'my_option' cleared. """ - When I run `wp cache flush-option my_option` - Then STDOUT should contain: + @skip-object-cache + Scenario: Flush all options cache requires support + Given a WP install + + When I try `wp cache flush-option` + Then STDERR should contain: """ - Success: Option cache for 'my_option' cleared. + Flushing all option caches requires WordPress 6.1+ """ + diff --git a/src/Cache_Command.php b/src/Cache_Command.php index 79a7e8f4..c97cfeba 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -641,6 +641,9 @@ public function flush_post( $args ) { clean_post_cache( $post_id ); WP_CLI::success( "Post cache for ID $post_id cleared." ); } else { + if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { + WP_CLI::error( 'Flushing all post caches requires WordPress 6.1+ or a persistent object cache with group flushing support.' ); + } wp_cache_flush_group( 'posts' ); wp_cache_flush_group( 'post_meta' ); WP_CLI::success( 'Post caches cleared.' ); @@ -676,6 +679,9 @@ public function flush_term( $args ) { clean_term_cache( $term_id ); WP_CLI::success( "Term cache for ID $term_id cleared." ); } else { + if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { + WP_CLI::error( 'Flushing all term caches requires WordPress 6.1+ or a persistent object cache with group flushing support.' ); + } wp_cache_flush_group( 'terms' ); wp_cache_flush_group( 'term_meta' ); WP_CLI::success( 'Term caches cleared.' ); @@ -711,6 +717,9 @@ public function flush_comment( $args ) { clean_comment_cache( $comment_id ); WP_CLI::success( "Comment cache for ID $comment_id cleared." ); } else { + if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { + WP_CLI::error( 'Flushing all comment caches requires WordPress 6.1+ or a persistent object cache with group flushing support.' ); + } wp_cache_flush_group( 'comment' ); wp_cache_flush_group( 'comment_meta' ); WP_CLI::success( 'Comment caches cleared.' ); @@ -746,6 +755,9 @@ public function flush_user( $args ) { clean_user_cache( $user_id ); WP_CLI::success( "User cache for ID $user_id cleared." ); } else { + if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { + WP_CLI::error( 'Flushing all user caches requires WordPress 6.1+ or a persistent object cache with group flushing support.' ); + } wp_cache_flush_group( 'users' ); wp_cache_flush_group( 'user_meta' ); WP_CLI::success( 'User caches cleared.' ); @@ -782,6 +794,9 @@ public function flush_option( $args ) { wp_cache_delete( $option_name, 'options' ); WP_CLI::success( "Option cache for '$option_name' cleared." ); } else { + if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { + WP_CLI::error( 'Flushing all option caches requires WordPress 6.1+ or a persistent object cache with group flushing support.' ); + } wp_cache_flush_group( 'options' ); WP_CLI::success( 'Option caches cleared.' ); } From 9afec2a8a08f9cddab49f7ad6a07207fe79f3247 Mon Sep 17 00:00:00 2001 From: Al-Amin Firdows Date: Sat, 27 Jun 2026 14:12:19 +0600 Subject: [PATCH 04/10] fix: Simplify error messages for granular cache flush commands Remove " or a persistent object cache with group flushing support" suffix from error messages to match test expectations. Commands now show: - "Flushing all post caches requires WordPress 6.1+" - "Flushing all term caches requires WordPress 6.1+" - "Flushing all comment caches requires WordPress 6.1+" - "Flushing all user caches requires WordPress 6.1+" - "Flushing all option caches requires WordPress 6.1+" --- src/Cache_Command.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Cache_Command.php b/src/Cache_Command.php index c97cfeba..1c87d799 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -642,7 +642,7 @@ public function flush_post( $args ) { WP_CLI::success( "Post cache for ID $post_id cleared." ); } else { if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { - WP_CLI::error( 'Flushing all post caches requires WordPress 6.1+ or a persistent object cache with group flushing support.' ); + WP_CLI::error( 'Flushing all post caches requires WordPress 6.1+' ); } wp_cache_flush_group( 'posts' ); wp_cache_flush_group( 'post_meta' ); @@ -680,7 +680,7 @@ public function flush_term( $args ) { WP_CLI::success( "Term cache for ID $term_id cleared." ); } else { if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { - WP_CLI::error( 'Flushing all term caches requires WordPress 6.1+ or a persistent object cache with group flushing support.' ); + WP_CLI::error( 'Flushing all term caches requires WordPress 6.1+' ); } wp_cache_flush_group( 'terms' ); wp_cache_flush_group( 'term_meta' ); @@ -718,7 +718,7 @@ public function flush_comment( $args ) { WP_CLI::success( "Comment cache for ID $comment_id cleared." ); } else { if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { - WP_CLI::error( 'Flushing all comment caches requires WordPress 6.1+ or a persistent object cache with group flushing support.' ); + WP_CLI::error( 'Flushing all comment caches requires WordPress 6.1+' ); } wp_cache_flush_group( 'comment' ); wp_cache_flush_group( 'comment_meta' ); @@ -756,7 +756,7 @@ public function flush_user( $args ) { WP_CLI::success( "User cache for ID $user_id cleared." ); } else { if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { - WP_CLI::error( 'Flushing all user caches requires WordPress 6.1+ or a persistent object cache with group flushing support.' ); + WP_CLI::error( 'Flushing all user caches requires WordPress 6.1+' ); } wp_cache_flush_group( 'users' ); wp_cache_flush_group( 'user_meta' ); @@ -795,7 +795,7 @@ public function flush_option( $args ) { WP_CLI::success( "Option cache for '$option_name' cleared." ); } else { if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { - WP_CLI::error( 'Flushing all option caches requires WordPress 6.1+ or a persistent object cache with group flushing support.' ); + WP_CLI::error( 'Flushing all option caches requires WordPress 6.1+' ); } wp_cache_flush_group( 'options' ); WP_CLI::success( 'Option caches cleared.' ); From dd141ce19b3561d835a75c0912d36dbda1c1dab4 Mon Sep 17 00:00:00 2001 From: Al-Amin Firdows Date: Sat, 27 Jun 2026 14:23:35 +0600 Subject: [PATCH 05/10] fix: Check wp_cache_flush_group function exists for granular flushing Replace wp_cache_supports check with direct function existence check. wp_cache_flush_group was added in WordPress 6.1, so checking if it exists is simpler and more direct than checking cache support via wp_cache_supports. --- src/Cache_Command.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Cache_Command.php b/src/Cache_Command.php index 1c87d799..d43ff257 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -641,7 +641,7 @@ public function flush_post( $args ) { clean_post_cache( $post_id ); WP_CLI::success( "Post cache for ID $post_id cleared." ); } else { - if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { + if ( ! function_exists( 'wp_cache_flush_group' ) ) { WP_CLI::error( 'Flushing all post caches requires WordPress 6.1+' ); } wp_cache_flush_group( 'posts' ); @@ -679,7 +679,7 @@ public function flush_term( $args ) { clean_term_cache( $term_id ); WP_CLI::success( "Term cache for ID $term_id cleared." ); } else { - if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { + if ( ! function_exists( 'wp_cache_flush_group' ) ) { WP_CLI::error( 'Flushing all term caches requires WordPress 6.1+' ); } wp_cache_flush_group( 'terms' ); @@ -717,7 +717,7 @@ public function flush_comment( $args ) { clean_comment_cache( $comment_id ); WP_CLI::success( "Comment cache for ID $comment_id cleared." ); } else { - if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { + if ( ! function_exists( 'wp_cache_flush_group' ) ) { WP_CLI::error( 'Flushing all comment caches requires WordPress 6.1+' ); } wp_cache_flush_group( 'comment' ); @@ -755,7 +755,7 @@ public function flush_user( $args ) { clean_user_cache( $user_id ); WP_CLI::success( "User cache for ID $user_id cleared." ); } else { - if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { + if ( ! function_exists( 'wp_cache_flush_group' ) ) { WP_CLI::error( 'Flushing all user caches requires WordPress 6.1+' ); } wp_cache_flush_group( 'users' ); @@ -794,7 +794,7 @@ public function flush_option( $args ) { wp_cache_delete( $option_name, 'options' ); WP_CLI::success( "Option cache for '$option_name' cleared." ); } else { - if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { + if ( ! function_exists( 'wp_cache_flush_group' ) ) { WP_CLI::error( 'Flushing all option caches requires WordPress 6.1+' ); } wp_cache_flush_group( 'options' ); From 2a8d53c58c7e92d475f0a80556ff94995c56d557 Mon Sep 17 00:00:00 2001 From: Al-Amin Firdows Date: Sat, 27 Jun 2026 14:38:18 +0600 Subject: [PATCH 06/10] fix: Revert to wp_cache_supports for feature detection Use wp_cache_supports('flush_group') to check if the object cache implementation supports group flushing, rather than just checking if the function exists. This properly detects when the feature is supported by the specific cache implementation in use. --- src/Cache_Command.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Cache_Command.php b/src/Cache_Command.php index d43ff257..1c87d799 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -641,7 +641,7 @@ public function flush_post( $args ) { clean_post_cache( $post_id ); WP_CLI::success( "Post cache for ID $post_id cleared." ); } else { - if ( ! function_exists( 'wp_cache_flush_group' ) ) { + if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { WP_CLI::error( 'Flushing all post caches requires WordPress 6.1+' ); } wp_cache_flush_group( 'posts' ); @@ -679,7 +679,7 @@ public function flush_term( $args ) { clean_term_cache( $term_id ); WP_CLI::success( "Term cache for ID $term_id cleared." ); } else { - if ( ! function_exists( 'wp_cache_flush_group' ) ) { + if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { WP_CLI::error( 'Flushing all term caches requires WordPress 6.1+' ); } wp_cache_flush_group( 'terms' ); @@ -717,7 +717,7 @@ public function flush_comment( $args ) { clean_comment_cache( $comment_id ); WP_CLI::success( "Comment cache for ID $comment_id cleared." ); } else { - if ( ! function_exists( 'wp_cache_flush_group' ) ) { + if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { WP_CLI::error( 'Flushing all comment caches requires WordPress 6.1+' ); } wp_cache_flush_group( 'comment' ); @@ -755,7 +755,7 @@ public function flush_user( $args ) { clean_user_cache( $user_id ); WP_CLI::success( "User cache for ID $user_id cleared." ); } else { - if ( ! function_exists( 'wp_cache_flush_group' ) ) { + if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { WP_CLI::error( 'Flushing all user caches requires WordPress 6.1+' ); } wp_cache_flush_group( 'users' ); @@ -794,7 +794,7 @@ public function flush_option( $args ) { wp_cache_delete( $option_name, 'options' ); WP_CLI::success( "Option cache for '$option_name' cleared." ); } else { - if ( ! function_exists( 'wp_cache_flush_group' ) ) { + if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { WP_CLI::error( 'Flushing all option caches requires WordPress 6.1+' ); } wp_cache_flush_group( 'options' ); From 8652b1fb78d3e147efa8b13aa51cc7ed2914055e Mon Sep 17 00:00:00 2001 From: Al-Amin Firdows Date: Sat, 27 Jun 2026 14:48:28 +0600 Subject: [PATCH 07/10] fix: Require persistent external cache for group-flush operations WP 6.1+ default in-memory cache returns true for wp_cache_supports('flush_group'), so the old check never errored on modern WordPress. Add wp_using_ext_object_cache() as the primary gate: group flushing only makes sense with a persistent external cache (Redis, Memcached, etc.), so error without one regardless of WP version. --- src/Cache_Command.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Cache_Command.php b/src/Cache_Command.php index 1c87d799..a62a440e 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -641,7 +641,7 @@ public function flush_post( $args ) { clean_post_cache( $post_id ); WP_CLI::success( "Post cache for ID $post_id cleared." ); } else { - if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { + if ( ! wp_using_ext_object_cache() || ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { WP_CLI::error( 'Flushing all post caches requires WordPress 6.1+' ); } wp_cache_flush_group( 'posts' ); @@ -679,7 +679,7 @@ public function flush_term( $args ) { clean_term_cache( $term_id ); WP_CLI::success( "Term cache for ID $term_id cleared." ); } else { - if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { + if ( ! wp_using_ext_object_cache() || ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { WP_CLI::error( 'Flushing all term caches requires WordPress 6.1+' ); } wp_cache_flush_group( 'terms' ); @@ -717,7 +717,7 @@ public function flush_comment( $args ) { clean_comment_cache( $comment_id ); WP_CLI::success( "Comment cache for ID $comment_id cleared." ); } else { - if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { + if ( ! wp_using_ext_object_cache() || ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { WP_CLI::error( 'Flushing all comment caches requires WordPress 6.1+' ); } wp_cache_flush_group( 'comment' ); @@ -755,7 +755,7 @@ public function flush_user( $args ) { clean_user_cache( $user_id ); WP_CLI::success( "User cache for ID $user_id cleared." ); } else { - if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { + if ( ! wp_using_ext_object_cache() || ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { WP_CLI::error( 'Flushing all user caches requires WordPress 6.1+' ); } wp_cache_flush_group( 'users' ); @@ -794,7 +794,7 @@ public function flush_option( $args ) { wp_cache_delete( $option_name, 'options' ); WP_CLI::success( "Option cache for '$option_name' cleared." ); } else { - if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { + if ( ! wp_using_ext_object_cache() || ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { WP_CLI::error( 'Flushing all option caches requires WordPress 6.1+' ); } wp_cache_flush_group( 'options' ); From bbc0fdfe02ff2afc5b8a8b2cd53d564409e10d3d Mon Sep 17 00:00:00 2001 From: Al-Amin Firdows Date: Sat, 27 Jun 2026 14:58:19 +0600 Subject: [PATCH 08/10] test: Remove untestable "requires support" scenarios WP 6.1+ default in-memory cache reports flush_group support via wp_cache_supports(), and wp_using_ext_object_cache() returns true under the SQLite test driver, so neither check reliably gates these scenarios in CI. Removing the scenarios until a proper object-cache drop-in test harness is available. --- features/cache-flush-granular.feature | 49 --------------------------- 1 file changed, 49 deletions(-) diff --git a/features/cache-flush-granular.feature b/features/cache-flush-granular.feature index 2793fd6a..f0123cef 100644 --- a/features/cache-flush-granular.feature +++ b/features/cache-flush-granular.feature @@ -19,16 +19,6 @@ Feature: Granular cache flushing operations Success: Post cache for ID 123 cleared. """ - @skip-object-cache - Scenario: Flush all posts cache requires support - Given a WP install - - When I try `wp cache flush-post` - Then STDERR should contain: - """ - Flushing all post caches requires WordPress 6.1+ - """ - @skip-object-cache Scenario: Flush specific term cache Given a WP install @@ -48,16 +38,6 @@ Feature: Granular cache flushing operations Success: Term cache for ID 5 cleared. """ - @skip-object-cache - Scenario: Flush all terms cache requires support - Given a WP install - - When I try `wp cache flush-term` - Then STDERR should contain: - """ - Flushing all term caches requires WordPress 6.1+ - """ - @skip-object-cache Scenario: Flush specific comment cache Given a WP install @@ -77,16 +57,6 @@ Feature: Granular cache flushing operations Success: Comment cache for ID 42 cleared. """ - @skip-object-cache - Scenario: Flush all comments cache requires support - Given a WP install - - When I try `wp cache flush-comment` - Then STDERR should contain: - """ - Flushing all comment caches requires WordPress 6.1+ - """ - @skip-object-cache Scenario: Flush specific user cache Given a WP install @@ -106,16 +76,6 @@ Feature: Granular cache flushing operations Success: User cache for ID 1 cleared. """ - @skip-object-cache - Scenario: Flush all users cache requires support - Given a WP install - - When I try `wp cache flush-user` - Then STDERR should contain: - """ - Flushing all user caches requires WordPress 6.1+ - """ - @skip-object-cache Scenario: Flush specific option cache Given a WP install @@ -135,13 +95,4 @@ Feature: Granular cache flushing operations Success: Option cache for 'my_option' cleared. """ - @skip-object-cache - Scenario: Flush all options cache requires support - Given a WP install - - When I try `wp cache flush-option` - Then STDERR should contain: - """ - Flushing all option caches requires WordPress 6.1+ - """ From 66daf71bdabe959fb8ba81e8fba7472e9009de77 Mon Sep 17 00:00:00 2001 From: Al-Amin Firdows Date: Tue, 11 Aug 2026 07:06:34 +0600 Subject: [PATCH 09/10] Fix input validation, capability detection, and test coverage - Add proper input validation for numeric IDs to prevent silent fallthrough - Remove wp_using_ext_object_cache() requirement; rely only on wp_cache_supports( 'flush_group' ) - Check return values of wp_cache_flush_group() calls and error on failure - Add after_invoke hooks to verify cache is actually cleared - Add @require-wp-6-1 version-gated scenarios for group flush behavior - Add error test cases for invalid IDs --- features/cache-flush-granular.feature | 231 ++++++++++++++++++++++++++ src/Cache_Command.php | 80 +++++---- 2 files changed, 282 insertions(+), 29 deletions(-) diff --git a/features/cache-flush-granular.feature b/features/cache-flush-granular.feature index f0123cef..d59a83d0 100644 --- a/features/cache-flush-granular.feature +++ b/features/cache-flush-granular.feature @@ -10,7 +10,15 @@ Feature: Granular cache flushing operations wp_cache_set( 'post_123', array( 'ID' => 123, 'post_title' => 'Test' ), 'posts' ); wp_cache_set( 'meta_123', array( 'key' => 'value' ), 'post_meta' ); }; + $verify_cache_cleared = function(){ + $post = wp_cache_get( 'post_123', 'posts' ); + $meta = wp_cache_get( 'meta_123', 'post_meta' ); + if ( false !== $post || false !== $meta ) { + WP_CLI::error( 'Cache was not properly cleared.' ); + } + }; WP_CLI::add_hook( 'before_invoke:cache flush-post', $cache_post ); + WP_CLI::add_hook( 'after_invoke:cache flush-post', $verify_cache_cleared ); """ When I run `wp cache flush-post 123` @@ -29,7 +37,15 @@ Feature: Granular cache flushing operations wp_cache_set( 'term_5', array( 'term_id' => 5 ), 'terms' ); wp_cache_set( 'term_meta_5', array(), 'term_meta' ); }; + $verify_cache_cleared = function(){ + $term = wp_cache_get( 'term_5', 'terms' ); + $meta = wp_cache_get( 'term_meta_5', 'term_meta' ); + if ( false !== $term || false !== $meta ) { + WP_CLI::error( 'Cache was not properly cleared.' ); + } + }; WP_CLI::add_hook( 'before_invoke:cache flush-term', $cache_term ); + WP_CLI::add_hook( 'after_invoke:cache flush-term', $verify_cache_cleared ); """ When I run `wp cache flush-term 5` @@ -48,7 +64,15 @@ Feature: Granular cache flushing operations wp_cache_set( 'comment_42', array(), 'comment' ); wp_cache_set( 'comment_meta_42', array(), 'comment_meta' ); }; + $verify_cache_cleared = function(){ + $comment = wp_cache_get( 'comment_42', 'comment' ); + $meta = wp_cache_get( 'comment_meta_42', 'comment_meta' ); + if ( false !== $comment || false !== $meta ) { + WP_CLI::error( 'Cache was not properly cleared.' ); + } + }; WP_CLI::add_hook( 'before_invoke:cache flush-comment', $cache_comment ); + WP_CLI::add_hook( 'after_invoke:cache flush-comment', $verify_cache_cleared ); """ When I run `wp cache flush-comment 42` @@ -67,7 +91,15 @@ Feature: Granular cache flushing operations wp_cache_set( 'user_1', array( 'ID' => 1 ), 'users' ); wp_cache_set( 'user_meta_1', array(), 'user_meta' ); }; + $verify_cache_cleared = function(){ + $user = wp_cache_get( 'user_1', 'users' ); + $meta = wp_cache_get( 'user_meta_1', 'user_meta' ); + if ( false !== $user || false !== $meta ) { + WP_CLI::error( 'Cache was not properly cleared.' ); + } + }; WP_CLI::add_hook( 'before_invoke:cache flush-user', $cache_user ); + WP_CLI::add_hook( 'after_invoke:cache flush-user', $verify_cache_cleared ); """ When I run `wp cache flush-user 1` @@ -86,7 +118,15 @@ Feature: Granular cache flushing operations wp_cache_set( 'my_option', 'value', 'options' ); wp_cache_set( 'alloptions', array( 'my_option' => 'value' ), 'options' ); }; + $verify_cache_cleared = function(){ + $option = wp_cache_get( 'my_option', 'options' ); + $alloptions = wp_cache_get( 'alloptions', 'options' ); + if ( false !== $option || false !== $alloptions ) { + WP_CLI::error( 'Cache was not properly cleared.' ); + } + }; WP_CLI::add_hook( 'before_invoke:cache flush-option', $cache_option ); + WP_CLI::add_hook( 'after_invoke:cache flush-option', $verify_cache_cleared ); """ When I run `wp cache flush-option my_option` @@ -95,4 +135,195 @@ Feature: Granular cache flushing operations Success: Option cache for 'my_option' cleared. """ + @skip-object-cache + Scenario: Invalid post ID fails gracefully + Given a WP install + + When I try `wp cache flush-post abc` + Then STDERR should contain: + """ + Please provide a valid post ID. + """ + + @skip-object-cache + Scenario: Invalid term ID fails gracefully + Given a WP install + + When I try `wp cache flush-term xyz` + Then STDERR should contain: + """ + Please provide a valid term ID. + """ + + @skip-object-cache + Scenario: Invalid comment ID fails gracefully + Given a WP install + + When I try `wp cache flush-comment notanumber` + Then STDERR should contain: + """ + Please provide a valid comment ID. + """ + + @skip-object-cache + Scenario: Invalid user ID fails gracefully + Given a WP install + + When I try `wp cache flush-user nope` + Then STDERR should contain: + """ + Please provide a valid user ID. + """ + + @require-wp-6-1 @skip-object-cache + Scenario: Flush all post caches on WordPress 6.1+ + Given a WP install + And a wp-content/mu-plugins/test-harness.php file: + """ + 1 ), 'posts' ); + wp_cache_set( 'post_2', array( 'ID' => 2 ), 'posts' ); + wp_cache_set( 'meta_1', array( 'key' => 'value' ), 'post_meta' ); + }; + $verify_group_cleared = function(){ + if ( function_exists( 'wp_cache_supports' ) && wp_cache_supports( 'flush_group' ) ) { + $post1 = wp_cache_get( 'post_1', 'posts' ); + $post2 = wp_cache_get( 'post_2', 'posts' ); + $meta = wp_cache_get( 'meta_1', 'post_meta' ); + if ( false !== $post1 || false !== $post2 || false !== $meta ) { + WP_CLI::error( 'Group cache was not properly cleared.' ); + } + } + }; + WP_CLI::add_hook( 'before_invoke:cache flush-post', $cache_posts ); + WP_CLI::add_hook( 'after_invoke:cache flush-post', $verify_group_cleared ); + """ + + When I run `wp cache flush-post` + Then STDOUT should contain: + """ + Success: Post caches cleared. + """ + + @require-wp-6-1 @skip-object-cache + Scenario: Flush all term caches on WordPress 6.1+ + Given a WP install + And a wp-content/mu-plugins/test-harness.php file: + """ + 1 ), 'terms' ); + wp_cache_set( 'term_2', array( 'term_id' => 2 ), 'terms' ); + wp_cache_set( 'meta_1', array(), 'term_meta' ); + }; + $verify_group_cleared = function(){ + if ( function_exists( 'wp_cache_supports' ) && wp_cache_supports( 'flush_group' ) ) { + $term1 = wp_cache_get( 'term_1', 'terms' ); + $term2 = wp_cache_get( 'term_2', 'terms' ); + $meta = wp_cache_get( 'meta_1', 'term_meta' ); + if ( false !== $term1 || false !== $term2 || false !== $meta ) { + WP_CLI::error( 'Group cache was not properly cleared.' ); + } + } + }; + WP_CLI::add_hook( 'before_invoke:cache flush-term', $cache_terms ); + WP_CLI::add_hook( 'after_invoke:cache flush-term', $verify_group_cleared ); + """ + + When I run `wp cache flush-term` + Then STDOUT should contain: + """ + Success: Term caches cleared. + """ + + @require-wp-6-1 @skip-object-cache + Scenario: Flush all comment caches on WordPress 6.1+ + Given a WP install + And a wp-content/mu-plugins/test-harness.php file: + """ + 1 ), 'users' ); + wp_cache_set( 'user_2', array( 'ID' => 2 ), 'users' ); + wp_cache_set( 'meta_1', array(), 'user_meta' ); + }; + $verify_group_cleared = function(){ + if ( function_exists( 'wp_cache_supports' ) && wp_cache_supports( 'flush_group' ) ) { + $user1 = wp_cache_get( 'user_1', 'users' ); + $user2 = wp_cache_get( 'user_2', 'users' ); + $meta = wp_cache_get( 'meta_1', 'user_meta' ); + if ( false !== $user1 || false !== $user2 || false !== $meta ) { + WP_CLI::error( 'Group cache was not properly cleared.' ); + } + } + }; + WP_CLI::add_hook( 'before_invoke:cache flush-user', $cache_users ); + WP_CLI::add_hook( 'after_invoke:cache flush-user', $verify_group_cleared ); + """ + + When I run `wp cache flush-user` + Then STDOUT should contain: + """ + Success: User caches cleared. + """ + + @require-wp-6-1 @skip-object-cache + Scenario: Flush all option caches on WordPress 6.1+ + Given a WP install + And a wp-content/mu-plugins/test-harness.php file: + """ + $args Positional arguments. */ public function flush_post( $args ) { - $post_id = ! empty( $args ) ? (int) $args[0] : null; - - if ( $post_id ) { + if ( ! empty( $args ) ) { + if ( ! is_numeric( $args[0] ) ) { + WP_CLI::error( 'Please provide a valid post ID.' ); + } + $post_id = (int) $args[0]; clean_post_cache( $post_id ); WP_CLI::success( "Post cache for ID $post_id cleared." ); } else { - if ( ! wp_using_ext_object_cache() || ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { + if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { WP_CLI::error( 'Flushing all post caches requires WordPress 6.1+' ); } - wp_cache_flush_group( 'posts' ); - wp_cache_flush_group( 'post_meta' ); + $posts_flushed = wp_cache_flush_group( 'posts' ); + $post_meta_flushed = wp_cache_flush_group( 'post_meta' ); + if ( ! $posts_flushed || ! $post_meta_flushed ) { + WP_CLI::error( 'Failed to flush post caches.' ); + } WP_CLI::success( 'Post caches cleared.' ); } } @@ -673,17 +678,22 @@ public function flush_post( $args ) { * @param array $args Positional arguments. */ public function flush_term( $args ) { - $term_id = ! empty( $args ) ? (int) $args[0] : null; - - if ( $term_id ) { + if ( ! empty( $args ) ) { + if ( ! is_numeric( $args[0] ) ) { + WP_CLI::error( 'Please provide a valid term ID.' ); + } + $term_id = (int) $args[0]; clean_term_cache( $term_id ); WP_CLI::success( "Term cache for ID $term_id cleared." ); } else { - if ( ! wp_using_ext_object_cache() || ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { + if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { WP_CLI::error( 'Flushing all term caches requires WordPress 6.1+' ); } - wp_cache_flush_group( 'terms' ); - wp_cache_flush_group( 'term_meta' ); + $terms_flushed = wp_cache_flush_group( 'terms' ); + $term_meta_flushed = wp_cache_flush_group( 'term_meta' ); + if ( ! $terms_flushed || ! $term_meta_flushed ) { + WP_CLI::error( 'Failed to flush term caches.' ); + } WP_CLI::success( 'Term caches cleared.' ); } } @@ -711,17 +721,22 @@ public function flush_term( $args ) { * @param array $args Positional arguments. */ public function flush_comment( $args ) { - $comment_id = ! empty( $args ) ? (int) $args[0] : null; - - if ( $comment_id ) { + if ( ! empty( $args ) ) { + if ( ! is_numeric( $args[0] ) ) { + WP_CLI::error( 'Please provide a valid comment ID.' ); + } + $comment_id = (int) $args[0]; clean_comment_cache( $comment_id ); WP_CLI::success( "Comment cache for ID $comment_id cleared." ); } else { - if ( ! wp_using_ext_object_cache() || ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { + if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { WP_CLI::error( 'Flushing all comment caches requires WordPress 6.1+' ); } - wp_cache_flush_group( 'comment' ); - wp_cache_flush_group( 'comment_meta' ); + $comment_flushed = wp_cache_flush_group( 'comment' ); + $comment_meta_flushed = wp_cache_flush_group( 'comment_meta' ); + if ( ! $comment_flushed || ! $comment_meta_flushed ) { + WP_CLI::error( 'Failed to flush comment caches.' ); + } WP_CLI::success( 'Comment caches cleared.' ); } } @@ -749,17 +764,22 @@ public function flush_comment( $args ) { * @param array $args Positional arguments. */ public function flush_user( $args ) { - $user_id = ! empty( $args ) ? (int) $args[0] : null; - - if ( $user_id ) { + if ( ! empty( $args ) ) { + if ( ! is_numeric( $args[0] ) ) { + WP_CLI::error( 'Please provide a valid user ID.' ); + } + $user_id = (int) $args[0]; clean_user_cache( $user_id ); WP_CLI::success( "User cache for ID $user_id cleared." ); } else { - if ( ! wp_using_ext_object_cache() || ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { + if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { WP_CLI::error( 'Flushing all user caches requires WordPress 6.1+' ); } - wp_cache_flush_group( 'users' ); - wp_cache_flush_group( 'user_meta' ); + $users_flushed = wp_cache_flush_group( 'users' ); + $user_meta_flushed = wp_cache_flush_group( 'user_meta' ); + if ( ! $users_flushed || ! $user_meta_flushed ) { + WP_CLI::error( 'Failed to flush user caches.' ); + } WP_CLI::success( 'User caches cleared.' ); } } @@ -787,17 +807,19 @@ public function flush_user( $args ) { * @param array $args Positional arguments. */ public function flush_option( $args ) { - $option_name = ! empty( $args ) ? $args[0] : null; - - if ( $option_name ) { + if ( ! empty( $args ) ) { + $option_name = $args[0]; wp_cache_delete( 'alloptions', 'options' ); wp_cache_delete( $option_name, 'options' ); WP_CLI::success( "Option cache for '$option_name' cleared." ); } else { - if ( ! wp_using_ext_object_cache() || ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { + if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { WP_CLI::error( 'Flushing all option caches requires WordPress 6.1+' ); } - wp_cache_flush_group( 'options' ); + $options_flushed = wp_cache_flush_group( 'options' ); + if ( ! $options_flushed ) { + WP_CLI::error( 'Failed to flush option caches.' ); + } WP_CLI::success( 'Option caches cleared.' ); } } From bc41b9e4e7bd3c468e1f5e17f92f39f9c86435ca Mon Sep 17 00:00:00 2001 From: Al-Amin Firdows Date: Sun, 23 Aug 2026 11:47:58 +0600 Subject: [PATCH 10/10] fix issues --- features/cache-flush-granular.feature | 102 ++++++++++++++++++++++---- src/Cache_Command.php | 15 ++-- 2 files changed, 96 insertions(+), 21 deletions(-) diff --git a/features/cache-flush-granular.feature b/features/cache-flush-granular.feature index d59a83d0..26c52972 100644 --- a/features/cache-flush-granular.feature +++ b/features/cache-flush-granular.feature @@ -7,12 +7,12 @@ Feature: Granular cache flushing operations """ 123, 'post_title' => 'Test' ), 'posts' ); - wp_cache_set( 'meta_123', array( 'key' => 'value' ), 'post_meta' ); + wp_cache_set( 123, array( 'ID' => 123, 'post_title' => 'Test' ), 'posts' ); + wp_cache_set( 123, array( 'key' => 'value' ), 'post_meta' ); }; $verify_cache_cleared = function(){ - $post = wp_cache_get( 'post_123', 'posts' ); - $meta = wp_cache_get( 'meta_123', 'post_meta' ); + $post = wp_cache_get( 123, 'posts' ); + $meta = wp_cache_get( 123, 'post_meta' ); if ( false !== $post || false !== $meta ) { WP_CLI::error( 'Cache was not properly cleared.' ); } @@ -34,12 +34,12 @@ Feature: Granular cache flushing operations """ 5 ), 'terms' ); - wp_cache_set( 'term_meta_5', array(), 'term_meta' ); + wp_cache_set( 5, array( 'term_id' => 5 ), 'terms' ); + wp_cache_set( 5, array(), 'term_meta' ); }; $verify_cache_cleared = function(){ - $term = wp_cache_get( 'term_5', 'terms' ); - $meta = wp_cache_get( 'term_meta_5', 'term_meta' ); + $term = wp_cache_get( 5, 'terms' ); + $meta = wp_cache_get( 5, 'term_meta' ); if ( false !== $term || false !== $meta ) { WP_CLI::error( 'Cache was not properly cleared.' ); } @@ -54,6 +54,16 @@ Feature: Granular cache flushing operations Success: Term cache for ID 5 cleared. """ + @skip-object-cache + Scenario: Flush cache for an existing term resolves its taxonomy + Given a WP install + + When I run `wp cache flush-term 1` + Then STDOUT should contain: + """ + Success: Term cache for ID 1 cleared. + """ + @skip-object-cache Scenario: Flush specific comment cache Given a WP install @@ -61,12 +71,12 @@ Feature: Granular cache flushing operations """ 1 ), 'users' ); - wp_cache_set( 'user_meta_1', array(), 'user_meta' ); + wp_cache_set( 1, array( 'ID' => 1 ), 'users' ); + wp_cache_set( 1, array(), 'user_meta' ); }; $verify_cache_cleared = function(){ - $user = wp_cache_get( 'user_1', 'users' ); - $meta = wp_cache_get( 'user_meta_1', 'user_meta' ); + $user = wp_cache_get( 1, 'users' ); + $meta = wp_cache_get( 1, 'user_meta' ); if ( false !== $user || false !== $meta ) { WP_CLI::error( 'Cache was not properly cleared.' ); } @@ -175,6 +185,66 @@ Feature: Granular cache flushing operations Please provide a valid user ID. """ + @skip-object-cache + Scenario Outline: Non-positive post IDs fail gracefully + Given a WP install + + When I try `wp cache flush-post ` + Then STDERR should contain: + """ + Please provide a valid post ID. + """ + + Examples: + | id | + | 0 | + | -1 | + + @skip-object-cache + Scenario Outline: Non-positive term IDs fail gracefully + Given a WP install + + When I try `wp cache flush-term ` + Then STDERR should contain: + """ + Please provide a valid term ID. + """ + + Examples: + | id | + | 0 | + | -1 | + + @skip-object-cache + Scenario Outline: Non-positive comment IDs fail gracefully + Given a WP install + + When I try `wp cache flush-comment ` + Then STDERR should contain: + """ + Please provide a valid comment ID. + """ + + Examples: + | id | + | 0 | + | -1 | + + @skip-object-cache + Scenario Outline: Non-positive user IDs fail gracefully + Given a WP install + + When I try `wp cache flush-user ` + Then STDERR should contain: + """ + Please provide a valid user ID. + """ + + Examples: + | id | + | 0 | + | -1 | + @require-wp-6-1 @skip-object-cache Scenario: Flush all post caches on WordPress 6.1+ Given a WP install diff --git a/src/Cache_Command.php b/src/Cache_Command.php index 164c577d..795bc862 100644 --- a/src/Cache_Command.php +++ b/src/Cache_Command.php @@ -636,7 +636,7 @@ function ( $key ) { */ public function flush_post( $args ) { if ( ! empty( $args ) ) { - if ( ! is_numeric( $args[0] ) ) { + if ( ! is_numeric( $args[0] ) || (int) $args[0] <= 0 ) { WP_CLI::error( 'Please provide a valid post ID.' ); } $post_id = (int) $args[0]; @@ -679,11 +679,14 @@ public function flush_post( $args ) { */ public function flush_term( $args ) { if ( ! empty( $args ) ) { - if ( ! is_numeric( $args[0] ) ) { + if ( ! is_numeric( $args[0] ) || (int) $args[0] <= 0 ) { WP_CLI::error( 'Please provide a valid term ID.' ); } $term_id = (int) $args[0]; - clean_term_cache( $term_id ); + $term = get_term( $term_id ); + $taxonomy = ( $term && ! is_wp_error( $term ) ) ? $term->taxonomy : ''; + clean_term_cache( $term_id, $taxonomy ); + wp_cache_delete( $term_id, 'term_meta' ); WP_CLI::success( "Term cache for ID $term_id cleared." ); } else { if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { @@ -722,11 +725,12 @@ public function flush_term( $args ) { */ public function flush_comment( $args ) { if ( ! empty( $args ) ) { - if ( ! is_numeric( $args[0] ) ) { + if ( ! is_numeric( $args[0] ) || (int) $args[0] <= 0 ) { WP_CLI::error( 'Please provide a valid comment ID.' ); } $comment_id = (int) $args[0]; clean_comment_cache( $comment_id ); + wp_cache_delete( $comment_id, 'comment_meta' ); WP_CLI::success( "Comment cache for ID $comment_id cleared." ); } else { if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) { @@ -765,11 +769,12 @@ public function flush_comment( $args ) { */ public function flush_user( $args ) { if ( ! empty( $args ) ) { - if ( ! is_numeric( $args[0] ) ) { + if ( ! is_numeric( $args[0] ) || (int) $args[0] <= 0 ) { WP_CLI::error( 'Please provide a valid user ID.' ); } $user_id = (int) $args[0]; clean_user_cache( $user_id ); + wp_cache_delete( $user_id, 'user_meta' ); WP_CLI::success( "User cache for ID $user_id cleared." ); } else { if ( ! function_exists( 'wp_cache_supports' ) || ! wp_cache_supports( 'flush_group' ) ) {