Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved page default status logic and add overwrite ability; ensure front page and page for posts can be served as AMP when enabled #872

Merged
merged 11 commits into from
Jan 18, 2018
Merged
68 changes: 58 additions & 10 deletions amp.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ function amp_after_setup_theme() {
add_filter( 'amp_post_template_analytics', 'amp_add_custom_analytics' );
add_action( 'wp_loaded', 'amp_post_meta_box' );
add_action( 'wp_loaded', 'amp_add_options_menu' );
add_action( 'parse_query', 'amp_correct_query_when_is_front_page' );
AMP_Post_Type_Support::add_post_type_support();
}
add_action( 'after_setup_theme', 'amp_after_setup_theme', 5 );
Expand Down Expand Up @@ -117,22 +118,69 @@ function amp_force_query_var_value( $query_vars ) {
return $query_vars;
}

/**
* Fix up WP_Query for front page when amp query var is present.
*
* Normally the front page would not get served if a query var is present other than preview, page, paged, and cpage.
*
* @since 0.6
* @see WP_Query::parse_query()
* @link https://github.com/WordPress/wordpress-develop/blob/0baa8ae85c670d338e78e408f8d6e301c6410c86/src/wp-includes/class-wp-query.php#L951-L971
*
* @param WP_Query $query Query.
*/
function amp_correct_query_when_is_front_page( WP_Query $query ) {
$is_front_page_query = (
$query->is_main_query()
&&
$query->is_home()
&&
// Is AMP endpoint.
false !== $query->get( AMP_QUERY_VAR, false )
&&
// Is query not yet fixed uo up to be front page.
! $query->is_front_page()
&&
// Is showing pages on front.
'page' === get_option( 'show_on_front' )
&&
// Has page on front set.
get_option( 'page_on_front' )
&&
// See line in WP_Query::parse_query() at <https://github.com/WordPress/wordpress-develop/blob/0baa8ae/src/wp-includes/class-wp-query.php#L961>.
0 === count( array_diff( array_keys( wp_parse_args( $query->query ) ), array( AMP_QUERY_VAR, 'preview', 'page', 'paged', 'cpage' ) ) )
);
if ( $is_front_page_query ) {
$query->is_home = false;
$query->is_page = true;
$query->is_singular = true;
$query->set( 'page_id', get_option( 'page_on_front' ) );
}
}

