diff --git a/typo3/sysext/seo/Classes/HrefLang/HrefLangGenerator.php b/typo3/sysext/seo/Classes/HrefLang/HrefLangGenerator.php index fa86d0308096..646615454d6f 100644 --- a/typo3/sysext/seo/Classes/HrefLang/HrefLangGenerator.php +++ b/typo3/sysext/seo/Classes/HrefLang/HrefLangGenerator.php @@ -17,8 +17,14 @@ namespace TYPO3\CMS\Seo\HrefLang; +use Psr\Http\Message\ServerRequestInterface; +use TYPO3\CMS\Core\Context\Context; +use TYPO3\CMS\Core\Context\LanguageAspectFactory; +use TYPO3\CMS\Core\Domain\Repository\PageRepository; use TYPO3\CMS\Core\Http\Uri; +use TYPO3\CMS\Core\Site\Entity\SiteInterface; use TYPO3\CMS\Core\Site\Entity\SiteLanguage; +use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; use TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor; @@ -60,16 +66,25 @@ public function __invoke(ModifyHrefLangTagsEvent $event): void $languages = $this->languageMenuProcessor->process($this->cObj, [], [], []); /** @var SiteLanguage $siteLanguage */ $siteLanguage = $event->getRequest()->getAttribute('language'); + $pageId = (int)$this->getTypoScriptFrontendController()->id; + foreach ($languages['languagemenu'] as $language) { if ($language['available'] === 1 && !empty($language['link']) && $language['hreflang']) { + $page = $this->getTranslatedPageRecord($pageId, $language['languageId'], $event->getRequest()); + if (!empty($page['canonical_link'])) { + // do not set hreflang when canonical is set + continue; + } + $href = $this->getAbsoluteUrl($language['link'], $siteLanguage); $hrefLangs[$language['hreflang']] = $href; } } if (count($hrefLangs) > 1) { - $href = $this->getAbsoluteUrl($languages['languagemenu'][0]['link'], $siteLanguage); - $hrefLangs['x-default'] = $href; + if (array_key_exists($languages['languagemenu'][0]['hreflang'], $hrefLangs)) { + $hrefLangs['x-default'] = $hrefLangs[$languages['languagemenu'][0]['hreflang']]; + } } $event->setHrefLangs($hrefLangs); @@ -101,4 +116,24 @@ protected function getTypoScriptFrontendController(): TypoScriptFrontendControll { return $GLOBALS['TSFE']; } + + protected function getTranslatedPageRecord(int $pageId, int $languageId, ServerRequestInterface $request): array + { + $site = $request->getAttribute('site'); + if (!$site instanceof SiteInterface) { + return $this->getTypoScriptFrontendController()->page; + } + + $targetSiteLanguage = $site->getLanguageById($languageId); + $languageAspect = LanguageAspectFactory::createFromSiteLanguage($targetSiteLanguage); + + $context = clone GeneralUtility::makeInstance(Context::class); + $context->setAspect('language', $languageAspect); + + $pageRepository = GeneralUtility::makeInstance(PageRepository::class, $context); + if ($languageId > 0) { + return $pageRepository->getPageOverlay($pageId, $languageId); + } + return $pageRepository->getPage($pageId); + } } diff --git a/typo3/sysext/seo/Tests/Functional/Fixtures/HrefLangScenario.yml b/typo3/sysext/seo/Tests/Functional/Fixtures/HrefLangScenario.yml index cacb83488890..0496f3962384 100644 --- a/typo3/sysext/seo/Tests/Functional/Fixtures/HrefLangScenario.yml +++ b/typo3/sysext/seo/Tests/Functional/Fixtures/HrefLangScenario.yml @@ -44,3 +44,11 @@ entities: languageVariants: - self: {id: 1101, title: 'DE: Willkommen', language: 1, slug: '/willkommen'} - self: {id: 1102, title: 'NL: Welkom', language: 3, slug: '/welkom'} + - self: {id: 1200, title: 'EN: Contact', slug: '/contact', canonical_link: 'https://www.typo3.org'} + languageVariants: + - self: {id: 1201, title: 'DE: Kontakt', language: 1, slug: '/kontakt'} + - self: {id: 1202, title: 'DE-CH: Kontakt', language: 2, slug: '/kontakt'} + - self: {id: 1300, title: 'EN: About', slug: '/about'} + languageVariants: + - self: {id: 1301, title: 'DE: Uber', language: 1, slug: '/uber'} + - self: {id: 1302, title: 'DE-CH: Uber', language: 2, slug: '/uber', canonical_link: 'https://acme.com/de/uber'} diff --git a/typo3/sysext/seo/Tests/Functional/HrefLang/HrefLangGeneratorTest.php b/typo3/sysext/seo/Tests/Functional/HrefLang/HrefLangGeneratorTest.php index 3f6188c0921f..8275dbe960d1 100644 --- a/typo3/sysext/seo/Tests/Functional/HrefLang/HrefLangGeneratorTest.php +++ b/typo3/sysext/seo/Tests/Functional/HrefLang/HrefLangGeneratorTest.php @@ -43,6 +43,7 @@ class HrefLangGeneratorTest extends FunctionalTestCase protected const LANGUAGE_PRESETS = [ 'EN' => ['id' => 0, 'title' => 'English', 'locale' => 'en_US.UTF8', 'iso' => 'en', 'hrefLang' => 'en-US', 'direction' => ''], 'DE' => ['id' => 1, 'title' => 'German', 'locale' => 'de_DE.UTF8', 'iso' => 'de', 'hrefLang' => 'de-DE', 'direction' => ''], + 'DE-CH' => ['id' => 2, 'title' => 'Swiss German', 'locale' => 'de_CH.UTF8', 'iso' => 'de', 'hrefLang' => 'de-CH', 'direction' => ''], 'NL' => ['id' => 3, 'title' => 'Dutch', 'locale' => 'nl_NL.UTF8', 'iso' => 'nl', 'hrefLang' => '', 'direction' => ''], ]; @@ -68,6 +69,7 @@ protected function setUp(): void [ $this->buildDefaultLanguageConfiguration('EN', '/'), $this->buildLanguageConfiguration('DE', '/de'), + $this->buildLanguageConfiguration('DE-CH', '/de-ch'), $this->buildLanguageConfiguration('NL', '/nl'), ] ); @@ -160,6 +162,28 @@ public function checkHrefLangOutputDataProvider(): array '', ] ], + 'English page with canonical' => [ + 'https://acme.com/contact', + [ + '', + '', + ], + [ + '', + '', + ] + ], + 'Swiss german page with canonical' => [ + 'https://acme.com/de-ch/uber', + [ + '', + '', + '', + ], + [ + '', + ] + ], ]; }