Twenty Seventeen

Here’s a look at how to make a theme AMP-compatible, using Twenty Seventeen as an example.

As usual, reimplementing JavaScript is the most common challenge. AMP doesn’t allow custom JavaScript.

‘Sticky’ Navigation

In Twenty Seventeen, there’s a ‘sticky’ nav menu implemented in JavaScript:

<?php if ( twentyseventeen_is_amp() ) : ?> <amp-position-observer layout="nodisplay" intersection-ratios="1" on="exit:navigationTopShow.start;enter:navigationTopHide.start" <?php if ( is_admin_bar_showing() ) : ?> viewport-margins="32px 0" <?php endif; ?> ></amp-position-observer> <?php endif; ?>

Notice the on attribute above:

on="exit:navigationTopShow.start;enter:navigationTopHide.start"

The navigationTopShow.start event then triggers an animation that’s set in an amp-animation element. This then displays a new menu, giving the effect of a menu ‘sticking’ to the top.

Sub-menu Buttons

Revealing sub-menu items is another common task in making themes AMP-compatible.

For example, Twenty Seventeen’s functions.js file causes the submenu to expand on clicking a menu item:

The AMP implementation can use amp-state.

It creates an amp-state to store the expanded state:

$item_output .= sprintf( '<amp-state id="%s"><script type="application/json">%s</script></amp-state>', esc_attr( $expanded_state_id ), wp_json_encode( $expanded ) );

This state is like a global JavaScript variable that stores whether that sub-menu is expanded.

On clicking a button to expand a sub-menu section, it toggles that amp-state. For example, if it was original false (unexpanded), it toggles to true.

This then toggles the class  to toggled-on, which determines whether the sub-menu items display. Notice how this class displays and is removed on clicking:

AMP-Specific Styling

The plugin generally handles styling well. AMP URLs will usually look very similar to non-AMP URLs.

But sometimes it’s necessary to add styling for AMP markup.

For example, twentyseventeen/style.css uses the class js, but that class won’t be present in AMP because it doesn’t allow custom JavaScript.

So it can help to have AMP-equivalents for those style rules.
For example, here are the non-AMP selectors:

.js .main-navigation ul, .js .main-navigation ul ul, .js .main-navigation > div > ul { display: block: }

And you can apply equivalent AMP selectors so the rule will also apply to AMP URLs:

.js .main-navigation ul, .js .main-navigation ul ul, .js .main-navigation > div > ul, html[amp] .main-navigation ul, html[amp] .main-navigation ul ul, html[amp] .main-navigation > div > ul { display: block; }

Body Classes

Themes sometimes add body classes with JavaScript, based on the state of the document.

For example, twentyseventeen/assets/js/global.js adds a has-header-video class when the header video is loaded.

For AMP endpoints, you can add this class with PHP:

/** * On AMP endpoints with a header video, add a class to the body classes. * * @param array $classes The body classes. * @return array $classes The body classes. */ add_filter( 'body_class', function( $classes ) { if ( function_exists( 'is_amp_endpoint' ) && is_amp_endpoint() && has_header_video() ) { $classes[] = 'has-header-video'; } return $classes; } );