Mercurial > hg > cmmr2012-drupal-site
comparison core/modules/layout_builder/layout_builder.module @ 5:12f9dff5fda9 tip
Update to Drupal core 8.7.1
author | Chris Cannam |
---|---|
date | Thu, 09 May 2019 15:34:47 +0100 |
parents | a9cd425dd02b |
children |
comparison
equal
deleted
inserted
replaced
4:a9cd425dd02b | 5:12f9dff5fda9 |
---|---|
3 /** | 3 /** |
4 * @file | 4 * @file |
5 * Provides hook implementations for Layout Builder. | 5 * Provides hook implementations for Layout Builder. |
6 */ | 6 */ |
7 | 7 |
8 use Drupal\Core\Breadcrumb\Breadcrumb; | |
9 use Drupal\Core\Cache\CacheableMetadata; | |
8 use Drupal\Core\Entity\EntityInterface; | 10 use Drupal\Core\Entity\EntityInterface; |
11 use Drupal\Core\Entity\FieldableEntityInterface; | |
9 use Drupal\Core\Form\FormStateInterface; | 12 use Drupal\Core\Form\FormStateInterface; |
13 use Drupal\Core\Link; | |
10 use Drupal\Core\Render\Element; | 14 use Drupal\Core\Render\Element; |
11 use Drupal\Core\Routing\RouteMatchInterface; | 15 use Drupal\Core\Routing\RouteMatchInterface; |
12 use Drupal\Core\Url; | 16 use Drupal\Core\Url; |
13 use Drupal\field\FieldConfigInterface; | 17 use Drupal\field\FieldConfigInterface; |
14 use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay; | 18 use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay; |
15 use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplayStorage; | 19 use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplayStorage; |
20 use Drupal\layout_builder\Form\DefaultsEntityForm; | |
16 use Drupal\layout_builder\Form\LayoutBuilderEntityViewDisplayForm; | 21 use Drupal\layout_builder\Form\LayoutBuilderEntityViewDisplayForm; |
22 use Drupal\layout_builder\Form\OverridesEntityForm; | |
17 use Drupal\Core\Entity\Display\EntityViewDisplayInterface; | 23 use Drupal\Core\Entity\Display\EntityViewDisplayInterface; |
18 use Drupal\layout_builder\Plugin\Block\ExtraFieldBlock; | 24 use Drupal\layout_builder\Plugin\Block\ExtraFieldBlock; |
19 use Drupal\layout_builder\InlineBlockEntityOperations; | 25 use Drupal\layout_builder\InlineBlockEntityOperations; |
20 use Drupal\Core\Session\AccountInterface; | 26 use Drupal\Core\Session\AccountInterface; |
21 use Drupal\Core\Access\AccessResult; | 27 use Drupal\Core\Access\AccessResult; |
22 use Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage; | 28 use Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage; |
29 use Drupal\layout_builder\QuickEditIntegration; | |
23 | 30 |
24 /** | 31 /** |
25 * Implements hook_help(). | 32 * Implements hook_help(). |
26 */ | 33 */ |
27 function layout_builder_help($route_name, RouteMatchInterface $route_match) { | 34 function layout_builder_help($route_name, RouteMatchInterface $route_match) { |
32 $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>'; | 39 $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>'; |
33 } | 40 } |
34 else { | 41 else { |
35 $output .= '<p>' . t('To manage other areas of the page, use the block administration page.') . '</p>'; | 42 $output .= '<p>' . t('To manage other areas of the page, use the block administration page.') . '</p>'; |
36 } | 43 } |
44 $output .= '<p>' . t('Forms and links inside the content of the layout builder tool have been disabled.') . '</p>'; | |
37 return $output; | 45 return $output; |
38 } | 46 } |
39 | 47 |
40 switch ($route_name) { | 48 switch ($route_name) { |
41 case 'help.page.layout_builder': | 49 case 'help.page.layout_builder': |
42 $output = '<h3>' . t('About') . '</h3>'; | 50 $output = '<h3>' . t('About') . '</h3>'; |
43 $output .= '<p>' . t('Layout Builder provides layout building utility.') . '</p>'; | 51 $output .= '<p>' . t('Layout Builder allows you to use layouts to customize how content, custom blocks, and other <a href=":field_help" title="Field module help, with background on content entities">content entities</a> are displayed.', [':field_help' => Url::fromRoute('help.page', ['name' => 'field'])->toString()]) . '</p>'; |
44 $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>'; | 52 $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>'; |
53 $output .= '<h3>' . t('Uses') . '</h3>'; | |
54 $output .= '<dl>'; | |
55 $output .= '<dt>' . t('Default layouts') . '</dt>'; | |
56 $output .= '<dd>' . t('Layout Builder can be selectively enabled on the "Manage Display" page in the <a href=":field_ui">Field UI</a>. This allows you to control the output of each type of display individually. For example, a "Basic page" might have view modes such as Full and Teaser, with each view mode having different layouts selected.', [':field_ui' => Url::fromRoute('help.page', ['name' => 'field_ui'])->toString()]) . '</dd>'; | |
57 $output .= '<dt>' . t('Overridden layouts') . '</dt>'; | |
58 $output .= '<dd>' . t('If enabled, each individual content item can have a custom layout. Once the layout for an individual content item is overridden, changes to the Default layout will no longer affect it. Overridden layouts may be reverted to return to matching and being synchronized to their Default layout.') . '</dd>'; | |
59 $output .= '<dt>' . t('User permissions') . '</dt>'; | |
60 $output .= '<dd>' . t('The Layout Builder module makes a number of permissions available, which can be set by role on the <a href=":permissions">permissions page</a>. For more information, see the <a href=":layout-builder-permissions">Configuring Layout Builder permissions</a> online documentation.', [ | |
61 ':permissions' => Url::fromRoute('user.admin_permissions', [], ['fragment' => 'module-layout_builder'])->toString(), | |
62 ':layout-builder-permissions' => 'https://www.drupal.org/docs/8/core/modules/layout-builder/configuring-layout-builder-permissions', | |
63 ]) . '</dd>'; | |
64 $output .= '</dl>'; | |
45 return $output; | 65 return $output; |
46 } | 66 } |
47 } | 67 } |
48 | 68 |
49 /** | 69 /** |
52 function layout_builder_entity_type_alter(array &$entity_types) { | 72 function layout_builder_entity_type_alter(array &$entity_types) { |
53 /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */ | 73 /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */ |
54 $entity_types['entity_view_display'] | 74 $entity_types['entity_view_display'] |
55 ->setClass(LayoutBuilderEntityViewDisplay::class) | 75 ->setClass(LayoutBuilderEntityViewDisplay::class) |
56 ->setStorageClass(LayoutBuilderEntityViewDisplayStorage::class) | 76 ->setStorageClass(LayoutBuilderEntityViewDisplayStorage::class) |
77 ->setFormClass('layout_builder', DefaultsEntityForm::class) | |
57 ->setFormClass('edit', LayoutBuilderEntityViewDisplayForm::class); | 78 ->setFormClass('edit', LayoutBuilderEntityViewDisplayForm::class); |
79 | |
80 // Ensure every fieldable entity type has a layout form. | |
81 foreach ($entity_types as $entity_type) { | |
82 if ($entity_type->entityClassImplements(FieldableEntityInterface::class)) { | |
83 $entity_type->setFormClass('layout_builder', OverridesEntityForm::class); | |
84 } | |
85 } | |
58 } | 86 } |
59 | 87 |
60 /** | 88 /** |
61 * Implements hook_form_FORM_ID_alter() for \Drupal\field_ui\Form\EntityFormDisplayEditForm. | 89 * Implements hook_form_FORM_ID_alter() for \Drupal\field_ui\Form\EntityFormDisplayEditForm. |
62 */ | 90 */ |
123 // else it will be rendered twice. | 151 // else it will be rendered twice. |
124 unset($build[$field_name]); | 152 unset($build[$field_name]); |
125 } | 153 } |
126 } | 154 } |
127 } | 155 } |
156 | |
157 $route_name = \Drupal::routeMatch()->getRouteName(); | |
158 | |
159 // If the entity is displayed within a Layout Builder block and the current | |
160 // route is in the Layout Builder UI, then remove all contextual link | |
161 // placeholders. | |
162 if ($display instanceof LayoutBuilderEntityViewDisplay && strpos($route_name, 'layout_builder.') === 0) { | |
163 unset($build['#contextual_links']); | |
164 } | |
165 | |
166 if (\Drupal::moduleHandler()->moduleExists('quickedit')) { | |
167 /** @var \Drupal\layout_builder\QuickEditIntegration $quick_edit_integration */ | |
168 $quick_edit_integration = \Drupal::classResolver(QuickEditIntegration::class); | |
169 $quick_edit_integration->entityViewAlter($build, $entity, $display); | |
170 } | |
171 } | |
172 | |
173 /** | |
174 * Implements hook_entity_build_defaults_alter(). | |
175 */ | |
176 function layout_builder_entity_build_defaults_alter(array &$build, EntityInterface $entity, $view_mode) { | |
177 // Contextual links are removed for entities viewed in Layout Builder's UI. | |
178 // The route.name.is_layout_builder_ui cache context accounts for this | |
179 // difference. | |
180 // @see layout_builder_entity_view_alter() | |
181 // @see \Drupal\layout_builder\Cache\LayoutBuilderUiCacheContext | |
182 $build['#cache']['contexts'][] = 'route.name.is_layout_builder_ui'; | |
128 } | 183 } |
129 | 184 |
130 /** | 185 /** |
131 * Implements hook_builder_module_implements_alter(). | 186 * Implements hook_builder_module_implements_alter(). |
132 */ | 187 */ |
173 $entity_operations->removeUnused(); | 228 $entity_operations->removeUnused(); |
174 } | 229 } |
175 } | 230 } |
176 | 231 |
177 /** | 232 /** |
233 * Implements hook_plugin_filter_TYPE__CONSUMER_alter(). | |
234 */ | |
235 function layout_builder_plugin_filter_block__layout_builder_alter(array &$definitions, array $extra) { | |
236 // @todo Restore the page title block in https://www.drupal.org/node/2938129. | |
237 unset($definitions['page_title_block']); | |
238 } | |
239 | |
240 /** | |
178 * Implements hook_plugin_filter_TYPE_alter(). | 241 * Implements hook_plugin_filter_TYPE_alter(). |
179 */ | 242 */ |
180 function layout_builder_plugin_filter_block_alter(array &$definitions, array $extra, $consumer) { | 243 function layout_builder_plugin_filter_block_alter(array &$definitions, array $extra, $consumer) { |
181 // @todo Determine the 'inline_block' blocks should be allowed outside | 244 // @todo Determine the 'inline_block' blocks should be allowed outside |
182 // of layout_builder https://www.drupal.org/node/2979142. | 245 // of layout_builder https://www.drupal.org/node/2979142. |
198 // If the operation is 'view' or this is reusable block or if this is | 261 // If the operation is 'view' or this is reusable block or if this is |
199 // non-reusable that isn't used by this module then don't alter the access. | 262 // non-reusable that isn't used by this module then don't alter the access. |
200 return AccessResult::neutral(); | 263 return AccessResult::neutral(); |
201 } | 264 } |
202 | 265 |
203 if ($account->hasPermission('configure any layout')) { | 266 if ($account->hasPermission('create and edit custom blocks')) { |
204 return AccessResult::allowed(); | 267 return AccessResult::allowed(); |
205 } | 268 } |
206 return AccessResult::forbidden(); | 269 return AccessResult::forbidden(); |
207 } | 270 } |
208 | 271 |
209 /** | 272 /** |
210 * Implements hook_plugin_filter_TYPE__CONSUMER_alter(). | 273 * Implements hook_plugin_filter_TYPE__CONSUMER_alter(). |
211 */ | 274 */ |
212 function layout_builder_plugin_filter_block__block_ui_alter(array &$definitions, array $extra) { | 275 function layout_builder_plugin_filter_block__block_ui_alter(array &$definitions, array $extra) { |
213 foreach ($definitions as $id => $definition) { | 276 foreach ($definitions as $id => $definition) { |
214 // Filter out any layout_builder definition with required contexts. | 277 // Filter out any layout_builder-provided block that has required context |
215 if ($definition['provider'] === 'layout_builder' && !empty($definition['context'])) { | 278 // definitions. |
216 /** @var \Drupal\Core\Plugin\Context\ContextDefinitionInterface $context */ | 279 if ($definition['provider'] === 'layout_builder' && !empty($definition['context_definitions'])) { |
217 foreach ($definition['context'] as $context) { | 280 /** @var \Drupal\Core\Plugin\Context\ContextDefinitionInterface $context_definition */ |
218 if ($context->isRequired()) { | 281 foreach ($definition['context_definitions'] as $context_definition) { |
282 if ($context_definition->isRequired()) { | |
219 unset($definitions[$id]); | 283 unset($definitions[$id]); |
220 break; | 284 break; |
221 } | 285 } |
222 } | 286 } |
223 } | 287 } |
224 } | 288 } |
225 } | 289 } |
290 | |
291 /** | |
292 * Implements hook_plugin_filter_TYPE__CONSUMER_alter(). | |
293 */ | |
294 function layout_builder_plugin_filter_layout__layout_builder_alter(array &$definitions, array $extra) { | |
295 // Remove layouts provide by layout discovery that are not needed because of | |
296 // layouts provided by this module. | |
297 $duplicate_layouts = [ | |
298 'layout_twocol', | |
299 'layout_twocol_bricks', | |
300 'layout_threecol_25_50_25', | |
301 'layout_threecol_33_34_33', | |
302 ]; | |
303 | |
304 foreach ($duplicate_layouts as $duplicate_layout) { | |
305 /** @var \Drupal\Core\Layout\LayoutDefinition[] $definitions */ | |
306 if (isset($definitions[$duplicate_layout])) { | |
307 if ($definitions[$duplicate_layout]->getProvider() === 'layout_discovery') { | |
308 unset($definitions[$duplicate_layout]); | |
309 } | |
310 } | |
311 } | |
312 | |
313 // Move the one column layout to the top. | |
314 if (isset($definitions['layout_onecol']) && $definitions['layout_onecol']->getProvider() === 'layout_discovery') { | |
315 $one_col = $definitions['layout_onecol']; | |
316 unset($definitions['layout_onecol']); | |
317 $definitions = [ | |
318 'layout_onecol' => $one_col, | |
319 ] + $definitions; | |
320 } | |
321 } | |
322 | |
323 /** | |
324 * Implements hook_plugin_filter_TYPE_alter(). | |
325 */ | |
326 function layout_builder_plugin_filter_layout_alter(array &$definitions, array $extra, $consumer) { | |
327 // Hide the blank layout plugin from listings. | |
328 unset($definitions['layout_builder_blank']); | |
329 } | |
330 | |
331 /** | |
332 * Implements hook_system_breadcrumb_alter(). | |
333 */ | |
334 function layout_builder_system_breadcrumb_alter(Breadcrumb &$breadcrumb, RouteMatchInterface $route_match, array $context) { | |
335 // Remove the extra 'Manage display' breadcrumb for Layout Builder defaults. | |
336 if ($route_match->getRouteObject()->hasOption('_layout_builder') && $route_match->getParameter('section_storage_type') === 'defaults') { | |
337 $links = array_filter($breadcrumb->getLinks(), function (Link $link) use ($route_match) { | |
338 $entity_type_id = $route_match->getParameter('entity_type_id'); | |
339 return $link->getUrl()->getRouteName() !== "entity.entity_view_display.$entity_type_id.default"; | |
340 }); | |
341 // Links cannot be removed from an existing breadcrumb object. Create a new | |
342 // object but carry over the cacheable metadata. | |
343 $cacheability = CacheableMetadata::createFromObject($breadcrumb); | |
344 $breadcrumb = new Breadcrumb(); | |
345 $breadcrumb->setLinks($links); | |
346 $breadcrumb->addCacheableDependency($cacheability); | |
347 } | |
348 } | |
349 | |
350 /** | |
351 * Implements hook_quickedit_render_field(). | |
352 */ | |
353 function layout_builder_quickedit_render_field(EntityInterface $entity, $field_name, $view_mode_id, $langcode) { | |
354 /** @var \Drupal\layout_builder\QuickEditIntegration $quick_edit_integration */ | |
355 $quick_edit_integration = \Drupal::classResolver(QuickEditIntegration::class); | |
356 return $quick_edit_integration->quickEditRenderField($entity, $field_name, $view_mode_id, $langcode); | |
357 } | |
358 | |
359 /** | |
360 * Implements hook_entity_translation_create(). | |
361 */ | |
362 function layout_builder_entity_translation_create(EntityInterface $translation) { | |
363 /** @var \Drupal\Core\Entity\FieldableEntityInterface $translation */ | |
364 if ($translation->hasField(OverridesSectionStorage::FIELD_NAME) && $translation->getFieldDefinition(OverridesSectionStorage::FIELD_NAME)->isTranslatable()) { | |
365 // When creating a new translation do not copy untranslated sections because | |
366 // per-language layouts are not supported. | |
367 $translation->set(OverridesSectionStorage::FIELD_NAME, []); | |
368 } | |
369 } | |
370 | |
371 /** | |
372 * Implements hook_theme_registry_alter(). | |
373 */ | |
374 function layout_builder_theme_registry_alter(&$theme_registry) { | |
375 // Move our preprocess to run after | |
376 // content_translation_preprocess_language_content_settings_table(). | |
377 if (!empty($theme_registry['language_content_settings_table']['preprocess functions'])) { | |
378 $preprocess_functions = &$theme_registry['language_content_settings_table']['preprocess functions']; | |
379 $index = array_search('layout_builder_preprocess_language_content_settings_table', $preprocess_functions); | |
380 if ($index !== FALSE) { | |
381 unset($preprocess_functions[$index]); | |
382 $preprocess_functions[] = 'layout_builder_preprocess_language_content_settings_table'; | |
383 } | |
384 } | |
385 } | |
386 | |
387 /** | |
388 * Implements hook_preprocess_HOOK() for language-content-settings-table.html.twig. | |
389 */ | |
390 function layout_builder_preprocess_language_content_settings_table(&$variables) { | |
391 foreach ($variables['build']['#rows'] as &$row) { | |
392 if (isset($row['#field_name']) && $row['#field_name'] === OverridesSectionStorage::FIELD_NAME) { | |
393 // Rebuild the label to include a warning about using translations with | |
394 // layouts. | |
395 $row['data'][1]['data']['field'] = [ | |
396 'label' => $row['data'][1]['data']['field'], | |
397 'description' => [ | |
398 '#type' => 'container', | |
399 '#markup' => t('<strong>Warning</strong>: Layout Builder does not support translating layouts. (<a href="https://www.drupal.org/docs/8/core/modules/layout-builder/layout-builder-and-content-translation">online documentation</a>)'), | |
400 '#attributes' => [ | |
401 'class' => ['layout-builder-translation-warning'], | |
402 ], | |
403 ], | |
404 ]; | |
405 } | |
406 } | |
407 } |