Accelerated Mobile Pages (AMP)

Google and Twitter collaborated to develop AMP, an open source framework for creating faster experiences on the mobile web. In a nutshell, it is a simplified set of html and css for mobile.

For this codeshare website I wanted to enable AMP. The first version of this site was built in Umbraco v7, so here is how I did it.

Premise

The basic premise is to have a new template called Amp.cshtml, have a true/false property on your page to enable AMP or not and if it is true provide the link in the head for the AMP version of the page.

Template

Here is the code for the template, it's a bit rough and naive but it might help someone:

@inherits Umbraco.Web.Mvc.UmbracoViewPage
@{
    Layout = null;

    string pageTitle = Model.GetPropertyValue<string>("pageTitle");

    string imgUrl = "";
    if (Model.HasValue("pageBannerImage"))
    {
        imgUrl = Umbraco.AssignedContentItem.GetPropertyValue<IPublishedContent>("pageBannerImage").Url;
    }
}


<!doctype html>
<html amp>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
    <title>@(Model.HasValue("pageTitle") ? pageTitle : Model.Name)</title>
    <link rel="canonical" href="@Model.Url" />
    <script src="https://cdn.ampproject.org/v0.js" async></script>
    <style amp-boilerplate>
        body {
            -webkit-animation: -amp-start 8s steps(1,end) 0s 1 normal both;
            -moz-animation: -amp-start 8s steps(1,end) 0s 1 normal both;
            -ms-animation: -amp-start 8s steps(1,end) 0s 1 normal both;
            animation: -amp-start 8s steps(1,end) 0s 1 normal both
        }

        @@-webkit-keyframes -amp-start {
            from {
                visibility: hidden
            }

            to {
                visibility: visible
            }
        }

        @@-moz-keyframes -amp-start {
            from {
                visibility: hidden
            }

            to {
                visibility: visible
            }
        }

        @@-ms-keyframes -amp-start {
            from {
                visibility: hidden
            }

            to {
                visibility: visible
            }
        }

        @@-o-keyframes -amp-start {
            from {
                visibility: hidden
            }

            to {
                visibility: visible
            }
        }

        @@keyframes -amp-start {
            from {
                visibility: hidden
            }

            to {
                visibility: visible
            }
        }
    </style>
    <noscript>
        <style amp-boilerplate>
            body {
                -webkit-animation: none;
                -moz-animation: none;
                -ms-animation: none;
                animation: none
            }
        </style>
    </noscript>

    <script async custom-element="amp-analytics" src="https://cdn.ampproject.org/v0/amp-analytics-0.1.js"></script>
</head>
<body>
    <amp-analytics type="googleanalytics" id="analytics1">
        <script type="application/json">
            {
               "vars": {
                    "account": "UA-12345678-1"
                },
                "triggers": {
                    "trackPageview": {
                        "on": "visible",
                        "request": "pageview"
                    }
                }
            }
        </script>
    </amp-analytics>
    <nav class="amp-wp-title-bar">
        <div>
            <a href="https://mydomain.com">
                mydomain.com
            </a>
        </div>
    </nav>
    <div class="amp-wp-content">
        <h1 class="amp-wp-title">@(Model.HasValue("pageTitle") ? pageTitle : Model.Name)</h1>
        <ul class="amp-wp-meta">
            <li class="amp-wp-byline">
                <span class="amp-wp-author">Paul Seal</span>
            </li>
            <li class="amp-wp-posted-on">
                <time datetime="@(Model.GetPropertyValue<DateTime>("blogPostDate").ToString("yyyy-MM-ddTHH:mm:sszzz", System.Globalization.CultureInfo.InvariantCulture))">
                    @CodeShare.Library.Utility.Social.General.GetRelativeTime(Model.GetPropertyValue<DateTime>("blogPostDate"))
                </time>
            </li>
        </ul>
        <a href="http://www.facebook.com/sharer/[email protected]" rel="nofollow">
            <amp-img src="https://codeshare.co.uk/media/1127/fbamp-1.png" alt="FB-Share" width="105" height="39" class="amp-wp-enforced-sizes"></amp-img>
        </a>
        <a href="http://twitter.com/intent/[email protected](Model.HasValue("pageTitle") ? pageTitle : Model.Name)&[email protected](Model.Url)&via=prjseal" rel="nofollow">
            <amp-img src="https://codeshare.co.uk/media/1128/twamp-1.png" alt="Tw-Share" width="105" height="39" class="amp-wp-enforced-sizes"></amp-img>
        </a>
        <div class="media-credit-container alignnone"><amp-img class="size-full wp-image-264208 amp-wp-enforced-sizes" src="@imgUrl" alt="@Model.Name" width="1200" srcset="@(imgUrl)?width=1200&mode=crop&anchor=center 1200w, @(imgUrl)?width=622&height=350&mode=crop&anchor=center 622w" sizes="(min-width: 800px) 800px, 100vw" height="675"></amp-img></div>
        @Html.GetGridHtml(Model, "contentGrid", "Amp")
    </div>
</body>
</html>

The Grid Partial

As you can see in my example, I am using the grid instead of just a rich text for my content.

If you are using the grid too, you want to create a partial in the folder Views > Partials > Grid and call it Amp.cshtml

Here is the code for it.

@inherits UmbracoViewPage<dynamic>

@if (Model != null && Model.sections != null)
{
    foreach (var section in Model.sections) {            
        foreach (var row in section.rows) {
            @renderRow(row);
        }
    }
}

@helper renderRow(dynamic row){
    foreach ( var area in row.areas ) {
        foreach (var control in area.controls) {
            if (control !=null && control.editor != null && control.editor.view != null ) {
                <text>@Html.Partial("grid/editors/base", (object)control)</text>
            }
        }
    }
}

Rendering the link in the head

In the head of your master template you want to add this:

@if(Model.Content.HasValue("enableAmp") 
    && (bool)Model.Content.GetPropertyValue<bool>("enableAmp"))
{
    <link rel="amphtml" href="@(Model.Content.Url)amp/" />
}

Then when the main page gets rendered, it has the amphtml link in it.

Enable SearchForTemplate

The last thing left to do is to make sure you have alternate templates enabled. To do this you need to have the SearchForTemplate line set in the 404handlers.config like this:

<?xml version="1.0" encoding="utf-8" ?>
<NotFoundHandlers>
    <notFound assembly="umbraco" type="SearchForAlias" />
    <notFound assembly="umbraco" type="SearchForTemplate"/>
    <notFound assembly="umbraco" type="SearchForProfile"/>
    <notFound assembly="umbraco" type="handle404"/>
</NotFoundHandlers>

That should work for you.

Want to thank me?

If I've helped you out and you want to thank me, why not buy me a coffee?

Buy me a coffee

About the author

Paul Seal

Umbraco MVP and .NET Web Developer from Derby (UK) who specialises in building Content Management System (CMS) websites using MVC with Umbraco as a framework. Paul is passionate about web development and programming as a whole. Apart from when he's with his wife and son, if he's not writing code, he's thinking about it or listening to a podcast about it.

Related Posts

How to search by picked multi node tree picker values in Umbraco v8

This post shows you how you can use examine to search for articles which have the category picked in…

Read Post

How to render the actual document type icons in the tree in Umbraco

This post gives you the code to be able to see the icons for your document types in the tree view ra…

Read Post

How to animate tree icons in Umbraco v8

This post shows you how you can change the colour and animate tree icons in Umbraco based on a prope…

Read Post

How to solve the error assets file project.assets.json not found in Visual Studio

This post tells you how to solve the error assets file project.assets.json not found in Visual Studi…

Read Post