Reading records stored in another site 

Two things have to be settled before a query can return records from another site: which pages to read, and which language to ask for. This page covers the pages. The language has its own page.

Naming the storage pages 

The storage pages of another site are ordinary page UIDs, and the storagePid configuration accepts them. Nothing checks that they belong to the current site.

For a setup with matching language configuration this is all it takes: configure the shared folder as the storagePid in TypoScript, or let an editor choose it in the Behavior > Starting point field of the plugin, and every query the repository builds reads from there.

Overriding the storage pages for one query 

Where the storage pages are decided at runtime — different for each visitor, each plugin instance or each site — the query settings carry the decision instead:

EXT:my_extension/Classes/Domain/Repository/ConferenceRepository.php
<?php

namespace MyVendor\MyExtension\Domain\Repository;

use MyVendor\MyExtension\Domain\Model\Conference;
use TYPO3\CMS\Core\Context\LanguageAspect;
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
use TYPO3\CMS\Extbase\Persistence\Repository;

class ConferenceRepository extends Repository
{
  /**
   * Reads conferences from storage pages that need not belong to the current
   * site, in the language the caller resolved for those pages.
   *
   * @param int[] $storagePageIds
   * @return QueryResultInterface<Conference>
   */
  public function findAllInStorage(
    array $storagePageIds,
    LanguageAspect $languageAspect,
  ): QueryResultInterface {
    $query = $this->createQuery();
    $querySettings = $query->getQuerySettings();

    $querySettings->setStoragePageIds($storagePageIds);
    $querySettings->setLanguageAspect($languageAspect);

    return $query->execute();
  }
}
Copied!

setStoragePageIds() replaces the configured storagePid for this one query. The repository takes both the pages and the language aspect as arguments, so it makes no assumption about which site either came from. That keeps it usable from a plugin, a backend module and a command alike.

Finding the storage site 

Reading the language configuration of the storage site — which the next page needs — means resolving the Site object it belongs to. \TYPO3\CMS\Core\Site\SiteFinder offers three ways in, and the choice matters:

Method Use it when
getSiteByIdentifier() The storage site is known by name from configuration. This is the most robust option: the identifier is stable, readable in a site setting, and survives page UIDs changing.
getSiteByPageId() Only the storage page UID is known. Resolves the site from the page it sits in.
getSiteByRootPageId() The root page UID of the storage site is known.

What this means for relations 

Relation queries ignore the storagePid entirely: Extbase sets setRespectStoragePage(false) on them. Relations therefore reach records the parent query could never have returned, wherever in the page tree they are stored.

For cross-site reading this works in your favor — a conference in the shared folder keeps its categories regardless of which site reads it, and you need do nothing to make that happen. The same mechanism also means a relation can pull in a record from a storage folder you did not intend to expose, which is worth knowing when the related table holds site-specific data.

The language of relations is a separate question, covered on the next page.