Experience Editor. It’s really great when it’s all working. But it’s not difficult to make mistakes in how you set up your site that lead to difficult to diagnose failures in the WYSIWYG editor. I came across one such issue recently that seemed like just the sort of thing Google needs to know about to save future developers (and probably Future Me as well) from the pain of debugging it.
I was assigned two QA bug reports for a site I’ve been building. They were both related to one particular rendering – which allowed editors to pull in external content via
<iframe/> tags injected into the page:
- The first bug report said that trying to add this rendering to a page on the QA server caused Experience Editor to throw up a modal dialog with the cryptic “
An error occurred.” as its message. The rendering did not end up on the page, but Experience Editor kept working after the dialog was dismissed:
- The second report said that on a page that already had this component, Experience Editor was now failing to render the component in edit mode, and displaying an exception from its parent container component instead: However the page was working fine in Preview and Published mode. For Google’s benifit, the key parts of the two exceptions here are:
Error Rendering View: /Views/PageLayout/66-33.cshtml: Error while rendering view: '/Views/PageLayout/66-33.cshtml' (model: 'Sitecore.Mvc.Presentation.RenderingModel, Sitecore.Mvc'). at Sitecore.Mvc.Presentation.ViewRenderer.Render(TextWriter writer) at Sitecore.Mvc.Pipelines.Response.RenderRendering.ExecuteRenderer.Render(Renderer renderer, TextWriter writer, RenderRenderingArgs args)
Inner Exception: Fields field cannot contain any of the following symbols: ():= at Sitecore.Diagnostics.Assert.IsFalse(Boolean condition, String message) at Sitecore.Pipelines.GetChromeData.GetChromeDataProcessor.GetFieldEditorButton(Item item) at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext() at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext() at System.Collections.Generic.List`1.InsertRange(Int32 index, IEnumerable`1 collection) at Sitecore.Pipelines.GetChromeData.GetRenderingChromeData.GetCustomButtons(RenderingItem renderingItem) at Sitecore.Pipelines.GetChromeData.GetRenderingChromeData.Process(GetChromeDataArgs args) at (Object , Object )
My initial reading of these issues made me think that the two bugs were probably related, and that giving editors the ability to use raw markup to add in
<iframe/> elements is a really good way of allowing them to accidentally break the page’s markup in some way. I also noted that I could not reproduce the problems on my development instance. They only happened on QA. So that started me thinking that dodgy markup can cause issues in Experience Editor, because so much of its behaviour relies on being able to inject all the “chrome” that editors use to control renderings. So I went through some basic checks to try and spot any obvious errors:
- I looked at the content in the DataSource items available for this component, to check that they were not injecting badly formed HTML.
- I looked at the Razor file for the rendering, to make sure it did not include any badly formed HTML.
- I looked at the Placeholder Settings, to make sure the component was allowed in the placeholders being used
- I checked the item security on the renderings, placeholder settings, data sources and pages, just in case those had been messed up
None of those came up with anything looking wrong… And to be honest, that was not surprising, as the same code and content from the Master database was working without issues on my development machine.
Next stop on my debugging voyage was the old “pull it all appart and put bits back until it breaks” ploy. So:
- I created a new Rendering Definition that pointed at the original CSHTML file, but didn’t have any other settings applied. When placed on a page, that worked fine.
- I create a new Placeholder Settings entry for the new Rendering Definition. I was able to add that via Experience Editor without issue.
- I added the DataSource Template settings from the original rendering to the new one. The new one still worked.
- I added the DataSource Location settings from the original rendering to the new one. And it still worked.
- I added the caching settings from the original rendering to the new one. The new one still worked.
- I compared all the other settings on the original rendering with the new one, and found only one other difference: Experience Editor Buttons. So I added the custom button from the old one to the new one. And BOOM! The new one broke in the same way as the old one…
With that in mind, I re-read the exception messages I’d been seeing, and noted two things: Firstly the stack trace included the type
Sitecore.Pipelines.GetChromeData.GetChromeDataProcessor.GetFieldEditorButton so it had been giving me a hint about this all along, and secondly the main error was “
Fields field cannot contain any of the following symbols: ():=” – which gave me a big hint.
So I switched over to the Core database, and drilled down to the custom Experience Editor Button definition that I’d added to my new Rendering. Looking through the fields I spotted:
Bingo: On the QA server, the field where you can specify what DataSource-Fields are edited by this button had acquired a rogue colon at the end of the name it was specifying. And the exception message did say that colons (as well as brackets and equals-signs) were not allowed. I’m guessing a copy/paste error was responsible for that.
Interestingly, I did not have the custom button item in Core on my dev machine (I’d not synched items in Core for a while, and hence didn’t have other people’s changes) and instead of failing with a “you are missing the item defining this button” error, my development instance was just carrying on happily anyway… Which explains why I could not reproduce the bug reports locally.
And once that colon was removed, and the item saved, everything went back to working properly on QA.