Use different domains within the same site in TYPO3

Use different domains within the same site in TYPO3

The site configuration in TYPO3 has been mandatory since TYPO3 10. This concept is well chosen and replaces the old sys_domain data records in the backend. But what if a certain area in the page tree should be accessible with several domains? If you have the same problem, we may have the solution for you.

I have often read the answer on various sources that you don't need several domains for one area in TYPO3. Finally, you can use an environment variable to assign different domains, for example if you want to develop locally or have a test environment.

Environment Variables

This is relatively easy to do by picking up this variable in the SiteConfiguration:

base: 'https://%env(HOST_MAIN)%/' rootPageId: 1 websiteTitle: 'My website' imports: - resource: 'EXT:sitepackage/Configuration/Routes/DefaultSiteConfiguration.yaml'

In the Apache configuration, this variable can then be easily set with:

SetEnv HOST_MAIN development.domain.org

Alternatively, this can also be easily defined in an .env file (here we recommend using helhum/dotenv-connector):

HOST_MAIN=development.domain.org
BaseVariants with own Condition

But there can also be cases in which you have to allow multiple domains for the same page tree section within the same TYPO3 instance (e.g. Production). This applies, for example, to areas in the intranet. In another case, however, an insurance customer would like us to access one area via two different domains. Depending on the domain, the content is then slightly different (we do not show the implementation here in order not to complicate the example).

This can be made possible with the help of BaseVariants in the SiteConfiguration. The only challenge: A condition that switches based on the current domain does not yet exist in TYPO3. We have to help a little here.

Let us assume that we have now defined two different domains in the .env file:

HOST_MAIN=domain1.org HOST_ALTERNATIVE=domain2.org

Then the SiteConfiguration could look like this:

base: 'https://%env(HOST_MAIN)%/' baseVariants: - base: 'https://%env(HOST_ALTERNATIVE)%/' condition: 'isAlternativeDomain("%env(HOST_ALTERNATIVE)%")' rootPageId: 1 websiteTitle: 'My website' imports: - resource: 'EXT:sitepackage/Configuration/Routes/DefaultSiteConfiguration.yaml'

The problem, however, is that the isAlternativeDomain() condition does not yet exist, and we have to make up for that in our sitepackage, for example. EXT:sitepackage/Configuration/ExpressionLanguage.php:

<?php return [ 'site' => [ \Vendor\Sitepackage\Condition\SiteConditionProvider::class ] ];

The related provider EXT:sitepackage/Classes/Condition/SiteConditionProvider.php:

<?php declare(strict_types = 1); namespace Vendor\Sitepackage\Condition; use Vendor\Sitepackage\Condition\FunctionsProvider\SiteConditionFunctionsProvider; use TYPO3\CMS\Core\ExpressionLanguage\AbstractProvider; /** * SiteConditionProvider */ class SiteConditionProvider extends AbstractProvider { /** * Constructor */ public function __construct() { $this->expressionLanguageProviders = [ SiteConditionFunctionsProvider::class, ]; } }

Last but not least the FunctionsProvider in EXT:sitepackage/Classes/Condition/FunctionsProvider/SiteConditionFunctionsProvider.php:

<?php declare(strict_types=1); namespace Vendor\Sitepackage\Condition\FunctionsProvider; use Symfony\Component\ExpressionLanguage\ExpressionFunction; use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface; use TYPO3\CMS\Core\Utility\GeneralUtility; /** * SiteConditionFunctionsProvider */ class SiteConditionFunctionsProvider implements ExpressionFunctionProviderInterface { /** * @return array|ExpressionFunction[] */ public function getFunctions() { return [ $this->isAlternativeDomain(), ]; } /** * Site configuration: Can be used to decide if a baseVariant should be loaded * * Example: * baseVariants: * - base: 'https://%env(HOST_MAKLERNETZ)%/' * condition: 'isAlternativeDomain("%env(HOST_MAKLERNETZ)%")' * * @return ExpressionFunction */ protected function isAlternativeDomain(): ExpressionFunction { return new ExpressionFunction('isAlternativeDomain', function () { // Not implemented, we only use the evaluator }, function (array $existingVariables, string $alternativeDomain) { return GeneralUtility::getIndpEnv('HTTP_HOST') == $alternativeDomain; }); } }

In principle, that's all. The same area in the page tree can now be accessed via the domains domain1.org and domain2.org.

TYPO3: Finding unused files in fileadmin

Do you want to delete unused or orphaned files in fileadmin or another storage location? Unfortunately, there's no direct core functionality for this. But a small command in your site package can...

Go to news

TYPO3: Editors with individual user_upload folders

Perhaps you're familiar with this client requirement? Editors should be able to add videos using the "Add media by URL" button. But the files shouldn't be located in fileadmin/user_upload/, but rather...

Go to news

TYPO3: Finding pages in mixed mode

In TYPO3, Mixed Mode refers to translated pages that contain content only partially related to the corresponding content in the main language. This is indicated in the backend by an error message. But...

Go to news

Extbase Extensions: Think extensibility with data, site and language

Today, I have a small request for the TYPO3 extension authors out there: Make sure your extensions are extensible. This will also promote the distribution of the corresponding plugins.

Go to news

SQL: Show all tables sorted by size in descending order

Lately I've been using the SQL command more often to find out which tables in the TYPO3 database are the largest. I've published the snippet once.

Go to news

TYPO3 12 with CKEditor 5: Styles in a single selection

If you set a link in the RTE in TYPO3, you may have to choose between different link classes, for example to create buttons in the frontend. What's new in TYPO3 12 is that you can select not just one...

Go to news