How can I use Umbraco to write good, maintainable code?
Hi all,
My employer's website is built entirely in Umbraco. We're currently upgrading from Umbraco 4.7.1.1 to Umbraco 7.2.1, and in the process of that we're tidying up a lot of our code. Please forgive how all over the place this question is, as Umbraco/MVC has gotten me very confused and I'm having difficulty presenting that confusion in an understandable way.
In our current codebase we have been struggling with reusability. Razor macros seem like the answer at first, but being unable to nest them makes them useless for all but the simplest tasks. For example, we use ClickDimensions to accept posted form data from our website. Each product we list on our website may have a RequestQuoteFormAction property, which contains the URL that should be in the action property of the Request a Quote form element. We use this form in a few places, most notably on the product pages but also on solution pages, product suite pages and so on. So the form should be reusable. The form goes in a seperate section on each page, and if RequestQuoteFormAction is not specified, not only should the form be hidden but the section containing it should be hidden too.
Because you cannot call a macro from within a macro, you can't conditionally call a macro, so the logic to hide the form needs to be within the reusable form macro. But then there's no way to hide the section containing the form, considering it's different on every page and therefore can't be integrated into the macro. In order to get the desired functionality we need to copy the macro code into the masterpage so that we can wrap a conditional around the whole thing.
Another example: We have a macro for the banner that goes across the top of each page on our site. This macro accepts a parameter that specifies the title that will be displayed on the banner. Different pages use different properties to populate this parameter using the [#propertyName] token. But we have a page with a bannerTitle property, and if bannerTitle isn't specified it should probably fall back to using pageHeading. Or we might want a page that can use @Model._bannerTitle. Or we may want a page that can format a date from its properties and use that as part of the title. Without being able to properly call macros from Razor we can't pass in variables as parameters, which limits us significantly.
With MVC we are given some new hope in the form of @Html.Partial(), which can take a 'model' as it's second argument. The model just seems to be any old Object, allowing us to define a class with properties for each parameter. Including one of these programmatically now would be easy, going back to the earlier example it looks a bit like @Html.Partial("ContactFormView", new ContactFormModel("formActionUrlGoesHere")).
But wait, we're abandoning Umbraco's macro system here. It appears we should instead be inheriting from Umbraco.Web.Macros.PartialViewMacroPage and then including some weird Param: syntax at the top of our View. This appears to make it impossible to pass in parameters programmatically with Html.Partial. Then we have to go into the Umbraco backend and create a new macro and define the parameters on that.
This brings me to my other main issue. Macros, Content Types and Media Types are stored in the database. If I make a new Content Type, I need to make it in the Umbraco backoffice and then make a masterpage for it in the filesystem. Then, when I deploy to my production environment, I can copy/paste my filesystem changes over but I have to manually recreate my Content Types, Media Types and Macros. Concierge provides a partial solution to this, although whenever I've used it it's broken things and I've had to manually fix them. Plus it seems to be impossible for me to place my Content Types/Media Types/Macros under version control, let alone implement some kind of Release Management system.
Umbraco already uses reflection heavily, why aren't Macros, Content Types and Media Types represented as Classes? Data Types can come too.
I'm trying really hard to like Umbraco because I love some aspects of the it's philosophy. It's just that the implementation has me hopelessly confused. Could somebody please provide me some guidance on what the intended way is to make maintainable websites with Umbraco?
You have a lot of good questions and maybe someone has time to give you elaborate answers for all of them. I only have a few minutes (also I don't understand your requirement of hiding stuff in forms):
The answer to all your questions around macros is: I don't think you need macros. In webforms you did, in MVC there is really no need unless you have to give the editor control over the parameters and need them to put the macro in the rich text editor.
So instead of macros, use the partials you've already found partials which seems like a good way to do the stuff you're now trying to do with a macro (round hole, square peg.. :) )
The banner: Make your question more specific and make it a new question in the forum. There's so many: "I may want to or I may want or I may want to" that I can't understand what you're trying to do. Don't think ahead so much, tackle one problem at a time and ask them as a single question so people actually have a chance of giving you a good answer.
We're working on all that stuff that's in the database, it's a non-trivial problem to solve and reflection is KINDA the solution, but not the whole solution later this year we'll have better ways of handling this. You'll like https://github.com/zpqrtbnk/Zbu.ModelsBuilder/ in the context of document types. For deployments we recommend Courier (full disclaimer: yes this is a paid plugin). Alternatives are things like uSync and there's a few other packages that help you with this. You'll find a lot of packages promising "code first" for Umbraco, think hard on whether you want to use them, very hard: https://offroadcode.com/blog/1839/the-code-first-in-umbraco-deadend/ (again, Zbu.ModelsBuilder is a way better solution and headed for integration in the core of Umbraco at some point).
Use umbraco.tv (19 euros per month, and you can cancel whenever you want, should be easy to watch all the videos in a month)
There are course in Melbourne in 2 weeks, consider joining them, almost all of your questions are covered in more depth in the level 2 courses and Peter (the trainer) has a lot of experience to help you out with all the questions that are not directly covered in the course material: http://umbraco.com/products/training/schedule.aspx
I know I'm pushing a lot of our paid products and believe me I am no salesman, I would hate doing that if I didn't believe in them.
I really appreciate being told not to use Macros, as I've been trying to do things 'the Umbraco way' considering we've chosen to adopt this CMS. So thanks for freeing me from that mental obligation.
The very specific requirements of hiding forms and having banner text should be easy to resolve when I use Partial views fully.
My employer is already paying for my umbraco.tv subscription, but I haven't found the videos particularly helpful yet. I think I find the organisation system difficult to use, as I can never quite find the right video.
Thanks for sending me Zbu, that looks very interesting.
I'll definitely consider taking a course, thanks.
EDIT: Almost all of the issues expressed in that Code First blog post would not apply if Code First implementation were first-party supported or even a full fork of Umbraco.
Other than that, I do hope that you'll learn to love Umbraco even if you can't appreciate it fully yet then at least know that one of our main focuses for the rest of the year is to make deployments much easier (which is where Code First comes into play, or at least "code last" as that's what Zbu does).
it seems to be impossible for me to place my Content Types/Media Types/Macros under version control, let alone implement some kind of Release Management system.
Regarding this point - I've been using a plug in called uSync for a few months now, and believe it will address this issue for you.
Essentially, it writes the doctype, template, styles etc into flat XML files which you can then version control.
When deploying to production, you simply change the usync config file to update the database with the newer XML files.
How can I use Umbraco to write good, maintainable code?
Hi all,
My employer's website is built entirely in Umbraco. We're currently upgrading from Umbraco 4.7.1.1 to Umbraco 7.2.1, and in the process of that we're tidying up a lot of our code. Please forgive how all over the place this question is, as Umbraco/MVC has gotten me very confused and I'm having difficulty presenting that confusion in an understandable way.
In our current codebase we have been struggling with reusability. Razor macros seem like the answer at first, but being unable to nest them makes them useless for all but the simplest tasks. For example, we use ClickDimensions to accept posted form data from our website. Each product we list on our website may have a RequestQuoteFormAction property, which contains the URL that should be in the action property of the Request a Quote form element. We use this form in a few places, most notably on the product pages but also on solution pages, product suite pages and so on. So the form should be reusable. The form goes in a seperate section on each page, and if RequestQuoteFormAction is not specified, not only should the form be hidden but the section containing it should be hidden too.
Because you cannot call a macro from within a macro, you can't conditionally call a macro, so the logic to hide the form needs to be within the reusable form macro. But then there's no way to hide the section containing the form, considering it's different on every page and therefore can't be integrated into the macro. In order to get the desired functionality we need to copy the macro code into the masterpage so that we can wrap a conditional around the whole thing.
Another example: We have a macro for the banner that goes across the top of each page on our site. This macro accepts a parameter that specifies the title that will be displayed on the banner. Different pages use different properties to populate this parameter using the [#propertyName] token. But we have a page with a bannerTitle property, and if bannerTitle isn't specified it should probably fall back to using pageHeading. Or we might want a page that can use @Model._bannerTitle. Or we may want a page that can format a date from its properties and use that as part of the title. Without being able to properly call macros from Razor we can't pass in variables as parameters, which limits us significantly.
With MVC we are given some new hope in the form of @Html.Partial(), which can take a 'model' as it's second argument. The model just seems to be any old Object, allowing us to define a class with properties for each parameter. Including one of these programmatically now would be easy, going back to the earlier example it looks a bit like @Html.Partial("ContactFormView", new ContactFormModel("formActionUrlGoesHere")).
But wait, we're abandoning Umbraco's macro system here. It appears we should instead be inheriting from Umbraco.Web.Macros.PartialViewMacroPage and then including some weird Param: syntax at the top of our View. This appears to make it impossible to pass in parameters programmatically with Html.Partial. Then we have to go into the Umbraco backend and create a new macro and define the parameters on that.
This brings me to my other main issue. Macros, Content Types and Media Types are stored in the database. If I make a new Content Type, I need to make it in the Umbraco backoffice and then make a masterpage for it in the filesystem. Then, when I deploy to my production environment, I can copy/paste my filesystem changes over but I have to manually recreate my Content Types, Media Types and Macros. Concierge provides a partial solution to this, although whenever I've used it it's broken things and I've had to manually fix them. Plus it seems to be impossible for me to place my Content Types/Media Types/Macros under version control, let alone implement some kind of Release Management system.
Umbraco already uses reflection heavily, why aren't Macros, Content Types and Media Types represented as Classes? Data Types can come too.
I'm trying really hard to like Umbraco because I love some aspects of the it's philosophy. It's just that the implementation has me hopelessly confused. Could somebody please provide me some guidance on what the intended way is to make maintainable websites with Umbraco?
Thanks,
Josh
You have a lot of good questions and maybe someone has time to give you elaborate answers for all of them. I only have a few minutes (also I don't understand your requirement of hiding stuff in forms):
I know I'm pushing a lot of our paid products and believe me I am no salesman, I would hate doing that if I didn't believe in them.
Wow, awesome answer, thanks heaps!
I really appreciate being told not to use Macros, as I've been trying to do things 'the Umbraco way' considering we've chosen to adopt this CMS. So thanks for freeing me from that mental obligation.
The very specific requirements of hiding forms and having banner text should be easy to resolve when I use Partial views fully.
My employer is already paying for my umbraco.tv subscription, but I haven't found the videos particularly helpful yet. I think I find the organisation system difficult to use, as I can never quite find the right video.
Thanks for sending me Zbu, that looks very interesting.
I'll definitely consider taking a course, thanks.
EDIT: Almost all of the issues expressed in that Code First blog post would not apply if Code First implementation were first-party supported or even a full fork of Umbraco.
You might benefit from this post about multi-step forms as it seems similar to what you're trying to do in hiding and showing stuff: https://umbraco.com/follow-us/blog-archive/2015/2/13/creating-multi-step-forms-using-a-surfacecontroller and in this post there's a simple MVC/Umbraco contact form that talks about redirecting to or returning to the current umbraco page that might be of benefit to understand the concepts that differ slightly from "the pure MVC way". http://umbraco.com/follow-us/blog-archive/2013/7/14/moving-from-webforms-to-mvc
Other than that, I do hope that you'll learn to love Umbraco even if you can't appreciate it fully yet then at least know that one of our main focuses for the rest of the year is to make deployments much easier (which is where Code First comes into play, or at least "code last" as that's what Zbu does).
Hi Joshua,
Regarding this point - I've been using a plug in called uSync for a few months now, and believe it will address this issue for you. Essentially, it writes the doctype, template, styles etc into flat XML files which you can then version control. When deploying to production, you simply change the usync config file to update the database with the newer XML files.
Take a look: https://our.umbraco.org/projects/developer-tools/usync
is working on a reply...