Custom rendering of content in XhtmlString areas
In CMS 7.5, the TinyMCE editor is basically equivalent to a regular ContentArea, which can be very useful. Sometimes, however, you want to render your content types with more than just it's default properties.
If you want to render your content, whether it's a block, a page, a commerce category or a product, in the middle of your editorial content, just drag-and-drop it into an XhtmlProperty
. Quite simple, as shown below. The way you normally do this is by having a view with the same name as your content type accepting a view model of the same type. So, if your content type is called ArticlePage
, you could have something like ~/Views/Shared/ArticlePage.cshtml
(if you have configured more view locations, you can tweak this path as you'd like) accepting a model of type ArticlePage
Now, however - that'll leave you with a view model of that exact content type. If you want to include information from external sources, other pages in your system or otherwise dynamic stuff, you're out of luck. Technically, you can write inline code in the views, but don't. Just don't.
Here's how you give it a completely customized renderer, with it's own controller and all. I'm going to be using a ProductVariant
class in a Commerce project as my content type, but this applies to every kind of IContent
. I want a customized rendering of it when I pull it into the main body of an article, to add things like it's price and other stuff which is not stored on the content type itself.
Step 1: Create your controller and view model
So first, you should define a view model that contains all the necessary stuff to display, like I've done here:
Next, you need a controller to handle all your logic:
Notice that it's still taking in a ProductVariant
as it's currentContent
parameter, but returning an InlineArticleProduct
. Also, it's inheriting from ActionControllerBase
. Apart from that, you can now demand things from your IoC container in the constructor as usual, if needed.
Step 2: Create your view
The view is pretty straightforward. As usual, it needs to have the same model type as the controller passes to it.
Step 3: Tell EPiServer about it
If you build and run your site now, nothing special happens. You need to let EPiServer know these things exist. You can do that by registering your new controller and view in an IViewTemplateModelRegistrator
, like shown below. EPiServer seems to pick up this class automatically as long as it inherits this interface.
Things to notice are:
Tags
- this tag is what will tie all this magic to the view and tell it to use your own implementation instead of the convention based one.TemplateType
- this should be the type of your controller.Path
- the path to your view. One should think this would not be necessary since you have an entire controller, but it doesn't seem to pick up on the rule without it.TemplateTypeCategory
- Set this to beTemplateTypeCategories.MvcPartialController
to tell EPiServer that we're using a separate controller for this.
Also, if you're doing this with things that are usually dropped as links (such as PageData
-based types), you will need a descriptor telling TinyMCE to create a content block, like shown below.
Step 4: Tie it all up in your view
You remember the tag we set in the previous step? In your view where you'd normally have something like this:
@Html.PropertyFor(m => m.CurrentContent.MainBody)
...you need to add this tag. Like so:
@Html.PropertyFor(m => m.CurrentContent.MainBody, new { Tag = "InlineContent" })
Notice that the tag I'm passing in to the additionalViewData
parameter has to match the one you set in step 3. That should be about it - you now have custom rendering of any content type, in any ContentArea
or XhtmlString
property on your site.