AMP for WordPress - Version 0.3

Version Description

(Feb 18, 2016) =

  • Fetch dimensions for hotlinked images.
  • Add amp-facebook support.
  • Add some new actions and filters (e.g. amp_init).
  • Fix validation errors for [gallery] shortcodes.
  • Fix issues with path validation on Windows.
  • Fix issues with really squeezed layout.
  • Breaking change: style.css no longer contains the `
Download this release

Release Info

Developer batmoo
Plugin Icon 128x128 AMP for WordPress
Version 0.3
Comparing to
See all releases

Code changes from version 0.2 to 0.3

amp.php CHANGED
@@ -5,16 +5,13 @@
5
  * Plugin URI: https://github.com/automattic/amp-wp
6
  * Author: Automattic
7
  * Author URI: https://automattic.com
8
- * Version: 0.2
9
  * Text Domain: amp
10
  * Domain Path: /languages/
11
  * License: GPLv2 or later
12
  */
13
 
14
  define( 'AMP_QUERY_VAR', 'amp' );
15
- if ( ! defined( 'AMP_DEV_MODE' ) ) {
16
- define( 'AMP_DEV_MODE', defined( 'WP_DEBUG' ) && WP_DEBUG );
17
- }
18
 
19
  define( 'AMP__FILE__', __FILE__ );
20
  define( 'AMP__DIR__', dirname( __FILE__ ) );
@@ -38,6 +35,8 @@ function amp_init() {
38
  return;
39
  }
40
 
 
 
41
  load_plugin_textdomain( 'amp', false, plugin_basename( AMP__DIR__ ) . '/languages' );
42
 
43
  add_rewrite_endpoint( AMP_QUERY_VAR, EP_PERMALINK );
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
12
  */
13
 
14
  define( 'AMP_QUERY_VAR', 'amp' );
 
 
 
15
 
16
  define( 'AMP__FILE__', __FILE__ );
17
  define( 'AMP__DIR__', dirname( __FILE__ ) );
35
  return;
36
  }
37
 
38
+ do_action( 'amp_init' );
39
+
40
  load_plugin_textdomain( 'amp', false, plugin_basename( AMP__DIR__ ) . '/languages' );
41
 
42
  add_rewrite_endpoint( AMP_QUERY_VAR, EP_PERMALINK );
assets/images/placeholder-icon.png CHANGED
Binary file
includes/amp-helper-functions.php CHANGED
@@ -16,7 +16,7 @@ function post_supports_amp( $post ) {
16
  return false;
17
  }
18
 
19
- if ( true === apply_filters( 'amp_skip_post', false, $post->ID ) ) {
20
  return false;
21
  }
22
 
16
  return false;
17
  }
18
 
19
+ if ( true === apply_filters( 'amp_skip_post', false, $post->ID, $post ) ) {
20
  return false;
21
  }
22
 
includes/amp-post-template-actions.php CHANGED
@@ -25,9 +25,20 @@ function amp_post_template_add_scripts( $amp_template ) {
25
  <?php
26
  }
27
 
 
 
 
 
 
 
 
28
  add_action( 'amp_post_template_head', 'amp_post_template_add_schemaorg_metadata' );
29
  function amp_post_template_add_schemaorg_metadata( $amp_template ) {
 
 
 
 
30
  ?>
31
- <script type="application/ld+json"><?php echo json_encode( $amp_template->get( 'metadata' ) ); ?></script>
32
  <?php
33
  }
25
  <?php
26
  }
27
 
28
+ add_action( 'amp_post_template_head', 'amp_post_template_add_boilerplate_css' );
29
+ function amp_post_template_add_boilerplate_css( $amp_template ) {
30
+ ?>
31
+ <style>body {opacity: 0}</style><noscript><style>body {opacity: 1}</style></noscript>
32
+ <?php
33
+ }
34
+
35
  add_action( 'amp_post_template_head', 'amp_post_template_add_schemaorg_metadata' );
36
  function amp_post_template_add_schemaorg_metadata( $amp_template ) {
37
+ $metadata = $amp_template->get( 'metadata' );
38
+ if ( empty( $metadata ) ) {
39
+ return;
40
+ }
41
  ?>
42
+ <script type="application/ld+json"><?php echo json_encode( $metadata ); ?></script>
43
  <?php
44
  }
includes/class-amp-post-template.php CHANGED
@@ -13,6 +13,7 @@ require_once( AMP__DIR__ . '/includes/embeds/class-amp-youtube-embed.php' );
13
  require_once( AMP__DIR__ . '/includes/embeds/class-amp-gallery-embed.php' );
14
  require_once( AMP__DIR__ . '/includes/embeds/class-amp-instagram-embed.php' );
15
  require_once( AMP__DIR__ . '/includes/embeds/class-amp-vine-embed.php' );
 
16
 
17
  class AMP_Post_Template {
18
  const SITE_ICON_SIZE = 32;
@@ -37,7 +38,7 @@ class AMP_Post_Template {
37
  'home_url' => home_url(),
38
  'blog_name' => get_bloginfo( 'name' ),
39
 
40
- 'site_icon_url' => get_site_icon_url( self::SITE_ICON_SIZE ),
41
  'placeholder_image_url' => amp_get_asset_url( 'images/placeholder-icon.png' ),
42
 
43
  'amp_runtime_script' => 'https://cdn.ampproject.org/v0.js',
@@ -121,7 +122,6 @@ class AMP_Post_Template {
121
  '@type' => 'Person',
122
  'name' => $post_author->display_name,
123
  ),
124
- 'image' => $this->get_post_image_metadata(),
125
  );
126
 
127
  $site_icon_url = $this->get( 'site_icon_url' );
@@ -134,7 +134,12 @@ class AMP_Post_Template {
134
  );
135
  }
136
 
137
- $this->add_data_by_key( 'metadata', $metadata );
 
 
 
 
 
138
  }
139
 
140
  private function build_post_content() {
@@ -144,6 +149,7 @@ class AMP_Post_Template {
144
  'AMP_YouTube_Embed_Handler' => array(),
145
  'AMP_Instagram_Embed_Handler' => array(),
146
  'AMP_Vine_Embed_Handler' => array(),
 
147
  'AMP_Gallery_Embed_Handler' => array(),
148
  ), $this->post ),
149
  apply_filters( 'amp_content_sanitizers', array(
@@ -198,7 +204,7 @@ class AMP_Post_Template {
198
 
199
  $post_image_src = wp_get_attachment_image_src( $post_image_id, 'full' );
200
 
201
- if ( $post_image_src ) {
202
  $post_image_meta = array(
203
  '@type' => 'ImageObject',
204
  'url' => $post_image_src[0],
@@ -232,7 +238,9 @@ class AMP_Post_Template {
232
  }
233
 
234
  private function is_valid_template( $template ) {
235
- if ( 0 !== strpos( $template, WP_CONTENT_DIR ) ) {
 
 
236
  return false;
237
  }
238
 
@@ -240,6 +248,14 @@ class AMP_Post_Template {
240
  return false;
241
  }
242
 
 
 
 
 
243
  return true;
244
  }
 
 
 
 
245
  }
13
  require_once( AMP__DIR__ . '/includes/embeds/class-amp-gallery-embed.php' );
14
  require_once( AMP__DIR__ . '/includes/embeds/class-amp-instagram-embed.php' );
15
  require_once( AMP__DIR__ . '/includes/embeds/class-amp-vine-embed.php' );
16
+ require_once( AMP__DIR__ . '/includes/embeds/class-amp-facebook-embed.php' );
17
 
18
  class AMP_Post_Template {
19
  const SITE_ICON_SIZE = 32;
38
  'home_url' => home_url(),
39
  'blog_name' => get_bloginfo( 'name' ),
40
 
41
+ 'site_icon_url' => apply_filters( 'amp_site_icon_url', function_exists( 'get_site_icon_url' ) ? get_site_icon_url( self::SITE_ICON_SIZE ) : '' ),
42
  'placeholder_image_url' => amp_get_asset_url( 'images/placeholder-icon.png' ),
43
 
44
  'amp_runtime_script' => 'https://cdn.ampproject.org/v0.js',
122
  '@type' => 'Person',
123
  'name' => $post_author->display_name,
124
  ),
 
125
  );
126
 
127
  $site_icon_url = $this->get( 'site_icon_url' );
134
  );
135
  }
136
 
137
+ $image_metadata = $this->get_post_image_metadata();
138
+ if ( $image_metadata ) {
139
+ $metadata['image'] = $image_metadata;
140
+ }
141
+
142
+ $this->add_data_by_key( 'metadata', apply_filters( 'amp_post_template_metadata', $metadata, $this->post ) );
143
  }
144
 
145
  private function build_post_content() {
149
  'AMP_YouTube_Embed_Handler' => array(),
150
  'AMP_Instagram_Embed_Handler' => array(),
151
  'AMP_Vine_Embed_Handler' => array(),
152
+ 'AMP_Facebook_Embed_Handler' => array(),
153
  'AMP_Gallery_Embed_Handler' => array(),
154
  ), $this->post ),
155
  apply_filters( 'amp_content_sanitizers', array(
204
 
205
  $post_image_src = wp_get_attachment_image_src( $post_image_id, 'full' );
206
 
207
+ if ( is_array( $post_image_src ) ) {
208
  $post_image_meta = array(
209
  '@type' => 'ImageObject',
210
  'url' => $post_image_src[0],
238
  }
239
 
240
  private function is_valid_template( $template ) {
241
+ $template = $this->normalize_path( $template );
242
+ $content_dir = $this->normalize_path( WP_CONTENT_DIR );
243
+ if ( 0 !== strpos( $template, $content_dir ) ) {
244
  return false;
245
  }
246
 
248
  return false;
249
  }
250
 
251
+ if ( ! file_exists( $template ) ) {
252
+ return false;
253
+ }
254
+
255
  return true;
256
  }
257
+
258
+ private function normalize_path( $path ) {
259
+ return str_replace( array( '/', '\\' ), DIRECTORY_SEPARATOR, $path );
260
+ }
261
  }
includes/embeds/class-amp-facebook-embed.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once( AMP__DIR__ . '/includes/embeds/class-amp-base-embed-handler.php' );
4
+
5
+ class AMP_Facebook_Embed_Handler extends AMP_Base_Embed_Handler {
6
+ const URL_PATTERN = '#https?://(www\.)?facebook\.com/.*#i';
7
+
8
+ protected $DEFAULT_WIDTH = 600;
9
+ protected $DEFAULT_HEIGHT = 400;
10
+
11
+ private static $script_slug = 'amp-facebook';
12
+ private static $script_src = 'https://cdn.ampproject.org/v0/amp-facebook-0.1.js';
13
+
14
+ public function register_embed() {
15
+ wp_embed_register_handler( 'amp-facebook', self::URL_PATTERN, array( $this, 'oembed' ), -1 );
16
+ }
17
+
18
+ public function unregister_embed() {
19
+ wp_embed_unregister_handler( 'amp-facebook', -1 );
20
+ }
21
+
22
+ public function get_scripts() {
23
+ if ( ! $this->did_convert_elements ) {
24
+ return array();
25
+ }
26
+
27
+ return array( self::$script_slug => self::$script_src );
28
+ }
29
+
30
+ public function oembed( $matches, $attr, $url, $rawattr ) {
31
+ return $this->render( array( 'url' => $url ) );
32
+ }
33
+
34
+ public function render( $args ) {
35
+ $args = wp_parse_args( $args, array(
36
+ 'url' => false,
37
+ ) );
38
+
39
+ if ( empty( $args['url'] ) ) {
40
+ return '';
41
+ }
42
+
43
+ $this->did_convert_elements = true;
44
+
45
+ return AMP_HTML_Utils::build_tag(
46
+ 'amp-facebook',
47
+ array(
48
+ 'data-href' => $args['url'],
49
+ 'layout' => 'responsive',
50
+ 'width' => $this->args['width'],
51
+ 'height' => $this->args['height'],
52
+ )
53
+ );
54
+ }
55
+ }
includes/embeds/class-amp-gallery-embed.php CHANGED
@@ -126,7 +126,12 @@ class AMP_Gallery_Embed_Handler extends AMP_Base_Embed_Handler {
126
 
127
  return AMP_HTML_Utils::build_tag(
128
  'amp-carousel',
129
- wp_parse_args( array(), $this->args ),
 
 
 
 
 
130
  implode( PHP_EOL, $images )
131
  );
132
  }
126
 
127
  return AMP_HTML_Utils::build_tag(
128
  'amp-carousel',
129
+ array(
130
+ 'width' => $this->args['width'],
131
+ 'height' => $this->args['height'],
132
+ 'type' => 'slides',
133
+ 'layout' => 'responsive',
134
+ ),
135
  implode( PHP_EOL, $images )
136
  );
137
  }
includes/lib/class-fastimage.php ADDED
@@ -0,0 +1,253 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * FastImage - Because sometimes you just want the size!
5
+ * Based on the Ruby Implementation by Steven Sykes (https://github.com/sdsykes/fastimage)
6
+ *
7
+ * Copyright (c) 2012 Tom Moor
8
+ * Tom Moor, http://tommoor.com
9
+ *
10
+ * MIT Licensed
11
+ * @version 0.1
12
+ */
13
+
14
+ class FastImage
15
+ {
16
+ private $strpos = 0;
17
+ private $str;
18
+ private $type;
19
+ private $handle;
20
+
21
+ public function __construct($uri = null)
22
+ {
23
+ if ($uri) $this->load($uri);
24
+ }
25
+
26
+
27
+ public function load($uri)
28
+ {
29
+ if ($this->handle) $this->close();
30
+
31
+ $this->handle = fopen($uri, 'r');
32
+ }
33
+
34
+
35
+ public function close()
36
+ {
37
+ if ($this->handle)
38
+ {
39
+ fclose($this->handle);
40
+ $this->handle = null;
41
+ $this->type = null;
42
+ $this->str = null;
43
+ }
44
+ }
45
+
46
+
47
+ public function getSize()
48
+ {
49
+ if (!$this->handle)
50
+ {
51
+ return false;
52
+ }
53
+
54
+ $this->strpos = 0;
55
+ if ($this->getType())
56
+ {
57
+ return array_values($this->parseSize());
58
+ }
59
+
60
+ return false;
61
+ }
62
+
63
+
64
+ public function getType()
65
+ {
66
+ if (!$this->handle)
67
+ {
68
+ return false;
69
+ }
70
+
71
+ $this->strpos = 0;
72
+
73
+ if (!$this->type)
74
+ {
75
+ switch ($this->getChars(2))
76
+ {
77
+ case "BM":
78
+ return $this->type = 'bmp';
79
+ case "GI":
80
+ return $this->type = 'gif';
81
+ case chr(0xFF).chr(0xd8):
82
+ return $this->type = 'jpeg';
83
+ case chr(0x89).'P':
84
+ return $this->type = 'png';
85
+ default:
86
+ return false;
87
+ }
88
+ }
89
+
90
+ return $this->type;
91
+ }
92
+
93
+
94
+ private function parseSize()
95
+ {
96
+ $this->strpos = 0;
97
+
98
+ switch ($this->type)
99
+ {
100
+ case 'png':
101
+ return $this->parseSizeForPNG();
102
+ case 'gif':
103
+ return $this->parseSizeForGIF();
104
+ case 'bmp':
105
+ return $this->parseSizeForBMP();
106
+ case 'jpeg':
107
+ return $this->parseSizeForJPEG();
108
+ }
109
+
110
+ return null;
111
+ }
112
+
113
+
114
+ private function parseSizeForPNG()
115
+ {
116
+ $chars = $this->getChars(25);
117
+
118
+ return unpack("N*", substr($chars, 16, 8));
119
+ }
120
+
121
+
122
+ private function parseSizeForGIF()
123
+ {
124
+ $chars = $this->getChars(11);
125
+
126
+ return unpack("S*", substr($chars, 6, 4));
127
+ }
128
+
129
+
130
+ private function parseSizeForBMP()
131
+ {
132
+ $chars = $this->getChars(29);
133
+ $chars = substr($chars, 14, 14);
134
+ $type = unpack('C', $chars);
135
+
136
+ return (reset($type) == 40) ? unpack('L*', substr($chars, 4)) : unpack('L*', substr($chars, 4, 8));
137
+ }
138
+
139
+
140
+ private function parseSizeForJPEG()
141
+ {
142
+ $state = null;
143
+ $i = 0;
144
+
145
+ while (true)
146
+ {
147
+ switch ($state)
148
+ {
149
+ default:
150
+ $this->getChars(2);
151
+ $state = 'started';
152
+ break;
153
+
154
+ case 'started':
155
+ $b = $this->getByte();
156
+ if ($b === false) return false;
157
+
158
+ $state = $b == 0xFF ? 'sof' : 'started';
159
+ break;
160
+
161
+ case 'sof':
162
+ $b = $this->getByte();
163
+ if (in_array($b, range(0xe0, 0xef)))
164
+ {
165
+ $state = 'skipframe';
166
+ }
167
+ elseif (in_array($b, array_merge(range(0xC0,0xC3), range(0xC5,0xC7), range(0xC9,0xCB), range(0xCD,0xCF))))
168
+ {
169
+ $state = 'readsize';
170
+ }
171
+ elseif ($b == 0xFF)
172
+ {
173
+ $state = 'sof';
174
+ }
175
+ else
176
+ {
177
+ $state = 'skipframe';
178
+ }
179
+ break;
180
+
181
+ case 'skipframe':
182
+ $skip = $this->readInt($this->getChars(2)) - 2;
183
+ $state = 'doskip';
184
+ break;
185
+
186
+ case 'doskip':
187
+ $this->getChars($skip);
188
+ $state = 'started';
189
+ break;
190
+
191
+ case 'readsize':
192
+ $c = $this->getChars(7);
193
+
194
+ return array($this->readInt(substr($c, 5, 2)), $this->readInt(substr($c, 3, 2)));
195
+ }
196
+ }
197
+ }
198
+
199
+
200
+ private function getChars($n)
201
+ {
202
+ $response = null;
203
+
204
+ // do we need more data?
205
+ if ($this->strpos + $n -1 >= strlen($this->str))
206
+ {
207
+ $end = ($this->strpos + $n);
208
+
209
+ while (strlen($this->str) < $end && $response !== false)
210
+ {
211
+ // read more from the file handle
212
+ $need = $end - ftell($this->handle);
213
+
214
+ if ($response = fread($this->handle, $need))
215
+ {
216
+ $this->str .= $response;
217
+ }
218
+ else
219
+ {
220
+ return false;
221
+ }
222
+ }
223
+ }
224
+
225
+ $result = substr($this->str, $this->strpos, $n);
226
+ $this->strpos += $n;
227
+
228
+ return $result;
229
+ }
230
+
231
+
232
+ private function getByte()
233
+ {
234
+ $c = $this->getChars(1);
235
+ $b = unpack("C", $c);
236
+
237
+ return reset($b);
238
+ }
239
+
240
+
241
+ private function readInt($str)
242
+ {
243
+ $size = unpack("C*", $str);
244
+
245
+ return ($size[1] << 8) + $size[2];
246
+ }
247
+
248
+
249
+ public function __destruct()
250
+ {
251
+ $this->close();
252
+ }
253
+ }
includes/sanitizers/class-amp-base-sanitizer.php CHANGED
@@ -31,10 +31,6 @@ abstract class AMP_Base_Sanitizer {
31
  * See https://github.com/Automattic/amp-wp/issues/101
32
  */
33
  public function enforce_sizes_attribute( $attributes ) {
34
- if ( isset( $attributes['sizes'] ) ) {
35
- return $attributes;
36
- }
37
-
38
  if ( ! isset( $attributes['width'], $attributes['height'] ) ) {
39
  return $attributes;
40
  }
31
  * See https://github.com/Automattic/amp-wp/issues/101
32
  */
33
  public function enforce_sizes_attribute( $attributes ) {
 
 
 
 
34
  if ( ! isset( $attributes['width'], $attributes['height'] ) ) {
35
  return $attributes;
36
  }
includes/sanitizers/class-amp-blacklist-sanitizer.php CHANGED
@@ -9,6 +9,8 @@ require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-base-sanitizer.php' )
9
  * https://github.com/ampproject/amphtml/blob/master/spec/amp-html-format.md#html-tags
10
  */
11
  class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
 
 
12
  public function sanitize() {
13
  $blacklisted_tags = $this->get_blacklisted_tags();
14
  $blacklisted_attributes = $this->get_blacklisted_attributes();
@@ -25,6 +27,7 @@ class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
25
  }
26
 
27
  if ( $node->hasAttributes() ) {
 
28
  $length = $node->attributes->length;
29
  for ( $i = $length - 1; $i >= 0; $i-- ) {
30
  $attribute = $node->attributes->item( $i );
@@ -38,14 +41,21 @@ class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
38
  if ( 0 === stripos( $attribute_name, 'on' ) ) {
39
  $node->removeAttribute( $attribute_name );
40
  continue;
41
- }
42
-
43
- if ( 'href' === $attribute_name ) {
44
  $protocol = strtok( $attribute->value, ':' );
45
  if ( in_array( $protocol, $bad_protocols ) ) {
46
  $node->removeAttribute( $attribute_name );
47
  continue;
48
  }
 
 
 
 
 
 
 
 
 
49
  }
50
  }
51
  }
@@ -93,7 +103,6 @@ class AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
93
  'applet',
94
  'form',
95
  'input',
96
- 'button',
97
  'textarea',
98
  'select',
99
  'option',
9
  * https://github.com/ampproject/amphtml/blob/master/spec/amp-html-format.md#html-tags
10
  */
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();
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
  if ( 0 === stripos( $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 && 'rel' === $attribute_name ) {
51
+ $old_value = $attribute->value;
52
+ $new_value = trim( preg_replace( self::PATTERN_REL_WP_ATTACHMENT, '', $old_value ) );
53
+ if ( empty( $new_value ) ) {
54
+ $node->removeAttribute( $attribute_name );
55
+ } elseif ( $old_value !== $new_value ) {
56
+ $node->setAttribute( $attribute_name, $new_value );
57
+ }
58
+
59
  }
60
  }
61
  }
103
  'applet',
104
  'form',
105
  'input',
 
106
  'textarea',
107
  'select',
108
  'option',
includes/sanitizers/class-amp-img-sanitizer.php CHANGED
@@ -33,7 +33,7 @@ class AMP_Img_Sanitizer extends AMP_Base_Sanitizer {
33
  $new_attributes = $this->filter_attributes( $old_attributes );
34
  if ( ! isset( $new_attributes['width'] ) || ! isset( $new_attributes['height'] ) ) {
35
  $dimensions = AMP_Image_Dimension_Extractor::extract( $new_attributes['src'] );
36
- if ( $dimensions ) {
37
  $new_attributes['width'] = $dimensions[0];
38
  $new_attributes['height'] = $dimensions[1];
39
  }
33
  $new_attributes = $this->filter_attributes( $old_attributes );
34
  if ( ! isset( $new_attributes['width'] ) || ! isset( $new_attributes['height'] ) ) {
35
  $dimensions = AMP_Image_Dimension_Extractor::extract( $new_attributes['src'] );
36
+ if ( is_array( $dimensions ) ) {
37
  $new_attributes['width'] = $dimensions[0];
38
  $new_attributes['height'] = $dimensions[1];
39
  }
includes/utils/class-amp-image-dimension-extractor.php CHANGED
@@ -15,10 +15,13 @@ class AMP_Image_Dimension_Extractor {
15
  self::$callbacks_registered = true;
16
 
17
  add_filter( 'amp_extract_image_dimensions', array( __CLASS__, 'extract_from_attachment_metadata' ), 10, 2 );
 
 
 
18
  }
19
 
20
  public static function extract_from_attachment_metadata( $dimensions, $url ) {
21
- if ( $dimensions ) {
22
  return $dimensions;
23
  }
24
 
@@ -35,4 +38,49 @@ class AMP_Image_Dimension_Extractor {
35
 
36
  return array( $metadata['width'], $metadata['height'] );
37
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  }
15
  self::$callbacks_registered = true;
16
 
17
  add_filter( 'amp_extract_image_dimensions', array( __CLASS__, 'extract_from_attachment_metadata' ), 10, 2 );
18
+ add_filter( 'amp_extract_image_dimensions', array( __CLASS__, 'extract_by_downloading_image' ), 999, 2 ); // Run really late since this is our last resort
19
+
20
+ do_action( 'amp_extract_image_dimensions_callbacks_registered' );
21
  }
22
 
23
  public static function extract_from_attachment_metadata( $dimensions, $url ) {
24
+ if ( is_array( $dimensions ) ) {
25
  return $dimensions;
26
  }
27
 
38
 
39
  return array( $metadata['width'], $metadata['height'] );
40
  }
41
+
42
+ public static function extract_by_downloading_image( $dimensions, $url ) {
43
+ if ( is_array( $dimensions ) ) {
44
+ return $dimensions;
45
+ }
46
+
47
+ $url_hash = md5( $url );
48
+ $transient_name = sprintf( 'amp_img_%s', $url_hash );
49
+ $transient_expiry = 30 * DAY_IN_SECONDS;
50
+ $transient_fail = 'fail';
51
+
52
+ $dimensions = get_transient( $transient_name );
53
+
54
+ if ( is_array( $dimensions ) ) {
55
+ return $dimensions;
56
+ } elseif ( $transient_fail === $dimensions ) {
57
+ return false;
58
+ }
59
+
60
+ // Very simple lock to prevent stampedes
61
+ $transient_lock_name = sprintf( 'amp_lock_%s', $url_hash );
62
+ if ( false !== get_transient( $transient_lock_name ) ) {
63
+ return false;
64
+ }
65
+ set_transient( $transient_lock_name, 1, MINUTE_IN_SECONDS );
66
+
67
+ // Note to other developers: please don't use this class directly as it may not stick around forever...
68
+ if ( ! class_exists( 'FastImage' ) ) {
69
+ require_once( AMP__DIR__ . '/includes/lib/class-fastimage.php' );
70
+ }
71
+
72
+ // TODO: look into using curl+stream (https://github.com/willwashburn/FasterImage)
73
+ $image = new FastImage( $url );
74
+ $dimensions = $image->getSize();
75
+
76
+ if ( ! is_array( $dimensions ) ) {
77
+ set_transient( $transient_name, $transient_fail, $transient_expiry );
78
+ delete_transient( $transient_lock_name );
79
+ return false;
80
+ }
81
+
82
+ set_transient( $transient_name, $dimensions, $transient_expiry );
83
+ delete_transient( $transient_lock_name );
84
+ return $dimensions;
85
+ }
86
  }
jetpack-helper.php CHANGED
@@ -2,16 +2,21 @@
2
 
3
  // Jetpack bits.
4
 
5
- add_action( 'pre_amp_render', 'amp_jetpack_mods' );
6
 
7
  /**
8
  * Disable Jetpack features that are not compatible with AMP.
9
  *
10
  **/
11
  function amp_jetpack_mods() {
 
12
  amp_jetpack_disable_related_posts();
13
  }
14
 
 
 
 
 
15
  /**
16
  * Remove the Related Posts placeholder and headline that gets hooked into the_content
17
  *
2
 
3
  // Jetpack bits.
4
 
5
+ add_action( 'pre_amp_render_post', 'amp_jetpack_mods' );
6
 
7
  /**
8
  * Disable Jetpack features that are not compatible with AMP.
9
  *
10
  **/
11
  function amp_jetpack_mods() {
12
+ amp_jetpack_disable_sharing();
13
  amp_jetpack_disable_related_posts();
14
  }
15
 
16
+ function amp_jetpack_disable_sharing() {
17
+ add_filter( 'sharing_show', '__return_false', 100 );
18
+ }
19
+
20
  /**
21
  * Remove the Related Posts placeholder and headline that gets hooked into the_content
22
  *
readme.md CHANGED
@@ -2,11 +2,13 @@
2
 
3
  ## Overview
4
 
5
- This plugin adds support for the Accelerated Mobile Pages (AMP) Project, which is an an open source initiative that aims to provide mobile optimized content that can load instantly everywhere.
6
 
7
- With the plugin active, all content on your site will have dynamically generated AMP-compatible versions, accessible by appending `/amp/` to the end your permalinks. (If you do not have pretty permalinks enabled, you can do the same thing by appending `?amp=1`.)
8
 
9
- Developers: please note that this plugin is still in early stages and the underlying APIs (like filters, classes, etc.) may change.
 
 
10
 
11
  ## Customization / Templating
12
 
@@ -14,16 +16,69 @@ The plugin ships with a default template that looks nice and clean and we tried
14
 
15
  You can tweak small pieces of the template or the entire thing depending on your needs.
16
 
17
- ### Theme Mods
 
 
 
 
 
 
 
 
18
 
19
- (This still needs to be implemented.)
 
 
 
 
 
20
 
21
  The default template will attempt to draw from various theme mods, such as site icon and background and header color/image, if supported by the active theme.
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  ### Template Tweaks
24
 
25
  You can tweak various parts of the template via code.
26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  #### Content Width
28
 
29
  By default, your theme's `$content_width` value will be used to determine the size of the `amp` content well. You can change this:
@@ -51,7 +106,27 @@ function xyz_set_custom_placeholder_image( $data ) {
51
 
52
  Note: The path must pass the default criteria set out by [`validate_file`](https://developer.wordpress.org/reference/functions/validate_file/) and must be somewhere in a subfolder of `WP_CONTENT_DIR`.
53
 
54
- #### Meta
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
  For the meta section of the template (i.e. author, date, taxonomies, etc.), you can override templates for the existing sections, remove them, add new ones.
57
 
@@ -137,12 +212,34 @@ Then, in `templates/xyz-meta-comment-count.php`:
137
 
138
  #### Custom CSS
139
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  If you'd prefer to use your own styles, you can either:
141
 
142
  - Create a folder in your theme called `amp` and add a file called `style.php` with your custom CSS.
143
- - Specify a custom template using the `amp_post_template_file` filter for `'style' === $type`.
144
 
145
- See the "Override" examples in the "Meta" section for examples.
146
 
147
  #### Head and Footer
148
 
@@ -199,6 +296,12 @@ do_action( 'amp_post_template_head', $this );
199
  do_action( 'amp_post_template_footer', $this );
200
  ```
