Skip to content

Commit

Permalink
Merge pull request #1199 from Automattic/add/admin-theme-support-options
Browse files Browse the repository at this point in the history
Add theme support settings to admin screen; prevent serving dirty AMP
  • Loading branch information
westonruter authored Jun 8, 2018
2 parents 6e6275b + 421dc74 commit 634fbb8
Show file tree
Hide file tree
Showing 17 changed files with 912 additions and 317 deletions.
21 changes: 17 additions & 4 deletions assets/js/amp-block-validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ var ampBlockValidation = ( function() { // eslint-disable-line no-unused-vars
*/
data: {
i18n: {},
ampValidityRestField: ''
ampValidityRestField: '',
isCanonical: false
},

/**
Expand Down Expand Up @@ -91,22 +92,28 @@ var ampBlockValidation = ( function() { // eslint-disable-line no-unused-vars
/**
* Handle state change regarding validation errors.
*
* This is essentially a JS implementation of \AMP_Validation_Manager::print_edit_form_validation_status() in PHP.
*
* @return {void}
*/
handleValidationErrorsStateChange: function handleValidationErrorsStateChange() {
var currentPost, validationErrors, blockValidationErrors, noticeElement, noticeMessage, blockErrorCount, ampValidity;
var currentPost, validationErrors, blockValidationErrors, noticeElement, noticeMessage, blockErrorCount, ampValidity, hasActuallyUnacceptedError;

// @todo Gutenberg currently is not persisting isDirty state if changes are made during save request. Block order mismatch.
// We can only align block validation errors with blocks in editor when in saved state, since only here will the blocks be aligned with the validation errors.
if ( wp.data.select( 'core/editor' ).isEditedPostDirty() ) {
return;
}

hasActuallyUnacceptedError = false;
currentPost = wp.data.select( 'core/editor' ).getCurrentPost();
ampValidity = currentPost[ module.data.ampValidityRestField ] || {};
validationErrors = _.map(
_.filter( ampValidity.results, function( result ) {
return ! result.sanitized;
if ( result.status !== 1 /* ACCEPTED */ ) {
hasActuallyUnacceptedError = true;
}
return result.term_status !== 1; /* ACCEPTED */
} ),
function( result ) {
return result.error;
Expand Down Expand Up @@ -179,7 +186,13 @@ var ampBlockValidation = ( function() { // eslint-disable-line no-unused-vars
);
}

noticeMessage += ' ' + wp.i18n.__( 'Non-accepted validation errors prevent AMP from being served.', 'amp' );
noticeMessage += ' ';
if ( hasActuallyUnacceptedError && ! module.data.isCanonical ) {
noticeMessage += wp.i18n.__( 'Non-accepted validation errors prevent AMP from being served, and the user will be redirected to the non-AMP version.', 'amp' );
} else {
noticeMessage += wp.i18n.__( 'The invalid markup will be automatically sanitized to ensure a valid AMP response is served.', 'amp' );
}

noticeElement = wp.element.createElement( 'p', {}, [
noticeMessage + ' ',
ampValidity.review_link && wp.element.createElement(
Expand Down
69 changes: 20 additions & 49 deletions includes/admin/class-amp-editor-blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ public function init() {
if ( function_exists( 'gutenberg_init' ) ) {
add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_block_editor_assets' ) );
add_filter( 'wp_kses_allowed_html', array( $this, 'whitelist_block_atts_in_wp_kses_allowed_html' ), 10, 2 );
add_filter( 'the_content', array( $this, 'tally_content_requiring_amp_scripts' ) );
add_action( 'wp_print_footer_scripts', array( $this, 'print_dirty_amp_scripts' ) );
}
}

Expand Down Expand Up @@ -109,27 +107,28 @@ public function whitelist_block_atts_in_wp_kses_allowed_html( $tags, $context )
*/
public function enqueue_block_editor_assets() {

// Styles.
wp_enqueue_style(
'amp-editor-blocks-style',
amp_get_asset_url( 'css/amp-editor-blocks.css' ),
array(),
AMP__VERSION
);
// Enqueue script and style for AMP-specific blocks.
if ( amp_is_canonical() ) {
wp_enqueue_style(
'amp-editor-blocks-style',
amp_get_asset_url( 'css/amp-editor-blocks.css' ),
array(),
AMP__VERSION
);

// Scripts.
wp_enqueue_script(
'amp-editor-blocks-build',
amp_get_asset_url( 'js/amp-blocks-compiled.js' ),
array( 'wp-blocks', 'lodash', 'wp-i18n', 'wp-element', 'wp-components' ),
AMP__VERSION
);
wp_enqueue_script(
'amp-editor-blocks-build',
amp_get_asset_url( 'js/amp-blocks-compiled.js' ),
array( 'wp-blocks', 'lodash', 'wp-i18n', 'wp-element', 'wp-components' ),
AMP__VERSION
);

wp_add_inline_script(
'amp-editor-blocks-build',
'wp.i18n.setLocaleData( ' . wp_json_encode( gutenberg_get_jed_locale_data( 'amp' ) ) . ', "amp" );',
'before'
);
wp_add_inline_script(
'amp-editor-blocks-build',
'wp.i18n.setLocaleData( ' . wp_json_encode( gutenberg_get_jed_locale_data( 'amp' ) ) . ', "amp" );',
'before'
);
}

wp_enqueue_script(
'amp-editor-blocks',
Expand All @@ -146,32 +145,4 @@ public function enqueue_block_editor_assets() {
) ) )
);
}

/**
* Tally the AMP component scripts that are needed in a dirty AMP document.
*
* @param string $content Content.
* @return string Content (unmodified).
*/
public function tally_content_requiring_amp_scripts( $content ) {
if ( ! is_amp_endpoint() ) {
$pattern = sprintf( '/<(%s)\b.*?>/s', join( '|', $this->amp_blocks ) );
if ( preg_match_all( $pattern, $content, $matches ) ) {
$this->content_required_amp_scripts = array_merge(
$this->content_required_amp_scripts,
$matches[1]
);
}
}
return $content;
}

/**
* Print AMP scripts required for AMP components used in a non-AMP document (dirty AMP).
*/
public function print_dirty_amp_scripts() {
if ( ! is_amp_endpoint() && ! empty( $this->content_required_amp_scripts ) ) {
wp_scripts()->do_items( $this->content_required_amp_scripts );
}
}
}
1 change: 1 addition & 0 deletions includes/amp-frontend-actions.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*
* @since 0.2
* @since 1.0 Deprecated
* @see amp_add_amphtml_link()
*/
function amp_frontend_add_canonical() {
_deprecated_function( __FUNCTION__, '1.0', 'amp_add_amphtml_link' );
Expand Down
43 changes: 40 additions & 3 deletions includes/amp-helper-functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ function amp_remove_endpoint( $url ) {
/**
* Add amphtml link.
*
* If there are known validation errors for the current URL then do not output anything.
*
* @since 1.0
*/
function amp_add_amphtml_link() {
Expand All @@ -183,12 +185,47 @@ function amp_add_amphtml_link() {
return;
}

$current_url = amp_get_current_url();

$amp_url = null;
if ( is_singular() ) {
$amp_url = amp_get_permalink( get_queried_object_id() );
if ( current_theme_supports( 'amp' ) ) {
if ( AMP_Theme_Support::is_paired_available() ) {
$amp_url = add_query_arg( amp_get_slug(), '', $current_url );
}
} else {
$amp_url = add_query_arg( amp_get_slug(), '', amp_get_current_url() );
if ( is_singular() ) {
$amp_url = amp_get_permalink( get_queried_object_id() );
} else {
$amp_url = add_query_arg( amp_get_slug(), '', $current_url );
}
}

if ( ! $amp_url ) {
printf( '<!-- %s -->', esc_html__( 'There is no amphtml version available for this URL.', 'amp' ) );
return;
}

// Check to see if there are known unaccepted validation errors for this URL.
if ( current_theme_supports( 'amp' ) ) {
$validation_errors = AMP_Invalid_URL_Post_Type::get_invalid_url_validation_errors( $current_url, array( 'ignore_accepted' => true ) );
$error_count = count( $validation_errors );
if ( $error_count > 0 ) {
echo "<!--\n";
echo esc_html( sprintf(
/* translators: %s is error count */
_n(
'There is %s validation error that is blocking the amphtml version from being available.',
'There are %s validation errors that are blocking the amphtml version from being available.',
$error_count,
'amp'
),
number_format_i18n( $error_count )
) );
echo "\n-->";
return;
}
}

if ( $amp_url ) {
printf( '<link rel="amphtml" href="%s">', esc_url( $amp_url ) );
}
Expand Down
48 changes: 42 additions & 6 deletions includes/class-amp-theme-support.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ class AMP_Theme_Support {
* @since 0.7
*/
public static function init() {
self::apply_options();
if ( ! current_theme_supports( 'amp' ) ) {
return;
}
Expand All @@ -117,7 +118,7 @@ public static function init() {
$args = array_shift( $support );
if ( ! is_array( $args ) ) {
trigger_error( esc_html__( 'Expected AMP theme support arg to be array.', 'amp' ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
} elseif ( count( array_diff( array_keys( $args ), array( 'template_dir', 'available_callback', 'comments_live_list' ) ) ) !== 0 ) {
} elseif ( count( array_diff( array_keys( $args ), array( 'template_dir', 'available_callback', 'comments_live_list', '__added_via_option' ) ) ) !== 0 ) {
trigger_error( esc_html__( 'Expected AMP theme support to only have template_dir and/or available_callback.', 'amp' ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
}
}
Expand All @@ -132,16 +133,36 @@ public static function init() {
add_action( 'wp', array( __CLASS__, 'finish_init' ), PHP_INT_MAX );
}

/**
* Apply options for whether theme support is enabled via admin and what sanitization is performed by default.
*
* @see AMP_Post_Type_Support::add_post_type_support() For where post type support is added, since it is irrespective of theme support.
*/
public static function apply_options() {
if ( ! current_theme_supports( 'amp' ) ) {
$theme_support_option = AMP_Options_Manager::get_option( 'theme_support' );
if ( 'disabled' === $theme_support_option ) {
return;
}

$args = array(
'__added_via_option' => true,
);
if ( 'paired' === $theme_support_option ) {
$args['template_dir'] = './';
}
add_theme_support( 'amp', $args );
}
}

/**
* Finish initialization once query vars are set.
*
* @since 0.7
*/
public static function finish_init() {
if ( ! is_amp_endpoint() ) {
if ( self::is_paired_available() ) {
amp_add_frontend_actions();
}
amp_add_frontend_actions();
return;
}

Expand Down Expand Up @@ -1187,7 +1208,10 @@ public static function prepare_response( $response, $args = array() ) {
$dom_serialize_start = microtime( true );
self::ensure_required_markup( $dom );

if ( ! AMP_Validation_Manager::should_validate_response() && AMP_Validation_Manager::has_blocking_validation_errors() ) {
$blocking_error_count = AMP_Validation_Manager::count_blocking_validation_errors();
if ( ! AMP_Validation_Manager::should_validate_response() && $blocking_error_count > 0 ) {

// Note the canonical check will not currently ever be met because dirty AMP is not yet supported; all validation errors will forcibly be sanitized.
if ( amp_is_canonical() ) {
$dom->documentElement->removeAttribute( 'amp' );

Expand All @@ -1201,7 +1225,19 @@ public static function prepare_response( $response, $args = array() ) {
$head->appendChild( $script );
}
} else {
self::redirect_ampless_url( false );
$current_url = amp_get_current_url();
$ampless_url = amp_remove_endpoint( $current_url );
$ampless_url = add_query_arg(
AMP_Validation_Manager::VALIDATION_ERRORS_QUERY_VAR,
$blocking_error_count,
$ampless_url
);

/*
* Temporary redirect because AMP URL may return when blocking validation errors
* occur or when a non-canonical AMP theme is used.
*/
wp_safe_redirect( $ampless_url, 302 );
return esc_html__( 'Redirecting to non-AMP version.', 'amp' );
}
}
Expand Down
39 changes: 30 additions & 9 deletions includes/options/class-amp-options-manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@ class AMP_Options_Manager {
*/
const OPTION_NAME = 'amp-options';

/**
* Default option values.
*
* @var array
*/
protected static $defaults = array(
'theme_support' => 'disabled',
'supported_post_types' => array(),
'analytics' => array(),
'force_sanitization' => false,
'accept_tree_shaking' => false,
);

/**
* Register settings.
*/
Expand Down Expand Up @@ -58,7 +71,11 @@ public static function maybe_flush_rewrite_rules( $old_options, $new_options ) {
* @return array Options.
*/
public static function get_options() {
return get_option( self::OPTION_NAME, array() );
$options = get_option( self::OPTION_NAME, array() );
if ( empty( $options ) ) {
$options = array();
}
return array_merge( self::$defaults, $options );
}

/**
Expand Down Expand Up @@ -86,15 +103,20 @@ public static function get_option( $option, $default = false ) {
* @return array Options.
*/
public static function validate_options( $new_options ) {
$defaults = array(
'supported_post_types' => array(),
'analytics' => array(),
);
$options = self::get_options();

$options = array_merge(
$defaults,
self::get_options()
// Theme support.
$recognized_theme_supports = array(
'disabled',
'paired',
'native',
);
if ( isset( $new_options['theme_support'] ) && in_array( $new_options['theme_support'], $recognized_theme_supports, true ) ) {
$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'] );

// Validate post type support.
if ( isset( $new_options['supported_post_types'] ) ) {
Expand Down Expand Up @@ -156,7 +178,6 @@ public static function validate_options( $new_options ) {
return $options;
}


/**
* Check for errors with updating the supported post types.
*
Expand Down
Loading

0 comments on commit 634fbb8

Please sign in to comment.