diff -u b/page_manager_ui/src/Form/PageVariantConfigureForm.php b/page_manager_ui/src/Form/PageVariantConfigureForm.php --- b/page_manager_ui/src/Form/PageVariantConfigureForm.php +++ b/page_manager_ui/src/Form/PageVariantConfigureForm.php @@ -1,4 +1,5 @@ layoutTempstoreRepository = $layout_tempstore_repository; $this->sectionStorageManager = $section_storage_manager; + $this->tempstore = $tempstore; } /** * {@inheritdoc} */ - public function getFormId() { - return 'page_manager_layout_builder_form'; + public static function create(ContainerInterface $container) { + return new static( + $container->get('layout_builder.tempstore_repository'), + $container->get('plugin.manager.layout_builder.section_storage'), + $container->get('tempstore.shared') + ); } /** * {@inheritdoc} */ - public static function create(ContainerInterface $container) { - return new static( - $container->get('layout_builder.tempstore_repository'), - $container->get('plugin.manager.layout_builder.section_storage') - ); + public function getFormId() { + return 'page_manager_layout_builder_form'; } /** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { - $page_variant = $form_state->getTemporaryValue('wizard')['page_variant']; + $cached_values = $form_state->getTemporaryValue('wizard'); + /** @var \Drupal\page_manager\PageVariantInterface $page_variant */ + $page_variant = $cached_values['page_variant']; + + // If this is a new variant, put it in the tempstore so that we can + // retrieve it by id later. + // @see \Drupal\page_manager\Plugin\SectionStorage\PageManagerSectionStorage::deriveContextsFromRoute. + if ($page_variant->isNew()) { + $this->tempstore->get('page_manager.layout_builder')->set($page_variant->id(), $page_variant); + } $section_storage = $this->sectionStorageManager->load('page_manager', [ 'entity' => EntityContext::fromEntity($page_variant), ]); - $section_storage = $this->layoutTempstoreRepository->get($section_storage); + $this->sectionStorage = $this->layoutTempstoreRepository->get($section_storage); + + $form['preview_toggle'] = $this->buildContentPreviewToggle(); $form['layout_builder'] = [ '#type' => 'layout_builder', - '#section_storage' => $section_storage, + '#section_storage' => $this->sectionStorage, ]; - $this->sectionStorage = $section_storage; + return $form; } @@ -94,27 +117,24 @@ * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { - $this->sectionStorage->save(); - - // \Drupal\ctools\Wizard\EntityFormWizardBase::finish will fetch the page - // from the form temporary values. Let's update that with the new values. $cached_values = $form_state->getTemporaryValue('wizard'); - // Override with the updated variant. - $cached_values['page']->addVariant($this->sectionStorage->getContextValue('entity')); - $form_state->setTemporaryValue('wizard', $cached_values); + /** @var \Drupal\page_manager\Entity\PageVariant $page_variant */ + $page_variant = $this->sectionStorage->getContextValue('entity'); + + // Pass down the variant settings and let the plugin handle saving it. + /** @var \Drupal\page_manager\Plugin\DisplayVariant\LayoutBuilderDisplayVariant $variant_plugin */ + $variant_plugin = $cached_values['plugin']; + $variant_plugin->setConfiguration($page_variant->get('variant_settings')); + + // The form wizard takes care of saving the variant. + // Clear the layout tempstore. $this->layoutTempstoreRepository->delete($this->sectionStorage); $this->messenger()->addMessage($this->t('The layout has been saved.')); - } - /** - * Retrieves the section storage object. - * - * @return \Drupal\layout_builder\SectionStorageInterface - * The section storage for the current form. - */ - public function getSectionStorage() { - return $this->sectionStorage; + // Clean up the tempstore. + $this->tempstore->get('page_manager.layout_builder')->delete($page_variant->id()); + $this->tempstore->get('page_manager.page_variant')->delete($page_variant->id()); } } diff -u b/src/Plugin/DisplayVariant/LayoutBuilderDisplayVariant.php b/src/Plugin/DisplayVariant/LayoutBuilderDisplayVariant.php --- b/src/Plugin/DisplayVariant/LayoutBuilderDisplayVariant.php +++ b/src/Plugin/DisplayVariant/LayoutBuilderDisplayVariant.php @@ -33,6 +33,12 @@ return $build; } + public function defaultConfiguration() { + return parent::defaultConfiguration() + [ + 'sections' => [], + ]; + } + /** * {@inheritdoc} */ @@ -43,6 +49,19 @@ /** * {@inheritdoc} */ + public function getWizardOperations($cached_values) { + $operations = []; + $operations['layout_builder'] = [ + 'title' => $this->t('Layout'), + 'form' => LayoutBuilderForm::class, + ]; + + return $operations; + } + + /** + * {@inheritdoc} + */ protected function setSections(array $sections) { $this->configuration['sections'] = array_values($sections); } @@ -72,15 +91,2 @@ - /** - * {@inheritdoc} - */ - public function getWizardOperations($cached_values) { - $operations = []; - $operations['layout_builder'] = [ - 'title' => $this->t('Layout Builder'), - 'form' => LayoutBuilderForm::class, - ]; - - return $operations; - } - } diff -u b/src/Plugin/LayoutBuilderStorage/PageManagerLayoutBuilderStorage.php b/src/Plugin/LayoutBuilderStorage/PageManagerLayoutBuilderStorage.php --- b/src/Plugin/LayoutBuilderStorage/PageManagerLayoutBuilderStorage.php +++ b/src/Plugin/LayoutBuilderStorage/PageManagerLayoutBuilderStorage.php @@ -18,6 +18,8 @@ class PageManagerLayoutBuilderStorage extends PluginBase implements ContainerFactoryPluginInterface { /** + * The entity type manager. + * * @var \Drupal\Core\Entity\EntityTypeManagerInterface */ protected $entityTypeManager; @@ -73,13 +75,13 @@ if ($id && ($page_variant = $this->loadPageVariant($id))) { $variant_plugin = $page_variant->getVariantPlugin(); if (!($variant_plugin instanceof LayoutBuilderDisplayVariant)) { - throw new \Exception("Page variant doesn't use a Panels display variant"); + throw new \Exception("Page variant doesn't use a Layout Builder display variant"); } $variant_plugin->setConfiguration($lb_display->getConfiguration()); $page_variant->save(); } else { - throw new \Exception("Couldn't find page variant to store Panels display"); + throw new \Exception("Couldn't find page variant to store Layout Builder display"); } } diff -u b/src/Plugin/SectionStorage/PageManagerSectionStorage.php b/src/Plugin/SectionStorage/PageManagerSectionStorage.php --- b/src/Plugin/SectionStorage/PageManagerSectionStorage.php +++ b/src/Plugin/SectionStorage/PageManagerSectionStorage.php @@ -8,6 +8,7 @@ use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Plugin\Context\EntityContext; use Drupal\Core\Session\AccountInterface; +use Drupal\Core\TempStore\SharedTempStoreFactory; use Drupal\Core\Url; use Drupal\layout_builder\Entity\SampleEntityGeneratorInterface; use Drupal\layout_builder\Plugin\SectionStorage\SectionStorageBase; @@ -43,13 +44,37 @@ protected $sampleEntityGenerator; /** - * {@inheritdoc} + * The tempstore factory. + * + * @var \Drupal\Core\TempStore\SharedTempStoreFactory */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, SampleEntityGeneratorInterface $sample_entity_generator) { + protected $tempstore; + + /** + * PageManagerSectionStorage constructor. + * + * @param array $configuration + * The plugin configuration, i.e. an array with configuration values keyed + * by configuration option name. The special key 'context' may be used to + * initialize the defined contexts by setting it to an array of context + * values keyed by context names. + * @param string $plugin_id + * The plugin_id for the plugin instance. + * @param mixed $plugin_definition + * The plugin implementation definition. + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * The entity type manager. + * @param \Drupal\layout_builder\Entity\SampleEntityGeneratorInterface $sample_entity_generator + * The sample entity generator. + * @param \Drupal\Core\TempStore\SharedTempStoreFactory $tempstore + * The tempstore factory. + */ + public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, SampleEntityGeneratorInterface $sample_entity_generator, SharedTempStoreFactory $tempstore) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->entityTypeManager = $entity_type_manager; $this->sampleEntityGenerator = $sample_entity_generator; + $this->tempstore = $tempstore; } /** @@ -61,7 +86,8 @@ $plugin_id, $plugin_definition, $container->get('entity_type.manager'), - $container->get('layout_builder.sample_entity_generator') + $container->get('layout_builder.sample_entity_generator'), + $container->get('tempstore.shared') ); } @@ -109,7 +135,6 @@ * {@inheritdoc} */ public function buildRoutes(RouteCollection $collection) { - // @todo $path = '/admin/structure/page_manager/{page_variant}/layout'; $options['parameters']['page_variant']['type'] = 'entity:page_variant'; @@ -123,22 +148,27 @@ * {@inheritdoc} */ public function deriveContextsFromRoute($value, $definition, $name, array $defaults) { - $contexts = []; + // Try to load from defaults. + $entity = $this->extractEntityFromRoute($value, $defaults); - if ($entity = $this->extractEntityFromRoute($value, $defaults)) { - $contexts['entity'] = EntityContext::fromEntity($entity); + // Otherwise try the tempstore. + if (!$entity) { + $entity = $this->tempstore->get('page_manager.layout_builder')->get($value); } - return $contexts; + + return [ + 'entity' => EntityContext::fromEntity($entity), + ]; } /** * {@inheritdoc} */ private function extractEntityFromRoute($value, array $defaults) { - // @todo if (!empty($value)) { return PageVariant::load($value); } + return PageVariant::load($defaults['page_variant']); } @@ -173,29 +203,31 @@ } /** - * {@inheritdoc} + * Determines if Layout Builder is enabled. + * + * @return bool + * TRUE if Layout Builder is enabled, FALSE otherwise. + * + * @throws \Drupal\Component\Plugin\Exception\PluginException */ - public function getSectionListFromId($id) { - // @todo + public function isLayoutBuilderEnabled() { + return $this->getContextValue('entity')->getVariantPlugin() instanceof LayoutBuilderDisplayVariant; } /** * {@inheritdoc} */ - public function extractIdFromRoute($value, $definition, $name, array $defaults) { + public function getSectionListFromId($id) { // @todo + // This is deprecated and can be removed before Drupal 9.0.0. } /** - * Determines if Layout Builder is enabled. - * - * @return bool - * TRUE if Layout Builder is enabled, FALSE otherwise. - * - * @throws \Drupal\Component\Plugin\Exception\PluginException + * {@inheritdoc} */ - public function isLayoutBuilderEnabled() { - return $this->getContextValue('entity')->getVariantPlugin() instanceof LayoutBuilderDisplayVariant; + public function extractIdFromRoute($value, $definition, $name, array $defaults) { + // @todo + // This is deprecated and can be removed before Drupal 9.0.0. } } only in patch2: unchanged: --- a/page_manager_ui/page_manager_ui.module +++ b/page_manager_ui/page_manager_ui.module @@ -139,3 +139,34 @@ function page_manager_ui_local_tasks_alter(&$local_tasks) { unset($local_tasks['config_translation.local_tasks:entity.page.config_translation_overview']); unset($local_tasks['config_translation.local_tasks:entity.page_variant.config_translation_overview']); } + +/** + * Implements hook_theme_registry_alter(). + */ +function page_manager_ui_theme_registry_alter(&$theme_registry) { + // Seven removes all block contextual links via a preprocess. + // Layout builder variants require contextual links to configure blocks. + // @see https://www.drupal.org/project/drupal/issues/2487025 + if (!empty($theme_registry['block']['preprocess functions'])) { + $preprocess_functions = &$theme_registry['block']['preprocess functions']; + + // Remove seven's implementation. + if ($index = array_search('seven_preprocess_block', $preprocess_functions)) { + unset($preprocess_functions[$index]); + } + } +} + +/** + * Implements hook_preprocess_HOOK(). + */ +function page_manager_ui_preprocess_block(&$variables) { + // If active theme is seven and the block has layout_builder contextual links, + // do nothing. + if (Drupal::theme()->getActiveTheme()->getName() === 'seven' && isset($variables['elements']['#contextual_links']['layout_builder_block'])) { + return; + } + + // Fallback to seven. + seven_preprocess_block($variables); +}