Issue #3628775: Build content type templates visually

Closes #3628775. Builds on #3628772 and #3628774.

The Gutenberg settings of content types move to their own Manage Gutenberg tab, which links to a visual template builder: a block editor of the template, on a page of its own.

Manage Gutenberg tab

  • Where: /admin/structure/types/manage/{node_type}/gutenberg (administer content types), the last tab of the content type, and a "Manage Gutenberg" operation in the content types list. It replaces the "Gutenberg experience" vertical tab of the content type form, which had grown into a full page (template, builder, allowed block lists).
  • Form: NodeTypeGutenbergForm, with the settings, validation and saving that were in gutenberg_form_alter(). The element names are unchanged, so the #states, the "All" checkboxes and the template JSON editor work as before.
  • Content type edit form: has no Gutenberg settings anymore, and saving it no longer touches them.
  • Attributes added to blocks: themes and modules declare the attributes their scripts add to blocks in block-attributes: of their *.gutenberg.yml (e.g. Gutenberg Base: headerOverlay of core/cover), so the template JSON editor knows them and checks their type, instead of reporting them as unknown. The form doesn't load the block scripts. A declaration doesn't override a block.json attribute.
  • Content type add form: only has the "Enable Gutenberg experience" checkbox, since the tab needs a saved content type. When it is checked, it submits the Manage Gutenberg form programmatically, so a new content type gets the defaults the tab pre-checks.
  • Notes: gutenberg_notes creates or removes its comment field from the Manage Gutenberg form (also when the add form submits it), instead of the content type form.

Template builder

  • A page of its own: /admin/structure/types/manage/{node_type}/gutenberg/template (administer content types), linked by "Open template builder" on the Manage Gutenberg tab. The editor stylesheets (some style body) never load on the Manage Gutenberg form, and Back returns to it. The link asks first when the form has unsaved changes, as the builder opens the saved template: the custom one, or a template of the theme or a module.
  • Layout: not fullscreen. Like the node editor (same page template), it sits between the admin navigation and top bar, in Claro, Default Admin and Gin. A loading screen covers the page from the first paint, and cross fades to the builder once its blocks and canvas are loaded.
  • The editor: the editor of the node form, with the inserter, list view, block settings and the theme's canvas styles. It offers the allowed blocks of the saved content type. Content blocks are left out, since they would create entities. There is no template lock, so per-block locks can be set. There is no code editor (nor "Edit as HTML"), as a template has no HTML.
  • Template settings panel:
    • Placeholder: for blocks with a placeholder (paragraph, heading, button…).
    • Content can add blocks here: for blocks with a template lock (Group, Cover, Columns…). It sets templateLock: false, as WordPress templates do: content adds, moves and removes blocks there, also when the template is locked. A full width Group with a constrained layout is then an area edited like a page, where blocks can be wide or full.
    • Field mapping: maps the block to a field of the content type (the mappingFields attribute, which so far was only written in the JSON): the field (the title and the fields of the form display), its property (e.g. the alt text of an image field), the source (the block text or one of its attributes), a label, and text options (keep HTML, allowed tags, text format). Several mappings per block. A mapped block shows a badge in the canvas, e.g. "→ Title", while it is selected, focused or hovered in the List View.
    • The entity title block shows a placeholder, since a template has no title.
  • Section block: this setting replaces it. The section block stays for existing content, now in the Design category and without the negative margins it had in the editor.
  • Save template: saves the template as the custom template (source Custom) and returns to the Manage Gutenberg tab, whose JSON editor shows it. It is formatted like the JSON editor does; attributes equal to their default, empty text and note IDs are left out. Blocks the editor doesn't know (e.g. of a disabled module) are written back as they were. An empty template saves no template, and sets the lock to None.
  • Cancel: asks before discarding changes, then goes back to the Manage Gutenberg tab, like Back. Leaving the page otherwise with changes asks too.

Architecture

  • New packages/edit-template/: a stripped edit-entity, using @wordpress/editor's <Editor> without meta boxes, welcome guide, entity status, browser URL, autosave or post lock. It edits a page of the api-fetch mock that is never saved, and <Editor> creates its blocks from the template setting. edit-entity has no template conditions.
  • Shared by both editors:
    • New packages/store/ (@drupal-gutenberg/store): the drupal store, now createReduxStore() + register() on load, instead of the deprecated registerStore() in packages/editor. The store name is unchanged, so select('drupal') keeps working.
    • Moved to packages/components: the Drupal helpers and media AJAX commands from gutenberg.js; buildEditorSettings() (defaults, theme support, canvas assets, preset styles); getDrupalAdminPrimaryColor() (from edit-entity); DrupalGutenberg.defaultSettings.
    • In packages/block-library: applyDenyList() and removeThemeCategory().
    • Canvas colors: buildEditorSettings() now adds the admin theme colors it forwards to the canvas after the canvas stylesheets, whose :root WordPress defaults overrode them: the canvas of both editors (selection outlines, buttons) now uses the primary color of the admin theme.
    • On the server: a new gutenberg.editor_settings service (libraries-edit, theme support, canvas CSS URLs, image sizes), used by the node form and the template builder. FieldBlockRenderer::describeField() and ::META_FIELDS are shared with the node form.
  • Builder page: NodeTypeTemplateForm attaches the libraries and editor settings, and the gutenbergTemplateBuilder behavior renders the builder in it. "Save template" puts the template in the form's hidden template element and submits it, so it is validated (TemplateManager) and saved like a Drupal form.

Tests

  • Playwright, template-builder.spec.mjs: building a template (Placeholder, Save), field mapping (panel, badge, saved mappings, new content titled by a mapped heading), unlocking a group for content in a locked template, unknown blocks kept, allowed blocks offered, inserting, a theme template saved as the custom one, the entity title placeholder, the saved template opened (asking before leaving unsaved changes of the form), Cancel with and without changes, and Back.
  • PHPUnit, ContentTypeEditTest::testTemplateBuilder(): access, settings, the link on the Manage Gutenberg form, saving (redirect, source Custom, lock kept), an invalid template, and an empty one.
  • PHPUnit, ContentTypeEditTest: the Manage Gutenberg tab and operation and their access, saving the content type form keeps the settings, and the add form checkbox enables Gutenberg with the defaults. The other tests use the tab.
  • Playwright: the setup and the specs that change content type settings use the tab.
  • The full Playwright suite, as a regression check for the shared refactors.
Edited by Marco Fernandes

Merge request reports

Loading
Loading