Glue for Yoast SEO & AMP - Version 0.3

Version Description

  • Split the plugin into several classes.
  • Added a settings page, found under SEO -> AMP
  • This new settings page has:
    • A post types settings tab;
    • A design settings tab;
    • An analytics integration tab.
  • Added sanitization functions that further clean up AMP output to make sure more pages pass validation.
  • Added a default image (settable on the design tab) to use when a post has no image. This because the image in the JSON+LD output is required by Google.
  • The plugin now automatically enables AMP GA tracking when GA by Yoast is enabled, but also allows you to add custom tracking.
Download this release

Release Info

Developer joostdevalk
Plugin Icon 128x128 Glue for Yoast SEO & AMP
Version 0.3
Comparing to
See all releases

Code changes from version 0.2 to 0.3

classes/assets/amp-admin-page.css ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ .yst_colorpicker {
2
+ clear: right;
3
+ }
classes/assets/amp-admin-page.js ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ jQuery(document).ready(function($){
2
+ $('.yst_colorpicker').wpColorPicker();
3
+ });
classes/assets/wp-seo-admin-media.js ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* global wpseoMediaL10n */
2
+ /* global ajaxurl */
3
+ /* global wp */
4
+ /* jshint -W097 */
5
+ /* jshint -W003 */
6
+ /* jshint unused:false */
7
+
8
+ // Taken and adapted from http://www.webmaster-source.com/2013/02/06/using-the-wordpress-3-5-media-uploader-in-your-plugin-or-theme/
9
+ jQuery(document).ready(
10
+ function($) {
11
+ 'use strict';
12
+ if( typeof wp.media === 'undefined' ) {
13
+ return;
14
+ }
15
+
16
+ $('.wpseo_image_upload_button').each(function(index, element) {
17
+ var wpseo_target_id = $(element).attr('id').replace(/_button$/, '');
18
+ var wpseo_custom_uploader = wp.media.frames.file_frame = wp.media({
19
+ title: wpseoMediaL10n.choose_image,
20
+ button: { text: wpseoMediaL10n.choose_image },
21
+ multiple: false
22
+ });
23
+
24
+ wpseo_custom_uploader.on( 'select', function() {
25
+ var attachment = wpseo_custom_uploader.state().get( 'selection' ).first().toJSON();
26
+ $( '#' + wpseo_target_id ).val( attachment.url );
27
+ }
28
+ );
29
+
30
+ $(element).click( function( e ) {
31
+ e.preventDefault();
32
+ wpseo_custom_uploader.open();
33
+ } );
34
+ } );
35
+ }
36
+ );
classes/class-backend.php ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package YoastSEO_AMP_Glue\Admin
4
+ * @author Joost de Valk
5
+ * @copyright 2016 Yoast BV
6
+ * @license GPL-2.0+
7
+ */
8
+
9
+ if ( ! class_exists( 'YoastSEO_AMP_Backend', false ) ) {
10
+ /**
11
+ * This class improves upon the AMP output by the default WordPress AMP plugin using Yoast SEO metadata.
12
+ */
13
+ class YoastSEO_AMP_Backend {
14
+
15
+ /**
16
+ * @var array
17
+ */
18
+ public $options;
19
+
20
+ /**
21
+ * YoastSEO_AMP_Backend constructor.
22
+ */
23
+ public function __construct() {
24
+ $this->options = YoastSEO_AMP_Options::get();
25
+
26
+ // Add subitem to menu
27
+ add_filter( 'wpseo_submenu_pages', array( $this, 'add_submenu_page' ) );
28
+
29
+ // Register AMP admin page as a Yoast SEO admin page
30
+ add_filter( 'wpseo_admin_pages', array( $this, 'add_admin_pages' ) );
31
+ }
32
+
33
+ /**
34
+ * Add submenu item
35
+ *
36
+ * @param array $sub_menu_pages
37
+ *
38
+ * @return array
39
+ */
40
+ public function add_submenu_page( $sub_menu_pages ) {
41
+
42
+ $sub_menu_pages[] = array(
43
+ 'wpseo_dashboard',
44
+ __( 'AMP', 'wordpress-seo' ),
45
+ __( 'AMP', 'wordpress-seo' ),
46
+ 'manage_options',
47
+ 'wpseo_amp',
48
+ array( $this, 'display' ),
49
+ array( array( $this, 'enqueue_admin_page' ) ),
50
+ );
51
+
52
+ return $sub_menu_pages;
53
+ }
54
+
55
+ /**
56
+ * Displays the admin page
57
+ */
58
+ public function display() {
59
+ require 'views/admin-page.php';
60
+ }
61
+
62
+ /**
63
+ * Enqueue admin page JS
64
+ */
65
+ public function enqueue_admin_page() {
66
+ wp_enqueue_style( 'yoast_amp_css', plugin_dir_url( __FILE__ ) . 'assets/amp-admin-page.css', array( 'wp-color-picker' ), false );
67
+
68
+ wp_enqueue_media(); // enqueue files needed for upload functionality
69
+ wp_enqueue_script( 'wpseo-admin-media', plugin_dir_url( __FILE__ ) . 'assets/wp-seo-admin-media.js', array(
70
+ 'jquery',
71
+ 'jquery-ui-core',
72
+ ), false, true );
73
+ wp_localize_script( 'wpseo-admin-media', 'wpseoMediaL10n', $this->localize_media_script() );
74
+
75
+ wp_enqueue_script( 'yoast_amp_js', plugin_dir_url( __FILE__ ) . 'assets/amp-admin-page.js', array(
76
+ 'jquery',
77
+ 'wp-color-picker'
78
+ ), false, true );
79
+ }
80
+
81
+ /**
82
+ * Pass some variables to js for upload module.
83
+ *
84
+ * @return array
85
+ */
86
+ public function localize_media_script() {
87
+ return array(
88
+ 'choose_image' => __( 'Use Logo', 'wordpress-seo' ),
89
+ );
90
+ }
91
+
92
+ /**
93
+ * Add admin page to admin_pages so the correct assets are loaded by WPSEO
94
+ *
95
+ * @param $admin_pages
96
+ *
97
+ * @return array
98
+ */
99
+ public function add_admin_pages( $admin_pages ) {
100
+ $admin_pages[] = 'wpseo_amp';
101
+
102
+ return $admin_pages;
103
+ }
104
+
105
+ /**
106
+ * @param string $var
107
+ * @param string $label
108
+ */
109
+ private function color_picker( $var, $label ) {
110
+ echo '<label class="checkbox" for="', $var, '">', $label, '</label>';
111
+ echo '<input type="text" name="wpseo_amp[', $var, ']"';
112
+ if ( isset( $this->options[ $var ] ) ) {
113
+ echo ' value="' . $this->options[ $var ] . '"';
114
+ }
115
+ echo ' class="yst_colorpicker" id="', $var, '"/>';
116
+ echo '<br/>';
117
+ }
118
+ }
119
+ }
classes/class-build-css.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package YoastSEO_AMP_Glue\CSS_Builder
4
+ * @author Jip Moors
5
+ * @copyright 2016 Yoast BV
6
+ * @license GPL-2.0+
7
+ */
8
+
9
+ if ( ! class_exists( 'YoastSEO_AMP_CSS_Builder', false ) ) {
10
+
11
+ class YoastSEO_AMP_CSS_Builder {
12
+
13
+ /** @var array Option to CSS lookup map */
14
+ private $items = array();
15
+
16
+ /**
17
+ * Add option to CSS map
18
+ *
19
+ * @param string $option_key Option key.
20
+ * @param string $selector CSS Selector.
21
+ * @param string $property CSS Property that will hold the value of the option.
22
+ */
23
+ public function add_option( $option_key, $selector, $property ) {
24
+ $this->items[ $option_key ] = array( 'selector' => $selector, 'property' => $property );
25
+ }
26
+
27
+ /**
28
+ * @return string Output CSS
29
+ */
30
+ public function build() {
31
+ $options = YoastSEO_AMP_Options::get();
32
+
33
+ $output = "\n";
34
+ $css = array();
35
+
36
+ $options = array_filter( $options );
37
+ $apply = array_intersect_key( $this->items, $options );
38
+
39
+ if ( is_array( $apply ) ) {
40
+ foreach ( $apply as $key => $placement ) {
41
+
42
+ if ( ! isset( $css[ $placement['selector'] ] ) ) {
43
+ $css[ $placement['selector'] ] = array();
44
+ }
45
+
46
+ $css[ $placement['selector'] ][ $placement['property'] ] = $options[ $key ];
47
+ }
48
+ }
49
+
50
+ if ( ! empty( $css ) ) {
51
+ foreach ( $css as $selector => $properties ) {
52
+
53
+ $inner = '';
54
+ foreach ( $properties as $property => $value ) {
55
+ $inner .= sprintf( "%s: %s;\n", $property, $value );
56
+ }
57
+
58
+ $output .= sprintf( "%s {\n%s}\n", $selector, $inner );
59
+ }
60
+ }
61
+
62
+ return $output;
63
+ }
64
+ }
65
+ }
classes/class-frontend.php ADDED
@@ -0,0 +1,311 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package YoastSEO_AMP_Glue\Frontend
4
+ * @author Joost de Valk
5
+ * @copyright 2016 Yoast BV
6
+ * @license GPL-2.0+
7
+ */
8
+
9
+ if ( ! class_exists( 'YoastSEO_AMP_Frontend' ) ) {
10
+ /**
11
+ * This class improves upon the AMP output by the default WordPress AMP plugin using Yoast SEO metadata.
12
+ */
13
+ class YoastSEO_AMP_Frontend {
14
+
15
+ /**
16
+ * @var WPSEO_Frontend
17
+ */
18
+ private $front;
19
+
20
+ /**
21
+ * @var array
22
+ */
23
+ private $options;
24
+
25
+ /**
26
+ * @var array
27
+ */
28
+ private $wpseo_options;
29
+
30
+ /**
31
+ * YoastSEO_AMP_Frontend constructor.
32
+ */
33
+ public function __construct() {
34
+ $this->set_options();
35
+
36
+ add_action( 'wp', array( $this, 'post_types' ) );
37
+
38
+ add_action( 'amp_post_template_css', array( $this, 'additional_css' ) );
39
+ add_action( 'amp_post_template_head', array( $this, 'extra_head' ) );
40
+ add_action( 'amp_post_template_footer', array( $this, 'extra_footer' ) );
41
+
42
+ add_filter( 'amp_post_template_data', array( $this, 'fix_amp_post_data' ) );
43
+ add_filter( 'amp_post_template_metadata', array( $this, 'fix_amp_post_metadata' ), 10, 2 );
44
+ add_filter( 'amp_post_template_analytics', array( $this, 'analytics' ) );
45
+
46
+ add_filter( 'amp_content_sanitizers', array( $this, 'add_sanitizer' ) );
47
+ }
48
+
49
+ private function set_options() {
50
+ $this->wpseo_options = WPSEO_Options::get_all();
51
+ $this->options = YoastSEO_AMP_Options::get();
52
+ }
53
+
54
+ /**
55
+ * Add our own sanitizer to the array of sanitizers
56
+ *
57
+ * @param array $sanitizers
58
+ *
59
+ * @return array
60
+ */
61
+ public function add_sanitizer( $sanitizers ) {
62
+ require_once 'class-sanitizer.php';
63
+
64
+ $sanitizers['Yoast_AMP_Blacklist_Sanitizer'] = array();
65
+
66
+ return $sanitizers;
67
+ }
68
+
69
+ /**
70
+ * If analytics tracking has been set, output it now.
71
+ *
72
+ * @param array $analytics
73
+ *
74
+ * @return array
75
+ */
76
+ public function analytics( $analytics ) {
77
+ if ( isset( $this->options['analytics-extra'] ) && ! empty( $this->options['analytics-extra'] ) ) {
78
+ return $analytics;
79
+ }
80
+
81
+ if ( ! class_exists( 'Yoast_GA_Options' ) || Yoast_GA_Options::instance()->get_tracking_code() === null ) {
82
+ return $analytics;
83
+ }
84
+ $UA = Yoast_GA_Options::instance()->get_tracking_code();
85
+
86
+ $analytics['yst-googleanalytics'] = array(
87
+ 'type' => 'googleanalytics',
88
+ 'attributes' => array(
89
+ ),
90
+ 'config_data' => array(
91
+ 'vars' => array(
92
+ 'account' => $UA
93
+ ),
94
+ 'triggers' => array(
95
+ 'trackPageview' => array(
96
+ 'on' => 'visible',
97
+ 'request' => 'pageview',
98
+ ),
99
+ ),
100
+ ),
101
+ );
102
+
103
+ return $analytics;
104
+ }
105
+
106
+ /**
107
+ * Make AMP work for all the post types we want it for
108
+ */
109
+ public function post_types() {
110
+ $post_types = get_post_types( array( 'public' => true ), 'objects' );
111
+ if ( is_array( $post_types ) && $post_types !== array() ) {
112
+ foreach ( $post_types as $pt ) {
113
+ if ( $this->options[ 'post_types-' . $pt->name . '-amp' ] === 'on' ) {
114
+ add_post_type_support( $pt->name, AMP_QUERY_VAR );
115
+ }
116
+ else {
117
+ remove_post_type_support( $pt->name, AMP_QUERY_VAR );
118
+ }
119
+ }
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Fix the basic AMP post data
125
+ *
126
+ * @param array $data
127
+ *
128
+ * @return array
129
+ */
130
+ public function fix_amp_post_data( $data ) {
131
+ $data['canonical_url'] = $this->front->canonical( false );
132
+ if ( ! empty( $this->options['amp_site_icon'] ) ) {
133
+ $data['site_icon_url'] = $this->options['amp_site_icon'];
134
+ }
135
+
136
+ // If we are loading extra analytics, we need to load the module too.
137
+ if ( ! empty( $this->options['analytics-extra'] ) ) {
138
+ $data['amp_component_scripts']['amp-analytics'] = 'https://cdn.ampproject.org/v0/amp-analytics-0.1.js';
139
+ }
140
+
141
+ return $data;
142
+ }
143
+
144
+ /**
145
+ * Fix the AMP metadata for a post
146
+ *
147
+ * @param array $metadata
148
+ * @param WP_Post $post
149
+ *
150
+ * @return array
151
+ */
152
+ public function fix_amp_post_metadata( $metadata, $post ) {
153
+ $this->front = WPSEO_Frontend::get_instance();
154
+
155
+ $this->build_organization_object( $metadata );
156
+
157
+ $desc = $this->front->metadesc( false );
158
+ if ( $desc ) {
159
+ $metadata['description'] = $desc;
160
+ }
161
+
162
+ $metadata['image'] = $this->get_image( $post );
163
+ $metadata['@type'] = $this->get_post_schema_type( $post );
164
+
165
+ return $metadata;
166
+ }
167
+
168
+ /**
169
+ * Add additional CSS to the AMP output
170
+ */
171
+ public function additional_css() {
172
+
173
+ require 'views/additional-css.php';
174
+
175
+ $css_builder = new YoastSEO_AMP_CSS_Builder();
176
+ $css_builder->add_option( 'header-color', 'nav.amp-wp-title-bar', 'background' );
177
+ $css_builder->add_option( 'headings-color', '.amp-wp-title, h2, h3, h4', 'color' );
178
+ $css_builder->add_option( 'text-color', '.amp-wp-content', 'color' );
179
+
180
+ $css_builder->add_option( 'blockquote-bg-color', '.amp-wp-content blockquote', 'background-color' );
181
+ $css_builder->add_option( 'blockquote-border-color', '.amp-wp-content blockquote', 'border-color' );
182
+ $css_builder->add_option( 'blockquote-text-color', '.amp-wp-content blockquote', 'color' );
183
+
184
+ $css_builder->add_option( 'link-color', 'a, a:active, a:visited', 'color' );
185
+ $css_builder->add_option( 'link-color-hover', 'a:hover, a:focus', 'color' );
186
+
187
+ $css_builder->add_option( 'meta-color', '.amp-wp-meta li, .amp-wp-meta li a', 'color' );
188
+
189
+ echo $css_builder->build();
190
+
191
+ echo esc_html( $this->options['extra-css'] );
192
+ }
193
+
194
+ /**
195
+ * Outputs extra code in the head, if set
196
+ */
197
+ public function extra_head() {
198
+ $options = WPSEO_Options::get_option( 'wpseo_social' );
199
+
200
+ if ( $options['twitter'] === true ) {
201
+ WPSEO_Twitter::get_instance();
202
+ }
203
+
204
+ if ( $options['opengraph'] === true ) {
205
+ $GLOBALS['wpseo_og'] = new WPSEO_OpenGraph;
206
+ }
207
+
208
+ do_action( 'wpseo_opengraph' );
209
+
210
+ echo strip_tags($this->options['extra-head'], '<link><meta>');
211
+ }
212
+
213
+ /**
214
+ * Outputs analytics code in the footer, if set
215
+ */
216
+ public function extra_footer() {
217
+ echo $this->options['analytics-extra'];
218
+ }
219
+
220
+ /**
221
+ * Builds the organization object if needed.
222
+ *
223
+ * @param array $metadata
224
+ */
225
+ private function build_organization_object( &$metadata ) {
226
+ // While it's using the blog name, it's actually outputting the company name.
227
+ if ( ! empty( $this->wpseo_options['company_name'] ) ) {
228
+ $metadata['publisher']['name'] = $this->wpseo_options['company_name'];
229
+ }
230
+
231
+ // The logo needs to be 600px wide max, 60px high max.
232
+ $logo = $this->get_image_object( $this->wpseo_options['company_logo'], array( 600, 60 ) );
233
+ if ( is_array( $logo ) ) {
234
+ $metadata['publisher']['logo'] = $logo;
235
+ }
236
+ }
237
+
238
+ /**
239
+ * Builds an image object array from an image URL
240
+ *
241
+ * @param string $image_url
242
+ * @param string|array $size Optional. Image size. Accepts any valid image size, or an array of width
243
+ * and height values in pixels (in that order). Default 'full'.
244
+ *
245
+ * @return array|false
246
+ */
247
+ private function get_image_object( $image_url, $size = 'full' ) {
248
+ if ( empty( $image_url ) ) {
249
+ return false;
250
+ }
251
+
252
+ $image_id = attachment_url_to_postid( $image_url );
253
+ $image_src = wp_get_attachment_image_src( $image_id, $size );
254
+
255
+ if ( is_array( $image_src ) ) {
256
+ return array(
257
+ '@type' => 'ImageObject',
258
+ 'url' => $image_src[0],
259
+ 'width' => $image_src[1],
260
+ 'height' => $image_src[2]
261
+ );
262
+ }
263
+
264
+ return false;
265
+ }
266
+
267
+ /**
268
+ * Retrieve the Schema.org image for the post
269
+ *
270
+ * @param WP_Post $post
271
+ *
272
+ * @return array|false
273
+ */
274
+ private function get_image( $post ) {
275
+ $image = $this->get_image_object( WPSEO_Meta::get_value( 'opengraph-image', $post->ID ) );
276
+
277
+ // Posts without an image fail validation in Google, leading to Search Console errors
278
+ if ( ! is_array( $image ) && isset( $this->options['default_image'] ) ) {
279
+ $image = $this->get_image_object( $this->options['default_image'] );
280
+ }
281
+
282
+ return $image;
283
+ }
284
+
285
+ /**
286
+ * Gets the Schema.org type for the post, based on the post type.
287
+ *
288
+ * @param WP_Post $post
289
+ *
290
+ * @return string
291
+ */
292
+ private function get_post_schema_type( $post ) {
293
+ if ( 'post' === $post->post_type ) {
294
+ $type = 'Article';
295
+ }
296
+ else {
297
+ $type = 'WebPage';
298
+ }
299
+
300
+ /**
301
+ * Filter: 'yoastseo_amp_schema_type' - Allow changing the Schema.org type for the post
302
+ *
303
+ * @api string $type The Schema.org type for the $post
304
+ * @param WP_Post $post
305
+ */
306
+ $type = apply_filters( 'yoastseo_amp_schema_type', $type, $post );
307
+
308
+ return $type;
309
+ }
310
+ }
311
+ }
classes/class-options.php ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package YoastSEO_AMP_Glue\Options
4
+ * @author Jip Moors
5
+ * @copyright 2016 Yoast BV
6
+ * @license GPL-2.0+
7
+ */
8
+
9
+ if ( ! class_exists( 'YoastSEO_AMP_Options' ) ) {
10
+
11
+ class YoastSEO_AMP_Options {
12
+
13
+ /** @var string Name of the option in the database */
14
+ private $option_name = 'wpseo_amp';
15
+
16
+ /** @var array Current options */
17
+ private $options;
18
+
19
+ /** @var array Option defaults */
20
+ private $defaults = array(
21
+ 'version' => 1,
22
+ 'amp_site_icon' => '',
23
+ 'default_image' => '',
24
+ 'header-color' => '',
25
+ 'headings-color' => '',
26
+ 'text-color' => '',
27
+ 'meta-color' => '',
28
+ 'link-color' => '',
29
+ 'link-color-hover' => '',
30
+ 'underline' => 'underline',
31
+ 'blockquote-text-color' => '',
32
+ 'blockquote-bg-color' => '',
33
+ 'blockquote-border-color' => '',
34
+ 'extra-css' => '',
35
+ 'extra-head' => '',
36
+ 'analytics-extra' => '',
37
+ );
38
+
39
+ /** @var self Class instance */
40
+ private static $instance;
41
+
42
+ private function __construct() {
43
+ // Register settings
44
+ add_action( 'admin_init', array( $this, 'register_settings' ) );
45
+ }
46
+
47
+ /**
48
+ * Register the premium settings
49
+ */
50
+ public function register_settings() {
51
+ register_setting( 'wpseo_amp_settings', $this->option_name, array( $this, 'sanitize_options' ) );
52
+ }
53
+
54
+ /**
55
+ * Sanitize options
56
+ *
57
+ * @param $options
58
+ *
59
+ * @return mixed
60
+ */
61
+ public function sanitize_options( $options ) {
62
+ $options['version'] = 1;
63
+
64
+ return $options;
65
+ }
66
+
67
+ /**
68
+ * Get the options
69
+ *
70
+ * @return array
71
+ */
72
+ public static function get() {
73
+
74
+ $me = self::get_instance();
75
+
76
+ if ( ! isset( $me->options ) ) {
77
+ $me->fetch_options();
78
+ }
79
+
80
+ return $me->options;
81
+ }
82
+
83
+ /**
84
+ * @return YoastSEO_AMP_Options
85
+ */
86
+ public static function get_instance() {
87
+ if ( ! isset( self::$instance ) ) {
88
+ self::$instance = new self();
89
+ }
90
+
91
+ return self::$instance;
92
+ }
93
+
94
+ /**
95
+ * Collect options
96
+ */
97
+ private function fetch_options() {
98
+
99
+ $saved_options = get_option( 'wpseo_amp' );
100
+
101
+ // Apply defaults.
102
+ $this->options = wp_parse_args( $saved_options, $this->defaults );
103
+
104
+ // Make sure all post types are present.
105
+ $this->update_post_type_settings();
106
+
107
+ // Save changes to database.
108
+ if ( $this->options !== $saved_options ) {
109
+ update_option( $this->option_name, $this->options );
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Get post types
115
+ */
116
+ private function update_post_type_settings() {
117
+ $post_type_names = array();
118
+ $post_types = get_post_types( array( 'public' => true ), 'objects' );
119
+
120
+ if ( is_array( $post_types ) && $post_types !== array() ) {
121
+ foreach ( $post_types as $post_type ) {
122
+ if ( ! isset( $this->options[ 'post_types-' . $post_type->name . '-amp' ] ) ) {
123
+ if ( 'post' === $post_type->name ) {
124
+ $this->options[ 'post_types-' . $post_type->name . '-amp' ] = 'on';
125
+ } else {
126
+ $this->options[ 'post_types-' . $post_type->name . '-amp' ] = 'off';
127
+ }
128
+ }
129
+
130
+ $post_type_names[] = $post_type->name;
131
+ }
132
+ }
133
+
134
+ // Remove missing post types.
135
+ foreach ( $this->options as $key => $value ) {
136
+ if ( 0 === strpos( $key, 'post_types' ) ) {
137
+ $post_type = substr( substr( $key, 11 ), 0, -4 );
138
+ if ( ! in_array( $post_type, $post_type_names ) ) {
139
+ unset ( $this->options[ $key ] );
140
+ }
141
+ }
142
+ }
143
+ }
144
+ }
145
+
146
+ }
classes/class-sanitizer.php ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! defined( 'AMP__DIR__' ) ) {
4
+ header( 'Status: 403 Forbidden' );
5
+ header( 'HTTP/1.1 403 Forbidden' );
6
+ exit();
7
+ }
8
+
9
+ require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-base-sanitizer.php' );
10
+
11
+ /**
12
+ * Strips blacklisted tags and attributes from content, on top of the ones the AMP plugin already removes.
13
+ *
14
+ * See following for blacklist:
15
+ * https://github.com/ampproject/amphtml/blob/master/spec/amp-html-format.md#html-tags
16
+ */
17
+ class Yoast_AMP_Blacklist_Sanitizer extends AMP_Base_Sanitizer {
18
+
19
+ /**
20
+ * The actual sanitization function
21
+ */
22
+ public function sanitize() {
23
+ $blacklisted_tags = $this->get_blacklisted_tags();
24
+ $body = $this->get_body_node();
25
+ $this->strip_tags( $body, $blacklisted_tags );
26
+ $this->strip_attributes_recursive( $body );
27
+ }
28
+
29
+ /**
30
+ * Passes through the DOM and removes stuff that shouldn't be there.
31
+ *
32
+ * @param DOMNode $node
33
+ */
34
+ private function strip_attributes_recursive( $node ) {
35
+ if ( $node->nodeType !== XML_ELEMENT_NODE ) {
36
+ return;
37
+ }
38
+
39
+ if ( $node->hasAttributes() ) {
40
+ $node_name = $node->nodeName;
41
+ $length = $node->attributes->length;
42
+ for ( $i = $length - 1; $i >= 0; $i -- ) {
43
+ $attribute = $node->attributes->item( $i );
44
+
45
+ switch ( $node_name ) {
46
+ case 'a':
47
+ $this->sanitize_a_attribute( $node, $attribute );
48
+ break;
49
+ case 'img':
50
+ $this->sanitize_img_attribute( $node, $attribute );
51
+ break;
52
+ case 'pre':
53
+ $this->sanitize_pre_attribute( $node, $attribute );
54
+ break;
55
+ case 'table':
56
+ $this->sanitize_table_attribute( $node, $attribute );
57
+ break;
58
+ case 'td':
59
+ case 'th':
60
+ $this->sanitize_cell_attribute( $node, $attribute );
61
+ break;
62
+ }
63
+ }
64
+ }
65
+
66
+ foreach ( $node->childNodes as $child_node ) {
67
+ $this->strip_attributes_recursive( $child_node );
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Passes through the DOM and strips forbidden tags
73
+ *
74
+ * @param DOMNode $node
75
+ * @param array $tag_names
76
+ */
77
+ private function strip_tags( $node, $tag_names ) {
78
+ foreach ( $tag_names as $tag_name ) {
79
+ $elements = $node->getElementsByTagName( $tag_name );
80
+ $length = $elements->length;
81
+ if ( 0 === $length ) {
82
+ continue;
83
+ }
84
+
85
+ for ( $i = $length - 1; $i >= 0; $i -- ) {
86
+ $element = $elements->item( $i );
87
+ $parent_node = $element->parentNode;
88
+ $parent_node->removeChild( $element );
89
+
90
+ if ( 'body' !== $parent_node->nodeName && AMP_DOM_Utils::is_node_empty( $parent_node ) ) {
91
+ $parent_node->parentNode->removeChild( $parent_node );
92
+ }
93
+ }
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Sanitizes anchor attributes
99
+ *
100
+ * @param DOMNode $node
101
+ * @param object $attribute
102
+ */
103
+ private function sanitize_a_attribute( $node, $attribute ) {
104
+ $attribute_name = strtolower( $attribute->name );
105
+
106
+ if ( 'rel' === $attribute_name ) {
107
+ if ( 'nofollow' !== $attribute->value ) {
108
+ $node->removeAttribute( $attribute_name );
109
+ }
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Sanitizes pre tag attributes
115
+ *
116
+ * @param DOMNode $node
117
+ * @param object $attribute
118
+ */
119
+ private function sanitize_pre_attribute( $node, $attribute ) {
120
+ $attribute_name = strtolower( $attribute->name );
121
+
122
+ if ( 'line' === $attribute_name ) {
123
+ $node->removeAttribute( $attribute_name );
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Sanitizes td / th tag attributes
129
+ *
130
+ * @param DOMNode $node
131
+ * @param object $attribute
132
+ */
133
+ private function sanitize_cell_attribute( $node, $attribute ) {
134
+ $attribute_name = strtolower( $attribute->name );
135
+
136
+ if ( in_array( $attribute_name, array( 'width', 'height' ) ) ) {
137
+ $node->removeAttribute( $attribute_name );
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Sanitize table tag
143
+ * attributes
144
+ *
145
+ * @param DOMNode $node
146
+ * @param object $attribute
147
+ */
148
+ private function sanitize_table_attribute( $node, $attribute ) {
149
+ $attribute_name = strtolower( $attribute->name );
150
+
151
+ if ( in_array( $attribute_name, array( 'border', 'cellspacing', 'cellpadding', 'summary' ) ) ) {
152
+ $node->removeAttribute( $attribute_name );
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Sanitize img tag attributes
158
+ *
159
+ * @param DOMNode $node
160
+ * @param object $attribute
161
+ */
162
+ private function sanitize_img_attribute( $node, $attribute ) {
163
+ $attribute_name = strtolower( $attribute->name );
164
+
165
+ if ( 'rel' === $attribute_name ) {
166
+ $node->removeAttribute( $attribute_name );
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Makes sure the following tags are removed
172
+ */
173
+ private function get_blacklisted_tags() {
174
+ return array(
175
+ 'embed',
176
+ );
177
+ }
178
+
179
+ }
classes/views/additional-css.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ td, th {
2
+ text-align: left;
3
+ }
4
+
5
+ a, a:active, a:visited {
6
+ text-decoration: <?php echo ( ( $this->options['underline'] ) ? 'none' : 'underline' ); ?>;
7
+ }
classes/views/admin-page.php ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! defined( 'WPSEO_VERSION' ) ) {
4
+ header( 'Status: 403 Forbidden' );
5
+ header( 'HTTP/1.1 403 Forbidden' );
6
+ exit();
7
+ }
8
+
9
+ $yform = Yoast_Form::get_instance();
10
+ $yform->admin_header( true, 'wpseo_amp', false, 'wpseo_amp_settings' );
11
+
12
+ // data-default-color="#0a89c0"
13
+ ?>
14
+
15
+ <h2 class="nav-tab-wrapper" id="wpseo-tabs">
16
+ <a class="nav-tab" id="posttypes-tab" href="#top#posttypes"><?php echo esc_html( __( 'Post types', 'wordpress-seo' ) ); ?></a>
17
+ <a class="nav-tab" id="design-tab" href="#top#design"><?php echo esc_html( __( 'Design', 'wordpress-seo' ) ); ?></a>
18
+ <a class="nav-tab" id="analytics-tab" href="#top#analytics"><?php echo esc_html( __( 'Analytics', 'wordpress-seo' ) ); ?></a>
19
+ </h2>
20
+
21
+ <div class="tabwrapper">
22
+
23
+ <div id="posttypes" class="wpseotab">
24
+ <h2><?php echo esc_html( __( 'Post types that have AMP support', 'wordpress-seo' ) ); ?></h2>
25
+ <p><?php echo esc_html( __( 'Generally you\'d want this to be your news post types.', 'wordpress-seo' ) ); ?><br/>
26
+ <?php echo esc_html( __( 'Post is enabled by default, feel free to enable any of them.', 'wordpress-seo' ) ); ?></p>
27
+ <?php
28
+
29
+ $post_types = apply_filters( 'wpseo_sitemaps_supported_post_types', get_post_types( array( 'public' => true ), 'objects' ) );
30
+ if ( is_array( $post_types ) && $post_types !== array() ) {
31
+ foreach ( $post_types as $pt ) {
32
+ $yform->toggle_switch(
33
+ 'post_types-' . $pt->name . '-amp',
34
+ array(
35
+ 'on' => __( 'Enabled', 'wordpress-seo' ),
36
+ 'off' => __( 'Disabled', 'wordpress-seo' )
37
+ ),
38
+ $pt->labels->name . ' (<code>' . $pt->name . '</code>)'
39
+ );
40
+ }
41
+ }
42
+
43
+ ?>
44
+ </div>
45
+
46
+ <div id="design" class="wpseotab">
47
+ <h3><?php echo esc_html( __( 'Images', 'wordpress-seo' ) ); ?></h3>
48
+
49
+ <?php
50
+ $yform->media_input( 'amp_site_icon', __( 'AMP icon', 'wordpress-seo' ) ); ?>
51
+ <p class="desc"><?php echo esc_html( __( 'Must be at least 32px &times; 32px', 'wordpress-seo' ) ); ?></p>
52
+ <br/>
53
+
54
+ <?php
55
+ $yform->media_input( 'default_image', __( 'Default image', 'wordpress-seo' ) ); ?>
56
+ <p class="desc"><?php echo esc_html( __( 'Used when a post doesn\'t have an image associated with it.', 'wordpress-seo' ) ); ?>
57
+ <br><?php echo esc_html( __( 'The image must be at least 696px wide.', 'wordpress-seo' ) ) ?></p>
58
+ <br/>
59
+
60
+ <h3><?php echo esc_html( __( 'Content colors', 'wordpress-seo' ) ); ?></h3>
61
+
62
+ <?php
63
+ $this->color_picker( 'header-color', __( 'AMP Header color', 'wordpress-seo' ) );
64
+ $this->color_picker( 'headings-color', __( 'Title color', 'wordpress-seo' ) );
65
+ $this->color_picker( 'text-color', __( 'Text color', 'wordpress-seo' ) );
66
+ $this->color_picker( 'meta-color', __( 'Post meta info color', 'wordpress-seo' ) );
67
+ ?>
68
+ <br/>
69
+
70
+ <h3><?php echo esc_html( __( 'Links', 'wordpress-seo' ) ); ?></h3>
71
+ <?php
72
+ $this->color_picker( 'link-color', __( 'Text color', 'wordpress-seo' ) );
73
+ $this->color_picker( 'link-color-hover', __( 'Hover color', 'wordpress-seo' ) );
74
+ ?>
75
+
76
+ <?php $yform->light_switch( 'underline', __( 'Underline', 'wordpress-seo' ), array(
77
+ __( 'Underline', 'wordpress-seo' ),
78
+ __( 'No underline', 'wordpress-seo' )
79
+ ) ); ?>
80
+
81
+ <br/>
82
+
83
+ <h3><?php echo esc_html( __( 'Blockquotes', 'wordpress-seo' ) ); ?></h3>
84
+ <?php
85
+ $this->color_picker( 'blockquote-text-color', __( 'Text color', 'wordpress-seo' ) );
86
+ $this->color_picker( 'blockquote-bg-color', __( 'Background color', 'wordpress-seo' ) );
87
+ $this->color_picker( 'blockquote-border-color', __( 'Border color', 'wordpress-seo' ) );
88
+ ?>
89
+ <br/>
90
+
91
+ <h3><?php echo esc_html( __( 'Extra CSS', 'wordpress-seo' ) ); ?></h3>
92
+ <?php $yform->textarea( 'extra-css', __( 'Extra CSS', 'wordpress-seo' ), array(
93
+ 'rows' => 5,
94
+ 'cols' => 100
95
+ ) ); ?>
96
+
97
+ <br/>
98
+
99
+ <h3><?php printf( esc_html( __( 'Extra code in %s', 'wordpress-seo' ) ), '<code>&lt;head&gt;</code>' ); ?></h3>
100
+ <p><?php echo sprintf( esc_html( __( 'Only %s and %s tags are allowed, other tags will be removed automatically.', 'wordpress-seo' ) ), '<code>meta</code>', '<code>link</code>' ) ?></p>
101
+ <?php $yform->textarea( 'extra-head', __( 'Extra code', 'wordpress-seo' ), array(
102
+ 'rows' => 5,
103
+ 'cols' => 100
104
+ ) ); ?>
105
+
106
+ </div>
107
+
108
+ <div id="analytics" class="wpseotab">
109
+ <h2><?php echo esc_html( __( 'AMP Analytics', 'wordpress-seo' ) ); ?></h2>
110
+
111
+ <?php
112
+ if ( class_exists( 'Yoast_GA_Options' ) ) {
113
+ echo '<p>', esc_html( __( 'Because your Google Analytics plugin by Yoast is active, your AMP pages will also be tracked.', 'wordpress-seo' ) ), '<br>';
114
+ $UA = Yoast_GA_Options::instance()->get_tracking_code();
115
+ if ( $UA === null ) {
116
+ echo esc_html( __( 'Make sure to connect your Google Analytics plugin properly.', 'wordpress-seo' ) );
117
+ } else {
118
+ echo sprintf( esc_html( __( 'Pageviews will be tracked using the following account: %s.', 'wordpress-seo' ) ), '<code>' . $UA . '</code>' );
119
+ }
120
+
121
+ echo '</p>';
122
+
123
+ echo '<p>', esc_html( __( 'Optionally you can override the default AMP tracking code with your own by putting it below:', 'wordpress-seo' ) ), '</p>';
124
+ $yform->textarea( 'analytics-extra', __( 'Analytics code', 'wordpress-seo' ), array(
125
+ 'rows' => 5,
126
+ 'cols' => 100
127
+ ) );
128
+ } else {
129
+ echo '<p>', esc_html( __( 'Optionally add a valid google analytics tracking code.', 'wordpress-seo' ) ), '</p>';
130
+ $yform->textarea( 'analytics-extra', __( 'Analytics code', 'wordpress-seo' ), array(
131
+ 'rows' => 5,
132
+ 'cols' => 100
133
+ ) );
134
+ }
135
+ ?>
136
+ </div>
137
+ </div>
138
+
139
+ <?php
140
+
141
+ $yform->admin_footer();
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: joostdevalk
3
  Tags: AMP, SEO
4
  Requires at least: 4.2
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,30 +13,7 @@ This plugin makes sure the default WordPress AMP plugin uses the proper Yoast SE
13
 
14
  This plugin makes sure the default [WordPress AMP plugin](https://wordpress.org/plugins/amp/) uses the proper [Yoast SEO](https://wordpress.org/plugins/wordpress-seo/) metadata. Without this glue plugin things like canonical might go wrong.
15
 
16
- This replaces the following values with Yoast SEO data, all in the JSON+LD data on posts:
17
-
18
- * Organization name (uses the blog name by default, now replaced by the Company name from the SEO General settings, Your info tab)
19
- * Organization logo (uses the blog icon by default, now replaced by the Company logo from the SEO General settings, Your info tab)
20
- * Post canonical (replaced by the Yoast SEO canonical, usually the same but makes sure its consistent when changed through Yoast SEO)
21
- * Post image (uses the featured image by default, replaced by the Facebook image if one is set)
22
- * Post description (added from the meta description, if set, by default the WordPress AMP plugin doesn't add one)
23
-
24
- > *Bugs? Ideas?*<br>
25
- > File them [on the GitHub repo for this plugin](https://github.com/Yoast/yoastseo-amp) please!
26
-
27
- == Frequently Asked Questions ==
28
-
29
- = How do I test whether it all works? =
30
-
31
- Use Google's [Structured Data testing tool](https://developers.google.com/structured-data/testing-tool/) and enter the AMP URL of one of your posts.
32
-
33
- = How do I change the Organization name or logo? =
34
-
35
- Go to SEO -> General -> Your Info tab.
36
-
37
- == Screenshots ==
38
-
39
- 1. Screenshot of the structured data testing tool testing an AMP page with the Yoast SEO plugin and this glue plugin.
40
 
41
  == Installation ==
42
 
@@ -46,5 +23,16 @@ Go to SEO -> General -> Your Info tab.
46
 
47
  == Changelog ==
48
 
 
 
 
 
 
 
 
 
 
 
 
49
  = 0.1 =
50
  * Initial version.
3
  Tags: AMP, SEO
4
  Requires at least: 4.2
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 makes sure the default [WordPress AMP plugin](https://wordpress.org/plugins/amp/) uses the proper [Yoast SEO](https://wordpress.org/plugins/wordpress-seo/) metadata. Without this glue plugin things like canonical might go wrong.
15
 
16
+ To change your company name or logo, you now have to go to the SEO settings, General tab.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  == Installation ==
19
 
23
 
24
  == Changelog ==
25
 
26
+ = 0.3 =
27
+ * Split the plugin into several classes.
28
+ * Added a settings page, found under SEO -> AMP
29
+ * This new settings page has:
30
+ * A post types settings tab;
31
+ * A design settings tab;
32
+ * An analytics integration tab.
33
+ * Added sanitization functions that further clean up AMP output to make sure more pages pass validation.
34
+ * Added a default image (settable on the design tab) to use when a post has no image. This because the image in the JSON+LD output is required by Google.
35
+ * The plugin now automatically enables AMP GA tracking when GA by Yoast is enabled, but also allows you to add custom tracking.
36
+
37
  = 0.1 =
38
  * Initial version.
yoastseo-amp.php CHANGED
@@ -9,139 +9,45 @@
9
  * Plugin Name: Glue for Yoast SEO & AMP
10
  * Plugin URI: https://yoast.com/yoast-seo-amp-glue/
11
  * Description: Makes sure the default WordPress AMP plugin uses the proper Yoast SEO metadata
12
- * Version: 0.2
13
  * Author: Joost de Valk
14
  * Author URI: https://yoast.com
15
  */
16
 
17
- /**
18
- * Defines the YoastSEO AMP class. In a wrapper function so we can overwrite this from within Yoast SEO later on.
19
- */
20
- function yoast_seo_amp_glue_define() {
21
- if ( ! class_exists( 'YoastSEO_AMP' ) ) {
 
22
  /**
23
- * This class improves upon the AMP output by the default WordPress AMP plugin using Yoast SEO metadata.
24
  */
25
- class YoastSEO_AMP {
26
-
27
- /**
28
- * @var WPSEO_Frontend
29
- */
30
- private $front;
31
-
32
- /**
33
- * @var array
34
- */
35
- private $options;
36
-
37
- /**
38
- * YoastSEO_AMP constructor.
39
- */
40
- public function __construct() {
41
- $this->front = WPSEO_Frontend::get_instance();
42
- $this->options = WPSEO_Options::get_all();
43
-
44
- add_filter( 'amp_post_template_data', array( $this, 'fix_amp_post_data' ), 10, 2 );
45
- add_filter( 'amp_post_template_metadata', array( $this, 'fix_amp_post_metadata' ), 10, 2 );
46
- }
47
-
48
- /**
49
- * Fix the basic AMP post data
50
- *
51
- * @param array $data
52
- * @param object $post
53
- *
54
- * @return array
55
- */
56
- public function fix_amp_post_data( $data, $post ) {
57
- $data['canonical_url'] = $this->front->canonical( false );
58
-
59
- return $data;
60
- }
61
 
62
- /**
63
- * Fix the AMP metadata for a post
64
- *
65
- * @param array $metadata
66
- * @param object $post
67
- *
68
- * @return array
69
- */
70
- public function fix_amp_post_metadata( $metadata, $post ) {
71
- $this->build_organization_object( $metadata );
72
 
73
- $desc = $this->front->metadesc( false );
74
- if ( $desc ) {
75
- $metadata['description'] = $desc;
76
- }
77
-
78
- $og_img = $this->get_image_object( WPSEO_Meta::get_value( 'opengraph-image', $post->ID ) );
79
- if ( is_array( $og_img ) ) {
80
- $metadata['image'] = $og_img;
81
- }
82
-
83
- return $metadata;
84
  }
85
-
86
- /**
87
- * Builds the organization object if needed.
88
- *
89
- * @param array $metadata
90
- */
91
- private function build_organization_object( &$metadata ) {
92
- // While it's using the blog name, it's actually outputting the company name
93
- if ( ! empty( $this->options['company_name'] ) ) {
94
- $metadata['publisher']['name'] = $this->options['company_name'];
95
- }
96
-
97
- // The logo needs to be 600px wide max, 60px high max
98
- $logo = $this->get_image_object( $this->options['company_logo'], array( 600, 60 ) );
99
- if ( is_array( $logo ) ) {
100
- $metadata['publisher']['logo'] = $logo;
101
- }
102
- }
103
-
104
- /**
105
- * Builds an image object array from an image URL
106
- *
107
- * @param string $image_url
108
- * @param string|array $size Optional. Image size. Accepts any valid image size, or an array of width
109
- * and height values in pixels (in that order). Default 'full'.
110
- *
111
- * @return bool|array
112
- */
113
- private function get_image_object( $image_url, $size = 'full' ) {
114
- if ( empty( $image_url ) ) {
115
- return false;
116
- }
117
-
118
- $image_id = attachment_url_to_postid( $image_url );
119
- $image_src = wp_get_attachment_image_src( $image_id, $size );
120
-
121
- if ( is_array( $image_src ) ) {
122
- return array(
123
- '@type' => 'ImageObject',
124
- 'url' => $image_src[0],
125
- 'width' => $image_src[1],
126
- 'height' => $image_src[2]
127
- );
128
- }
129
-
130
- return false;
131
  }
132
  }
 
133
  }
134
  }
135
 
136
- add_action( 'plugins_loaded', 'yoast_seo_amp_glue_define', 99 );
137
-
138
  /**
139
  * Initialize the Yoast SEO AMP Glue plugin
140
  */
141
  function yoast_seo_amp_glue_init() {
142
- if ( class_exists( 'WPSEO_Frontend' ) ) {
143
  new YoastSEO_AMP();
144
  }
145
  }
146
 
147
- add_action( 'init', 'yoast_seo_amp_glue_init', 12 );
9
  * Plugin Name: Glue for Yoast SEO & AMP
10
  * Plugin URI: https://yoast.com/yoast-seo-amp-glue/
11
  * Description: Makes sure the default WordPress AMP plugin uses the proper Yoast SEO metadata
12
+ * Version: 0.3
13
  * Author: Joost de Valk
14
  * Author URI: https://yoast.com
15
  */
16
 
17
+ if ( ! class_exists( 'YoastSEO_AMP', false ) ) {
18
+ /**
19
+ * This class improves upon the AMP output by the default WordPress AMP plugin using Yoast SEO metadata.
20
+ */
21
+ class YoastSEO_AMP {
22
+
23
  /**
24
+ * YoastSEO_AMP constructor.
25
  */
26
+ public function __construct() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
+ require 'classes/class-options.php';
 
 
 
 
 
 
 
 
 
29
 
30
+ if ( is_admin() ) {
31
+ require 'classes/class-backend.php';
32
+ new YoastSEO_AMP_Backend();
 
 
 
 
 
 
 
 
33
  }
34
+ else {
35
+ require 'classes/class-build-css.php';
36
+ require 'classes/class-frontend.php';
37
+ new YoastSEO_AMP_Frontend();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  }
39
  }
40
+
41
  }
42
  }
43
 
 
 
44
  /**
45
  * Initialize the Yoast SEO AMP Glue plugin
46
  */
47
  function yoast_seo_amp_glue_init() {
48
+ if ( defined( 'WPSEO_FILE' ) && defined( 'AMP__FILE__' ) ) {
49
  new YoastSEO_AMP();
50
  }
51
  }
52
 
53
+ add_action( 'init', 'yoast_seo_amp_glue_init', 9 );