Problem/Motivation

When the CSS field formatter is configured to render the <style> element in <head>, Layout Builder's live update is unable to update the CSS code. The live update feature works when the CSS field formatter is configured to render the <style> element in <body>.

Proposed resolution

Modify \Drupal\field_css\Plugin\Field\FieldFormatter\CssFormatter::view() to check the current route. If it belongs to the following Layout Builder routes, then override the formatter's configuration and render the <style> element in <body>:

  • layout_builder.add_block
  • layout_builder.update_block
  • layout_builder.remove_block
  • layout_builder.defaults.*
  • layout_builder.overrides.*

Remaining tasks

  • Submit patch
  • Update tests

User interface changes

Layout Builder's live preview will now reflect changes in real time for CSS field formatters that are configured to render <style> element in <head>.

API changes

None.

Data model changes

None.

Release notes snippet

Release [version] adds support for live updates in Layout Builder when a CSS field formatter is configured to <style> element in <head>.

Original report by ericras

When this is used in a custom block inside layout builder, the CSS isn't inserted/updated on the content preview screen upon creation/update of a block with a CSS field.

This is because Layout Builder renders the whole content section anew and sends it back via AJAX, but this module doesn't output the CSS in the regular content region.

Approach to solve this:
- the current <style> block needs an ID so it can be removed upon update.
- a couple AJAX commands need to be triggered by an update to Layout Builder https://www.drupal.org/docs/8/api/ajax-api/core-ajax-callback-commands

Comments

ericras created an issue. See original summary.

ericras’s picture

Issue summary: View changes
chris burge’s picture

I tried pursuing the approach laid out in the issue summary and was unsuccessful.

An alternative approach would be to check the current route and in certain cases, override the location from 'head' to 'body'.

Drupal\field_css\Plugin\Field\FieldFormatter\CssFormatter:

  /**
   * {@inheritdoc}
   */
  public function view(FieldItemListInterface $items, $langcode = NULL) {
+   // Whether <style> element is rendered in <head> or <body>.
+   $location = $this->getSetting('location');
+   // If the route is for certain Layout Builder routes, then override the
+   // location to 'body'. If the <style> element is rendered in <head>, then
+   // CSS changes will not be updated by Layout Builder's live preview
+   // feature. This forces an editor reload the page to see CSS changes.
+   $routes = [
+     'layout_builder.add_block',
+     'layout_builder.choose_block',
+     'layout_builder.choose_inline_block',
+     'layout_builder.update_block',
+     'layout_builder.remove_block',
+     'layout_builder.defaults.*',
+     'layout_builder.overrides.*',
+   ];
+   foreach ($routes as $item) {
+     if (preg_match("/$item/", \Drupal::service('current_route_match')->getRouteName())) { // Update to use dependency injection.
+       $location = 'body';
+       break;
+     }
+   }
+
    $element = [];
chris burge’s picture

Title: Trigger an AJAX update when used in Layout Builder » Support Layout Builder live preview when formatter is configured to render style in head
Issue summary: View changes
Status: Active » Needs review
StatusFileSize
new3.85 KB

Patch attached.

  • Chris Burge committed 0866d71 on 2.0.x
    Issue #3154655 by Chris Burge, ericras: Support Layout Builder live...
chris burge’s picture

Status: Needs review » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.