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

Add capability to generate AMP-only content (AMP-as-Canonical) #668

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d409c07
Add capability to generate AMP-only content (AMP-as-Canonical)
amedina Mar 23, 2017
b306aa1
Add capability to generate AMP-only content (AMP-as-Canonical)
amedina Mar 23, 2017
cba87d8
Fix merge conflicts
amedina Mar 23, 2017
06513d4
First steps in postprocessing the AMP canonical html: add amp attr to…
amedina Mar 24, 2017
d355e39
Experimenting with getting the AMP Canonical mode working with the 20…
amedina Mar 25, 2017
26b7526
Refactor code to add modulatiry to posprocessing functinoality.
amedina Mar 26, 2017
5c57b70
Merge branch 'master' into amedina/amp-canonical
amedina Apr 19, 2017
74c58c0
Fix canonical link issue for index page
amedina Apr 25, 2017
9558d54
Merge branch 'master' into amedina/amp-canonical
amedina Apr 25, 2017
94deda7
Fix index page
amedina Apr 26, 2017
c03dc7c
Expand canonical generation to index page
amedina Apr 28, 2017
e386b6a
Reorg of code
amedina Apr 29, 2017
190edf3
Resolve conflict with master
amedina Apr 29, 2017
6d85380
Resolve conflict with master
amedina Apr 29, 2017
e07964f
Merge branch 'amedina/amp-canonical' of github.com:Automattic/amp-wp …
amedina Apr 29, 2017
94a5782
Add processing of canonical index page
amedina May 2, 2017
34db70f
Progress on AMPing of index page
amedina May 2, 2017
b0d7ac9
Do not remove sidebars from index page
amedina May 2, 2017
ee552be
Fixed include of AMPContent class
amedina May 2, 2017
30121f6
Rename postprocessing file/class; Define img-to-ampimg coverter
amedina May 5, 2017
f6799f0
Add carousel sanitzer; add amp link to REST API output
amedina May 16, 2017
5d70e94
Fix flush rewrite rules after changing settings
amedina May 26, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 40 additions & 105 deletions amp.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,16 @@
define( 'AMP__VERSION', '0.4.2' );

require_once( AMP__DIR__ . '/back-compat/back-compat.php' );
require_once( AMP__DIR__ . '/includes/amp-helper-functions.php' );
require_once(AMP__DIR__ . '/includes/utils/amp-helper-functions.php');
require_once( AMP__DIR__ . '/includes/admin/functions.php' );
require_once( AMP__DIR__ . '/includes/settings/class-amp-customizer-settings.php' );
require_once( AMP__DIR__ . '/includes/settings/class-amp-customizer-design-settings.php' );
require_once( AMP__DIR__ . '/includes/utils/class-amp-dom-utils.php');
require_once(AMP__DIR__ . '/includes/utils/class-amp-utils.php');
require_once(AMP__DIR__ . '/includes/utils/class-amp-render.php');
require_once(AMP__DIR__ . '/includes/actions/class-paired-mode-actions.php');
require_once(AMP__DIR__ . '/includes/actions/class-canonical-mode-actions.php');
require_once( AMP__DIR__ . '/option.php' );

