Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • DanH 36 posts 61 karma points
    Nov 30, 2010 @ 17:21
    DanH
    0

    Umbraco backend structure - best practices for separating layout and content

    I'm starting this thread is to discuss the best way to design the backend site structure to separate the layout from the content.  In almost all of sites I create, I only want to give the client very basic "writer" permission.  I don't want them to see the internal guts, nor do I want them to be able to break anything even if they try, so it is vital that I hide the layout data from them.  I came up with a solution, but it's not without problems, so I'm curious what others have done in this situation.

    Let me back up slightly to explain.  Here's an example of a Simple Approach to a very basic site:

    The layout data:

    • Header Image
    • Left Image
    • Headline
    • umbracoUrlAlias
    • metadata, etc

    The content data:

    • Body Content (Multiline text field)

    Now the typical Umbraco site probably has most of this layout data hard coded into templates or scripted somehow.  There are two big problems with this:

    1. If the layout data is different per page, then each page requires its own template.  Even with master/child templates, this can get unwieldly for even a small site.
    2. More importantly, I really want my site designer to be able to manage the layout data through Umbraco so they can easily upload/crop photos, change headlines, adjust the urlalias, etc - without having to manually edit HTML and FTP images for every page.  So this layout data definintely needs to be in a doctype.

    And so I present the most basic approach to this problem.  One doctype holds the layout data and the content field.  It has a single template:

    Settings View

    I created a writer user next, and locked down their permissions as best I could.  Their view then looks like this:

    Content View

    So as I explained in my intro, this is not acceptable since the layout and content are not separated.  My client will  get confused by the complexity of the layout stuff, and they will undoubtably get curious and break stuff as well.  Yeah, I could put the layout stuff on a separate tab, but that's just one click away, and users love to click stuff they shouldn't.  If Umbraco had a way to hide tabs per user, life would remain simple, but alas that is not the case, so it's time to get a bit more creative.

    Master/Child Template Approach:

    So to separate the layout and content, I created a doctype for the layout data called Master and a doctype for the content called Simple Text.  Their templates are arranged in a master/child relationship so that the Simple Text template will inherit the Master template.  It looks like this:

    Settings View

    Now, here's the view of the content section:

    Content View

    The About Us node is a Master doctype so it holds the layout data.  Underneath it, the About node is of doctype Simple Text, so it holds the content data.  My site designer can still access the parent node and manage the layout data.  For the writer user, I locked the permissions down so they can only access the child node with the content data.  The layout and content have successfully been separated, but here's where we run into a few  problems.

    1. It's a pain in the butt to individually lock the permissions down like this for every single parent/child node on a site.
    2. The writer user has to drill down a node to update the content.  Not a big deal, but kind of annoying, and they will be a bit confused.  To make it worse, when they do click on the top node they get an ugly permissions error: Error Screenshot.  Uh oh, now they are going to phone me, and I'll have to explain Umbraco document types and templates to the Common Man, who is already so mixed up they think "a browser is a website you can search on".
    3. The writer user has the ability to screw with the URL because it is now based on the name of the node.  No doubt there is some tricky way to get around this with some custom URL rewriting - if you want to open that can of worms.

    The next strategy is what I finally settled on, even though it does have a couple drawbacks itself.  Still awake?  Read on:

    Linked Content Approach

    Learning from my mistakes in the previous strategy, I decided I needed to separate the layout and content not only by document type, but also create completely separate branches in the Content section as well.  To facilitate this approach, I added a Content Picker property type on the layout doctype, Master.  This content property is the key to linking the content to the layout.  Here is what the admin or site designer will see in the Content Section:

    Layout View

    And here is what the writer user will see:

    Content View

    For the writer user, I edited the permissions so that they start in the Content branch.  They never see the layout branch, so I don't even have to worry about the permissions there.  They can screw up the name if they want, and it won't break a thing.  There are no extra clicks or permission errors to complain about either. Great!

    Here's a view of how it was done in the Settings section:

    Settings View

    The Master doctype is the same as before with the addition of the Content Picker datatype.  The Simple Text doctype is still just as simple, with a single property.  The Folder doctype is just an empty doctype used to create the separate branches in the Content section.

    The big thing to notice here is that the Master template uses Umbraco's RenderTemplate method to render the content from the content picker (as highlighted in the screen shot).  That content of course is of type Simple Text.  Of course on a real site there will be additional doctypes/templates besides Simple Text, but the content picker doesn't care what kind of content you pick, so you can create as many doctypes/templates to render as you want.

    I thought I was home free with this approach until I was tweaking my site just before launch, and noticed with SQL Server Profiler that Umbraco was hitting up the DB with two queries everytime I went to a page. 

    exec sp_executesql N'SELECT id, createDate, trashed, parentId, 
    nodeObjectType, nodeUser, level, path, sortOrder, uniqueID, text FROM 
    umbracoNode WHERE id = @id',N'@id int',@id=1112
    select xml from cmsContentXml where nodeID = 1112

    But wait, I thought Umbraco cached all the content data into memory and to an XML file? It turns out that my RenderTemplate method is bypassing the cache and causing the database hits.

    So I did some old fashioned Response Caching.  Since you can't put caching directives into master pages, I did it programatically in the master template's Page_Load event:

            Response.Cache.SetExpires(DateTime.Now.AddMinutes(10));
            Response.Cache.SetCacheability(HttpCacheability.Server);
            Response.Cache.SetValidUntilExpires(true);
            Response.Cache.VaryByParams["*"] = true;

    Ok, now I'm caching again, so it's only hitting the database periodically, which I can live with.  The worst part about this hack is that after a user updates and publishes content, it won't be instantly available on the frontend due to the response caching.  Still, this last approach is my favorite of the the ones reviewed.

    So, am I just being too picky with the whole layout/content separation?  Maybe, I do sometimes obsess over details, and then spend 6 hours posting a blog on a forum.  Then again, I intend to do dozens of Umbraco sites in the future.  I don't want to do things half ass over and over again.  I want to get a dependable, polished model to replicate efficiently.  I want the content area to be professional looking and intuitive for the client.  I want my site designer to be able to leverage the Umbraco backend to flesh out the site with layout items.  And I want the performance of caching without the drawbacks.

    So my question to the Umbraco community, am I missing anything obvious here?  Any other solutions to this layout/content separation dilemma?

    Thanks for reading.

  • Rich Green 2246 posts 4008 karma points
    Nov 30, 2010 @ 18:32
    Rich Green
    0

    Hey Dan,

    I confess that I didn't read this all the way to the end as I can't work out if you're achieve something very unusual or there's something else fundamental going on.

    Can we clarify this line as it confuses me completely.

    "Now the typical Umbraco site probably has most of this layout data hard coded into templates or scripted somehow."

    There is no reason to hard code any content/data in a template, each 'node' or page can have a different Header Image, Left Image, Headline etc,

    Do you mean Layout (the design of the site css, html etc.) or content (Header Image, Left Image, Headline etc)?

    Rich




  • DanH 36 posts 61 karma points
    Nov 30, 2010 @ 19:33
    DanH
    0

    I think if you keep reading, it will clarify itself.  My first example does show how you can put the header image, left image, headline, etc into a doctype.  I consider those properties part of the layout not content.  For me, "content" is the stuff that the client is actually managing, and I don't want them to manage those aforementioned properties as they are part of the site design and beyond the client's comprehension.

    Sorry, I know it is a super long post.  I don't know how to put it succinctly without losing the meaning.  Hopefully the screenshots help.

  • Rich Green 2246 posts 4008 karma points
    Nov 30, 2010 @ 19:58
    Rich Green
    0

    Hey Dan,

    I get you, perhaps this will help?

    http://our.umbraco.org/projects/developer-tools/axendo-disabled-properties

    Rich

  • DanH 36 posts 61 karma points
    Dec 01, 2010 @ 11:28
    DanH
    0

    That looks very close to what I need.  I can't tell from the screen shot, but I'm assuming it's disabling properties by document, not document type.  It will still work (once it is 4.5.x compatible), it will just be a lot of clicks!  Thank you for your patience, Rich.  Now that I see the solution, I think there probably was a more succinct way to ask my question, like "how do you hide properties?"  Oh well.

  • Rich Green 2246 posts 4008 karma points
    Dec 01, 2010 @ 11:51
    Rich Green
    0

    Hey Dan,

    I did see a project / some code that would hide a Tab for certain user groups, though I can't find it right now.

    However I need to do this for my current project, so if I work it out I'll let you know.

    Cheers

    Rich

  • Rich Green 2246 posts 4008 karma points
    Dec 01, 2010 @ 11:53
    Rich Green
    0

    FYI, pretty sure that it disables DocType properties, not for each piece of content, so not many clicks.

    Rich

  • DanH 36 posts 61 karma points
    Dec 01, 2010 @ 16:15
    DanH
    0

    I think I found that project you mentioned.  It hides entire tabs based on tab name, user group, and (optionally) document type, and it is compatible with 4.5.x.  This works perfectly for my setup because "layout" items should really be on a separate tab anyways.

    http://our.umbraco.org/projects/backoffice-extensions/attackmonkey-tab-hider

     

  • Rich Green 2246 posts 4008 karma points
    Dec 01, 2010 @ 16:17
    Rich Green
    0

    Hey Dan, 

    Fantastic :) knew I'd seen it somewhere

    Many thanks for posting back

    Let us know how your project goes.

    Rich

  • Jørgen Bakke Eriksen 44 posts 95 karma points
    Jan 22, 2013 @ 14:33
    Jørgen Bakke Eriksen
    0

    Dan, we have recently built a site using the principle of separating content from structure like you describe: we map content using the multinode picker to nodes of type MenuItems which we use solely for building menu-structure. I thought this was an excellent idea until I read your post about the missing caching of content from the multinode tree picker.

    I'm curious about what solution you ended with. It seems from your other posts that you are using the attackmonkey-plugin to hide tabs and properties from the user in order to hide the "layout information". I would still wan't to go with the separation of content and structure since I think there are a lot of advantages to this approach, the obvious beeing reuse of content, but also easily setting up containers to pick a-few-from-many etc, using different templates for same content in different parts of a site etc.

    I also find it a bit confusing the way Umbraco is by default: Mixing structure and content. I think this is confusing for editors as well and a lot of overhead with permissions in order to micro manage access to content while keeping them from braking the structure.

    And pardon me, if you had taken your separation one step further - like we do - and we get a solution for the cache - I think we would have a smashing solution that is extremely flexible, dynamic and generic :-)

    So I really hope you found a way to fulfill the separate-content-structure principle.

  • DanH 36 posts 61 karma points
    Jan 23, 2013 @ 03:13
    DanH
    0

    Unfortunately, I ended up abandoning the idea of separating the two concerns.  For a couple sites I used the tab hider project and also uHidesy, which can hide individual properties.  But as you mentioned, the micro management was too much overhead.  

    My goal lately has been to turn out functional Umbraco sites as quickly as I can, even if they are not intuitive and idiot proof for the client.  I just explain that we're using a CMS, which gives them a lot of power for a low cost, but it's not perfect.  Worst case they can rollback/restore screwups or pay me to fix it.

    That said, with the new MVC features, maybe you can do what you want without the caching problem using Partials.  Something like:

    @{

    var contentNode = Umbraco.Content(CurrentPage.contentId);

    }

    @Html.Partial("PartialName",contentNode)

    http://our.umbraco.org/documentation/Reference/Mvc/

    Or, just not worry about those database hits unless you have a really busy site.  Sorry, I have not come up with a magic solution.  

Please Sign in or register to post replies

Write your reply to:

Draft