201
 
 
 
 
 
 
 
202
  * You must include [all required mark-up](https://www.ampproject.org/docs/get_started/create/basic_markup.html) that isn't already output via the `amp_post_template_head` action.
203
 
204
  ## Handling Media
@@ -358,3 +461,32 @@ function xyz_amp_add_ad_sanitizer( $sanitizer_classes, $post ) {
358
  return $sanitizer_classes;
359
  }
360
  ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  ## Overview
4
 
5
+ This plugin adds support for the [Accelerated Mobile Pages](https://www.ampproject.org) (AMP) Project, which is an 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
 
9
+ Note #1: that Pages and archives are not currently supported.
10
+
11
+ 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).
12
 
13
  ## Customization / Templating
14
 
16
 
17
  You can tweak small pieces of the template or the entire thing depending on your needs.
18
 
19
+ ### Where Do I Put My Code?
20
+
21
+ The code snippets below and any other code-level customizations should happen in one of the following locations.
22
+
23
+ If you're using an off-the-shelf theme (like from the WordPress.org Theme Directory):
24
+
25
+ - A [child theme](https://developer.wordpress.org/themes/advanced-topics/child-themes/).
26
+ - A custom plugin that you activate via the Dashboard.
27
+ - A [mu-plugin](https://codex.wordpress.org/Must_Use_Plugins).
28
 
29
+ If you're using a custom theme:
30
+
31
+ - `functions.php` (or a file `require`-ed by `functions.php`).
32
+ - Any of the options above.
33
+
34
+ ### Theme Mods
35
 
36
  The default template will attempt to draw from various theme mods, such as site icon and background and header color/image, if supported by the active theme.
37
 
38
+ #### Site Icon
39
+
40
+ If you add a site icon, we will automatically replace the WordPress logo in the template.
41
+
42
+ If you'd prefer to do it via code:
43
+
44
+ ```php
45
+ add_filter( 'amp_post_template_data', 'xyz_amp_set_site_icon_url' );
46
+
47
+ function xyz_amp_set_site_icon_url( $data ) {
48
+ // Ideally a 32x32 image
49
+ $data[ 'site_icon_url' ] = get_stylesheet_directory_uri() . '/images/amp-site-icon.png';
50
+ return $data;
51
+ }
52
+ ```
53
+
54
+ #### Custom Header
55
+
56
+ This needs to be implemented.
57
+
58
  ### Template Tweaks
59
 
60
  You can tweak various parts of the template via code.
61
 
62
+ #### Featured Image
63
+
64
+ The default template does not display the featured image currently. There are many ways to add it, such as the snippet below:
65
+
66
+ ```php
67
+ add_action( 'pre_amp_render_post', 'xyz_amp_add_custom_actions' );
68
+ function xyz_amp_add_custom_actions() {
69
+ add_filter( 'the_content', 'xyz_amp_add_featured_image' );
70
+ }
71
+
72
+ function xyz_amp_add_featured_image( $content ) {
73
+ if ( has_post_thumbnail() ) {
74
+ // Just add the raw <img /> tag; our sanitizer will take care of it later.
75
+ $image = sprintf( '<p class="xyz-featured-image">%s</p>', get_the_post_thumbnail() );
76
+ $content = $image . $content;
77
+ }
78
+ return $content;
79
+ }
80
+ ```
81
+
82
  #### Content Width
83
 
84
  By default, your theme's `$content_width` value will be used to determine the size of the `amp` content well. You can change this:
106
 
107
  Note: The path must pass the default criteria set out by [`validate_file`](https://developer.wordpress.org/reference/functions/validate_file/) and must be somewhere in a subfolder of `WP_CONTENT_DIR`.
108
 
109
+ #### Schema.org (JSON) Metadata
110
+
111
+ The plugin adds some default metadata to enable ["Rich Snippet" support](https://developers.google.com/structured-data/rich-snippets/articles). You can modify this using the `amp_post_template_metadata` filter. The following changes the type annotation to `NewsArticle` (from the default `BlogPosting`) and overrides the default Publisher Logo.
112
+
113
+ ```
114
+ add_filter( 'amp_post_template_metadata', 'xyz_amp_modify_json_metadata', 10, 2 );
115
+
116
+ function xyz_amp_modify_json_metadata( $metadata, $post ) {
117
+ $metadata['@type'] = 'NewsArticle';
118
+
119
+ $metadata['publisher']['logo'] = array(
120
+ '@type' => 'ImageObject',
121
+ 'url' => get_template_directory_uri() . '/images/my-amp-metadata-logo.png',
122
+ 'height' => 60,
123
+ 'width' => 600,
124
+ );
125
+ return $metadata;
126
+ }
127
+ ```
128
+
129
+ #### Template Meta (Author, Date, etc.)
130
 
131
  For the meta section of the template (i.e. author, date, taxonomies, etc.), you can override templates for the existing sections, remove them, add new ones.
132
 
212
 
213
  #### Custom CSS
214
 
215
+ ##### Rule Additions
216
+
217
+ If you want to append to the existing CSS rules (e.g. styles for a custom embed handler), you can use the `amp_post_template_css` action:
218
+
219
+ ```php
220
+ add_action( 'amp_post_template_css', 'xyz_amp_my_additional_css_styles' );
221
+
222
+ function xyz_amp_my_additional_css_styles( $amp_template ) {
223
+ // only CSS here please...
224
+ ?>
225
+ .byline amp-img {
226
+ border-radius: 0; /* we don't want round avatars! */
227
+ }
228
+ .my-custom-class {
229
+ color: blue;
230
+ }
231
+ <?php
232
+ }
233
+ ```
234
+
235
+ ##### Completely Override CSS
236
+
237
  If you'd prefer to use your own styles, you can either:
238
 
239
  - Create a folder in your theme called `amp` and add a file called `style.php` with your custom CSS.
240
+ - Specify a custom template using the `amp_post_template_file` filter for `'style' === $type`. See the "Override" examples in the "Meta" section for examples.
241
 
242
+ Note: the file should only include CSS, not the `<style>` opening and closing tag.
243
 
244
  #### Head and Footer
245
 
296
  do_action( 'amp_post_template_footer', $this );
297
  ```
298
 
299
+ * Within your `amp-custom` `style` tags, you must trigger the `amp_post_template_css` action:
300
+
301
+ ```php
302
+ do_action( 'amp_post_template_css', $this );
303
+ ```
304
+
305
  * You must include [all required mark-up](https://www.ampproject.org/docs/get_started/create/basic_markup.html) that isn't already output via the `amp_post_template_head` action.
306
 
307
  ## Handling Media
461
  return $sanitizer_classes;
462
  }
463
  ```
464
+
465
+ ## Custom Post Type Support
466
+
467
+ By default, the plugin only creates AMP content for posts. You can add support for other post_types like so (assume our post_type slug is `xyz-review`):
468
+
469
+ ```php
470
+ add_action( 'amp_init', 'xyz_amp_add_review_cpt' );
471
+ function xyz_amp_add_review_cpt() {
472
+ add_post_type_support( 'xyz-review', AMP_QUERY_VAR );
473
+ }
474
+ ```
475
+
476
+ You'll need to flush your rewrite rules after this.
477
+
478
+ If you want a custom template for your post type:
479
+
480
+ ```
481
+ add_filter( 'amp_post_template_file', 'xyz_amp_set_review_template', 10, 3 );
482
+
483
+ function xyz_amp_set_custom_template( $file, $type, $post ) {
484
+ if ( 'single' === $type && 'xyz-review' === $post->post_type ) {
485
+ $file = dirname( __FILE__ ) . '/templates/my-amp-review-template.php';
486
+ }
487
+ return $file;
488
+ }
489
+
490
+ ```
491
+
492
+ We may provide better ways to handle this in the future.
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: batmoo, joen, automattic
3
  Tags: amp, mobile
4
  Requires at least: 4.4
5
  Tested up to: 4.4
6
- Stable tag: 0.2
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -13,9 +13,11 @@ Enable Accelerated Mobile Pages (AMP) on your WordPress site.
13
 
14
  This plugin adds support for the [Accelerated Mobile Pages](https://www.ampproject.org) (AMP) Project, which is an an open source initiative that aims to provide mobile optimized content that can load instantly everywhere.
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 permalinks. (If you do not have pretty permalinks enabled, you can do the same thing by appending `?amp=1`.)
17
 
18
- Note that Pages and archives are not currently supported.
 
 
19
 
20
  Follow along with or contribute to the development of this plugin at https://github.com/Automattic/amp-wp
21
 
@@ -32,6 +34,17 @@ You can find details about customization options at https://github.com/Automatti
32
 
33
  == Changelog ==
34
 
 
 
 
 
 
 
 
 
 
 
 
35
  = 0.2 (Jan 28, 2016) =
36
 
37
  * Lots and lots and lots of compatibility and validation fixes
3
  Tags: amp, mobile
4
  Requires at least: 4.4
5
  Tested up to: 4.4
6
+ Stable tag: 0.3
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
13
 
14
  This plugin adds support for the [Accelerated Mobile Pages](https://www.ampproject.org) (AMP) Project, which is an an open source initiative that aims to provide mobile optimized content that can load instantly everywhere.
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
 
22
  Follow along with or contribute to the development of this plugin at https://github.com/Automattic/amp-wp
23
 
34
 
35
  == Changelog ==
36
 
37
+ = 0.3 (Feb 18, 2016) =
38
+
39
+ * Fetch dimensions for hotlinked images.
40
+ * Add amp-facebook support.
41
+ * Add some new actions and filters (e.g. `amp_init`).
42
+ * Fix validation errors for [gallery] shortcodes.
43
+ * Fix issues with path validation on Windows.
44
+ * Fix issues with really squeezed layout.
45
+ * Breaking change: `style.css` no longer contains the `<style> tag. If you have a custom stylesheet, you need to update it to remove the tag.
46
+ * Breaking change: `single.php` no longer includes the AMP boilerplate styles. They are instead added via the `amp_post_template_head` hook. If you have a custom template, please remove the boilerplate styles.
47
+
48
  = 0.2 (Jan 28, 2016) =
49
 
50
  * Lots and lots and lots of compatibility and validation fixes
templates/meta-author.php CHANGED
@@ -1,7 +1,9 @@
1
  <?php $post_author = $this->get( 'post_author' ); ?>
2
  <li class="byline">
 
3
  <amp-img src="<?php echo esc_url( get_avatar_url( $post_author->user_email, array(
4
  'size' => 24,
5
  ) ) ); ?>" width="24" height="24" layout="fixed"></amp-img>
 
6
  <span class="author"><?php echo esc_html( $post_author->display_name ); ?></span>
7
  </li>
1
  <?php $post_author = $this->get( 'post_author' ); ?>
2
  <li class="byline">
3
+ <?php if ( function_exists( 'get_avatar_url' ) ) : ?>
4
  <amp-img src="<?php echo esc_url( get_avatar_url( $post_author->user_email, array(
5
  'size' => 24,
6
  ) ) ); ?>" width="24" height="24" layout="fixed"></amp-img>
7
+ <?php endif; ?>
8
  <span class="author"><?php echo esc_html( $post_author->display_name ); ?></span>
9
  </li>
templates/single.php CHANGED
@@ -5,8 +5,11 @@
5
  <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,minimal-ui">
6
  <link href="https://fonts.googleapis.com/css?family=Merriweather:400,400italic,700,700italic|Open+Sans:400,700,400italic,700italic" rel="stylesheet" type="text/css">
7
  <?php do_action( 'amp_post_template_head', $this ); ?>
8
- <style>body {opacity: 0}</style><noscript><style>body {opacity: 1}</style></noscript>
 
9
  <?php $this->load_parts( array( 'style' ) ); ?>
 
 
10
  </head>
11
  <body>
12
  <nav class="title-bar">
@@ -15,10 +18,6 @@
15
  <?php $site_icon_url = $this->get( 'site_icon_url' ); ?>
16
  <?php if ( $site_icon_url ) : ?>
17
  <amp-img src="<?php echo esc_url( $site_icon_url ); ?>" width="32" height="32" class="site-icon"></amp-img>
18
- <?php else : ?>
19
- <svg x="0px" y="0px" width="24" height="24" viewBox="0 0 24 24">
20
- <path class="st0" d="M12,0C5.4,0,0,5.4,0,12c0,6.6,5.4,12,12,12c6.6,0,12-5.4,12-12C24,5.4,18.6,0,12,0z M1.2,12c0-1.6,0.3-3,0.9-4.4l5.1,14.1C3.7,20,1.2,16.3,1.2,12z M12,22.8c-1.1,0-2.1-0.2-3-0.4l3.2-9.4l3.3,9.1c0,0.1,0,0.1,0.1,0.1C14.5,22.6,13.3,22.8,12,22.8z M13.5,6.9c0.6,0,1.2-0.1,1.2-0.1c0.6-0.1,0.5-0.9-0.1-0.9c0,0-1.7,0.1-2.9,0.1c-1.1,0-2.8-0.1-2.8-0.1c-0.6,0-0.7,0.9-0.1,0.9c0,0,0.6,0.1,1.1,0.1l1.7,4.6l-2.4,7.1L5.4,6.9c0.7,0,1.2-0.1,1.2-0.1c0.6-0.1,0.5-0.9-0.1-0.9c0,0-1.7,0.1-2.9,0.1c-0.2,0-0.4,0-0.7,0c1.9-2.9,5.2-4.9,9-4.9c2.8,0,5.4,1.1,7.3,2.8c0,0-0.1,0-0.1,0c-1.1,0-1.8,0.9-1.8,1.9c0,0.9,0.5,1.6,1.1,2.5c0.4,0.7,0.9,1.6,0.9,3c0,0.9-0.3,2.1-0.8,3.5l-1.1,3.6L13.5,6.9z M17.4,21.3l3.3-9.5c0.6-1.5,0.8-2.8,0.8-3.9c0-0.4,0-0.8-0.1-1.1c0.8,1.5,1.3,3.3,1.3,5.2C22.8,16,20.6,19.5,17.4,21.3z"/>
21
- </svg>
22
  <?php endif; ?>
23
  <?php echo esc_html( $this->get( 'blog_name' ) ); ?>
24
  </a>
5
  <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,minimal-ui">
6
  <link href="https://fonts.googleapis.com/css?family=Merriweather:400,400italic,700,700italic|Open+Sans:400,700,400italic,700italic" rel="stylesheet" type="text/css">
7
  <?php do_action( 'amp_post_template_head', $this ); ?>
8
+
9
+ <style amp-custom>
10
  <?php $this->load_parts( array( 'style' ) ); ?>
11
+ <?php do_action( 'amp_post_template_css', $this ); ?>
12
+ </style>
13
  </head>
14
  <body>
15
  <nav class="title-bar">
18
  <?php $site_icon_url = $this->get( 'site_icon_url' ); ?>
19
  <?php if ( $site_icon_url ) : ?>
20
  <amp-img src="<?php echo esc_url( $site_icon_url ); ?>" width="32" height="32" class="site-icon"></amp-img>
 
 
 
 
21
  <?php endif; ?>
22
  <?php echo esc_html( $this->get( 'blog_name' ) ); ?>
23
  </a>
templates/style.php CHANGED
@@ -1,4 +1,3 @@
1
- <style amp-custom>
2
  /* Generic WP styling */
3
  amp-img.alignright { float: right; margin: 0 0 1em 1em; }
4
  amp-img.alignleft { float: left; margin: 0 1em 1em 0; }
@@ -17,8 +16,11 @@ amp-img.aligncenter { display: block; margin-left: auto; margin-right: auto; }
17
 
18
  /* Generic WP.com reader style */
19
  .content, .title-bar div {
20
- max-width: <?php echo sprintf( '%dpx', absint( $this->get( 'content_max_width' ) ) ); ?>;
 
 
21
  margin: 0 auto;
 
22
  }
23
 
24
  body {
@@ -151,13 +153,6 @@ nav.title-bar .site-icon {
151
  border-radius: 50%;
152
  }
153
 
154
- nav.title-bar svg {
155
- /** svg is 24px **/
156
- fill: #fff;
157
- float: left;
158
- margin: 15px 8px 0 0;
159
- }
160
-
161
 
162
  /* Captions */
163
  .wp-caption-text {
@@ -196,4 +191,3 @@ amp-vine {
196
  background-size: 48px 48px;
197
  min-height: 48px;
198
  }
199
- </style>
 
1
  /* Generic WP styling */
2
  amp-img.alignright { float: right; margin: 0 0 1em 1em; }
3
  amp-img.alignleft { float: left; margin: 0 1em 1em 0; }
16
 
17
  /* Generic WP.com reader style */
18
  .content, .title-bar div {
19
+ <?php $content_max_width = absint( $this->get( 'content_max_width' ) ); ?>
20
+ <?php if ( $content_max_width > 0 ) : ?>
21
+ max-width: <?php echo sprintf( '%dpx', $content_max_width ); ?>;
22
  margin: 0 auto;
23
+ <?php endif; ?>
24
  }
25
 
26
  body {
153
  border-radius: 50%;
154
  }
155
 
 
 
 
 
 
 
 
156
 
157
  /* Captions */
158
  .wp-caption-text {
191
  background-size: 48px 48px;
192
  min-height: 48px;
193
  }
 
wpcom-helper.php CHANGED
@@ -2,34 +2,25 @@
2
 
3
  // WPCOM-specific things
4
 
5
- define( 'AMP_DEV_MODE', defined( 'WPCOM_SANDBOXED' ) && WPCOM_SANDBOXED );
6
-
7
  // Add stats pixel
8
- add_filter( 'amp_post_content', function( $content, $post ) {
9
- $urls = array(
10
- wpcom_amp_get_pageview_url(),
11
- wpcom_amp_get_mc_url(),
12
- wpcom_amp_get_stats_extras_url(),
13
- );
14
-
15
- foreach ( $urls as $url ) {
16
- if ( ! $url ) {
17
- continue;
18
- }
19
- $content .= sprintf( '<amp-pixel src="%s">', esc_url( $url ) );
20
- }
21
-
22
- return $content;
23
- }, 10, 2 );
24
 
25
  function wpcom_amp_get_pageview_url() {
26
  $stats_info = stats_collect_info();
27
  $a = $stats_info['st_go_args'];
28
 
29
  $url = add_query_arg( array(
30
- 'rand' => '$RANDOM', // special amp placeholder
31
  'host' => rawurlencode( $_SERVER['HTTP_HOST'] ),
32
- // TODO: ref; not reliably accessible server-side; flag as amp?
33
  ), 'https://pixel.wp.com/b.gif' );
34
  $url .= '&' . stats_array_string( $a );
35
  return $url;
@@ -37,7 +28,7 @@ function wpcom_amp_get_pageview_url() {
37
 
38
  function wpcom_amp_get_mc_url() {
39
  return add_query_arg( array(
40
- 'rand' => '$RANDOM', // special amp placeholder
41
  'v' => 'wpcom-no-pv',
42
  'x_amp-views' => 'view',
43
  ), 'https://pixel.wp.com/b.gif' );
@@ -50,7 +41,7 @@ function wpcom_amp_get_stats_extras_url() {
50
  }
51
 
52
  $url = add_query_arg( array(
53
- 'rand' => '$RANDOM', // special amp placeholder
54
  'v' => 'wpcom-no-pv',
55
  ), 'https://pixel.wp.com/b.gif' );
56
 
@@ -67,29 +58,30 @@ function wpcom_amp_get_stats_extras_url() {
67
  return $url;
68
  }
69
 
70
- add_action( 'pre_amp_render', function() {
 
 
71
  add_filter( 'post_flair_disable', '__return_true', 99 );
72
  remove_filter( 'the_title', 'widont' );
73
 
74
  remove_filter( 'pre_kses', array( 'Filter_Embedded_HTML_Objects', 'filter' ), 11 );
75
  remove_filter( 'pre_kses', array( 'Filter_Embedded_HTML_Objects', 'maybe_create_links' ), 100 );
76
- } );
77
 
78
- add_action( 'post_amp_render', function() {
79
- add_filter( 'pre_kses', array( 'Filter_Embedded_HTML_Objects', 'filter' ), 11 );
80
- add_filter( 'pre_kses', array( 'Filter_Embedded_HTML_Objects', 'maybe_create_links' ), 100 );
81
- } );
82
 
83
- add_action( 'amp_head', function( $amp_post ) {
84
  if ( function_exists( 'jetpack_og_tags' ) ) {
85
  jetpack_og_tags();
86
  }
87
- } );
 
 
88
 
89
- add_filter( 'amp_post_metadata', function( $metadata, $post ) {
90
  $metadata = wpcom_amp_add_blavatar( $metadata, $post );
91
  return $metadata;
92
- }, 10, 2 );
93
 
94
  function wpcom_amp_add_blavatar( $metadata, $post ) {
95
  if ( ! function_exists( 'blavatar_domain' ) ) {
@@ -118,9 +110,20 @@ function wpcom_amp_add_blavatar( $metadata, $post ) {
118
  return $metadata;
119
  }
120
 
121
- add_action( 'amp_extract_image_dimensions', 'wpcom_amp_extract_image_dimensions', 9, 2 ); // Hook in before the default extractors
122
- function wpcom_amp_extract_image_dimensions( $dimensions, $url ) {
123
- if ( $dimensions ) {
 
 
 
 
 
 
 
 
 
 
 
124
  return $dimensions;
125
  }
126
 
@@ -140,10 +143,8 @@ function wpcom_amp_extract_image_dimensions( $dimensions, $url ) {
140
  return false;
141
  }
142
 
143
-
144
- add_action( 'amp_extract_image_dimensions', 'wpcom_amp_extract_image_dimensions_fallback', 100, 2 ); // Our last resort
145
- function wpcom_amp_extract_image_dimensions_fallback( $dimensions, $url ) {
146
- if ( $dimensions ) {
147
  return $dimensions;
148
  }
149
 
@@ -153,9 +154,9 @@ function wpcom_amp_extract_image_dimensions_fallback( $dimensions, $url ) {
153
 
154
  require_lib( 'wpcom/imagesize' );
155
  $size = wpcom_getimagesize( $url );
156
- if ( $size ) {
157
- return array( $size[0], $size[1] );
158
  }
159
 
160
- return false;
161
  }
2
 
3
  // WPCOM-specific things
4
 
 
 
5
  // Add stats pixel
6
+ add_filter( 'amp_post_template_footer', 'jetpack_amp_add_stats_pixel' );
7
+
8
+ function jetpack_amp_add_stats_pixel( $amp_template ) {
9
+ ?>
10
+ <amp-pixel src="<?php echo esc_url( wpcom_amp_get_pageview_url() ); ?>"></amp-pixel>
11
+ <amp-pixel src="<?php echo esc_url( wpcom_amp_get_mc_url() ); ?>"></amp-pixel>
12
+ <amp-pixel src="<?php echo esc_url( wpcom_amp_get_stats_extras_url() ); ?>"></amp-pixel>
13
+ <?php
14
+ }
 
 
 
 
 
 
 
15
 
16
  function wpcom_amp_get_pageview_url() {
17
  $stats_info = stats_collect_info();
18
  $a = $stats_info['st_go_args'];
19
 
20
  $url = add_query_arg( array(
21
+ 'rand' => 'RANDOM', // AMP placeholder
22
  'host' => rawurlencode( $_SERVER['HTTP_HOST'] ),
23
+ 'ref' => 'DOCUMENT_REFERRER', // AMP placeholder
24
  ), 'https://pixel.wp.com/b.gif' );
25
  $url .= '&' . stats_array_string( $a );
26
  return $url;
28
 
29
  function wpcom_amp_get_mc_url() {
30
  return add_query_arg( array(
31
+ 'rand' => 'RANDOM', // special amp placeholder
32
  'v' => 'wpcom-no-pv',
33
  'x_amp-views' => 'view',
34
  ), 'https://pixel.wp.com/b.gif' );
41
  }
42
 
43
  $url = add_query_arg( array(
44
+ 'rand' => 'RANDOM', // special amp placeholder
45
  'v' => 'wpcom-no-pv',
46
  ), 'https://pixel.wp.com/b.gif' );
47
 
58
  return $url;
59
  }
60
 
61
+ add_action( 'pre_amp_render_post', 'jetpack_amp_disable_the_content_filters' );
62
+
63
+ function jetpack_amp_disable_the_content_filters( $post_id ) {
64
  add_filter( 'post_flair_disable', '__return_true', 99 );
65
  remove_filter( 'the_title', 'widont' );
66
 
67
  remove_filter( 'pre_kses', array( 'Filter_Embedded_HTML_Objects', 'filter' ), 11 );
68
  remove_filter( 'pre_kses', array( 'Filter_Embedded_HTML_Objects', 'maybe_create_links' ), 100 );
69
+ }
70
 
71
+ add_action( 'amp_post_template_head', 'jetpack_amp_add_og_tags' );
 
 
 
72
 
73
+ function jetpack_amp_add_og_tags( $amp_template ) {
74
  if ( function_exists( 'jetpack_og_tags' ) ) {
75
  jetpack_og_tags();
76
  }
77
+ }
78
+
79
+ add_filter( 'amp_post_template_metadata', 'jetpack_amp_post_template_metadata', 10, 2 );
80
 
81
+ function jetpack_amp_post_template_metadata( $metadata, $post ) {
82
  $metadata = wpcom_amp_add_blavatar( $metadata, $post );
83
  return $metadata;
84
+ }
85
 
86
  function wpcom_amp_add_blavatar( $metadata, $post ) {
87
  if ( ! function_exists( 'blavatar_domain' ) ) {
110
  return $metadata;
111
  }
112
 
113
+ add_action( 'amp_extract_image_dimensions_callbacks_registered', 'wpcom_amp_extract_image_dimensions_add_custom_callbacks' );
114
+ function wpcom_amp_extract_image_dimensions_add_custom_callbacks() {
115
+ // If images are being served from Photon or WP.com files, try extracting the size using querystring.
116
+ add_action( 'amp_extract_image_dimensions', 'wpcom_amp_extract_image_dimensions_from_querystring', 9, 2 ); // Hook in before the default extractors
117
+
118
+ // Uses a special wpcom lib (wpcom_getimagesize) to extract dimensions as a last resort if we weren't able to figure them out.
119
+ add_action( 'amp_extract_image_dimensions', 'wpcom_amp_extract_image_dimensions_from_getimagesize', 99, 2 ); // Our last resort, so run late
120
+
121
+ // The wpcom override obviates this one, so take it out.
122
+ remove_action( 'amp_extract_image_dimensions', array( 'AMP_Image_Dimension_Extractor', 'extract_by_downloading_image' ), 100 );
123
+ }
124
+
125
+ function wpcom_amp_extract_image_dimensions_from_querystring( $dimensions, $url ) {
126
+ if ( is_array( $dimensions ) ) {
127
  return $dimensions;
128
  }
129
 
143
  return false;
144
  }
145
 
146
+ function wpcom_amp_extract_image_dimensions_from_getimagesize( $dimensions, $url ) {
147
+ if ( is_array( $dimensions ) ) {
 
 
148
  return $dimensions;
149
  }
150
 
154
 
155
  require_lib( 'wpcom/imagesize' );
156
  $size = wpcom_getimagesize( $url );
157
+ if ( ! is_array( $size ) ) {
158
+ return false;
159
  }
160
 
161
+ return array( $size[0], $size[1] );
162
  }