Problem/Motivation
Panelizer (at least in D7) allowed you to override a view mode for an entity and add relationships to pull in fields from additional entities (an obvious example being a User view which pulls in data from a profile attached to the user). Panelizer appears to be winding down now so much of what it did is in core, but this relationship aspect is not currently supported by core and is not easily possible in contrib either without swapping out large parts of core.
Proposed resolution
Make it possible for contrib to provide additional context for the layout builder. There are probably a few ways to do this, but the two obvious options to me seem to be one of:
- An event that can be subscribed to: Pro - OO with subscribers able to inject services and possibly better 'applies' logic
- A hook that modules can implement: Pro - quick and easy to implement!
The places I have identified which would need to invoke whatever process are:
\Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay::buildMultipleafter adding thelayout_builder.entitycontext: Implementers would need to provide real (potentially empty) context.\Drupal\layout_builder\Plugin\SectionStorage\DefaultsSectionStorage::getContexts: Implementors would need to provide sample context.\Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage::getContexts: Implementors would need to provide real or sample context.
Remaining tasks
- Decide what mechanism we want to use (events, hooks or other).
- Trigger implementations in the identified locations.
- Make sure there aren't other places that also need to trigger implementations.
- Test coverage!
User interface changes
None - it would be down to contrib to implement any UI to configure relationships, or to provide them programatically.
API changes
Addition of a mechanism to add additional context.
Data model changes
None - it would be down to contrib to deal with any additional storage requirements.
| Comment | File | Size | Author |
|---|
Issue fork drupal-3001188
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
yanniboi commentedPatch attached.
I have created a hook implementation like the following:
Comment #4
tim.plunkettNice approach!
Can you add the snippet in #2 to layout_builder.api.php?
Comment #5
rlmumfordUpdated this to be inline with 8.7.0 layout builder. I've also added the documentation to layout_builder.api.php.
I've decided to pass the SectionStorage to the hook so that implementations can access SectionStorage third party settings when generating or altering context. This would allow a module to provide configurable context relationships, similar to panelizer in drupal 7. Passing the section storage (rather than relying on the 'display' context in the array) allows hook implementers to be agnostic to which SectionStorage plugin is being used - provided it implements the third party settings interface. For example something like:
Comment #6
rlmumfordComment #7
rlmumfordAdding a patch that works for composer-patches.
Comment #8
bnjmnmMade a change to address an issue that surfaced in #2916876: Add visibility control conditions to blocks within Layout Builder -- in
Drupal\layout_builder\SectionComponent::toRenderArray()there's a call tonew SectionComponentBuildRenderArrayEventwhich is now in a try/catch block as it may result in an acceptable ContextException that simply means the block should not be rendered.Interdiffing from #5 as #7 cannot be applied. The changes there shouldn't be necessary for use with composer-patches (or else we'd be seeing composer-patches versions of patches all over the issue queue).
If a site's composer configuration requires an altered version of a patch to support composer-patches, it's best to include that patch in your repo and apply it locally - info on how to do this here. This eliminates the need to post a public patch intended for non-standard use cases.
Comment #9
jhedstromThis is looking good, just a few comments here:
Nit: This description needs to be less than 80 characters.
Would this hook ever be called without this context?
We probably can't alter the
__constructparameters at this point, but it would be good to at least set this as a class property in the constructer so that in the future the service can be injected. This is currently out the entity field manager service is set:Comment #10
sam152 commentedDoes this feature already exist to some degree by implementing a 'context_provider' tagged service?
Comment #12
hctomI'm not sure, if I missed something, but I applied the patch from #8 against 8.7.10 and added a
hook_layout_builder_view_context_alter()implementation like this:With this it is possible to add field blocks of media entities referenced via
field_media_mainfield. But unfortunately, when opening a node that uses this layout for animageparagraph, it breaks with a fatal saying:Assigned contexts were not satisfied: entity in Drupal\Core\Plugin\Context\ContextHandler->applyContextMapping().So do I have to add some more custom code to get this working or is there still a problem with the context handling for field blocks?
I'd appreciate your feedback & thanx in advance!
Comment #13
larowlanSee also #3099968: Layout builder incorrectly resolves global contexts values when viewing layouts
Comment #14
jparkinson1991 commentedPatch #4 is working for me.
I noticed similar issues to @hctom and it turns out it was down to the entity context existing under different keys than documented.
When on the layout builder edit pages
$contexts['layout_builder.entity']exists as expected. When viewing the actual content that uses the layout the entity context exists under$contexts['entity']Can anyone explain this difference in keys, i have been digging around the modules and so far struggling to work out what is going on?
@htcom, to fix your issues try the following
Thanks
Comment #15
jparkinson1991 commentedJust a quick note to say, i have created a patch to add more granular field block categorisation, very useful when using this patch to add in entity relationships to context.
#3111973: Use granular entity type bundle driven field block categories when choosing blocks
Comment #16
tim.plunkettNW for tests
Comment #19
johnwebdev commentedAnother idea would be to add an additional optional argument to ContextRepositoryInterface::getRuntimeContexts, not entirely sure if i think that would be good or not
Comment #21
t-loRe-rolling for 9.1x+
Comment #22
dhirendra.mishra commentedManually re-rolled it for 9.3.x
Comment #24
dqdIs NW referring to tests (#16) ?
Or are we still thinking about the proper solution (#19) ?
Would LOVE to see this getting in. Awesome work in here! +1
Comment #25
bnjmnm#24
The suggestion in #19 doesn't seem to be based on any major concerns with the current implementation, it's an interesting suggestion I'm glad is documented, but I don't think there's a need to pursue it unless it provides obvious benefits over the current one.
The issue definitely needs tests before it can land. Adding those will get this issue to a point where someone can RTBC it.
Comment #27
andypost@bnjmnm please change target branch to 9.4.x as MR outdated a bit
Definitely new hook needs test, btw maybe instead of hook it could use event?
The module handler needs to be injected properly - maybe section storage manager can care to invoke hook/event
PS: unpublished patches as the issue using MR
Comment #31
liquidcms commentedI feel like this is close to solving my issue.
I have a block inside a block placed on a node layout. I need the inner block to control visibility based on the value of a node field. I have the block visibility patch (#2916876: Add visibility control conditions to blocks within Layout Builder) and the patch from here. When i add this hook code:
This gives me the ability to add a field condition based off my node bundle when setting visibility of the inner block. But I don't see where, when it comes time to display the actual node, that the block has the context of the specific node it is on. And sure enough, on display, i get this error:
Error: Call to a member function getValue() on null in Drupal\entity_field_condition\Plugin\Condition\FieldValue->evaluate() (line 415 of modules\contrib\entity_field_condition\src\Plugin\Condition\FieldValue.php).which makes sense as I would need to specify somewhere, the context from the actual node taken from route. What am i missing or is this not possible with the work being done here?