PDF rausgenommen

This commit is contained in:
aschwarz
2023-01-23 11:03:31 +01:00
parent 82d562a322
commit a6523903eb
28078 changed files with 4247552 additions and 2 deletions

View File

@ -0,0 +1,149 @@
<?php
/**
* Admin pointer class.
*
* @package AMP
* @since 1.0
*/
/**
* AMP_Admin_Pointer class.
*
* Outputs an admin pointer to show the new features of v1.0.
* Based on https://code.tutsplus.com/articles/integrating-with-wordpress-ui-admin-pointers--wp-26853
*
* @since 1.0
*/
class AMP_Admin_Pointer {
/**
* The ID of the template mode admin pointer.
*
* @var string
*/
const TEMPLATE_POINTER_ID = 'amp_template_mode_pointer_10';
/**
* The slug of the script.
*
* @var string
*/
const SCRIPT_SLUG = 'amp-admin-pointer';
/**
* The slug of the tooltip script.
*
* @var string
*/
const TOOLTIP_SLUG = 'amp-validation-tooltips';
/**
* Initializes the class.
*
* @since 1.0
*/
public function init() {
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_pointer' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'register_tooltips' ) );
}
/**
* Enqueues the pointer assets.
*
* If the pointer has not been dismissed, enqueues the style and script.
* And outputs the pointer data for the script.
*
* @since 1.0
*/
public function enqueue_pointer() {
if ( $this->is_pointer_dismissed() ) {
return;
}
wp_enqueue_style( 'wp-pointer' );
wp_enqueue_script(
self::SCRIPT_SLUG,
amp_get_asset_url( 'js/' . self::SCRIPT_SLUG . '.js' ),
array( 'jquery', 'wp-pointer' ),
AMP__VERSION,
true
);
wp_add_inline_script(
self::SCRIPT_SLUG,
sprintf( 'ampAdminPointer.load( %s );', wp_json_encode( $this->get_pointer_data() ) )
);
}
/**
* Registers style and script for tooltips.
*
* @since 1.0
*/
public function register_tooltips() {
wp_register_style(
self::TOOLTIP_SLUG,
amp_get_asset_url( 'css/' . self::TOOLTIP_SLUG . '.css' ),
array( 'wp-pointer' ),
AMP__VERSION
);
wp_register_script(
self::TOOLTIP_SLUG,
amp_get_asset_url( 'js/' . self::TOOLTIP_SLUG . '.js' ),
array( 'jquery', 'wp-pointer' ),
AMP__VERSION,
true
);
}
/**
* Whether the AMP admin pointer has been dismissed.
*
* @since 1.0
* @return boolean Is dismissed.
*/
protected function is_pointer_dismissed() {
// Consider dismissed in v1.1, since admin pointer is only to educate about the new modes in 1.0.
if ( version_compare( strtok( AMP__VERSION, '-' ), '1.1', '>=' ) ) {
return true;
}
$dismissed = get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true );
if ( empty( $dismissed ) ) {
return false;
}
$dismissed = explode( ',', strval( $dismissed ) );
return in_array( self::TEMPLATE_POINTER_ID, $dismissed, true );
}
/**
* Gets the pointer data to pass to the script.
*
* @since 1.0
* @return array Pointer data.
*/
public function get_pointer_data() {
return array(
'pointer' => array(
'pointer_id' => self::TEMPLATE_POINTER_ID,
'target' => '#toplevel_page_amp-options',
'options' => array(
'content' => sprintf(
'<h3>%s</h3><p><strong>%s</strong></p><p>%s</p>',
__( 'AMP', 'amp' ),
__( 'New AMP Template Modes', 'amp' ),
__( 'You can now reuse your theme\'s templates and styles in AMP responses, in both &#8220;Transitional&#8221; and &#8220;Native&#8221; modes.', 'amp' )
),
'position' => array(
'edge' => 'left',
'align' => 'middle',
),
),
),
);
}
}

View File

