Version Description
(Aug 18, 2016) =
- Handle many more validation errors (props bcampeau and alleyinteractive).
- New filter:
amp_post_template_dir
(props mustafauysal). - New template: Nav bar is now it's own template part (props jdevalk).
- Better ratio for YouTube embeds.
- Fix: better timezone handling (props rinatkhaziev).
- Fix: better handling of non-int dimensions (like
100%
). - Fix: better handling of empty dimensions.
- Fix:
autoplay
is a bool-like value. - Fix: breakage when using the
query_string
hook (h/t mkuplens). - Fix: don't break really large Twitter IDs.
- Fix: don't break Instagram shortcodes when using URLs with querystrings.
- Readme improvements (props nickjohnford, sotayamashita)
Download this release
Release Info
Developer | batmoo |
Plugin | AMP for WordPress |
Version | 0.3.3 |
Comparing to | |
See all releases |
Code changes from version 0.3.2 to 0.3.3
- amp.php +13 -3
- includes/class-amp-post-template.php +2 -1
- includes/embeds/class-amp-instagram-embed.php +4 -7
- includes/embeds/class-amp-twitter-embed.php +10 -6
- includes/embeds/class-amp-youtube-embed.php +14 -0
- includes/sanitizers/class-amp-audio-sanitizer.php +25 -6
- includes/sanitizers/class-amp-base-sanitizer.php +63 -0
- includes/sanitizers/class-amp-blacklist-sanitizer.php +103 -21
- includes/sanitizers/class-amp-iframe-sanitizer.php +14 -17
- includes/sanitizers/class-amp-img-sanitizer.php +6 -2
- includes/sanitizers/class-amp-video-sanitizer.php +29 -11
- includes/utils/class-amp-string-utils.php +9 -0
- readme.md +3 -3
- readme.txt +25 -4
- templates/header-bar.php +11 -0
- templates/meta-time.php +1 -1
- templates/single.php +1 -11
amp.php
CHANGED
@@ -5,7 +5,7 @@
|
|
5 |
* Plugin URI: https://github.com/automattic/amp-wp
|
6 |
* Author: Automattic
|
7 |
* Author URI: https://automattic.com
|
8 |
-
* Version: 0.3.
|
9 |
* Text Domain: amp
|
10 |
* Domain Path: /languages/
|
11 |
* License: GPLv2 or later
|
@@ -17,13 +17,13 @@ define( 'AMP__DIR__', dirname( __FILE__ ) );
|
|
17 |
require_once( AMP__DIR__ . '/includes/amp-helper-functions.php' );
|
18 |
|
19 |
register_activation_hook( __FILE__, 'amp_activate' );
|
20 |
-
function amp_activate(){
|
21 |
amp_init();
|
22 |
flush_rewrite_rules();
|
23 |
}
|
24 |
|
25 |
register_deactivation_hook( __FILE__, 'amp_deactivate' );
|
26 |
-
function amp_deactivate(){
|
27 |
flush_rewrite_rules();
|
28 |
}
|
29 |
|
@@ -42,6 +42,7 @@ function amp_init() {
|
|
42 |
add_rewrite_endpoint( AMP_QUERY_VAR, EP_PERMALINK );
|
43 |
add_post_type_support( 'post', AMP_QUERY_VAR );
|
44 |
|
|
|
45 |
add_action( 'wp', 'amp_maybe_add_actions' );
|
46 |
|
47 |
if ( class_exists( 'Jetpack' ) && ! ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) {
|
@@ -49,6 +50,15 @@ function amp_init() {
|
|
49 |
}
|
50 |
}
|
51 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
function amp_maybe_add_actions() {
|
53 |
if ( ! is_singular() || is_feed() ) {
|
54 |
return;
|
5 |
* Plugin URI: https://github.com/automattic/amp-wp
|
6 |
* Author: Automattic
|
7 |
* Author URI: https://automattic.com
|
8 |
+
* Version: 0.3.3
|
9 |
* Text Domain: amp
|
10 |
* Domain Path: /languages/
|
11 |
* License: GPLv2 or later
|
17 |
require_once( AMP__DIR__ . '/includes/amp-helper-functions.php' );
|
18 |
|
19 |
register_activation_hook( __FILE__, 'amp_activate' );
|
20 |
+
function amp_activate() {
|
21 |
amp_init();
|
22 |
flush_rewrite_rules();
|
23 |
}
|
24 |
|
25 |
register_deactivation_hook( __FILE__, 'amp_deactivate' );
|
26 |
+
function amp_deactivate() {
|
27 |
flush_rewrite_rules();
|
28 |
}
|
29 |
|
42 |
add_rewrite_endpoint( AMP_QUERY_VAR, EP_PERMALINK );
|
43 |
add_post_type_support( 'post', AMP_QUERY_VAR );
|
44 |
|
45 |
+
add_filter( 'request', 'amp_force_query_var_value' );
|
46 |
add_action( 'wp', 'amp_maybe_add_actions' );
|
47 |
|
48 |
if ( class_exists( 'Jetpack' ) && ! ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) {
|
50 |
}
|
51 |
}
|
52 |
|
53 |
+
// Make sure the `amp` query var has an explicit value.
|
54 |
+
// Avoids issues when filtering the deprecated `query_string` hook.
|
55 |
+
function amp_force_query_var_value( $query_vars ) {
|
56 |
+
if ( isset( $query_vars[ AMP_QUERY_VAR ] ) && '' === $query_vars[ AMP_QUERY_VAR ] ) {
|
57 |
+
$query_vars[ AMP_QUERY_VAR ] = 1;
|
58 |
+
}
|
59 |
+
return $query_vars;
|
60 |
+
}
|
61 |
+
|
62 |
function amp_maybe_add_actions() {
|
63 |
if ( ! is_singular() || is_feed() ) {
|
64 |
return;
|
includes/class-amp-post-template.php
CHANGED
@@ -2,6 +2,7 @@
|
|
2 |
|
3 |
require_once( AMP__DIR__ . '/includes/utils/class-amp-dom-utils.php' );
|
4 |
require_once( AMP__DIR__ . '/includes/utils/class-amp-html-utils.php' );
|
|
|
5 |
|
6 |
require_once( AMP__DIR__ . '/includes/class-amp-content.php' );
|
7 |
|
@@ -26,7 +27,7 @@ class AMP_Post_Template {
|
|
26 |
private $data;
|
27 |
|
28 |
public function __construct( $post_id ) {
|
29 |
-
$this->template_dir = AMP__DIR__ . '/templates';
|
30 |
|
31 |
$this->ID = $post_id;
|
32 |
$this->post = get_post( $post_id );
|
2 |
|
3 |
require_once( AMP__DIR__ . '/includes/utils/class-amp-dom-utils.php' );
|
4 |
require_once( AMP__DIR__ . '/includes/utils/class-amp-html-utils.php' );
|
5 |
+
require_once( AMP__DIR__ . '/includes/utils/class-amp-string-utils.php' );
|
6 |
|
7 |
require_once( AMP__DIR__ . '/includes/class-amp-content.php' );
|
8 |
|
27 |
private $data;
|
28 |
|
29 |
public function __construct( $post_id ) {
|
30 |
+
$this->template_dir = apply_filters( 'amp_post_template_dir', AMP__DIR__ . '/templates' );
|
31 |
|
32 |
$this->ID = $post_id;
|
33 |
$this->post = get_post( $post_id );
|
includes/embeds/class-amp-instagram-embed.php
CHANGED
@@ -79,15 +79,12 @@ class AMP_Instagram_Embed_Handler extends AMP_Base_Embed_Handler {
|
|
79 |
}
|
80 |
|
81 |
private function get_instagram_id_from_url( $url ) {
|
82 |
-
$
|
83 |
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
if( ! empty( $instagram_id ) ) {
|
88 |
-
return $instagram_id;
|
89 |
}
|
90 |
|
91 |
-
return
|
92 |
}
|
93 |
}
|
79 |
}
|
80 |
|
81 |
private function get_instagram_id_from_url( $url ) {
|
82 |
+
$found = preg_match( self::URL_PATTERN, $url, $matches );
|
83 |
|
84 |
+
if ( ! $found ) {
|
85 |
+
return false;
|
|
|
|
|
|
|
86 |
}
|
87 |
|
88 |
+
return end( $matches );
|
89 |
}
|
90 |
}
|
includes/embeds/class-amp-twitter-embed.php
CHANGED
@@ -32,13 +32,17 @@ class AMP_Twitter_Embed_Handler extends AMP_Base_Embed_Handler {
|
|
32 |
'tweet' => false,
|
33 |
) );
|
34 |
|
|
|
|
|
|
|
|
|
35 |
$id = false;
|
36 |
-
if (
|
37 |
-
$id =
|
38 |
} else {
|
39 |
preg_match( self::URL_PATTERN, $attr['tweet'], $matches );
|
40 |
-
if ( isset( $matches[5] ) &&
|
41 |
-
$id =
|
42 |
}
|
43 |
|
44 |
if ( empty( $id ) ) {
|
@@ -62,8 +66,8 @@ class AMP_Twitter_Embed_Handler extends AMP_Base_Embed_Handler {
|
|
62 |
function oembed( $matches, $attr, $url, $rawattr ) {
|
63 |
$id = false;
|
64 |
|
65 |
-
if ( isset( $matches[5] ) &&
|
66 |
-
$id =
|
67 |
}
|
68 |
|
69 |
if ( ! $id ) {
|
32 |
'tweet' => false,
|
33 |
) );
|
34 |
|
35 |
+
if ( empty( $attr['tweet'] ) && ! empty( $attr[0] ) ) {
|
36 |
+
$attr['tweet'] = $attr[0];
|
37 |
+
}
|
38 |
+
|
39 |
$id = false;
|
40 |
+
if ( is_numeric( $attr['tweet'] ) ) {
|
41 |
+
$id = $attr['tweet'];
|
42 |
} else {
|
43 |
preg_match( self::URL_PATTERN, $attr['tweet'], $matches );
|
44 |
+
if ( isset( $matches[5] ) && is_numeric( $matches[5] ) ) {
|
45 |
+
$id = $matches[5];
|
46 |
}
|
47 |
|
48 |
if ( empty( $id ) ) {
|
66 |
function oembed( $matches, $attr, $url, $rawattr ) {
|
67 |
$id = false;
|
68 |
|
69 |
+
if ( isset( $matches[5] ) && is_numeric( $matches[5] ) ) {
|
70 |
+
$id = $matches[5];
|
71 |
}
|
72 |
|
73 |
if ( ! $id ) {
|
includes/embeds/class-amp-youtube-embed.php
CHANGED
@@ -6,10 +6,24 @@ require_once( AMP__DIR__ . '/includes/embeds/class-amp-base-embed-handler.php' )
|
|
6 |
class AMP_YouTube_Embed_Handler extends AMP_Base_Embed_Handler {
|
7 |
const SHORT_URL_HOST = 'youtu.be';
|
8 |
const URL_PATTERN = '#https?://(?:www\.)?(?:youtube.com/(?:v/|e/|embed/|playlist|watch[/\#?])|youtu\.be/).*#i';
|
|
|
|
|
|
|
|
|
9 |
|
10 |
private static $script_slug = 'amp-youtube';
|
11 |
private static $script_src = 'https://cdn.ampproject.org/v0/amp-youtube-0.1.js';
|
12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
function register_embed() {
|
14 |
wp_embed_register_handler( 'amp-youtube', self::URL_PATTERN, array( $this, 'oembed' ), -1 );
|
15 |
add_shortcode( 'youtube', array( $this, 'shortcode' ) );
|
6 |
class AMP_YouTube_Embed_Handler extends AMP_Base_Embed_Handler {
|
7 |
const SHORT_URL_HOST = 'youtu.be';
|
8 |
const URL_PATTERN = '#https?://(?:www\.)?(?:youtube.com/(?:v/|e/|embed/|playlist|watch[/\#?])|youtu\.be/).*#i';
|
9 |
+
const RATIO = 0.5625;
|
10 |
+
|
11 |
+
protected $DEFAULT_WIDTH = 600;
|
12 |
+
protected $DEFAULT_HEIGHT = 338;
|
13 |
|
14 |
private static $script_slug = 'amp-youtube';
|
15 |
private static $script_src = 'https://cdn.ampproject.org/v0/amp-youtube-0.1.js';
|
16 |
|
17 |
+
function __construct( $args = array() ) {
|
18 |
+
parent::__construct( $args );
|
19 |
+
|
20 |
+
if ( isset( $this->args['content_max_width'] ) ) {
|
21 |
+
$max_width = $this->args['content_max_width'];
|
22 |
+
$this->args['width'] = $max_width;
|
23 |
+
$this->args['height'] = round( $max_width * self::RATIO );
|
24 |
+
}
|
25 |
+
}
|
26 |
+
|
27 |
function register_embed() {
|
28 |
wp_embed_register_handler( 'amp-youtube', self::URL_PATTERN, array( $this, 'oembed' ), -1 );
|
29 |
add_shortcode( 'youtube', array( $this, 'shortcode' ) );
|
includes/sanitizers/class-amp-audio-sanitizer.php
CHANGED
@@ -31,14 +31,28 @@ class AMP_Audio_Sanitizer extends AMP_Base_Sanitizer {
|
|
31 |
|
32 |
$new_node = AMP_DOM_Utils::create_node( $this->dom, 'amp-audio', $new_attributes );
|
33 |
|
34 |
-
// TODO: limit child nodes too (only allowed: `source`; move rest to div+fallback)
|
35 |
// TODO: `source` does not have closing tag, and DOMDocument doesn't handle it well.
|
36 |
foreach ( $node->childNodes as $child_node ) {
|
37 |
$new_child_node = $child_node->cloneNode( true );
|
38 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
}
|
40 |
|
41 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
|
43 |
$this->did_convert_elements = true;
|
44 |
}
|
@@ -50,20 +64,25 @@ class AMP_Audio_Sanitizer extends AMP_Base_Sanitizer {
|
|
50 |
foreach ( $attributes as $name => $value ) {
|
51 |
switch ( $name ) {
|
52 |
case 'src':
|
|
|
|
|
|
|
53 |
case 'width':
|
54 |
case 'height':
|
|
|
|
|
|
|
55 |
case 'class':
|
56 |
$out[ $name ] = $value;
|
57 |
break;
|
58 |
case 'loop':
|
59 |
case 'muted':
|
|
|
60 |
if ( 'false' !== $value ) {
|
61 |
$out[ $name ] = '';
|
62 |
}
|
63 |
break;
|
64 |
-
|
65 |
-
$out[ $name ] = 'desktop tablet mobile';
|
66 |
-
break;
|
67 |
default;
|
68 |
break;
|
69 |
}
|
31 |
|
32 |
$new_node = AMP_DOM_Utils::create_node( $this->dom, 'amp-audio', $new_attributes );
|
33 |
|
|
|
34 |
// TODO: `source` does not have closing tag, and DOMDocument doesn't handle it well.
|
35 |
foreach ( $node->childNodes as $child_node ) {
|
36 |
$new_child_node = $child_node->cloneNode( true );
|
37 |
+
$old_child_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $new_child_node );
|
38 |
+
$new_child_attributes = $this->filter_attributes( $old_child_attributes );
|
39 |
+
|
40 |
+
// Only append source tags with a valid src attribute
|
41 |
+
if ( ! empty( $new_child_attributes['src'] ) && 'source' === $new_child_node->tagName ) {
|
42 |
+
$new_node->appendChild( $new_child_node );
|
43 |
+
}
|
44 |
}
|
45 |
|
46 |
+
// If the node has at least one valid source, replace the old node with it.
|
47 |
+
// Otherwise, just remove the node.
|
48 |
+
//
|
49 |
+
// TODO: Add a fallback handler.
|
50 |
+
// See: https://github.com/ampproject/amphtml/issues/2261
|
51 |
+
if ( 0 === $new_node->childNodes->length && empty( $new_attributes['src'] ) ) {
|
52 |
+
$node->parentNode->removeChild( $node );
|
53 |
+
} else {
|
54 |
+
$node->parentNode->replaceChild( $new_node, $node );
|
55 |
+
}
|
56 |
|
57 |
$this->did_convert_elements = true;
|
58 |
}
|
64 |
foreach ( $attributes as $name => $value ) {
|
65 |
switch ( $name ) {
|
66 |
case 'src':
|
67 |
+
$out[ $name ] = $this->maybe_enforce_https_src( $value );
|
68 |
+
break;
|
69 |
+
|
70 |
case 'width':
|
71 |
case 'height':
|
72 |
+
$out[ $name ] = $this->sanitize_dimension( $value, $name );
|
73 |
+
break;
|
74 |
+
|
75 |
case 'class':
|
76 |
$out[ $name ] = $value;
|
77 |
break;
|
78 |
case 'loop':
|
79 |
case 'muted':
|
80 |
+
case 'autoplay':
|
81 |
if ( 'false' !== $value ) {
|
82 |
$out[ $name ] = '';
|
83 |
}
|
84 |
break;
|
85 |
+
|
|
|
|
|
86 |
default;
|
87 |
break;
|
88 |
}
|
includes/sanitizers/class-amp-base-sanitizer.php
CHANGED
@@ -1,6 +1,8 @@
|
|
1 |
<?php
|
2 |
|
3 |
abstract class AMP_Base_Sanitizer {
|
|
|
|
|
4 |
protected $DEFAULT_ARGS = array();
|
5 |
|
6 |
protected $dom;
|
@@ -22,6 +24,42 @@ abstract class AMP_Base_Sanitizer {
|
|
22 |
return $this->dom->getElementsByTagName( 'body' )->item( 0 );
|
23 |
}
|
24 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
/**
|
26 |
* This is our workaround to enforce max sizing with layout=responsive.
|
27 |
*
|
@@ -54,4 +92,29 @@ abstract class AMP_Base_Sanitizer {
|
|
54 |
$attributes[ $key ] = $value;
|
55 |
}
|
56 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
}
|
1 |
<?php
|
2 |
|
3 |
abstract class AMP_Base_Sanitizer {
|
4 |
+
const FALLBACK_HEIGHT = 400;
|
5 |
+
|
6 |
protected $DEFAULT_ARGS = array();
|
7 |
|
8 |
protected $dom;
|
24 |
return $this->dom->getElementsByTagName( 'body' )->item( 0 );
|
25 |
}
|
26 |
|
27 |
+
public function sanitize_dimension( $value, $dimension ) {
|
28 |
+
if ( empty( $value ) ) {
|
29 |
+
return $value;
|
30 |
+
}
|
31 |
+
|
32 |
+
if ( false !== filter_var( $value, FILTER_VALIDATE_INT ) ) {
|
33 |
+
return absint( $value );
|
34 |
+
}
|
35 |
+
|
36 |
+
if ( AMP_String_Utils::endswith( $value, 'px' ) ) {
|
37 |
+
return absint( $value );
|
38 |
+
}
|
39 |
+
|
40 |
+
if ( AMP_String_Utils::endswith( $value, '%' ) ) {
|
41 |
+
if ( 'width' === $dimension && isset( $this->args[ 'content_max_width'] ) ) {
|
42 |
+
$percentage = absint( $value ) / 100;
|
43 |
+
return round( $percentage * $this->args[ 'content_max_width'] );
|
44 |
+
}
|
45 |
+
}
|
46 |
+
|
47 |
+
return '';
|
48 |
+
}
|
49 |
+
|
50 |
+
public function enforce_fixed_height( $attributes ) {
|
51 |
+
if ( empty( $attributes['height'] ) ) {
|
52 |
+
unset( $attributes['width'] );
|
53 |
+
$attributes['height'] = self::FALLBACK_HEIGHT;
|
54 |
+
}
|
55 |
+
|
56 |
+
if ( empty( $attributes['width'] ) ) {
|
57 |
+
$attributes['layout'] = 'fixed-height';
|
58 |
+
}
|
59 |
+
|
60 |
+
return $attributes;
|
61 |
+
}
|
62 |
+
|
63 |
/**
|
64 |
* This is our workaround to enforce max sizing with layout=responsive.
|
65 |
*
|
92 |
$attributes[ $key ] = $value;
|
93 |
}
|
94 |
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Decide if we should remove a src attribute if https is required.
|
98 |
+
* If not required, the implementing class may want to try and force https instead.
|
99 |
+
*
|
100 |
+
* @param string $src
|
101 |
+
* @param boolean $force_https
|
102 |
+
* @return string
|
103 |
+
*/
|
104 |
+
public function maybe_enforce_https_src( $src, $force_https = false ) {
|
105 |
+
$protocol = strtok( $src, ':' );
|
106 |
+
if ( 'https' !== $protocol ) {
|
107 |
+
// Check if https is required
|
108 |
+
if ( isset( $this->args['require_https_src'] ) && true === $this->args['require_https_src'] ) {
|
109 |
+
// Remove the src. Let the implementing class decide what do from here.
|
110 |
+
$src = '';
|
111 |
+
} elseif ( ( ! isset( $this->args['require_https_src'] ) || false === $this->args['require_https_src'] )
|
112 |
+
&& true === $force_https ) {
|
113 |
+
// Don't remove the src, but force https instead
|
114 |
+
$src = set_url_scheme( $src, 'https' );
|
115 |
+
}
|
116 |
+
}
|
117 |
+
|
118 |
+
return $src;
|
119 |
+
}
|
120 |
}
|
includes/sanitizers/class-amp-blacklist-sanitizer.php
CHANGED
@@ -11,6 +11,12 @@ require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-base-sanitizer.php' )
|
|
11 |
class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
|
12 |
const PATTERN_REL_WP_ATTACHMENT = '#wp-att-([\d]+)#';
|
13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
public function sanitize() {
|
15 |
$blacklisted_tags = $this->get_blacklisted_tags();
|
16 |
$blacklisted_attributes = $this->get_blacklisted_attributes();
|
@@ -26,8 +32,17 @@ class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
|
|
26 |
return;
|
27 |
}
|
28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
if ( $node->hasAttributes() ) {
|
30 |
-
$node_name = $node->nodeName;
|
31 |
$length = $node->attributes->length;
|
32 |
for ( $i = $length - 1; $i >= 0; $i-- ) {
|
33 |
$attribute = $node->attributes->item( $i );
|
@@ -41,19 +56,16 @@ class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
|
|
41 |
if ( 0 === stripos( $attribute_name, 'on' ) && $attribute_name != 'on' ) {
|
42 |
$node->removeAttribute( $attribute_name );
|
43 |
continue;
|
44 |
-
} elseif ( 'href' === $attribute_name ) {
|
45 |
-
$protocol = strtok( $attribute->value, ':' );
|
46 |
-
if ( in_array( $protocol, $bad_protocols ) ) {
|
47 |
-
$node->removeAttribute( $attribute_name );
|
48 |
-
continue;
|
49 |
-
}
|
50 |
} elseif ( 'a' === $node_name ) {
|
51 |
$this->sanitize_a_attribute( $node, $attribute );
|
52 |
}
|
53 |
}
|
54 |
}
|
55 |
|
56 |
-
|
|
|
|
|
|
|
57 |
$this->strip_attributes_recursive( $child_node, $bad_attributes, $bad_protocols );
|
58 |
}
|
59 |
}
|
@@ -93,24 +105,88 @@ class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
|
|
93 |
// rev removed from HTML5 spec, which was used by Jetpack Markdown.
|
94 |
$node->removeAttribute( $attribute_name );
|
95 |
} elseif ( 'target' === $attribute_name ) {
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
|
|
|
|
|
|
103 |
}
|
104 |
}
|
105 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
private function get_blacklisted_protocols() {
|
107 |
-
return array(
|
108 |
'javascript',
|
109 |
-
);
|
110 |
}
|
111 |
|
112 |
private function get_blacklisted_tags() {
|
113 |
-
return array(
|
114 |
'script',
|
115 |
'noscript',
|
116 |
'style',
|
@@ -126,18 +202,24 @@ class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
|
|
126 |
'select',
|
127 |
'option',
|
128 |
'link',
|
|
|
|
|
|
|
|
|
|
|
129 |
|
130 |
// These are converted into amp-* versions
|
131 |
//'img',
|
132 |
//'video',
|
133 |
//'audio',
|
134 |
//'iframe',
|
135 |
-
);
|
136 |
}
|
137 |
|
138 |
private function get_blacklisted_attributes() {
|
139 |
-
return array(
|
140 |
'style',
|
141 |
-
|
|
|
142 |
}
|
143 |
}
|
11 |
class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
|
12 |
const PATTERN_REL_WP_ATTACHMENT = '#wp-att-([\d]+)#';
|
13 |
|
14 |
+
protected $DEFAULT_ARGS = array(
|
15 |
+
'add_blacklisted_protocols' => array(),
|
16 |
+
'add_blacklisted_tags' => array(),
|
17 |
+
'add_blacklisted_attributes' => array(),
|
18 |
+
);
|
19 |
+
|
20 |
public function sanitize() {
|
21 |
$blacklisted_tags = $this->get_blacklisted_tags();
|
22 |
$blacklisted_attributes = $this->get_blacklisted_attributes();
|
32 |
return;
|
33 |
}
|
34 |
|
35 |
+
$node_name = $node->nodeName;
|
36 |
+
|
37 |
+
// Some nodes may contain valid content but are themselves invalid.
|
38 |
+
// Remove the node but preserve the children.
|
39 |
+
if ( 'font' === $node_name ) {
|
40 |
+
$this->replace_node_with_children( $node );
|
41 |
+
} elseif ( 'a' === $node_name && false === $this->validate_a_node( $node ) ) {
|
42 |
+
$this->replace_node_with_children( $node );
|
43 |
+
}
|
44 |
+
|
45 |
if ( $node->hasAttributes() ) {
|
|
|
46 |
$length = $node->attributes->length;
|
47 |
for ( $i = $length - 1; $i >= 0; $i-- ) {
|
48 |
$attribute = $node->attributes->item( $i );
|
56 |
if ( 0 === stripos( $attribute_name, 'on' ) && $attribute_name != 'on' ) {
|
57 |
$node->removeAttribute( $attribute_name );
|
58 |
continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
} elseif ( 'a' === $node_name ) {
|
60 |
$this->sanitize_a_attribute( $node, $attribute );
|
61 |
}
|
62 |
}
|
63 |
}
|
64 |
|
65 |
+
$length = $node->childNodes->length;
|
66 |
+
for ( $i = $length - 1; $i >= 0; $i-- ) {
|
67 |
+
$child_node = $node->childNodes->item( $i );
|
68 |
+
|
69 |
$this->strip_attributes_recursive( $child_node, $bad_attributes, $bad_protocols );
|
70 |
}
|
71 |
}
|
105 |
// rev removed from HTML5 spec, which was used by Jetpack Markdown.
|
106 |
$node->removeAttribute( $attribute_name );
|
107 |
} elseif ( 'target' === $attribute_name ) {
|
108 |
+
// _blank is the only allowed value and it must be lowercase.
|
109 |
+
// replace _new with _blank and others should simply be removed.
|
110 |
+
$old_value = strtolower( $attribute->value );
|
111 |
+
if ( '_blank' === $old_value || '_new' === $old_value ) {
|
112 |
+
// _new is not allowed; swap with _blank
|
113 |
+
$node->setAttribute( $attribute_name, '_blank' );
|
114 |
+
} else {
|
115 |
+
// only _blank is allowed
|
116 |
+
$node->removeAttribute( $attribute_name );
|
117 |
+
}
|
118 |
}
|
119 |
}
|
120 |
|
121 |
+
private function validate_a_node( $node ) {
|
122 |
+
// Get the href attribute
|
123 |
+
$href = $node->getAttribute( 'href' );
|
124 |
+
|
125 |
+
// If no href is set and this isn't an anchor, it's invalid
|
126 |
+
if ( empty( $href ) ) {
|
127 |
+
$name_attr = $node->getAttribute( 'name' );
|
128 |
+
if ( ! empty( $name_attr ) ) {
|
129 |
+
// No further validation is required
|
130 |
+
return true;
|
131 |
+
} else {
|
132 |
+
return false;
|
133 |
+
}
|
134 |
+
}
|
135 |
+
|
136 |
+
// If this is an anchor link, just return true
|
137 |
+
if ( 0 === strpos( $href, '#' ) ) {
|
138 |
+
return true;
|
139 |
+
}
|
140 |
+
|
141 |
+
// If the href starts with a '/', append the home_url to it for validation purposes.
|
142 |
+
if ( 0 === stripos( $href, '/' ) ) {
|
143 |
+
$href = untrailingslashit( get_home_url() ) . $href;
|
144 |
+
}
|
145 |
+
|
146 |
+
$valid_protocols = array( 'http', 'https', 'mailto', 'sms', 'tel', 'viber', 'whatsapp' );
|
147 |
+
$protocol = strtok( $href, ':' );
|
148 |
+
if ( false === filter_var( $href, FILTER_VALIDATE_URL )
|
149 |
+
|| ! in_array( $protocol, $valid_protocols ) ) {
|
150 |
+
return false;
|
151 |
+
}
|
152 |
+
|
153 |
+
return true;
|
154 |
+
}
|
155 |
+
|
156 |
+
private function replace_node_with_children( $node ) {
|
157 |
+
// If the node has children and also has a parent node,
|
158 |
+
// clone and re-add all the children just before current node.
|
159 |
+
if ( $node->hasChildNodes() && $node->parentNode ) {
|
160 |
+
foreach ( $node->childNodes as $child_node ) {
|
161 |
+
$new_child = $child_node->cloneNode( true );
|
162 |
+
$node->parentNode->insertBefore( $new_child, $node );
|
163 |
+
}
|
164 |
+
}
|
165 |
+
|
166 |
+
// Remove the node from the parent, if defined.
|
167 |
+
if ( $node->parentNode ) {
|
168 |
+
$node->parentNode->removeChild( $node );
|
169 |
+
}
|
170 |
+
}
|
171 |
+
|
172 |
+
private function merge_defaults_with_args( $key, $values ) {
|
173 |
+
// Merge default values with user specified args
|
174 |
+
if ( ! empty( $this->args[ $key ] )
|
175 |
+
&& is_array( $this->args[ $key ] ) ) {
|
176 |
+
$values = array_merge( $values, $this->args[ $key ] );
|
177 |
+
}
|
178 |
+
|
179 |
+
return $values;
|
180 |
+
}
|
181 |
+
|
182 |
private function get_blacklisted_protocols() {
|
183 |
+
return $this->merge_defaults_with_args( 'add_blacklisted_protocols', array(
|
184 |
'javascript',
|
185 |
+
) );
|
186 |
}
|
187 |
|
188 |
private function get_blacklisted_tags() {
|
189 |
+
return $this->merge_defaults_with_args( 'add_blacklisted_tags', array(
|
190 |
'script',
|
191 |
'noscript',
|
192 |
'style',
|
202 |
'select',
|
203 |
'option',
|
204 |
'link',
|
205 |
+
'picture',
|
206 |
+
|
207 |
+
// Sanitizers run after embed handlers, so if anything wasn't matched, it needs to be removed.
|
208 |
+
'embed',
|
209 |
+
'embedvideo',
|
210 |
|
211 |
// These are converted into amp-* versions
|
212 |
//'img',
|
213 |
//'video',
|
214 |
//'audio',
|
215 |
//'iframe',
|
216 |
+
) );
|
217 |
}
|
218 |
|
219 |
private function get_blacklisted_attributes() {
|
220 |
+
return $this->merge_defaults_with_args( 'add_blacklisted_attributes', array(
|
221 |
'style',
|
222 |
+
'size',
|
223 |
+
) );
|
224 |
}
|
225 |
}
|
includes/sanitizers/class-amp-iframe-sanitizer.php
CHANGED
@@ -37,23 +37,22 @@ class AMP_Iframe_Sanitizer extends AMP_Base_Sanitizer {
|
|
37 |
$node = $nodes->item( $i );
|
38 |
$old_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $node );
|
39 |
|
40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
$node->parentNode->removeChild( $node );
|
42 |
continue;
|
43 |
}
|
44 |
|
45 |
$this->did_convert_elements = true;
|
46 |
|
47 |
-
$new_attributes = $this->
|
48 |
-
|
49 |
-
if ( ! isset( $new_attributes['height'] ) ) {
|
50 |
-
unset( $new_attributes['width'] );
|
51 |
-
$new_attributes['height'] = self::FALLBACK_HEIGHT;
|
52 |
-
}
|
53 |
-
|
54 |
-
if ( ! isset( $new_attributes['width'] ) ) {
|
55 |
-
$new_attributes['layout'] = 'fixed-height';
|
56 |
-
}
|
57 |
$new_attributes = $this->enforce_sizes_attribute( $new_attributes );
|
58 |
|
59 |
$new_node = AMP_DOM_Utils::create_node( $this->dom, 'amp-iframe', $new_attributes );
|
@@ -84,23 +83,21 @@ class AMP_Iframe_Sanitizer extends AMP_Base_Sanitizer {
|
|
84 |
foreach ( $attributes as $name => $value ) {
|
85 |
switch ( $name ) {
|
86 |
case 'sandbox':
|
87 |
-
case 'height':
|
88 |
case 'class':
|
89 |
case 'sizes':
|
90 |
$out[ $name ] = $value;
|
91 |
break;
|
92 |
|
93 |
case 'src':
|
94 |
-
$out[ $name ] =
|
95 |
break;
|
96 |
|
97 |
case 'width':
|
98 |
-
|
99 |
-
|
100 |
-
}
|
101 |
-
$out[ $name ] = $value;
|
102 |
break;
|
103 |
|
|
|
104 |
case 'frameborder':
|
105 |
if ( '0' !== $value && '1' !== $value ) {
|
106 |
$value = '0';
|
37 |
$node = $nodes->item( $i );
|
38 |
$old_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $node );
|
39 |
|
40 |
+
$new_attributes = $this->filter_attributes( $old_attributes );
|
41 |
+
|
42 |
+
// If the src doesn't exist, remove the node.
|
43 |
+
// This means that it never existed or was invalidated
|
44 |
+
// while filtering attributes above.
|
45 |
+
//
|
46 |
+
// TODO: add a filter to allow for a fallback element in this instance.
|
47 |
+
// See: https://github.com/ampproject/amphtml/issues/2261
|
48 |
+
if ( empty( $new_attributes['src'] ) ) {
|
49 |
$node->parentNode->removeChild( $node );
|
50 |
continue;
|
51 |
}
|
52 |
|
53 |
$this->did_convert_elements = true;
|
54 |
|
55 |
+
$new_attributes = $this->enforce_fixed_height( $new_attributes );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
$new_attributes = $this->enforce_sizes_attribute( $new_attributes );
|
57 |
|
58 |
$new_node = AMP_DOM_Utils::create_node( $this->dom, 'amp-iframe', $new_attributes );
|
83 |
foreach ( $attributes as $name => $value ) {
|
84 |
switch ( $name ) {
|
85 |
case 'sandbox':
|
|
|
86 |
case 'class':
|
87 |
case 'sizes':
|
88 |
$out[ $name ] = $value;
|
89 |
break;
|
90 |
|
91 |
case 'src':
|
92 |
+
$out[ $name ] = $this->maybe_enforce_https_src( $value, true );
|
93 |
break;
|
94 |
|
95 |
case 'width':
|
96 |
+
case 'height':
|
97 |
+
$out[ $name ] = $this->sanitize_dimension( $value, $name );
|
|
|
|
|
98 |
break;
|
99 |
|
100 |
+
|
101 |
case 'frameborder':
|
102 |
if ( '0' !== $value && '1' !== $value ) {
|
103 |
$value = '0';
|
includes/sanitizers/class-amp-img-sanitizer.php
CHANGED
@@ -81,14 +81,18 @@ class AMP_Img_Sanitizer extends AMP_Base_Sanitizer {
|
|
81 |
switch ( $name ) {
|
82 |
case 'src':
|
83 |
case 'alt':
|
84 |
-
case 'width':
|
85 |
-
case 'height':
|
86 |
case 'class':
|
87 |
case 'srcset':
|
88 |
case 'sizes':
|
89 |
case 'on':
|
90 |
$out[ $name ] = $value;
|
91 |
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
92 |
default;
|
93 |
break;
|
94 |
}
|
81 |
switch ( $name ) {
|
82 |
case 'src':
|
83 |
case 'alt':
|
|
|
|
|
84 |
case 'class':
|
85 |
case 'srcset':
|
86 |
case 'sizes':
|
87 |
case 'on':
|
88 |
$out[ $name ] = $value;
|
89 |
break;
|
90 |
+
|
91 |
+
case 'width':
|
92 |
+
case 'height':
|
93 |
+
$out[ $name ] = $this->sanitize_dimension( $value, $name );
|
94 |
+
break;
|
95 |
+
|
96 |
default;
|
97 |
break;
|
98 |
}
|
includes/sanitizers/class-amp-video-sanitizer.php
CHANGED
@@ -22,22 +22,34 @@ class AMP_Video_Sanitizer extends AMP_Base_Sanitizer {
|
|
22 |
$old_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $node );
|
23 |
|
24 |
$new_attributes = $this->filter_attributes( $old_attributes );
|
25 |
-
|
26 |
-
|
27 |
-
$new_attributes['layout'] = 'fixed-height';
|
28 |
-
}
|
29 |
$new_attributes = $this->enforce_sizes_attribute( $new_attributes );
|
30 |
|
31 |
$new_node = AMP_DOM_Utils::create_node( $this->dom, 'amp-video', $new_attributes );
|
32 |
|
33 |
-
// TODO: limit child nodes too (only allowed: `source`; move rest to div+fallback)
|
34 |
// TODO: `source` does not have closing tag, and DOMDocument doesn't handle it well.
|
35 |
foreach ( $node->childNodes as $child_node ) {
|
36 |
$new_child_node = $child_node->cloneNode( true );
|
37 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
}
|
39 |
|
40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
}
|
42 |
}
|
43 |
|
@@ -47,23 +59,29 @@ class AMP_Video_Sanitizer extends AMP_Base_Sanitizer {
|
|
47 |
foreach ( $attributes as $name => $value ) {
|
48 |
switch ( $name ) {
|
49 |
case 'src':
|
50 |
-
|
|
|
|
|
51 |
case 'width':
|
52 |
case 'height':
|
|
|
|
|
|
|
|
|
53 |
case 'class':
|
54 |
case 'sizes':
|
55 |
$out[ $name ] = $value;
|
56 |
break;
|
|
|
57 |
case 'controls':
|
58 |
case 'loop':
|
59 |
case 'muted':
|
|
|
60 |
if ( 'false' !== $value ) {
|
61 |
$out[ $name ] = '';
|
62 |
}
|
63 |
break;
|
64 |
-
|
65 |
-
$out[ $name ] = 'desktop tablet mobile';
|
66 |
-
break;
|
67 |
default;
|
68 |
break;
|
69 |
}
|
22 |
$old_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $node );
|
23 |
|
24 |
$new_attributes = $this->filter_attributes( $old_attributes );
|
25 |
+
|
26 |
+
$new_attributes = $this->enforce_fixed_height( $new_attributes );
|
|
|
|
|
27 |
$new_attributes = $this->enforce_sizes_attribute( $new_attributes );
|
28 |
|
29 |
$new_node = AMP_DOM_Utils::create_node( $this->dom, 'amp-video', $new_attributes );
|
30 |
|
|
|
31 |
// TODO: `source` does not have closing tag, and DOMDocument doesn't handle it well.
|
32 |
foreach ( $node->childNodes as $child_node ) {
|
33 |
$new_child_node = $child_node->cloneNode( true );
|
34 |
+
$old_child_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $new_child_node );
|
35 |
+
$new_child_attributes = $this->filter_attributes( $old_child_attributes );
|
36 |
+
|
37 |
+
// Only append source tags with a valid src attribute
|
38 |
+
if ( ! empty( $new_child_attributes['src'] ) && 'source' === $new_child_node->tagName ) {
|
39 |
+
$new_node->appendChild( $new_child_node );
|
40 |
+
}
|
41 |
}
|
42 |
|
43 |
+
// If the node has at least one valid source, replace the old node with it.
|
44 |
+
// Otherwise, just remove the node.
|
45 |
+
//
|
46 |
+
// TODO: Add a fallback handler.
|
47 |
+
// See: https://github.com/ampproject/amphtml/issues/2261
|
48 |
+
if ( 0 === $new_node->childNodes->length && empty( $new_attributes['src'] ) ) {
|
49 |
+
$node->parentNode->removeChild( $node );
|
50 |
+
} else {
|
51 |
+
$node->parentNode->replaceChild( $new_node, $node );
|
52 |
+
}
|
53 |
}
|
54 |
}
|
55 |
|
59 |
foreach ( $attributes as $name => $value ) {
|
60 |
switch ( $name ) {
|
61 |
case 'src':
|
62 |
+
$out[ $name ] = $this->maybe_enforce_https_src( $value );
|
63 |
+
break;
|
64 |
+
|
65 |
case 'width':
|
66 |
case 'height':
|
67 |
+
$out[ $name ] = $this->sanitize_dimension( $value, $name );
|
68 |
+
break;
|
69 |
+
|
70 |
+
case 'poster':
|
71 |
case 'class':
|
72 |
case 'sizes':
|
73 |
$out[ $name ] = $value;
|
74 |
break;
|
75 |
+
|
76 |
case 'controls':
|
77 |
case 'loop':
|
78 |
case 'muted':
|
79 |
+
case 'autoplay':
|
80 |
if ( 'false' !== $value ) {
|
81 |
$out[ $name ] = '';
|
82 |
}
|
83 |
break;
|
84 |
+
|
|
|
|
|
85 |
default;
|
86 |
break;
|
87 |
}
|
includes/utils/class-amp-string-utils.php
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class AMP_String_Utils {
|
4 |
+
public static function endswith( $haystack, $needle ) {
|
5 |
+
return '' !== $haystack
|
6 |
+
&& '' !== $needle
|
7 |
+
&& $needle === substr( $haystack, -strlen( $needle ) );
|
8 |
+
}
|
9 |
+
}
|
readme.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
## Overview
|
4 |
|
5 |
-
This plugin adds support for the [Accelerated Mobile Pages](https://www.ampproject.org) (AMP) Project, which is an
|
6 |
|
7 |
With the plugin active, all posts on your site will have dynamically generated AMP-compatible versions, accessible by appending `/amp/` to the end your post URLs. For example, if your post URL is `http://example.com/2016/01/01/amp-on/`, you can access the AMP version at `http://example.com/2016/01/01/amp-on/amp/`. If you do not have [pretty permalinks](https://codex.wordpress.org/Using_Permalinks#mod_rewrite:_.22Pretty_Permalinks.22) enabled, you can do the same thing by appending `?amp=1`, i.e. `http://example.com/2016/01/01/amp-on/?amp=1`
|
8 |
|
@@ -275,7 +275,7 @@ If you want to add stuff to the head or footer of the default AMP template, use
|
|
275 |
```php
|
276 |
add_action( 'amp_post_template_footer', 'xyz_amp_add_pixel' );
|
277 |
|
278 |
-
function
|
279 |
$post_id = $amp_template->get( 'post_id' );
|
280 |
?>
|
281 |
<amp-pixel src="https://example.com/hi.gif?x=RANDOM"></amp-pixel>
|
@@ -559,7 +559,7 @@ If you want a custom template for your post type:
|
|
559 |
```
|
560 |
add_filter( 'amp_post_template_file', 'xyz_amp_set_review_template', 10, 3 );
|
561 |
|
562 |
-
function
|
563 |
if ( 'single' === $type && 'xyz-review' === $post->post_type ) {
|
564 |
$file = dirname( __FILE__ ) . '/templates/my-amp-review-template.php';
|
565 |
}
|
2 |
|
3 |
## Overview
|
4 |
|
5 |
+
This plugin adds support for the [Accelerated Mobile Pages](https://www.ampproject.org) (AMP) Project, which is an open source initiative that aims to provide mobile optimized content that can load instantly everywhere.
|
6 |
|
7 |
With the plugin active, all posts on your site will have dynamically generated AMP-compatible versions, accessible by appending `/amp/` to the end your post URLs. For example, if your post URL is `http://example.com/2016/01/01/amp-on/`, you can access the AMP version at `http://example.com/2016/01/01/amp-on/amp/`. If you do not have [pretty permalinks](https://codex.wordpress.org/Using_Permalinks#mod_rewrite:_.22Pretty_Permalinks.22) enabled, you can do the same thing by appending `?amp=1`, i.e. `http://example.com/2016/01/01/amp-on/?amp=1`
|
8 |
|
275 |
```php
|
276 |
add_action( 'amp_post_template_footer', 'xyz_amp_add_pixel' );
|
277 |
|
278 |
+
function xyz_amp_add_pixel( $amp_template ) {
|
279 |
$post_id = $amp_template->get( 'post_id' );
|
280 |
?>
|
281 |
<amp-pixel src="https://example.com/hi.gif?x=RANDOM"></amp-pixel>
|
559 |
```
|
560 |
add_filter( 'amp_post_template_file', 'xyz_amp_set_review_template', 10, 3 );
|
561 |
|
562 |
+
function xyz_amp_set_review_template( $file, $type, $post ) {
|
563 |
if ( 'single' === $type && 'xyz-review' === $post->post_type ) {
|
564 |
$file = dirname( __FILE__ ) . '/templates/my-amp-review-template.php';
|
565 |
}
|
readme.txt
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
=== AMP ===
|
2 |
-
Contributors: batmoo, joen, automattic
|
3 |
Tags: amp, mobile
|
4 |
Requires at least: 4.4
|
5 |
-
Tested up to: 4.
|
6 |
-
Stable tag: 0.3.
|
7 |
License: GPLv2 or later
|
8 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
|
@@ -15,7 +15,7 @@ This plugin adds support for the [Accelerated Mobile Pages](https://www.ampproje
|
|
15 |
|
16 |
With the plugin active, all posts on your site will have dynamically generated AMP-compatible versions, accessible by appending `/amp/` to the end your post URLs. For example, if your post URL is `http://example.com/2016/01/01/amp-on/`, you can access the AMP version at `http://example.com/2016/01/01/amp-on/amp/`. If you do not have [pretty permalinks](https://codex.wordpress.org/Using_Permalinks#mod_rewrite:_.22Pretty_Permalinks.22) enabled, you can do the same thing by appending `?amp=1`, i.e. `http://example.com/2016/01/01/amp-on/?amp=1`
|
17 |
|
18 |
-
Note #1: that Pages and archives are not currently supported.
|
19 |
|
20 |
Note #2: this plugin only creates AMP content but does not automatically display it to your users when they visit from a mobile device. That is handled by AMP consumers such as Google Search. For more details, see the [AMP Project FAQ](https://www.ampproject.org/docs/support/faqs.html).
|
21 |
|
@@ -34,6 +34,27 @@ You can find details about customization options at https://github.com/Automatti
|
|
34 |
|
35 |
== Changelog ==
|
36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
= 0.3.2 (Mar 4, 2016) =
|
38 |
|
39 |
* Jetpack Stats support.
|
1 |
=== AMP ===
|
2 |
+
Contributors: batmoo, joen, automattic, potatomaster
|
3 |
Tags: amp, mobile
|
4 |
Requires at least: 4.4
|
5 |
+
Tested up to: 4.6
|
6 |
+
Stable tag: 0.3.3
|
7 |
License: GPLv2 or later
|
8 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
|
15 |
|
16 |
With the plugin active, all posts on your site will have dynamically generated AMP-compatible versions, accessible by appending `/amp/` to the end your post URLs. For example, if your post URL is `http://example.com/2016/01/01/amp-on/`, you can access the AMP version at `http://example.com/2016/01/01/amp-on/amp/`. If you do not have [pretty permalinks](https://codex.wordpress.org/Using_Permalinks#mod_rewrite:_.22Pretty_Permalinks.22) enabled, you can do the same thing by appending `?amp=1`, i.e. `http://example.com/2016/01/01/amp-on/?amp=1`
|
17 |
|
18 |
+
Note #1: that Pages and archives are not currently supported. Pages support is being worked on.
|
19 |
|
20 |
Note #2: this plugin only creates AMP content but does not automatically display it to your users when they visit from a mobile device. That is handled by AMP consumers such as Google Search. For more details, see the [AMP Project FAQ](https://www.ampproject.org/docs/support/faqs.html).
|
21 |
|
34 |
|
35 |
== Changelog ==
|
36 |
|
37 |
+
= 0.4 (in-progress) =
|
38 |
+
|
39 |
+
- Pages
|
40 |
+
- Customizer
|
41 |
+
- Updated Template
|
42 |
+
|
43 |
+
= 0.3.3 (Aug 18, 2016) =
|
44 |
+
|
45 |
+
- Handle many more validation errors (props bcampeau and alleyinteractive).
|
46 |
+
- New filter: `amp_post_template_dir` (props mustafauysal).
|
47 |
+
- New template: Nav bar is now it's own template part (props jdevalk).
|
48 |
+
- Better ratio for YouTube embeds.
|
49 |
+
- Fix: better timezone handling (props rinatkhaziev).
|
50 |
+
- Fix: better handling of non-int dimensions (like `100%`).
|
51 |
+
- Fix: better handling of empty dimensions.
|
52 |
+
- Fix: `autoplay` is a bool-like value.
|
53 |
+
- Fix: breakage when using the `query_string` hook (h/t mkuplens).
|
54 |
+
- Fix: don't break really large Twitter IDs.
|
55 |
+
- Fix: don't break Instagram shortcodes when using URLs with querystrings.
|
56 |
+
- Readme improvements (props nickjohnford, sotayamashita)
|
57 |
+
|
58 |
= 0.3.2 (Mar 4, 2016) =
|
59 |
|
60 |
* Jetpack Stats support.
|
templates/header-bar.php
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<nav class="amp-wp-title-bar">
|
2 |
+
<div>
|
3 |
+
<a href="<?php echo esc_url( $this->get( 'home_url' ) ); ?>">
|
4 |
+
<?php $site_icon_url = $this->get( 'site_icon_url' ); ?>
|
5 |
+
<?php if ( $site_icon_url ) : ?>
|
6 |
+
<amp-img src="<?php echo esc_url( $site_icon_url ); ?>" width="32" height="32" class="amp-wp-site-icon"></amp-img>
|
7 |
+
<?php endif; ?>
|
8 |
+
<?php echo esc_html( $this->get( 'blog_name' ) ); ?>
|
9 |
+
</a>
|
10 |
+
</div>
|
11 |
+
</nav>
|
templates/meta-time.php
CHANGED
@@ -4,7 +4,7 @@
|
|
4 |
echo esc_html(
|
5 |
sprintf(
|
6 |
_x( '%s ago', '%s = human-readable time difference', 'amp' ),
|
7 |
-
human_time_diff( $this->get( 'post_publish_timestamp' ) )
|
8 |
)
|
9 |
);
|
10 |
?>
|
4 |
echo esc_html(
|
5 |
sprintf(
|
6 |
_x( '%s ago', '%s = human-readable time difference', 'amp' ),
|
7 |
+
human_time_diff( $this->get( 'post_publish_timestamp' ), current_time( 'timestamp' ) )
|
8 |
)
|
9 |
);
|
10 |
?>
|
templates/single.php
CHANGED
@@ -11,17 +11,7 @@
|
|
11 |
</style>
|
12 |
</head>
|
13 |
<body>
|
14 |
-
|
15 |
-
<div>
|
16 |
-
<a href="<?php echo esc_url( $this->get( 'home_url' ) ); ?>">
|
17 |
-
<?php $site_icon_url = $this->get( 'site_icon_url' ); ?>
|
18 |
-
<?php if ( $site_icon_url ) : ?>
|
19 |
-
<amp-img src="<?php echo esc_url( $site_icon_url ); ?>" width="32" height="32" class="amp-wp-site-icon"></amp-img>
|
20 |
-
<?php endif; ?>
|
21 |
-
<?php echo esc_html( $this->get( 'blog_name' ) ); ?>
|
22 |
-
</a>
|
23 |
-
</div>
|
24 |
-
</nav>
|
25 |
<div class="amp-wp-content">
|
26 |
<h1 class="amp-wp-title"><?php echo wp_kses_data( $this->get( 'post_title' ) ); ?></h1>
|
27 |
<ul class="amp-wp-meta">
|
11 |
</style>
|
12 |
</head>
|
13 |
<body>
|
14 |
+
<?php $this->load_parts( array( 'header-bar' ) ); ?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
<div class="amp-wp-content">
|
16 |
<h1 class="amp-wp-title"><?php echo wp_kses_data( $this->get( 'post_title' ) ); ?></h1>
|
17 |
<ul class="amp-wp-meta">
|