5 * Provides hook implementations for Layout Builder.
8 use Drupal\Core\Entity\EntityInterface;
9 use Drupal\Core\Form\FormStateInterface;
10 use Drupal\Core\Routing\RouteMatchInterface;
12 use Drupal\field\FieldConfigInterface;
13 use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
14 use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplayStorage;
15 use Drupal\layout_builder\Form\LayoutBuilderEntityViewDisplayForm;
16 use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
17 use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface;
18 use Drupal\layout_builder\Plugin\Block\ExtraFieldBlock;
19 use Drupal\layout_builder\InlineBlockEntityOperations;
20 use Drupal\Core\Session\AccountInterface;
21 use Drupal\Core\Access\AccessResult;
24 * Implements hook_help().
26 function layout_builder_help($route_name, RouteMatchInterface $route_match) {
27 // Add help text to the Layout Builder UI.
28 if ($route_match->getRouteObject()->getOption('_layout_builder')) {
29 $output = '<p>' . t('This layout builder tool allows you to configure the layout of the main content area.') . '</p>';
30 if (\Drupal::currentUser()->hasPermission('administer blocks')) {
31 $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>';
34 $output .= '<p>' . t('To manage other areas of the page, use the block administration page.') . '</p>';
39 switch ($route_name) {
40 case 'help.page.layout_builder':
41 $output = '<h3>' . t('About') . '</h3>';
42 $output .= '<p>' . t('Layout Builder provides layout building utility.') . '</p>';
43 $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>';
49 * Implements hook_entity_type_alter().
51 function layout_builder_entity_type_alter(array &$entity_types) {
52 /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
53 $entity_types['entity_view_display']
54 ->setClass(LayoutBuilderEntityViewDisplay::class)
55 ->setStorageClass(LayoutBuilderEntityViewDisplayStorage::class)
56 ->setFormClass('edit', LayoutBuilderEntityViewDisplayForm::class);
60 * Implements hook_form_FORM_ID_alter() for \Drupal\field_ui\Form\EntityFormDisplayEditForm.
62 function layout_builder_form_entity_form_display_edit_form_alter(&$form, FormStateInterface $form_state) {
63 // Hides the Layout Builder field. It is rendered directly in
64 // \Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay::buildMultiple().
65 unset($form['fields']['layout_builder__layout']);
66 $key = array_search('layout_builder__layout', $form['#fields']);
68 unset($form['#fields'][$key]);
73 * Implements hook_field_config_insert().
75 function layout_builder_field_config_insert(FieldConfigInterface $field_config) {
76 // Clear the sample entity for this entity type and bundle.
77 $sample_entity_generator = \Drupal::service('layout_builder.sample_entity_generator');
78 $sample_entity_generator->delete($field_config->getTargetEntityTypeId(), $field_config->getTargetBundle());
79 \Drupal::service('plugin.manager.block')->clearCachedDefinitions();
83 * Implements hook_field_config_delete().
85 function layout_builder_field_config_delete(FieldConfigInterface $field_config) {
86 // Clear the sample entity for this entity type and bundle.
87 $sample_entity_generator = \Drupal::service('layout_builder.sample_entity_generator');
88 $sample_entity_generator->delete($field_config->getTargetEntityTypeId(), $field_config->getTargetBundle());
89 \Drupal::service('plugin.manager.block')->clearCachedDefinitions();
93 * Implements hook_entity_view_alter().
95 * ExtraFieldBlock block plugins add placeholders for each extra field which is
96 * configured to be displayed. Those placeholders are replaced by this hook.
97 * Modules that implement hook_entity_extra_field_info() use their
98 * implementations of hook_entity_view_alter() to add the rendered output of
99 * the extra fields they provide, so we cannot get the rendered output of extra
100 * fields before this point in the view process.
101 * layout_builder_module_implements_alter() moves this implementation of
102 * hook_entity_view_alter() to the end of the list.
104 * @see \Drupal\layout_builder\Plugin\Block\ExtraFieldBlock::build()
105 * @see layout_builder_module_implements_alter()
107 function layout_builder_entity_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) {
108 if ($display instanceof LayoutEntityDisplayInterface) {
109 /** @var \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager */
110 $field_manager = \Drupal::service('entity_field.manager');
111 $extra_fields = $field_manager->getExtraFields($entity->getEntityTypeId(), $entity->bundle());
112 if (!empty($extra_fields['display'])) {
113 foreach ($extra_fields['display'] as $field_name => $extra_field) {
114 // If the extra field is not set replace with an empty array to avoid
115 // the placeholder text from being rendered.
116 $replacement = isset($build[$field_name]) ? $build[$field_name] : [];
117 ExtraFieldBlock::replaceFieldPlaceholder($build, $replacement, $field_name);
118 // After the rendered field in $build has been copied over to the
119 // ExtraFieldBlock block we must remove it from its original location or
120 // else it will be rendered twice.
121 unset($build[$field_name]);
128 * Implements hook_builder_module_implements_alter().
130 function layout_builder_module_implements_alter(&$implementations, $hook) {
131 if ($hook === 'entity_view_alter') {
132 // Ensure that this module's implementation of hook_entity_view_alter() runs
133 // last so that other modules that use this hook to render extra fields will
135 $group = $implementations['layout_builder'];
136 unset($implementations['layout_builder']);
137 $implementations['layout_builder'] = $group;
142 * Implements hook_entity_presave().
144 function layout_builder_entity_presave(EntityInterface $entity) {
145 if (\Drupal::moduleHandler()->moduleExists('block_content')) {
146 /** @var \Drupal\layout_builder\InlineBlockEntityOperations $entity_operations */
147 $entity_operations = \Drupal::classResolver(InlineBlockEntityOperations::class);
148 $entity_operations->handlePreSave($entity);
153 * Implements hook_entity_delete().
155 function layout_builder_entity_delete(EntityInterface $entity) {
156 if (\Drupal::moduleHandler()->moduleExists('block_content')) {
157 /** @var \Drupal\layout_builder\InlineBlockEntityOperations $entity_operations */
158 $entity_operations = \Drupal::classResolver(InlineBlockEntityOperations::class);
159 $entity_operations->handleEntityDelete($entity);
164 * Implements hook_cron().
166 function layout_builder_cron() {
167 if (\Drupal::moduleHandler()->moduleExists('block_content')) {
168 /** @var \Drupal\layout_builder\InlineBlockEntityOperations $entity_operations */
169 $entity_operations = \Drupal::classResolver(InlineBlockEntityOperations::class);
170 $entity_operations->removeUnused();
175 * Implements hook_plugin_filter_TYPE_alter().
177 function layout_builder_plugin_filter_block_alter(array &$definitions, array $extra, $consumer) {
178 // @todo Determine the 'inline_block' blocks should be allowed outside
179 // of layout_builder https://www.drupal.org/node/2979142.
180 if ($consumer !== 'layout_builder') {
181 foreach ($definitions as $id => $definition) {
182 if ($definition['id'] === 'inline_block') {
183 unset($definitions[$id]);
190 * Implements hook_ENTITY_TYPE_access().
192 function layout_builder_block_content_access(EntityInterface $entity, $operation, AccountInterface $account) {
193 /** @var \Drupal\block_content\BlockContentInterface $entity */
194 if ($operation === 'view' || $entity->isReusable() || empty(\Drupal::service('inline_block.usage')->getUsage($entity->id()))) {
195 // If the operation is 'view' or this is reusable block or if this is
196 // non-reusable that isn't used by this module then don't alter the access.
197 return AccessResult::neutral();
200 if ($account->hasPermission('configure any layout')) {
201 return AccessResult::allowed();
203 return AccessResult::forbidden();