diff --git a/core-bundle/src/Resources/config/services.yml b/core-bundle/src/Resources/config/services.yml index a970a31a90a..03c61a3bab0 100644 --- a/core-bundle/src/Resources/config/services.yml +++ b/core-bundle/src/Resources/config/services.yml @@ -702,6 +702,7 @@ services: - '@Contao\CoreBundle\Routing\ResponseContext\ResponseContextAccessor' - '@event_dispatcher' - '@contao.security.token_checker' + - '@contao.framework' public: true contao.search.indexer.default: diff --git a/core-bundle/src/Resources/contao/pages/PageRegular.php b/core-bundle/src/Resources/contao/pages/PageRegular.php index a840e84d36e..118ec4e029a 100644 --- a/core-bundle/src/Resources/contao/pages/PageRegular.php +++ b/core-bundle/src/Resources/contao/pages/PageRegular.php @@ -13,7 +13,6 @@ use Contao\CoreBundle\Exception\NoLayoutSpecifiedException; use Contao\CoreBundle\Routing\ResponseContext\CoreResponseContextFactory; use Contao\CoreBundle\Routing\ResponseContext\HtmlHeadBag\HtmlHeadBag; -use Contao\CoreBundle\Routing\ResponseContext\JsonLd\ContaoPageSchema; use Contao\CoreBundle\Routing\ResponseContext\JsonLd\JsonLdManager; use Contao\CoreBundle\Routing\ResponseContext\ResponseContext; use Contao\CoreBundle\Routing\ResponseContext\ResponseContextAccessor; @@ -80,7 +79,8 @@ protected function prepare($objPage) $locale = LocaleUtil::formatAsLocale($objPage->language); $container = System::getContainer(); - $container->get('request_stack')->getCurrentRequest()->setLocale($locale); + $request = $container->get('request_stack')->getCurrentRequest(); + $request->setLocale($locale); $container->get('translator')->setLocale($locale); $this->responseContext = $container->get(CoreResponseContextFactory::class)->createContaoWebpageResponseContext($objPage); @@ -224,6 +224,12 @@ protected function prepare($objPage) // Meta robots tag $this->Template->robots = $this->responseContext->get(HtmlHeadBag::class)->getMetaRobots(); + // Canonical + if ($objPage->enableCanonical) + { + $this->Template->canonical = $this->responseContext->get(HtmlHeadBag::class)->getCanonicalUri($request); + } + // Fall back to the default title tag if (!$objLayout->titleTag) { diff --git a/core-bundle/src/Resources/contao/templates/frontend/fe_page.html5 b/core-bundle/src/Resources/contao/templates/frontend/fe_page.html5 index 97e9983a854..24e13184525 100644 --- a/core-bundle/src/Resources/contao/templates/frontend/fe_page.html5 +++ b/core-bundle/src/Resources/contao/templates/frontend/fe_page.html5 @@ -13,6 +13,12 @@ endblock(); ?> + block('canonical'); ?> + canonical): ?> + + + endblock(); ?> + viewport ?> framework ?> stylesheets ?> diff --git a/core-bundle/src/Routing/ResponseContext/CoreResponseContextFactory.php b/core-bundle/src/Routing/ResponseContext/CoreResponseContextFactory.php index a93f61f2e95..4f5b1643347 100644 --- a/core-bundle/src/Routing/ResponseContext/CoreResponseContextFactory.php +++ b/core-bundle/src/Routing/ResponseContext/CoreResponseContextFactory.php @@ -12,10 +12,13 @@ namespace Contao\CoreBundle\Routing\ResponseContext; +use Contao\Controller; +use Contao\CoreBundle\Framework\ContaoFramework; use Contao\CoreBundle\Routing\ResponseContext\HtmlHeadBag\HtmlHeadBag; use Contao\CoreBundle\Routing\ResponseContext\JsonLd\ContaoPageSchema; use Contao\CoreBundle\Routing\ResponseContext\JsonLd\JsonLdManager; use Contao\CoreBundle\Security\Authentication\Token\TokenChecker; +use Contao\Environment; use Contao\PageModel; use Contao\StringUtil; use Spatie\SchemaOrg\WebPage; @@ -26,12 +29,14 @@ class CoreResponseContextFactory private ResponseContextAccessor $responseContextAccessor; private EventDispatcherInterface $eventDispatcher; private TokenChecker $tokenChecker; + private ContaoFramework $contaoFramework; - public function __construct(ResponseContextAccessor $responseContextAccessor, EventDispatcherInterface $eventDispatcher, TokenChecker $tokenChecker) + public function __construct(ResponseContextAccessor $responseContextAccessor, EventDispatcherInterface $eventDispatcher, TokenChecker $tokenChecker, ContaoFramework $contaoFramework) { $this->responseContextAccessor = $responseContextAccessor; $this->eventDispatcher = $eventDispatcher; $this->tokenChecker = $tokenChecker; + $this->contaoFramework = $contaoFramework; } public function createResponseContext(): ResponseContext @@ -83,6 +88,20 @@ public function createContaoWebpageResponseContext(PageModel $pageModel): Respon $htmlHeadBag->setMetaRobots($pageModel->robots); } + if ($pageModel->enableCanonical && $pageModel->canonicalLink) { + $url = $this->contaoFramework->getAdapter(Controller::class)->replaceInsertTags($pageModel->canonicalLink, false); + + // Ensure absolute links (FIXME: Remove once we remove support for relative urls) + if (!preg_match('#^https?://#', $url)) { + $url = $this->contaoFramework->getAdapter(Environment::class)->get('base').$url; + } + $htmlHeadBag->setCanonicalUri($url); + } + + if ($pageModel->enableCanonical && $pageModel->canonicalKeepParams) { + $htmlHeadBag->setKeepParamsForCanonical(array_map('trim', explode(',', (string) $pageModel->canonicalKeepParams))); + } + $jsonLdManager ->getGraphForSchema(JsonLdManager::SCHEMA_CONTAO) ->set(