Custom Shortcodes and Widgets

Widgets are now supported when adding theme support, and shortcodes have always been supported. Here are some considerations for creating custom shortcodes and widgets:

  • No inline scripts, as this plugin will strip <script> tags on the front-end. Consider using amp-bind instead. While script elements will be stripped in AMP, if you have fallback content in accompanying noscripttags then (as of 1.0-beta1) they will be unwrapped so their contents will be served in AMP. 
  • While it is a best practice is to enqueue stylesheets with wp_enqueue_style(), this plugin will also recognize inline styling, and it automatically to the <style amp-custom> element. If the stylesheet causes the total page CSS size to go over the 50 KB limit, it might be stripped. But a new feature as of 1.0-alpha1 reduces the need to reduce additional CSS by automatically tree-shaking the CSS added to the page.
  • As is generally a good idea even when not using AMP, it's a good idea to only enqueue scripts and styles when you're actually rendering a widget or shortcode so that you can be sure that the asset will actually be used on the page. Use the is_amp_endpoint() function to check for whether to enqueue a script; by doing so you'll avoid raising an AMP validation error that has to be accepted, as the script must get stripped in any case for the page to be served as AMP. 👉 It's important to note that you cannot call is_amp_endpoint()prior to the parse_query action since it needs to look at the populated WP_Query.
  • You can also use is_amp_endpoint() to output different markup for AMP and non-AMP pages, such as when you are using the paired mode. For example, a social sharing widget or shortcode might output the amp-social-share component on the AMP page:
<?php if ( function_exists( 'is_amp_endpoint' ) && is_amp_endpoint() ) : ?>
        <amp-social-share type="twitter"></amp-social-share>
<?php else : ?>
        <a href="https://twitter.com/intent/tweet/?url=http%3A%2F%2Fexample.com">Share</a>
<?php endif; ?>
  • The plugin will automatically output the required scripts for any AMP components that you output. In the example above, the plugin will recognize the amp-social-share component and output the required script.
  • Gutenberg Blocks that use AMP components can be created as Dynamic Blocks using the same approach in the render_callback as rendering widgets or shortcodes. If you want to use AMP components in non-dynamic blocks where the content is written statically into the post content, you should be sure to only let such a block be available when the user has selected native mode (when amp_is_canonical() returns true). Otherwise, the AMP component could get displayed on non-AMP pages and thus appear broken; for an issue regarding the use of AMP components in non-AMP pages, see amphtml#15583. The other important consideration for static blocks using AMP components is that you should make sure you whitelist the AMP components and their attributes so that Kses will not strip them out upon saving if a user does not have unfiltered_html capability. For example, if you have a block that outputs an amp-social-share component, then you should include the following code so that your AMP markup will persist:
add_filter( 'wp_kses_allowed_html', function( $tags, $context ) {
    if ( ! class_exists( 'AMP_Allowed_Tags_Generated' ) || 'post' !== $context ) {
        return $tags;
    }

    $amp_component = 'amp-social-share';
    if ( ! isset( $tags[ $amp_component ] ) ) {
        $tags[ $amp_component ] = array();
    }

    $tags[ $amp_component ] = array_merge(
        // Layout attributes.
        array_fill_keys(
            array_keys( AMP_Allowed_Tags_Generated::get_layout_attributes() ),
            true
        ),
        // Global attributes. You may want to limit these to just the ones you need.
        array_fill_keys(
            array_keys( AMP_Allowed_Tags_Generated::get_allowed_attributes() ),
            true
        ),
        $tags[ $amp_component ]
    );

    $amp_tag_specs = AMP_Allowed_Tags_Generated::get_allowed_tag( $amp_component );
    foreach ( $amp_tag_specs as $amp_tag_spec ) {
        if ( ! isset( $amp_tag_spec[ AMP_Rule_Spec::ATTR_SPEC_LIST ] ) ) {
            continue;
        }
        $tags[ $amp_component ] = array_merge(
            $tags[ $amp_component ],
            array_fill_keys( array_keys( $amp_tag_spec[ AMP_Rule_Spec::ATTR_SPEC_LIST ] ), true )
        );
    }

    return $tags;
}, 10, 2 );