Flux supports publishing multiple web sites from one implementation. The core of this is provided through the "Website mappings" tool within the "Content and Asset Management" menu group;
This tool allows you to define any domain names that will be responded to from this flux installation and provide flux with information about where to get it's content from for the domain and which item of content should act as it's homepage. The form for defining an entry is shown below;
As you can see, you specify which node contains the domains content (root node) and which node should be the homepage. For this to work correctly you will need to define a content type that acts as a container for other content. This can be called "website" or "channel" (or in fact anything that makes sense to you). You define the content type purely to act as a container and then add content into this. You then create your content within these containers;
In the example above, I would then specify "Main Website" as the root node and "Homepage" as the home node in my website domain mapping.
This all integrates as standard to the URL re-writer engine, so accessing flux from various domains works out of the box. However, you do have to do a bit of extra work when it comes time to building any menus as you'll need to work out where your navigation starts from. IE: Site A - we'd want top level menus from within the defined root of Site A, whilst Site B would need entries from Site B and so on.
To do this, you can use code similar to that below;
public static ContentObject GetRoot()
{
// First, see if our page is within a known mapping path
// for the domain we're using....IE: If localhost is mapped to /1/2/3
// and our page is /1/2/3/4 we know the mapping holds a valid root.
string DomainName = HttpContext.Current.Request.ServerVariables["SERVER_NAME"];
DomainMappings dm = new DomainMappings();
DomainMapping m = dm.GetByDomain(DomainName);
if (m != null)
{
ContentObject rootPage = m.Rootpage_Live;
if (rootPage != null)
{
if (RequestCache.NodeObject.PK_ID == -1) return rootPage;
string rootPath = rootPage.NodePath + rootPage.NodeName;
if (RequestCache.NodeObject.NodePath.StartsWith(rootPath))
return rootPage;
}
}
// Search up the tree until we find a channel type
ContentObject trav = RequestCache.NodeObject.ParentLive;
while (trav != null)
{
if (trav.FK_STypeID == "channel") return trav;
trav = trav.ParentLive;
}
return null;
}
In this instance, RequestCache.NodeObject returns the ContentObject of the page we're rendering and we've defined our container type as having a type code of "channel". Let's walk through the code;
string DomainName = HttpContext.Current.Request.ServerVariables["SERVER_NAME"];
DomainMappings dm = new DomainMappings();
DomainMapping m = dm.GetByDomain(DomainName);
This is just asking the domain mapping system to give us information about the domain the website is presently being accessed as. This will tell us the ID for the homepage and the content container.
if (m != null)
{
ContentObject rootPage = m.Rootpage_Live;
if (rootPage != null)
{
if (RequestCache.NodeObject.PK_ID == -1) return rootPage;
string rootPath = rootPage.NodePath + rootPage.NodeName;
if (RequestCache.NodeObject.NodePath.StartsWith(rootPath))
return rootPage;
}
}
If we were able to find a mapping record for the domain we're accessing the site at, we try to get the rootpage from the mapping record. Provided we get a root page we then ensure that the page we're rendering sits within the container specified by the mapping. It's possible that you have multiple containers, not all of which correspond to a domain and you allow users to navigate across these containers - for this reason we ensure that the page we're rendering sits within the container the mapping record states is the content container. If it's not, we drop through to the next part of the code, but if it is, then we know that the root node specified by the mapping is the correct one and return it.
There is one strange looking line of code in that part though;
if (RequestCache.NodeObject.PK_ID == -1) return rootPage;
What's this all about? How can you have a node object with an ID of -1? Well, conventionally you can't, but in the implementation that this code is taken from we have some non-CMS portions of the site that still use the same master page templates and user controls etc, even though these parts of the site aren't controlled by the CMS. In these instances, the request cache is initialised with dummy content so that we can still get back a valid menu etc. In the line of code above, we're basically saying if our content being rendered isn't pulled from CMS, then trust the mapping record for the domain for where to get content from etc.
Ok, next - if we didn't get a mapping record or if our rendered page is outside of the container that the mapping record says we should use, we try to intelligently find what the container node is;
// Search up the tree until we find a channel type
ContentObject trav = RequestCache.NodeObject.ParentLive;
while (trav != null)
{
if (trav.FK_STypeID == "channel") return trav;
trav = trav.ParentLive;
}
This starts by looking at the parent of the template we're rendering and keeps traversing up the tree until it finds a node that is a channel node type (our prescribed content container) - when it finds one, it uses this as the root irrespective of any mapping records etc.
Hope this helps.