register_activation_hook( __FILE__, 'amp_activate' );
function amp_activate() {
Expand All @@ -45,6 +51,7 @@ function amp_deactivate() {

add_action( 'init', 'amp_init' );
function amp_init() {

if ( false === apply_filters( 'amp_is_enabled', true ) ) {
return;
}
Expand All @@ -55,134 +62,62 @@ function amp_init() {

load_plugin_textdomain( 'amp', false, plugin_basename( AMP__DIR__ ) . '/languages' );

add_rewrite_endpoint( AMP_QUERY_VAR, EP_PERMALINK );
add_post_type_support( 'post', AMP_QUERY_VAR );
// If the amp_canonical option has not been setup, or the current
// theme does not provide AMP support, then follow the "paired" approach
if ( ! get_option('amp_canonical') || ! get_theme_support('amp')) {
add_rewrite_endpoint( AMP_QUERY_VAR, EP_PERMALINK );
add_post_type_support( 'post', AMP_QUERY_VAR );
}

add_filter( 'request', 'amp_force_query_var_value' );
add_action( 'wp', 'amp_maybe_add_actions' );
add_filter( 'request', 'AMPUtils::amp_force_query_var_value' );
add_action( 'wp', 'amp_add_actions');

// Redirect the old url of amp page to the updated url.
add_filter( 'old_slug_redirect_url', 'amp_redirect_old_slug_to_new_url' );
add_filter( 'old_slug_redirect_url', 'AMPUtils::amp_redirect_old_slug_to_new_url' );

if ( class_exists( 'Jetpack' ) && ! ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) {
require_once( AMP__DIR__ . '/jetpack-helper.php' );
}
}

// Make sure the `amp` query var has an explicit value.
// Avoids issues when filtering the deprecated `query_string` hook.
function amp_force_query_var_value( $query_vars ) {
if ( isset( $query_vars[ AMP_QUERY_VAR ] ) && '' === $query_vars[ AMP_QUERY_VAR ] ) {
$query_vars[ AMP_QUERY_VAR ] = 1;
}
return $query_vars;
}

function amp_maybe_add_actions() {
if ( ! is_singular() || is_feed() ) {
return;
}

$is_amp_endpoint = is_amp_endpoint();
function amp_add_actions() {

// 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 ) {
if ( $is_amp_endpoint ) {
wp_safe_redirect( get_permalink( $post->ID ) );
exit;
}
if ( is_feed()) {
return;
}

if ( $is_amp_endpoint ) {
amp_prepare_render();
if (get_option('amp_canonical') ) {
CanonicalModeActions::add_actions();
} else {
amp_add_frontend_actions();
PairedModeActions::add_actions();
}
}

function amp_load_classes() {
require_once( AMP__DIR__ . '/includes/class-amp-post-template.php' ); // this loads everything else
}

function amp_add_frontend_actions() {
require_once( AMP__DIR__ . '/includes/amp-frontend-actions.php' );
}

function amp_add_post_template_actions() {
require_once( AMP__DIR__ . '/includes/amp-post-template-actions.php' );
require_once( AMP__DIR__ . '/includes/amp-post-template-functions.php' );
}

function amp_prepare_render() {
add_action( 'template_redirect', 'amp_render' );
}

function amp_render() {
$post_id = get_queried_object_id();
amp_render_post( $post_id );
exit;
require_once(AMP__DIR__ . '/includes/actions/amp-frontend-actions.php');
}

function amp_render_post( $post_id ) {
$post = get_post( $post_id );
if ( ! $post ) {
return;
}

amp_load_classes();

do_action( 'pre_amp_render_post', $post_id );

amp_add_post_template_actions();
$template = new AMP_Post_Template( $post_id );
$template->load();
}
add_action( 'plugins_loaded', 'AMPUtils::_amp_bootstrap_customizer', 9 );

/**
* Bootstraps the AMP customizer.
*
* If the AMP customizer is enabled, initially drop the core widgets and menus panels. If the current
* preview page isn't flagged as an AMP template, the core panels will be re-added and the AMP panel
* hidden.
*
* @internal This callback must be hooked before priority 10 on 'plugins_loaded' to properly unhook
* the core panels.
*
* @since 0.4
* Inject link to AMP version of a post to the REST API posts endpoint
* @param $response
* @param $post
* @return mixed
*/
function _amp_bootstrap_customizer() {
/**
* Filter whether to enable the AMP template customizer functionality.
*
* @param bool $enable Whether to enable the AMP customizer. Default true.
*/
$amp_customizer_enabled = apply_filters( 'amp_customizer_is_enabled', true );

if ( true === $amp_customizer_enabled ) {
amp_init_customizer();
function amp_add_link_to_rest_response( $response, $post ) {
if ( ! post_supports_amp( $post ) ) {
return $response;
}
}
add_action( 'plugins_loaded', '_amp_bootstrap_customizer', 9 );

/**
* 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.
*
* @param string $link New URL of the post.
*
* @return string $link URL to be redirected.
*/
function amp_redirect_old_slug_to_new_url( $link ) {

if ( is_amp_endpoint() ) {
$link = trailingslashit( trailingslashit( $link ) . AMP_QUERY_VAR );
}
$response->add_link( 'amphtml', amp_get_permalink( $post->ID ) );

return $link;
return $response;
}
add_filter( 'rest_prepare_post', 'amp_add_link_to_rest_response', 10, 2 );

// TODO (@amedina): Check the removal of wpautop
// Stop WP adding extra <p> </p> to your pages' content
remove_filter( 'the_content', 'wpautop' );


130 changes: 130 additions & 0 deletions includes/actions/amp-canonical-index-actions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<?php

require_once(AMP__DIR__ . '/includes/content/amp-content-generator.php');
require_once(AMP__DIR__ . '/post-processing/class-amp-postprocessing.php');

class AMPCanonicalIndexActions
{
static $amp_posts;
static $current;
static $is_processing;

public static function init() {
self:$amp_posts = array();
add_action( 'the_post', array( __CLASS__, 'prepare_content' ));
add_action( 'the_content', array( __CLASS__, 'the_content_filter'), 99999 );
}

public static function the_content_filter($content ) {
// Avoid infinite loops when calling amp_canonical_retrieve_content
if (self::$is_processing ) {
return $content;
}
//return self::$current->get_amp_content();
$post = get_post();
return self::$amp_posts[ $post->ID ]->get_amp_content();
}

public static function prepare_content( $post ) {
if ( !isset( self::$amp_posts[ $post->ID ] ) ) {
self::$is_processing = true;
self::$amp_posts[ $post->ID ] = AMPContentGenerator::amp_canonical_retrieve_content( $post );
self::$is_processing = false;
}
self::$current = self::$amp_posts[ $post->ID ];
}

public static function deregister_scripts() {
wp_deregister_script( 'wp_embed');
}

public static function add_boilerplate_css() {
?>
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
<?php
}

public static function add_general_scripts() {
$amp_runtime_script = 'https://cdn.ampproject.org/v0.js';

// Always include AMP form & analytics, as almost every template includes
// a search form and is tracking page views
$scripts = array_merge(
array('amp-form' => 'https://cdn.ampproject.org/v0/amp-form-0.1.js'),
array('amp-analytics' => 'https://cdn.ampproject.org/v0/amp-analytics-0.1.js')
);

foreach ( $scripts as $element => $script) : ?>
<script custom-element="<?php echo esc_attr( $element ); ?>" src="<?php echo esc_url( $script ); ?>" async></script>
<?php endforeach; ?>
<script src="<?php echo esc_url( $amp_runtime_script ); ?>" async></script>
<?php
}

public static function add_scripts($dom) {

$scripts = array();
// Flatten the arrays of scripts
foreach ( self::$amp_posts as $amp_post) {
$amp_scripts = $amp_post->get_amp_scripts();
// Use an associative array for dedupping scripts
foreach ($amp_scripts as $element => $amp_script) {
$scripts[ $element ] = $amp_script;
}
}

$head = $dom->getElementsByTagName('head')->item(0);
foreach ( $scripts as $element => $script) {
$custom_script = $dom->createElement( 'script');
$custom_script->setAttribute('async', '');
$custom_script->setAttribute('custom-element', esc_attr( $element ));
$custom_script->setAttribute('src', esc_url( $script ));
$head->appendChild($custom_script);
}
}

public static function add_canonical($dom) {

$head = $dom->getElementsByTagName('head')->item(0);
$link = $dom->createElement( 'link');
$link->setAttribute('rel', 'canonical');
$link->setAttribute('href', esc_url( get_site_url() ) );
$head->appendChild($link);
}

public static function postprocess_index_html( $html ) {
$dom = new DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTML($html);
libxml_use_internal_errors(false);

self::add_scripts($dom);
self::add_canonical($dom);

// Add amp attribute to html tag
AMP_Postprocessing::add_amp_attr($dom);
// Eliminate 3p JS
AMP_Postprocessing::eliminate_3p_js($dom);
// Eliminate external stylesheets
AMP_Postprocessing::eliminate_ext_css($dom);
// Set meta viewport
AMP_Postprocessing::set_meta_viewport($dom);
// Eliminate non-amp-custom Stylesheets
AMP_Postprocessing::eliminate_non_amp_custom_styles($dom);
// Inline theme CSS
AMP_Postprocessing::inline_theme_css($dom);
// AMP Custom-header img
AMP_Postprocessing::amp_custom_header_img($dom);
// Remove styled SVGs
AMP_Postprocessing::remove_styled_svgs($dom);
// Save new HTML contents
$amp_html = $dom->saveHTML();

return $amp_html;
}
}

AMPCanonicalIndexActions::init();
add_action( 'wp_head', 'AMPCanonicalIndexActions::add_general_scripts' );
add_action( 'wp_head', 'AMPCanonicalIndexActions::add_boilerplate_css' );
add_action( 'wp_footer', 'AMPCanonicalIndexActions::deregister_scripts' );
Loading