diff --git a/core/lib/Drupal/Core/Entity/EntityPublishedTrait.php b/core/lib/Drupal/Core/Entity/EntityPublishedTrait.php index 871aceb..59fddd5 100644 --- a/core/lib/Drupal/Core/Entity/EntityPublishedTrait.php +++ b/core/lib/Drupal/Core/Entity/EntityPublishedTrait.php @@ -33,8 +33,7 @@ public static function publishedBaseFieldDefinitions(EntityTypeInterface $entity } return [$entity_type->getKey('published') => BaseFieldDefinition::create('boolean') - ->setLabel(new TranslatableMarkup('Publishing status')) - ->setDescription(new TranslatableMarkup('A boolean indicating the published state.')) + ->setLabel(new TranslatableMarkup('Published')) ->setRevisionable(TRUE) ->setTranslatable(TRUE) ->setDefaultValue(TRUE)]; diff --git a/core/modules/book/config/optional/core.entity_form_display.node.book.default.yml b/core/modules/book/config/optional/core.entity_form_display.node.book.default.yml index 58aba45..b1db6d1 100644 --- a/core/modules/book/config/optional/core.entity_form_display.node.book.default.yml +++ b/core/modules/book/config/optional/core.entity_form_display.node.book.default.yml @@ -33,6 +33,13 @@ content: weight: 15 region: content third_party_settings: { } + status: + type: boolean_checkbox + settings: + display_label: true + weight: 120 + region: content + third_party_settings: { } sticky: type: boolean_checkbox settings: diff --git a/core/modules/book/tests/src/Functional/BookTest.php b/core/modules/book/tests/src/Functional/BookTest.php index 66edec9..e52e484 100644 --- a/core/modules/book/tests/src/Functional/BookTest.php +++ b/core/modules/book/tests/src/Functional/BookTest.php @@ -741,8 +741,8 @@ public function testBookNavigationBlockOnUnpublishedBook() { $this->drupalPlaceBlock('book_navigation', ['block_mode' => 'book pages']); // Unpublish book node. - $edit = []; - $this->drupalPostForm('node/' . $this->book->id() . '/edit', $edit, t('Save and unpublish')); + $edit = ['status[value]' => FALSE]; + $this->drupalPostForm('node/' . $this->book->id() . '/edit', $edit, t('Save')); // Test node page. $this->drupalGet('node/' . $this->book->id()); diff --git a/core/modules/comment/tests/src/Functional/CommentStatusFieldAccessTest.php b/core/modules/comment/tests/src/Functional/CommentStatusFieldAccessTest.php index 504b3ba..e208c71 100644 --- a/core/modules/comment/tests/src/Functional/CommentStatusFieldAccessTest.php +++ b/core/modules/comment/tests/src/Functional/CommentStatusFieldAccessTest.php @@ -86,14 +86,14 @@ public function testCommentStatusFieldAccessStatus() { $assert->fieldNotExists('comment[0][status]'); $this->submitForm([ 'title[0][value]' => 'Node 1', - ], t('Save and publish')); + ], t('Save')); $assert->fieldExists('subject[0][value]'); $this->drupalLogin($this->commentAdmin); $this->drupalGet('node/add/article'); $assert->fieldExists('comment[0][status]'); $this->submitForm([ 'title[0][value]' => 'Node 2', - ], t('Save and publish')); + ], t('Save')); $assert->fieldExists('subject[0][value]'); } diff --git a/core/modules/content_moderation/content_moderation.module b/core/modules/content_moderation/content_moderation.module index 31cc6c9..921fe2a 100644 --- a/core/modules/content_moderation/content_moderation.module +++ b/core/modules/content_moderation/content_moderation.module @@ -14,6 +14,8 @@ use Drupal\Core\Entity\Display\EntityViewDisplayInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityTypeInterface; +use Drupal\Core\Field\FieldDefinitionInterface; +use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Session\AccountInterface; @@ -167,6 +169,27 @@ function content_moderation_node_access(NodeInterface $node, $operation, Account } /** + * Implements hook_entity_field_access(). + */ +function content_moderation_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) { + if ($items && $operation === 'edit') { + /** @var \Drupal\content_moderation\ModerationInformationInterface $moderation_info */ + $moderation_info = Drupal::service('content_moderation.moderation_information'); + + $entity_type = \Drupal::entityTypeManager()->getDefinition($field_definition->getTargetEntityTypeId()); + + $entity = $items->getEntity(); + + // Deny edit access to the published field if the entity is being moderated. + if ($entity_type->hasKey('published') && $moderation_info->isModeratedEntity($entity) && $entity->moderation_state && $field_definition->getName() == $entity_type->getKey('published')) { + return AccessResult::forbidden(); + } + } + + return AccessResult::neutral(); +} + +/** * Implements hook_theme(). */ function content_moderation_theme() { diff --git a/core/modules/content_moderation/tests/src/Functional/ModerationStateNodeTest.php b/core/modules/content_moderation/tests/src/Functional/ModerationStateNodeTest.php index 74129a1..277acdf 100644 --- a/core/modules/content_moderation/tests/src/Functional/ModerationStateNodeTest.php +++ b/core/modules/content_moderation/tests/src/Functional/ModerationStateNodeTest.php @@ -62,7 +62,7 @@ public function testCreatingContent() { // Create a new node. $this->drupalPostForm('node/add/moderated_content', [ 'title[0][value]' => 'non-moderated content', - ], t('Save and publish')); + ], t('Save')); $node = $this->getNodeByTitle('non-moderated content'); if (!$node) { diff --git a/core/modules/content_moderation/tests/src/Functional/ModerationStateNodeTypeTest.php b/core/modules/content_moderation/tests/src/Functional/ModerationStateNodeTypeTest.php index de4a7c2..0555120 100644 --- a/core/modules/content_moderation/tests/src/Functional/ModerationStateNodeTypeTest.php +++ b/core/modules/content_moderation/tests/src/Functional/ModerationStateNodeTypeTest.php @@ -18,10 +18,10 @@ public function testNotModerated() { $this->assertText('The content type Not moderated has been added.'); $this->grantUserPermissionToCreateContentOfType($this->adminUser, 'not_moderated'); $this->drupalGet('node/add/not_moderated'); - $this->assertRaw('Save as unpublished'); + $this->assertRaw('Save'); $this->drupalPostForm(NULL, [ 'title[0][value]' => 'Test', - ], t('Save and publish')); + ], t('Save')); $this->assertText('Not moderated Test has been created.'); } @@ -53,7 +53,7 @@ public function testEnablingOnExistingContent() { $this->drupalGet('node/add/not_moderated'); $this->drupalPostForm(NULL, [ 'title[0][value]' => 'Test', - ], t('Save and publish')); + ], t('Save')); $this->assertText('Not moderated Test has been created.'); // Now enable moderation state. diff --git a/core/modules/content_moderation/tests/src/Functional/NodeAccessTest.php b/core/modules/content_moderation/tests/src/Functional/NodeAccessTest.php index 00e847d..eeac1ce 100644 --- a/core/modules/content_moderation/tests/src/Functional/NodeAccessTest.php +++ b/core/modules/content_moderation/tests/src/Functional/NodeAccessTest.php @@ -46,7 +46,7 @@ class NodeAccessTest extends ModerationStateTestBase { protected function setUp() { parent::setUp(); $this->drupalLogin($this->adminUser); - $this->createContentTypeFromUi('Moderated content', 'moderated_content', TRUE); + $this->createContentTypeFromUi('Moderated content', 'moderated_content', FALSE); $this->grantUserPermissionToCreateContentOfType($this->adminUser, 'moderated_content'); // Rebuild permissions because hook_node_grants() is implemented by the @@ -60,8 +60,20 @@ protected function setUp() { public function testPageAccess() { $this->drupalLogin($this->adminUser); + // Access the node form before moderation is enabled, the publication state + // should now be visible. + $this->drupalGet('node/add/moderated_content'); + $this->assertSession()->fieldExists('Published'); + + // Now enable the workflow. + $this->enableModerationThroughUi('moderated_content', 'editorial'); + + // Access that the status field is no longer visible. + $this->drupalGet('node/add/moderated_content'); + $this->assertSession()->fieldNotExists('Published'); + // Create a node to test with. - $this->drupalPostForm('node/add/moderated_content', [ + $this->drupalPostForm(NULL, [ 'title[0][value]' => 'moderated content', ], t('Save and Create New Draft')); $node = $this->getNodeByTitle('moderated content'); diff --git a/core/modules/content_translation/src/Tests/ContentTranslationLanguageChangeTest.php b/core/modules/content_translation/src/Tests/ContentTranslationLanguageChangeTest.php index bb9b223..04bd023 100644 --- a/core/modules/content_translation/src/Tests/ContentTranslationLanguageChangeTest.php +++ b/core/modules/content_translation/src/Tests/ContentTranslationLanguageChangeTest.php @@ -73,12 +73,12 @@ public function testLanguageChange() { $edit = [ 'title[0][value]' => 'english_title', ]; - $this->drupalPostForm(NULL, $edit, t('Save and publish')); + $this->drupalPostForm(NULL, $edit, t('Save')); // Create a translation in French. $this->clickLink('Translate'); $this->clickLink('Add'); - $this->drupalPostForm(NULL, [], t('Save and keep published (this translation)')); + $this->drupalPostForm(NULL, [], t('Save (this translation)')); $this->clickLink('Translate'); // Edit English translation. @@ -90,7 +90,7 @@ public function testLanguageChange() { 'files[field_image_field_0]' => $images->uri, ]; $this->drupalPostForm(NULL, $edit, t('Upload')); - $this->drupalPostForm(NULL, ['field_image_field[0][alt]' => 'alternative_text'], t('Save and keep published (this translation)')); + $this->drupalPostForm(NULL, ['field_image_field[0][alt]' => 'alternative_text'], t('Save (this translation)')); // Check that the translation languages are correct. $node = $this->getNodeByTitle('english_title'); @@ -109,13 +109,13 @@ public function testTitleDoesNotChangesOnChangingLanguageWidgetAndTriggeringAjax 'title[0][value]' => 'english_title', 'test_field_only_en_fr' => 'node created', ]; - $this->drupalPostForm(NULL, $edit, t('Save and publish')); + $this->drupalPostForm(NULL, $edit, t('Save')); $this->assertEqual('node created', \Drupal::state()->get('test_field_only_en_fr')); // Create a translation in French. $this->clickLink('Translate'); $this->clickLink('Add'); - $this->drupalPostForm(NULL, [], t('Save and keep published (this translation)')); + $this->drupalPostForm(NULL, [], t('Save (this translation)')); $this->clickLink('Translate'); // Edit English translation. @@ -137,7 +137,7 @@ public function testTitleDoesNotChangesOnChangingLanguageWidgetAndTriggeringAjax 'langcode[0][value]' => 'en', 'field_image_field[0][alt]' => 'alternative_text' ]; - $this->drupalPostForm(NULL, $edit, t('Save and keep published (this translation)')); + $this->drupalPostForm(NULL, $edit, t('Save (this translation)')); // Check that the translation languages are correct. $node = $this->getNodeByTitle('english_title'); diff --git a/core/modules/field/tests/src/Functional/EntityReference/EntityReferenceXSSTest.php b/core/modules/field/tests/src/Functional/EntityReference/EntityReferenceXSSTest.php index 46986ec..b161ed6 100644 --- a/core/modules/field/tests/src/Functional/EntityReference/EntityReferenceXSSTest.php +++ b/core/modules/field/tests/src/Functional/EntityReference/EntityReferenceXSSTest.php @@ -62,7 +62,7 @@ public function testEntityReferenceXSS() { 'title[0][value]' => $this->randomString(), 'entity_reference_test' => $referenced_node->id() ]; - $this->drupalPostForm(NULL, $edit, 'Save and publish'); + $this->drupalPostForm(NULL, $edit, 'Save'); $this->assertEscaped($referenced_node->getTitle()); // Test the options_buttons type. diff --git a/core/modules/file/src/Tests/FileFieldAnonymousSubmissionTest.php b/core/modules/file/src/Tests/FileFieldAnonymousSubmissionTest.php index b59b1ba..66d87cd 100644 --- a/core/modules/file/src/Tests/FileFieldAnonymousSubmissionTest.php +++ b/core/modules/file/src/Tests/FileFieldAnonymousSubmissionTest.php @@ -138,7 +138,7 @@ protected function doTestNodeWithFileWithoutTitle() { $label = 'Save'; } else { - $label = 'Save and publish'; + $label = 'Save'; } $this->drupalPostForm(NULL, $edit, $label); $this->assertResponse(200); diff --git a/core/modules/file/src/Tests/FileFieldDisplayTest.php b/core/modules/file/src/Tests/FileFieldDisplayTest.php index 1b7e534..db9b7dc 100644 --- a/core/modules/file/src/Tests/FileFieldDisplayTest.php +++ b/core/modules/file/src/Tests/FileFieldDisplayTest.php @@ -77,7 +77,7 @@ public function testNodeDisplay() { // Turn the "display" option off and check that the file is no longer displayed. $edit = [$field_name . '[0][display]' => FALSE]; - $this->drupalPostForm('node/' . $nid . '/edit', $edit, t('Save and keep published')); + $this->drupalPostForm('node/' . $nid . '/edit', $edit, t('Save')); $this->assertNoRaw($default_output, 'Field is hidden when "display" option is unchecked.'); @@ -87,7 +87,7 @@ public function testNodeDisplay() { $field_name . '[0][description]' => $description, $field_name . '[0][display]' => TRUE, ]; - $this->drupalPostForm('node/' . $nid . '/edit', $edit, t('Save and keep published')); + $this->drupalPostForm('node/' . $nid . '/edit', $edit, t('Save')); $this->assertText($description); // Ensure the filename in the link's title attribute is escaped. @@ -167,7 +167,7 @@ public function testDescToggle() { 'title[0][value]' => $title, 'files[field_' . $field_name . '_0]' => drupal_realpath($file->uri), ]; - $this->drupalPostForm('node/add/' . $type_name, $edit, t('Save and publish')); + $this->drupalPostForm('node/add/' . $type_name, $edit, t('Save')); $node = $this->drupalGetNodeByTitle($title); $this->drupalGet('node/' . $node->id() . '/edit'); $this->assertText(t('The description may be used as the label of the link to the file.')); diff --git a/core/modules/file/src/Tests/FileFieldRevisionTest.php b/core/modules/file/src/Tests/FileFieldRevisionTest.php index 7de496f..7b7b4d3 100644 --- a/core/modules/file/src/Tests/FileFieldRevisionTest.php +++ b/core/modules/file/src/Tests/FileFieldRevisionTest.php @@ -63,7 +63,7 @@ public function testRevisions() { // Save a new version of the node without any changes. // Check that the file is still the same as the previous revision. - $this->drupalPostForm('node/' . $nid . '/edit', ['revision' => '1'], t('Save and keep published')); + $this->drupalPostForm('node/' . $nid . '/edit', ['revision' => '1'], t('Save')); $node_storage->resetCache([$nid]); $node = $node_storage->load($nid); $node_file_r3 = File::load($node->{$field_name}->target_id); diff --git a/core/modules/file/src/Tests/FileFieldTestBase.php b/core/modules/file/src/Tests/FileFieldTestBase.php index 73cc96a..b7b90d7 100644 --- a/core/modules/file/src/Tests/FileFieldTestBase.php +++ b/core/modules/file/src/Tests/FileFieldTestBase.php @@ -227,7 +227,7 @@ public function uploadNodeFiles(array $files, $field_name, $nid_or_type, $new_re $edit[$name][] = $file_path; } } - $this->drupalPostForm("node/$nid/edit", $edit, t('Save and keep published')); + $this->drupalPostForm("node/$nid/edit", $edit, t('Save')); return $nid; } @@ -243,7 +243,7 @@ public function removeNodeFile($nid, $new_revision = TRUE) { ]; $this->drupalPostForm('node/' . $nid . '/edit', [], t('Remove')); - $this->drupalPostForm(NULL, $edit, t('Save and keep published')); + $this->drupalPostForm(NULL, $edit, t('Save')); } /** @@ -256,7 +256,7 @@ public function replaceNodeFile($file, $field_name, $nid, $new_revision = TRUE) ]; $this->drupalPostForm('node/' . $nid . '/edit', [], t('Remove')); - $this->drupalPostForm(NULL, $edit, t('Save and keep published')); + $this->drupalPostForm(NULL, $edit, t('Save')); } /** diff --git a/core/modules/file/src/Tests/FileFieldValidateTest.php b/core/modules/file/src/Tests/FileFieldValidateTest.php index 5ddcdde..422bf68 100644 --- a/core/modules/file/src/Tests/FileFieldValidateTest.php +++ b/core/modules/file/src/Tests/FileFieldValidateTest.php @@ -29,7 +29,7 @@ public function testRequired() { // Try to post a new node without uploading a file. $edit = []; $edit['title[0][value]'] = $this->randomMachineName(); - $this->drupalPostForm('node/add/' . $type_name, $edit, t('Save and publish')); + $this->drupalPostForm('node/add/' . $type_name, $edit, t('Save')); $this->assertRaw(t('@title field is required.', ['@title' => $field->getLabel()]), 'Node save failed when required file field was empty.'); // Create a new node with the uploaded file. @@ -50,7 +50,7 @@ public function testRequired() { // Try to post a new node without uploading a file in the multivalue field. $edit = []; $edit['title[0][value]'] = $this->randomMachineName(); - $this->drupalPostForm('node/add/' . $type_name, $edit, t('Save and publish')); + $this->drupalPostForm('node/add/' . $type_name, $edit, t('Save')); $this->assertRaw(t('@title field is required.', ['@title' => $field->getLabel()]), 'Node save failed when required multiple value file field was empty.'); // Create a new node with the uploaded file into the multivalue field. diff --git a/core/modules/file/src/Tests/FileFieldWidgetTest.php b/core/modules/file/src/Tests/FileFieldWidgetTest.php index ddfd8f4..ad47d77 100644 --- a/core/modules/file/src/Tests/FileFieldWidgetTest.php +++ b/core/modules/file/src/Tests/FileFieldWidgetTest.php @@ -121,7 +121,7 @@ public function testSingleValuedWidget() { $this->assertTrue(isset($label[0]), 'Label for upload found.'); // Save the node and ensure it does not have the file. - $this->drupalPostForm(NULL, [], t('Save and keep published')); + $this->drupalPostForm(NULL, [], t('Save')); $node_storage->resetCache([$nid]); $node = $node_storage->load($nid); $this->assertTrue(empty($node->{$field_name}->target_id), 'File was successfully removed from the node.'); @@ -238,8 +238,7 @@ public function testMultiValuedWidget() { $this->assertNoFieldByXPath('//input[@type="submit"]', t('Remove'), format_string('After removing all files, there is no "Remove" button displayed (JSMode=%type).', ['%type' => $type])); // Save the node and ensure it does not have any files. - $this->drupalPostForm(NULL, ['title[0][value]' => $this->randomMachineName()], t('Save and publish')); - $matches = []; + $this->drupalPostForm(NULL, ['title[0][value]' => $this->randomMachineName()], t('Save')); preg_match('/node\/([0-9]+)/', $this->getUrl(), $matches); $nid = $matches[1]; $node_storage->resetCache([$nid]); @@ -368,7 +367,7 @@ public function testPrivateFileComment() { $edit = [ 'title[0][value]' => $this->randomMachineName(), ]; - $this->drupalPostForm('node/add/article', $edit, t('Save and publish')); + $this->drupalPostForm('node/add/article', $edit, t('Save')); $node = $this->drupalGetNodeByTitle($edit['title[0][value]']); // Add a comment with a file. @@ -402,7 +401,8 @@ public function testPrivateFileComment() { // Unpublishes node. $this->drupalLogin($this->adminUser); - $this->drupalPostForm('node/' . $node->id() . '/edit', [], t('Save and unpublish')); + $edit = ['status[value]' => FALSE]; + $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save')); // Ensures normal user can no longer download the file. $this->drupalLogin($user); diff --git a/core/modules/file/src/Tests/FilePrivateTest.php b/core/modules/file/src/Tests/FilePrivateTest.php index 3c9776f..7ecd485 100644 --- a/core/modules/file/src/Tests/FilePrivateTest.php +++ b/core/modules/file/src/Tests/FilePrivateTest.php @@ -72,10 +72,10 @@ public function testPrivateFile() { // Attempt to reuse the file when editing a node. $edit = []; $edit['title[0][value]'] = $this->randomMachineName(); - $this->drupalPostForm('node/add/' . $type_name, $edit, t('Save and publish')); + $this->drupalPostForm('node/add/' . $type_name, $edit, t('Save')); $new_node = $this->drupalGetNodeByTitle($edit['title[0][value]']); $edit[$field_name . '[0][fids]'] = $node_file->id(); - $this->drupalPostForm('node/' . $new_node->id() . '/edit', $edit, t('Save and keep published')); + $this->drupalPostForm('node/' . $new_node->id() . '/edit', $edit, t('Save')); // Make sure the form submit failed - we stayed on the edit form. $this->assertUrl('node/' . $new_node->id() . '/edit'); // Check that we got the expected constraint form error. @@ -86,7 +86,7 @@ public function testPrivateFile() { $edit = []; $edit['title[0][value]'] = $this->randomMachineName(); $edit[$field_name . '[0][fids]'] = $node_file->id(); - $this->drupalPostForm('node/add/' . $type_name, $edit, t('Save and publish')); + $this->drupalPostForm('node/add/' . $type_name, $edit, t('Save')); $new_node = $this->drupalGetNodeByTitle($edit['title[0][value]']); $this->assertTrue(empty($new_node), 'Node was not created.'); $this->assertUrl('node/add/' . $type_name); diff --git a/core/modules/filter/tests/src/Functional/FilterHooksTest.php b/core/modules/filter/tests/src/Functional/FilterHooksTest.php index c799460..5ff4a8a 100644 --- a/core/modules/filter/tests/src/Functional/FilterHooksTest.php +++ b/core/modules/filter/tests/src/Functional/FilterHooksTest.php @@ -60,7 +60,7 @@ public function testFilterHooks() { $edit['title[0][value]'] = $title; $edit['body[0][value]'] = $this->randomMachineName(32); $edit['body[0][format]'] = $format_id; - $this->drupalPostForm("node/add/{$type->id()}", $edit, t('Save and publish')); + $this->drupalPostForm("node/add/{$type->id()}", $edit, t('Save')); $this->assertText(t('@type @title has been created.', ['@type' => $type_name, '@title' => $title])); // Disable the text format. diff --git a/core/modules/forum/config/optional/core.entity_form_display.node.forum.default.yml b/core/modules/forum/config/optional/core.entity_form_display.node.forum.default.yml index 6773d32..965a691 100644 --- a/core/modules/forum/config/optional/core.entity_form_display.node.forum.default.yml +++ b/core/modules/forum/config/optional/core.entity_form_display.node.forum.default.yml @@ -42,6 +42,13 @@ content: weight: 15 region: content third_party_settings: { } + status: + type: boolean_checkbox + settings: + display_label: true + weight: 120 + region: content + third_party_settings: { } sticky: type: boolean_checkbox settings: diff --git a/core/modules/forum/tests/src/Functional/ForumBlockTest.php b/core/modules/forum/tests/src/Functional/ForumBlockTest.php index 6c412b7..2914e94 100644 --- a/core/modules/forum/tests/src/Functional/ForumBlockTest.php +++ b/core/modules/forum/tests/src/Functional/ForumBlockTest.php @@ -170,7 +170,7 @@ protected function createForumTopics($count = 5) { ]; // Create the forum topic, preselecting the forum ID via a URL parameter. - $this->drupalPostForm('node/add/forum', $edit, t('Save and publish'), ['query' => ['forum_id' => 1]]); + $this->drupalPostForm('node/add/forum', $edit, t('Save'), ['query' => ['forum_id' => 1]]); $topics[] = $title; } diff --git a/core/modules/forum/tests/src/Functional/ForumIndexTest.php b/core/modules/forum/tests/src/Functional/ForumIndexTest.php index 53c8364..38adb72 100644 --- a/core/modules/forum/tests/src/Functional/ForumIndexTest.php +++ b/core/modules/forum/tests/src/Functional/ForumIndexTest.php @@ -44,7 +44,7 @@ public function testForumIndexStatus() { $this->drupalGet("forum/$tid"); $this->clickLink(t('Add new @node_type', ['@node_type' => 'Forum topic'])); $this->assertUrl('node/add/forum', ['query' => ['forum_id' => $tid]]); - $this->drupalPostForm(NULL, $edit, t('Save and publish')); + $this->drupalPostForm(NULL, $edit, t('Save')); // Check that the node exists in the database. $node = $this->drupalGetNodeByTitle($title); @@ -71,7 +71,8 @@ public function testForumIndexStatus() { // Unpublish the node. - $this->drupalPostForm('node/' . $node->id() . '/edit', [], t('Save and unpublish')); + $edit = ['status[value]' => FALSE]; + $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save')); $this->drupalGet('node/' . $node->id()); $this->assertText(t('Access denied'), 'Unpublished node is no longer accessible.'); diff --git a/core/modules/image/src/Tests/ImageFieldDisplayTest.php b/core/modules/image/src/Tests/ImageFieldDisplayTest.php index 9c105c1..8061526 100644 --- a/core/modules/image/src/Tests/ImageFieldDisplayTest.php +++ b/core/modules/image/src/Tests/ImageFieldDisplayTest.php @@ -282,7 +282,7 @@ public function testImageFieldSettings() { $field_name . '[0][alt]' => $image['#alt'], $field_name . '[0][title]' => $image['#title'], ]; - $this->drupalPostForm('node/' . $nid . '/edit', $edit, t('Save and keep published')); + $this->drupalPostForm('node/' . $nid . '/edit', $edit, t('Save')); $default_output = str_replace("\n", NULL, $renderer->renderRoot($image)); $this->assertRaw($default_output, 'Image displayed using user supplied alt and title attributes.'); @@ -292,7 +292,7 @@ public function testImageFieldSettings() { $field_name . '[0][alt]' => $this->randomMachineName($test_size), $field_name . '[0][title]' => $this->randomMachineName($test_size), ]; - $this->drupalPostForm('node/' . $nid . '/edit', $edit, t('Save and keep published')); + $this->drupalPostForm('node/' . $nid . '/edit', $edit, t('Save')); $schema = $field->getFieldStorageDefinition()->getSchema(); $this->assertRaw(t('Alternative text cannot be longer than %max characters but is currently %length characters long.', [ '%max' => $schema['columns']['alt']['length'], @@ -314,9 +314,9 @@ public function testImageFieldSettings() { $edit = [ 'files[' . $field_name . '_1][]' => drupal_realpath($test_image->uri), ]; - $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published')); + $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save')); // Add the required alt text. - $this->drupalPostForm(NULL, [$field_name . '[1][alt]' => $alt], t('Save and keep published')); + $this->drupalPostForm(NULL, [$field_name . '[1][alt]' => $alt], t('Save')); $this->assertText(format_string('Article @title has been updated.', ['@title' => $node->getTitle()])); // Assert ImageWidget::process() calls FieldWidget::process(). diff --git a/core/modules/image/src/Tests/ImageFieldTestBase.php b/core/modules/image/src/Tests/ImageFieldTestBase.php index eec7f7b..c023917 100644 --- a/core/modules/image/src/Tests/ImageFieldTestBase.php +++ b/core/modules/image/src/Tests/ImageFieldTestBase.php @@ -90,10 +90,10 @@ public function uploadNodeImage($image, $field_name, $type, $alt = '') { 'title[0][value]' => $this->randomMachineName(), ]; $edit['files[' . $field_name . '_0]'] = drupal_realpath($image->uri); - $this->drupalPostForm('node/add/' . $type, $edit, t('Save and publish')); + $this->drupalPostForm('node/add/' . $type, $edit, t('Save')); if ($alt) { // Add alt text. - $this->drupalPostForm(NULL, [$field_name . '[0][alt]' => $alt], t('Save and publish')); + $this->drupalPostForm(NULL, [$field_name . '[0][alt]' => $alt], t('Save')); } // Retrieve ID of the newly created node from the current URL. diff --git a/core/modules/image/src/Tests/ImageFieldValidateTest.php b/core/modules/image/src/Tests/ImageFieldValidateTest.php index 7e5ee9b..e429d0b 100644 --- a/core/modules/image/src/Tests/ImageFieldValidateTest.php +++ b/core/modules/image/src/Tests/ImageFieldValidateTest.php @@ -119,7 +119,7 @@ public function testRequiredAttributes() { $edit = [ 'title[0][value]' => $this->randomMachineName(), ]; - $this->drupalPostForm('node/add/article', $edit, t('Save and publish')); + $this->drupalPostForm('node/add/article', $edit, t('Save')); $this->assertNoText(t('Alternative text field is required.')); $this->assertNoText(t('Title field is required.')); @@ -132,7 +132,7 @@ public function testRequiredAttributes() { $edit = [ 'title[0][value]' => $this->randomMachineName(), ]; - $this->drupalPostForm('node/add/article', $edit, t('Save and publish')); + $this->drupalPostForm('node/add/article', $edit, t('Save')); $this->assertNoText(t('Alternative text field is required.')); $this->assertNoText(t('Title field is required.')); diff --git a/core/modules/inline_form_errors/tests/src/FunctionalJavascript/FormErrorHandlerCKEditorTest.php b/core/modules/inline_form_errors/tests/src/FunctionalJavascript/FormErrorHandlerCKEditorTest.php index bce4ff8..2007e1e 100644 --- a/core/modules/inline_form_errors/tests/src/FunctionalJavascript/FormErrorHandlerCKEditorTest.php +++ b/core/modules/inline_form_errors/tests/src/FunctionalJavascript/FormErrorHandlerCKEditorTest.php @@ -85,7 +85,7 @@ public function testFragmentLink() { // Only enter a title in the node add form and leave the body field empty. $edit = ['edit-title-0-value' => 'Test inline form error with CKEditor']; - $this->submitForm($edit, 'Save and publish'); + $this->submitForm($edit, 'Save'); // Add a bottom margin to the title field to be sure the body field is not // visible. PhantomJS runs with a resolution of 1024x768px. diff --git a/core/modules/language/tests/src/Functional/LanguageNegotiationUrlTest.php b/core/modules/language/tests/src/Functional/LanguageNegotiationUrlTest.php index 8472ff7..07ae85d 100644 --- a/core/modules/language/tests/src/Functional/LanguageNegotiationUrlTest.php +++ b/core/modules/language/tests/src/Functional/LanguageNegotiationUrlTest.php @@ -70,7 +70,7 @@ public function testDomain() { 'title[0][value]' => 'Test', 'path[0][alias]' => '/eng/test', ]; - $this->drupalPostForm('node/add/article', $nodeValues, $this->t('Save and publish')); + $this->drupalPostForm('node/add/article', $nodeValues, $this->t('Save')); $this->assertSession()->statusCodeEquals(200); } diff --git a/core/modules/media/src/Entity/Media.php b/core/modules/media/src/Entity/Media.php index 8584041..5c68552 100644 --- a/core/modules/media/src/Entity/Media.php +++ b/core/modules/media/src/Entity/Media.php @@ -423,6 +423,16 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { ]) ->setDisplayConfigurable('view', TRUE); + $fields['status'] + ->setDisplayOptions('form', [ + 'type' => 'boolean_checkbox', + 'settings' => [ + 'display_label' => TRUE, + ], + 'weight' => 120, + ]) + ->setDisplayConfigurable('form', TRUE); + $fields['created'] = BaseFieldDefinition::create('created') ->setLabel(t('Authored on')) ->setDescription(t('The time the media item was created.')) diff --git a/core/modules/media/src/MediaForm.php b/core/modules/media/src/MediaForm.php index 1e91e9f..c3c6a13 100644 --- a/core/modules/media/src/MediaForm.php +++ b/core/modules/media/src/MediaForm.php @@ -25,6 +25,15 @@ public function form(array $form, FormStateInterface $form_state) { ]); } + $form['footer'] = [ + '#type' => 'container', + '#weight' => 99, + '#attributes' => [ + 'class' => ['media-form-footer'] + ] + ]; + $form['status']['#group'] = 'footer'; + // Media author information for administrators. if (isset($form['uid']) || isset($form['created'])) { $form['author'] = [ @@ -49,8 +58,6 @@ public function form(array $form, FormStateInterface $form_state) { $form['#attached']['library'][] = 'media/media_form'; - $form['#entity_builders']['update_status'] = [$this, 'updateStatus']; - return $form; } @@ -61,47 +68,6 @@ protected function actions(array $form, FormStateInterface $form_state) { $element = parent::actions($form, $form_state); $media = $this->entity; - // Add a "Publish" button. - $element['publish'] = $element['submit']; - // If the "Publish" button is clicked, we want to update the status to - // "published". - $element['publish']['#published_status'] = TRUE; - $element['publish']['#dropbutton'] = 'save'; - if ($media->isNew()) { - $element['publish']['#value'] = $this->t('Save and publish'); - } - else { - $element['publish']['#value'] = $media->isPublished() ? $this->t('Save and keep published') : $this->t('Save and publish'); - } - $element['publish']['#weight'] = 0; - - // Add a "Unpublish" button. - $element['unpublish'] = $element['submit']; - // If the "Unpublish" button is clicked, we want to update the status to - // "unpublished". - $element['unpublish']['#published_status'] = FALSE; - $element['unpublish']['#dropbutton'] = 'save'; - if ($media->isNew()) { - $element['unpublish']['#value'] = $this->t('Save as unpublished'); - } - else { - $element['unpublish']['#value'] = !$media->isPublished() ? $this->t('Save and keep unpublished') : $this->t('Save and unpublish'); - } - $element['unpublish']['#weight'] = 10; - - // If already published, the 'publish' button is primary. - if ($media->isPublished()) { - $element['publish']['#button_type'] = 'primary'; - } - // Otherwise, the 'unpublish' button is primary and should come first. - else { - $element['unpublish']['#button_type'] = 'primary'; - $element['unpublish']['#weight'] = -10; - } - - // Remove the "Save" button. - $element['submit']['#access'] = FALSE; - $element['delete']['#access'] = $media->access('delete'); $element['delete']['#weight'] = 100; @@ -120,6 +86,9 @@ protected function actions(array $form, FormStateInterface $form_state) { * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. * + * @deprecated in Drupal 8.4.x, will be removed before Drupal 9.0.0. + * The "Publish" button was removed. + * * @see \Drupal\media\MediaForm::form() */ public function updateStatus($entity_type_id, MediaInterface $media, array $form, FormStateInterface $form_state) { diff --git a/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php b/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php index 883f27e..6b3fa02 100644 --- a/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php +++ b/core/modules/media/tests/src/Functional/MediaUiFunctionalTest.php @@ -53,7 +53,7 @@ public function testMediaWithOnlyOneMediaType() { $page->fillField('name[0][value]', $media_name); $revision_log_message = $this->randomString(); $page->fillField('revision_log_message[0][value]', $revision_log_message); - $page->pressButton('Save and publish'); + $page->pressButton('Save'); $media_id = $this->container->get('entity.query')->get('media')->execute(); $media_id = reset($media_id); /** @var \Drupal\media\MediaInterface $media */ @@ -72,7 +72,7 @@ public function testMediaWithOnlyOneMediaType() { $assert_session->checkboxNotChecked('edit-revision'); $media_name = $this->randomMachineName(); $page->fillField('name[0][value]', $media_name2); - $page->pressButton('Save and keep published'); + $page->pressButton('Save'); /** @var \Drupal\media\MediaInterface $media */ $media = $this->container->get('entity_type.manager') ->getStorage('media') @@ -103,7 +103,7 @@ public function testMediaWithOnlyOneMediaType() { $assert_session->checkboxChecked('edit-revision'); $page->fillField('name[0][value]', $media_name); $page->fillField('revision_log_message[0][value]', $revision_log_message); - $page->pressButton('Save and keep published'); + $page->pressButton('Save'); $assert_session->titleEquals($media_name . ' | Drupal'); /** @var \Drupal\media\MediaInterface $media */ $media = $this->container->get('entity_type.manager') @@ -112,6 +112,18 @@ public function testMediaWithOnlyOneMediaType() { $this->assertEquals($media->getRevisionLogMessage(), $revision_log_message); $this->assertNotEquals($previous_revision_id, $media->getRevisionId()); + // the 'Published' boolean_checkbox and clicking 'Save'. + $this->drupalGet("media/" . $media_id . "/edit"); + $edit = ['status[value]' => FALSE]; + $this->drupalPostForm(NULL, $edit, t('Save')); + $this->container->get('entity_type.manager') + ->getStorage('media') + ->resetCache([$media_id]); + $media = $this->container->get('entity_type.manager') + ->getStorage('media') + ->loadUnchanged($media_id); + $this->assertFalse($media->isPublished(), 'Media is unpublished'); + // Tests media delete form. $this->drupalGet('media/' . $media_id . '/edit'); $page->clickLink('Delete'); diff --git a/core/modules/menu_ui/src/Tests/MenuNodeTest.php b/core/modules/menu_ui/src/Tests/MenuNodeTest.php index 3f1bba0..9990095 100644 --- a/core/modules/menu_ui/src/Tests/MenuNodeTest.php +++ b/core/modules/menu_ui/src/Tests/MenuNodeTest.php @@ -134,8 +134,7 @@ public function testMenuNodeFormWidget() { $this->drupalGet('test-page'); $this->assertNoLink($node_title); - // Use not only the save button, but also the two special buttons: - // 'Save and publish' as well as 'Save and keep published'. + // Make sure the menu links only appear when the node is published. // These buttons just appear for 'administer nodes' users. $admin_user = $this->drupalCreateUser([ 'access administration pages', @@ -146,21 +145,20 @@ public function testMenuNodeFormWidget() { 'edit any page content', ]); $this->drupalLogin($admin_user); - foreach (['Save and unpublish' => FALSE, 'Save and keep unpublished' => FALSE, 'Save and publish' => TRUE, 'Save and keep published' => TRUE] as $submit => $visible) { - $edit = [ - 'menu[enabled]' => 1, - 'menu[title]' => $node_title, - ]; - $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, $submit); - // Assert that the link exists. - $this->drupalGet('test-page'); - if ($visible) { - $this->assertLink($node_title, 0, 'Found a menu link after submitted with ' . $submit); - } - else { - $this->assertNoLink($node_title, 'Found no menu link after submitted with ' . $submit); - } - } + // Assert that the link does not exist if unpublished. + $edit = [ + 'menu[enabled]' => 1, + 'menu[title]' => $node_title, + 'status[value]' => FALSE, + ]; + $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, 'Save'); + $this->drupalGet('test-page'); + $this->assertNoLink($node_title, 'Found no menu link with the node unpublished'); + // Assert that the link exists if published. + $edit['status[value]'] = TRUE; + $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, 'Save'); + $this->drupalGet('test-page'); + $this->assertLink($node_title, 0, 'Found a menu link with the node published'); // Log back in as normal user. $this->drupalLogin($this->editor); diff --git a/core/modules/node/node.post_update.php b/core/modules/node/node.post_update.php new file mode 100644 index 0000000..43e3cd6 --- /dev/null +++ b/core/modules/node/node.post_update.php @@ -0,0 +1,29 @@ +condition('targetEntityType', 'node'); + $ids = $query->execute(); + $form_displays = EntityFormDisplay::loadMultiple($ids); + + // Assign status settings for each 'node' target entity types with 'default' + // form mode. + foreach ($form_displays as $id => $form_display) { + /** @var \Drupal\Core\Entity\Display\EntityDisplayInterface $form_display */ + $form_display->setComponent('status', [ + 'type' => 'boolean_checkbox', + 'settings' => [ + 'display_label' => TRUE, + ], + ])->save(); + } +} diff --git a/core/modules/node/src/Entity/Node.php b/core/modules/node/src/Entity/Node.php index 74a7c0b..e5544a2 100644 --- a/core/modules/node/src/Entity/Node.php +++ b/core/modules/node/src/Entity/Node.php @@ -340,6 +340,16 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { ]) ->setDisplayConfigurable('form', TRUE); + $fields['status'] + ->setDisplayOptions('form', [ + 'type' => 'boolean_checkbox', + 'settings' => [ + 'display_label' => TRUE, + ], + 'weight' => 120, + ]) + ->setDisplayConfigurable('form', TRUE); + $fields['created'] = BaseFieldDefinition::create('created') ->setLabel(t('Authored on')) ->setDescription(t('The time that the node was created.')) diff --git a/core/modules/node/src/NodeForm.php b/core/modules/node/src/NodeForm.php index 203c2e6..007b7c6 100644 --- a/core/modules/node/src/NodeForm.php +++ b/core/modules/node/src/NodeForm.php @@ -86,7 +86,10 @@ public function form(array $form, FormStateInterface $form_state) { $node = $this->entity; if ($this->operation == 'edit') { - $form['#title'] = $this->t('Edit @type @title', ['@type' => node_get_type_label($node), '@title' => $node->label()]); + $form['#title'] = $this->t('Edit @type @title', [ + '@type' => node_get_type_label($node), + '@title' => $node->label() + ]); } // Changed must be sent to the client, for later overwrite error checking. @@ -99,6 +102,15 @@ public function form(array $form, FormStateInterface $form_state) { $form['advanced']['#attributes']['class'][] = 'entity-meta'; + $form['footer'] = [ + '#type' => 'container', + '#weight' => 99, + '#attributes' => [ + 'class' => ['node-form-footer'] + ] + ]; + $form['status']['#group'] = 'footer'; + // Node author information for administrators. $form['author'] = [ '#type' => 'details', @@ -147,8 +159,6 @@ public function form(array $form, FormStateInterface $form_state) { $form['#attached']['library'][] = 'node/form'; - $form['#entity_builders']['update_status'] = '::updateStatus'; - return $form; } @@ -165,6 +175,9 @@ public function form(array $form, FormStateInterface $form_state) { * The current state of the form. * * @see \Drupal\node\NodeForm::form() + * + * @deprecated in Drupal 8.4.x, will be removed before Drupal 9.0.0. + * The "Publish" button was removed. */ public function updateStatus($entity_type_id, NodeInterface $node, array $form, FormStateInterface $form_state) { $element = $form_state->getTriggeringElement(); @@ -183,59 +196,6 @@ protected function actions(array $form, FormStateInterface $form_state) { $element['submit']['#access'] = $preview_mode != DRUPAL_REQUIRED || $form_state->get('has_been_previewed'); - // If saving is an option, privileged users get dedicated form submit - // buttons to adjust the publishing status while saving in one go. - // @todo This adjustment makes it close to impossible for contributed - // modules to integrate with "the Save operation" of this form. Modules - // need a way to plug themselves into 1) the ::submit() step, and - // 2) the ::save() step, both decoupled from the pressed form button. - if ($element['submit']['#access'] && \Drupal::currentUser()->hasPermission('administer nodes')) { - // isNew | prev status » default & publish label & unpublish label - // 1 | 1 » publish & Save and publish & Save as unpublished - // 1 | 0 » unpublish & Save and publish & Save as unpublished - // 0 | 1 » publish & Save and keep published & Save and unpublish - // 0 | 0 » unpublish & Save and keep unpublished & Save and publish - - // Add a "Publish" button. - $element['publish'] = $element['submit']; - // If the "Publish" button is clicked, we want to update the status to "published". - $element['publish']['#published_status'] = TRUE; - $element['publish']['#dropbutton'] = 'save'; - if ($node->isNew()) { - $element['publish']['#value'] = t('Save and publish'); - } - else { - $element['publish']['#value'] = $node->isPublished() ? t('Save and keep published') : t('Save and publish'); - } - $element['publish']['#weight'] = 0; - - // Add a "Unpublish" button. - $element['unpublish'] = $element['submit']; - // If the "Unpublish" button is clicked, we want to update the status to "unpublished". - $element['unpublish']['#published_status'] = FALSE; - $element['unpublish']['#dropbutton'] = 'save'; - if ($node->isNew()) { - $element['unpublish']['#value'] = t('Save as unpublished'); - } - else { - $element['unpublish']['#value'] = !$node->isPublished() ? t('Save and keep unpublished') : t('Save and unpublish'); - } - $element['unpublish']['#weight'] = 10; - - // If already published, the 'publish' button is primary. - if ($node->isPublished()) { - unset($element['unpublish']['#button_type']); - } - // Otherwise, the 'unpublish' button is primary and should come first. - else { - unset($element['publish']['#button_type']); - $element['unpublish']['#weight'] = -10; - } - - // Remove the "Save" button. - $element['submit']['#access'] = FALSE; - } - $element['preview'] = [ '#type' => 'submit', '#access' => $preview_mode != DRUPAL_DISABLED && ($node->access('create') || $node->access('update')), diff --git a/core/modules/node/src/Tests/Update/NodeUpdateTest.php b/core/modules/node/src/Tests/Update/NodeUpdateTest.php index b8b30be..b193ea8 100644 --- a/core/modules/node/src/Tests/Update/NodeUpdateTest.php +++ b/core/modules/node/src/Tests/Update/NodeUpdateTest.php @@ -2,6 +2,7 @@ namespace Drupal\node\Tests\Update; +use Drupal\Core\Entity\Entity\EntityFormDisplay; use Drupal\system\Tests\Update\UpdatePathTestBase; /** @@ -38,4 +39,29 @@ public function testPublishedEntityKey() { $this->assertEqual('status', $entity_type->getKey('published')); } + /** + * Tests that the node entity form has the status checkbox. + * + * @see node_post_update_configure_status_field_widget() + */ + public function testStatusCheckbox() { + // Run updates. + $this->runUpdates(); + + $query = \Drupal::entityQuery('entity_form_display') + ->condition('targetEntityType', 'node'); + $ids = $query->execute(); + $form_displays = EntityFormDisplay::loadMultiple($ids); + + /** + * @var string $id + * @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display + */ + foreach ($form_displays as $id => $form_display) { + $component = $form_display->getComponent('status'); + $this->assertEqual('boolean_checkbox', $component['type']); + $this->assertEqual(['display_label' => TRUE], $component['settings']); + } + } + } diff --git a/core/modules/node/tests/src/Functional/NodeEditFormTest.php b/core/modules/node/tests/src/Functional/NodeEditFormTest.php index ea2a168..ce032e5 100644 --- a/core/modules/node/tests/src/Functional/NodeEditFormTest.php +++ b/core/modules/node/tests/src/Functional/NodeEditFormTest.php @@ -98,7 +98,7 @@ public function testNodeEdit() { $edit['title[0][value]'] = $this->randomMachineName(8); $edit[$body_key] = $this->randomMachineName(16); $edit['revision'] = TRUE; - $this->drupalPostForm(NULL, $edit, t('Save and keep published')); + $this->drupalPostForm(NULL, $edit, t('Save')); // Ensure that the node revision has been created. $revised_node = $this->drupalGetNodeByTitle($edit['title[0][value]'], TRUE); @@ -124,12 +124,21 @@ public function testNodeEdit() { $edit['created[0][value][date]'] = $this->randomMachineName(8); // Get the current amount of open details elements. $open_details_elements = count($this->cssSelect('details[open="open"]')); - $this->drupalPostForm(NULL, $edit, t('Save and keep published')); + $this->drupalPostForm(NULL, $edit, t('Save')); // The node author details must be open. $this->assertRaw('
'); // Only one extra details element should now be open. $open_details_elements++; $this->assertEqual(count($this->cssSelect('details[open="open"]')), $open_details_elements, 'Exactly one extra open <details> element found.'); + + // Edit the same node, save it and verify it's unpublished after unchecking + // the 'Published' boolean_checkbox and clicking 'Save'. + $this->drupalGet("node/" . $node->id() . "/edit"); + $edit = ['status[value]' => FALSE]; + $this->drupalPostForm(NULL, $edit, t('Save')); + $this->nodeStorage->resetCache([$node->id()]); + $node = $this->nodeStorage->load($node->id()); + $this->assertFalse($node->isPublished(), 'Node is unpublished'); } /** @@ -143,7 +152,7 @@ public function testNodeEditAuthoredBy() { $edit = []; $edit['title[0][value]'] = $this->randomMachineName(8); $edit[$body_key] = $this->randomMachineName(16); - $this->drupalPostForm('node/add/page', $edit, t('Save and publish')); + $this->drupalPostForm('node/add/page', $edit, t('Save')); // Check that the node was authored by the currently logged in user. $node = $this->drupalGetNodeByTitle($edit['title[0][value]']); @@ -172,7 +181,7 @@ public function testNodeEditAuthoredBy() { $this->drupalLogin($this->adminUser); // Save the node without making any changes. - $this->drupalPostForm('node/' . $node->id() . '/edit', [], t('Save and keep published')); + $this->drupalPostForm('node/' . $node->id() . '/edit', [], t('Save')); $this->nodeStorage->resetCache([$node->id()]); $node = $this->nodeStorage->load($node->id()); $this->assertIdentical($this->webUser->id(), $node->getOwner()->id()); @@ -184,7 +193,7 @@ public function testNodeEditAuthoredBy() { // Check that saving the node without making any changes keeps the proper // author ID. - $this->drupalPostForm('node/' . $node->id() . '/edit', [], t('Save and keep published')); + $this->drupalPostForm('node/' . $node->id() . '/edit', [], t('Save')); $this->nodeStorage->resetCache([$node->id()]); $node = $this->nodeStorage->load($node->id()); $this->assertIdentical($this->webUser->id(), $node->getOwner()->id()); @@ -203,13 +212,13 @@ protected function checkVariousAuthoredByValues(NodeInterface $node, $form_eleme $edit = [ $form_element_name => 'invalid-name', ]; - $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published')); + $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save')); $this->assertRaw(t('There are no entities matching "%name".', ['%name' => 'invalid-name'])); // Change the authored by field to an empty string, which should assign // authorship to the anonymous user (uid 0). $edit[$form_element_name] = ''; - $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published')); + $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save')); $this->nodeStorage->resetCache([$node->id()]); $node = $this->nodeStorage->load($node->id()); $uid = $node->getOwnerId(); @@ -228,7 +237,7 @@ protected function checkVariousAuthoredByValues(NodeInterface $node, $form_eleme // Change the authored by field to another user's name (that is not // logged in). $edit[$form_element_name] = $this->webUser->getUsername(); - $this->drupalPostForm(NULL, $edit, t('Save and keep published')); + $this->drupalPostForm(NULL, $edit, t('Save')); $this->nodeStorage->resetCache([$node->id()]); $node = $this->nodeStorage->load($node->id()); $this->assertIdentical($node->getOwnerId(), $this->webUser->id(), 'Node authored by normal user.'); diff --git a/core/modules/node/tests/src/Functional/NodeFormButtonsTest.php b/core/modules/node/tests/src/Functional/NodeFormButtonsTest.php deleted file mode 100644 index 546a633..0000000 --- a/core/modules/node/tests/src/Functional/NodeFormButtonsTest.php +++ /dev/null @@ -1,135 +0,0 @@ -webUser = $this->drupalCreateUser(['create article content', 'edit own article content']); - // Create a user that has access to change the state of the node. - $this->adminUser = $this->drupalCreateUser(['administer nodes', 'bypass node access']); - } - - /** - * Tests that the right buttons are displayed for saving nodes. - */ - public function testNodeFormButtons() { - $node_storage = $this->container->get('entity.manager')->getStorage('node'); - // Log in as administrative user. - $this->drupalLogin($this->adminUser); - - // Verify the buttons on a node add form. - $this->drupalGet('node/add/article'); - $this->assertButtons([t('Save and publish'), t('Save as unpublished')]); - - // Save the node and assert it's published after clicking - // 'Save and publish'. - $edit = ['title[0][value]' => $this->randomString()]; - $this->drupalPostForm('node/add/article', $edit, t('Save and publish')); - - // Get the node. - $node_1 = $node_storage->load(1); - $this->assertTrue($node_1->isPublished(), 'Node is published'); - - // Verify the buttons on a node edit form. - $this->drupalGet('node/' . $node_1->id() . '/edit'); - $this->assertButtons([t('Save and keep published'), t('Save and unpublish')]); - - // Save the node and verify it's still published after clicking - // 'Save and keep published'. - $this->drupalPostForm(NULL, $edit, t('Save and keep published')); - $node_storage->resetCache([1]); - $node_1 = $node_storage->load(1); - $this->assertTrue($node_1->isPublished(), 'Node is published'); - - // Save the node and verify it's unpublished after clicking - // 'Save and unpublish'. - $this->drupalPostForm('node/' . $node_1->id() . '/edit', $edit, t('Save and unpublish')); - $node_storage->resetCache([1]); - $node_1 = $node_storage->load(1); - $this->assertFalse($node_1->isPublished(), 'Node is unpublished'); - - // Verify the buttons on an unpublished node edit screen. - $this->drupalGet('node/' . $node_1->id() . '/edit'); - $this->assertButtons([t('Save and keep unpublished'), t('Save and publish')]); - - // Create a node as a normal user. - $this->drupalLogout(); - $this->drupalLogin($this->webUser); - - // Verify the buttons for a normal user. - $this->drupalGet('node/add/article'); - $this->assertButtons([t('Save')], FALSE); - - // Create the node. - $edit = ['title[0][value]' => $this->randomString()]; - $this->drupalPostForm('node/add/article', $edit, t('Save')); - $node_2 = $node_storage->load(2); - $this->assertTrue($node_2->isPublished(), 'Node is published'); - - // Log in as an administrator and unpublish the node that just - // was created by the normal user. - $this->drupalLogout(); - $this->drupalLogin($this->adminUser); - $this->drupalPostForm('node/' . $node_2->id() . '/edit', [], t('Save and unpublish')); - $node_storage->resetCache([2]); - $node_2 = $node_storage->load(2); - $this->assertFalse($node_2->isPublished(), 'Node is unpublished'); - - // Log in again as the normal user, save the node and verify - // it's still unpublished. - $this->drupalLogout(); - $this->drupalLogin($this->webUser); - $this->drupalPostForm('node/' . $node_2->id() . '/edit', [], t('Save')); - $node_storage->resetCache([2]); - $node_2 = $node_storage->load(2); - $this->assertFalse($node_2->isPublished(), 'Node is still unpublished'); - $this->drupalLogout(); - - // Set article content type default to unpublished. This will change the - // the initial order of buttons and/or status of the node when creating - // a node. - $fields = \Drupal::entityManager()->getFieldDefinitions('node', 'article'); - $fields['status']->getConfig('article') - ->setDefaultValue(FALSE) - ->save(); - - // Verify the buttons on a node add form for an administrator. - $this->drupalLogin($this->adminUser); - $this->drupalGet('node/add/article'); - $this->assertButtons([t('Save as unpublished'), t('Save and publish')]); - - // Verify the node is unpublished by default for a normal user. - $this->drupalLogout(); - $this->drupalLogin($this->webUser); - $edit = ['title[0][value]' => $this->randomString()]; - $this->drupalPostForm('node/add/article', $edit, t('Save')); - $node_3 = $node_storage->load(3); - $this->assertFalse($node_3->isPublished(), 'Node is unpublished'); - } - -} diff --git a/core/modules/node/tests/src/Functional/NodeRevisionsUiBypassAccessTest.php b/core/modules/node/tests/src/Functional/NodeRevisionsUiBypassAccessTest.php index a3a575d..186b694 100644 --- a/core/modules/node/tests/src/Functional/NodeRevisionsUiBypassAccessTest.php +++ b/core/modules/node/tests/src/Functional/NodeRevisionsUiBypassAccessTest.php @@ -67,7 +67,7 @@ public function testDisplayRevisionTab() { // Uncheck the create new revision checkbox and save the node. $edit = ['revision' => FALSE]; - $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, 'Save and keep published'); + $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, 'Save'); $this->assertUrl($node->toUrl()); $this->assertNoLink(t('Revisions')); @@ -78,7 +78,7 @@ public function testDisplayRevisionTab() { // Submit the form without changing the checkbox. $edit = []; - $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, 'Save and keep published'); + $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, 'Save'); $this->assertUrl($node->toUrl()); $this->assertLink(t('Revisions')); diff --git a/core/modules/node/tests/src/Functional/NodeRevisionsUiTest.php b/core/modules/node/tests/src/Functional/NodeRevisionsUiTest.php index cc364cd..a437e4a 100644 --- a/core/modules/node/tests/src/Functional/NodeRevisionsUiTest.php +++ b/core/modules/node/tests/src/Functional/NodeRevisionsUiTest.php @@ -55,7 +55,7 @@ public function testNodeFormSaveWithoutRevision() { // Uncheck the create new revision checkbox and save the node. $edit = ['revision' => FALSE]; - $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published')); + $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save')); // Load the node again and check the revision is the same as before. $node_storage->resetCache([$node->id()]); @@ -68,7 +68,7 @@ public function testNodeFormSaveWithoutRevision() { // Submit the form without changing the checkbox. $edit = []; - $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published')); + $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save')); // Load the node again and check the revision is different from before. $node_storage->resetCache([$node->id()]); diff --git a/core/modules/node/tests/src/Functional/NodeTranslationUITest.php b/core/modules/node/tests/src/Functional/NodeTranslationUITest.php index a8a7454..a44bea1 100644 --- a/core/modules/node/tests/src/Functional/NodeTranslationUITest.php +++ b/core/modules/node/tests/src/Functional/NodeTranslationUITest.php @@ -99,7 +99,9 @@ public function testPublishedStatusNoFields() { 'source' => $default_langcode, 'target' => $langcode ], ['language' => $language]); - $this->drupalPostForm($add_url, $this->getEditValues($values, $langcode), t('Save and unpublish (this translation)')); + $edit = $this->getEditValues($values, $langcode); + $edit['status[value]'] = FALSE; + $this->drupalPostForm($add_url, $edit, t('Save (this translation)')); $storage->resetCache([$this->entityId]); $entity = $storage->load($this->entityId); @@ -139,18 +141,6 @@ protected function getNewEntityValues($langcode) { /** * {@inheritdoc} */ - protected function getFormSubmitAction(EntityInterface $entity, $langcode) { - if ($entity->getTranslation($langcode)->isPublished()) { - return t('Save and keep published') . $this->getFormSubmitSuffix($entity, $langcode); - } - else { - return t('Save and keep unpublished') . $this->getFormSubmitSuffix($entity, $langcode); - } - } - - /** - * {@inheritdoc} - */ protected function doTestPublishedStatus() { $storage = $this->container->get('entity_type.manager') ->getStorage($this->entityTypeId); @@ -158,18 +148,18 @@ protected function doTestPublishedStatus() { $entity = $storage->load($this->entityId); $languages = $this->container->get('language_manager')->getLanguages(); - $actions = [ - t('Save and keep published'), - t('Save and unpublish'), + $statuses = [ + TRUE, + FALSE, ]; - foreach ($actions as $index => $action) { + foreach ($statuses as $index => $value) { // (Un)publish the node translations and check that the translation // statuses are (un)published accordingly. foreach ($this->langcodes as $langcode) { $options = ['language' => $languages[$langcode]]; $url = $entity->urlInfo('edit-form', $options); - $this->drupalPostForm($url, [], $action . $this->getFormSubmitSuffix($entity, $langcode), $options); + $this->drupalPostForm($url, ['status[value]' => $value], t('Save') . $this->getFormSubmitSuffix($entity, $langcode), $options); } $storage->resetCache([$this->entityId]); $entity = $storage->load($this->entityId); diff --git a/core/modules/options/tests/src/Functional/OptionsFieldUITest.php b/core/modules/options/tests/src/Functional/OptionsFieldUITest.php index 836740d..e29a1d0 100644 --- a/core/modules/options/tests/src/Functional/OptionsFieldUITest.php +++ b/core/modules/options/tests/src/Functional/OptionsFieldUITest.php @@ -328,7 +328,7 @@ public function testNodeDisplay() { $edit = [ $this->fieldName => '1', ]; - $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published')); + $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save')); // Check the node page and see if the values are correct. $file_formatters = ['list_default', 'list_key']; diff --git a/core/modules/search/src/Tests/SearchConfigSettingsFormTest.php b/core/modules/search/src/Tests/SearchConfigSettingsFormTest.php index 191e0cf..cc77f2b 100644 --- a/core/modules/search/src/Tests/SearchConfigSettingsFormTest.php +++ b/core/modules/search/src/Tests/SearchConfigSettingsFormTest.php @@ -47,7 +47,7 @@ protected function setUp() { // also needs the word "pizza" so we can use it as the search keyword. $body_key = 'body[0][value]'; $edit[$body_key] = \Drupal::l($node->label(), $node->urlInfo()) . ' pizza sandwich'; - $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published')); + $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save')); $this->container->get('plugin.manager.search')->createInstance('node_search')->updateIndex(); search_update_totals(); diff --git a/core/modules/system/src/Tests/Menu/BreadcrumbTest.php b/core/modules/system/src/Tests/Menu/BreadcrumbTest.php index 64c8c15..39303ff 100644 --- a/core/modules/system/src/Tests/Menu/BreadcrumbTest.php +++ b/core/modules/system/src/Tests/Menu/BreadcrumbTest.php @@ -206,7 +206,7 @@ public function testBreadCrumbs() { $edit = [ 'menu[menu_parent]' => $link->getMenuName() . ':' . $link->getPluginId(), ]; - $this->drupalPostForm('node/' . $parent->id() . '/edit', $edit, t('Save and keep published')); + $this->drupalPostForm('node/' . $parent->id() . '/edit', $edit, t('Save')); $expected = [ "node" => $link->getTitle(), ]; @@ -227,7 +227,7 @@ public function testBreadCrumbs() { $edit = [ 'field_tags[target_id]' => implode(',', array_keys($tags)), ]; - $this->drupalPostForm('node/' . $parent->id() . '/edit', $edit, t('Save and keep published')); + $this->drupalPostForm('node/' . $parent->id() . '/edit', $edit, t('Save')); // Put both terms into a hierarchy Drupal » Breadcrumbs. Required for both // the menu links and the terms itself, since taxonomy_term_page() resets diff --git a/core/modules/system/src/Tests/Update/UpdatePathRC1TestBaseFilledTest.php b/core/modules/system/src/Tests/Update/UpdatePathRC1TestBaseFilledTest.php index 09cc586..9ee6d0c 100644 --- a/core/modules/system/src/Tests/Update/UpdatePathRC1TestBaseFilledTest.php +++ b/core/modules/system/src/Tests/Update/UpdatePathRC1TestBaseFilledTest.php @@ -117,7 +117,7 @@ public function testUpdatedSite() { $this->assertText('Test Article - New title'); $this->assertText('Test 1'); $this->assertRaw('0.01'); - $this->drupalPostForm('node/8/edit', [], 'Save and keep published (this translation)'); + $this->drupalPostForm('node/8/edit', [], 'Save (this translation)'); $this->assertResponse(200); $this->drupalGet('node/8/edit', ['language' => $spanish]); $this->assertText('Test title Spanish'); diff --git a/core/modules/system/src/Tests/Update/UpdatePathTestBaseFilledTest.php b/core/modules/system/src/Tests/Update/UpdatePathTestBaseFilledTest.php index fe62340..3c5aab0 100644 --- a/core/modules/system/src/Tests/Update/UpdatePathTestBaseFilledTest.php +++ b/core/modules/system/src/Tests/Update/UpdatePathTestBaseFilledTest.php @@ -117,7 +117,7 @@ public function testUpdatedSite() { $this->assertText('Test Article - New title'); $this->assertText('Test 1'); $this->assertRaw('0.01'); - $this->drupalPostForm('node/8/edit', [], 'Save and keep published (this translation)'); + $this->drupalPostForm('node/8/edit', [], 'Save (this translation)'); $this->assertResponse(200); $this->drupalGet('node/8/edit', ['language' => $spanish]); $this->assertText('Test title Spanish'); diff --git a/core/modules/taxonomy/tests/src/Functional/LegacyTest.php b/core/modules/taxonomy/tests/src/Functional/LegacyTest.php index 2894715..ac8e82d 100644 --- a/core/modules/taxonomy/tests/src/Functional/LegacyTest.php +++ b/core/modules/taxonomy/tests/src/Functional/LegacyTest.php @@ -60,7 +60,7 @@ public function testTaxonomyLegacyNode() { $edit['created[0][value][time]'] = $date->format('H:i:s'); $edit['body[0][value]'] = $this->randomMachineName(); $edit['field_tags[target_id]'] = $this->randomMachineName(); - $this->drupalPostForm('node/add/article', $edit, t('Save and publish')); + $this->drupalPostForm('node/add/article', $edit, t('Save')); // Checks that the node has been saved. $node = $this->drupalGetNodeByTitle($edit['title[0][value]']); $this->assertEqual($node->getCreatedTime(), $date->getTimestamp(), 'Legacy node was saved with the right date.'); diff --git a/core/profiles/standard/config/install/core.entity_form_display.node.article.default.yml b/core/profiles/standard/config/install/core.entity_form_display.node.article.default.yml index c94e36e..9082f2d 100644 --- a/core/profiles/standard/config/install/core.entity_form_display.node.article.default.yml +++ b/core/profiles/standard/config/install/core.entity_form_display.node.article.default.yml @@ -66,6 +66,13 @@ content: weight: 15 region: content third_party_settings: { } + status: + type: boolean_checkbox + settings: + display_label: true + weight: 120 + region: content + third_party_settings: { } sticky: type: boolean_checkbox settings: diff --git a/core/profiles/standard/config/install/core.entity_form_display.node.page.default.yml b/core/profiles/standard/config/install/core.entity_form_display.node.page.default.yml index 0b7ffd1..682f1a5 100644 --- a/core/profiles/standard/config/install/core.entity_form_display.node.page.default.yml +++ b/core/profiles/standard/config/install/core.entity_form_display.node.page.default.yml @@ -40,6 +40,13 @@ content: weight: 15 region: content third_party_settings: { } + status: + type: boolean_checkbox + settings: + display_label: true + weight: 120 + region: content + third_party_settings: { } sticky: type: boolean_checkbox settings: diff --git a/core/themes/bartik/css/components/form.css b/core/themes/bartik/css/components/form.css index 5ff46e4..672e591 100644 --- a/core/themes/bartik/css/components/form.css +++ b/core/themes/bartik/css/components/form.css @@ -172,6 +172,14 @@ input.form-submit:focus { .node-form .form-wrapper { margin-bottom: 2em; } +.node-form .node-form-footer, +.node-form .field--name-status { + margin-bottom: 0; +} +.node-form .form-actions { + padding-top: 0; + margin-top: 0; +} /* Contact Form */ .contact-form #edit-name { diff --git a/core/themes/seven/css/layout/node-add.css b/core/themes/seven/css/layout/node-add.css index 22faf33..96b0bc7 100644 --- a/core/themes/seven/css/layout/node-add.css +++ b/core/themes/seven/css/layout/node-add.css @@ -1,3 +1,9 @@ +.layout-region-node-footer__content { + border-top: 1px solid #bebfb9; + padding-top: 5px; + margin-top: 5px; +} + /** * Widescreen * diff --git a/core/themes/seven/templates/node-edit-form.html.twig b/core/themes/seven/templates/node-edit-form.html.twig new file mode 100644 index 0000000..cf747f9 --- /dev/null +++ b/core/themes/seven/templates/node-edit-form.html.twig @@ -0,0 +1,31 @@ +{# +/** + * @file + * Theme override for a node edit form. + * + * Two column template for the node add/edit form. + * + * This template will be used when a node edit form specifies 'node_edit_form' + * as its #theme callback. Otherwise, by default, node add/edit forms will be + * themed by form.html.twig. + * + * Available variables: + * - form: The node add/edit form. + * + * @see seven_form_node_form_alter() + */ +#} +
+
+ {{ form|without('advanced', 'footer', 'actions') }} +
+
+ {{ form.advanced }} +
+ +