Issue #2905922 by tim.plunkett, tedbow, xjm, EclipseGc, webchick, vijaycs85, larowlan, andrewmacpherson, droplet, Bojhan, mgifford, drpal, phenaproxima, DyanneNova, japerry: Implementation issue for Layout Builder
2017-11-17 19:01:26 +00:00
<?php
/**
* @file
* Provides hook implementations for Layout Builder.
*/
Issue #2957425 by tedbow, johndevman, mpotter, tim.plunkett, hawkeye.twolf, alexpott, Berdir, samuel.mortenson, xjm, kevincrafts, jibran, amateescu, larowlan, twfahey, EclipseGc, sjerdo, japerry, mtodor, phenaproxima, johnzzon, mglaman: Allow the inline creation of non-reusable Custom Blocks in the layout builder
2018-08-25 17:07:16 +00:00
use Drupal\Core\Entity\EntityInterface;
Issue #2905922 by tim.plunkett, tedbow, xjm, EclipseGc, webchick, vijaycs85, larowlan, andrewmacpherson, droplet, Bojhan, mgifford, drpal, phenaproxima, DyanneNova, japerry: Implementation issue for Layout Builder
2017-11-17 19:01:26 +00:00
use Drupal\Core\Form\FormStateInterface;
2018-01-15 21:13:53 +00:00
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
2018-01-30 22:28:03 +00:00
use Drupal\field\FieldConfigInterface;
use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplayStorage;
use Drupal\layout_builder\Form\LayoutBuilderEntityViewDisplayForm;
2018-07-23 09:11:33 +00:00
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface;
use Drupal\layout_builder\Plugin\Block\ExtraFieldBlock;
Issue #2957425 by tedbow, johndevman, mpotter, tim.plunkett, hawkeye.twolf, alexpott, Berdir, samuel.mortenson, xjm, kevincrafts, jibran, amateescu, larowlan, twfahey, EclipseGc, sjerdo, japerry, mtodor, phenaproxima, johnzzon, mglaman: Allow the inline creation of non-reusable Custom Blocks in the layout builder
2018-08-25 17:07:16 +00:00
use Drupal\layout_builder\InlineBlockEntityOperations;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Access\AccessResult;
2018-11-22 11:59:49 +00:00
use Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage;
Issue #2905922 by tim.plunkett, tedbow, xjm, EclipseGc, webchick, vijaycs85, larowlan, andrewmacpherson, droplet, Bojhan, mgifford, drpal, phenaproxima, DyanneNova, japerry: Implementation issue for Layout Builder
2017-11-17 19:01:26 +00:00
/**
* Implements hook_help().
*/
2018-01-15 21:13:53 +00:00
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;
}
Issue #2905922 by tim.plunkett, tedbow, xjm, EclipseGc, webchick, vijaycs85, larowlan, andrewmacpherson, droplet, Bojhan, mgifford, drpal, phenaproxima, DyanneNova, japerry: Implementation issue for Layout Builder
2017-11-17 19:01:26 +00:00
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 */
2018-01-30 22:28:03 +00:00
$entity_types['entity_view_display']
->setClass(LayoutBuilderEntityViewDisplay::class)
->setStorageClass(LayoutBuilderEntityViewDisplayStorage::class)
->setFormClass('edit', LayoutBuilderEntityViewDisplayForm::class);
Issue #2905922 by tim.plunkett, tedbow, xjm, EclipseGc, webchick, vijaycs85, larowlan, andrewmacpherson, droplet, Bojhan, mgifford, drpal, phenaproxima, DyanneNova, japerry: Implementation issue for Layout Builder
2017-11-17 19:01:26 +00:00
}
/**
2018-01-30 22:28:03 +00:00
* Implements hook_form_FORM_ID_alter() for \Drupal\field_ui\Form\EntityFormDisplayEditForm.
Issue #2905922 by tim.plunkett, tedbow, xjm, EclipseGc, webchick, vijaycs85, larowlan, andrewmacpherson, droplet, Bojhan, mgifford, drpal, phenaproxima, DyanneNova, japerry: Implementation issue for Layout Builder
2017-11-17 19:01:26 +00:00
*/
2018-01-30 22:28:03 +00:00
function layout_builder_form_entity_form_display_edit_form_alter(&$form, FormStateInterface $form_state) {
// Hides the Layout Builder field. It is rendered directly in
// \Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay::buildMultiple().
2018-11-22 11:59:49 +00:00
unset($form['fields'][OverridesSectionStorage::FIELD_NAME]);
$key = array_search(OverridesSectionStorage::FIELD_NAME, $form['#fields']);
Issue #2905922 by tim.plunkett, tedbow, xjm, EclipseGc, webchick, vijaycs85, larowlan, andrewmacpherson, droplet, Bojhan, mgifford, drpal, phenaproxima, DyanneNova, japerry: Implementation issue for Layout Builder
2017-11-17 19:01:26 +00:00
if ($key !== FALSE) {
unset($form['#fields'][$key]);
}
}
/**
2018-01-30 22:28:03 +00:00
* Implements hook_field_config_insert().
Issue #2905922 by tim.plunkett, tedbow, xjm, EclipseGc, webchick, vijaycs85, larowlan, andrewmacpherson, droplet, Bojhan, mgifford, drpal, phenaproxima, DyanneNova, japerry: Implementation issue for Layout Builder
2017-11-17 19:01:26 +00:00
*/
2018-01-30 22:28:03 +00:00
function layout_builder_field_config_insert(FieldConfigInterface $field_config) {
// Clear the sample entity for this entity type and bundle.
2018-02-05 03:19:43 +00:00
$sample_entity_generator = \Drupal::service('layout_builder.sample_entity_generator');
$sample_entity_generator->delete($field_config->getTargetEntityTypeId(), $field_config->getTargetBundle());
2018-01-30 22:28:03 +00:00
\Drupal::service('plugin.manager.block')->clearCachedDefinitions();
Issue #2905922 by tim.plunkett, tedbow, xjm, EclipseGc, webchick, vijaycs85, larowlan, andrewmacpherson, droplet, Bojhan, mgifford, drpal, phenaproxima, DyanneNova, japerry: Implementation issue for Layout Builder
2017-11-17 19:01:26 +00:00
}
/**
2018-01-30 22:28:03 +00:00
* Implements hook_field_config_delete().
Issue #2905922 by tim.plunkett, tedbow, xjm, EclipseGc, webchick, vijaycs85, larowlan, andrewmacpherson, droplet, Bojhan, mgifford, drpal, phenaproxima, DyanneNova, japerry: Implementation issue for Layout Builder
2017-11-17 19:01:26 +00:00
*/
2018-01-30 22:28:03 +00:00
function layout_builder_field_config_delete(FieldConfigInterface $field_config) {
// Clear the sample entity for this entity type and bundle.
2018-02-05 03:19:43 +00:00
$sample_entity_generator = \Drupal::service('layout_builder.sample_entity_generator');
$sample_entity_generator->delete($field_config->getTargetEntityTypeId(), $field_config->getTargetBundle());
2018-01-30 22:28:03 +00:00
\Drupal::service('plugin.manager.block')->clearCachedDefinitions();
Issue #2905922 by tim.plunkett, tedbow, xjm, EclipseGc, webchick, vijaycs85, larowlan, andrewmacpherson, droplet, Bojhan, mgifford, drpal, phenaproxima, DyanneNova, japerry: Implementation issue for Layout Builder
2017-11-17 19:01:26 +00:00
}
2018-07-23 09:11:33 +00:00
/**
* Implements hook_entity_view_alter().
*
* ExtraFieldBlock block plugins add placeholders for each extra field which is
* configured to be displayed. Those placeholders are replaced by this hook.
* Modules that implement hook_entity_extra_field_info() use their
* implementations of hook_entity_view_alter() to add the rendered output of
* the extra fields they provide, so we cannot get the rendered output of extra
* fields before this point in the view process.
* layout_builder_module_implements_alter() moves this implementation of
* hook_entity_view_alter() to the end of the list.
*
* @see \Drupal\layout_builder\Plugin\Block\ExtraFieldBlock::build()
* @see layout_builder_module_implements_alter()
*/
function layout_builder_entity_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) {
if ($display instanceof LayoutEntityDisplayInterface) {
/** @var \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager */
$field_manager = \Drupal::service('entity_field.manager');
$extra_fields = $field_manager->getExtraFields($entity->getEntityTypeId(), $entity->bundle());
if (!empty($extra_fields['display'])) {
foreach ($extra_fields['display'] as $field_name => $extra_field) {
// If the extra field is not set replace with an empty array to avoid
// the placeholder text from being rendered.
$replacement = isset($build[$field_name]) ? $build[$field_name] : [];
ExtraFieldBlock::replaceFieldPlaceholder($build, $replacement, $field_name);
// After the rendered field in $build has been copied over to the
// ExtraFieldBlock block we must remove it from its original location or
// else it will be rendered twice.
unset($build[$field_name]);
}
}
}
}
/**
* Implements hook_builder_module_implements_alter().
*/
function layout_builder_module_implements_alter(&$implementations, $hook) {
if ($hook === 'entity_view_alter') {
// Ensure that this module's implementation of hook_entity_view_alter() runs
// last so that other modules that use this hook to render extra fields will
// run before it.
$group = $implementations['layout_builder'];
unset($implementations['layout_builder']);
$implementations['layout_builder'] = $group;
}
}
Issue #2957425 by tedbow, johndevman, mpotter, tim.plunkett, hawkeye.twolf, alexpott, Berdir, samuel.mortenson, xjm, kevincrafts, jibran, amateescu, larowlan, twfahey, EclipseGc, sjerdo, japerry, mtodor, phenaproxima, johnzzon, mglaman: Allow the inline creation of non-reusable Custom Blocks in the layout builder
2018-08-25 17:07:16 +00:00
/**
* Implements hook_entity_presave().
*/
function layout_builder_entity_presave(EntityInterface $entity) {
if (\Drupal::moduleHandler()->moduleExists('block_content')) {
/** @var \Drupal\layout_builder\InlineBlockEntityOperations $entity_operations */
$entity_operations = \Drupal::classResolver(InlineBlockEntityOperations::class);
$entity_operations->handlePreSave($entity);
}
}
/**
* Implements hook_entity_delete().
*/
function layout_builder_entity_delete(EntityInterface $entity) {
if (\Drupal::moduleHandler()->moduleExists('block_content')) {
/** @var \Drupal\layout_builder\InlineBlockEntityOperations $entity_operations */
$entity_operations = \Drupal::classResolver(InlineBlockEntityOperations::class);
$entity_operations->handleEntityDelete($entity);
}
}
/**
* Implements hook_cron().
*/
function layout_builder_cron() {
if (\Drupal::moduleHandler()->moduleExists('block_content')) {
/** @var \Drupal\layout_builder\InlineBlockEntityOperations $entity_operations */
$entity_operations = \Drupal::classResolver(InlineBlockEntityOperations::class);
$entity_operations->removeUnused();
}
}
/**
* Implements hook_plugin_filter_TYPE_alter().
*/
function layout_builder_plugin_filter_block_alter(array &$definitions, array $extra, $consumer) {
// @todo Determine the 'inline_block' blocks should be allowed outside
// of layout_builder https://www.drupal.org/node/2979142.
2018-11-12 20:45:33 +00:00
if ($consumer !== 'layout_builder' || !isset($extra['list']) || $extra['list'] !== 'inline_blocks') {
Issue #2957425 by tedbow, johndevman, mpotter, tim.plunkett, hawkeye.twolf, alexpott, Berdir, samuel.mortenson, xjm, kevincrafts, jibran, amateescu, larowlan, twfahey, EclipseGc, sjerdo, japerry, mtodor, phenaproxima, johnzzon, mglaman: Allow the inline creation of non-reusable Custom Blocks in the layout builder
2018-08-25 17:07:16 +00:00
foreach ($definitions as $id => $definition) {
if ($definition['id'] === 'inline_block') {
unset($definitions[$id]);
}
}
}
}
/**
* Implements hook_ENTITY_TYPE_access().
*/
function layout_builder_block_content_access(EntityInterface $entity, $operation, AccountInterface $account) {
/** @var \Drupal\block_content\BlockContentInterface $entity */
if ($operation === 'view' || $entity->isReusable() || empty(\Drupal::service('inline_block.usage')->getUsage($entity->id()))) {
// If the operation is 'view' or this is reusable block or if this is
// non-reusable that isn't used by this module then don't alter the access.
return AccessResult::neutral();
}
if ($account->hasPermission('configure any layout')) {
return AccessResult::allowed();
}
return AccessResult::forbidden();
}
2018-11-28 11:59:59 +00:00
/**
* Implements hook_plugin_filter_TYPE__CONSUMER_alter().
*/
function layout_builder_plugin_filter_block__block_ui_alter(array &$definitions, array $extra) {
foreach ($definitions as $id => $definition) {
// Filter out any layout_builder definition with required contexts.
if ($definition['provider'] === 'layout_builder' && !empty($definition['context'])) {
/** @var \Drupal\Core\Plugin\Context\ContextDefinitionInterface $context */
foreach ($definition['context'] as $context) {
if ($context->isRequired()) {
unset($definitions[$id]);
break;
}
}
}
}
}
2018-12-10 22:18:57 +00:00
/**
* Implements hook_layout_builder_section_storage_alter().
*/
function layout_builder_layout_builder_section_storage_alter(array &$definitions) {
// @todo Until https://www.drupal.org/node/3016420 is resolved, context
// definition annotations cannot specify any constraints. Alter
// \Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage to
// add the constraint of having the required layout field.
/** @var \Drupal\layout_builder\SectionStorage\SectionStorageDefinition[] $definitions */
$definitions['overrides']->getContextDefinition('entity')
->addConstraint('EntityHasField', OverridesSectionStorage::FIELD_NAME);
}