From 143cd2a21b547b0f92f5ebb4816ffdd8d9ba0fa9 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Thu, 21 Jun 2018 17:12:35 -0700 Subject: [PATCH 01/34] WIP --- amp.php | 50 ++++++++++++++++--- includes/class-amp-theme-support.php | 49 +++++++++++++----- .../options/class-amp-options-manager.php | 20 ++++---- includes/options/class-amp-options-menu.php | 36 ++++++++++--- tests/test-class-amp-theme-support.php | 14 +++--- 5 files changed, 124 insertions(+), 45 deletions(-) diff --git a/amp.php b/amp.php index ef419328c96..43542fb3669 100644 --- a/amp.php +++ b/amp.php @@ -272,15 +272,36 @@ function amp_correct_query_when_is_front_page( WP_Query $query ) { } /** - * Whether this is in 'canonical mode.' + * Whether this is in 'canonical mode'. * - * Themes can register support for this with `add_theme_support( 'amp' )`. - * Then, this will change the plugin from 'paired mode,' and it won't use its own templates. - * Nor output frontend markup like the 'rel' link. If the theme registers support for AMP with: - * `add_theme_support( 'amp', array( 'template_dir' => 'my-amp-templates' ) )` - * it will retain 'paired mode. + * Themes can register support for this with `add_theme_support( 'amp' )`, or via the + * following so that only so that single blog posts will be native/canonical, pages are paired, + * and everything else has AMP unavailable: * - * @return boolean Whether this is in AMP 'canonical mode'. + * add_theme_support( 'amp', array( + * 'template_dir' => 'amp-templates/', // Optional. In case you need to override the template as a whole. + * 'available_callback' => function() { + * // @todo Warning: If a plugin or theme calls is_amp_endpoint() before parse_query() then the conditionals will not work! + * if ( is_single() ) { + * return 'native'; + * } elseif ( is_page() ) { + * return 'paired'; // Or 'true'. + * } else { + * return false; + * } + * }, + * ) ); + * + * Then, this will change the plugin so that it won't run in 'paired mode' with separate URLs. + * Neither will it output the rel=amphtml link on the frontend. + * + * Paired mode will be retained if the theme registers support for AMP with just a template_dir and no available_callback: + * + * add_theme_support( 'amp', array( + * 'template_dir' => 'my-amp-templates', + * ) ); + * + * @return boolean Whether this is in AMP 'canonical' mode, that is whether it is native and there is not separate AMP URL current URL. */ function amp_is_canonical() { $support = get_theme_support( 'amp' ); @@ -289,9 +310,22 @@ function amp_is_canonical() { } if ( is_array( $support ) ) { $args = array_shift( $support ); - if ( empty( $args['template_dir'] ) ) { + + $is_native = ( + isset( $args['available_callback'] ) + && + is_callable( $args['available_callback'] ) + && + 'native' === call_user_func( $args['available_callback'] ) + ); + if ( $is_native ) { return true; } + + // If there is no available_callback and yet there is a template_dir, then paired mode is implied. + if ( empty( $args['available_callback'] ) && ! empty( $args['template_dir'] ) ) { + return false; + } } return false; } diff --git a/includes/class-amp-theme-support.php b/includes/class-amp-theme-support.php index 7389490b2bb..a43189097ab 100644 --- a/includes/class-amp-theme-support.php +++ b/includes/class-amp-theme-support.php @@ -24,7 +24,7 @@ class AMP_Theme_Support { * * @var string */ - const RESPONSE_CACHE_GROUP = 'amp-reponse'; + const RESPONSE_CACHE_GROUP = 'amp-response'; /** * Sanitizer classes. @@ -148,8 +148,24 @@ public static function apply_options() { $args = array( '__added_via_option' => true, ); - if ( 'paired' === $theme_support_option ) { - $args['template_dir'] = './'; + if ( 'native' === $theme_support_option ) { + $args['available_callback'] = function() { + /** + * Queried object. + * + * @var WP_Post $queried_object + */ + $queried_object = get_queried_object(); + if ( is_singular() && post_supports_amp( $queried_object ) ) { + return 'native'; + } + + if ( AMP_Options_Manager::get_option( 'non_singular_supported' ) ) { + return 'native'; + } + + return false; + }; } add_theme_support( 'amp', $args ); } @@ -168,8 +184,9 @@ public static function finish_init() { self::ensure_proper_amp_location(); - if ( ! amp_is_canonical() ) { - self::register_paired_hooks(); + $theme_support = get_theme_support( 'amp' ); + if ( ! empty( $theme_support[0]['template_dir'] ) ) { + self::add_amp_template_filters(); } self::add_hooks(); @@ -285,8 +302,14 @@ public static function is_paired_available() { $args = array_shift( $support ); if ( isset( $args['available_callback'] ) && is_callable( $args['available_callback'] ) ) { - return call_user_func( $args['available_callback'] ); + /* + * The available_callback here will return a bool or the string 'paired'. + * If it returns 'native' then `amp_is_canonical()` above would have short-circuited. + */ + return (bool) call_user_func( $args['available_callback'] ); } + + // This is the same as if there is a template_dir defined with no available_callback. return true; } @@ -303,13 +326,13 @@ public static function is_customize_preview_iframe() { } /** - * Register hooks for paired mode. + * Register filters for loading AMP-specific templates. */ - public static function register_paired_hooks() { + public static function add_amp_template_filters() { foreach ( self::$template_types as $template_type ) { - add_filter( "{$template_type}_template_hierarchy", array( __CLASS__, 'filter_paired_template_hierarchy' ) ); + add_filter( "{$template_type}_template_hierarchy", array( __CLASS__, 'filter_amp_template_hierarchy' ) ); } - add_filter( 'template_include', array( __CLASS__, 'filter_paired_template_include' ), 100 ); + add_filter( 'template_include', array( __CLASS__, 'filter_amp_template_include' ), 100 ); } /** @@ -727,7 +750,7 @@ public static function amend_comment_form() { * @param array $templates Template hierarchy. * @return array Templates. */ - public static function filter_paired_template_hierarchy( $templates ) { + public static function filter_amp_template_hierarchy( $templates ) { $support = get_theme_support( 'amp' ); $args = array_shift( $support ); if ( isset( $args['template_dir'] ) ) { @@ -749,8 +772,8 @@ public static function filter_paired_template_hierarchy( $templates ) { * @param string $template Template to include. * @return string Template to include. */ - public static function filter_paired_template_include( $template ) { - if ( empty( $template ) || ! self::is_paired_available() ) { + public static function filter_amp_template_include( $template ) { + if ( empty( $template ) ) { wp_safe_redirect( self::get_current_canonical_url(), 302 ); // Temporary redirect because support may come later. exit; } diff --git a/includes/options/class-amp-options-manager.php b/includes/options/class-amp-options-manager.php index 7e0fbf4018e..c41ce3acdc7 100644 --- a/includes/options/class-amp-options-manager.php +++ b/includes/options/class-amp-options-manager.php @@ -23,12 +23,13 @@ class AMP_Options_Manager { * @var array */ protected static $defaults = array( - 'theme_support' => 'disabled', - 'supported_post_types' => array(), - 'analytics' => array(), - 'force_sanitization' => false, - 'accept_tree_shaking' => false, - 'disable_admin_bar' => false, + 'theme_support' => 'disabled', + 'supported_post_types' => array(), + 'analytics' => array(), + 'force_sanitization' => false, + 'accept_tree_shaking' => false, + 'disable_admin_bar' => false, + 'non_singular_supported' => true, ); /** @@ -116,9 +117,10 @@ public static function validate_options( $new_options ) { $options['theme_support'] = $new_options['theme_support']; } - $options['force_sanitization'] = ! empty( $new_options['force_sanitization'] ); - $options['accept_tree_shaking'] = ! empty( $new_options['accept_tree_shaking'] ); - $options['disable_admin_bar'] = ! empty( $new_options['disable_admin_bar'] ); + $options['force_sanitization'] = ! empty( $new_options['force_sanitization'] ); + $options['accept_tree_shaking'] = ! empty( $new_options['accept_tree_shaking'] ); + $options['disable_admin_bar'] = ! empty( $new_options['disable_admin_bar'] ); + $options['non_singular_supported'] = ! empty( $new_options['non_singular_supported'] ); // Validate post type support. if ( isset( $new_options['supported_post_types'] ) ) { diff --git a/includes/options/class-amp-options-menu.php b/includes/options/class-amp-options-menu.php index f3e51f34f7b..2c5eb81f3fc 100644 --- a/includes/options/class-amp-options-menu.php +++ b/includes/options/class-amp-options-menu.php @@ -99,9 +99,9 @@ public function add_menu_items() { ); add_settings_field( - 'supported_post_types', - __( 'Post Type Support', 'amp' ), - array( $this, 'render_post_types_support' ), + 'supported_queries', + __( 'Supported Queries', 'amp' ), + array( $this, 'render_supported_queries' ), AMP_Options_Manager::OPTION_NAME, 'general', array( @@ -276,16 +276,36 @@ public function render_validation_handling() { * * @since 0.6 */ - public function render_post_types_support() { - $builtin_support = AMP_Post_Type_Support::get_builtin_supported_post_types(); - $element_name = AMP_Options_Manager::OPTION_NAME . '[supported_post_types][]'; + public function render_supported_queries() { ?> + +
+

+ +

+

+ +

+
+
+ + +

+
+ + name}"; @@ -299,7 +319,7 @@ public function render_post_types_support() { id="" name="" value="name ); ?>" - name, amp_get_slug() ) ); ?> + name, amp_get_slug() ) ); ?> >