/**
* Add AMP actions when the request can be served as AMP.
*
* Actions will only be added if the request is for a singular post (including front page and page for posts), excluding feeds.
*
* @since 0.2
*/
function amp_maybe_add_actions() {
if ( ! is_singular() || is_feed() ) {
global $wp_query;
if ( ! ( is_singular() || $wp_query->is_posts_page ) || is_feed() ) {
return;
}

$is_amp_endpoint = is_amp_endpoint();

// Cannot use `get_queried_object` before canonical redirect; see https://core.trac.wordpress.org/ticket/35344
global $wp_query;
$post = $wp_query->post;

$supports = post_supports_amp( $post );

if ( ! $supports ) {
/**
* Queried post object.
*
* @var WP_Post $post
*/
$post = get_queried_object();
if ( ! post_supports_amp( $post ) ) {
if ( $is_amp_endpoint ) {
wp_safe_redirect( get_permalink( $post->ID ), 301 );
wp_safe_redirect( get_permalink( $post->ID ), 302 ); // Temporary redirect because AMP may be supported in future.
exit;
}
return;
Expand Down
12 changes: 8 additions & 4 deletions assets/js/amp-post-meta-box.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ var ampPostMetaBox = ( function( $ ) {
*/
data: {
previewLink: '',
disabled: false,
enabled: true, // Overridden by post_supports_amp( $post ).
canSupport: true, // Overridden by count( AMP_Post_Type_Support::get_support_errors( $post ) ) === 0.
statusInputName: '',
l10n: {
ampPreviewBtnLabel: ''
Expand Down Expand Up @@ -58,7 +59,8 @@ var ampPostMetaBox = ( function( $ ) {
component.boot = function boot( data ) {
component.data = data;
$( document ).ready( function() {
if ( ! component.data.disabled ) {
component.statusRadioInputs = $( '[name="' + component.data.statusInputName + '"]' );
if ( component.data.enabled ) {
component.addPreviewButton();
}
component.listen();
Expand All @@ -77,8 +79,10 @@ var ampPostMetaBox = ( function( $ ) {
component.onAmpPreviewButtonClick();
} );

component.statusRadioInputs.prop( 'disabled', true ); // Prevent cementing setting default status as overridden status.
$( '.edit-amp-status, [href="#amp_status"]' ).click( function( e ) {
e.preventDefault();
component.statusRadioInputs.prop( 'disabled', false );
component.toggleAmpStatus( $( e.target ) );
} );

Expand Down Expand Up @@ -147,7 +151,7 @@ var ampPostMetaBox = ( function( $ ) {

// Don't modify status on cancel button click.
if ( ! $target.hasClass( 'button-cancel' ) ) {
status = $( '[name="' + component.data.statusInputName + '"]:checked' ).val();
status = component.statusRadioInputs.filter( ':checked' ).val();
}

$checked = $( '#amp-status-' + status );
Expand All @@ -161,7 +165,7 @@ var ampPostMetaBox = ( function( $ ) {
$container.slideToggle( component.toggleSpeed );

// Update status.
if ( ! component.data.disabled ) {
if ( component.data.canSupport ) {
$container.data( 'amp-status', status );
$checked.prop( 'checked', true );
$( '.amp-status-text' ).text( $checked.next().text() );
Expand Down
78 changes: 50 additions & 28 deletions includes/admin/class-amp-post-meta-box.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,28 @@ class AMP_Post_Meta_Box {
const ASSETS_HANDLE = 'amp-post-meta-box';

/**
* The post meta key for whether the post is skipped.
* The enabled status post meta value.
*
* @since 0.6
* @var string
*/
const DISABLED_POST_META_KEY = 'amp_disabled';
const ENABLED_STATUS = 'enabled';

/**
* The disabled status post meta value.
*
* @since 0.6
* @var string
*/
const DISABLED_STATUS = 'disabled';

/**
* The status post meta key.
*
* @since 0.6
* @var string
*/
const STATUS_POST_META_KEY = 'amp_status';

/**
* The field name for the enabled/disabled radio buttons.
Expand Down Expand Up @@ -59,32 +75,38 @@ class AMP_Post_Meta_Box {
* @since 0.6
*/
public function init() {
register_meta( 'post', self::STATUS_POST_META_KEY, array(
'sanitize_callback' => array( $this, 'sanitize_status' ),
'type' => 'string',
'description' => __( 'AMP status.', 'amp' ),
'show_in_rest' => true,
'single' => true,
) );

add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) );
add_action( 'post_submitbox_misc_actions', array( $this, 'render_status' ) );
add_action( 'save_post', array( $this, 'save_amp_status' ) );
add_filter( 'preview_post_link', array( $this, 'preview_post_link' ) );
}

/**
* Get whether AMP is available for a given post.
*
* This is just calling `post_supports_amp()` but ignoring any user-supplied opt-out for AMP.
* Sanitize status.
*
* @since 0.6
* @see post_supports_amp()
*
* @param WP_Post $post Post.
* @return bool Whether or not AMP is available.
* @param string $status Status.
* @return string Sanitized status. Empty string when invalid.
*/
protected function is_amp_available( $post ) {
$support_errors = AMP_Post_Type_Support::get_support_errors( $post );
if ( empty( $support_errors ) ) {
return true;
}
if ( 1 === count( $support_errors ) && 'post-disabled' === $support_errors[0] ) {
return true;
public function sanitize_status( $status ) {
$status = strtolower( trim( $status ) );
if ( ! in_array( $status, array( 'enabled', 'disabled' ), true ) ) {
/*
* In lieu of actual validation being available, clear the status entirely
* so that the underlying default status will be used instead.
* In the future it would be ideal if register_meta() accepted a
* validate_callback as well which the REST API could leverage.
*/
$status = '';
}
return false;
return $status;
}

/**
Expand Down Expand Up @@ -122,7 +144,8 @@ public function enqueue_admin_assets() {
wp_add_inline_script( self::ASSETS_HANDLE, sprintf( 'ampPostMetaBox.boot( %s );',
wp_json_encode( array(
'previewLink' => esc_url_raw( add_query_arg( AMP_QUERY_VAR, '', get_preview_post_link( $post ) ) ),
'disabled' => (bool) get_post_meta( $post->ID, self::DISABLED_POST_META_KEY, true ) || ! $this->is_amp_available( $post ),
'enabled' => post_supports_amp( $post ),
'canSupport' => count( AMP_Post_Type_Support::get_support_errors( $post ) ) === 0,
'statusInputName' => self::STATUS_INPUT_NAME,
'l10n' => array(
'ampPreviewBtnLabel' => __( 'Preview changes in AMP (opens in new window)', 'amp' ),
Expand All @@ -148,10 +171,9 @@ public function render_status( $post ) {
return;
}

$available = $this->is_amp_available( $post );
$disabled = (bool) get_post_meta( $post->ID, self::DISABLED_POST_META_KEY, true );
$status = $disabled || ! $available ? 'disabled' : 'enabled';
$labels = array(
$errors = AMP_Post_Type_Support::get_support_errors( $post );
$status = post_supports_amp( $post ) ? self::ENABLED_STATUS : self::DISABLED_STATUS;
$labels = array(
'enabled' => __( 'Enabled', 'amp' ),
'disabled' => __( 'Disabled', 'amp' ),
);
Expand Down Expand Up @@ -182,11 +204,11 @@ public function save_amp_status( $post_id ) {
);

if ( true === $verify ) {
if ( 'disabled' === $_POST[ self::STATUS_INPUT_NAME ] ) {
update_post_meta( $post_id, self::DISABLED_POST_META_KEY, true );
} else {
delete_post_meta( $post_id, self::DISABLED_POST_META_KEY );
}
update_post_meta(
$post_id,
self::STATUS_POST_META_KEY,
$_POST[ self::STATUS_INPUT_NAME ] // Note: The sanitize_callback has been supplied in the register_meta() call above.
);
}
}

Expand Down
44 changes: 42 additions & 2 deletions includes/amp-helper-functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,55 @@ function amp_get_permalink( $post_id ) {
* Determine whether a given post supports AMP.
*
* @since 0.1
* @since 0.6 Returns false when post has meta to disable AMP or when page is homepage or page for posts.
* @since 0.6 Returns false when post has meta to disable AMP.
* @see AMP_Post_Type_Support::get_support_errors()
*
* @param WP_Post $post Post.
*
* @return bool Whether the post supports AMP.
*/
function post_supports_amp( $post ) {
return 0 === count( AMP_Post_Type_Support::get_support_errors( $post ) );
$errors = AMP_Post_Type_Support::get_support_errors( $post );

// Return false if an error is found.
if ( ! empty( $errors ) ) {
return false;
}

switch ( get_post_meta( $post->ID, AMP_Post_Meta_Box::STATUS_POST_META_KEY, true ) ) {
case AMP_Post_Meta_Box::ENABLED_STATUS:
return true;

case AMP_Post_Meta_Box::DISABLED_STATUS:
return false;

// Disabled by default for custom page templates, page on front and page for posts.
default:
$enabled = (
! (bool) get_page_template_slug( $post )
&&
! (
'page' === $post->post_type
&&
'page' === get_option( 'show_on_front' )
&&
in_array( (int) $post->ID, array(
(int) get_option( 'page_on_front' ),
(int) get_option( 'page_for_posts' ),
), true )
)
);

/**
* Filters whether default AMP status should be enabled or not.
*
* @since 0.6
*
* @param string $status Status.
* @param WP_Post $post Post.
*/
return apply_filters( 'amp_post_status_default_enabled', $enabled, $post );
}
}

/**
Expand Down
17 changes: 2 additions & 15 deletions includes/class-amp-post-type-support.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class AMP_Post_Type_Support {
* @return string[] Post types.
*/
public static function get_builtin_supported_post_types() {
return array_filter( array( 'post', 'page' ), 'post_type_exists' );
return array_filter( array( 'post' ), 'post_type_exists' );
}

/**
Expand All @@ -29,6 +29,7 @@ public static function get_builtin_supported_post_types() {
public static function get_eligible_post_types() {
return array_merge(
self::get_builtin_supported_post_types(),
array( 'page' ),
array_values( get_post_types(
array(
'public' => true,
Expand Down Expand Up @@ -76,20 +77,6 @@ public static function get_support_errors( $post ) {
$errors[] = 'post-type-support';
}

// Skip based on postmeta.
if ( ! isset( $post->ID ) || (bool) get_post_meta( $post->ID, AMP_Post_Meta_Box::DISABLED_POST_META_KEY, true ) ) {
$errors[] = 'post-disabled';
}

// Homepage and page for posts are not supported yet.
if ( 'page' === get_post_type( $post ) && 'page' === get_option( 'show_on_front' ) ) {
if ( (int) get_option( 'page_for_posts' ) === (int) $post->ID ) {
$errors[] = 'page-for-posts';
} elseif ( (int) get_option( 'page_on_front' ) === (int) $post->ID ) {
$errors[] = 'page-on-front';
}
}

if ( post_password_required( $post ) ) {
$errors[] = 'password-protected';
}
Expand Down
3 changes: 2 additions & 1 deletion includes/templates/class-amp-post-template.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,8 @@ public function get_customizer_setting( $name, $default = null ) {
* Load and print the template parts for the given post.
*/
public function load() {
$template = is_page() ? 'page' : 'single';
global $wp_query;
$template = is_page() || $wp_query->is_posts_page ? 'page' : 'single';
$this->load_parts( array( $template ) );
}

Expand Down
Loading