diff --git a/js/src/duplicate-post-edit-script.js b/js/src/duplicate-post-edit-script.js index 3587ef8d0..5f27c6a4f 100644 --- a/js/src/duplicate-post-edit-script.js +++ b/js/src/duplicate-post-edit-script.js @@ -257,6 +257,7 @@ class DuplicatePost { notice.text, { isDismissible: notice.isDismissible || true, + __unstableHTML: notice.isHTML || false, } ); } diff --git a/src/watchers/copied-post-watcher.php b/src/watchers/copied-post-watcher.php index 2e7278933..71aec54fa 100644 --- a/src/watchers/copied-post-watcher.php +++ b/src/watchers/copied-post-watcher.php @@ -47,9 +47,33 @@ public function register_hooks() { */ public function get_notice_text( $post ) { if ( $this->permissions_helper->has_trashed_rewrite_and_republish_copy( $post ) ) { + $trash_url = \add_query_arg( + [ + 'post_status' => 'trash', + 'post_type' => $post->post_type, + ], + \admin_url( 'edit.php' ), + ); + $view_trash_html = \sprintf( + ' %2$s', + \esc_url( $trash_url ), + \__( 'View trash.', 'duplicate-post' ), + ); + return \__( 'You can only make one Rewrite & Republish duplicate at a time, and a duplicate of this post already exists in the trash. Permanently delete it if you want to make a new duplicate.', 'duplicate-post', + ) . $view_trash_html; + } + + $copy = $this->permissions_helper->get_rewrite_and_republish_copy( $post ); + $edit_url = ( $copy instanceof WP_Post ) ? \get_edit_post_link( $copy->ID, 'raw' ) : ''; + $link_html = ''; + if ( $edit_url !== '' ) { + $link_html = \sprintf( + ' %2$s', + \esc_url( $edit_url ), + \__( 'Edit the duplicate.', 'duplicate-post' ), ); } @@ -58,7 +82,7 @@ public function get_notice_text( $post ) { return \__( 'A duplicate of this post was made. Please note that any changes you make to this post will be replaced when the duplicated version is republished.', 'duplicate-post', - ); + ) . $link_html; } return \sprintf( @@ -69,7 +93,7 @@ public function get_notice_text( $post ) { ), \get_the_time( \get_option( 'date_format' ), $scheduled_copy ), \get_the_time( \get_option( 'time_format' ), $scheduled_copy ), - ); + ) . $link_html; } /** @@ -90,7 +114,7 @@ public function add_admin_notice() { if ( $this->permissions_helper->has_rewrite_and_republish_copy( $post ) ) { print '

' - . \esc_html( $this->get_notice_text( $post ) ) + . \wp_kses( $this->get_notice_text( $post ), [ 'a' => [ 'href' => [] ] ] ) . '

'; } } @@ -113,6 +137,7 @@ public function add_block_editor_notice() { 'text' => $this->get_notice_text( $post ), 'status' => 'warning', 'isDismissible' => true, + 'isHTML' => true, ]; \wp_add_inline_script( diff --git a/tests/Unit/Watchers/Copied_Post_Watcher_Test.php b/tests/Unit/Watchers/Copied_Post_Watcher_Test.php index 88d34138f..c483a3467 100644 --- a/tests/Unit/Watchers/Copied_Post_Watcher_Test.php +++ b/tests/Unit/Watchers/Copied_Post_Watcher_Test.php @@ -81,8 +81,12 @@ public function test_register_hooks() { */ public function test_get_notice_text_not_scheduled() { $this->stubTranslationFunctions(); + $this->stubEscapeFunctions(); $post = Mockery::mock( WP_Post::class ); + $copy = Mockery::mock( WP_Post::class ); + + $copy->ID = 456; $this->permissions_helper ->expects( 'has_scheduled_rewrite_and_republish_copy' ) @@ -94,8 +98,16 @@ public function test_get_notice_text_not_scheduled() { ->with( $post ) ->andReturnFalse(); + $this->permissions_helper + ->expects( 'get_rewrite_and_republish_copy' ) + ->with( $post ) + ->andReturn( $copy ); + + Monkey\Functions\when( '\get_edit_post_link' ) + ->justReturn( 'http://example.com/edit?post=456' ); + $this->assertSame( - 'A duplicate of this post was made. Please note that any changes you make to this post will be replaced when the duplicated version is republished.', + 'A duplicate of this post was made. Please note that any changes you make to this post will be replaced when the duplicated version is republished. Edit the duplicate.', $this->instance->get_notice_text( $post ), ); } @@ -109,10 +121,13 @@ public function test_get_notice_text_not_scheduled() { */ public function test_get_notice_text_scheduled() { $this->stubTranslationFunctions(); + $this->stubEscapeFunctions(); $post = Mockery::mock( WP_Post::class ); $copy = Mockery::mock( WP_Post::class ); + $copy->ID = 789; + $this->permissions_helper ->expects( 'has_scheduled_rewrite_and_republish_copy' ) ->with( $post ) @@ -123,6 +138,14 @@ public function test_get_notice_text_scheduled() { ->with( $post ) ->andReturnFalse(); + $this->permissions_helper + ->expects( 'get_rewrite_and_republish_copy' ) + ->with( $post ) + ->andReturn( $copy ); + + Monkey\Functions\when( '\get_edit_post_link' ) + ->justReturn( 'http://example.com/edit?post=789' ); + Monkey\Functions\expect( '\get_option' ) ->twice() ->andReturnValues( [ 'Y/m/d', 'g:i a' ] ); @@ -132,7 +155,7 @@ public function test_get_notice_text_scheduled() { ->andReturnValues( [ '2020/12/02', '10:30 am' ] ); $this->assertSame( - 'A duplicate of this post was made, which is scheduled to replace this post on 2020/12/02 at 10:30 am.', + 'A duplicate of this post was made, which is scheduled to replace this post on 2020/12/02 at 10:30 am. Edit the duplicate.', $this->instance->get_notice_text( $post ), ); } @@ -146,9 +169,12 @@ public function test_get_notice_text_scheduled() { */ public function test_get_notice_text_copy_in_the_trash() { $this->stubTranslationFunctions(); + $this->stubEscapeFunctions(); $post = Mockery::mock( WP_Post::class ); + $post->post_type = 'post'; + $this->permissions_helper ->expects( 'has_scheduled_rewrite_and_republish_copy' ) ->never(); @@ -158,8 +184,14 @@ public function test_get_notice_text_copy_in_the_trash() { ->with( $post ) ->andReturnTrue(); + Monkey\Functions\when( '\admin_url' ) + ->justReturn( 'http://example.com/wp-admin/edit.php' ); + + Monkey\Functions\when( '\add_query_arg' ) + ->justReturn( 'http://example.com/wp-admin/edit.php?post_status=trash&post_type=post' ); + $this->assertSame( - 'You can only make one Rewrite & Republish duplicate at a time, and a duplicate of this post already exists in the trash. Permanently delete it if you want to make a new duplicate.', + 'You can only make one Rewrite & Republish duplicate at a time, and a duplicate of this post already exists in the trash. Permanently delete it if you want to make a new duplicate. View trash.', $this->instance->get_notice_text( $post ), ); } @@ -192,6 +224,10 @@ public function test_add_admin_notice_classic() { ->expects( 'get_notice_text' ) ->andReturn( 'notice' ); + Monkey\Functions\expect( '\wp_kses' ) + ->with( 'notice', [ 'a' => [ 'href' => [] ] ] ) + ->andReturn( 'notice' ); + $this->instance->add_admin_notice(); $this->expectOutputString( '

notice

' ); @@ -268,16 +304,17 @@ public function test_add_block_editor_notice() { 'text' => 'notice', 'status' => 'warning', 'isDismissible' => true, + 'isHTML' => true, ]; Monkey\Functions\expect( '\wp_json_encode' ) ->with( $notice ) - ->andReturn( '{"text":"notice","status":"warning","isDismissible":true}' ); + ->andReturn( '{"text":"notice","status":"warning","isDismissible":true,"isHTML":true}' ); Monkey\Functions\expect( '\wp_add_inline_script' ) ->with( 'duplicate_post_edit_script', - 'duplicatePostNotices.has_rewrite_and_republish_notice = {"text":"notice","status":"warning","isDismissible":true};', + 'duplicatePostNotices.has_rewrite_and_republish_notice = {"text":"notice","status":"warning","isDismissible":true,"isHTML":true};', 'before', );