<p>Maybe this is some kind of broad answer too but when you take a look at your CP requests you'll see: the <code>siteHandle</code> is mostly passed as a variable in nearly every request.</p>

<p>As for the URL routes the last segment is always the <code>siteHandle</code>: By default, the current site will be used in every query but as soon as Craft recognizes a bodyParam <code>siteId</code>/<code>criteria['siteId']</code> (for example in your baseElementIndex) or in the URL route it uses that site for all <code>ElementQueries</code>.</p>

<p>In your CP there is no such a thing like <code>currentSite</code> (at least it is not really used for important logic) instead the current site is determined like </p>

<pre><code>{% for siteId in groupSiteIds %}
    {% if siteId == entry.siteId %} 
        // currentSite = entry.siteId
    {% else %}
        // not the current site
    {% endif %}
{% endif %}
</code></pre>

<p>When I started I used the same method to check for a parameter <code>siteId</code> within the bodyParam <code>criteria</code>. My plugin routes are always something like this</p>

<pre><code>$event-&gt;rules[] = [
    'pattern' =&gt; 'form-builder/elements/&lt;action:&gt;/&lt;id:\d+&gt;/&lt;siteHandle:\w+&gt;',
    'route' =&gt; 'form-builder/element/&lt;action&gt;',
    'defaults' =&gt; [
        'id' =&gt; null,
        'siteHandle' =&gt; Craft::$app-&gt;getSites()-&gt;getPrimarySite()-&gt;handle,
        'action'    =&gt; 'index'
    ]
];
</code></pre>

<p>if no <code>siteHandle</code> is passed I use the <code>Craft::$app-&gt;getSites()-&gt;getPrimarySite()</code></p>

<h3>craft\controllers\EntriesController</h3>

<pre><code>public function actionEditEntry(string $sectionHandle, int $entryId = null, int $draftId = null, int $versionId = null, string $siteHandle = null, Entry $entry = null): Response
if ($siteHandle !== null) {
    $variables['site'] = Craft::$app-&gt;getSites()-&gt;getSiteByHandle($siteHandle);

    if (!$variables['site']) {
        throw new NotFoundHttpException('Invalid site handle: '.$siteHandle);
    }
}
</code></pre>

<p>later on, when there is really nothing at all it just assumes the following</p>

<pre><code>if (empty($variables['site'])) {
    /** @noinspection PhpUnhandledExceptionInspection */
    $variables['site'] = Craft::$app-&gt;getSites()-&gt;getCurrentSite();

    if (!in_array($variables['site']-&gt;id, $variables['siteIds'], false)) {
        $variables['site'] = Craft::$app-&gt;getSites()-&gt;getSiteById($variables['siteIds'][0]);
    }

    $site = $variables['site'];
}
</code></pre>

<h3>TL:DR</h3>

<p>Craft doesn't use the <code>currentSite</code> that much in the CP, it is determined by the current <code>element.siteId</code> or the <code>siteMenu</code> (in js). As soon as you enter the CP the selected site in the menu will be stored in your Javascript session, when you click on <code>create new entry</code> you'll get routed to the site that is specified in your session. I think it's best to manage it the same way</p>

CC BY-SA 4.0
2018-05-21T16:52:43.873Z
2018-05-22T04:49:32.653Z
2018-05-22T04:49:32.653Z
Robin Schambach
<p>In some of our plugins, we have added multi-site support. For the most part, things are working fine but I'm feeling a bit confused about the correct way to set the <code>currentSite</code> in the Control Panel.</p>

<p>On the front-end, I would expect <code>currentSite</code> could be determined from the Base URL matching that of the request.</p>

<p>On the backend, since all admin behavior is managed from the same base domain, there is nothing specific about the request that would indicate the request is for a certain site so using something like <code>Craft::$app-&gt;getSites()-&gt;currentSite</code> seems to always give back the same answer.</p>

<p>Does Craft define the <code>currentSite</code> on backend requests? What role should a plugin take in defining the <code>currentSite</code>? Should we go as far as creating the variable for current site itself or could we just set the current site using something like <code>Craft::$app-&gt;getSites()-&gt;setCurrentSite()</code> and expect Craft to do several things for us?  Should we expect different behavior of the <code>currentSite</code> variable when working with Elements vs other components?</p>

