diff --git a/src/wp-admin/css/dashboard.css b/src/wp-admin/css/dashboard.css index ab73f828f7067..fc5d83bef6dc8 100644 --- a/src/wp-admin/css/dashboard.css +++ b/src/wp-admin/css/dashboard.css @@ -854,7 +854,7 @@ body #dashboard-widgets .postbox form .submit { color: #646970; } -#dashboard_quick_press .drafts p { +#dashboard_quick_press .drafts .draft-content { margin: 0; word-wrap: break-word; } diff --git a/src/wp-admin/includes/dashboard.php b/src/wp-admin/includes/dashboard.php index 778e3de40326b..761e85f640ccd 100644 --- a/src/wp-admin/includes/dashboard.php +++ b/src/wp-admin/includes/dashboard.php @@ -586,6 +586,9 @@ function wp_dashboard_quick_press( $error_msg = false ) { $error_msg, array( 'additional_classes' => array( 'error' ), + 'attributes' => array( + 'role' => 'alert', + ), ) ); } @@ -688,7 +691,7 @@ function wp_dashboard_recent_drafts( $drafts = false ) { $the_content = wp_trim_words( $draft->post_content, $draft_length ); if ( $the_content ) { - echo '

' . $the_content . '

'; + echo '

' . $the_content . '

