To summarize in one sentence, what I’m trying to achieve: I’d like to separate the common core functionality of all of my sites from the site packages and have dedicated/interchangeable packages which render the html.
My setup
I have a multisite setup with four sites, currently. Every site does have a distinct site package:
- My.SiteA
- My.SiteB
- My.SiteC
- My.SiteD
There is a base package which handles most of the logic: My.Core
. My.Core
also defines the Document, Component and Content nodetypes which My.SiteA-D
use. Basically My.SiteA-D
are “empty” site packages, because they do not define nodetypes or have fusion prototypes, unless they need something specific for this site. So far, no problems, if every site would look alike. Unfortunately they don’t.
So, I decided to create dedicated “theme” packages in order to render the different looks of the websites. I did this, because I want to be able to switch the themes easily without touching the site package. So, I created the packages:
- My.ThemeOne
- My.ThemeTwo
- My.ThemeThree (for site My.SiteC and My.SiteD)
The problem(s)
Every node is of the base nodetype defined in My.Core
. E.g. My.Core:Document.SomePage
or My.Core:Component.SomethingFancy
. While intended at first this has the drawback that I can’t create a document node for just one of the sites.
If I create a document node for a specific site, e.g. My.SiteB:Document.Instrument
, which won’t ever be used in one of the other sites, I can’t exclude it via constraints
in the backend of the other sites. I could only set a constraint for the base My.Core
, but that would affect My.SiteB
as well and is therefore useless.
To solve this, I could create nodetypes for every site, which just inherit from My.Core
:
'My.SiteB:Document.SomePage':
superTypes:
'My.Core:Document.SomePage': true
'My.SiteB:Constraint.AllowInSiteB': true
#...
constraints:
'*': false
'My.SiteB:Constraint.AllowInSiteB': true
But (and here my problem kicks in): Creating site specific nodetypes breaks the “template mechanism”. Because right now the nodetype rendering relies on every node type being a My.Core:*
nodetype. This is achieved by an additional matcher case for the root
fusion path:
root {
themedDocumentType {
@position = 'before documentType'
condition = Neos.Fusion:CanRender {
type = ${q(documentNode).property('_nodeType.name') + '.' + Configuration.setting('My.Core.templatePackages.' + site.name)}
}
type = ${q(documentNode).property('_nodeType.name') + '.' + Configuration.setting('My.Core.templatePackages.' + site.name)}
}
}
#Settings.yaml
#----
My:
Core:
templatePackages:
site-a: 'My.ThemeOne'
site-b: 'My.ThemeTwo'
site-c: 'My.ThemeThree'
site-d: 'My.ThemeThree'
E.g.: On the site My.SiteB
the document nodetype My.Core:Document.SomePage
would be rendered using the prototype My.Core:Document.SomePage.My.ThemeTwo
(which is defined in the package My.ThemeTwo
). This works only with a common nodetype.
Also: If I would create site specific nodetypes, the theme packages can’t just define one prototype to render a core nodetype. In order to render the nodetypes for Site.C
and Site.D
, My.ThemeThree
would have to define the prototypes My.SiteC:Document.SomePage.My.ThemeThree
and My.SiteD:Document.SomePage.My.ThemeThree
.
Furthermore I could not switch the themes easily by changing just one line of code in Settings.yaml
, because I would have to make sure, that e.g. My.ThemeOne
would define the correct nodetypes.
To sum it up, I’m stuck here. Maybe there’s a simple solution, I don’t see. I’m overcomplicating things probably, too. To summarize in one sentence, what I’m trying to achieve: I’d like to separate the common core functionality of all of my sites from the site packages and have dedicated/interchangeable packages which render the html. So, have basically a integrational and a presentational and a site package.
Is that possible somehow? If not, would appreciate any hints how I could use a better approach.
One idea I came up with is, choosing the prototype which renders a nodetype by exchanging the package name:
prototype(My.Core:NodeTypeRenderer) < prototype(Neos.Fusion:Component) {
fullNodeTypeIdentifier = ${q(node).property('_nodeType.name')}
nodeTypeName = ${String.split(this.fullNodeTypeIdentifier, ':')[1]}
themePackage = ${Configuration.setting('My.Core.templatePackages.' + site.name)}
renderer = Neos.Fusion:Renderer {
type = ${props.themePackage + ':' + props.nodeTypeName}
}
}
So, My.SiteB:Document.SomePage
would be rendered using My.ThemeTwo:Document.SomePage
and My.Core:Component.SomethingFancy
would be rendered using My.ThemeTwo:Component.SomethingFancy
. The problem is, that this could affect third party packages.