getAttribute('frontend.page.information')->getPageRecord(); $canonicalGenerationDisabledException = null; $href = ''; $typoScriptConfigArray = $request->getAttribute('frontend.typoscript')->getConfigArray(); try { if ($typoScriptConfigArray['disableCanonical'] ?? false) { throw new CanonicalGenerationDisabledException('Generation of the canonical tag is disabled via TypoScript "disableCanonical"', 1706104146); } if ((int)$pageRecord['no_index'] === 1) { throw new CanonicalGenerationDisabledException('Generation of the canonical is disabled due to "no_index" being set active in the page properties', 1706104147); } // 1) Check if page has canonical URL set $href = $this->checkForCanonicalLink($request); if ($href === '') { // 2) Check if page show content from other page $href = $this->checkContentFromPid($request); } if ($href === '') { // 3) Fallback, create canonical URL $href = $this->checkDefaultCanonical($request); } } catch (CanonicalGenerationDisabledException $canonicalGenerationDisabledException) { } finally { /** @var Page $page */ $page = $this->recordFactory->createFromDatabaseRow('pages', $pageRecord); $event = $this->eventDispatcher->dispatch( new ModifyUrlForCanonicalTagEvent($request, $page, $href, $canonicalGenerationDisabledException) ); $href = $event->getUrl(); } if ($href !== '') { $docType = DocType::createFromConfigurationKey($typoScriptConfigArray['doctype'] ?? ''); $canonical = ' 'canonical', 'href' => $href, ], true) . ($docType->isXmlCompliant() ? '/' : '') . '>' . LF; $this->pageRenderer->addHeaderData($canonical); return $canonical; } return ''; } protected function checkForCanonicalLink(ServerRequestInterface $request): string { $pageRecord = $request->getAttribute('frontend.page.information')->getPageRecord(); $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class); $cObj->setRequest($request); $cObj->start($pageRecord, 'pages'); if (!empty($pageRecord['canonical_link'])) { return $cObj->createUrl([ 'parameter' => $pageRecord['canonical_link'], 'forceAbsoluteUrl' => true, ]); } return ''; } protected function checkContentFromPid(ServerRequestInterface $request): string { $pageInformation = $request->getAttribute('frontend.page.information'); $id = $pageInformation->getId(); $contentPid = $pageInformation->getContentFromPid(); if ($id !== $contentPid) { $targetPid = $contentPid; if ($targetPid > 0) { $targetPageRecord = $this->pageRepository->getPage($contentPid, true); if (!empty($targetPageRecord['canonical_link'])) { $targetPid = $targetPageRecord['canonical_link']; } $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class); $cObj->setRequest($request); $cObj->start($request->getAttribute('frontend.page.information')->getPageRecord(), 'pages'); return $cObj->createUrl([ 'parameter' => $targetPid, 'forceAbsoluteUrl' => true, ]); } } return ''; } protected function checkDefaultCanonical(ServerRequestInterface $request): string { $pageInformation = $request->getAttribute('frontend.page.information'); $id = $pageInformation->getId(); // We should only create a canonical link to the target, if the target is within a valid site root $inSiteRoot = $this->isPageWithinSiteRoot($id); if (!$inSiteRoot) { return ''; } // Temporarily remove current mount point information as we want to have the // URL of the target page and not of the page within the mount point if the // current page is a mount point. $pageInformation = clone $pageInformation; $pageInformation->setMountPoint(''); $request = $request->withAttribute('frontend.page.information', $pageInformation); $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class); $cObj->setRequest($request); $cObj->start($pageInformation->getPageRecord(), 'pages'); return $cObj->createUrl([ 'parameter' => $id . ',' . $request->getAttribute('routing')->getPageType(), 'forceAbsoluteUrl' => true, 'addQueryString' => true, 'addQueryString.' => [ 'exclude' => implode( ',', CanonicalizationUtility::getParamsToExcludeForCanonicalizedUrl( $id, (array)$GLOBALS['TYPO3_CONF_VARS']['FE']['additionalCanonicalizedUrlParameters'], $request ) ), ], ]); } protected function isPageWithinSiteRoot(int $id): bool { $rootline = GeneralUtility::makeInstance(RootlineUtility::class, $id)->get(); foreach ($rootline as $page) { if ($page['is_siteroot']) { return true; } } return false; } }