@ -0,0 +1,332 @@
<?php
/**
* Class AMP_Template_Customizer
*
* @package AMP
*/
/**
* AMP class that implements a template style editor in the Customizer.
*
* A direct, formed link to the AMP editor in the Customizer is added via
* {@see amp_customizer_editor_link()} as a submenu to the Appearance menu.
*
* @since 0.4
*/
class AMP_Template_Customizer {
/**
* AMP template editor panel ID.
*
* @since 0.4
* @var string
*/
const PANEL_ID = 'amp_panel';
/**
* Customizer instance.
*
* @since 0.4
* @access protected
* @var WP_Customize_Manager $wp_customize
*/
protected $wp_customize;
/**
* Initialize the template Customizer feature class.
*
* @static
* @since 0.4
* @access public
*
* @param WP_Customize_Manager $wp_customize Customizer instance.
*/
public static function init( $wp_customize ) {
$self = new self();
$self->wp_customize = $wp_customize;
/**
* Fires when the AMP Template Customizer initializes.
*
* In practice the `customize_register` hook should be used instead.
*
* @since 0.4
* @param AMP_Template_Customizer $self Instance.
*/
do_action( 'amp_customizer_init', $self );
$self->register_settings();
$self->register_ui();
add_action( 'customize_controls_enqueue_scripts', array( $self, 'add_customizer_scripts' ) );
add_action( 'customize_controls_print_footer_scripts', array( $self, 'print_controls_templates' ) );
add_action( 'customize_preview_init', array( $self, 'init_preview' ) );
}
/**
* Init Customizer preview.
*
* @since 0.4
* @global WP_Customize_Manager $wp_customize
*/
public function init_preview() {
add_action( 'amp_post_template_head', 'wp_no_robots' );
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_preview_scripts' ) );
add_action( 'amp_customizer_enqueue_preview_scripts', array( $this, 'enqueue_preview_scripts' ) );
// Output scripts and styles which will break AMP validation only when preview is opened with controls for manipulation.
if ( $this->wp_customize->get_messenger_channel() ) {
add_action( 'amp_post_template_head', array( $this->wp_customize, 'customize_preview_loading_style' ) );
add_action( 'amp_post_template_css', array( $this, 'add_customize_preview_styles' ) );
add_action( 'amp_post_template_head', array( $this->wp_customize, 'remove_frameless_preview_messenger_channel' ) );
add_action( 'amp_post_template_footer', array( $this, 'add_preview_scripts' ) );
}
}
/**
* Sets up the AMP Customizer preview.
*/
public function register_ui() {
$this->wp_customize->add_panel(
self::PANEL_ID,
array(
'type' => 'amp',
'title' => __( 'AMP', 'amp' ),
/* translators: placeholder is URL to AMP project. */
'description' => sprintf( __( '<a href="%s" target="_blank">The AMP Project</a> is a Google-led initiative that dramatically improves loading speeds on phones and tablets. You can use the Customizer to preview changes to your AMP template before publishing them.', 'amp' ), 'https://ampproject.org' ),
)
);
/**
* Fires after the AMP panel has been registered for plugins to add additional controls.
*
* In practice the `customize_register` hook should be used instead.
*
* @since 0.4
* @param WP_Customize_Manager $manager Manager.
*/
do_action( 'amp_customizer_register_ui', $this->wp_customize );
}
/**
* Registers settings for customizing AMP templates.
*
* @since 0.4
*/
public function register_settings() {
/**
* Fires when plugins should register settings for AMP.
*
* In practice the `customize_register` hook should be used instead.
*
* @since 0.4
* @param WP_Customize_Manager $manager Manager.
*/
do_action( 'amp_customizer_register_settings', $this->wp_customize );
}
/**
* Load up AMP scripts needed for Customizer integrations.
*
* @since 0.6
*/
public function add_customizer_scripts() {
if ( ! amp_is_canonical() ) {
wp_enqueue_script(
'amp-customize-controls',
amp_get_asset_url( 'js/amp-customize-controls.js' ),
array( 'jquery', 'customize-controls' ),
AMP__VERSION,
true
);
wp_add_inline_script(
'amp-customize-controls',
sprintf(
'ampCustomizeControls.boot( %s );',
wp_json_encode(
array(
'queryVar' => amp_get_slug(),
'panelId' => self::PANEL_ID,
'ampUrl' => amp_admin_get_preview_permalink(),
'l10n' => array(
'unavailableMessage' => __( 'AMP is not available for the page currently being previewed.', 'amp' ),
'unavailableLinkText' => __( 'Navigate to an AMP compatible page', 'amp' ),
),
)
)
)
);
// phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion
wp_enqueue_style(
'amp-customizer',
amp_get_asset_url( 'css/amp-customizer.css' )
);
}
/**
* Fires when plugins should register settings for AMP.
*
* In practice the `customize_controls_enqueue_scripts` hook should be used instead.
*
* @since 0.4
* @param WP_Customize_Manager $manager Manager.
*/
do_action( 'amp_customizer_enqueue_scripts', $this->wp_customize );
}
/**
* Enqueues scripts used in both the AMP and non-AMP Customizer preview.
*
* @since 0.6
* @global WP_Query $wp_query
*/
public function enqueue_preview_scripts() {
global $wp_query;
// Bail if user can't customize anyway.
if ( ! current_user_can( 'customize' ) ) {
return;
}
wp_enqueue_script(
'amp-customize-preview',
amp_get_asset_url( 'js/amp-customize-preview.js' ),
array( 'jquery', 'customize-preview' ),
AMP__VERSION,
true
);
if ( current_theme_supports( AMP_Theme_Support::SLUG ) ) {
$availability = AMP_Theme_Support::get_template_availability();
$available = $availability['supported'];
} elseif ( is_singular() || $wp_query->is_posts_page ) {
/**
* Queried object.
*
* @var WP_Post $queried_object
*/
$queried_object = get_queried_object();
$available = post_supports_amp( $queried_object );
} else {
$available = false;
}
wp_add_inline_script(
'amp-customize-preview',
sprintf(
'ampCustomizePreview.boot( %s );',
wp_json_encode(
array(
'available' => $available,
'enabled' => is_amp_endpoint(),
)
)
)
);
}
/**
* Add AMP Customizer preview styles.
*/
public function add_customize_preview_styles() {
?>
/* Text meant only for screen readers; this is needed for wp.a11y.speak() */
.screen-reader-text {
border: 0;
clip: rect(1px, 1px, 1px, 1px);
-webkit-clip-path: inset(50%);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
word-wrap: normal !important;
}
body.wp-customizer-unloading {
opacity: 0.25 !important; /* Because AMP sets body to opacity:1 once layout complete. */
}
<?php
}
/**
* Enqueues scripts and does wp_print_footer_scripts() so we can output customizer scripts.
*
* This breaks AMP validation in the customizer but is necessary for the live preview.
*
* @since 0.6
*/
public function add_preview_scripts() {
// Bail if user can't customize anyway.
if ( ! current_user_can( 'customize' ) ) {
return;
}
wp_enqueue_script( 'customize-selective-refresh' );
wp_enqueue_script( 'amp-customize-preview' );
/**
* Fires when plugins should enqueue their own scripts for the AMP Customizer preview.
*
* @since 0.4
* @param WP_Customize_Manager $wp_customize Manager.
*/
do_action( 'amp_customizer_enqueue_preview_scripts', $this->wp_customize );
$this->wp_customize->customize_preview_settings();
$this->wp_customize->selective_refresh->export_preview_data();
wp_print_footer_scripts();
}
/**
* Print templates needed for AMP in Customizer.
*
* @since 0.6
*/
public function print_controls_templates() {
?>
<script type="text/html" id="tmpl-customize-amp-enabled-toggle">
<div class="amp-toggle">
<# var elementIdPrefix = _.uniqueId( 'customize-amp-enabled-toggle' ); #>
<div id="{{ elementIdPrefix }}tooltip" aria-hidden="true" class="tooltip" role="tooltip">
{{ data.message }}
<# if ( data.url ) { #>
<a href="{{ data.url }}">{{ data.linkText }}</a>
<# } #>
</div>
<input id="{{ elementIdPrefix }}checkbox" type="checkbox" class="disabled" aria-describedby="{{ elementIdPrefix }}tooltip">
<span class="slider"></span>
<label for="{{ elementIdPrefix }}checkbox" class="screen-reader-text"><?php esc_html_e( 'AMP preview enabled', 'amp' ); ?></label>
</div>
</script>
<script type="text/html" id="tmpl-customize-amp-unavailable-notification">
<li class="notice notice-{{ data.type || 'info' }} {{ data.alt ? 'notice-alt' : '' }} {{ data.containerClasses || '' }}" data-code="{{ data.code }}" data-type="{{ data.type }}">
<div class="notification-message">
{{ data.message }}
<# if ( data.url ) { #>
<a href="{{ data.url }}">{{ data.linkText }}</a>
<# } #>
</div>
</li>
</script>
<?php
}
/**
* Whether the Customizer is AMP. This is always true since the AMP Customizer has been merged with the main Customizer.
*
* @deprecated 0.6
* @return bool
*/
public static function is_amp_customizer() {
_deprecated_function( __METHOD__, '0.6' );
return true;
}
}

