Exam Area: Area 1 – Product Knowledge (15%) Reference: https://docs.developers.optimizely.com/content-management-system/docs/seo
Optimizely CMS 12 includes several built-in SEO capabilities:
| Feature | Description |
|---|---|
| Friendly URLs | Human-readable page URLs from page names |
| Canonical URLs | Prevent duplicate content via canonical link |
| Sitemap support | Site map can be generated (via add-on or code) |
| Metadata properties | Title, Description, Keywords on PageData |
| 301 / 302 redirects | Automatic redirect from old URLs when pages move |
| Language-specific URLs | Separate URLs per language |
| Open Graph support | Via custom properties or add-ons |
CMS generates URLs from content names by default:
Page name: "About Us"
Generated URL: /about-us/
Page name: "News & Events"
Generated URL: /news-events/ (special chars stripped)
You can override the URL segment on a page:
Edit View → Properties → URL Segment field (on PageData)
// Resolve a ContentReference to a URL
public class LinkBuilder
{
private readonly IUrlResolver _urlResolver;
public LinkBuilder(IUrlResolver urlResolver)
{
_urlResolver = urlResolver;
}
public string GetUrl(ContentReference contentRef, string language = null)
{
return _urlResolver.GetUrl(
contentRef,
language,
new VirtualPathArguments { ForceCanonical = true });
}
public IContent ResolveFromUrl(string url)
{
return _urlResolver.Route(new UrlBuilder(url));
}
}
// PageData includes these SEO-related properties:
public abstract class PageData
{
// Used as <title> tag
[Display(Name = "Page name in URL")]
public virtual string URLSegment { get; set; }
// Used as <meta name="keywords">
[Display(Name = "Keywords")]
public virtual string MetaKeywords { get; set; }
// Used as <meta name="description">
[Display(Name = "Description")]
public virtual string PageDescription { get; set; }
// Generates canonical URL
public virtual bool ExcludedFromSearch { get; set; }
}
public class SeoPage : PageData
{
[Display(Name = "SEO Title", Order = 300, GroupName = "SEO")]
public virtual string SeoTitle { get; set; }
[Display(Name = "Meta Description", Order = 310, GroupName = "SEO")]
[StringLength(160)]
public virtual string MetaDescription { get; set; }
[Display(Name = "Open Graph Image", Order = 320, GroupName = "SEO")]
[UIHint(UIHint.Image)]
public virtual ContentReference OgImage { get; set; }
[Display(Name = "Canonical URL", Order = 330, GroupName = "SEO")]
public virtual Url CanonicalUrl { get; set; }
}
@model SeoPage
@{
var title = string.IsNullOrEmpty(Model.SeoTitle) ? Model.Name : Model.SeoTitle;
var description = Model.MetaDescription ?? Model.PageDescription;
}
<head>
<title>@title - My Site</title>
<meta name="description" content="@description" />
@if (Model.CanonicalUrl != null)
{
<link rel="canonical" href="@Model.CanonicalUrl" />
}
@if (Model.OgImage != null)
{
<meta property="og:image" content="@Url.ContentUrl(Model.OgImage)" />
}
</head>
When a page is moved or renamed, CMS can issue automatic redirects:
Admin → CMS → Config → Manage Website → URL Rewriting
→ Enable automatic redirects for moved/renamed pages
// Register custom URL rewrite rules
services.Configure<RedirectOptions>(options =>
{
options.AddPermanentRedirect("/old-url/", "/new-url/");
});
// Mark content as excluded from search (search engines and CMS Find)
page.ExcludedFromSearch = true;
This sets <meta name="robots" content="noindex,nofollow"> if implemented in the view.
CMS 12 does not include a built-in sitemap generator. Options:
IContentLoader// Simple custom sitemap endpoint
app.MapGet("/sitemap.xml", async (IContentLoader loader, IUrlResolver urlResolver) =>
{
var pages = loader.GetDescendents(ContentReference.StartPage)
.Select(r => loader.Get<IContent>(r))
.OfType<PageData>()
.Where(p => !p.ExcludedFromSearch);
var xml = GenerateSitemapXml(pages, urlResolver);
return Results.Content(xml, "application/xml");
});
ExcludedFromSearch = true signal? (The page should not be indexed — implementation renders noindex/nofollow meta tag)