Wagtail multisite on same domain
Answering an old question for future enquirers. @gasman has nailed the issue with this ask in his comment above:
In Wagtail's terminology, sites and domains are exactly the same thing, so "multiple sites on the same domain" doesn't make sense.
However, I was able to work around this using the following steps.
I needed this kind of arrangement so that different site-wide settings could be used for mainsite.com and mainsite.com/subsite (example names).
While I can always enforce different settings for different parts of my website in the code I've written, I wanted this to work for third-party packages as well such as wagtailmenus
etc.
E.g. I wanted the menu-items for all pages on mysite.com to be different from those for all pages under and including mainsite.com/subsite.
Note that this is a crude approach, and there can be unforeseen issues with this. But, so far, it has worked fine for me.
-
Create a new site in Wagtail admin for your subsite.
Use the samehostname
as was used for the mainsite, but add a dot in the end for satisfying uniqueness. We'll not use thishostname
anyway.
Also, use the same root page asmainsite
's. This is for generating the URLs correctly. -
Create a small middleware:
if request.path.startswith('/subsite'): # find subsite and mainsite using Site.objects.filter(site_name='') queries subsite.hostname = mainsite.hostname request._wagtail_site = subsite
This will make sure that all requests coming to the subsite get their specific
_wagtail_site
attribute but with the correcthostname
. This will let your code and all other code in third-party packages to determine the site as subsite. But, if a third-party package uses Django'ssite
instead of Wagtail'sSite
, I'm not sure if this will still work. -
Generally, you would not want the subsite to be set as default website. To enforce this, include the following in any of your apps'
admin.py
(I added some extra validations as well):def clean_subsite(self): instance = self if instance.site_name != 'Subsite': return super(Site, self).clean() if instance.is_default_site: raise ValidationError({'is_default_site': ["'Subsite' cannot be made the default website."]}) mainsite = Site.objects.filter(site_name='Mainsite').first() if not mainsite: raise ValidationError({'hostname': ["'Mainsite' must exist before saving 'Subsite'."]}) if instance.hostname != (mainsite.hostname + '.'): raise ValidationError({'hostname': ["Hostname for Subsite is just a placeholder (Subsite uses the same domain as Mainsite does)." + " Use the Mainsite's hostname with a '.' as suffix for satisfying uniqueness constraint."]}) from wagtail.core.models import Site Site.add_to_class("clean", clean_subsite)
As the
Site
filter queries above are usingsite_name=''
, do not change the names of Mainsite and Subsite in the Admin (without modifying these queries in the code). -
Lastly, be warned that the query
Page.objects.in_site()
will work incorrectly for bothmainsite
andsubsite
.
Either do not usein_site()
, or override it. This function uses:self.descendant_of(site.root_page, inclusive=True)
For mainsite, we need to exclude the descendants of
subsite
's root page. For subsite, we need to include only the descendants ofsubsite
's root page.