diff --git a/modules/next/css/next.site_preview.iframe.css b/modules/next/css/next.site_preview.iframe.css index 0803bcb2..1ee5e394 100644 --- a/modules/next/css/next.site_preview.iframe.css +++ b/modules/next/css/next.site_preview.iframe.css @@ -33,7 +33,7 @@ color: #325e1c; } -.next-site-preview-toolbar .operations .live-link .button { +.next-site-preview-toolbar .operations .live-link .preview-link .button { margin-top: 0; margin-bottom: 0; } diff --git a/modules/next/next.links.task.yml b/modules/next/next.links.task.yml index 16545c5a..7d04de58 100644 --- a/modules/next/next.links.task.yml +++ b/modules/next/next.links.task.yml @@ -18,3 +18,9 @@ next.settings: route_name: next.settings base_route: next.settings weight: 20 + +entity.node.headless_preview: + title: Preview + route_name: entity.node.headless_preview + base_route: entity.node.canonical + weight: 5 diff --git a/modules/next/next.routing.yml b/modules/next/next.routing.yml index 35be98f4..5ce1a5e2 100644 --- a/modules/next/next.routing.yml +++ b/modules/next/next.routing.yml @@ -16,3 +16,18 @@ next.validate_preview_url: requirements: _access: 'TRUE' _format: 'json' + +entity.node.headless_preview: + path: '/node/{node}/site-preview' + defaults: + _title_callback: '\Drupal\next\Controller\SitePreviewController::nodePreviewTitle' + _controller: '\Drupal\next\Controller\SitePreviewController::nodePreview' + requirements: + _entity_access: node.view + _module_dependencies: content_moderation + options: + _node_operation_route: TRUE + _admin_route: TRUE + parameters: + node: + type: entity:node diff --git a/modules/next/src/Controller/SitePreviewController.php b/modules/next/src/Controller/SitePreviewController.php new file mode 100644 index 00000000..16b1755a --- /dev/null +++ b/modules/next/src/Controller/SitePreviewController.php @@ -0,0 +1,99 @@ +nextEntityTypeManager = $nextEntityTypeManager; + $this->sitePreviewerManager = $sitePreviewerManager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) + { + return new static( + $container->get('next.entity_type.manager'), + $container->get('plugin.manager.next.site_previewer') + ); + } + + /** + * Displays the node title for preview. + * @param Node $node [description] + * @return string [description] + */ + public function nodePreviewTitle(Node $node) + { + return 'Preview: ' . $node->getTitle(); + } + + /** + * Displays the next.js site preview of a node. + */ + public function nodePreview(Node $node) + { + $storage = \Drupal::entityTypeManager()->getStorage($node->getEntityTypeId()); + $revision = $storage->loadRevision($storage->getLatestRevisionId($node->id())); + + $next_entity_type_config = $this->nextEntityTypeManager->getConfigForEntityType($revision->getEntityTypeId(), $revision->bundle()); + $sites = $next_entity_type_config->getSiteResolver()->getSitesForEntity($revision); + if (!count($sites)) { + throw new \Exception('Next.js sites for the entity could not be resolved.'); + } + + $config = $this->config('next.settings'); + $site_previewer_id = $config->get('site_previewer') ?? 'iframe'; + + /** @var \Drupal\next\Plugin\SitePreviewerInterface $site_previewer */ + $site_previewer = $this->sitePreviewerManager->createInstance($site_previewer_id, $config->get('site_previewer_configuration') ?? []); + if (!$site_previewer) { + throw new PluginNotFoundException('Invalid site previewer.'); + } + + // Build preview. + $preview = $site_previewer->render($revision, $sites); + + $context = [ + 'plugin' => $site_previewer, + 'entity' => $revision, + 'sites' => $sites, + ]; + + // Allow modules to alter the preview. + $this->moduleHandler()->alter('next_site_preview', $preview, $context); + + return $preview; + } +}