diff --git a/amp.php b/amp.php
index f854b6caea3..3bbb9ac540f 100644
--- a/amp.php
+++ b/amp.php
@@ -127,7 +127,20 @@ function amp_force_query_var_value( $query_vars ) {
* @return void
*/
function amp_maybe_add_actions() {
- if ( amp_is_canonical() || ! is_singular() || is_feed() ) {
+
+ // Add hooks for when a themes that support AMP.
+ if ( current_theme_supports( 'amp' ) ) {
+ if ( amp_is_canonical() ) {
+ AMP_Canonical_Mode_Actions::register_hooks();
+ } elseif ( is_amp_endpoint() ) {
+ AMP_Paired_Mode_Actions::register_hooks();
+ } else {
+ AMP_Frontend_Actions::register_hooks();
+ }
+ return;
+ }
+
+ if ( ! is_singular() || is_feed() ) {
return;
}
diff --git a/includes/actions/class-amp-canonical-mode-actions.php b/includes/actions/class-amp-canonical-mode-actions.php
new file mode 100644
index 00000000000..952da21096e
--- /dev/null
+++ b/includes/actions/class-amp-canonical-mode-actions.php
@@ -0,0 +1,191 @@
+.
+ add_action( 'wp_head', array( __CLASS__, 'print_meta_charset' ), 0 );
+ add_action( 'wp_head', array( __CLASS__, 'print_meta_viewport' ), 2 );
+ add_action( 'wp_head', array( __CLASS__, 'print_amp_boilerplate_code' ), 3 );
+ add_action( 'wp_head', array( __CLASS__, 'print_amp_scripts' ), 4 );
+ add_action( 'wp_head', array( __CLASS__, 'print_amp_custom_style' ), 5 );
+
+ add_action( 'admin_bar_init', array( __CLASS__, 'admin_bar_init' ) );
+ add_theme_support( 'admin-bar', array( 'callback' => '__return_false' ) );
+
+ // @todo Add output buffering.
+ // @todo Add character conversion.
+ }
+
+ /**
+ * Print meta charset tag.
+ *
+ * @link https://www.ampproject.org/docs/reference/spec#chrs
+ */
+ public static function print_meta_charset() {
+ echo '';
+ }
+
+ /**
+ * Print meta charset tag.
+ *
+ * @link https://www.ampproject.org/docs/reference/spec#vprt
+ */
+ public static function print_meta_viewport() {
+ echo '';
+ }
+
+ /**
+ * Print AMP boilerplate code.
+ *
+ * @link https://www.ampproject.org/docs/reference/spec#boilerplate
+ */
+ public static function print_amp_boilerplate_code() {
+ echo '';
+ echo '';
+ }
+
+ /**
+ * Print AMP script and placeholder for others.
+ *
+ * @link https://www.ampproject.org/docs/reference/spec#scrpt
+ */
+ public static function print_amp_scripts() {
+ echo ''; // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript
+ echo ''; // Replaced after output buffering with all AMP component scripts.
+ }
+
+ /**
+ * Add canonical link.
+ *
+ * Replaces `rel_canonical()` which only outputs canonical URLs for singular posts and pages.
+ * This can be removed once WP Core #18660 lands.
+ *
+ * @link https://www.ampproject.org/docs/reference/spec#canon.
+ * @link https://core.trac.wordpress.org/ticket/18660
+ *
+ * @see rel_canonical()
+ * @global WP $wp
+ * @global WP_Rewrite $wp_rewrite
+ */
+ public static function rel_canonical() {
+ global $wp, $wp_rewrite;
+
+ $url = null;
+ if ( is_singular() ) {
+ $url = wp_get_canonical_url();
+ }
+
+ // For non-singular queries, make use of the request URI and public query vars to determine canonical URL.
+ if ( empty( $url ) ) {
+ $added_query_vars = $wp->query_vars;
+ if ( ! $wp_rewrite->permalink_structure || empty( $wp->request ) ) {
+ $url = home_url( '/' );
+ } else {
+ $url = home_url( user_trailingslashit( $wp->request ) );
+ parse_str( $wp->matched_query, $matched_query_vars );
+ foreach ( $wp->query_vars as $key => $value ) {
+
+ // Remove query vars that were matched in the rewrite rules for the request.
+ if ( isset( $matched_query_vars[ $key ] ) ) {
+ unset( $added_query_vars[ $key ] );
+ }
+ }
+ }
+ }
+
+ if ( ! empty( $added_query_vars ) ) {
+ $url = add_query_arg( $added_query_vars, $url );
+ }
+
+ echo '' . "\n";
+ }
+
+ /**
+ * Print Custom AMP styles.
+ *
+ * @see wp_custom_css_cb()
+ */
+ public static function print_amp_custom_style() {
+ echo '';
+ }
+
+ /**
+ * Fix up admin bar.
+ */
+ public static function admin_bar_init() {
+ remove_action( 'wp_head', 'wp_admin_bar_header' );
+ add_action( 'admin_bar_menu', array( __CLASS__, 'remove_customize_support_script' ), 100 ); // See WP_Admin_Bar::add_menus().
+ add_filter( 'body_class', array( __CLASS__, array( __CLASS__, 'filter_body_class_to_force_customize_support' ) ) );
+ }
+
+ /**
+ * Let the body class include customize-support by default since support script won't be able to dynamically add it.
+ *
+ * @see wp_customize_support_script()
+ *
+ * @param array $classes Body classes.
+ * @return array Classes.
+ */
+ public static function filter_body_class_to_force_customize_support( $classes ) {
+ $i = array_search( 'no-customize-support', $classes, true );
+ if ( false !== $i ) {
+ array_splice( $classes, $i, 1 );
+ }
+ $classes[] = 'customize-support';
+ return $classes;
+ }
+
+ /**
+ * Remove Customizer support script.
+ *
+ * @see WP_Admin_Bar::add_menus()
+ * @see wp_customize_support_script()
+ */
+ public static function remove_customize_support_script() {
+ remove_action( 'wp_before_admin_bar_render', 'wp_customize_support_script' );
+ }
+}
diff --git a/includes/actions/class-amp-paired-mode-actions.php b/includes/actions/class-amp-paired-mode-actions.php
new file mode 100644
index 00000000000..8e3531936b1
--- /dev/null
+++ b/includes/actions/class-amp-paired-mode-actions.php
@@ -0,0 +1,21 @@
+ 'includes/actions/class-amp-actions',
'AMP_Frontend_Actions' => 'includes/actions/class-amp-frontend-actions',
'AMP_Paired_Post_Actions' => 'includes/actions/class-amp-paired-post-actions',
+ 'AMP_Paired_Mode_Actions' => 'includes/actions/class-amp-paired-mode-actions',
+ 'AMP_Canonical_Mode_Actions' => 'includes/actions/class-amp-canonical-mode-actions',
'AMP_Template_Customizer' => 'includes/admin/class-amp-customizer',
'AMP_Post_Meta_Box' => 'includes/admin/class-amp-post-meta-box',
'AMP_Post_Type_Support' => 'includes/class-amp-post-type-support',