Understanding Multisite and routing

Let’s say we have a site A and B, the route for site A is https://example.com/lv and site B is https://example.com/en. In CMS → Edit Site we are setting a site prefix to /lv and /en respectfully.

Here is the link to doc (Multisite - October CMS - 3.x) and it is said:

October CMS is configured to automatically detect a matching site based on the browser’s preferred language when the following conditions are met. 1.) All sites in the group have a prefix set. 2) There are no other sites matching the base URL.

https://yoursite.tld/en - Displays the English
https://yoursite.tld/fr - Displays the French
https://yoursite.tld - Redirect based on language preference (IMHO here could be the problem)

So the issue is that the url: https://example.com/anything-leading-to-404 - is 301 redirected to https://example.com/lv as it is a default language. It should be throwing 404 instead. Anything that matches https://example.com/lv/any-404-page - is handeled as expected.

Any suggestions how to improve that part?

Hi @mrmax ,

I ran a test using a fresh installation with the following site configurations (2):

English Site

  • Name: English
  • Unique Code: en
  • Locale: “en - English (United States)”
  • Route Prefix: Checked “Use a CMS route prefix” with the value “/en”.

French Site

  • Name: French
  • Unique Code: fr
  • Locale: “fr - Français”
  • Route Prefix: Checked “Use a CMS route prefix” with the value “/fr”.

When I enter the URL http://domain/pagedoesntexist, it redirects me to http://domain/en/pagedoesntexist, which results in a 404 error: “Page Not Found - We’re sorry, but the page you requested cannot be found.”

I recommend checking your routing settings to ensure there are no fallback rules that redirect to the homepage when a 404 error occurs (perhaps in the .htaccess file?).

There is config for this in config/cms.php… Should we include a “404” setting, would that solve it?

/*
|--------------------------------------------------------------------------
| Site Redirect Policy
|--------------------------------------------------------------------------
|
| Controls the behavior when the root URL is opened without a matched site.
|
| detect    - detect the site based on the browser language
| primary   - use the primary site
| <site_id> - use a specific site identifier (id)
|
*/

'redirect_policy' => env('CMS_REDIRECT_POLICY', 'detect'),

When I enter the URL http://domain/pagedoesntexist , it redirects me to http://domain/en/pagedoesntexist , which results in a 404 error: “Page Not Found - We’re sorry, but the page you requested cannot be found.”

Exactly, 301 redirect should not be here, instead it should fire 404 immidiatly.

Here is the intended behaviour we think could be good in case of multisites:

Let’s say we are vising the page1 and this page exists in themes/acme/pages with slug page1: http://domain/page1 - 301 redirect to it’s language version.

If page2 with slug page2 doen’t exist - http://domain/page2 - 404 error.


Tricky part

In case if we have a page.htm with url = “/:slug” or wildcards like url = “/:slug*”

At first we should look for existing pages with slug variable value, only if not found run this page without any redirects, so that the control is given to a component or php section of this page and it will decide about redirects.

Maybe having pages with url = “/:slug” is not recommended but it works right now


Right now to fix the things we are thinking of adding few lines to .htaccess to prevent any requests to non language prefixed url. It is temporary solution and not generic as language prefixes should be hardcoded into the .htaccess.

After doing more tests, I think then using Multisite and trying to access any 404 page route without lang prefix, like http://domain/any-non-existing-page - the multisite router tries to use /any-non-existing-page like it is a language code, and if not found redirects to /en/any-non-existing-page , if not found goes 301 to 404.

It could be good to have some event or middleware hook so that the control is more custom. Any suggestion ?

Already tried App::before in routes.php without success as it, imho, doesn’t have a priority for multisite.
I’m honestly simply guessing here.

The solution we found is not generic, but does the thing through the Middleware extending the CmsController. We check if $request->path(); matches the lang prefix and return $next($request); if it does, parsing and firering custom code in case it doesn’t match.
In our project we are using only 1 theme so looping through Pages in our case is ok, but it is possible to just return 404 in case if lang prefix is not present.

Here is the solution to the homepage, code is in middleware handle function:

// HOMEPAGE
if ($request->path() === "/" or empty($request->path())) {
	// default locale
	$locale = "lv";
	$deafultPage = "home";
	$defaultSiteId = 1;

    Site::setActiveSiteId($defaultSiteId);
    $theme = Theme::getActiveTheme();
    
    $page = Page::loadCached($theme, $deafultPage);
    if (! $page) {
        $page = Page::load($theme, $deafultPage);
    }

    Cms::setUrlPrefix('/'.$locale);
    $controller = new Controller($theme);

	$pageContent = $controller->runPage($page);

    return new Response($pageContent, 200);
}

This code returns 200 responce with home page for the “/” path, Cms::setUrlPrefix(‘/lv’); is responsible for further |page filter so that all links have default /lang_prefix. IMHO this is good for the SEO, so that the homepage doesn’t redirect. Of course the ability to have a session stored lang is not oppted in this case.

this solution seem ok, but main question is, why prefixing a default language?
when you have primary site for example in “lv” then why you adding prefix? for me its strange. to “ensure” someone that this is on /lv as “lv”.

my site is in slovak (sk) - www.snipi.sk and when i want users, to visit my page in english, then i prefixed with /en to ensure users that this will be their lang. this wont confusing site and cms to looking for “correct” page or annoying redirecting when server error or 404.

Thanks, this is a very good point btw. I have to do it this way because of the migration from old to new site, but I will change this in closest future by creating a necessary 301 redirects and propper canonical links.