Problem/Motivation

Right now if you use the "Content Blocks" there's no preview -- just "No Preview Available" text on a grey background. It makes sense because you can't render a block that doesn't exist yet. Is there any way to get a more accurate preview "image"?

A screenshot of the Gutenberg editor showing a Content Block with no preview image.

Steps to reproduce

1. Allow a "Content Block" like the "Text" block to be allowed on your node.
2. On the node edit page, use the "Block inserter" library to add the "Text" block. Hover over the block in the "Content Blocks" section and see no preview image, just "No Preview Available".

Proposed resolution

I imagine the ideal solution would be to render these blocks dynamically with some kind of default values, and then use a screenshot of that. Or possibly grab an existing block of the same type and render that?

An alternate, easier approach (explored initially here) is to allow editors to provide an image they load up somewhere to be the preview image.

Remaining tasks

- Submit preview image option patch
- Decide if that's a good approach or if we should go down the rendering path.
- If we do, add documentation about this feature somewhere... where does that go?

User interface changes

None

API changes

Adds a section to the gutenberg.yml file content-block-preview-image: where you can set a preview image per content-block bundle, like this: content-block/simple-hero: images/simple-hero.jpg

Data model changes

None

Issue fork gutenberg-3617959

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

mariacha1 created an issue. See original summary.

mariacha1’s picture

Status: Active » Needs review
marcofernandes’s picture

Status: Needs review » Needs work

Thanks @mariacha1! Let's go with the static preview image. It costs nothing at runtime, and the theme decides what editors see. Live previews can be a follow-up, see the end of this comment.

Review of MR !264

  1. No need for a previewImage attribute. registerBlock() already has the definition, so the edit component can read definition.previewImage, and the block only needs example: {} when there is an image (blocks without example keep "No preview available"). As an attribute, it becomes part of the block's schema for no reason.
  2. Only the default theme and modules should count. getContentBlockPreviewImage() goes through getDefinitions(), which includes every installed theme, so an image of an installed but unused theme can be picked. Use the default theme and its base themes (getActiveThemeDefinitions()), plus modules.
  3. Key the images by content block type ID. The key is the block name with _ and : replaced (content-block/simple-hero), which site builders don't see anywhere. The bundle ID, as in the UI, is clearer:
    content-block-previews:
      simple_hero: images/simple-hero.jpg
  4. Read the preview mode under both names. __unstableIsPreviewMode works with the block editor 3.0.x ships, but since WP 6.8 the setting is isPreviewMode, and BlockPreview only sets the new name. Checking both (settings.isPreviewMode || settings.__unstableIsPreviewMode) keeps the preview working after the next package update, and in 4.0.x.
  5. Smaller things:
    • Build the URL with the file_url_generator service instead of Url::fromUri('base:…') and \Drupal::root() in a service.
    • alt="": the inserter already shows the block title next to the preview.
    • A FunctionalJavascript test: hover the content block in the inserter, the preview shows the image (and "No preview available" without one).
    • Docs: the new key on the drupal.org documentation page of the *.gutenberg.yml settings.

About live previews

Rendering previews live is mostly a performance question. Upstream doesn't cache them: server-rendered core blocks (Archives, RSS, Latest Comments…) have example: {}, so every inserter hover sends a request to /wp/v2/block-renderer, and so does every pattern preview containing one. WordPress gets away with it because the inserter only previews the hovered block. Drupal's case is harder: an unconfigured content block has no entity to render.

If we do it in a follow-up, roughly:

  • A sample entity per bundle, generated once. Generating sample values isn't free of side effects (an image field creates a file each time), so the sample block is generated once and stored, like Layout Builder's SampleEntityGenerator does in tempstore.
  • Cache the render on the server. An unsaved entity isn't render cached, so the preview route wraps the build in an element with #cache keys (bundle, view mode). The cache tags of the view display and the fields then invalidate it.
  • Fetch each preview once per editor session. Keep the rendered HTML in a client side cache (a data store), by type and view mode, so hovering again or showing many pattern previews doesn't repeat requests. Upstream's ServerSideRender doesn't do this.
  • Drupal blocks first. DrupalBlock already renders from its settings (/editor/blocks/load), so it only needs an example and the client side cache. Content blocks come after, with the sample entity.
  • The static image still wins. When a theme declares an image, it's shown instead of the live render.

Setting back to Needs work for the points above.