<p>Understandably, these are some broad questions. I'm mostly just looking for a better framework to understand what assumptions Craft makes about multi-site on the CP side of things and how we can best plan our code to take advantage of what is already there instead of reinventing the wheel.</p>

<plugin-development><craft3><multi-site>
What is the proper way to set `currentSite` in a CP template when managing multi-site stuff in Craft 3?
# What is the proper way to set `currentSite` in a CP template when managing multi-site stuff in Craft 3?

(Asked by: username_0 on 2018-05-21)

In some of our plugins, we have added multi-site support. For the most part, things are working fine but I'm feeling a bit confused about the correct way to set the `currentSite` in the Control Panel.

On the front-end, I would expect `currentSite` could be determined from the Base URL matching that of the request.

On the backend, since all admin behavior is managed from the same base domain, there is nothing specific about the request that would indicate the request is for a certain site so using something like `Craft::$app->getSites()->currentSite` seems to always give back the same answer.

Does Craft define the `currentSite` on backend requests? What role should a plugin take in defining the `currentSite`? Should we go as far as creating the variable for current site itself or could we just set the current site using something like `Craft::$app->getSites()->setCurrentSite()` and expect Craft to do several things for us? Should we expect different behavior of the `currentSite` variable when working with Elements vs other components?

Understandably, these are some broad questions. I'm mostly just looking for a better framework to understand what assumptions Craft makes about multi-site on the CP side of things and how we can best plan our code to take advantage of what is already there instead of reinventing the wheel.

**Tags:** plugin-development, craft3, multi-site

---

## 1 answers

### Answer by username_1 on 2018-05-21. Score: 3 | Accepted answer

Maybe this is some kind of broad answer too but when you take a look at your CP requests you'll see: the siteHandle is mostly passed as a variable in nearly every request.
As for the URL routes the last segment is always the siteHandle: By default, the current site will be used in every query but as soon as Craft recognizes a bodyParam siteId/criteria['siteId'] (for example in your baseElementIndex) or in the URL route it uses that site for all ElementQueries.
In your CP there is no such a thing like currentSite (at least it is not really used for important logic) instead the current site is determined like 
{% for siteId in groupSiteIds %}
    {% if siteId == entry.siteId %} 
        // currentSite = entry.siteId
    {% else %}
        // not the current site
    {% endif %}
{% endif %}

When I started I used the same method to check for a parameter siteId within the bodyParam criteria. My plugin routes are always something like this
$event->rules[] = [
    'pattern' => 'form-builder/elements///',
    'route' => 'form-builder/element/',
    'defaults' => [
        'id' => null,
        'siteHandle' => Craft::$app->getSites()->getPrimarySite()->handle,
        'action'    => 'index'
    ]
];

if no siteHandle is passed I use the Craft::$app->getSites()->getPrimarySite()
craft\controllers\EntriesController
public function actionEditEntry(string $sectionHandle, int $entryId = null, int $draftId = null, int $versionId = null, string $siteHandle = null, Entry $entry = null): Response
if ($siteHandle !== null) {
    $variables['site'] = Craft::$app->getSites()->getSiteByHandle($siteHandle);

    if (!$variables['site']) {
        throw new NotFoundHttpException('Invalid site handle: '.$siteHandle);
    }
}

later on, when there is really nothing at all it just assumes the following
if (empty($variables['site'])) {
    /** @noinspection PhpUnhandledExceptionInspection */
    $variables['site'] = Craft::$app->getSites()->getCurrentSite();

    if (!in_array($variables['site']->id, $variables['siteIds'], false)) {
        $variables['site'] = Craft::$app->getSites()->getSiteById($variables['siteIds'][0]);
    }

    $site = $variables['site'];
}

TL:DR
Craft doesn't use the currentSite that much in the CP, it is determined by the current element.siteId or the siteMenu (in js). As soon as you enter the CP the selected site in the menu will be stored in your Javascript session, when you click on create new entry you'll get routed to the site that is specified in your session. I think it's best to manage it the same way


---

