-
Notifications
You must be signed in to change notification settings - Fork 94
Add wp post revision restore, diff, and prune commands #563
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
f919b12
8f2b422
98d8590
598c559
af620a2
9b54f2f
3e511a1
acc2907
c1c8cf9
4b174c4
087ee6b
f812fc5
b6babf6
52cb85a
b18631e
8503d88
698da34
c0611b0
5efdc41
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| Feature: Manage WordPress post revisions | ||
|
|
||
| Background: | ||
| Given a WP install | ||
|
|
||
| Scenario: Restore a post revision | ||
| When I run `wp post create --post_title='Original Post' --post_content='Original content' --porcelain` | ||
| Then STDOUT should be a number | ||
| And save STDOUT as {POST_ID} | ||
|
|
||
| When I run `wp post update {POST_ID} --post_content='Updated content'` | ||
| Then STDOUT should contain: | ||
| """ | ||
| Success: Updated post {POST_ID}. | ||
| """ | ||
|
|
||
| When I run `wp post list --post_type=revision --post_parent={POST_ID} --fields=ID,post_title --format=ids` | ||
| Then STDOUT should not be empty | ||
| And save STDOUT as {REVISION_ID} | ||
|
|
||
| When I run `wp post revision restore {REVISION_ID}` | ||
| Then STDOUT should contain: | ||
| """ | ||
| Success: Restored revision | ||
| """ | ||
|
|
||
| When I run `wp post get {POST_ID} --field=post_content` | ||
| Then STDOUT should contain: | ||
| """ | ||
| Original content | ||
| """ | ||
|
|
||
| Scenario: Restore invalid revision should fail | ||
| When I try `wp post revision restore 99999` | ||
| Then STDERR should contain: | ||
| """ | ||
| Error: Invalid revision ID | ||
| """ | ||
| And the return code should be 1 | ||
|
|
||
| Scenario: Show diff between two revisions | ||
| When I run `wp post create --post_title='Test Post' --post_content='First version' --porcelain` | ||
| Then STDOUT should be a number | ||
| And save STDOUT as {POST_ID} | ||
|
|
||
| When I run `wp post update {POST_ID} --post_content='Second version'` | ||
| Then STDOUT should contain: | ||
| """ | ||
| Success: Updated post {POST_ID}. | ||
| """ | ||
|
|
||
| When I run `wp post list --post_type=revision --post_parent={POST_ID} --fields=ID --format=csv --orderby=ID --order=ASC` | ||
| Then STDOUT should not be empty | ||
|
|
||
| When I run `wp post list --post_type=revision --post_parent={POST_ID} --format=ids --orderby=ID --order=ASC` | ||
| Then STDOUT should not be empty | ||
|
|
||
| Scenario: Show diff between revision and current post | ||
| When I run `wp post create --post_title='Diff Test' --post_content='Original text' --porcelain` | ||
| Then STDOUT should be a number | ||
| And save STDOUT as {POST_ID} | ||
|
|
||
| When I run `wp post update {POST_ID} --post_content='Modified text'` | ||
| Then STDOUT should contain: | ||
| """ | ||
| Success: Updated post {POST_ID}. | ||
| """ | ||
|
|
||
| When I run `wp post list --post_type=revision --post_parent={POST_ID} --fields=ID --format=ids --orderby=ID --order=ASC` | ||
| Then STDOUT should not be empty | ||
| And save STDOUT as {REVISION_ID} | ||
|
|
||
| When I run `wp post revision diff {REVISION_ID}` | ||
| Then the return code should be 0 | ||
|
|
||
| Scenario: Diff with invalid revision should fail | ||
| When I try `wp post revision diff 99999` | ||
| Then STDERR should contain: | ||
| """ | ||
| Error: Invalid 'from' ID | ||
| """ | ||
| And the return code should be 1 | ||
|
|
||
| Scenario: Diff between two invalid revisions should fail | ||
| When I try `wp post revision diff 99998 99999` | ||
| Then STDERR should contain: | ||
| """ | ||
| Error: Invalid 'from' ID | ||
| """ | ||
| And the return code should be 1 | ||
|
|
||
| Scenario: Diff with specific field | ||
| When I run `wp post create --post_title='Field Test' --post_content='Some content' --porcelain` | ||
| Then STDOUT should be a number | ||
| And save STDOUT as {POST_ID} | ||
|
|
||
| When I run `wp post update {POST_ID} --post_title='Modified Field Test'` | ||
| Then STDOUT should contain: | ||
| """ | ||
| Success: Updated post {POST_ID}. | ||
| """ | ||
|
|
||
| When I run `wp post list --post_type=revision --post_parent={POST_ID} --fields=ID --format=ids --orderby=ID --order=ASC` | ||
| Then STDOUT should not be empty | ||
| And save STDOUT as {REVISION_ID} | ||
|
|
||
| When I run `wp post revision diff {REVISION_ID} --field=post_title` | ||
| Then the return code should be 0 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,186 @@ | ||
| <?php | ||
|
|
||
| use WP_CLI\Utils; | ||
|
|
||
| /** | ||
| * Manages post revisions. | ||
| * | ||
| * ## EXAMPLES | ||
| * | ||
| * # Restore a post revision | ||
| * $ wp post revision restore 123 | ||
| * Success: Restored revision 123. | ||
| * | ||
| * # Show diff between two revisions | ||
| * $ wp post revision diff 123 456 | ||
| * | ||
| * @package wp-cli | ||
| */ | ||
| class Post_Revision_Command { | ||
|
|
||
| /** | ||
| * Valid post fields that can be compared. | ||
| * | ||
| * @var array<string> | ||
| */ | ||
| private $valid_fields = [ | ||
| 'post_title', | ||
| 'post_content', | ||
| 'post_excerpt', | ||
| 'post_name', | ||
| 'post_status', | ||
| 'post_type', | ||
| 'post_author', | ||
| 'post_date', | ||
| 'post_date_gmt', | ||
| 'post_modified', | ||
| 'post_modified_gmt', | ||
| 'post_parent', | ||
| 'menu_order', | ||
| 'comment_status', | ||
| 'ping_status', | ||
| ]; | ||
|
|
||
| /** | ||
| * Restores a post revision. | ||
| * | ||
| * ## OPTIONS | ||
| * | ||
| * <revision_id> | ||
| * : The revision ID to restore. | ||
| * | ||
| * ## EXAMPLES | ||
| * | ||
| * # Restore a post revision | ||
| * $ wp post revision restore 123 | ||
| * Success: Restored revision 123. | ||
| * | ||
| * @subcommand restore | ||
| */ | ||
| public function restore( $args ) { | ||
| $revision_id = (int) $args[0]; | ||
|
|
||
| // Get the revision post | ||
| $revision = wp_get_post_revision( $revision_id ); | ||
|
|
||
| if ( ! $revision ) { | ||
| WP_CLI::error( "Invalid revision ID {$revision_id}." ); | ||
| } | ||
|
|
||
| // Restore the revision | ||
| $restored_post_id = wp_restore_post_revision( $revision_id ); | ||
|
|
||
| // wp_restore_post_revision() returns post ID on success, false on failure, or null if revision is same as current | ||
| if ( ! $restored_post_id ) { | ||
swissspidy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| WP_CLI::error( "Failed to restore revision {$revision_id}." ); | ||
| } | ||
|
|
||
| WP_CLI::success( "Restored revision {$revision_id}." ); | ||
swissspidy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| /** | ||
| * Shows the difference between two revisions. | ||
| * | ||
| * ## OPTIONS | ||
| * | ||
| * <from> | ||
| * : The 'from' revision ID or post ID. | ||
| * | ||
| * [<to>] | ||
| * : The 'to' revision ID. If not provided, compares with the current post. | ||
swissspidy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| * | ||
| * [--field=<field>] | ||
| * : Compare specific field(s). Default: post_content | ||
| * | ||
| * ## EXAMPLES | ||
| * | ||
| * # Show diff between two revisions | ||
| * $ wp post revision diff 123 456 | ||
| * | ||
| * # Show diff between a revision and the current post | ||
| * $ wp post revision diff 123 | ||
| * | ||
| * @subcommand diff | ||
| */ | ||
| public function diff( $args, $assoc_args ) { | ||
| $from_id = (int) $args[0]; | ||
| $to_id = isset( $args[1] ) ? (int) $args[1] : null; | ||
| $field = Utils\get_flag_value( $assoc_args, 'field', 'post_content' ); | ||
|
|
||
| // Get the 'from' revision or post | ||
| $from_revision = wp_get_post_revision( $from_id ); | ||
| if ( ! $from_revision instanceof \WP_Post ) { | ||
| // Try as a regular post | ||
| $from_revision = get_post( $from_id ); | ||
| if ( ! $from_revision instanceof \WP_Post ) { | ||
| WP_CLI::error( "Invalid 'from' ID {$from_id}." ); | ||
| } | ||
| } | ||
|
|
||
| // Get the 'to' revision or post | ||
| $to_revision = null; | ||
| if ( $to_id ) { | ||
| $to_revision = wp_get_post_revision( $to_id ); | ||
| if ( ! $to_revision instanceof \WP_Post ) { | ||
| // Try as a regular post | ||
| $to_revision = get_post( $to_id ); | ||
| if ( ! $to_revision instanceof \WP_Post ) { | ||
| WP_CLI::error( "Invalid 'to' ID {$to_id}." ); | ||
| } | ||
| } | ||
|
||
| } elseif ( 'revision' === $from_revision->post_type ) { | ||
| // If no 'to' ID provided, use the parent post of the revision | ||
| $to_revision = get_post( $from_revision->post_parent ); | ||
| if ( ! $to_revision instanceof \WP_Post ) { | ||
| WP_CLI::error( "Could not find parent post for revision {$from_id}." ); | ||
| } | ||
| } else { | ||
| WP_CLI::error( "Please provide a 'to' revision ID when comparing posts." ); | ||
| } | ||
|
|
||
| // Validate field | ||
| if ( ! in_array( $field, $this->valid_fields, true ) ) { | ||
| WP_CLI::error( "Invalid field '{$field}'. Valid fields: " . implode( ', ', $this->valid_fields ) ); | ||
| } | ||
|
|
||
| // Get the field values - use isset to check if field exists on the object | ||
| if ( ! isset( $from_revision->{$field} ) ) { | ||
| WP_CLI::error( "Field '{$field}' not found on revision {$from_id}." ); | ||
swissspidy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| // $to_revision is guaranteed to be non-null at this point due to earlier validation | ||
| if ( ! isset( $to_revision->{$field} ) ) { | ||
| $to_error_id = $to_id ?? $to_revision->ID; | ||
| WP_CLI::error( "Field '{$field}' not found on revision/post {$to_error_id}." ); | ||
| } | ||
|
|
||
| $left_string = $from_revision->{$field}; | ||
| $right_string = $to_revision->{$field}; | ||
|
|
||
| // Generate the diff | ||
| $diff_args = [ | ||
| 'title_left' => sprintf( | ||
| '%s (%s) - ID %d', | ||
| $from_revision->post_title, | ||
| $from_revision->post_modified, | ||
| $from_revision->ID | ||
| ), | ||
| 'title_right' => sprintf( | ||
| '%s (%s) - ID %d', | ||
| $to_revision->post_title, | ||
| $to_revision->post_modified, | ||
| $to_revision->ID | ||
| ), | ||
| ]; | ||
|
|
||
| $diff = wp_text_diff( $left_string, $right_string, $diff_args ); | ||
|
|
||
| if ( ! $diff ) { | ||
| WP_CLI::success( 'No difference found.' ); | ||
| return; | ||
| } | ||
|
|
||
| // Output the diff | ||
| WP_CLI::line( $diff ); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test scenario is incomplete. It creates revisions and verifies they exist, but it never actually runs the
wp post revision diffcommand to test the diff functionality between two revisions. Add test steps to execute the diff command with two revision IDs and verify the output.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot apply changes based on this feedback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in c1c8cf9. The test scenario now:
wp post revision diffwith two revision IDs