Skip to content
This repository has been archived by the owner on Dec 9, 2023. It is now read-only.

Commit

Permalink
Migrate part of the app shell logic from ampproject#1519
Browse files Browse the repository at this point in the history
  • Loading branch information
delawski committed Aug 5, 2020
1 parent 77fca7d commit 27a5679
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 228 deletions.
121 changes: 17 additions & 104 deletions includes/amp-helper-functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,7 @@ function amp_init() {
*/
do_action( 'amp_init' );

global $amp_service_worker;
$amp_service_worker = new AMP_Service_Worker();
$amp_service_worker->init();

add_filter( 'allowed_redirect_hosts', [ 'AMP_HTTP', 'filter_allowed_redirect_hosts' ] );
add_filter( 'wp_redirect', [ 'AMP_HTTP', 'add_purged_query_vars' ] );
AMP_HTTP::purge_amp_query_vars();
AMP_HTTP::send_cors_headers();
AMP_HTTP::handle_xhr_request();
Expand Down Expand Up @@ -527,7 +522,6 @@ function _amp_bootstrap_customizer() {
* Redirects the old AMP URL to the new AMP URL.
*
* If post slug is updated the amp page with old post slug will be redirected to the updated url.
* Also includes all original query vars.
*
* @since 0.5
*
Expand Down Expand Up @@ -794,7 +788,7 @@ function is_amp_endpoint() {
(
isset( $support_args['app_shell'] )
&&
'inner' === AMP_Theme_Support::get_requested_app_shell_component()
'inner' === AMP_App_Shell::get_requested_app_shell_component()
)
);

Expand Down Expand Up @@ -922,6 +916,13 @@ function amp_register_default_scripts( $wp_scripts ) {
[],
null
);
$wp_scripts->add_data(
$handle,
'amp_script_attributes',
[
'async' => true,
]
);

// Shadow AMP API.
$handle = 'amp-shadow';
Expand All @@ -932,38 +933,6 @@ function amp_register_default_scripts( $wp_scripts ) {
null
);

// Add Web Components polyfill if Shadow DOM is not natively available.
$wp_scripts->add_inline_script(
$handle,
sprintf(
'if ( ! Element.prototype.attachShadow ) { const script = document.createElement( "script" ); script.src = %s; script.async = true; document.head.appendChild( script ); }',
wp_json_encode( 'https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.4.1/webcomponents-bundle.js' )
),
'after'
);

// App shell library.
$handle = 'amp-wp-app-shell';
$asset_file = AMP__DIR__ . '/assets/js/' . $handle . '.asset.php';
$asset = require $asset_file;
$dependencies = $asset['dependencies'];
$dependencies[] = 'amp-shadow';
$version = $asset['version'];
$wp_scripts->add(
$handle,
amp_get_asset_url( 'js/' . $handle . '.js' ),
$dependencies,
$version
);
$wp_scripts->add_data(
$handle,
'amp_script_attributes',
[
'async' => true,
]
);
$wp_scripts->add_data( $handle, 'precache', true );

// Register all AMP components as defined in the spec.
foreach ( AMP_Allowed_Tags_Generated::get_extension_specs() as $extension_name => $extension_spec ) {
$src = sprintf(
Expand Down Expand Up @@ -1066,17 +1035,18 @@ function amp_render_scripts( $scripts ) {
function amp_filter_script_loader_tag( $tag, $handle ) {
$prefix = 'https://cdn.ampproject.org/';
$src = wp_scripts()->registered[ $handle ]->src;
$attributes = wp_scripts()->get_data( $handle, 'amp_script_attributes' );
if ( empty( $attributes ) && 0 === strpos( $src, $prefix ) ) {
// All scripts from AMP CDN should be loaded async.
$attributes = [
'async' => true,
];
}
if ( empty( $attributes ) ) {
if ( 0 !== strpos( $src, $prefix ) ) {
return $tag;
}

/*
* All scripts from AMP CDN should be loaded async.
* See <https://www.ampproject.org/docs/integration/pwa-amp/amp-in-pwa#include-"shadow-amp"-in-your-progressive-web-app>.
*/
$attributes = [
'async' => true,
];

// Add custom-template and custom-element attributes. All component scripts look like https://cdn.ampproject.org/v0/:name-:version.js.
if ( 'v0' === strtok( substr( $src, strlen( $prefix ) ), '/' ) ) {
/*
Expand Down Expand Up @@ -1779,63 +1749,6 @@ function amp_wp_kses_mustache( $markup ) {
return wp_kses( $markup, array_fill_keys( $amp_mustache_allowed_html_tags, [] ) );
}

/**
* Mark the beginning of the content that will be displayed inside the app shell.
*
* Depends on adding app_shell to the amp theme support args.
*
* @since 1.1
* @todo Should this take an argument for the content placeholder?
*/
function amp_start_app_shell_content() {
$support_args = AMP_Theme_Support::get_theme_support_args();
if ( ! isset( $support_args['app_shell'] ) ) {
return;
}

printf( '<div id="%s">', esc_attr( AMP_Theme_Support::APP_SHELL_CONTENT_ELEMENT_ID ) );

// Start output buffering if requesting outer shell, since all content will be omitted from the response.
if ( 'outer' === AMP_Theme_Support::get_requested_app_shell_component() ) {
$content_placeholder = '<p>' . esc_html__( 'Loading&hellip;', 'amp' ) . '</p>';

/**
* Filters the content which is shown in the app shell for the content before it is loaded.
*
* This is used to display a loading message or a content skeleton.
*
* @since 1.1
* @todo Consider using template part for this instead, or an action with a default.
*
* @param string $content_placeholder Content placeholder.
*/
echo apply_filters( 'amp_app_shell_content_placeholder', $content_placeholder ); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped

ob_start();
}
}

/**
* Mark the end of the content that will be displayed inside the app shell.
*
* Depends on adding app_shell to the amp theme support args.
*
* @since 1.1
*/
function amp_end_app_shell_content() {
$support_args = AMP_Theme_Support::get_theme_support_args();
if ( ! isset( $support_args['app_shell'] ) ) {
return;
}

// Clean output buffer if requesting outer shell, since all content will be omitted from the response.
if ( 'outer' === AMP_Theme_Support::get_requested_app_shell_component() ) {
ob_end_clean();
}

printf( '</div><!-- #%s -->', esc_attr( AMP_Theme_Support::APP_SHELL_CONTENT_ELEMENT_ID ) );
}

/**
* Add "View AMP" admin bar item for Transitional/Reader mode.
*
Expand Down
16 changes: 0 additions & 16 deletions includes/class-amp-http.php
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,6 @@ public static function purge_amp_query_vars() {
self::ACTION_XHR_CONVERTED_QUERY_VAR,
'amp_latest_update_time',
'amp_last_check_time',
AMP_Theme_Support::APP_SHELL_COMPONENT_QUERY_VAR,
];

// Scrub input vars.
Expand Down Expand Up @@ -191,21 +190,6 @@ public static function purge_amp_query_vars() {
}
}

/**
* Add purged query vars to the supplied URL.
*
* @since 1.0
*
* @param string $url URL.
* @return string URL with purged query vars.
*/
public static function add_purged_query_vars( $url ) {
if ( ! empty( self::$purged_amp_query_vars ) ) {
$url = add_query_arg( self::$purged_amp_query_vars, $url );
}
return $url;
}

/**
* Filter the allowed redirect hosts to include AMP caches.
*
Expand Down
4 changes: 2 additions & 2 deletions includes/class-amp-service-worker.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public static function init() {
add_filter(
'wp_service_worker_navigation_route',
function ( $navigation_route ) {
$navigation_route['url'] = add_query_arg( AMP_Theme_Support::APP_SHELL_COMPONENT_QUERY_VAR, 'outer', home_url( '/' ) );
$navigation_route['url'] = add_query_arg( AMP_App_Shell::COMPONENT_QUERY_VAR, 'outer', home_url( '/' ) );
return $navigation_route;
}
);
Expand All @@ -58,7 +58,7 @@ function ( $navigation_route ) {
*/
$add_inner_app_shell_component = function( $precache_entry ) {
$precache_entry['url'] = add_query_arg(
AMP_Theme_Support::APP_SHELL_COMPONENT_QUERY_VAR,
AMP_App_Shell::COMPONENT_QUERY_VAR,
'inner',
$precache_entry['url']
);
Expand Down
109 changes: 3 additions & 106 deletions includes/class-amp-theme-support.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,6 @@ class AMP_Theme_Support {
*/
const SLUG = 'amp';

/**
* Query var for requesting the inner or outer app shell.
*
* @todo This can go into the AMP_Service_Worker class or rather an AMP_App_Shell class.
* @var string
*/
const APP_SHELL_COMPONENT_QUERY_VAR = 'amp_app_shell_component';

/**
* ID for element that contains the content for app shell.
*
* @var string
*/
const APP_SHELL_CONTENT_ELEMENT_ID = 'amp-app-shell-content';

/**
* Slug identifying standard website mode.
*
Expand Down Expand Up @@ -170,8 +155,6 @@ public static function init() {
// Ensure extra theme support for core themes is in place.
AMP_Core_Theme_Sanitizer::extend_theme_support();

add_action( 'parse_query', [ __CLASS__, 'init_app_shell' ], 9 );

/*
* Note that wp action is used instead of template_redirect because some themes/plugins output
* the response at this action and then short-circuit with exit. So this is why the preceding
Expand Down Expand Up @@ -389,70 +372,6 @@ static function() {
}
}

/**
* Init app shell.
*
* @since 1.1
*/
public static function init_app_shell() {
$theme_support = self::get_theme_support_args();
if ( ! isset( $theme_support['app_shell'] ) ) {
return;
}

$requested_app_shell_component = self::get_requested_app_shell_component();

// When inner app shell is requested, it is always an AMP request. Do not allow AMP when getting outer app shell for now (but this should be allowed in the future).
if ( 'outer' === $requested_app_shell_component ) {
add_action(
'template_redirect',
function() {
if ( ! is_amp_endpoint() ) {
return;
}
wp_die(
esc_html__( 'Outer app shell can only be requested of the non-AMP version (thus requires Transitional mode).', 'amp' ),
esc_html__( 'AMP Outer App Shell Problem', 'amp' ),
[ 'response' => 400 ]
);
}
);
}

// @todo This query param should be standardized and then this can be handled in the same place as WP_Service_Worker_Navigation_Routing_Component::filter_title_for_streaming_header().
if ( 'outer' === $requested_app_shell_component ) {
add_filter(
'pre_get_document_title',
function() {
return __( 'Loading...', 'amp' );
}
);
}

// Enqueue scripts for (outer) app shell, including precached app shell and normal site navigation prior to service worker installation.
if ( 'inner' !== $requested_app_shell_component ) {
add_action(
'wp_enqueue_scripts',
function() use ( $requested_app_shell_component ) {
if ( is_amp_endpoint() ) {
return;
}
wp_enqueue_script( 'amp-shadow' );
wp_enqueue_script( 'amp-wp-app-shell' );

$exports = [
'contentElementId' => AMP_Theme_Support::APP_SHELL_CONTENT_ELEMENT_ID,
'homeUrl' => home_url( '/' ),
'adminUrl' => admin_url( '/' ),
'componentQueryVar' => AMP_Theme_Support::APP_SHELL_COMPONENT_QUERY_VAR,
'isOuterAppShell' => 'outer' === $requested_app_shell_component,
];
wp_add_inline_script( 'amp-wp-app-shell', sprintf( 'var ampAppShell = %s;', wp_json_encode( $exports ) ), 'before' );
}
);
}
}

/**
* Ensure that the current AMP location is correct.
*
Expand Down Expand Up @@ -1941,28 +1860,6 @@ public static function filter_customize_partial_render( $partial ) {
return $partial;
}

/**
* Get the requested app shell component (either inner or outer).
*
* @return string|null App shell component.
*/
public static function get_requested_app_shell_component() {
if ( ! isset( AMP_HTTP::$purged_amp_query_vars[ self::APP_SHELL_COMPONENT_QUERY_VAR ] ) ) {
return null;
}

$theme_support_args = self::get_theme_support_args();
if ( ! isset( $theme_support_args['app_shell'] ) ) {
return null;
}

$component = AMP_HTTP::$purged_amp_query_vars[ self::APP_SHELL_COMPONENT_QUERY_VAR ];
if ( in_array( $component, [ 'inner', 'outer' ], true ) ) {
return $component;
}
return null;
}

/**
* Prepare inner app shell.
*
Expand Down Expand Up @@ -2124,7 +2021,7 @@ public static function prepare_response( $response, $args = [] ) {
}

// Get request for shadow DOM.
$app_shell_component = self::get_requested_app_shell_component();
$app_shell_component = AMP_App_Shell::get_requested_app_shell_component();

$args = array_merge(
[
Expand Down Expand Up @@ -2168,10 +2065,10 @@ public static function prepare_response( $response, $args = [] ) {
// Remove the children of the content if requesting the outer app shell.
$content_element = null;
if ( $app_shell_component ) {
$content_element = $dom->getElementById( self::APP_SHELL_CONTENT_ELEMENT_ID );
$content_element = $dom->getElementById( AMP_App_Shell::CONTENT_ELEMENT_ID );
if ( ! $content_element ) {
status_header( 500 );
return esc_html__( 'Unable to locate APP_SHELL_CONTENT_ELEMENT_ID.', 'amp' );
return esc_html__( 'Unable to locate AMP_App_Shell::CONTENT_ELEMENT_ID.', 'amp' );
}
if ( 'inner' === $app_shell_component ) {
self::prepare_inner_app_shell_document( $content_element );
Expand Down

0 comments on commit 27a5679

Please sign in to comment.