Newer
Older
<?php
/**
* @file
* Provides hook implementations for Layout Builder.
*/
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Form\FormStateInterface;
Angie Byron
committed
use Drupal\Core\Plugin\Context\Context;
use Drupal\Core\Plugin\Context\ContextDefinition;
Angie Byron
committed
use Drupal\Core\Routing\RouteMatchInterface;
Angie Byron
committed
use Drupal\Core\StringTranslation\TranslatableMarkup;
Angie Byron
committed
use Drupal\Core\Url;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
/**
* Implements hook_help().
*/
Angie Byron
committed
function layout_builder_help($route_name, RouteMatchInterface $route_match) {
// Add help text to the Layout Builder UI.
if ($route_match->getRouteObject()->getOption('_layout_builder')) {
$output = '<p>' . t('This layout builder tool allows you to configure the layout of the main content area.') . '</p>';
if (\Drupal::currentUser()->hasPermission('administer blocks')) {
$output .= '<p>' . t('To manage other areas of the page, use the <a href="@block-ui">block administration page</a>.', ['@block-ui' => Url::fromRoute('block.admin_display')->toString()]) . '</p>';
}
else {
$output .= '<p>' . t('To manage other areas of the page, use the block administration page.') . '</p>';
}
return $output;
}
switch ($route_name) {
case 'help.page.layout_builder':
$output = '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('Layout Builder provides layout building utility.') . '</p>';
$output .= '<p>' . t('For more information, see the <a href=":layout-builder-documentation">online documentation for the Layout Builder module</a>.', [':layout-builder-documentation' => 'https://www.drupal.org/docs/8/core/modules/layout_builder']) . '</p>';
return $output;
}
}
/**
* Implements hook_entity_type_alter().
*/
function layout_builder_entity_type_alter(array &$entity_types) {
/** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
foreach ($entity_types as $entity_type) {
if ($entity_type->entityClassImplements(FieldableEntityInterface::class) && $entity_type->hasLinkTemplate('canonical') && $entity_type->hasViewBuilderClass()) {
$entity_type->setLinkTemplate('layout-builder', $entity_type->getLinkTemplate('canonical') . '/layout');
}
}
}
/**
* Removes the Layout Builder field both visually and from the #fields handling.
*
* This prevents any interaction with this field. It is rendered directly
* in layout_builder_entity_view_alter().
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
*
* @internal
*/
function _layout_builder_hide_layout_field(array &$form) {
unset($form['fields']['layout_builder__layout']);
$key = array_search('layout_builder__layout', $form['#fields']);
if ($key !== FALSE) {
unset($form['#fields'][$key]);
}
}
/**
* Implements hook_form_FORM_ID_alter() for \Drupal\field_ui\Form\EntityFormDisplayEditForm.
*/
function layout_builder_form_entity_form_display_edit_form_alter(&$form, FormStateInterface $form_state) {
_layout_builder_hide_layout_field($form);
}
/**
* Implements hook_form_FORM_ID_alter() for \Drupal\field_ui\Form\EntityViewDisplayEditForm.
*/
function layout_builder_form_entity_view_display_edit_form_alter(&$form, FormStateInterface $form_state) {
/** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display */
$display = $form_state->getFormObject()->getEntity();
$entity_type = \Drupal::entityTypeManager()->getDefinition($display->getTargetEntityTypeId());
_layout_builder_hide_layout_field($form);
// @todo Expand to work for all view modes in
// https://www.drupal.org/node/2907413.
if (!in_array($display->getMode(), ['full', 'default'], TRUE)) {
return;
}
$form['layout'] = [
'#type' => 'details',
'#open' => TRUE,
'#title' => t('Layout options'),
'#tree' => TRUE,
];
// @todo Unchecking this box is a destructive action, this should be made
// clear to the user in https://www.drupal.org/node/2914484.
$form['layout']['allow_custom'] = [
'#type' => 'checkbox',
'#title' => t('Allow each @entity to have its layout customized.', [
'@entity' => $entity_type->getSingularLabel(),
]),
'#default_value' => $display->getThirdPartySetting('layout_builder', 'allow_custom', FALSE),
];
$form['#entity_builders'][] = 'layout_builder_form_entity_view_display_edit_entity_builder';
}
/**
* Entity builder for layout options on the entity view display form.
*
* @see layout_builder_form_entity_view_display_edit_form_alter()
*/
function layout_builder_form_entity_view_display_edit_entity_builder($entity_type_id, EntityViewDisplayInterface $display, &$form, FormStateInterface &$form_state) {
$new_value = (bool) $form_state->getValue(['layout', 'allow_custom'], FALSE);
$display->setThirdPartySetting('layout_builder', 'allow_custom', $new_value);
}
/**
* Implements hook_ENTITY_TYPE_presave().
*/
function layout_builder_entity_view_display_presave(EntityViewDisplayInterface $display) {
$original_value = isset($display->original) ? $display->original->getThirdPartySetting('layout_builder', 'allow_custom', FALSE) : FALSE;
$new_value = $display->getThirdPartySetting('layout_builder', 'allow_custom', FALSE);
if ($original_value !== $new_value) {
$entity_type_id = $display->getTargetEntityTypeId();
$bundle = $display->getTargetBundle();
if ($new_value) {
layout_builder_add_layout_section_field($entity_type_id, $bundle);
}
elseif ($field = FieldConfig::loadByName($entity_type_id, $bundle, 'layout_builder__layout')) {
$field->delete();
}
}
}
/**
* Adds a layout section field to a given bundle.
*
* @param string $entity_type_id
* The entity type ID.
* @param string $bundle
* The bundle.
* @param string $field_name
* (optional) The name for the layout section field. Defaults to
* 'layout_builder__layout'.
*
* @return \Drupal\field\FieldConfigInterface
* A layout section field.
*/
function layout_builder_add_layout_section_field($entity_type_id, $bundle, $field_name = 'layout_builder__layout') {
$field = FieldConfig::loadByName($entity_type_id, $bundle, $field_name);
if (!$field) {
$field_storage = FieldStorageConfig::loadByName($entity_type_id, $field_name);
if (!$field_storage) {
$field_storage = FieldStorageConfig::create([
'entity_type' => $entity_type_id,
'field_name' => $field_name,
'type' => 'layout_section',
]);
$field_storage->save();
}
$field = FieldConfig::create([
'field_storage' => $field_storage,
'bundle' => $bundle,
'label' => t('Layout'),
]);
$field->save();
}
return $field;
}
/**
* Implements hook_entity_view_alter().
*/
function layout_builder_entity_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) {
if ($display->getThirdPartySetting('layout_builder', 'allow_custom', FALSE) && !$entity->layout_builder__layout->isEmpty()) {
Angie Byron
committed
$contexts = \Drupal::service('context.repository')->getAvailableContexts();
// @todo Use EntityContextDefinition after resolving
// https://www.drupal.org/node/2932462.
$contexts['layout_builder.entity'] = new Context(new ContextDefinition("entity:{$entity->getEntityTypeId()}", new TranslatableMarkup('@entity being viewed', ['@entity' => $entity->getEntityType()->getLabel()])), $entity);
$sections = $entity->layout_builder__layout->getSections();
foreach ($sections as $delta => $section) {
Angie Byron
committed
$build['_layout_builder'][$delta] = $section->toRenderArray($contexts);
}
// If field layout is active, that is all that needs to be removed.
if (\Drupal::moduleHandler()->moduleExists('field_layout') && isset($build['_field_layout'])) {
unset($build['_field_layout']);
return;
}
/** @var \Drupal\Core\Field\FieldDefinitionInterface[] $field_definitions */
$field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions($display->getTargetEntityTypeId(), $display->getTargetBundle());
// Remove all display-configurable fields.
foreach (array_keys($display->getComponents()) as $name) {
if ($name !== 'layout_builder__layout' && isset($field_definitions[$name]) && $field_definitions[$name]->isDisplayConfigurable('view')) {
unset($build[$name]);
}
}
}
}