Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0ccc287
feat: add --all flag to comment delete command
shawnhooper Oct 15, 2025
be45039
fix: linting errors
shawnhooper Oct 15, 2025
24f1c4c
fix: phpstan issues
shawnhooper Oct 15, 2025
c4d8775
fix: phpstan issues
shawnhooper Oct 15, 2025
ea5d314
fix: incorrect return type
shawnhooper Oct 15, 2025
846b801
fix: always return array
shawnhooper Oct 15, 2025
6dbf62d
fix: code style
shawnhooper Oct 15, 2025
e0f124b
fix: update test expectations to handle comment deletion order
shawnhooper Oct 15, 2025
000c832
fix: remove $exclude code
shawnhooper Oct 16, 2025
860bb2b
fix: defer comment counts
shawnhooper Oct 20, 2025
3af6933
fix: strict comparison on mixed
shawnhooper Oct 20, 2025
3c9ea3c
fix: strict comparison on mixed
shawnhooper Oct 20, 2025
95e7211
fix: phpcs comparison
shawnhooper Oct 20, 2025
1e396e8
fix: behat tests. Add checks for multiple success lines
shawnhooper Oct 20, 2025
a7849ca
fix: behat tests. Add checks for multiple success lines
shawnhooper Oct 20, 2025
669caae
test: Delete comments with explicit defer-term-counting flag
shawnhooper Oct 20, 2025
8a3df5b
test: Success/Error returns
shawnhooper Oct 20, 2025
db90889
fix: remove --defer-comment-count flag, not referenced in coommand def
shawnhooper Oct 21, 2025
1c8144c
test: return to STDERR
shawnhooper Oct 21, 2025
37c0ba6
test: combined success/warning output to STDOUT
shawnhooper Oct 21, 2025
61f74b6
test: trying to get combined success/fail ouput
shawnhooper Oct 21, 2025
d33e0b8
test: add blank line to return
shawnhooper Oct 21, 2025
fc0e2a2
test: could it be STDERR, now that we have the foramtting fixed?
shawnhooper Oct 21, 2025
fb2d6be
test: Separates STDOUT and STDERR
shawnhooper Oct 21, 2025
d0dd60a
Last try on STDOUT
shawnhooper Oct 21, 2025
a8bdff2
test: ah, the problem was I try vs I run
shawnhooper Oct 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions features/comment.feature
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Feature: Manage WordPress comments
"""
Success: Trashed comment 3.
Success: Trashed comment 4.
Success: Deleted 2 comments.
"""

When I run `wp comment delete 3`
Expand Down Expand Up @@ -472,3 +473,148 @@ Feature: Manage WordPress comments
And I run `wp comment unspam {COMMENT_ID} --url=www.example.com`
And I run `wp comment trash {COMMENT_ID} --url=www.example.com`
And I run `wp comment untrash {COMMENT_ID} --url=www.example.com`

Scenario: Delete all comments with --all flag
Given a WP install
And I run `wp comment create --comment_post_ID=1 --comment_content='Comment 1' --porcelain`
And save STDOUT as {COMMENT_ID_1}
And I run `wp comment create --comment_post_ID=1 --comment_content='Comment 2' --porcelain`
And save STDOUT as {COMMENT_ID_2}
And I run `wp comment create --comment_post_ID=1 --comment_content='Comment 3' --porcelain`
And save STDOUT as {COMMENT_ID_3}

When I run `wp comment list --format=count`
Then STDOUT should be:
"""
4
"""

When I run `wp comment delete --all`
Then STDOUT should contain:
"""
Success: Trashed comment 1.
"""
And STDOUT should contain:
"""
Success: Trashed comment {COMMENT_ID_1}.
"""
And STDOUT should contain:
"""
Success: Trashed comment {COMMENT_ID_2}.
"""
And STDOUT should contain:
"""
Success: Trashed comment {COMMENT_ID_3}.
"""

When I run `wp comment list --format=count`
Then STDOUT should be:
"""
0
"""

Scenario: Delete all comments with --all flag and --force
Given a WP install
And I run `wp comment create --comment_post_ID=1 --comment_content='Comment 1' --porcelain`
And save STDOUT as {COMMENT_ID_1}
And I run `wp comment create --comment_post_ID=1 --comment_content='Comment 2' --porcelain`
And save STDOUT as {COMMENT_ID_2}

