One of the greatest features of Umbraco is that it lets you do whatever you want with the front-end and the data in the back office. It's also one of the greatest headaches when it comes to SEO and other "kind of standard" properties to be included in every page. Where other CMSs have it figured out, either in a good or not-so-good way, in Umbraco you are required to implement all this yourself. Surprise, no two developers and sometimes even no two Umbraco installations do this in the same way.
(The reaction to seeing so many different implementations is that in the photo used for the article :) )
Being aware of that, we tried to standardize the data and the way they should be rendered and use the same practice on all the sites we developed. We took what we have been using and applied it to the uMazel Starter Kit. It's not covering a hundred percent of what's required, but it can still be considered a standard practice. So here goes:
First thing we needed to do was to define some global, as in site-wide, settings. On uMazel, you'll find a Settings node under which there are several subnodes, each serving a different purpose. What we are interested in here is the Site Settings one. There, under the "Icon and Site Name" tab you'll find the following:
Site name: What you'll see in the home page browser title (can be overridden), and optionally serve as a suffix to all other pages
Add site name as suffix to page titles: Does what it says. When enabled, takes the site name mentioned above, and appends it to the browser title of internal pages. For example, if your site name is "Our Awesome Site" and you have this setting on, then a page named "Our Clients" will render a browser title of "Our Clients - Our Awesome Site".
Favicon and touch icon: Here you set an image which will be used to render all other icons used in various devices, down to the site's favicon that will be used in the browser. Typically, this will be a company logo or similar.
Let's leave Site Settings now for a while (we'll return to it) and go see what we can do with each individual page of our site. All our site's pages are composed with two special doctypes: Abstract Page and Abstract OpenGraph. Those two provide all the common properties we need.
The first tab we get on all pages, coming from the Abstract Page composition, is Navigation.
The first two properties, Hide from Menu and Hide from Footer are somewhat generic and can be enriched with additional ones or removed according to the site's content. They generally do what they say. Hide from Menu has more meaning if the menu is being generated automatically (uMazel has two ways of generating the main menu: automatic and manual), while Hide from Footer prevents a page of being used as a footer link even if it is specified. Hide from Menu is the good all loved umbracoNaviHide property as some of you may already know.
URL Part Substitution and Alternate URL(s) are more interesting, since they represent the standard umbracoUrlName and umbracoUrlAlias properties respectively. URL part substitution allows you to substitute what would normally be generated as part of the page URL, based on the node name, with something else. For example, if we have the hierarchy "Category 1", "Page 1", "Subpage 1", it would render as "/Category-1/Page-1/Subpage-1". Now let's say we use the URL part substitution field for Page 1 and give it a value of "Burt". Then our new url for Page 1 would be "/Category-1/Burt" while the new url for Subpage 1 would be "/Category-1/Burt/Subpage-1".
The alternate URL is not very good for SEO since it will essentially create a URL alias and make a page have two or more different URLs, but it's handy when you have a really complicated one. Think of a page with a generated url of /Clients/Rich-Clients/Extremely-Wealthy-Ones/Jeff-Bezos". It's long, it's hard to remember, and it's ugly. How about "/JeffBezos"? Well, you can do that if you put "JeffBezos" in that field. Don't like that? How about "/Awesome/Bezos"? You can do that as well. In fact, you can even have both if you separate them with a comma.
Next tab we get from the Abstract Page composition is Titles.
This one can again, be enriched or restricted a bit depending on each site's content, but the standard properties you'll always want to use are the following:
Title Override: This one essentially replaces the title that you get from the node's name, everywhere the node name is used. The rest of the fields will still work. Great when the node's name is not what you would like to be used as an actual title.
Browser Title Override: This one sets the browser title. If the "Add site name as suffix to page titles" setting, which we saw above in Site Settings is on, it still respects it. Filling this will get you a different browser title.
Alternate Internal Page Title: When the title is used inside the page (e.g. as a header) you can have a totally different literal for that.
Two more properties that may come in handy, depending on context, are:
Alternate Page Title for Menus: This one lets you specify a different title for any menu or listing that includes this page. Handy when your page's name is long, but you need a shorter one for menus or lists. For example, "Financial Data and Shareholder Information" can just become "Financial Data" for menus, while the full title will still be used elsewhere.
Alternate Breadcrumb Page Title: Same usage as the Menus one - provided you've got navigation breadcrumbs on your site. You may need shorter or different literals for breadcrumbs but retain normal titles for other uses.
Of course, to utilize this part, we needed to use a convention: Never use the .Name property. Instead, we have created some extension methods such as .GetPageName() or .GetPageTitleInternal() that not only get the right title for each part but respect any overrides as well.
Next tab is Redirects.
This serves a single purpose: Apply a redirect (permanent or temporary) to the current page. The redirect can be an external URL, an internal page, or even a file from Media.
uMazel has also a built-in dynamic XML sitemap page that can be submitted to Google or other search engines. Each page composed with the Abstract Page document is included in the site map, but you can exclude the current page or even the current page and all its child pages (the whole hierarchy) by checking the appropriate options in the Sitemap tab. You can also set the site map priority for the current page:
Now, what about including scripts in our pages? One obvious way is to include scripts in our "master" template(s) (and apply them to all pages that follow it/them by default), or include some scripts in specific templates. But this adds a burden to developers and restricts content editors from managing scripts that can be added for various reasons. And what about adding scripts to a specific page only?
The solution we came up with involves two sets of settings: The first one is in the Settings/Script Settings node and handles global (site-wide) scripts, while the second one is added to each page when it's composed with the Abstract Page doctype and handles page-specific scripts.
So, in the Script Settings node under "Settings", you'll find the following:
You can set up scripts that load inside the HEAD section of your page, immediately after the BODY tag, or immediately before the closing BODY tag, depending on whether you should load each one. Each script gets a name and a "cookie level" category:
As you can see, you can specify the script's code in the Content field (must be careful there so you don't break the front end with any faulty code!). The title is just for you to be able to identify your script, while the "cookie level" dropdown allows you to specify a category the script belongs to depending on any cookies being issued by it, so it can be excluded if users set up their cookie preferences (we've got that one, too, but we won't go into more depth in this post). Finally, you can select one or more pages where the global script won't be loaded at all via the "Exclusions" picker.
Having done all that, you may need to add a script to a specific page on your site. You can achieve that by going to the "Page Specific Scripts and Code" tab on any page and setting up the script there in a similar way (without categorization though):
And now we're getting to the second composition all pages have - the composition with the Abstract OpenGraph doctype. (It's name doesn't make justice to it exactly, since it's actually used for both Open Graph AND Meta Tags). So in every page you'll see a tab like this:
And another one for meta tags:
What makes those two tabs interesting is not that you can specify Open Graph and Meta Tags values - most CMS and most implementations in Umbraco have this already, although (as noted at the start of this post) implemented in varying ways.
What's interesting here is that you can specify custom Open Graph and Meta (meta and http-equiv) properties per page, and also that you can have Open Graph properties propagate to sub-pages (see the "Apply to Sub Pages" property on OpenGraph), i.e. inheritable OG properties.
Returning to the global "Site Settings" node, you'll see that there are some additional global settings regarding OG and Meta tags:
You can specify a default OG image for every page of your site if no image has been provided to prevent scraping and automatically assigning the first "I think that's suitable" image from Social Media websites. If you have a multilingual web site, you can also set up a default image for the default language only and have all other languages use it by checking the "Use Image From Default Language if Empty" setting.
In the screenshot, you also see a "Fields for OG Title" field, but since it would be too long for a screenshot, let me tell you that there are similar properties for OG Description and OG Image. What you can do there is define a comma-separated list of property aliases that Umbraco will scan for data, and use the first non-empty one it finds if nothing else has been specified, in the order in which they are defined in the field, substituting "blind" value scraping with your own customized version.
Then we have this part:
Here you can define a default OG type in case nothing has been provided, e.g. "article" or "website", and also have Umbraco generate meta tags based on OG values if meta tags are left empty. You can also generate a URL and Language meta tag automatically for every page.
And, finally, we have this one:
This works to future-proof our website against new globally used OG and Meta tags you may want to include at any point. Just as with each individual page, you can add your own here and they will be included on every page.
So that's about it! If you've noticed some discrepancies in property descriptions in the screenshots, we apologize - we're aware of them, and we'll fix them very soon.
What do you think? (We know you'll shout "Twitter Cards", but apart from that)? We'll be very happy to know!