Ghost ships with a clean, simple AMP template which works with just about any site, but wouldn't it be nice if you could customise it to make it perfectly match your theme and your brand? Well you can! Read on:

How does AMP work in Ghost?

Ghost comes with AMP built-in, and it can be enabled or disabled (for those who prefer not to use it). When enabled, Ghost uses a single Handlebars template file to render your AMP content. As soon as you add /amp to the url of any post URL (e. g. https://www.myblog.com/welcome-to-ghost/amp), you'll see this template file being rendered.

All blog posts also get a new canonical link, which refers to the AMP version of the post: <link rel="amphtml" href="https://www.myblog.com/welcome-to-ghost/amp/" />. This is a necessary link. Without it, your AMP post will not be served from the Google AMP Cache.

The amp.hbs template exists in the active theme directory. By default, Ghost comes with an amp.hbs template that is suitable for most publications. It can be used out of the box without any extra effort or code, but it can also be customised for additional features or styling. The structure of the file looks like this:

├── /assets
|   └── /css
|       ├── screen.css
|   ├── /fonts
|   ├── /images
|   ├── /js
├── default.hbs 
├── index.hbs [required]
└── post.hbs [required]
└── amp.hbs [optional]
└── package.json [required]

Be aware of the AMP restrictions

Before you start developing your AMP template, it's useful to know a few things about the restrictions which Google has enforced in AMP to maintain optimal performance:

⚡ No client side scripts

AMP pages can't include any client side scripts, except under special circumstances. Any use of jQuery or JavaScript will lead to an invalid AMP template!

⚡ Keep CSS inside <style amp-custom>

CSS can only live in the <style amp-custom></style> tag inside the <head> section. You can use class and id in your HTML, but you can't use inline CSS. The CSS is also size limited to 50 kilobytes. Additionally, some CSS styles are disallowed for performance.

⚡ Prohibited HTML

AMP uses its own AMP-HTML markup language. This means that some HTML tags are prohibited while others need to be transformed. Ghost automatically transforms HTML in your {{content}} (e. g. <img> becomes <amp-img>) and strips out disallowed tags, like embed or frame. You can find a full list of banned HTML tags here.

⚡ Required AMP markup

AMP has a few pieces of required markup which must be used.

If you want to load stuff externally, you'll need to use https protocol. Ghost does this automatically for any links in your post {{content}}.

⚡ Media needs width & height

All kind of media need width and height attributes. Again, anything being rendered within post {{content}} will be handled automatically. Here's an example of how you'd implement an image outside of the main content:

{{#post}}
  <amp-img src={{image absolute="true"}} width="600" height="400" layout="responsive"></amp-img>
{{/post}}

or the author image:

{{#post}}
	{{#author}}
  	<amp-img src={{image absolute="true"}} width="50" height="50"></amp-img>
	{{/author"}}
{{/post}}

⚡ Validate your template on-the-fly

AMP provides two ways to validate your template:

  • The first is to add #development=1 to the URL and check for any validation errors in the console.
  • The second is to copy your HTML into the online validator, but keep in mind that this will not work with Ghost handlebars helpers.

Building a custom AMP templates

The Google-led AMP project often add support for new features and customisation of your AMP content. For example, you can do cool things like edit the styling of your AMP content or generate revenue with advertising.

The best way to implement these features is to follow the AMP documentation for the features you are interested in adding, and edit the amp.hbs template in Ghost. Note that using AMP features that require content from Ghost will not work.

The rest of this tutorial will walk you through the default amp.hbs template in Ghost and walk you through what each section contains and how it works. The easiest way to get started with developing your own is to use this default template and make changes to it. Let's get to it...

AMP template <head>

<!DOCTYPE html>
<html ⚡>
<head>
    <meta charset="utf-8">
    <title>{{meta_title}}</title>
    <meta name="description" content="{{meta_description}}" />
    <meta name="HandheldFriendly" content="True" /> //required
    <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1"> //required
    <link rel="shortcut icon" href="{{asset "favicon.ico"}}">
    
    {{amp_ghost_head}}
    
    <link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Merriweather:300,700,700italic,300italic|Open+Sans:700,600,400" />
    <style amp-custom>
       ...
    </style>
    
    <style amp-boilerplate>...</style><noscript><style amp-boilerplate>...</style></noscript>

    <script async src="https://cdn.ampproject.org/v0.js"></script>

    {{amp_components}}
</head>

If you're a theme developer, this is probably all very familiar. Here are the highlights:

<html ⚡>

This makes it AMP! You can also use <html amp>, but ⚡ is more awesome.

Required by AMP:

  • <meta charset="utf-8">
  • <meta name="HandheldFriendly" content="True" />
  • <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">

{{amp_ghost_head}}

This helper will output the mandatory structured data and the JSON+LD data, just like {{ghost_head}} does. It also renders the necessary link to the regular post, which is (wait for it) required by AMP. 💃🏻

Code injection content won't be rendered here, as this may contain additional<style> and <script> tags.

AMP does allow the use of custom font faces.

<style amp-custom>

All your CSS goes here. The default AMP template comes with a similar structure to the Casper theme. You can work with CSS classes just as you're used to. Just keep in mind that there are some CSS restrictions, as mentioned above.

<style amp-boilerplate>

This is required by AMP, and essentially outputs a few default AMP UI styles for animations/etc which are mandatory. You can find the current version here.

<script async src="https://cdn.ampproject.org/v0.js"></script>

This will load the AMP JavaScript library and is required by AMP.

{{amp_components}}

This is a special helper which scans your {{content}} for any extended components, such as .gif files, iframe-tags and audio tags. If it finds them, it'll include scripts to make them work good. Yes, work good. That's what we're going with.

AMP template <body>

Now it's time to build the structure for the content:

<body class="amp-template">
    {{#post}}
    <header class="main-header">
        <nav class="blog-title">
            <a href="{{@blog.url}}">{{@blog.title}}</a>
        </nav>
    </header>
    <main class="content" role="main">
        <article class="post">
            <header class="post-header">
                <h1 class="post-title">{{title}}</h1>
                <section class="post-meta">
                    {{#author}}
                    <p class="author">by <a href="{{url}}">{{name}}</a></p>
                    {{/author}}
                    <time class="post-date" datetime="{{date format="YYYY-MM-DD"}}">{{date format="YYYY-MM-DD"}}</time>
                </section>
            </header>
            {{#if image}}
            <figure class="post-image">
                <amp-img src="{{image absolute="true"}}" width="600" height="400" layout="responsive"></amp-img>
            </figure>
            {{/if}}
            <section class="post-content">
                {{amp_content}}
            </section>
       </article>
    </main>
    {{/post}}
    <footer class="site-footer clearfix">
        <section class="copyright"><a href="{{@blog.url}}">{{@blog.title}}</a> &copy; {{date format="YYYY"}}</section>
        <section class="poweredby">Proudly published with <a href="https://ghost.org">Ghost</a></section>
    </footer>
</body>

This is where you can go wild! Here's a quick explanation of the most important stuff in here:

{{image}} and <amp-img>

The default template uses the {{#if}} helper to check for a post image. But you'll notice that it needs to be wrapped in <amp-img> and also provide the mandatory width and height attributes.

{{amp_content}}

A special version of the regular {{content}} helper which transforms HTML tags into AMP HTML where appropriate.

Remember to validate your template

Don't forget to open any blog post on your site and add /amp/#development=1 to the URL. This will not only render your AMP template, but also open the AMP validator.

Summary

You now have a strong understanding of how AMP content works in Ghost and a detailed overview of the default amp.hbs template and how you can adjust it to suit your needs. If you run into any difficulties with AMP, try their developer support options.