Selectively Overriding Page Type Template Mapping
One thing which has always been a mild frustration to me is EPiServer’s template mapping. The concept of each Page Type only having one template always seemed restrictive. The concept works fine in 95% of cases, but the other 5% can be a pain. What if you have one page you want to do something a little (or a lot) differently than other pages of the same Page Type?
In these cases, the obvious solution is to create a new Page Type and specify a different template for it. But I hated the idea of creating a new Page Type just to get a new ASPX file to render. You have to copy all the properties over to the new type, and you now have to keep the two Page Types in sync. With one extra type, it’s not so bad. When you get a dozen or so, it becomes a problem.
Furthermore, right now we have a client coming off a Serena Collage install, managed in Dreamweaver. (For those not familiar, Collage was really an SCM system, re-purposed as a CMS. You didn’t manage “content,” as much as you managed raw HTML files. Think Subversion, but with some CMS-ish functionality wrapped around it. Collage was discontinued and went unsupported two years ago, and I don’t think we’ll ever see another CMS quite like it.)
Consequent to this experience, the client’s Web guy is very hands-on, and has created many landing pages which are painstakingly hand-crafted HTML. To make their transition to EPiServer less painful, we needed to give him the ability to “escape” from type-bound templates whenever he felt the need, and be able to hand-write HTML in his editor of choice.
So, I set out to find a way to be able to specify the template for a particular page. I originally started down the road of creating a bizarre contraption of dynamically-loaded User Controls, but I ended up just extending the URL rewriter, which was much easier than I expected.
My TemplateOverrideRewriteProvider allows you to do two things:
- Specify a custom ASPX file in a property called “CustomTemplate” (add it to your Page Types as a simple string property). If this property exists and has a value, the URL rewriter will send the request there.
- Put an ASPX file in a specific directory, named for the page ID. If this file exists (ex: “27.aspx”), requests for that page ID will use that ASPX file. (Essentially the same as above, but you enable it by creating a file, rather then specifying the file name.)
The thing that made it easy is that we’re not hacking the whole URL rewriter. In fact, we’re letting the core URL rewriter do its thing, we’re just tacking on some extra stuff at the end. So, after we’ve called the base rewriting functionality, then we check to see if our page has a custom template specified, or if there’s an APSX page named for the ID. If there is, we rewrite a little further to accommodate it.
The actual mechanics of it are really simple – the “ConvertToInternalInternal” (say that five times fast…) method takes an incoming UrlBuilder object. This is where the request is currently heading. You can do whatever you want with this, primarily by changing the Path property. Change it to whatever you like, an IIS will send the request there instead.
This is in the works for us on a couple of projects. We’re going to use it for situations where we need “application-ish” pages – like search results pages, for example – but we have a lot of logic and properties bound up in our standard Page Type, and we don’t want to recreate and manage a new Page Type just to enable a new template. I’m thinking this will cut down our necessary Page Types on our average install by at least half.
To use it, compile it into your project, and register it in episerver.config. You’ll need to add an element for it under “episerver/urlRewrite/providers” and specify it as the “defaultProvider.” Check the comments in the code also, as there’s a little configuration – you need to specify the directory paths you want to use for your custom templates.
To represent the new concept behind this more appropriately, we’re dividing our template directories up like this:
The “ByPageType” directory is where the previously-standard templates went, to represent Page Types. “ByPageId” contains templates named for page IDs, and “ByCustomMapping” contains templates that editors might enter in the “CustomTemplate” property.