View File

@ -0,0 +1,210 @@
<?php
/**
* AMP Editor Blocks extending.
*
* @package AMP
* @since 1.0
*/
/**
* Class AMP_Editor_Blocks
*/
class AMP_Editor_Blocks {
/**
* List of AMP scripts that need to be printed when AMP components are used in non-AMP document context ("dirty AMP").
*
* @var array
*/
public $content_required_amp_scripts = array();
/**
* AMP components that have blocks.
*
* @var array
*/
public $amp_blocks = array(
'amp-mathml',
'amp-timeago',
'amp-o2-player',
'amp-ooyala-player',
'amp-reach-player',
'amp-springboard-player',
'amp-jwplayer',
'amp-brid-player',
'amp-ima-video',
'amp-fit-text',
);
/**
* Init.
*/
public function init() {
if ( function_exists( 'register_block_type' ) ) {
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 );
/*
* Dirty AMP is required when a site is in native mode but not all templates are being served
* as AMP. In particular, if a single post is using AMP-specific Gutenberg Blocks which make
* use of AMP components, and the singular template is served as AMP but the blog page is not,
* then the non-AMP blog page need to load the AMP runtime scripts so that the AMP components
* in the posts displayed there will be rendered properly. This is only relevant on native AMP
* sites because the AMP Gutenberg blocks are only made available in that mode; they are not
* presented in the Gutenberg inserter in transitional mode. In general, using AMP components in
* non-AMP documents is still not officially supported, so it's occurrence is being minimized
* as much as possible. For more, see <https://github.com/ampproject/amp-wp/issues/1192>.
*/
if ( amp_is_canonical() ) {
add_filter( 'the_content', array( $this, 'tally_content_requiring_amp_scripts' ) );
add_action( 'wp_print_footer_scripts', array( $this, 'print_dirty_amp_scripts' ) );
}
}
}
/**
* Whitelist elements and attributes used for AMP.
*
* This prevents AMP markup from being deleted in
*
* @param array $tags Array of allowed post tags.
* @param string $context Context.
* @return mixed Modified array.
*/
public function whitelist_block_atts_in_wp_kses_allowed_html( $tags, $context ) {
if ( 'post' !== $context ) {
return $tags;
}
foreach ( $tags as &$tag ) {
if ( ! is_array( $tag ) ) {
continue;
}
$tag['data-amp-layout'] = true;
$tag['data-amp-noloading'] = true;
$tag['data-amp-lightbox'] = true;
$tag['data-close-button-aria-label'] = true;
}
foreach ( $this->amp_blocks as $amp_block ) {
if ( ! isset( $tags[ $amp_block ] ) ) {
$tags[ $amp_block ] = array();
}
// @todo The global attributes included here should be matched up with what is actually used by each block.
$tags[ $amp_block ] = array_merge(
array_fill_keys(
array(
'layout',
'width',
'height',
'class',
),
true
),
$tags[ $amp_block ]
);
$amp_tag_specs = AMP_Allowed_Tags_Generated::get_allowed_tag( $amp_block );
foreach ( $amp_tag_specs as $amp_tag_spec ) {
if ( ! isset( $amp_tag_spec[ AMP_Rule_Spec::ATTR_SPEC_LIST ] ) ) {
continue;
}
$tags[ $amp_block ] = array_merge(
$tags[ $amp_block ],
array_fill_keys( array_keys( $amp_tag_spec[ AMP_Rule_Spec::ATTR_SPEC_LIST ] ), true )
);
}
}
return $tags;
}
/**
* Enqueue filters for extending core blocks attributes.
* Has to be loaded before registering the blocks in registerCoreBlocks.
*/
public function enqueue_block_editor_assets() {
// 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
);
// phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NotInFooter
wp_enqueue_script(
'amp-editor-blocks-build',
amp_get_asset_url( 'js/amp-blocks-compiled.js' ),
array( 'wp-editor', 'wp-blocks', 'lodash', 'wp-i18n', 'wp-element', 'wp-components' ),
AMP__VERSION
);
if ( function_exists( 'wp_set_script_translations' ) ) {
wp_set_script_translations( 'amp-editor-blocks-build', 'amp' );
}
}
wp_enqueue_script(
'amp-editor-blocks',
amp_get_asset_url( 'js/amp-editor-blocks.js' ),
array( 'underscore', 'wp-hooks', 'wp-i18n', 'wp-components' ),
AMP__VERSION,
true
);
wp_add_inline_script(
'amp-editor-blocks',
sprintf(
'ampEditorBlocks.boot( %s );',
wp_json_encode(
array(
'hasThemeSupport' => current_theme_supports( AMP_Theme_Support::SLUG ),
)
)
)
);
if ( function_exists( 'wp_set_script_translations' ) ) {
wp_set_script_translations( 'amp-editor-blocks', 'amp' );
} elseif ( function_exists( 'wp_get_jed_locale_data' ) || function_exists( 'gutenberg_get_jed_locale_data' ) ) {
$locale_data = function_exists( 'wp_get_jed_locale_data' ) ? wp_get_jed_locale_data( 'amp' ) : gutenberg_get_jed_locale_data( 'amp' );
wp_add_inline_script(
'wp-i18n',
'wp.i18n.setLocaleData( ' . wp_json_encode( $locale_data ) . ', "amp" );',
'after'
);
}
}
/**
* 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 );
}
}
}

View File

@ -0,0 +1,394 @@
<?php
/**
* AMP meta box settings.
*
* @package AMP
* @since 0.6
*/
/**
* Post meta box class.
*
* @since 0.6
*/
class AMP_Post_Meta_Box {
/**
* Assets handle.
*
* @since 0.6
* @var string
*/
const ASSETS_HANDLE = 'amp-post-meta-box';
/**
* Block asset handle.
*
* @since 1.0
* @var string
*/
const BLOCK_ASSET_HANDLE = 'amp-block-editor-toggle-compiled';
/**
* The enabled status post meta value.
*
* @since 0.6
* @var string
*/
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.
*
* @since 0.6
* @var string
*/
const STATUS_INPUT_NAME = 'amp_status';
/**
* The nonce name.
*
* @since 0.6
* @var string
*/
const NONCE_NAME = 'amp-status-nonce';
/**
* The nonce action.
*
* @since 0.6
* @var string
*/
const NONCE_ACTION = 'amp-update-status';
/**
* Initialize.
*
* @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( 'enqueue_block_editor_assets', array( $this, 'enqueue_block_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' ) );
}
/**
* Sanitize status.
*
* @param string $status Status.
* @return string Sanitized status. Empty string when invalid.
*/
public function sanitize_status( $status ) {
$status = strtolower( trim( $status ) );
if ( ! in_array( $status, array( self::ENABLED_STATUS, self::DISABLED_STATUS ), 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 $status;
}
/**
* Enqueue admin assets.
*
* @since 0.6
*/
public function enqueue_admin_assets() {
$post = get_post();
$screen = get_current_screen();
$validate = (
isset( $screen->base )
&&
'post' === $screen->base
&&
is_post_type_viewable( $post->post_type )
);
if ( ! $validate ) {
return;
}
wp_enqueue_style(
self::ASSETS_HANDLE,
amp_get_asset_url( 'css/amp-post-meta-box.css' ),
false,
AMP__VERSION
);
// phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NotInFooter
wp_enqueue_script(
self::ASSETS_HANDLE,
amp_get_asset_url( 'js/amp-post-meta-box.js' ),
array( 'jquery' ),
AMP__VERSION
);
if ( current_theme_supports( AMP_Theme_Support::SLUG ) ) {
$availability = AMP_Theme_Support::get_template_availability( $post );
$support_errors = $availability['errors'];
} else {
$support_errors = AMP_Post_Type_Support::get_support_errors( $post );
}
wp_add_inline_script(
self::ASSETS_HANDLE,
sprintf(
'ampPostMetaBox.boot( %s );',
wp_json_encode(
array(
'previewLink' => esc_url_raw( add_query_arg( amp_get_slug(), '', get_preview_post_link( $post ) ) ),
'canonical' => amp_is_canonical(),
'enabled' => empty( $support_errors ),
'canSupport' => 0 === count( array_diff( $support_errors, array( 'post-status-disabled' ) ) ),
'statusInputName' => self::STATUS_INPUT_NAME,
'l10n' => array(
'ampPreviewBtnLabel' => __( 'Preview changes in AMP (opens in new window)', 'amp' ),
),
)
)
)
);
}
/**
* Enqueues block assets.
*
* @since 1.0
*/
public function enqueue_block_assets() {
$post = get_post();
if ( ! is_post_type_viewable( $post->post_type ) ) {
return;
}
wp_enqueue_script(
self::BLOCK_ASSET_HANDLE,
amp_get_asset_url( 'js/' . self::BLOCK_ASSET_HANDLE . '.js' ),
array( 'wp-hooks', 'wp-i18n', 'wp-components' ),
AMP__VERSION,
true
);
$status_and_errors = $this->get_status_and_errors( $post );
$enabled_status = $status_and_errors['status'];
$error_messages = $this->get_error_messages( $status_and_errors['status'], $status_and_errors['errors'] );
$script_data = array(
'possibleStati' => array( self::ENABLED_STATUS, self::DISABLED_STATUS ),
'defaultStatus' => $enabled_status,
'errorMessages' => $error_messages,
);
if ( function_exists( 'wp_set_script_translations' ) ) {
wp_set_script_translations( self::BLOCK_ASSET_HANDLE, 'amp' );
} elseif ( function_exists( 'wp_get_jed_locale_data' ) ) {
$script_data['i18n'] = wp_get_jed_locale_data( 'amp' );
} elseif ( function_exists( 'gutenberg_get_jed_locale_data' ) ) {
$script_data['i18n'] = gutenberg_get_jed_locale_data( 'amp' );
}
wp_add_inline_script(
self::BLOCK_ASSET_HANDLE,
sprintf( 'var wpAmpEditor = %s;', wp_json_encode( $script_data ) ),
'before'
);
}
/**
* Render AMP status.
*
* @since 0.6
* @param WP_Post $post Post.
*/
public function render_status( $post ) {
$verify = (
isset( $post->ID )
&&
is_post_type_viewable( $post->post_type )
&&
current_user_can( 'edit_post', $post->ID )
);
if ( true !== $verify ) {
return;
}
$status_and_errors = $this->get_status_and_errors( $post );
$status = $status_and_errors['status'];
$errors = $status_and_errors['errors'];
$error_messages = $this->get_error_messages( $status, $errors );
$labels = array(
'enabled' => __( 'Enabled', 'amp' ),
'disabled' => __( 'Disabled', 'amp' ),
);
// The preceding variables are used inside the following amp-status.php template.
include AMP__DIR__ . '/templates/admin/amp-status.php';
}
/**
* Gets the AMP enabled status and errors.
*
* @since 1.0
* @param WP_Post $post The post to check.
* @return array {
* The status and errors.
*
* @type string $status The AMP enabled status.
* @type string[] $errors AMP errors.
* }
*/
public function get_status_and_errors( $post ) {
/*
* When theme support is present then theme templates can be served in AMP and we check first if the template is available.
* Checking for template availability will include a check for get_support_errors. Otherwise, if theme support is not present
* then we just check get_support_errors.
*/
if ( current_theme_supports( AMP_Theme_Support::SLUG ) ) {
$availability = AMP_Theme_Support::get_template_availability( $post );
$status = $availability['supported'] ? self::ENABLED_STATUS : self::DISABLED_STATUS;
$errors = array_diff( $availability['errors'], array( 'post-status-disabled' ) ); // Subtract the status which the metabox will allow to be toggled.
if ( true === $availability['immutable'] ) {
$errors[] = 'status_immutable';
}
} else {
$errors = AMP_Post_Type_Support::get_support_errors( $post );
$status = empty( $errors ) ? self::ENABLED_STATUS : self::DISABLED_STATUS;
$errors = array_diff( $errors, array( 'post-status-disabled' ) ); // Subtract the status which the metabox will allow to be toggled.
}
return compact( 'status', 'errors' );
}
/**
* Gets the AMP enabled error message(s).
*
* @since 1.0
* @param string $status The AMP enabled status.
* @param array $errors The AMP enabled errors.
* @return array $error_messages The error messages, as an array of strings.
*/
public function get_error_messages( $status, $errors ) {
$error_messages = array();
if ( in_array( 'status_immutable', $errors, true ) ) {
if ( self::ENABLED_STATUS === $status ) {
$error_messages[] = __( 'Your site does not allow AMP to be disabled.', 'amp' );
} else {
$error_messages[] = __( 'Your site does not allow AMP to be enabled.', 'amp' );
}
}
if ( in_array( 'template_unsupported', $errors, true ) || in_array( 'no_matching_template', $errors, true ) ) {
$error_messages[] = sprintf(
/* translators: %s is a link to the AMP settings screen */
__( 'There are no <a href="%s">supported templates</a> to display this in AMP.', 'amp' ),
esc_url( admin_url( 'admin.php?page=' . AMP_Options_Manager::OPTION_NAME ) )
);
}
if ( in_array( 'password-protected', $errors, true ) ) {
$error_messages[] = __( 'AMP cannot be enabled on password protected posts.', 'amp' );
}
if ( in_array( 'post-type-support', $errors, true ) ) {
$error_messages[] = sprintf(
/* translators: %s is a link to the AMP settings screen */
__( 'AMP cannot be enabled because this <a href="%s">post type does not support it</a>.', 'amp' ),
esc_url( admin_url( 'admin.php?page=' . AMP_Options_Manager::OPTION_NAME ) )
);
}
if ( in_array( 'skip-post', $errors, true ) ) {
$error_messages[] = __( 'A plugin or theme has disabled AMP support.', 'amp' );
}
if ( count( array_diff( $errors, array( 'status_immutable', 'page-on-front', 'page-for-posts', 'password-protected', 'post-type-support', 'skip-post', 'template_unsupported', 'no_matching_template' ) ) ) > 0 ) {
$error_messages[] = __( 'Unavailable for an unknown reason.', 'amp' );
}
return $error_messages;
}
/**
* Save AMP Status.
*
* @since 0.6
* @param int $post_id The Post ID.
*/
public function save_amp_status( $post_id ) {
$verify = (
isset( $_POST[ self::NONCE_NAME ] )
&&
isset( $_POST[ self::STATUS_INPUT_NAME ] )
&&
wp_verify_nonce( sanitize_key( wp_unslash( $_POST[ self::NONCE_NAME ] ) ), self::NONCE_ACTION )
&&
current_user_can( 'edit_post', $post_id )
&&
! wp_is_post_revision( $post_id )
&&
! wp_is_post_autosave( $post_id )
);
if ( true === $verify ) {
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.
);
}
}
/**
* Modify post preview link.
*
* Add the AMP query var is the amp-preview flag is set.
*
* @since 0.6
*
* @param string $link The post preview link.
* @return string Preview URL.
*/
public function preview_post_link( $link ) {
$is_amp = (
isset( $_POST['amp-preview'] ) // phpcs:ignore WordPress.Security.NonceVerification.Missing
&&
'do-preview' === sanitize_key( wp_unslash( $_POST['amp-preview'] ) ) // phpcs:ignore WordPress.Security.NonceVerification.Missing
);
if ( $is_amp ) {
$link = add_query_arg( amp_get_slug(), true, $link );
}
return $link;
}
}

View File

@ -0,0 +1,201 @@
<?php
/**
* Callbacks for adding AMP-related things to the admin.
*
* @package AMP
*/
/**
* Obsolete constant for flagging when Customizer is opened for AMP.
*
* @deprecated
* @var string
*/
define( 'AMP_CUSTOMIZER_QUERY_VAR', 'customize_amp' );
/**
* Sets up the AMP template editor for the Customizer.
*
* If this is in AMP canonical mode, exit.
* There's no need for the 'AMP' Customizer panel,
* And this does not need to toggle between the AMP and normal display.
*/
function amp_init_customizer() {
if ( amp_is_canonical() ) {
return;
}
// Fire up the AMP Customizer.
add_action( 'customize_register', array( 'AMP_Template_Customizer', 'init' ), 500 );
// Add some basic design settings + controls to the Customizer.
add_action( 'amp_init', array( 'AMP_Customizer_Design_Settings', 'init' ) );
// Add a link to the Customizer.
add_action( 'admin_menu', 'amp_add_customizer_link' );
}
/**
* Get permalink for the first AMP-eligible post.
*
* @return string|null URL on success, null if none found.
*/
function amp_admin_get_preview_permalink() {
/**
* Filter the post type to retrieve the latest for use in the AMP template customizer.
*
* @param string $post_type Post type slug. Default 'post'.
*/
$post_type = (string) apply_filters( 'amp_customizer_post_type', 'post' );
// Make sure the desired post type is actually supported, and if so, prefer it.
$supported_post_types = get_post_types_by_support( AMP_Post_Type_Support::SLUG );
if ( in_array( $post_type, $supported_post_types, true ) ) {
$supported_post_types = array_unique( array_merge( array( $post_type ), $supported_post_types ) );
}
// Bail if there are no supported post types.
if ( empty( $supported_post_types ) ) {
return null;
}
// If theme support is present, then bail if the singular template is not supported.
if ( current_theme_supports( AMP_Theme_Support::SLUG ) ) {
$supported_templates = AMP_Theme_Support::get_supportable_templates();
if ( empty( $supported_templates['is_singular']['supported'] ) ) {
return null;
}
}
$post_ids = get_posts(
array(
'no_found_rows' => true,
'suppress_filters' => false,
'post_status' => 'publish',
'post_password' => '',
'post_type' => $supported_post_types,
'posts_per_page' => 1,
'fields' => 'ids',
// @todo This should eventually do a meta_query to make sure there are none that have AMP_Post_Meta_Box::STATUS_POST_META_KEY = DISABLED_STATUS.
)
);
if ( empty( $post_ids ) ) {
return false;
}
$post_id = $post_ids[0];
return amp_get_permalink( $post_id );
}
/**
* Registers a submenu page to access the AMP template editor panel in the Customizer.
*/
function amp_add_customizer_link() {
/** This filter is documented in includes/settings/class-amp-customizer-design-settings.php */
if ( ! apply_filters( 'amp_customizer_is_enabled', true ) || current_theme_supports( AMP_Theme_Support::SLUG ) ) {
return;
}
$menu_slug = add_query_arg(
array(
'autofocus[panel]' => AMP_Template_Customizer::PANEL_ID,
'url' => rawurlencode( amp_admin_get_preview_permalink() ),
'return' => rawurlencode( admin_url() ),
),
'customize.php'
);
// Add the theme page.
add_theme_page(
__( 'AMP', 'amp' ),
__( 'AMP', 'amp' ),
'edit_theme_options',
$menu_slug
);
}
/**
* Registers AMP settings.
*/
function amp_add_options_menu() {
if ( ! is_admin() ) {
return;
}
/**
* Filter whether to enable the AMP settings.
*
* @since 0.5
* @param bool $enable Whether to enable the AMP settings. Default true.
*/
$short_circuit = apply_filters( 'amp_options_menu_is_enabled', true );
if ( true !== $short_circuit ) {
return;
}
$amp_options = new AMP_Options_Menu();
$amp_options->init();
}
/**
* Add custom analytics.
*
* This is currently only used for legacy AMP post templates.
*
* @since 0.5
* @see amp_get_analytics()
*
* @param array $analytics Analytics.
* @return array Analytics.
*/
function amp_add_custom_analytics( $analytics = array() ) {
$analytics = amp_get_analytics( $analytics );
/**
* Add amp-analytics tags.
*
* This filter allows you to easily insert any amp-analytics tags without needing much heavy lifting.
* This filter should be used to alter entries for legacy AMP templates.
*
* @since 0.4
*
* @param array $analytics An associative array of the analytics entries we want to output. Each array entry must have a unique key, and the value should be an array with the following keys: `type`, `attributes`, `script_data`. See readme for more details.
* @param WP_Post $post The current post.
*/
$analytics = apply_filters( 'amp_post_template_analytics', $analytics, get_queried_object() );
return $analytics;
}
/**
* Bootstrap AMP post meta box.
*
* This function must be invoked only once through the 'wp_loaded' action.
*
* @since 0.6
*/
function amp_post_meta_box() {
$post_meta_box = new AMP_Post_Meta_Box();
$post_meta_box->init();
}
/**
* Bootstrap AMP Editor core blocks.
*/
function amp_editor_core_blocks() {
$editor_blocks = new AMP_Editor_Blocks();
$editor_blocks->init();
}
/**
* Bootstrap the AMP admin pointer class.
*
* @since 1.0
*/
function amp_admin_pointer() {
$admin_pointer = new AMP_Admin_Pointer();
$admin_pointer->init();
}