When I run `wp comment list --format=count`
Then STDOUT should be:
"""
3
"""

When I run `wp comment delete --all --force`
Then STDOUT should contain:
"""
Success: Deleted comment 1.
"""
And STDOUT should contain:
"""
Success: Deleted comment {COMMENT_ID_1}.
"""
And STDOUT should contain:
"""
Success: Deleted comment {COMMENT_ID_2}.
"""

When I run `wp comment list --format=count`
Then STDOUT should be:
"""
0
"""

Scenario: Delete all comments when no comments exist
Given a WP install
And I run `wp comment delete $(wp comment list --field=ID) --force`

When I run `wp comment delete --all`
Then STDOUT should be:
"""
Success: No comments deleted.
"""

Scenario: Delete multiple comments shows summary message
Given a WP install
And I run `wp comment create --comment_post_ID=1 --comment_content='Comment 1' --porcelain`
And save STDOUT as {COMMENT_ID_1}
And I run `wp comment create --comment_post_ID=1 --comment_content='Comment 2' --porcelain`
And save STDOUT as {COMMENT_ID_2}
And I run `wp comment create --comment_post_ID=1 --comment_content='Comment 3' --porcelain`
And save STDOUT as {COMMENT_ID_3}

When I run `wp comment delete {COMMENT_ID_1} {COMMENT_ID_2} {COMMENT_ID_3}`
Then STDOUT should contain:
"""
Success: Trashed comment {COMMENT_ID_1}.
"""
And STDOUT should contain:
"""
Success: Trashed comment {COMMENT_ID_2}.
"""
And STDOUT should contain:
"""
Success: Trashed comment {COMMENT_ID_3}.
"""
And STDOUT should contain:
"""
Success: Deleted 3 comments.
"""

Scenario: Delete comments with mixed success and failure
Given a WP install
And I run `wp comment create --comment_post_ID=1 --comment_content='Comment 1' --porcelain`
And save STDOUT as {COMMENT_ID_1}
And I run `wp comment create --comment_post_ID=1 --comment_content='Comment 2' --porcelain`
And save STDOUT as {COMMENT_ID_2}

When I try `wp comment delete {COMMENT_ID_1} {COMMENT_ID_2} 99999`
Then STDOUT should contain:
"""
Success: Trashed comment {COMMENT_ID_1}.
"""
And STDOUT should contain:
"""
Success: Trashed comment {COMMENT_ID_2}.
"""
And STDERR should contain:
"""
Warning: Failed deleting comment 99999.
"""
And STDERR should contain:
"""
Error: Failed deleting 1 comments.
"""
And the return code should be 1

Scenario: Error when no comment IDs and no --all flag provided
Given a WP install

When I try `wp comment delete`
Then STDERR should be:
"""
Error: Please specify one or more comment IDs, or use --all.
"""
And the return code should be 1
117 changes: 102 additions & 15 deletions src/Comment_Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* # Update an existing comment.
* $ wp comment update 123 --comment_author='That Guy'
* Success: Updated comment 123.
*

