[PP-1] Expose Layout Builder data to REST and JSON:API

Created on 7 February 2018, almost 7 years ago
Updated 6 September 2024, 3 months ago

Problem/Motivation

When accessing Layout Builder overrides via REST (i.e. when accessing an overridden entity's layout field), the contents of sections are empty.

Proposed resolution

Add a normalizer for the layout_section DataType, which ensures that sections can be properly serialized and unserialized via the serialization API (and REST).

Remaining tasks

N/A

User interface changes

N/A

API changes

A new normalizer will be added for the layout_section DataType.
Layout section data will be exposed for all serialization types.

Data model changes

N/A

📌 Task
Status

Postponed

Version

11.0 🔥

Component
Layout builder 

Last updated 1 day ago

Created by

🇺🇸United States samuel.mortenson

Live updates comments and jobs are added and updated live.
  • Blocks-Layouts

    Blocks and Layouts Initiative. See the #2811175 Add layouts to Drupal issue.

Missing content requested by

🇦🇺Australia dpi
about 1 year ago
Sign in to follow issues

Comments & Activities

  • Issue created by @samuel.mortenson
  • 🇺🇸United States tim.plunkett Philadelphia
  • 🇺🇸United States samuel.mortenson

    Here's a start to this, still need to add tests and think about validation.

    I opted to write two normalizers - one for the layout_section DataType and another for the field item. This made sense to me as it allows for new kinds of layout field, but we could put everything in the field item normalizer if that seem simpler. I tested GET/PATCH and it seems to work, so feel free to test things out and find bugs as I (or others) write test coverage.

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    Great start :)

    1. Thanks for having a @DataType-level normalizer! This is in line with 📌 Discourage @FieldType-level normalizers, encourage @DataType-level normalizers, to strengthen the API-First ecosystem Needs work ! It also means this will work with JSON API :)
    2. +++ b/core/modules/layout_builder/layout_builder.services.yml
      @@ -39,3 +39,11 @@ services:
      +      - { name: normalizer, priority: 1 }
      ...
      +      - { name: normalizer, priority: 9 }
      

      Why these priorities? We've been insisting that normalizers always have a comment explaining the rationale behind their priorities.

      (This is a huge weakness in the Symfony DIC — priorities should not be numerical; one should have to define before/after dependencies. Numerical priorities don't work in projects that can be extended by simply installing modules.)

    3. +++ b/core/modules/layout_builder/src/Normalizer/LayoutSectionItemNormalizer.php
      @@ -0,0 +1,28 @@
      +class LayoutSectionItemNormalizer extends FieldItemNormalizer {
      ...
      +  protected $supportedInterfaceOrClass = LayoutSectionItem::class;
      

      Ideally we wouldn't have @FieldType-level normalizers.

      But it's indeed necessary for denormalization.

      Can you please make this service private and internal? So we can remove it when #2957385: FieldItemNormalizer never calls @DataType-level normalizer service' ::denormalize() method lands.

    4. +++ b/core/modules/layout_builder/src/Normalizer/SectionDataNormalizer.php
      @@ -0,0 +1,45 @@
      +    return $object->getValue()->toArray();
      

      I'm a bit scared by how freeform this seems to be. If it's so freeform, how will https://www.drupal.org/project/openapi then be able to generate documentation for this?

    5. In general: please look at #2926508: Add DateTimeNormalizer+TimestampNormalizer, deprecate TimestampItemNormalizer: @DataType-level normalizers are reusable by JSON:API for guidance/inspiration!
    6. It'd be great to also manually test this in JSON API (I realize you can't add test coverage for it since JSON API is not in core).
  • 🇺🇸United States samuel.mortenson

    Addressed all points in #4 (including new unit test coverage 🏄‍♂️) except the validation and schema feedback. May need @tim.plunkett to chime in here for direction.

  • 🇺🇸United States samuel.mortenson

    Fixed coding standards on the new test.

  • 🇺🇸United States samuel.mortenson

    And updated a test method to actually test ::supportsDenormalization

  • 🇺🇸United States samuel.mortenson

    Missed one.

  • 🇺🇸United States tim.plunkett Philadelphia
    +++ b/core/modules/layout_builder/src/Normalizer/SectionDataNormalizer.php
    --- /dev/null
    +++ b/core/modules/layout_builder/tests/src/Unit/SectionDataNormalizerTest.php
    
    +++ b/core/modules/layout_builder/tests/src/Unit/SectionDataNormalizerTest.php
    @@ -0,0 +1,86 @@
    +namespace Drupal\Tests\layout_builder\Unit\Normalizer;
    

    namespace mismatch; delete the \Normalizer part or move the file in and things should pass.

  • 🇺🇸United States samuel.mortenson

    Fixed the namespace issue, thanks @tim.plunkett!

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    Great work!

    1. +++ b/core/modules/layout_builder/src/Normalizer/LayoutSectionItemNormalizer.php
      @@ -0,0 +1,32 @@
      + * @todo Remove in https://www.drupal.org/node/issues/2957385
      

      ❤️

    2. +++ b/core/modules/layout_builder/src/Normalizer/SectionDataNormalizer.php
      @@ -0,0 +1,45 @@
      +  protected $supportedInterfaceOrClass = SectionData::class;
      ...
      +    /** @var \Drupal\Core\Field\FieldItemInterface $field_item */
      

      This is tying the denormalization of a @DataType to its containing field. That shouldn't be necessary. All this should be doing is creating the value necessary to be set on the main property of a @FieldType=layout_section.

      Then LayoutSectionItemNormalizer::denormalize() can take that return value and set it on the @FieldType=layout_section target instance.

      Is this confusing, messy, and poorly delineated? Yes. That's what 📌 Discourage @FieldType-level normalizers, encourage @DataType-level normalizers, to strengthen the API-First ecosystem Needs work aims to fix/standardize, but until then we need to be vigilant, to not introduce even more of these.

    3. +++ b/core/modules/layout_builder/tests/src/Unit/SectionDataNormalizerTest.php
      @@ -0,0 +1,86 @@
      +class SectionDataNormalizerTest extends UnitTestCase {
      

      🤘

  • 🇧🇪Belgium borisson_ Mechelen, 🇧🇪

    Based on #15, we need to fix .2 of that review.

  • 🇺🇸United States samuel.mortenson

    We discussed this in a private chat already, but I don't like the idea of having a typed data normalizer that normalizes \Drupal\layout_builder\Plugin\DataType\SectionData, but does not return an instance of SectionData when denormalized. Normalizers are meant to accept their ::supportedInterfaceOrClass in normalize, and return an object of that class in denormalize based on the $class argument. Changing this behavior defeats the purpose of normalization for me, even if core is already doing this.

    Maybe a middle ground would be to not have a typed data normalizer for SectionData, and instead write one for Drupal\layout_builder\Section, which is the value it accepts. Then the field normalizer could use this to set a value on its typed data object.

  • Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle .

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    I'm not sure I agree with #2914503: Determine if serializing blobs is safe for use in Layout Builder 's outcome — if that had had a different outcome, then this issue may not have needed to exist.

  • 🇺🇸United States mpotter

    Adding this as a stable blocker as sites need a way to export landing page content for deployment to other environments. This was possible with Lightning Landing Pages with Panelizer and is needed for nodes using Layout Builder with modules such as Default Content. Default Content exports are empty without this serializing patch.

  • 🇺🇸United States mpotter

    Here is a reroll of #14 against the latest 8.6

  • 🇺🇸United States mpotter

    Not sure if this is working for REST, but it's not working for default_content. This patch allows me to export a node with layout_builder and I see the proper json data in the export. However when I try to import the node json, I get:

    In SqlContentEntityStorage.php line 783:

    Value assigned to "section" is not a valid section

    In SectionData.php line 31:

    Value assigned to "section" is not a valid section

    When debugging this, it's trying to assign an array to the "section" property rather than a Section object class. Doesn't seem like the denormalizer is being called in LayoutSectionItemNormalizer::denormalize. But maybe it hasn't gotten to that point yet since the debug stack shows it is trying to get the property value in order to determine if it's empty first.

    Seems maybe related to this: https://www.drupal.org/project/jsonapi/issues/2955615 in JSONApi, but not fixed in core itself.

    Edited: Looks like this is what @samuel.mortenson was saying in #17, so sorry for the dup.

  • 🇺🇸United States mpotter

    Here is a tweak to the patch. This doesn't feel right at all, but it got me past the errors in default_content when importing the section json. default_content import is never calling anything in the SectionDataNormalizer so not sure if that's an issue with default_content or with the normalizer. Given that Sam mentioned he tested the previous patch with JSON get/patch it makes me think either default_content has a problem with json importing typed-data or that there is another core issue buried somewhere.

    In any case, posting this patch so a client can try it and to get more comments.

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    #24: Yeah, it definitely doesn't seem right that LayoutSectionItemNormalizer::denormalize() is duplicating logic from SectionDataNormalizer::denormalize(). That almost must mean that default_content does something funky, like only denormalizing field-level data and not field property-level data.

    Re-scanning this issue, I see that in #18 I linked to #2914503: Determine if serializing blobs is safe for use in Layout Builder . That reminds me of #2895532: @DataType=map cannot be normalized, affects @FieldType=link, @FieldType=map .

  • 🇭🇺Hungary huzooka Hungary 🇭🇺🇪🇺
  • 🇨🇦Canada jibran Toronto, Canada
    1. +++ b/core/modules/layout_builder/src/Normalizer/LayoutSectionItemNormalizer.php
      @@ -0,0 +1,32 @@
      +    $section_data = $this->serializer->denormalize($data['section'], SectionData::class, $format, $context);;
      +    return parent::denormalize($section_data->getValue(), $class, $format, $context);
      

      Let's add some docs here.

    2. +++ b/core/modules/layout_builder/src/Plugin/DataType/SectionData.php
      @@ -27,6 +27,9 @@ class SectionData extends TypedData {
      +    if ($value && is_array($value)) {
      +      $value = Section::fromArray($value);
      +    }
      

      We should add dedicated test(maybe KTB) for this.

  • 🇧🇾Belarus gun_dose

    I applied patch from #24 to Drupal 8.6.4 and it works fine for me. I exported node with layout to default content and imported it back and all works fine.

  • 🇨🇴Colombia jidrone

    The #24 also worked for me.

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    This just came up in the JSON:API issue queue: #3022575: [upstream] Support for layout 😀

  • 🇦🇺Australia tallytarik

    #24 also worked for me, Drupal 8.6.5.

  • 🇩🇪Germany jurgenhaas Gottmadingen

    Tried #24 in 8.6.7 and it works as expected.

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    👍 Normalization:

    First, and most importantly: applying this patch makes it show up in the json and hal_json formats fore core's REST module, as well as for the contrib JSON:API module (soon to be in core: #2843147: Add JSON:API to core as a stable module ). All information is available, and consistently so.

    🙏 Normalization test coverage

    This patch contains unit test coverage (👏), but not functional test coverage. Experience has taught me that for anything REST API-related, we want functional test coverage. Because there are so many subsystems being integrated (Entity API, Field API, Typed Data API, Routing API, Access API, Serialization API …), a functional test is a way to prove that it all actually works in actual requests.

    #2942976: Add REST test coverage for Layout Builder already exists for this, but I think it should be merged with this. We already have examples of REST tests for specific field types: \Drupal\Tests\datetime\Functional\EntityResource\EntityTest\EntityTestDateonlyTest, \Drupal\Tests\entity_test\Functional\Rest\EntityTestTextItemNormalizerTest, and more.

    🤔 Schema: documentation describing how to interpret the stored value

    Second most important: being able to make sense of this data: what is its schema, what is the meaning of the structure, and each particular value?

    Without this, it's going to be difficult for decoupled applications to allow a content creator to customize each individual entity and have the client respect this custom layout.

    Now, to be fair, Drupal 8.0.0 shipped without schema support for its REST API. I don't think we should hold Layout Builder to a higher standard. So I'm not arguing for complete/comprehensive API docs. I'm saying that for this field to be actually consumable/interpretable, given the complexity of a value for this field/data type is significantly higher than other core fields, it's necessary for it to be at least clearly documented. https://www.drupal.org/docs/8/core/modules/layout-builder does not yet exist.

    #2919811: Write Layout Builder handbook documentation already exists for this.

    😨 Validation

    It seems that validation is currently limited to:

        if ($value && !$value instanceof Section) {
          throw new \InvalidArgumentException(sprintf('Value assigned to "%s" is not a valid section', $this->getName()));
        }
    

    @mpotter encountered this in #23 when trying to use Layout Builder + https://www.drupal.org/project/default_content . Which is why he added the tweak/hack/work-around in #24.

    This isn't "real" validation though: it's only verifying that it receives data of a certain type, it doesn't yet verify the values of that data.

    I've searched through the code base, and as far as I can tell, validation is absent! 😨 To be more precise: there is no active need for validation logic, because the UI is structured in such a way that only trusted logic ever generates values to be stored. \Drupal\layout_builder\SectionListInterface + \Drupal\layout_builder\Section + \Drupal\layout_builder\SectionComponent fit together, forming a data structure that is more restricted than just an array, the UI/form logic interacts with methods on these, and hence there hasn't been a need for validation logic (at least not yet).

    However, when a decoupled client wishes to modify the layout for an entity, it of course does not have access to these nice PHP interfaces — all it has is plain JSON. There is no validation constraint on either @FieldType=layout_section or @DataType=layout_section. Which means that I can set arbitrary data. This has at least two dangerous consequences:

    1. I can break the site (or at least the viewing of a particular entity, and probably the editing of said entity too) by sending garbage data — AFAICT any array will be accepted.
    2. I can disclose sensitive information, by for example placing a "View" block with sensitive information without further access control, whose access is intended to be protected through block visibility rules. Since there are no restrictions on which blocks I can place.

    😨 Access

    AFAICT currently anybody who can edit the entity, can also edit Layout Builder's field.

    Considering the risks wrt validation, a viable strategy could be that only trusted users can modify Layout Builder's field. There is a configure any layout permission, but it's only applied to routes (with the _has_layout_section route requirement).

    @FieldType=layout_section could be protected by this permission as well. Created #3028301: Do not expose to Layout Builder's sections either in defaults or overrides to REST and other external APIs for this.

    🙏 Normalization implementation: complicated by the desire to support writes

    The only reason that LayoutSectionItemNormalizer exists (at least until #2957385: FieldItemNormalizer never calls @DataType-level normalizer service' ::denormalize() method lands), and also the only reason that \Drupal\layout_builder\Plugin\DataType\SectionData needs to be modified, is to support writes. The patch would become much simpler if we chose to not support writing, for now. Most of the value is in reading it anyway!

    Conclusion

    I see the following paths forward:

    1. The patch works well in that it exposes the data. But I worry that client developers will not know how to interpret this data.
      1. We could solve this altogether by simply not yet exposing this field via an API — that's totally legitimate! Once we make this available via APIs, we have to support it forever. Are we confident enough to commit to that? Marking this field type inaccessible (even better!) would instantly solve this issue.
        See 2942975-33_forbid_all_access.patch.
      2. If we don't want to do that, we have to document it and add explicit test coverage for at least one of every possible type of thing (field, block, view …) that can be placed using Layout Builder, to ensure we don't unknowingly change the schema. This is doable.
    2. My biggest fear is letting API clients writing layout information. AFAICT validation is absent. Which is fine for the coupled UI because it naturally limits what data can be saved, but not for a decoupled UI. I've explained why this can easily lead to broken sites at minimum, and information disclosure at worst.
      1. I think we should remove the ability to set this field via the API, at least for now.
        See 2942975-33_forbid_write_access.patch.
      2. If that's not an option, then I think we should at least restrict access.
        See #3028301: Do not expose to Layout Builder's sections either in defaults or overrides to REST and other external APIs .
  • 🇺🇸United States tedbow Ithaca, NY, USA

    @Wim Leers thanks for the detailed review!

    I can disclose sensitive information, by for example placing a "View" block with sensitive information without further access control, whose access is intended to be protected through block visibility rules. Since there are no restrictions on which blocks I can place.

    I think this is similar to the block UI in that if you give the user administer blocks permission that can place any block. True the user could set a visibility rule for user role but they don't have to. So you are essentially giving them permission to place any block and have render whatever it will render.

    At least in the layout case, for now, configure any layout, is a restricted permission.

    So for a Layout user they can place any block regardless of whether they are doing so via the UI or through a REST call.

    AFAICT currently anybody who can edit the entity, can also edit Layout Builder's field.

    Yes this is true for except for the access control on the routes. With the route access control only users with configure any layout permission can edit layouts. They don't actually need access to update the entity(or view right now 😫 #3028490: Users with "configure any layout" can see entities they don't have "view" access to )

    The patch would become much simpler if we chose to not support writing, for now. Most of the value is in reading it anyway!

    I 2nd this. I think a read-only solution now would be very useful.

    Once we make this available via APIs, we have to support it forever. Are we confident enough to commit to that?

    I would probably defer to @tim.plunkett on this. I guess 1 reason to not expose the field at all right now is I think we would be much more sure after 6 months or 1 year of Layout Builder being stable.

    I think that if for some reason we need to change the way the field is stored we could do that without any BC implications if the field is not exposed via our APIs. Because the no module should ever deserializing the Layout reading the data.

    If we expose the field over the API it would be effectively just that same as saying we support modules getting the json string decoding it and figuring out the layout from there. Because this is effectively be what a decoupled application would be doing.

    And once we expose we can never change that structure. Though in theory we could write a BC layer to with normalizer to keep the format the same for sites that want it the same. But considering how much discussion there was around #2751325: All serialized values are strings, should be integers/booleans when appropriate and #2768651: Let TimestampItem (de)normalize to/from RFC3339 timestamps, not UNIX timestamps, for better DX I think that is something we want to avoid at all costs if we can.

    So that would lead me to endorse:

    We could solve this altogether by simply not yet exposing this field via an API — that's totally legitimate! Once we make this available via APIs, we have to support it forever.

    If we can't do that I think we should only allow read access for now.

  • 🇺🇸United States tedbow Ithaca, NY, USA

    I have repurposed the existing issue which was Add default field-level access restriction to Layout Builder's field type to #3028301: Do not expose to Layout Builder's sections either in defaults or overrides to REST and other external APIs

    basically the idea is do this in 3 stages

    1. No field API access
    2. Read access
    3. Write access

    but we could discuss on that issue and leave this 1 for when we actually want to implement the normalizer(if we don't want to do it now)

  • 🇺🇸United States tim.plunkett Philadelphia

    Moving tag to other issue

  • Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle .

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    #34:

    I think this is similar to the block UI in that if you give the user administer blocks permission that can place any block.

    If that were the case, I wouldn't be worried. But today, there's no access control on the layout field at all: if the entity can be edited, then the layout can be edited. Which you acknowledged further in your comment.

    Thanks for linking #3028490: Users with "configure any layout" can see entities they don't have "view" access to — I hadn't found that yet. Following.

    Marking this issue postponed on #3028301: Do not expose to Layout Builder's sections either in defaults or overrides to REST and other external APIs .

  • 🇺🇸United States xjm
  • 🇺🇸United States xjm

    Turns out we had to introduce a hack in JSON:API itself to avoid exposing LB data over JSON:API. Adding Introduce entity type annotation key for indicating that an entity type is *safe* for HTTP API usage Needs work as a related issue.

    Since our existing normalizer for REST didn't apply to JSON:API, retitling to make it clear that fixing both should be in scope.

  • 🇫🇷France andypost

    The only issue I recall is inline blocks which has no ui and not enough data exposed

  • 🇺🇸United States mrweiner

    Just curious whether any progress has been made here. Since both JSON:API and Layout Builder are stable in core I think people will expect them to play nicely together.

  • 🇺🇸United States mpotter

    Also wondering what the current workaround for this is. The original patch in #24 was to provide a Json Normalizer for SectionData so the default_content module could export landing page nodes to be deployed across sites.

    In the past, landing pages could be designed using Panels and Page Manager and exported to config and deployed across site environments. With Layout Builder, landing pages are Node content and the main way our clients deployed this content was via the default_content module. Now with 8.7 this has all broken and clients no longer have a way to deploy configured landing pages between environments (such as a search results page with facet blocks and other blocks placed on the page).

    Is there any other way to restore a Json Normalizer that default_content can use to export a Node with Layout SectionData as JSON without exposing it to the world via Json:api?

  • 🇫🇷France andypost

    @mpotter for a while this normalizers could be added to https://www.drupal.org/project/better_normalizers

  • 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10

    Added duplicate issue from Default Content to related issues

  • 🇮🇳India Sharique

    I'm using 8.7.1, patch #33 doesn't work for me.
    And patch #24 give following error.
    Error: Maximum function nesting level of '256' reached, aborting! in Drupal::getContainer() (line 128 of /var/www/centara/docroot/core/lib/Drupal.php) #0 /var/www/centara/docroot/core/lib/Drupal.php(283): Drupal::getContainer() #1 ......

    Both patches work for me neither in JSON API nor default content export.

  • 🇺🇸United States mrweiner

    @Sharique I haven't actually tested the patches yet myself, but the error you've noted is unrelated. See https://stackoverflow.com/questions/4293775/increasing-nesting-function-...

  • 🇧🇾Belarus gun_dose

    Is there any progress? At 8.7 version all patches are not working.

  • 🇦🇺Australia thursday_bw

    Like gundose stated.

    The patches on this page don't work with 8.7.

    I have applied the patch in #24 cleanly, however there is no layout in the exported landing page.

  • 🇦🇺Australia thursday_bw

    If i'm understanding all this correctly,
    layouts aren't exposed to REST and other API's in drupal 8.7.* due to https://www.drupal.org/project/drupal/issues/3028301 which in turn means, default_content_deploy doesn't export it either. Even with the patches on the issue this comment refers to being applied.

    Can anyone thing of a work around, even if temporally?

  • 🇦🇺Australia thursday_bw

    OK.. Work around.

    I'm uploading this patch but I do not recommend that it be accepted into core.
    It's just here for you to apply to D8.7 if you so choose as a work around.

    If you apply patch 2942975-24.patch
    along with 2942975-52.patch

    You will be able to export the layout using
    default content deploy

    Due to https://www.drupal.org/project/drupal/issues/3028301 restricting exposure of layouts, I don't know yet what a correct solution to this
    would be.

  • 🇫🇷France andypost

    I think better to add normalizer to https://www.drupal.org/project/better_normalizers and create separate release for 8.7

  • 🇵🇱Poland Luke_Nuke

    This issue blocks layouts from being exportable by any module attempting that (default_content, content_sync among others). As most people from issue queues of these modules will end up here, I decided to write up the possible solution here.

    If you really want to have this working on 8.7.x (and possibly 8.8.x), you would have to apply the attached patch. It's just workaround though, because it has some security implications mentioned by Wim Leers . But that's not enough, you also would have to write custom normalizers for Layout elements. It is what was attempted by #24 . There are more issues if you want to use this exporting capability to later import these nodes with layouts. For example exported references to revision ids of inline block contents in layouts configurations won't match with the real ones, so there is more logic required to get proper references on import. I managed to make it work for my use case, and assuming the attached patch has been applied - it can be done by contrib module.

  • 🇦🇺Australia thursday_bw

    Luke Nuke, there is a work around for exporting layouts that works now, without any patch by taking advantage of layout builder library module. https://www.drupal.org/project/layout_library

    With this you can create a layout in the library, and then instead of adding a layout override on a node, you tell that node to use the layout from the library.. and then it all exports nicely.

  • 🇺🇦Ukraine GEO

    Reworked patches from #52 for D8.7.5
    As mentioned in #52 It is a temporary solution. I've created it for using it along with default content export.

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    I've created it for using it along with default content export.

    Just be aware that by doing this, you're on your own. Layout Builder does not guarantee that those storage details will remain the same. So if they change, your default content exports will stop working.

  • 🇺🇦Ukraine GEO

    Updated my previous patch #56 (I've missed several files).
    The patch for D8.7.5 and use it on your own risk.

  • Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles .

  • 🇺🇦Ukraine GEO

    One more patch for D8.7.5 - still use it on your own risk.

  • 🇬🇧United Kingdom vijaycs85 London, UK

    Manually tested the patch (8.7.x HEAD) with default_content module and the exported node has the layout configuration and node-level override details (as below).

    "layout_builder__layout": [
            {
                "section": {
                    "layout_id": "layout_onecol",
                    "layout_settings": [],
                    "components": {
                        "b9d1b078-51c2-4918-a69b-5a4b58e3a947": {
                            "uuid": "b9d1b078-51c2-4918-a69b-5a4b58e3a947",
                            "region": "content",
                            "configuration": {
                                "id": "block_content:18853fa3-6af3-44a2-a14e-799af4e46910",
                                "label": "Working block",
                                "provider": "block_content",
                                "label_display": 0,
                                "status": true,
                                "info": "",
                                "view_mode": "full",
                                "context_mapping": []
                            },
                            "additional": [],
                            "weight": 1
                        }
                    },
                    "third_party_settings": []
                }
            }
    ]
  • 🇬🇧United Kingdom lpc

    Tested patch manually on Umami (8.7.8) and multilingual website I am working on (8.7.7). I can confirm that Default content exports layout builder configuration.

    "layout_builder__layout": [
            {
                "section": {
                    "layout_id": "layout_onecol",
                    "layout_settings": [],
    		"components": {
                        "7ac803f4-47bf-45c6-bfda-cd53baa6bf06": {
                            "uuid": "7ac803f4-47bf-45c6-bfda-cd53baa6bf06",
                            "region": "content",
                            "configuration": {
                                "label_display": "0",
                                "context_mapping": {
                                    "entity": "layout_builder.entity"
                                },
                                "id": "extra_field_block:node:page_laybout_builder:>
                            },
                            "additional": [],
                            "weight": 0
                        },
                        "a2e569b1-224c-4e3a-9569-03d0db59f2f0": {
                            "uuid": "a2e569b1-224c-4e3a-9569-03d0db59f2f0",
                            "region": "content",
                            "configuration": {
                                "label_display": "0",
                                "context_mapping": {
                                    "entity": "layout_builder.entity"
                                },
                                "id": "field_block:node:page_laybout_builder:body",
                                "formatter": {
                                    "label": "hidden",
                                    "type": "text_default",
                                    "settings": [],
                                    "third_party_settings": []
                                }
                            },                                   
                        "16c0a1b9-9fb5-4b5d-9f71-bc30c84d65bd": {                   
                            "uuid": "16c0a1b9-9fb5-4b5d-9f71-bc30c84d65bd",         
                            "region": "content",                                    
                            "configuration": {                                      
                                "id": "inline_block:basic",                         
                                "label": "reger",                                   
                                "provider": "layout_builder",                       
                                "label_display": "visible",                         
                                "view_mode": "full",                                
                                "block_revision_id": "7",                           
                                "block_serialized": null,                           
                                "context_mapping": []                               
                            },                                                      
                            "additional": [],                                       
                            "weight": 2                                             
                        }                                                           
                    },                                                              
                    "third_party_settings": []                                      
                }                                                                   
            }                                                                       
        ]   
  • 🇮🇳India vaibhavjain Delhi

    The patch at #59 works well. I checked with JSON API output, and I am able to see the components there.
    However I have a case, where I am not able to fetch the component content.

    1. Added a new node, with layout builder enabled per node.
    2. Added a new block type, text block.
    3. Added a new block content of type, text block.
    4. From Node, layout manager, add a new block of type text block and add a block that already exists.
    5. In the JSON API output, we cannot access content of Block, added via layout builder.

    Question 1 - If we are exposing components, inside the layout, how do we plan to get content of each component ? There are no self or related links, to help you fetch the content and meta data of the component.
    Question 2 - If all of the above is true, are we saying that, we can only access content of the block, which are not create via Layout Builder ?

    I also see that JSONAPI, wont allow you to access the content of a block which is not reusable. A non Reusable block is created, when you add a block via Layout builder. However, this is also being worked upon here 2999491

    Output of my JSON API

    {
      "fda2e964-4a5e-4203-81ff-09954d1fb919": {
        "uuid": "fda2e964-4a5e-4203-81ff-09954d1fb919",
        "region": "first",
        "configuration": {
          "id": "inline_block:text_block",
          "label": "Non Reusable Block",
          "provider": "layout_builder",
          "label_display": "visible",
          "view_mode": "full",
          "block_revision_id": "2",
          "block_serialized": null,
          "context_mapping": []
        },
        "additional": [],
        "weight": 0
      },
      "f21a9758-3abe-4c96-8c60-53496fd31e42": {
        "uuid": "f21a9758-3abe-4c96-8c60-53496fd31e42",
        "region": "second",
        "configuration": {
          "id": "block_content:6255d80f-07e4-455e-bd47-f7a37fa9cee0",
          "label": "Reusable Block",
          "provider": "block_content",
          "label_display": "visible",
          "status": true,
          "info": "",
          "view_mode": "full",
          "context_mapping": []
        },
        "additional": [],
        "weight": 0
      }
    }
    
  • 🇮🇳India vedpareek

    Hi @Vaibhav I was facing the same issue, I have been able to send block bundle and block uuid in json output. This patch has been tested against 8.9.x branch.
    Attaching the patch for the same
    Thanks

  • 🇮🇳India vaibhavjain Delhi

    As the patch in #65 is incorrect, uploading the correct patch, with interdiff.

  • 🇺🇸United States zkent

    Hello,

    Our website uses a fair number of custom landing pages built using the landing page content type and modified using the layout builder. What is the status of a patch for this issue?

    Zach

  • 🇬🇧United Kingdom lpc

    What is the status of a patch for this issue?

    Patch #59 📌 [PP-1] Expose Layout Builder data to REST and JSON:API Postponed works well.

  • 🇨🇴Colombia aldibier Manizales

    Patch #67 works like a charm! tested in Drupal 8.8.1

  • 🇻🇳Vietnam lpmthong.dev

    I used #67, now can see the layout_builder__layout but how can I use jsonapi to PATCH the node to change the layout? Always get errors when tried to PATCH.

  • 🇬🇧United Kingdom vijaycs85 London, UK

    Re-rolling against 8.9.x (and works for 8.8.x as well).

  • 🇬🇧United Kingdom vijaycs85 London, UK

    @arthur.islamov could you provide interdiff ?

  • 🇺🇸United States morbus iff

    Confirming #72 is still an issue with #75: When attempting to PATCH a layout_builder__layout field, I receive: "The current user is not allowed to PATCH the selected field (layout_builder__layout)." I receive the same error with POST, meaning I can't create a custom layout in a node (i.e., I can't create custom landing pages from JSON:API). That's my sole need - is this patch only for EXPOSING the data, or also for creating/updating that data?

  • 🇷🇺Russia i-grou

    Tried patch #78 and it works fine for export, but somehow $section_data->getValue() (in LayoutSectionItemNormalizer->denormalize()) produces an error when importing node with individual layout (using content_sync module):

    Error: Call to undefined method Drupal\layout_builder\Section::getValue() in Drupal\layout_builder\Normalizer\LayoutSectionItemNormalizer->denormalize() (line 30 of /var/www/rtc.ccuptest.co.uk/web/core/modules/layout_builder/src/Normalizer/LayoutSectionItemNormalizer.php).
    

    So to workaround it I've added a check if method exists, if not - then using $data['section'] instead works fine.
    Maybe it's better to debug SectionData class, but I got no luck with this (in 15 min), maybe someone else can handle it. Or maybe it's related ot my drupal version - 8.8.4. Meanwhile we can go ahead with this patch.

  • 🇷🇺Russia i-grou

    I've ran some more tests and it turned out that patch above not working as expected. Hope it would be fixed in the next release.

  • 🇺🇦Ukraine aleevas

    The latest patch was rerolled

  • 🇺🇦Ukraine aleevas

    Fixed for latest patch

  • 🇬🇧United Kingdom jonathanjain

    I have applied #82 patch

  • 🇨🇦Canada adam3145

    I just tested this on Drupal 8.8, with layout builder and it's working well with content sync to export my inline blocks!
    Anything I can do to help get this commited?

  • 🇨🇦Canada adam3145

    I am on 8.8.2, I just put the file in the /web folder of my site, and ran the patch -p1

  • 🇳🇱Netherlands tbsiqueira Rotterdam

    Currently tested for drupal 8.5 works like a charm! Thank you!

    EDIT: Thank you for the reply @adam3145 I was using the wrong patch version, I used version 73 and it worked.

  • 🇺🇸United States carlosrfm Frederick, MD

    Successfully applied patch #82.

    Does anyone else is getting this a duplicate "section" tag? This is generating an error whenever I try to import.

    "layout_builder__layout": [
            {
                "section": {
                    "section": {
                        "layout_id": "layout_onecol",
                        "layout_settings": {

    Thanks!

  • 🇨🇦Canada adam3145

    I am not, do you have multiple sections on your export, as currently I only have 1 on all my pages.

  • 🇺🇸United States carlosrfm Frederick, MD

    No, just a single section containing 2 blocks (body and a form).

  • Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles .

  • 🇨🇦Canada adam3145

    Actually yes I do have duplicate sections, however I don't seem to be getting an error when trying to import.

    Are you using content sync?

  • heddn Nicaragua

    This hopefully fixes some things.

  • heddn Nicaragua

    removes a level of un-needed nesting and general cleanup.

  • heddn Nicaragua

    Hopefully a few more things fixed. The remaining failures I think are more complicated then what time I have to give right now. I did some manual testing and remaining failing tests didn't fail manually (for me).

  • heddn Nicaragua

    We have to remove the uuids as the keys for components since it causes XML serialization to fail. It isn't really needed any way, so I don't think that is an issue. See interdiff for how that looks in umami.

  • 🇨🇦Canada adam3145

    I don’t know what you mean content not exposed. I am using this with the content sync module and all of my inline blocks content are exporting and working perfectly

  • 🇭🇷Croatia Marko B

    As #64 wrote there are important questions this patch doesn't address. Layout builder will and should be used mostly for one time blocks and custom landing pages. So far we get config of the layout but content is non fetchable.

  • 🇭🇷Croatia Marko B

    @adam3145 sorry I didn't make it clear enough. So currently only "reusable" blocks can be fetched with JSON:API, those that dont have that option enabled have access restriction. There is this message "The current user is not allowed to GET the selected resource. Non-reusable blocks must set an access dependency for access control." that comes from getAccessCheckedResourceObject which gets access info from
    web/core/modules/block_content/src/BlockContentAccessControlHandler.php and checkAccess which has this

        if ($entity->isReusable() === FALSE) {
          if (!$entity instanceof DependentAccessInterface) {
            throw new \LogicException("Non-reusable block entities must implement \Drupal\block_content\Access\DependentAccessInterface for access control.");
          }

    meaning you won't be able to fetch with JSON API non-reusable blocks with current access checker in getAccessCheckedResourceObject.

  • 🇭🇷Croatia Marko B

    Other problem we have is that JSON:API output is not really DX friendly, simplest example would be that we get this export for simple custom block

                    "uuid": "365dd4c2-41ad-469a-94b3-dc426e8587d0",
                    "region": "content",
                    "configuration": {
                      "id": "inline_block:hero_block",

    which you then need to substring to get proper endpoint which would be jsonapi/block_content/hero_block/365dd4c2-41ad-469a-94b3-dc426e8587d0. This looks more like hardcoding stuff then dynamically getting proper endpoints.

    And this is simple example. I have much more complex, like having ID from commerce block

             "uuid": "60bf2ad0-4fcc-4633-ba40-80b1a6829979",
                    "region": "second",
                    "configuration": {
                      "id": "field_block:commerce_product:toys:variations",

    How to get proper url for this one :) is it even obtainable in current setup. There is some UUID but which endpoint to use here, JSON output doesnt help much?

  • 🇺🇸United States tim.plunkett Philadelphia

    #70 removed the issue summary, not sure why.
    Restoring what it was, but I think it needs an update anyway.

  • 🇨🇦Canada adam3145

    That’s interesting. I am using content sync and my non reusable inline blocks are exporting perfectly. I think I am using patch from 82 or so.

  • 🇩🇪Germany geek-merlin Freiburg, Germany

    #106: This means there will never be access for those one-shot blocks on their own.
    I suppose Includes come to the rescue, and maybe #105.

  • 🇭🇷Croatia Marko B

    I am using patch #78 as this is last one that works with 8.8.6 but I don't see this worked on on later patches and mentioned in comments and interfdiffs. If someone can verify this has been worked on later and where, would gladly check it.

  • 🇭🇷Croatia Marko B

    Also if you are using revisions for your LB and blocks also have revisions you will probably have problems with jsonapi and UUIDs. Seems to me this is the problem https://www.drupal.org/project/drupal/issues/3043321 which leads to this
    https://www.drupal.org/project/drupal/issues/3031271 Support version negotiation for any entity type (currently only Node & Media are supported) Fixed

    For me block uuids in LB json object dont match what I can fetch, when exposing them they return nothing, but I can manually find proper versions that JA can expose.

  • 🇨🇦Canada adam3145

    I have made a module that automatically fixes the UUID's for the purposes of content sync with exposed inline blocks. I can share it here if that's helpfull, it is a stand alone module that I was going to post while this is fixed up in core...

  • heddn Nicaragua

    I ran into an issue recently when exporting the layout builder data on a node that the inline blocks are linked via bid/vid. I can't just use their UUID and it relinks them when re-importing the content. That seems related to #112/113, is that true?

  • 🇨🇦Canada adam3145

    So I have a module that i did to fix that, It's attached. You just import normally then run this drush command to clean it up. "drush content-sync-fixer:all"

    What we had to do is:

    Layout Builder adds a new field to the tables where this feature is enabled, this field is a BLOB field where the layout configuration is saved as a PHP serialized object, each object in the layout is stored in this field with all the proper data to be shown, but, Layout Builder doesn't work as a Drupal entity itself it works in the same way as a text in a field.

    Content Sync converts any content in a config presentation in YML when it is exported and then each file is interpreted in a reverse way. Content Sync creates blocks normally when it imports the content, but the relationship stored in the BLOB field is not processed to try to connect properly the content of the field with the blocks. Then the revision_ids inside each inline-block in the layout configuration could not match with the revision_ids over the imported blocks, this is why some inline-blocks are missed and others are misconnected.

    To follow up the issue you must query the database in both instances (origin and destination) and check the related data to known entities and fields.

    To get specific node information
    SELECT * FROM node_field_data WHERE title = 'Web Design';

    To get layout builder data using previous information
    SELECT bundle, deleted, entity_id, revision_id FROM node__layout_builder__layout WHERE entity_id = 7;

    To get serialized data
    SELECT CAST(layout_builder__layout_section AS CHAR(50000) CHARACTER SET utf8) FROM node__layout_builder__layout WHERE entity_id = 7;

    You will get some like this...
    image.png

    If you check the layout builder information with the block_content table in both instances (origin and destination), you could check that the information is the same (after import in destination)

    But, if you check specific block using
    SELECT * FROM block_content WHERE revision_id = 107;

    It is possible that block content doesn't match, se below images
    image.png

    Our solution processes the content inside each node__layout_builder__layout record to connect each inline-block stored in the BLOB field taking in count its UUID code to connect to the correct block.

  • 🇷🇺Russia ilya.no

    I'm currently using latest patch and noticed, that new options have been added to the configuration, but no corresponding schema. Attaching patch with added schema changes.

  • 🇬🇧United Kingdom alexmoreno

    I've been testing this with latest patch in #116. TLDR, it works.

    Now, the long answer, in case it helps anyone else.

    Use case: Drupal as a repository of content for a js application (react, but could be vuejs or anything else).

    Layout builder is needed to build the content and expose it via json. A content type with layout builder enabled and a few custom blocks for testing.

    Used:

    - Drupal Version 8.9.2
    - https://www.drupal.org/project/jsonapi_explorer (for testing and exploration purposes)

    New brand install, enabled json api and layout builder, left everything else untouched. From there, I created a few landing pages where I am overriding the layout, adding new columns, adding blocks, custom blocks with specific fields, etc…

    I am fetching the whole list of nodes with this query:
    http://alexplayground.lndo.site:8000/jsonapi/node/landing_page/

    Then, once I know the node that I to check out, I just fetch that one, say for example:

    http://alexplayground.lndo.site:8000/jsonapi/node/landing_page/?filter[d...

    Results:
    Without the patch I could not see any information related to the layout or the fields exposed on that layout.

    After that, I applied the path and I repeated the query. Then I could see how a new field comes available: layout_builder__layout

    On it I can see the different layouts, the components I have created inside those layouts, layout_id, column_widths, the weight of each component, etc.

    Something to notice is that there will be no information on that query regarding the fields contained on those blocks, apart of label, uuid, and a few other bits. See:

      "configuration": {
            "id": "inline_block:custom_block",
            "label": "test title",
            "provider": "layout_builder",
            "label_display": 0,
            "view_mode": "full",
            "block_revision_id": "6",
            "block_serialized": null,
            "context_mapping": [],
            "type": "custom_block",
            "uuid": "3370b3b9-7d02-43b7-8b65-4c38de8dbf2d"
          },
    

    This can be puzzling on the beginning if you are not familiar with json, and make you think that you are missing information on that query. However, and please correct me here if I'm wrong, I think this is expected. Those extra bits require an extra jsonapi call using the uuid that is provided. For example, I have several blocks on that payload. I choose one of them, get the uuid and make a query like this:

    http://alexplayground.lndo.site:8000/jsonapi/block_content/text/d49bdb94...

  • 🇩🇪Germany geek-merlin Freiburg, Germany

    @alexmoreno #117:

    Great writeup!

    > Something to notice is that there will be no information on that query regarding the fields contained on those blocks, apart of label, uuid, and a few other bits.
    > This can be puzzling on the beginning if you are not familiar with json, and make you think that you are missing information on that query. However, and please correct me here if I'm wrong, I think this is expected. Those extra bits require an extra jsonapi call using the uuid that is provided.

    Can you check if Includes do work for this case?

  • 🇮🇳India vaibhavjain Delhi

    Thank you for explaining things well @alexmoreno. I had same issue ( https://www.drupal.org/project/drupal/issues/2942975#comment-13341530 📌 [PP-1] Expose Layout Builder data to REST and JSON:API Postponed ), and hence added type and UUID fields to be output ( https://www.drupal.org/project/drupal/issues/2942975#comment-13361683 📌 [PP-1] Expose Layout Builder data to REST and JSON:API Postponed ). This lets me atleast build the JSON:API URL, which I can use to fetch the content of the components placed, via layout builder.
    Yes, this was tested well with custom blocks and multiple block type, however never tried with fields from node or any other blocks from contrib modules.

    IMO, we should be providing the relative link automatically, so that we can hit one specific key to fetch the content, than building a URL currently.

    @geek-merlin I have verified this before, JSON:API includes does not work well here. Hence the route of adding more info to the output was taken.

  • 🇩🇪Germany geek-merlin Freiburg, Germany

    > I have verified this before, JSON:API includes does not work well here.

    Interesting. We should understand and document why. Or even better, make this work, maybe in a followup.

  • 🇬🇧United Kingdom alexmoreno

    @geek-merlin what I can see is that the document specifies that you need to use "relationship", ie:

    {
      "data": {
        "type": "node--article",
        "id": "some-random-uuid",
        "relationships": {
          "field_comments": {
            "links": {
              "related": {
                "href": "https://my.example.com/node/article/some-random-uuid/field_comments"
              }
            }
          }
        }
      }
    }

    then you can make a query like this:

    /jsonapi/node/article/some-random-uuid?include=field_comments.uid

    where field_comments is specified on the relationships.

    However on my tests I would not get those relationship fields, at least not for the layout builder components. I may not be doing it right though, see payload attached for reference.

    https://www.drupal.org/files/issues/2020-07-17/response-layout-builder-p...

  • 🇩🇪Germany geek-merlin Freiburg, Germany

    @alexmoreno: Thanks a lot!

    I did not check the source how JsonApi populates that reference field, but the hottest guess is that it uses EntityInterface::referencedEntities. In which case fixing this at least needs the referenced issue (it may or may not need more).

  • 🇵🇱Poland dmitry.korhov Poland, Warsaw

    Any news so far? This functionality is pretty essential for decoupled Drupal.
    Is https://www.drupal.org/project/drupal/issues/3151275 a blocker?
    Can we have this patch released at least as experemental module?

  • 🇬🇧United Kingdom alexmoreno

    Hi again,

    I have found an scenario where this is not working. I don't think it's expected, but please keep me humble here

    If you override the node with a custom layout, the layout data is exposed correctly (as shown in #117).

    However, if you have a default layout, and you don't override it in your node with the aim for that node to use the default one, then the json returns that the layout is empty. See:

    ```"layout_builder__layout":[]}```

    When selecting as well that

    Another case, if you specify that you don't want for that content type to be customised by the user on the node level, then the layout_builder__layout does not even appear on the json data.

    Does this even make sense? Anyone could raise any light on this?

    Thanks.

  • 🇺🇸United States tedbow Ithaca, NY, USA

    re #124

    Does this even make sense? Anyone could raise any light on this?

    Yes it makes sense. This issue just deals with exposing the stored layout information. Layout Builder stores the layout override data in a field it controls layout_builder__layout. It stores the default layout in the third party settings information of the LayoutBuilderEntityViewDisplay entity. If a particular bundle does not allow overrides then it does not create the layout_builder__layout field for that bundle.

    It sounds like what you want is "For any entity using the layout builder give me layout information". This would take more custom code either on the client side making more request or server-side augmenting the data that is stored with the entity when it is returned with JSON API.

    However, if you have a default layout, and you don't override it in your node with the aim for that node to use the default one, then the json returns that the layout is empty.

    Yes this because when you make a JSON API request for the node it only returns the actual data that is stored in the field just like any other field. In the case when there is not an override there is not date stored in this field.

    Another case, if you specify that you don't want for that content type to be customised by the user on the node level, then the layout_builder__layout does not even appear on the json data.

    This is because the layout_builder__layout is not added until entity display is set to use the layout builder and allow overrides. The field is also deleted if the ability do overrides is removed(you can't do this while there is field data, i.e. any existing overrides.)
    @see \Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay::addSectionField() and \Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay::removeSectionField()

    if you wanted get the default layout when there is no override you would have to make a JSON API request for entity_view_display entity that stores this information in it's third party settings. It would tell if the layout builder is enable and the default layout.

  • 🇬🇧United Kingdom alexmoreno

    I did some work trying to get the default layouts for when the nodes are not overriding it.

    Here are my notes, I'll publish this code in a module as well, so it's easier to patch in case anyone has any feedback

    https://www.alexmoreno.net/layout-builder-exposing-content-type-default-...

  • 🇬🇧United Kingdom alexmoreno

    see as well the code here: https://www.drupal.org/project/lb_default_layout

    Can we assume that this patch is tested and RBTC? Are there any concerns left?

  • 🇺🇸United States tim.plunkett Philadelphia

    Still needs an issue summary update.
    The patch is also failing tests.
    Here's a code review.
    Whoever updates the patch, please include an interdiff.

    1. +++ b/core/modules/layout_builder/layout_builder.services.yml
      @@ -44,6 +44,17 @@ services:
      +  layout_builder.normalizer.entity_display:
      +    class: Drupal\layout_builder\Normalizer\LayoutEntityDisplayNormalizer
      +    tags:
      +      # Priority must be higher than serializer.normalizer.config_entity.
      +      - { name: normalizer, priority: 1 }
      +    arguments: ['@entity_type.manager', '@entity_type.repository', '@entity_field.manager']
      +  layout_builder.normalizer.section_data:
      +    class: Drupal\layout_builder\Normalizer\SectionDataNormalizer
      +    tags:
      +      # Priority must be higher than serializer.normalizer.typed_data.
      +      - { name: normalizer, priority: 1 }
      
      +++ b/core/modules/layout_builder/src/LayoutBuilderServiceProvider.php
      @@ -39,14 +37,6 @@ public function register(ContainerBuilder $container) {
      -    if (isset($modules['serialization'])) {
      -      $definition = (new ChildDefinition('serializer.normalizer.config_entity'))
      -        ->setClass(LayoutEntityDisplayNormalizer::class)
      -        // Ensure that this normalizer takes precedence for Layout Builder data
      -        // over the generic serializer.normalizer.config_entity.
      -        ->addTag('normalizer', ['priority' => 5]);
      -      $container->setDefinition('layout_builder.normalizer.layout_entity_display', $definition);
      -    }
      

      Why this change?

    2. +++ b/core/modules/layout_builder/src/Plugin/DataType/SectionData.php
      @@ -30,8 +30,18 @@ class SectionData extends TypedData {
      +
      +    if ($value && is_array($value)) {
      +      $value = Section::fromArray($value);
      +    }
      ...
           if ($value && !$value instanceof Section) {
      

      This addition isn't documented. It also seems to overlap with the next conditional

    3. +++ b/core/modules/layout_builder/src/Plugin/DataType/SectionData.php
      @@ -30,8 +30,18 @@ class SectionData extends TypedData {
      +      else {
      +        parent::setValue($value->value, $notify);
      +      }
      

      Drop the else case, and have $value = $value->value;?

      Also why is there all of a sudden a $value->value?

    4. +++ b/core/modules/layout_builder/src/Section.php
      @@ -337,9 +337,9 @@ public function toArray() {
      -      'components' => array_map(function (SectionComponent $component) {
      +      'components' => array_values(array_map(function (SectionComponent $component) {
      

      Why this addition? Does this change have test coverage?

    5. +++ b/core/modules/layout_builder/tests/src/Unit/SectionDataNormalizerTest.php
      @@ -0,0 +1,95 @@
      +    $section->toArray()
      +      ->willReturn($data);
      +    $section_data->getValue()
      +      ->willReturn($section);
      

      Nit: remove needless returns/indents

    6. +++ b/core/profiles/demo_umami/config/install/core.entity_view_display.node.recipe.full.yml
      @@ -31,7 +31,7 @@ third_party_settings:
      -          eadd557c-6414-40e5-9a95-355720385477:
      +          -
      

      Whoa, this is a data model change, isn't it?

  • Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle .

  • heddn Nicaragua

    re #128.6. See #100 for the reason for those changes. It was an issue w/ XML seralization. Not so much for JSON/YAML. But we have to support all, right?

  • 🇨🇳China Oscaner

    Based on #116 patch, no changes, just want to patch successfully on Drupal 8.8.10

  • 🇮🇳India mayurjadhav Mumbai

    Added patch for 8.9.x, Kindly Review.

    Ref from duplicate issue: https://www.drupal.org/project/drupal/issues/3182960

  • 🇺🇸United States tim.plunkett Philadelphia

    @mayurjadhav How does that relate to the patch from #116 that I reviewed in #128?
    Or the reroll for 8.8 in #131? Your patch is less than half the size, and doesn't seem to have any test coverage.

    As I asked in #128:

    Whoever updates the patch, please include an interdiff.

    Someone please help get this issue back on track! Needs an issue summary update, and also a fresh 9.2.x patch that takes #128 into account.

  • 🇮🇳India mayurjadhav Mumbai

    @tim.plunkett Sorry for the incomplete patch...I was in rush and uploaded patch without reading all comments..I'm working on latest patch which will address all the points mention in #128 along with Test.

  • Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle .

  • 🇪🇸Spain manuel.adan 🌌

    #131 just for the 8.9.x branch

  • 🇮🇳India kuhikar

    Hello Team

    I have resolved phpcs for 9.1.x and added patch: 2942975_137.patch by combining 2942975-drupal_8_9_x-136.patch.

    I have followed below steps for 9.1.x version:

    Please do check attached images for the reference.

  • 🇮🇳India kuhikar

    Hello Team,

    I have corrected CSpell : failed issue of https://www.drupal.org/pift-ci-job/2105852 for #138. Please do check updated patch (
    2942975_140.patch, 2942975_d8_to_d9_140.patch )
    for resolving the phpcs errors in Drupal 9.1.x.

    Please merge #136 and create 3.x version, after that for 9.1.x, please merge
    2942975_140.patch.

    2942975_d8_to_d9_140.patch created for Unix Line Ending formats and root directory is in /app folder.

  • 🇵🇱Poland dmitry.korhov Poland, Warsaw

    @kuhikar please add interdiff

  • 🇮🇳India kuhikar

    Hello Team,

    Please do check updated patch : 2942975-142-d8_d9.patch for resolving hunk error.

    @dmitry.korhov, Please check attached interdiff-136-142.txt.

    I have applied #136 patch on D89x and #142 on D91x and after that, I run command to get diff for --core/modules/layout_builder.

  • 🇮🇳India kuhikar

    Hello Team,

    Currently, we are migrating D8 to D9 and please help to merge patch so we will have 3.x version.

    Please do check: Drupal 8 end-of-life on November 2, 2021 : https://www.drupal.org/psa-2021-2021-06-29

    Kindly help us to release 3.x version.

  • 🇮🇳India kuhikar

    Hello Team,

    Any update to release 3.x version of this module? Kindly help us.
    @dmitry.korhov, Can you please review patch: 2942975-142-d8_d9.patch

    Drupal 8 end-of-life on November 2, 2021 : https://www.drupal.org/psa-2021-2021-06-29

  • 🇺🇸United States acouch

    I re-rolled this against 9.3.x

  • 🇺🇸United States tim.plunkett Philadelphia

    Unfortunately all of the patches posted since #116 have either lost changes or added new unnecessary changes. Switching to an MR and maybe going to try to address #128...

    Still needs an issue summary update.

  • @timplunkett opened merge request.
  • 🇺🇸United States tim.plunkett Philadelphia

    NR to see how tests are doing

  • 🇺🇸United States tim.plunkett Philadelphia

    Okay I went ahead and made the issue summary updates and feedback changes I'd asked for last year, and resolved the remaining test failures.
    This should be ready for review now.

  • 🇨🇦Canada TrevorBradley

    Commit e866ee63 is causing a fault on my system:

    [error] InvalidArgumentException: Value assigned to "section" is not a valid section in Drupal\layout_builder\Plugin\DataType\SectionData->setValue() (line 34 of /app/docroot/core/modules/layout_builder/src/Plugin/DataType/SectionData.php).

    $value is still being passed in as an array for a custom layout section, removing the array filter from SectionData::setValue() causes it to break.

  • 🇩🇪Germany mkalkbrenner 🇩🇪

    Here's a patch based on MR 1131 and the comment #150.

  • 🇩🇪Germany mkalkbrenner 🇩🇪

    Something went wrong.

  • 🇺🇸United States tedbow Ithaca, NY, USA
  • 🇩🇪Germany mkalkbrenner 🇩🇪

    I ran the failing tests multiple times locally. The result toggles. Sometimes the tests succeed, sometimes they fail.

  • 🇺🇸United States tim.plunkett Philadelphia

    Please stop posting patches now that we're using the MR. Just push new commits to the branch.

  • 🇩🇪Germany mkalkbrenner 🇩🇪

    @tim.plunkett the patch I posted didn't contain anything new. It just reflects an earlier version of the MR, that doesn't lead to errors in default_content_deploy, just as mentioned in #150.
    I uploaded it to have something that could be used deployment piplines already.

    Am I allowed to revert your change directly in the MR?

    The required change is already discussed above and it seemed that you're not convinced yet.

  • 🇦🇺Australia Deciphered

    I can confirm that the patch from #152 works with Tome and JSON:API whereas the current MR works with JSON:API but not Tome, with the errors reported in #150.

    It would be ideal to get the MR synced back to the patch.

  • 🇮🇳India BalasaranyaV

    Rebased a patch #152 to merge with Drupal 9.3.x branch.

  • Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle .

  • 🇩🇪Germany Christian.wiedemann

    Hi all, I try to solve the puzzle to load layout builder inline blocks with JSON:API. My puzzle starts here and after a long weekend I just want to ask if I am on the right trail.

    This patch provides sections and components but not the associated block content entities. This is by design. To fetch inline blocks we need a second jsonapi call. @alexmoreno mentioned it in #117. (Thanks for the post, it helps to understand such long issues)

    Fetching blocks works right now BUT filter by any query doesn't. There is hard coded resuable=true in TemporaryQueryGuard. So I can't fetch them. This is propably also by design? So I can fetch a block with jsonapi/block_content/text/d49bdb94... but not with jsonapi/block_content/text?filter[id]=d49bdb94... or with any other filter.

            if (isset(static::$fieldManager->getBaseFieldDefinitions($entity_type_id)['reusable'])) {
              $specific_condition = new EntityCondition('reusable', 1);
              $cacheability->addCacheTags($entity_type->getListCacheTags());
            }
    

    So I did not find any solution to fetch multiple non reusable inline blocks in one call. To help me out I created https://www.drupal.org/project/jsonapi_include_lb which uses a simple computed field to provide blocks as entity reference.

    Is there a better option?

  • 🇩🇪Germany mkalkbrenner 🇩🇪

    Re-rolled against 9.4.x to get test results

  • 🇩🇪Germany mkalkbrenner 🇩🇪

    I ran the tests locally. The same tests fail. As soon as I enable xdebug and step through \Drupal\rest\Plugin\rest\resource\EntityRessource::get(), the tests succeed. It looks like a timing issue which is strange.
    If the error happens and the server returns status code 500 it complains about an illegal character in \Symfony\Component\Serializer\Encoder\XmlEncoder.
    But I can't debug it. As already mentioned, the error doesn't happen as soon as xdebug is enabled and I try to step through the process.

  • 🇩🇪Germany mkalkbrenner 🇩🇪

    like described in #165 and seen as different numbers of failures in #163 and #166, there seems to be a timing problem or an issue with randomized content in the tests.

  • 🇺🇸United States drupalninja99

    I am confused why we went away from this approach which return components as an array of objects: https://www.drupal.org/files/issues/2021-08-25/2942975_145.patch

    This is much more useful in Gatsby. I saw at some point that change went away back to a nested object.

  • 🇺🇸United States drupalninja99

    I have the same issue cited in https://www.drupal.org/project/drupal/issues/2942975#comment-13361683 📌 [PP-1] Expose Layout Builder data to REST and JSON:API Postponed and other places where I can't fetch inline block data from JSON:API like I would say paragraphs. Those JSON:API endpoints only include reusable blocks and the patch from this thread does not include all the block fields in layout_builder__layout. That means I am unable to get all the block data I need on the frontend.

  • 🇺🇸United States drupalninja99

    After quite a bit of work/testing I found the solution I needed in project jsonapi_include_lb.

  • First commit to issue fork.
  • 🇮🇳India sumitmadan Chandigarh

    I rebased the MR with 9.4.x branch. I am not able to edit the base branch in the MR. I am not sure if I need any permission for that.

    @tim.plunkett can you please update that?

  • 🇮🇳India sumitmadan Chandigarh

    I continued testing the MR on my local. I see two tests are failing which are because of a single reason. The xml format is not rendering properly. The error is following:

    DOMException: Invalid Character Error in DOMDocument->createElement() (line 490 of /app/vendor/symfony/serializer/Encoder/XmlEncoder.php).

    The reason is the uuid part inside the component key.

    "components": {
       "38a9bdec-3df6-457d-bf7a-15b19bd67736": {
    }
    

    Does anybody have a suggestion on this problem?

    Paragraph does it like this and it works fine with paragraph:

    "field_test": [
    	{
    		"target_id": 1,
    		"target_revision_id": 1,
    		"target_type": "paragraph",
    		"target_uuid": "d1fd68e4-e561-4d09-afd4-cbb6ac86d190"
    	},
    	{
    		"target_id": 2,
    		"target_revision_id": 2,
    		"target_type": "paragraph",
    		"target_uuid": "02b5f3d6-8cf5-4b31-9b07-cb5480223860"
    	}
    ]
    
  • 🇺🇸United States tim.plunkett Philadelphia

    #173, thanks for the rebase. I adjusted the target branch.

  • 🇬🇧United Kingdom mattjones86 🇬🇧 GMT+0

    I have given this MR a try today and found that while it did expose the Layout Builder data, it unfortunately didn't do a great job exposing data for the inline_block entities.

    Within each Layout Builder Section these block are referenced with block_revision_id, but the relationships are not attached to allow modules like entity_share to know where to find these.

    It would be ideal if these could be looked up and appended in a similar method to EntityReference fields. I did take a look at updating the MR with this myself, but it looked a little too complex to attempt without guidance.

    From what I understand, it would involve updating ResourceObjectNormalizer::serializeField() to handle LayoutSectionItemList fields, along with adding quite a few new methods (e.g. Relationship::createFromLayoutBuilderField()) to find and append the correct relationships.

          if ($field instanceof EntityReferenceFieldItemListInterface) {
            // Build the relationship object based on the entity reference and
            // normalize that object instead.
            assert(!empty($context['resource_object']) && $context['resource_object'] instanceof ResourceObject);
            $resource_object = $context['resource_object'];
            $relationship = Relationship::createFromEntityReferenceField($resource_object, $field);
            $normalized_field = $this->serializer->normalize($relationship, $format, $context);
          }
          else if ($field instanceof LayoutSectionItemList) {
            // Pluck inline_block revision IDs and append to relationships here
          }
          else {
            $normalized_field = $this->serializer->normalize($field, $format, $context);
          }
    
    {
      "jsonapi": {
        "version": "1.0",
        "meta": {
          "links": {
            "self": {
              "href": "http://jsonapi.org/format/1.0/"
            }
          }
        }
      },
      "data": {
        "type": "node--article",
        "id": "d7284b3e-a616-4d33-ac88-919bce701b63",
        "links": {
          "self": {
            "href": "https://dev.example.com/jsonapi/node/article/d7284b3e-a616-4d33-ac88-919bce701b63?resourceVersion=id%3A1"
          }
        },
        "attributes": {
          "drupal_internal__nid": 1,
          "drupal_internal__vid": 1,
          "langcode": "en",
          "revision_timestamp": "2021-09-14T09:41:50+00:00",
          "revision_log": null,
          "status": true,
          "title": "Article Style Guide",
          "created": "2021-09-14T09:41:39+00:00",
          "changed": "2022-01-19T10:47:02+00:00",
          "promote": false,
          "sticky": false,
          "default_langcode": true,
          "revision_translation_affected": true,
          "metatag": null,
          "path": {
            "alias": "/article-style-guide",
            "pid": 82,
            "langcode": "en"
          },
    
          ...
    
          "layout_builder__layout": [
            {
              "section": {
                "layout_id": "layout_twocol_section",
                "layout_settings": {
                  "label": "",
                  "column_widths": "50-50",
                  "layout_builder_styles_style": [
                    "section_margin_normal",
                    "section_vertical_align_top",
                    "section_width_normal"
                  ],
                  "context_mapping": []
                },
                "components": {
                  "5a6eed43-01f1-4bc3-88d3-0e933da4ab7e": {
                    "uuid": "5a6eed43-01f1-4bc3-88d3-0e933da4ab7e",
                    "region": "first",
                    "configuration": {
                      "id": "inline_block:image",
                      "label": "",
                      "label_display": true,
                      "provider": "layout_builder",
                      "view_mode": "full",
                      "block_revision_id": "223987",
                      "block_serialized": null,
                      "context_mapping": []
                    },
                    "weight": 0,
                    "additional": []
                  }
                }
              }
            }
          ]
        },
        "relationships": {
          "node_type": {
            "data": {
              "type": "node_type--node_type",
              "id": "1af93c9b-8669-4535-b786-f4c3f0b51488",
              "meta": {
                "drupal_internal__target_id": "article"
              }
            },
            "links": {
              "related": {
                "href": "https://dev.example.com/jsonapi/node/article/d7284b3e-a616-4d33-ac88-919bce701b63/node_type?resourceVersion=id%3A1"
              },
              "self": {
                "href": "https://dev.example.com/jsonapi/node/article/d7284b3e-a616-4d33-ac88-919bce701b63/relationships/node_type?resourceVersion=id%3A1"
              }
            }
          },
    
           // Would be ideal to see the related inline_block entities here!!
    
        }
      },
      "links": {
        "self": {
          "href": "https://dev.example.com/jsonapi/node/article/d7284b3e-a616-4d33-ac88-919bce701b63?resourceVersion=id%3A1"
        }
      }
    }
    
  • 🇺🇸United States tedbow Ithaca, NY, USA

    re #176

    It would be ideal if these could be looked up and appended in a similar method to EntityReference fields.

    I agree what that would be ideal but I think that could be follow-up to this issue. This issue is already 4 years old and adding more scope will just make take longer to get committed.

    I don't think we can alter layout_builder__layout to add this information because then this would probably cause problems for instance where this serialization was being used for import/export purposes. So it would probably have to be somewhere else in the JSON API response. For that reason I think it adds extra complexity to this issue.

  • 🇧🇴Bolivia vacho Cochabamba

    This patch is for core 8.3.x and contains array_values for SectionComponent. To avoid to crash the installation.

  • First commit to issue fork.
  • 🇩🇪Germany Antonnavi Berlin

    Patch for core 9.3.x (posted in #178) was updated:
    Added exposing of sections on request (through jsonapi module /jsonapi/page_variant/page_variant) of page variant which was built as a "Layout Builder". See more details here: https://www.drupal.org/project/page_manager/issues/3170526

  • 🇩🇪Germany Antonnavi Berlin

    @tim.plunkett or @joachim is it possible to add changes:

    diff -u b/core/modules/layout_builder/src/Section.php b/core/modules/layout_builder/src/Section.php
    --- b/core/modules/layout_builder/src/Section.php
    +++ b/core/modules/layout_builder/src/Section.php
    @@ -16,7 +16,7 @@
      * @see \Drupal\Core\Layout\LayoutDefinition
      * @see \Drupal\layout_builder\SectionComponent
      */
    -class Section implements ThirdPartySettingsInterface {
    +class Section implements ThirdPartySettingsInterface, \JsonSerializable {
     
       /**
        * The layout plugin ID.
    @@ -441,2 +441,11 @@
     
    +  /**
    +   * Returns a representation of the section for use in JSON serialization.
    +   *
    +   * @return array
    +   *   Representation of the section.
    +   */
    +  public function jsonSerialize() {
    +    return $this->toArray();
    +  }
    +
     }

    to the issue branch (to be able to export of sections through the jsonapi module on request like /jsonapi/page_variant/page_variant).

    UPD: Added, found how to do it by myself. Sorry for bothering.

  • 🇧🇴Bolivia vacho Cochabamba

    Still needs to fix, test issues.

  • 🇺🇸United States tim.plunkett Philadelphia

    Hiding patches since all work should be in the MR.

  • 🇨🇦Canada TrevorBradley

    [Deleted] My comment is about the layout_builder_st contrib module, not core. Apologies for getting my wires crossed. I'll go make my comment there.

  • 🇺🇸United States drupalninja99

    A shot in the dark but I liked the array_values() addition that was questioned in #128. This makes it much easier to query component data from GraphQL. Adding to the layout_builder-rebase_drupal_9_3_x-2942975-159.patch so that you can see what it looks like in comparison.

  • I tried path #185 and #180 and I do get the section data although I only get the components definitions without the block values. Here an example :

    "layout_builder__layout": [
        {
          "section": {
            "layout_id": "layout_onecol",
            "layout_settings": {
              "label": ""
            },
            "components": [
              {
                "uuid": "567ecf83-40c0-4554-befb-491ceaf38eb5",
                "region": "content",
                "configuration": {
                  "id": "inline_block:card",
                  "label": "Lorem ipsum title",
                  "label_display": "visible",
                  "provider": "layout_builder",
                  "view_mode": "full",
                  "block_revision_id": "2",
                  "block_serialized": null,
                  "context_mapping": [
                    
                  ],
                  "type": "card",
                  "uuid": "4d8cb490-6d31-4a2b-8d16-98a1490dcdef"
                },
                "weight": 2,
                "additional": [
                  
                ]
              }
            ],
            "third_party_settings": [
              
            ]
          }
        }
      ]

    I did some debugging and I realize that the `LayoutEntityDisplayNormalizer` is never called which could maybe explain why the inline block values are not showing ?

  • 🇮🇹Italy plach Venezia

    I was testing this and got an error on denormalizaton, this updated patch seems to fix it.

  • 🇮🇹Italy plach Venezia

    And this the 9.3.x version.

  • 🇧🇪Belgium kriboogh

    Small update on #189 to silence the return type error.

  • 🇮🇳India junaidpv Kannur, Kerala

    Exporting works fine with #191, but it fails with this message when try to import the exported node with layout builder settings:

    [error] Drupal\Component\Plugin\Exception\PluginNotFoundException: The "" plugin does not exist. Valid plugin IDs for Drupal\Core\Layout\LayoutPluginManager are: layout_twocol_section, layout_threecol_section, layout_fourcol_section, layout_onecol, layout_twocol, layout_twocol_bricks, layout_threecol_25_50_25, layout_threecol_33_34_33, radix_bryant_flipped, radix_bartlett_flipped, radix_bartlett, radix_boxton, radix_brenham_flipped, radix_brenham, radix_brown, radix_bryant, radix_burr_flipped, radix_burr, radix_geary, radix_harris, radix_hewston_flipped, radix_hewston, radix_mccoppin, radix_moscone_flipped, radix_moscone, radix_phelan, radix_pond, radix_rolph, radix_sanderson_flipped, radix_sanderson, radix_selby_flipped, radix_selby, radix_sutro_double, radix_sutro, radix_taylor_flipped, radix_taylor, radix_webb_flipped, radix_webb, radix_whelan, vefl_onecol, layout_builder_blank in Drupal\Core\Plugin\DefaultPluginManager->doGetDefinition() (line 53 of core/lib/Drupal/Component/Plugin/Discovery/DiscoveryTrait.php).

    I noticed the exported layout builder settings part having extra level of "section". Here is the patch fixing that issue. Then it worked with importing node with same layout builder settings.

  • Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle .

  • 🇷🇺Russia ilya.no

    Attaching patch for 9.5.x-dev version. Works locally. Tried to fix tests, but no luck so far. Interdiff may be not correct, since some test files were moved to hal module.

  • 🇧🇪Belgium flyke

    I can confirm that patch #196 also applies to 9.4.1

  • 🇮🇳India rassoni Bangalore

    Try to fix test failed issues.

  • 🇩🇪Germany Christian.wiedemann

    With the latest patch #199 enabled layout builder sections are not part of json output of entity_view_display jsonapi call.

    e.g:
    jsonapi/entity_view_display/entity_view_display/2edbf6ce-3960-4f54-86ac-0703774c9d8f

    The reason for this behavior is "Drupal\jsonapi\Normalizer\ResourceObjectNormalizer:196";

          // @todo Replace this workaround after https://www.drupal.org/node/3043245
          //   or remove the need for this in https://www.drupal.org/node/2942975.
          //   See \Drupal\layout_builder\Normalizer\LayoutEntityDisplayNormalizer.
          if ($context['resource_object']->getResourceType()->getDeserializationTargetClass() === 'Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay' && $context['resource_object']->getField('third_party_settings') === $field) {
            unset($field['layout_builder']['sections']);
          }
    

    I created a follow up issue to remove the unset.

    see: https://www.drupal.org/project/drupal/issues/3293908 📌 Expose Layout Builder Sections to entity view displays (jsonapi/entity_view_display/entity_view_display) Postponed: needs info

  • 🇺🇸United States tim.plunkett Philadelphia

    That was added in #3042198: Add JSON:API integration test for LayoutBuilderEntityViewDisplay (after this issue had begun). I don't know that it needs to be removed separately, could happen here

  • Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle .

  • 🇺🇸United States morbus iff

    Do the updated patches support the PATCH/POSTing of the layout builder layouts field? Back in #72/75: "When attempting to PATCH a layout_builder__layout field, I receive: "The current user is not allowed to PATCH the selected field (layout_builder__layout)." I receive the same error with POST, meaning I can't create a custom layout in a node (i.e., I can't create custom landing pages from JSON:API). That's my sole need - is this patch only for EXPOSING the data, or also for creating/updating that data?"

  • 🇯🇴Jordan yahyaalhamad Palestine

    The field only displays overridden layouts, it does not work with default layouts.

  • 🇵🇱Poland dmitry.korhov Poland, Warsaw

    The field only displays overridden layouts, it does not work with default layouts.

    There is a workaround for it, we managed it by triggering Enhancer (from JSONAPI Extras) manually in some event

  • 🇧🇪Belgium nielsaers

    For those creating a patch from https://git.drupalcode.org/issue/drupal-2942975/-/tree/2942975-reroll-9.4.x and using the the patch from https://www.drupal.org/project/drupal/issues/2946333 📌 Allow synced Layout override Translations: translating labels and inline blocks Needs work . There will be a conflict in applying it.

    The patch in 2946333 adds the following line to LayoutBuilderEntityViewDisplayResourceTestBase.php:

        $expected['hidden'][OverridesSectionStorage::TRANSLATED_CONFIGURATION_FIELD_NAME] = TRUE;
    

    Below:

        $expected['hidden'][OverridesSectionStorage::FIELD_NAME] = TRUE;
    
  • 🇮🇳India junaidpv Kannur, Kerala

    #196 used to work for me. But now I also need patch from #3293908-5: Expose Layout Builder Sections to entity view displays (jsonapi/entity_view_display/entity_view_display) to work the importing back the content with the layout builder overriden settings.

  • @s_leu opened merge request.
  • 🇦🇹Austria daniel.pernold

    Reroll for Drupal 9.4.8

  • 🇮🇳India _pratik_ Banglore

    Patch is applying now for me.

  • 🇮🇳India _utsavsharma

    Fixed CCF of #212.
    Please review.

  • 🇮🇳India arisen Goa

    Added missing files SectionDataNormalizer.php and SectionDataNormalizerTest.php to #213.
    Patch applying properly. Please review.

  • 🇮🇳India arisen Goa

    Fixed CCF of #215. Please review.

  • 🇫🇷France andypost

    Re-roll and clean-up for 10.1.x

  • 🇫🇷France andypost

    Fix return types

  • 🇫🇷France andypost

    and bit more

  • 🇵🇱Poland dmitry.korhov Poland, Warsaw

    `mixed` return type should not be used, we know what kind of entity|variable is returned.

  • 🇫🇷France andypost

    One more polishing round

  • 🇫🇷France andypost

    still not clear why serializer does not return tests for failed LB tests, but here copy-paste clean-up

  • Status changed to Needs work over 1 year ago
  • 🇺🇸United States morbus iff

    Has anyone gotten this to work with POSTING a new node, with a layout_builder__layout configuration? Every time I add my own layout_builder__layout configuration in the node/TYPE POST request, the node is submitted successfully, but the layout builder configuration is ignored entirely.

  • 🇮🇳India Aaron23

    Hi Team,

    This patch works for me 2942975-196.patch

    In addition to that I have used layout library module.

    When I create a node and selecting the layout library (chosen any of the template which is created from layout library). In the page api response I'm seeing an empty array,

    "layout_builder__layout": []

    Just simply once, I go to the layout of the node and save it.. I'm able to see the components

    Could anyone help here???

  • 🇨🇿Czech Republic kyberman Czech Rep. 🇨🇿

    Hi, if anybody simply needs to export the "layout_builder__layout" field serialized value using a REST view (e.g. for migration), I created a little formatter with a combination of hook_entity_field_access_alter. Any feedback is welcome, thanks!

    function YOUR_MODULE_entity_field_access_alter(array &$grants, array $context) {
      if ($context['field_definition']->getName() === 'layout_builder__layout'
        && $context['operation'] === 'view' && $grants[':default']->isForbidden()
      ) {
        $grants[':default'] = AccessResult::allowed()->inheritCacheability($grants[':default']);
      }
    }
    
    namespace Drupal\YOUR_MODULE\Plugin\Field\FieldFormatter;
    
    use Drupal\Core\Field\FieldItemListInterface;
    use Drupal\Core\Field\FormatterBase;
    use Drupal\Core\Render\Markup;
    
    /**
     * @FieldFormatter(
     *   id = "layout_builder_raw",
     *   label = @Translation("Layout Builder raw data"),
     *   description = @Translation("Display the Layout Builder raw data."),
     *   field_types = {
     *     "layout_section",
     *   }
     * )
     */
    class LayoutBuilderRawFormatter extends FormatterBase {
    
      public function viewElements(FieldItemListInterface $items, $langcode) {
        $elements = [];
        $entity = $items->getEntity();
    
        foreach ($items as $delta => $item) {
          $elements[$delta] = [
            '#markup' => Markup::create(serialize($item->section)),
            '#cache' => [
              'tags' => $entity->getCacheTags(),
            ],
          ];
        }
    
        return $elements;
      }
    
    }
    
  • Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened , as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle .

  • 🇫🇷France andypost

    After SF 6.3 upgrade it will need return types

  • 🇩🇪Germany mkalkbrenner 🇩🇪

    #230 doesn't apply for Drupal 10.1.1. Here's an adjusted version.

  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update over 1 year ago
    Patch Failed to Apply
  • I rerrolled the patch because it couldn't be applied to version 10.1. I couldn't generate the interdiff file because it throws the typical error with whitespaces that I haven't been able to solve.

  • I rerrolled the patch because it couldn't be applied to version 10.1. I couldn't generate the interdiff file because it throws the typical error with whitespaces that I haven't been able to solve.

  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.0 & MySQL 5.7
    last update over 1 year ago
    Custom Commands Failed
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update over 1 year ago
    Custom Commands Failed
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update over 1 year ago
    Patch Failed to Apply
  • 🇷🇺Russia sorlov

    reroll for latest 10.1.x

  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update over 1 year ago
    Patch Failed to Apply
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update over 1 year ago
    Patch Failed to Apply
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update over 1 year ago
    Custom Commands Failed
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update over 1 year ago
    29,931 pass, 10 fail
  • Status changed to Needs review over 1 year ago
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update over 1 year ago
    30,029 pass, 10 fail
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update over 1 year ago
    30,033 pass, 10 fail
  • Status changed to Needs work over 1 year ago
  • 🇺🇸United States smustgrave

    Seems there are a few test failures.

    Also see a schema change imagine that will need a post_update and tests.

  • 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10

    At present there's a security issue with this patch, if you're using it to POST/PATCH

    \Drupal\layout_builder\Plugin\Block\InlineBlock::getEntity calls unserialize on block_serialized

    If that value is provided by untrusted user input over an API, you could open the site up to a gadget chain attack.

    I also think that points to a larger issue with this patch in relation to JSON:API, and that's that we don't get relationship support for inline blocks.

    I've got some thoughts on that and will take some time to write that up in the next fortnight or so.

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    I lost this write-up not once, but twice, because my >5 year old iPad is not able to handle looking at 2 browser tabs if one of them is this one. Kind of understandable though: it's 158 KB of HTML 🫣

    I haven't reviewed this issue in ~5 years, but #247 shows that there are still security concerns (see the ones I raised 5 years ago at #33).

    👏 @larowlan for the detailed analysis over at https://www.previousnext.com.au/blog/pitchburgh-diaries-decoupled-layout... 👏

    I agree with his statements, assuming that it is a hard requirement to be able to truly access sections and components as related resources.

    I'm not convinced this is truly a hard requirement though. I do see the need for listing all available section plugins and all available components. Without that, it's impossible for the client to know the possible values. But I don't see the need to address/access section (plugin) instances and component (plugin) instances (meaning: as they are used in a specific entity) directly via JSON:API? 🤔

    If we'd drop that requirement:

    1. Why would it not be enough to model/expose/normalize Layout Builder sections and components used in a given entity like any other field? Because attributes (the JSON:API equivalent of "entity fields") ?
    2. If we did that, then I think we might be able to express references to other entities from within those components kind of like Dynamic Entity References? Why would that not be sufficient? /jsonapi/<node 4453>/relationships/layout + a meta on the relationship to express that this is a reference for that component?

    I bet I'm missing something though, because it's been years since I dug into JSON:API or Layout Builder details 😅 But it's a testament to your excellent write-up, that I was able to articulate this. Still an inkling of hope that this will help get this issue going… 🤞🤓

  • 🇫🇷France andypost

    I bet there's different purpose and requirement additionally to subject of the issue.

    Moreover this part already exists - 🐛 DiffArray does not serialize Layout builder section objects causing an error with view display configs managed by layout_builder Needs work

    (De)serialization is required for
    - configuration of entity displays with pre-configured sections #3151275: referencedEntities should return referenced layout builder added entities
    - entities for contrib Default_content Add a Normalizer and Denormalizer to support Layout Builder RTBC and similar to #2956221: Issue with Layout Builder and Serializer normalization

  • Status changed to Postponed about 1 year ago
  • 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10

    #248 I think that's worth exploring - hadn't considered using meta.

    In the meantime I opened 🐛 Harden the use of unserialize in InlineBlock via allowed classes Active which is a hard blocker for this.

  • 🇺🇸United States wmcmillian-coalmarch

    I've re-rolled this and added this to the SectionDataNormalizer:

    /**
       * {@inheritdoc}
       */
      protected $supportedInterfaceOrClass = SectionData::class;
    

    This was causing an issue when normalizing/denormalizing entities with other typed data attached to them.

  • 🇮🇳India adwivedi008

    Hii everyone

    I am using #239 for D-10.1.7 and along with this patch I am also using https://www.drupal.org/files/issues/2023-07-25/2946333-d10-307.patch

    The patch applies clearly but I am facing this error while clearing the cache

    PHP Fatal error: Class Drupal\layout_builder\Section contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (JsonSerializable::jsonSerialize) in /web/core/modules/layout_builder/src/Section.php on line 21

    Please suggest how to resolve this

  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7 updated deps
    last update about 1 year ago
    Patch Failed to Apply
  • 🇮🇳India adwivedi008

    Revised #239 for

    PHP Fatal error: Class Drupal\layout_builder\Section contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (JsonSerializable::jsonSerialize) in /web/core/modules/layout_builder/src/Section.php on line 21

    After comparing with #251

  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MariaDB 10.3.22
    last update about 1 year ago
    Custom Commands Failed
  • 🇧🇪Belgium flyke

    The most recent patch I found that applies to Drupal 10.2 is #237 at this moment.

  • 🇮🇳India adwivedi008

    Rerolled patch#237 as it was failing for D-10.1.7

  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update 11 months ago
    29,695 pass, 10 fail
  • First commit to issue fork.
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 5.3 & MySQL 5.5
    last update 11 months ago
    Composer error. Unable to continue.
  • last update 10 months ago
    29,695 pass, 10 fail
  • 🇺🇸United States kevinquillen

    Where does this issue stand? In my case I am only concerned with GET requests to feed headless instances. With the patch, I do get some layout data, for example:

    "layout_builder__layout": [
    {
    "layout_id": "layout_onecol",
    "layout_settings": {
    "label": "",
    "section_uuid": "4d50e824-c405-4f5d-bfe7-b96dc1e88b99"
    },
    "components": [
    {
    "uuid": "eadd557c-6414-40e5-9a95-355720385477",
    "region": "content",
    "configuration": {
    "id": "field_block:node:recipe:field_tags",
    "label_display": "0",
    "context_mapping": {
    "entity": "layout_builder.entity"
    },
    "formatter": {
    "type": "entity_reference_label",
    "label": "inline",
    "settings": {
    "link": true
    },
    "third_party_settings": []
    }
    },
    "weight": 3,
    "additional": []
    },

    But no inline block data, or relationships.

  • 🇺🇸United States kevinquillen

    With the patch from 255, and:

    I can get managed layout data, overridden entity layout data, and block data in layout builder over JSON:API. However, regions are not in order and neither are blocks, and I think that should be a part of this patch. The data should be stored or returned in the order it is saved. Otherwise this forces consumers to have to assemble it after the fact.

  • 🇺🇸United States kevinquillen

    Re-roll for 10.3.

  • 🇺🇸United States kevinquillen

    Re-rolled patch to include new files.

  • 🇧🇪Belgium flyke

    patches from #261 and #262 could not be applied to Drupal 10.3.0 when I tried it.

  • 🇧🇪Belgium flyke

    Attempted patch for 10.3.x

  • 🇺🇸United States kevinquillen

    Noticed that if you try to load and include layout builder data from a default managed layout, you will get an access denied exception with "The administer node display permission is required". This prevents exporting and attaching default layout data to a response for JSON:API - which you would need to have if the viewed node did not override / add a layout (you'd have to check the content type display and return that).

    The access check happens here in core/modules/jsonapi/src/Access/EntityAccessChecker.php:

      /**
       * Get the object to normalize and the access based on the provided entity.
       *
       * @param \Drupal\Core\Entity\EntityInterface $entity
       *   The entity to test access for.
       * @param \Drupal\Core\Session\AccountInterface $account
       *   (optional) The account with which access should be checked. Defaults to
       *   the current user.
       *
       * @return \Drupal\jsonapi\JsonApiResource\ResourceObject|\Drupal\jsonapi\JsonApiResource\LabelOnlyResourceObject|\Drupal\jsonapi\Exception\EntityAccessDeniedHttpException
       *   The ResourceObject, a LabelOnlyResourceObject or an
       *   EntityAccessDeniedHttpException object if neither is accessible. All
       *   three possible return values carry the access result cacheability.
       */
      public function getAccessCheckedResourceObject(EntityInterface $entity, ?AccountInterface $account = NULL) {
        $account = $account ?: $this->currentUser;
        $resource_type = $this->resourceTypeRepository->get($entity->getEntityTypeId(), $entity->bundle());
        $entity = $this->entityRepository->getTranslationFromContext($entity, NULL, ['operation' => 'entity_upcast']);
        $access = $this->checkEntityAccess($entity, 'view', $account);
        $entity->addCacheableDependency($access);
        if (!$access->isAllowed()) {
          // If this is the default revision or the entity is not revisionable, then
          // check access to the entity label. Revision support is all or nothing.
          if (!$entity->getEntityType()->isRevisionable() || $entity->isDefaultRevision()) {
            $label_access = $entity->access('view label', NULL, TRUE);
            $entity->addCacheableDependency($label_access);
            if ($label_access->isAllowed()) {
              return LabelOnlyResourceObject::createFromEntity($resource_type, $entity);
            }
            $access = $access->orIf($label_access);
          }
          return new EntityAccessDeniedHttpException($entity, $access, '/data', 'The current user is not allowed to GET the selected resource.');
        }
        return ResourceObject::createFromEntity($resource_type, $entity);
      }
    

    A default layout with block_content entities has a dependency on the entity view display to which it is attached, which will deny access if the current user does not have 'administer node display' permissions.

    For our local POC I worked around this for now by patching in this before EntityAccessDeniedHttpException is returned, ran out of time investigating last Friday:

          // Workaround for blocks in default managed layouts.
          // The 'administer node display' is required to view, but that breaks for
          // layout builder blocks.
          if ($entity->getEntityTypeId() == 'block_content' && $access->getReason() == "The 'administer node display' permission is required.") {
            return ResourceObject::createFromEntity($resource_type, $entity);
          }
    
  • 🇧🇪Belgium flyke

    Added issue #3049332 🐛 PHP message: Error: Call to a member function getEntityTypeId() on null (Layout Builder) Needs work as related because its impossible to use this patch and patch from that issue at the same time.

  • 🇮🇳India gaurav_manerkar Vasco Da Gama, Goa

    Missing `SectionDataNormalizer` class in #264 patch

  • 🇺🇦Ukraine artsays

    Looks like into the latest patch #264 for Drupal Core version 10.3.x
    Was missed in creating class two classes SectionDataNormalizer & SectionDataNormalizerTest the result Fatal errors

    PHP Fatal error: Uncaught Error: Class "Drupal\layout_builder\Normalizer\SectionDataNormalizer" not found in

    I've updated the patch 2942975-10.3.x.patch

  • 🇺🇸United States kevinquillen

    Note that for Drupal 11 compatibility, the following change has to be made in SectionDataNormalizer, as $supportedInterfaceOrClass has been removed:

      /**
       * {@inheritdoc}
       */
      public function getSupportedTypes(?string $format): array {
        return [
          SectionData::class => TRUE,
        ];
      }
    

    Otherwise, this patch will apply cleanly to Drupal 11 and works. I will try to re-roll this week when I get time.

  • 🇺🇸United States drupalninja99

    The content looks like it exports correctly but then I get this error on import:

    In SectionData.php line 35:
    
      [InvalidArgumentException]
      Value assigned to "section" is not a valid section
    

    I think the function is here in core/modules/layout_builder/src/Plugin/DataType/SectionData.php:

    public function setValue($value, $notify = TRUE) {
        if ($value && !$value instanceof Section) {
          throw new \InvalidArgumentException(sprintf('Value assigned to "%s" is not a valid section', $this->getName()));
        }
        parent::setValue($value, $notify);
      }
    

    $value is coming in as an array not instanceof Section

  • 🇺🇸United States drupalninja99

    Bleh sorry posted to the wrong issue ignore me

Production build 0.71.5 2024