'; } echo "\n"; } diff --git a/src/wp-admin/post.php b/src/wp-admin/post.php index dd7bad1bb3830..8341ac969559b 100644 --- a/src/wp-admin/post.php +++ b/src/wp-admin/post.php @@ -96,11 +96,23 @@ $_POST['comment_status'] = get_default_comment_status( $post->post_type ); $_POST['ping_status'] = get_default_comment_status( $post->post_type, 'pingback' ); - // Wrap Quick Draft content in the Paragraph block. - if ( ! str_contains( $_POST['content'], '' ) ) { + $quickdraft_post_title = trim( $_POST['post_title'] ); + $quickdraft_post_content = trim( $_POST['content'] ); + + if ( empty( $quickdraft_post_title ) && empty( $quickdraft_post_content ) ) { + return wp_dashboard_quick_press( __( 'Cannot create a draft post with empty title and content.' ) ); + } + + // Wrap Quick Draft content in a Paragraph block. + if ( + use_block_editor_for_post_type( 'post' ) && + ! empty( $quickdraft_post_content ) && + ! str_contains( $quickdraft_post_content, '' ) + ) { + // Note that `edit_post()` reads from the $_POST superglobal by reference. $_POST['content'] = sprintf( '%s', - str_replace( array( "\r\n", "\r", "\n" ), '
', $_POST['content'] ) + str_replace( array( "\r\n", "\r", "\n" ), '
', $quickdraft_post_content ) ); } diff --git a/tests/e2e/specs/dashboard.test.js b/tests/e2e/specs/dashboard.test.js index 90459ac83ae6f..09508f6622299 100644 --- a/tests/e2e/specs/dashboard.test.js +++ b/tests/e2e/specs/dashboard.test.js @@ -8,13 +8,13 @@ test.describe( 'Quick Draft', () => { await requestUtils.deleteAllPosts(); } ); - test( 'Allows draft to be created with Title and Content', async ( { + test( 'should allow Quick Draft to be created with Title and Content', async ( { admin, page } ) => { await admin.visitAdminPage( '/' ); - // Wait for Quick Draft title field to appear. + // Wait for the Quick Draft title field to appear. const draftTitleField = page.locator( '#quick-press' ).getByRole( 'textbox', { name: 'Title' } ); @@ -22,36 +22,51 @@ test.describe( 'Quick Draft', () => { await expect( draftTitleField ).toBeVisible(); // Focus and fill in a title. - await draftTitleField.fill( 'Test Draft Title' ); + await draftTitleField.fill( 'Quick Draft test title' ); - // Navigate to content field and type in some content - await page.keyboard.press( 'Tab' ); - await page.keyboard.type( 'Test Draft Content' ); + // Wait for the Quick Draft content textarea to appear. + const quickDraftContentTextarea = page.locator( + '#quick-press' + ).getByRole( 'textbox', { name: 'Content' } ); + + await expect( quickDraftContentTextarea ).toBeVisible(); + + // Focus and fill in some content. + await quickDraftContentTextarea.fill( 'Quick Draft test content' ); + + // Wait for the Save Draft button to appear and click it. + const saveDraftButton = page.locator( + '#quick-press' + ).getByRole( 'button', { name: 'Save Draft' } ); - // Navigate to Save Draft button and press it. - await page.keyboard.press( 'Tab' ); - await page.keyboard.press( 'Enter' ); + await expect( saveDraftButton ).toBeVisible(); + await saveDraftButton.click(); - // Check that new draft appears in Your Recent Drafts section + // Check that the new draft title appears in the 'Your Recent Drafts' section. await expect( page.locator( '.drafts .draft-title' ).first().getByRole( 'link' ) - ).toHaveText( 'Test Draft Title' ); + ).toHaveText( 'Quick Draft test title' ); + + // Check that the new draft content appears in the 'Your Recent Drafts' section. + await expect( + page.locator( '.drafts .draft-content' ).first() + ).toHaveText( 'Quick Draft test content' ); - // Check that new draft appears in Posts page + // Check that the new draft appears in the Posts page. await admin.visitAdminPage( '/edit.php' ); await expect( page.locator( '.type-post.status-draft .title' ).first() - ).toContainText( 'Test Draft Title' ); + ).toContainText( 'Quick Draft test title' ); } ); - test( 'Allows draft to be created without Title or Content', async ( { + test( 'should prevent Quick Draft from being created without Title or Content', async ( { admin, page } ) => { await admin.visitAdminPage( '/' ); - // Wait for Save Draft button to appear and click it + // Wait for the Save Draft button to appear and click it. const saveDraftButton = page.locator( '#quick-press' ).getByRole( 'button', { name: 'Save Draft' } ); @@ -59,12 +74,92 @@ test.describe( 'Quick Draft', () => { await expect( saveDraftButton ).toBeVisible(); await saveDraftButton.click(); - // Check that new draft appears in Your Recent Drafts section + // Check that an admin notice with ARIA role 'alert' appears. + await expect( + page.locator( '#quick-press' ).getByRole( 'alert' ) + ).toHaveText( 'Cannot create a draft post with empty title and content.' ); + + // Check that no new draft appears in the Posts page. + await admin.visitAdminPage( '/edit.php' ); + + await expect( + page.locator( '#the-list .no-items .colspanchange' ) + ).toContainText( 'No posts found.' ); + } ); + + test( 'should allow Quick Draft to be created with only the Title', async ( { + admin, + page + } ) => { + await admin.visitAdminPage( '/' ); + + // Wait for the Quick Draft title field to appear. + const quickDraftTitleField = page.locator( + '#quick-press' + ).getByRole( 'textbox', { name: 'Title' } ); + + await expect( quickDraftTitleField ).toBeVisible(); + + // Focus and fill in a title. + await quickDraftTitleField.fill( 'Quick Draft test title' ); + + // Wait for the Save Draft button to appear and click it. + const saveDraftButton = page.locator( + '#quick-press' + ).getByRole( 'button', { name: 'Save Draft' } ); + + await expect( saveDraftButton ).toBeVisible(); + await saveDraftButton.click(); + + // Check that the new draft title appears in the 'Your Recent Drafts' section. + await expect( + page.locator( '.drafts .draft-title' ).first().getByRole( 'link' ) + ).toHaveText( 'Quick Draft test title' ); + + // Check that the new draft appears in the Posts page. + await admin.visitAdminPage( '/edit.php' ); + + await expect( + page.locator( '.type-post.status-draft .title' ).first() + ).toContainText( 'Quick Draft test title' ); + } ); + + test( 'should allow Quick Draft to be created with only the Content', async ( { + admin, + page + } ) => { + await admin.visitAdminPage( '/' ); + + // Wait for the Quick Draft content textarea to appear. + const quickDraftContentTextarea = page.locator( + '#quick-press' + ).getByRole( 'textbox', { name: 'Content' } ); + + await expect( quickDraftContentTextarea ).toBeVisible(); + + // Focus and fill in some content. + await quickDraftContentTextarea.fill( 'Quick Draft test content' ); + + // Wait for the Save Draft button to appear and click it. + const saveDraftButton = page.locator( + '#quick-press' + ).getByRole( 'button', { name: 'Save Draft' } ); + + await expect( saveDraftButton ).toBeVisible(); + await saveDraftButton.click(); + + // Check that the new draft title appears in the 'Your Recent Drafts' section. + // This test relies on Twenty Twenty-One being the active theme. + // Twenty Twenty-One alters the default post title from "(no title)" to "Untitled". await expect( page.locator( '.drafts .draft-title' ).first().getByRole( 'link' ) ).toHaveText( 'Untitled' ); - // Check that new draft appears in Posts page + await expect( + page.locator( '.drafts .draft-content' ).first() + ).toHaveText( 'Quick Draft test content' ); + + // Check that the new draft appears in the Posts page. await admin.visitAdminPage( '/edit.php' ); await expect(