* # Delete an existing comment.
* $ wp comment delete 1337 --force
* Success: Deleted comment 1337.
Expand Down Expand Up @@ -416,9 +416,12 @@ function ( $comment ) {
*
* ## OPTIONS
*
* <id>...
* [<id>...]
* : One or more IDs of comments to delete.
*
* [--all]
* : If set, all comments will be deleted.
*
* [--force]
* : Skip the trash bin.
*
Expand All @@ -432,25 +435,65 @@ function ( $comment ) {
* $ wp comment delete 1337 2341 --force
* Success: Deleted comment 1337.
* Success: Deleted comment 2341.
*
* # Delete all comments.
* $ wp comment delete --all --force
* Success: Deleted comment 1337.
* Success: Deleted comment 2341.
* Success: Deleted 2 of 2 comments.
*/
public function delete( $args, $assoc_args ) {
parent::_delete(
$args,
$assoc_args,
function ( $comment_id, $assoc_args ) {
$force = (bool) Utils\get_flag_value( $assoc_args, 'force' );
$all = Utils\get_flag_value( $assoc_args, 'all', false );

$status = wp_get_comment_status( $comment_id );
$result = wp_delete_comment( $comment_id, $force );
// Check if comment IDs or --all is passed.
$args = $this->check_optional_args_and_all( $args, $all, 'delete' );
if ( ! $args ) {
return;
}

if ( ! $result ) {
return [ 'error', "Failed deleting comment {$comment_id}." ];
}
$status = 0;

$verb = ( $force || 'trash' === $status ) ? 'Deleted' : 'Trashed';
return [ 'success', "{$verb} comment {$comment_id}." ];
$defer_term_counting = wp_defer_comment_counting();
if ( $all ) {
wp_defer_term_counting( true );
}

$total = count( $args );
$successfully_deleted = 0;

$force = (bool) Utils\get_flag_value( $assoc_args, 'force' );

foreach ( $args as $comment_id ) {

$comment_status = wp_get_comment_status( $comment_id );
$result = wp_delete_comment( $comment_id, $force );

if ( ! $result ) {
$response = [ 'error', "Failed deleting comment {$comment_id}." ];
$status = $this->success_or_failure( $response );
// Keep status as 1 (error) if any deletion fails
} else {
$verb = ( $force || 'trash' === $comment_status ) ? 'Deleted' : 'Trashed';
$response = [ 'success', "{$verb} comment {$comment_id}." ];
$this->success_or_failure( $response );
++$successfully_deleted;
}
);
}

if ( $all ) {
wp_defer_term_counting( $defer_term_counting );
}

if ( 0 === $status ) {
if ( $total > 1 ) {
WP_CLI::success( "Deleted {$successfully_deleted} comments." );
}
} else {
$error_count = $total - $successfully_deleted;
WP_CLI::error( "Failed deleting {$error_count} comments." );
}

exit( $status );
}

private function call( $args, $status, $success, $failure ) {
Expand Down Expand Up @@ -734,4 +777,48 @@ public function exists( $args ) {
WP_CLI::success( "Comment with ID {$args[0]} exists." );
}
}

/**
* If have optional args ([<id>...]) and an all option, then check have something to do.
*
* @param array $args Passed-in arguments.
* @param bool $all All flag.
* @param string $verb Optional. Verb to use. Defaults to 'delete'.
* @return array Same as $args if not all, otherwise all comment IDs.
*/
private function check_optional_args_and_all( $args, $all, $verb = 'delete' ) {
if ( $all ) {
$args = $this->get_all_comment_ids();
}

if ( empty( $args ) ) {
if ( ! $all ) {
WP_CLI::error( 'Please specify one or more comment IDs, or use --all.' );
}

$past_tense_verb = Utils\past_tense_verb( $verb );
WP_CLI::success( "No comments {$past_tense_verb}." );
}

return $args;
}

/**
* Gets all available comment IDs.
*/
private function get_all_comment_ids(): array {
$query = new WP_Comment_Query();
$comments = $query->query(
array(
'fields' => 'ids',
'number' => 0, // Get all comments
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds like it could be very slow on a large site

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, I didn't like the looping either, but I wanted it to still trigger the delete_comment and deleted_comment hooks.

Do you have any suggestions?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which makes sense I suppose, there is usually a lot attached to these filters. And wp_delete_comment itself does a lot as well, such as moving up children, deleting comment meta, and updating comment count. Plus, only this way can we adhere to the --force flag as well.

So yeah... there might be no way around it. Maybe it would be worth adding a warning to the docblock to indicate this might be slow if there are lots of comments.

We should probably use wp_defer_comment_counting() to defer updating comment counts, otherwise it will be done after every single deletion.

Something like:

$defer_count = wp_defer_comment_counting();

wp_defer_comment_counting( true );

// delete all comments

wp_defer_comment_counting( $defer_count )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@swissspidy Ok. I've added in the support for wp_defer_comment_counting. This got a little more complex, since the call to the parent::_delete() function exited WP-CLI after a single delete.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shawnhooper That's amazing, thanks a lot for diving straight in!

I see you're battling with the Behat tests. Tip: If you are expecting an error output in a test, you need to use When I try ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@swissspidy Yep, that did it! Thanks, was really banging my head against my desk. Thinking it was STDOUT vs STDERR issues, etc.

)
);

if ( ! is_array( $comments ) ) {
return [];
}

return $comments;
}
}