Subsite¶
A Subsite is a self-contained area within a Plone site that acts as its own navigation root. Content placed inside a subsite gets its own navigation, theming, footer and search scope, while still living inside the same Plone site. This makes it possible to run several visually and structurally distinct sites from a single backend.
Overview¶
A Subsite is a container content type that is marked as a navigation root. Being a navigation root has two consequences a frontend cares about:
Navigation (
@navigation,@contextnavigation,@navroot) is scoped to the subsite rather than the main site root.Root-level services such as
@footer,@linklistand@popular-searchesresolve to the subsite, so each subsite can carry its own footer, link lists and popular searches.
The logo viewlet is overridden so that, even on a subsite, the site logo always links back to the main site root – giving visitors a way to navigate out of the subsite.
Content Type¶
Subsite A folderish content item that holds the content of the subsite. It can contain content pages, news folders, media folders, contact folders and the standard Simplelayout blocks.
Configuration Fields¶
The Subsite carries a Configuration fieldset of optional theming fields. These
all use the subsite_ prefix, which is how the @subsite endpoint discovers
them.
subsite_logo Image used as the subsite logo.
subsite_mobile_logo Image used as the subsite logo on small viewports.
subsite_primary_color
Primary brand color for the subsite (e.g. #ff0000).
subsite_secondary_color Secondary brand color for the subsite.
subsite_base_font Base font for body text.
subsite_heading_font Font for headings.
Additional subsite-scoped settings (preview configuration and popular searches) are provided by a manage behavior and are editable only by users who can manage the subsite.
@subsite¶
Returns the subsite theming configuration. The endpoint collects every schema
field on the subsite whose name starts with subsite_, strips the prefix, and
returns the values under a data object together with the subsite title. The
frontend uses this to apply per-subsite branding (colors, fonts, logos).
The endpoint is registered on the Subsite itself. When the current context is a
page inside a subsite, the component resolves the request to the owning
subsite’s @subsite URL.
GET /Plone/my-subsite/@subsite HTTP/1.1
Host: localhost:8080
Accept: application/json
Response structure:
{
"@id": "http://localhost:8080/Plone/my-subsite/@subsite",
"data": {
"title": "My Subsite",
"primary_color": "#ff0000",
"secondary_color": "#00ff00",
"logo": null,
"mobile_logo": null,
"base_font": null,
"heading_font": null
}
}
The keys inside data correspond to the configuration field names with the
subsite_ prefix removed (subsite_primary_color becomes primary_color), plus
the subsite title. Each value is the standard REST serialization of the field,
so image fields (logo, mobile_logo) serialize to their usual image
representation when set. Fields are only included when the requesting user has
read permission for them.
Expansion behaviour¶
@subsite is also an expandable component, but it does not embed its full
data when expanded. For caching reasons the expanded component only returns its
@id and a hint to fetch it separately:
GET /Plone/my-subsite?expand=subsite HTTP/1.1
Host: localhost:8080
Accept: application/json
Expanded component:
{
"@components": {
"subsite": {
"@id": "http://localhost:8080/Plone/my-subsite/@subsite",
"data": {
"msg": "Not extandable for caching reasons, please call @id in a separate request."
}
}
}
}
The subsite component is only present when the current context is a subsite or
lives inside one. On the plain Plone site root it is absent. When the context is
a page inside a subsite, the component’s @id points at the owning subsite’s
@subsite endpoint. The frontend should follow that @id in a separate request
to read the actual configuration, which keeps the per-page content responses
cacheable.
Root-level services on a Subsite¶
Because a Subsite is a navigation root, the navigation-root services documented on the Navigation page resolve to the subsite when called on or inside it:
@navrootreturns the subsite as the navigation root.@footerreturns the subsite’s footer fields (schema fields prefixedfooter_).@popular-searchesreturns the subsite’s popular searches, each linking to an@es-searchquery scoped to the subsite.
@popular-searches on a Subsite¶
Returns the popular search terms configured for the subsite. Each item links to a search within the subsite.
GET /Plone/my-subsite/@popular-searches HTTP/1.1
Host: localhost:8080
Accept: application/json
Response structure:
{
"@id": "http://localhost:8080/Plone/my-subsite/@popular-searches",
"items": [
{
"title": "search 1",
"@id": "http://localhost:8080/Plone/my-subsite/@es-search?SearchableText=search 1"
},
{
"title": "search 2",
"@id": "http://localhost:8080/Plone/my-subsite/@es-search?SearchableText=search 2"
}
]
}
When no popular searches are configured, items is an empty array.
Integration Guide¶
Applying subsite branding¶
JavaScript:
async function fetchSubsiteConfig(subsiteUrl) {
const response = await fetch(`${subsiteUrl}/@subsite`, {
headers: { 'Accept': 'application/json' }
});
const data = await response.json();
return data.data;
}
const config = await fetchSubsiteConfig('http://localhost:8080/Plone/my-subsite');
document.documentElement.style.setProperty('--primary', config.primary_color);
document.documentElement.style.setProperty('--secondary', config.secondary_color);
Resolving the subsite from any page¶
When rendering an arbitrary page, read the subsite component to find the
owning subsite, then fetch its configuration:
JavaScript:
async function resolveSubsite(pageUrl) {
const page = await (await fetch(`${pageUrl}?expand=subsite`, {
headers: { 'Accept': 'application/json' }
})).json();
const component = page['@components'].subsite;
if (!component) {
return null; // not inside a subsite
}
const config = await (await fetch(component['@id'], {
headers: { 'Accept': 'application/json' }
})).json();
return config.data;
}
Python:
import requests
page = requests.get(
'http://localhost:8080/Plone/my-subsite/some-page',
params={'expand': 'subsite'},
headers={'Accept': 'application/json'},
).json()
component = page['@components'].get('subsite')
if component:
config = requests.get(
component['@id'],
headers={'Accept': 'application/json'},
).json()
print(config['data']['primary_color'])