My initial reaction to this question was to say to use a shared block, but you'd still need to create the pages and drag the block into a content area. Personally, I think this is the best way to go.
But you could possibly accomplish what you want by using partial routing and some site settings. So with that option, a couple questions:
- Will "PageA" ever have child pages managed in EPiServer?
- Are the "SectionA", "SectionB", and "SectionC" pages the same page type?
Thanks for the reply Chris. A shared block could be used but the issue is that there are hundreds of pages with the same content. The editors feel that there will be to much work creating pages.
Yes, "PageA" will have child pages.
"SectionA", "SectionB", and "SectionC" may be different page types.
Nope, "PageA" will have the exact same content everywhere. Thats why we want to store it in a global place and replicate the content at several locations. So when I edit "/Global/PageA" the changes are also displayed in the exact same way for "/SectionA/PageA", "/SectionB/PageA" and "/SectionC/PageA".
My question was about the children of "PageA"...
Will there be "/SectionA/PageA/SubPageA" and "/SectionB/PageA/SubPageB"?
Or will all of the children of "PageA" only be under "/Global/PageA/"?
OK I missed that part :)
"PageA"'s children will be exactly the same under each section.
The entire structure of child pages would be created globally. All of the children of "PageA" will be under "/Global/PageA/.
Ok. So it looks like you might be able to handle this with a partial router, but this might cause issues with other things (which I haven't explored). This might at least get you started on the path you are trying to accomplish.
Here's the partial router:
public class GlobalContentPartialRouter : IPartialRouter
{
public object RoutePartial(PageData content, SegmentContext segmentContext)
{
var loader = ServiceLocator.Current.GetInstance();
// The reference to the global folder (sitting under the Root) is found in my StartPage properties
var rootContentReference = loader.Get(ContentReference.StartPage).GlobalContentReference;
// Put each of the URL segments from the RemainingPath into a List
var urlSegments = segmentContext.RemainingPath.Split('/').Where(s => !string.IsNullOrEmpty(s)).ToList();
PageData routedContent = null;
// We'll go through each URL segment one at a time to ensure the proper page hierarchy stays intact
foreach (var segment in urlSegments)
{
// Make sure we have a ContentReference to get children
if (ContentReference.IsNullOrEmpty(rootContentReference))
{
return null;
}
// Get the child where the URL segment matches
routedContent = loader.GetChildren(rootContentReference).FirstOrDefault(c => c.URLSegment == segment);
if (routedContent != null)
{
rootContentReference = routedContent.ContentLink;
}
else
{
// If no child is found, the page doesn't exist in the global folder, or however deep in the page tree we are
// So we immediately return null (404)
return null;
}
}
// Retun null (404) if nothing was found
if (routedContent == null)
{
return null;
}
// Setting the RemainingPath to string.Empty was important in order to get this to work
segmentContext.RemainingPath = string.Empty;
segmentContext.RoutedContentLink = routedContent.ContentLink;
// Return the routedContent that was found.
return routedContent;
}
public PartialRouteData GetPartialVirtualPath(PageData content, string language, RouteValueDictionary routeValues, RequestContext requestContext)
{
// This might be able to be implemented some how...
return null;
}
}
And to use it, here's the initialization module:
[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class GlobalContentPartialRouterInitialization : IInitializableModule
{
public void Initialize(InitializationEngine context)
{
var partialRouter = new GlobalContentPartialRouter();
RouteTable.Routes.RegisterPartialRouter(partialRouter);
}
public void Preload(string[] parameters) { }
public void Uninitialize(InitializationEngine context) { }
}
Then you can set up your page tree like this:
-Root
--Global
---PageA
----SubPageA
---PageB
----SubPageB
--StartPage
---SectionA
---SectionB
---NotASection
These are valid URLs:
- domain.com/en/SectionA
- domain.com/en/SectionA/PageA
- domain.com/en/SectionA/PageA/SubPageA
- domain.com/en/NotASection/PageA/SubPageA
- domain.com/en/PageA/SubPageA
You get the idea...
Some issues with this approach:
So obviously there are pro's and con's to both approaches (blocks vs. partial router)...
I have not really tested it myself but there is a ClonedContentProvider in the Alloy sample packages that appears to do what you are looking for.
Hello!
We have a website where we want to display the same content at multiple places in the page tree.
To make the life easier for editors and avoid having to create the same content several times we would like to create one page and then display it at multiple places in the page tree. This could be solved by creating pages at these locations and use EPis shortcut function and "Fetch content from page..." but the editors whould still have to create many pages.
For example let's say we have three pages: "SectionA", "SectionB" and "SectionC". They should all have a child page called "PageA".
/SectionA/PageA
/SectionB/PageA
/SectionC/PageA
Whenever any of these URL:s would be requested we would like to check if the page exists in the EPi page tree. If it does it should display the page, and if not is should look for the page at another location (for example "/Global/PageA") and display that page's content as if it existed at the requested URL.
Is there a simple solution where this could be done with MVC routing? Or maybe some other solution?