Version Description
(2017-08-04) =
- Whitelist Sanitizer: Replace Blacklist Sanitizer with a whitelist-based approach using the AMP spec (props delputnam)
- Image Dimensions: Replace fastimage with fasterimage for PHP 5.4+. Enables faster downloads and wider support (props gititon)
- Embed Handlers: Added support for Vimeo, SoundCloud, Pinterest (props amedina) and PlayBuzz (props lysk88)
- Analytics: UI for easier addition of analytics tags (props amedina)
- Fix: parse query strings properly (props amyevans)
- Fix: Old slug redirect for AMP URLs (props rahulsprajapati)
- Fix: Handle issues with data uri images in CSS (props trepmal)
- Fix: Add amp-video js for amp-video tags (props ptbello)
- Fix: Output CSS for feature image (props mjangda)
- Fix: Fix attribute when adding AMP Mustache lib (props luigitec)
- Fix: Various documentation updates (props piersb, bhhaskin)
- Fix: PHP Warnings from
register_customizer_ui
(props jahvi) - Fix: Coding Standards (props paulschreiber)
Download this release
Release Info
Developer | batmoo |
Plugin | ![]() |
Version | 0.5 |
Comparing to | |
See all releases |
Code changes from version 0.4.2 to 0.5
- amp.php +34 -4
- assets/images/placeholder-icon.png +0 -0
- includes/admin/class-amp-customizer.php +3 -3
- includes/admin/functions.php +59 -19
- includes/amp-helper-functions.php +8 -3
- includes/amp-post-template-actions.php +20 -17
- includes/amp-post-template-functions.php +1 -1
- includes/class-amp-content.php +3 -3
- includes/class-amp-post-template.php +22 -7
- includes/embeds/class-amp-dailymotion-embed.php +103 -0
- includes/embeds/class-amp-gallery-embed.php +1 -1
- includes/embeds/class-amp-instagram-embed.php +1 -1
- includes/embeds/class-amp-pinterest-embed.php +60 -0
- includes/embeds/class-amp-soundcloud-embed.php +95 -0
- includes/embeds/class-amp-vimeo-embed.php +114 -0
- includes/embeds/class-amp-vine-embed.php +1 -1
- includes/embeds/class-amp-youtube-embed.php +3 -3
- includes/lib/class-fastimage.php +0 -253
- includes/lib/fasterimage/Exception/InvalidImageException.php +8 -0
- includes/lib/fasterimage/ExifParser.php +134 -0
- includes/lib/fasterimage/FasterImage.php +187 -0
- includes/lib/fasterimage/ImageParser.php +377 -0
- includes/lib/fasterimage/Stream/Exception/StreamBufferTooSmallException.php +8 -0
- includes/lib/fasterimage/Stream/Stream.php +78 -0
- includes/lib/fasterimage/Stream/StreamableInterface.php +39 -0
- includes/lib/fasterimage/amp-fasterimage.php +25 -0
- includes/lib/fastimage/class-fastimage.php +201 -0
- includes/options/class-amp-analytics-options-submenu.php +53 -0
- includes/options/class-amp-options-menu.php +54 -0
- includes/options/views/class-amp-analytics-options-submenu-page.php +101 -0
- includes/options/views/class-amp-options-manager.php +84 -0
- includes/options/views/class-amp-options-menu-page.php +17 -0
- includes/sanitizers/class-amp-allowed-tags-generated.php +6210 -0
- includes/sanitizers/class-amp-base-sanitizer.php +2 -2
- includes/sanitizers/class-amp-blacklist-sanitizer.php +12 -14
- includes/sanitizers/class-amp-iframe-sanitizer.php +2 -3
- includes/sanitizers/class-amp-img-sanitizer.php +68 -27
- includes/sanitizers/class-amp-playbuzz-sanitizer.php +104 -0
- includes/sanitizers/class-amp-style-sanitizer.php +6 -3
- includes/sanitizers/class-amp-tag-and-attribute-sanitizer.php +978 -0
- includes/sanitizers/class-amp-video-sanitizer.php +13 -0
- includes/settings/class-amp-customizer-design-settings.php +9 -9
- includes/utils/class-amp-dom-utils.php +19 -2
- includes/utils/class-amp-html-utils.php +12 -0
- includes/utils/class-amp-image-dimension-extractor.php +173 -53
- includes/utils/class-amp-string-utils.php +1 -1
- includes/utils/class-amp-wp-utils.php +61 -0
- jetpack-helper.php +2 -2
- readme-assets/amp-options-analytics.png +0 -0
- readme-assets/analytics-option-entries.png +0 -0
- readme-assets/invalid-input.png +0 -0
- readme-assets/options-saved.png +0 -0
- readme.md +118 -25
- readme.txt +21 -5
- templates/footer.php +2 -2
- templates/header-bar.php +1 -1
- templates/meta-author.php +1 -2
- templates/style.php +1 -1
amp.php
CHANGED
@@ -5,7 +5,7 @@
|
|
5 |
* Plugin URI: https://github.com/automattic/amp-wp
|
6 |
* Author: Automattic
|
7 |
* Author URI: https://automattic.com
|
8 |
-
* Version: 0.
|
9 |
* Text Domain: amp
|
10 |
* Domain Path: /languages/
|
11 |
* License: GPLv2 or later
|
@@ -13,7 +13,7 @@
|
|
13 |
|
14 |
define( 'AMP__FILE__', __FILE__ );
|
15 |
define( 'AMP__DIR__', dirname( __FILE__ ) );
|
16 |
-
define( 'AMP__VERSION', '0.
|
17 |
|
18 |
require_once( AMP__DIR__ . '/back-compat/back-compat.php' );
|
19 |
require_once( AMP__DIR__ . '/includes/amp-helper-functions.php' );
|
@@ -61,6 +61,9 @@ function amp_init() {
|
|
61 |
add_filter( 'request', 'amp_force_query_var_value' );
|
62 |
add_action( 'wp', 'amp_maybe_add_actions' );
|
63 |
|
|
|
|
|
|
|
64 |
if ( class_exists( 'Jetpack' ) && ! ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) {
|
65 |
require_once( AMP__DIR__ . '/jetpack-helper.php' );
|
66 |
}
|
@@ -114,6 +117,7 @@ function amp_add_frontend_actions() {
|
|
114 |
function amp_add_post_template_actions() {
|
115 |
require_once( AMP__DIR__ . '/includes/amp-post-template-actions.php' );
|
116 |
require_once( AMP__DIR__ . '/includes/amp-post-template-functions.php' );
|
|
|
117 |
}
|
118 |
|
119 |
function amp_prepare_render() {
|
@@ -121,15 +125,24 @@ function amp_prepare_render() {
|
|
121 |
}
|
122 |
|
123 |
function amp_render() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
amp_load_classes();
|
125 |
|
126 |
-
$post_id = get_queried_object_id();
|
127 |
do_action( 'pre_amp_render_post', $post_id );
|
128 |
|
129 |
amp_add_post_template_actions();
|
130 |
$template = new AMP_Post_Template( $post_id );
|
131 |
$template->load();
|
132 |
-
exit;
|
133 |
}
|
134 |
|
135 |
/**
|
@@ -157,3 +170,20 @@ function _amp_bootstrap_customizer() {
|
|
157 |
}
|
158 |
}
|
159 |
add_action( 'plugins_loaded', '_amp_bootstrap_customizer', 9 );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
* Plugin URI: https://github.com/automattic/amp-wp
|
6 |
* Author: Automattic
|
7 |
* Author URI: https://automattic.com
|
8 |
+
* Version: 0.5
|
9 |
* Text Domain: amp
|
10 |
* Domain Path: /languages/
|
11 |
* License: GPLv2 or later
|
13 |
|
14 |
define( 'AMP__FILE__', __FILE__ );
|
15 |
define( 'AMP__DIR__', dirname( __FILE__ ) );
|
16 |
+
define( 'AMP__VERSION', '0.5' );
|
17 |
|
18 |
require_once( AMP__DIR__ . '/back-compat/back-compat.php' );
|
19 |
require_once( AMP__DIR__ . '/includes/amp-helper-functions.php' );
|
61 |
add_filter( 'request', 'amp_force_query_var_value' );
|
62 |
add_action( 'wp', 'amp_maybe_add_actions' );
|
63 |
|
64 |
+
// Redirect the old url of amp page to the updated url.
|
65 |
+
add_filter( 'old_slug_redirect_url', 'amp_redirect_old_slug_to_new_url' );
|
66 |
+
|
67 |
if ( class_exists( 'Jetpack' ) && ! ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) {
|
68 |
require_once( AMP__DIR__ . '/jetpack-helper.php' );
|
69 |
}
|
117 |
function amp_add_post_template_actions() {
|
118 |
require_once( AMP__DIR__ . '/includes/amp-post-template-actions.php' );
|
119 |
require_once( AMP__DIR__ . '/includes/amp-post-template-functions.php' );
|
120 |
+
amp_post_template_init_hooks();
|
121 |
}
|
122 |
|
123 |
function amp_prepare_render() {
|
125 |
}
|
126 |
|
127 |
function amp_render() {
|
128 |
+
$post_id = get_queried_object_id();
|
129 |
+
amp_render_post( $post_id );
|
130 |
+
exit;
|
131 |
+
}
|
132 |
+
|
133 |
+
function amp_render_post( $post_id ) {
|
134 |
+
$post = get_post( $post_id );
|
135 |
+
if ( ! $post ) {
|
136 |
+
return;
|
137 |
+
}
|
138 |
+
|
139 |
amp_load_classes();
|
140 |
|
|
|
141 |
do_action( 'pre_amp_render_post', $post_id );
|
142 |
|
143 |
amp_add_post_template_actions();
|
144 |
$template = new AMP_Post_Template( $post_id );
|
145 |
$template->load();
|
|
|
146 |
}
|
147 |
|
148 |
/**
|
170 |
}
|
171 |
}
|
172 |
add_action( 'plugins_loaded', '_amp_bootstrap_customizer', 9 );
|
173 |
+
|
174 |
+
/**
|
175 |
+
* Redirects the old AMP URL to the new AMP URL.
|
176 |
+
* If post slug is updated the amp page with old post slug will be redirected to the updated url.
|
177 |
+
*
|
178 |
+
* @param string $link New URL of the post.
|
179 |
+
*
|
180 |
+
* @return string $link URL to be redirected.
|
181 |
+
*/
|
182 |
+
function amp_redirect_old_slug_to_new_url( $link ) {
|
183 |
+
|
184 |
+
if ( is_amp_endpoint() ) {
|
185 |
+
$link = trailingslashit( trailingslashit( $link ) . AMP_QUERY_VAR );
|
186 |
+
}
|
187 |
+
|
188 |
+
return $link;
|
189 |
+
}
|
assets/images/placeholder-icon.png
CHANGED
Binary file
|
includes/admin/class-amp-customizer.php
CHANGED
@@ -46,7 +46,7 @@ class AMP_Template_Customizer {
|
|
46 |
|
47 |
// Our custom panels only need to go for AMP Customizer requests though
|
48 |
if ( self::is_amp_customizer() ) {
|
49 |
-
if ( empty( $_GET['url'] ) ) {
|
50 |
$wp_customize->set_preview_url( amp_admin_get_preview_permalink() );
|
51 |
}
|
52 |
|
@@ -156,7 +156,7 @@ class AMP_Template_Customizer {
|
|
156 |
}
|
157 |
|
158 |
public function force_mobile_preview( $devices ) {
|
159 |
-
if ( isset( $devices
|
160 |
$devices['mobile']['default'] = true;
|
161 |
unset( $devices['desktop']['default'] );
|
162 |
}
|
@@ -165,6 +165,6 @@ class AMP_Template_Customizer {
|
|
165 |
}
|
166 |
|
167 |
public static function is_amp_customizer() {
|
168 |
-
return ! empty( $_REQUEST[ AMP_CUSTOMIZER_QUERY_VAR ] );
|
169 |
}
|
170 |
}
|
46 |
|
47 |
// Our custom panels only need to go for AMP Customizer requests though
|
48 |
if ( self::is_amp_customizer() ) {
|
49 |
+
if ( empty( $_GET['url'] ) ) { // input var ok
|
50 |
$wp_customize->set_preview_url( amp_admin_get_preview_permalink() );
|
51 |
}
|
52 |
|
156 |
}
|
157 |
|
158 |
public function force_mobile_preview( $devices ) {
|
159 |
+
if ( isset( $devices['mobile'] ) ) {
|
160 |
$devices['mobile']['default'] = true;
|
161 |
unset( $devices['desktop']['default'] );
|
162 |
}
|
165 |
}
|
166 |
|
167 |
public static function is_amp_customizer() {
|
168 |
+
return ! empty( $_REQUEST[ AMP_CUSTOMIZER_QUERY_VAR ] ); // input var ok
|
169 |
}
|
170 |
}
|
includes/admin/functions.php
CHANGED
@@ -1,6 +1,9 @@
|
|
1 |
<?php
|
2 |
// Callbacks for adding AMP-related things to the admin.
|
3 |
|
|
|
|
|
|
|
4 |
define( 'AMP_CUSTOMIZER_QUERY_VAR', 'customize_amp' );
|
5 |
|
6 |
/**
|
@@ -22,6 +25,34 @@ function amp_init_customizer() {
|
|
22 |
add_action( 'admin_menu', 'amp_add_customizer_link' );
|
23 |
}
|
24 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
/**
|
26 |
* Registers a submenu page to access the AMP template editor panel in the Customizer.
|
27 |
*/
|
@@ -34,7 +65,7 @@ function amp_add_customizer_link() {
|
|
34 |
), 'customize.php' );
|
35 |
|
36 |
// Add the theme page.
|
37 |
-
|
38 |
__( 'AMP', 'amp' ),
|
39 |
__( 'AMP', 'amp' ),
|
40 |
'edit_theme_options',
|
@@ -42,30 +73,39 @@ function amp_add_customizer_link() {
|
|
42 |
);
|
43 |
}
|
44 |
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
|
53 |
-
|
|
|
54 |
return;
|
55 |
}
|
56 |
|
57 |
-
$
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
'fields' => 'ids',
|
62 |
-
) );
|
63 |
|
64 |
-
|
65 |
-
|
|
|
|
|
|
|
66 |
}
|
67 |
|
68 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
|
70 |
-
return
|
71 |
}
|
|
1 |
<?php
|
2 |
// Callbacks for adding AMP-related things to the admin.
|
3 |
|
4 |
+
require_once( AMP__DIR__ . '/includes/options/class-amp-options-menu.php' );
|
5 |
+
require_once( AMP__DIR__ . '/includes/options/views/class-amp-options-manager.php' );
|
6 |
+
|
7 |
define( 'AMP_CUSTOMIZER_QUERY_VAR', 'customize_amp' );
|
8 |
|
9 |
/**
|
25 |
add_action( 'admin_menu', 'amp_add_customizer_link' );
|
26 |
}
|
27 |
|
28 |
+
function amp_admin_get_preview_permalink() {
|
29 |
+
/**
|
30 |
+
* Filter the post type to retrieve the latest for use in the AMP template customizer.
|
31 |
+
*
|
32 |
+
* @param string $post_type Post type slug. Default 'post'.
|
33 |
+
*/
|
34 |
+
$post_type = (string) apply_filters( 'amp_customizer_post_type', 'post' );
|
35 |
+
|
36 |
+
if ( ! post_type_supports( $post_type, 'amp' ) ) {
|
37 |
+
return;
|
38 |
+
}
|
39 |
+
|
40 |
+
$post_ids = get_posts( array(
|
41 |
+
'post_status' => 'publish',
|
42 |
+
'post_type' => $post_type,
|
43 |
+
'posts_per_page' => 1,
|
44 |
+
'fields' => 'ids',
|
45 |
+
) );
|
46 |
+
|
47 |
+
if ( empty( $post_ids ) ) {
|
48 |
+
return false;
|
49 |
+
}
|
50 |
+
|
51 |
+
$post_id = $post_ids[0];
|
52 |
+
|
53 |
+
return amp_get_permalink( $post_id );
|
54 |
+
}
|
55 |
+
|
56 |
/**
|
57 |
* Registers a submenu page to access the AMP template editor panel in the Customizer.
|
58 |
*/
|
65 |
), 'customize.php' );
|
66 |
|
67 |
// Add the theme page.
|
68 |
+
add_theme_page(
|
69 |
__( 'AMP', 'amp' ),
|
70 |
__( 'AMP', 'amp' ),
|
71 |
'edit_theme_options',
|
73 |
);
|
74 |
}
|
75 |
|
76 |
+
/**
|
77 |
+
* Registers a top-level menu for AMP configuration options
|
78 |
+
*/
|
79 |
+
function amp_add_options_menu() {
|
80 |
+
if ( ! is_admin() ) {
|
81 |
+
return;
|
82 |
+
}
|
83 |
|
84 |
+
$show_options_menu = apply_filters( 'amp_options_menu_is_enabled', true );
|
85 |
+
if ( true !== $show_options_menu ) {
|
86 |
return;
|
87 |
}
|
88 |
|
89 |
+
$amp_options = new AMP_Options_Menu();
|
90 |
+
$amp_options->init();
|
91 |
+
}
|
92 |
+
add_action( 'wp_loaded', 'amp_add_options_menu' );
|
|
|
|
|
93 |
|
94 |
+
function amp_add_custom_analytics( $analytics ) {
|
95 |
+
$analytics_entries = AMP_Options_Manager::get_option( 'analytics', array() );
|
96 |
+
|
97 |
+
if ( ! $analytics_entries ) {
|
98 |
+
return $analytics;
|
99 |
}
|
100 |
|
101 |
+
foreach ( $analytics_entries as $entry_id => $entry ) {
|
102 |
+
$analytics[ $entry_id ] = array(
|
103 |
+
'type' => $entry['type'],
|
104 |
+
'attributes' => array(),
|
105 |
+
'config_data' => json_decode( $entry['config'] ),
|
106 |
+
);
|
107 |
+
}
|
108 |
|
109 |
+
return $analytics;
|
110 |
}
|
111 |
+
add_filter( 'amp_post_template_analytics', 'amp_add_custom_analytics' );
|
includes/amp-helper-functions.php
CHANGED
@@ -7,10 +7,11 @@ function amp_get_permalink( $post_id ) {
|
|
7 |
return $pre_url;
|
8 |
}
|
9 |
|
10 |
-
|
11 |
-
|
12 |
-
} else {
|
13 |
$amp_url = add_query_arg( AMP_QUERY_VAR, 1, get_permalink( $post_id ) );
|
|
|
|
|
14 |
}
|
15 |
|
16 |
return apply_filters( 'amp_get_permalink', $amp_url, $post_id );
|
@@ -39,6 +40,10 @@ function post_supports_amp( $post ) {
|
|
39 |
* Note: will always return `false` if called before the `parse_query` hook.
|
40 |
*/
|
41 |
function is_amp_endpoint() {
|
|
|
|
|
|
|
|
|
42 |
return false !== get_query_var( AMP_QUERY_VAR, false );
|
43 |
}
|
44 |
|
7 |
return $pre_url;
|
8 |
}
|
9 |
|
10 |
+
$structure = get_option( 'permalink_structure' );
|
11 |
+
if ( empty( $structure ) ) {
|
|
|
12 |
$amp_url = add_query_arg( AMP_QUERY_VAR, 1, get_permalink( $post_id ) );
|
13 |
+
} else {
|
14 |
+
$amp_url = trailingslashit( get_permalink( $post_id ) ) . user_trailingslashit( AMP_QUERY_VAR, 'single_amp' );
|
15 |
}
|
16 |
|
17 |
return apply_filters( 'amp_get_permalink', $amp_url, $post_id );
|
40 |
* Note: will always return `false` if called before the `parse_query` hook.
|
41 |
*/
|
42 |
function is_amp_endpoint() {
|
43 |
+
if ( 0 === did_action( 'parse_query' ) ) {
|
44 |
+
_doing_it_wrong( __FUNCTION__, sprintf( esc_html__( "is_amp_endpoint() was called before the 'parse_query' hook was called. This function will always return 'false' before the 'parse_query' hook is called.", 'amp' ) ), '0.4.2' );
|
45 |
+
}
|
46 |
+
|
47 |
return false !== get_query_var( AMP_QUERY_VAR, false );
|
48 |
}
|
49 |
|
includes/amp-post-template-actions.php
CHANGED
@@ -1,69 +1,74 @@
|
|
1 |
<?php
|
2 |
// Callbacks for adding content to an AMP template
|
3 |
|
4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
function amp_post_template_add_title( $amp_template ) {
|
6 |
?>
|
7 |
<title><?php echo esc_html( $amp_template->get( 'document_title' ) ); ?></title>
|
8 |
<?php
|
9 |
}
|
10 |
|
11 |
-
add_action( 'amp_post_template_head', 'amp_post_template_add_canonical' );
|
12 |
function amp_post_template_add_canonical( $amp_template ) {
|
13 |
?>
|
14 |
<link rel="canonical" href="<?php echo esc_url( $amp_template->get( 'canonical_url' ) ); ?>" />
|
15 |
<?php
|
16 |
}
|
17 |
|
18 |
-
add_action( 'amp_post_template_head', 'amp_post_template_add_scripts' );
|
19 |
function amp_post_template_add_scripts( $amp_template ) {
|
20 |
$scripts = $amp_template->get( 'amp_component_scripts', array() );
|
21 |
-
foreach ( $scripts as $element => $script ) :
|
22 |
-
|
|
|
23 |
<?php endforeach; ?>
|
24 |
<script src="<?php echo esc_url( $amp_template->get( 'amp_runtime_script' ) ); ?>" async></script>
|
25 |
<?php
|
26 |
}
|
27 |
|
28 |
-
add_action( 'amp_post_template_head', 'amp_post_template_add_fonts' );
|
29 |
function amp_post_template_add_fonts( $amp_template ) {
|
30 |
$font_urls = $amp_template->get( 'font_urls', array() );
|
31 |
-
foreach( $font_urls as $slug => $url ) : ?>
|
32 |
<link rel="stylesheet" href="<?php echo esc_url( $url ); ?>">
|
33 |
<?php endforeach;
|
34 |
}
|
35 |
|
36 |
-
add_action( 'amp_post_template_head', 'amp_post_template_add_boilerplate_css' );
|
37 |
function amp_post_template_add_boilerplate_css( $amp_template ) {
|
38 |
?>
|
39 |
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
|
40 |
<?php
|
41 |
}
|
42 |
|
43 |
-
add_action( 'amp_post_template_head', 'amp_post_template_add_schemaorg_metadata' );
|
44 |
function amp_post_template_add_schemaorg_metadata( $amp_template ) {
|
45 |
$metadata = $amp_template->get( 'metadata' );
|
46 |
if ( empty( $metadata ) ) {
|
47 |
return;
|
48 |
}
|
49 |
?>
|
50 |
-
<script type="application/ld+json"><?php echo
|
51 |
<?php
|
52 |
}
|
53 |
|
54 |
-
add_action( 'amp_post_template_css', 'amp_post_template_add_styles', 99 );
|
55 |
function amp_post_template_add_styles( $amp_template ) {
|
56 |
$styles = $amp_template->get( 'post_amp_styles' );
|
57 |
if ( ! empty( $styles ) ) {
|
58 |
echo '/* Inline styles */' . PHP_EOL;
|
59 |
foreach ( $styles as $selector => $declarations ) {
|
60 |
-
$declarations = implode(
|
61 |
printf( '%1$s{%2$s}', $selector, $declarations );
|
62 |
}
|
63 |
}
|
64 |
}
|
65 |
|
66 |
-
add_action( 'amp_post_template_data', 'amp_post_template_add_analytics_script' );
|
67 |
function amp_post_template_add_analytics_script( $data ) {
|
68 |
if ( ! empty( $data['amp_analytics'] ) ) {
|
69 |
$data['amp_component_scripts']['amp-analytics'] = 'https://cdn.ampproject.org/v0/amp-analytics-0.1.js';
|
@@ -71,7 +76,6 @@ function amp_post_template_add_analytics_script( $data ) {
|
|
71 |
return $data;
|
72 |
}
|
73 |
|
74 |
-
add_action( 'amp_post_template_footer', 'amp_post_template_add_analytics_data' );
|
75 |
function amp_post_template_add_analytics_data( $amp_template ) {
|
76 |
$analytics_entries = $amp_template->get( 'amp_analytics' );
|
77 |
if ( empty( $analytics_entries ) ) {
|
@@ -80,13 +84,12 @@ function amp_post_template_add_analytics_data( $amp_template ) {
|
|
80 |
|
81 |
foreach ( $analytics_entries as $id => $analytics_entry ) {
|
82 |
if ( ! isset( $analytics_entry['type'], $analytics_entry['attributes'], $analytics_entry['config_data'] ) ) {
|
83 |
-
_doing_it_wrong( __FUNCTION__, sprintf(
|
84 |
continue;
|
85 |
}
|
86 |
-
|
87 |
$script_element = AMP_HTML_Utils::build_tag( 'script', array(
|
88 |
'type' => 'application/json',
|
89 |
-
),
|
90 |
|
91 |
$amp_analytics_attr = array_merge( array(
|
92 |
'id' => $id,
|
1 |
<?php
|
2 |
// Callbacks for adding content to an AMP template
|
3 |
|
4 |
+
function amp_post_template_init_hooks() {
|
5 |
+
add_action( 'amp_post_template_head', 'amp_post_template_add_title' );
|
6 |
+
add_action( 'amp_post_template_head', 'amp_post_template_add_canonical' );
|
7 |
+
add_action( 'amp_post_template_head', 'amp_post_template_add_scripts' );
|
8 |
+
add_action( 'amp_post_template_head', 'amp_post_template_add_fonts' );
|
9 |
+
add_action( 'amp_post_template_head', 'amp_post_template_add_boilerplate_css' );
|
10 |
+
add_action( 'amp_post_template_head', 'amp_post_template_add_schemaorg_metadata' );
|
11 |
+
add_action( 'amp_post_template_css', 'amp_post_template_add_styles', 99 );
|
12 |
+
add_action( 'amp_post_template_data', 'amp_post_template_add_analytics_script' );
|
13 |
+
add_action( 'amp_post_template_footer', 'amp_post_template_add_analytics_data' );
|
14 |
+
}
|
15 |
+
|
16 |
function amp_post_template_add_title( $amp_template ) {
|
17 |
?>
|
18 |
<title><?php echo esc_html( $amp_template->get( 'document_title' ) ); ?></title>
|
19 |
<?php
|
20 |
}
|
21 |
|
|
|
22 |
function amp_post_template_add_canonical( $amp_template ) {
|
23 |
?>
|
24 |
<link rel="canonical" href="<?php echo esc_url( $amp_template->get( 'canonical_url' ) ); ?>" />
|
25 |
<?php
|
26 |
}
|
27 |
|
|
|
28 |
function amp_post_template_add_scripts( $amp_template ) {
|
29 |
$scripts = $amp_template->get( 'amp_component_scripts', array() );
|
30 |
+
foreach ( $scripts as $element => $script ) :
|
31 |
+
$custom_type = ($element == 'amp-mustache') ? 'template' : 'element'; ?>
|
32 |
+
<script custom-<?php echo esc_attr( $custom_type ); ?>="<?php echo esc_attr( $element ); ?>" src="<?php echo esc_url( $script ); ?>" async></script>
|
33 |
<?php endforeach; ?>
|
34 |
<script src="<?php echo esc_url( $amp_template->get( 'amp_runtime_script' ) ); ?>" async></script>
|
35 |
<?php
|
36 |
}
|
37 |
|
|
|
38 |
function amp_post_template_add_fonts( $amp_template ) {
|
39 |
$font_urls = $amp_template->get( 'font_urls', array() );
|
40 |
+
foreach ( $font_urls as $slug => $url ) : ?>
|
41 |
<link rel="stylesheet" href="<?php echo esc_url( $url ); ?>">
|
42 |
<?php endforeach;
|
43 |
}
|
44 |
|
|
|
45 |
function amp_post_template_add_boilerplate_css( $amp_template ) {
|
46 |
?>
|
47 |
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
|
48 |
<?php
|
49 |
}
|
50 |
|
|
|
51 |
function amp_post_template_add_schemaorg_metadata( $amp_template ) {
|
52 |
$metadata = $amp_template->get( 'metadata' );
|
53 |
if ( empty( $metadata ) ) {
|
54 |
return;
|
55 |
}
|
56 |
?>
|
57 |
+
<script type="application/ld+json"><?php echo wp_json_encode( $metadata ); ?></script>
|
58 |
<?php
|
59 |
}
|
60 |
|
|
|
61 |
function amp_post_template_add_styles( $amp_template ) {
|
62 |
$styles = $amp_template->get( 'post_amp_styles' );
|
63 |
if ( ! empty( $styles ) ) {
|
64 |
echo '/* Inline styles */' . PHP_EOL;
|
65 |
foreach ( $styles as $selector => $declarations ) {
|
66 |
+
$declarations = implode( ';', $declarations ) . ';';
|
67 |
printf( '%1$s{%2$s}', $selector, $declarations );
|
68 |
}
|
69 |
}
|
70 |
}
|
71 |
|
|
|
72 |
function amp_post_template_add_analytics_script( $data ) {
|
73 |
if ( ! empty( $data['amp_analytics'] ) ) {
|
74 |
$data['amp_component_scripts']['amp-analytics'] = 'https://cdn.ampproject.org/v0/amp-analytics-0.1.js';
|
76 |
return $data;
|
77 |
}
|
78 |
|
|
|
79 |
function amp_post_template_add_analytics_data( $amp_template ) {
|
80 |
$analytics_entries = $amp_template->get( 'amp_analytics' );
|
81 |
if ( empty( $analytics_entries ) ) {
|
84 |
|
85 |
foreach ( $analytics_entries as $id => $analytics_entry ) {
|
86 |
if ( ! isset( $analytics_entry['type'], $analytics_entry['attributes'], $analytics_entry['config_data'] ) ) {
|
87 |
+
_doing_it_wrong( __FUNCTION__, sprintf( esc_html__( 'Analytics entry for %s is missing one of the following keys: `type`, `attributes`, or `config_data` (array keys: %s)', 'amp' ), esc_html( $id ), esc_html( implode( ', ', array_keys( $analytics_entry ) ) ) ), '0.3.2' );
|
88 |
continue;
|
89 |
}
|
|
|
90 |
$script_element = AMP_HTML_Utils::build_tag( 'script', array(
|
91 |
'type' => 'application/json',
|
92 |
+
), wp_json_encode( $analytics_entry['config_data'] ) );
|
93 |
|
94 |
$amp_analytics_attr = array_merge( array(
|
95 |
'id' => $id,
|
includes/amp-post-template-functions.php
CHANGED
@@ -8,7 +8,7 @@ if ( ! function_exists( 'sanitize_hex_color' ) ) {
|
|
8 |
}
|
9 |
|
10 |
// 3 or 6 hex digits, or the empty string.
|
11 |
-
if ( preg_match
|
12 |
return $color;
|
13 |
}
|
14 |
}
|
8 |
}
|
9 |
|
10 |
// 3 or 6 hex digits, or the empty string.
|
11 |
+
if ( preg_match( '|^#([A-Fa-f0-9]{3}){1,2}$|', $color ) ) {
|
12 |
return $color;
|
13 |
}
|
14 |
}
|
includes/class-amp-content.php
CHANGED
@@ -63,7 +63,7 @@ class AMP_Content {
|
|
63 |
$embed_handler = new $embed_handler_class( array_merge( $this->args, $args ) );
|
64 |
|
65 |
if ( ! is_subclass_of( $embed_handler, 'AMP_Base_Embed_Handler' ) ) {
|
66 |
-
_doing_it_wrong( __METHOD__, sprintf(
|
67 |
continue;
|
68 |
}
|
69 |
|
@@ -99,14 +99,14 @@ class AMP_Content_Sanitizer {
|
|
99 |
|
100 |
foreach ( $sanitizer_classes as $sanitizer_class => $args ) {
|
101 |
if ( ! class_exists( $sanitizer_class ) ) {
|
102 |
-
_doing_it_wrong( __METHOD__, sprintf(
|
103 |
continue;
|
104 |
}
|
105 |
|
106 |
$sanitizer = new $sanitizer_class( $dom, array_merge( $global_args, $args ) );
|
107 |
|
108 |
if ( ! is_subclass_of( $sanitizer, 'AMP_Base_Sanitizer' ) ) {
|
109 |
-
_doing_it_wrong( __METHOD__, sprintf(
|
110 |
continue;
|
111 |
}
|
112 |
|
63 |
$embed_handler = new $embed_handler_class( array_merge( $this->args, $args ) );
|
64 |
|
65 |
if ( ! is_subclass_of( $embed_handler, 'AMP_Base_Embed_Handler' ) ) {
|
66 |
+
_doing_it_wrong( __METHOD__, sprintf( esc_html__( 'Embed Handler (%s) must extend `AMP_Embed_Handler`', 'amp' ), $embed_handler_class ), '0.1' );
|
67 |
continue;
|
68 |
}
|
69 |
|
99 |
|
100 |
foreach ( $sanitizer_classes as $sanitizer_class => $args ) {
|
101 |
if ( ! class_exists( $sanitizer_class ) ) {
|
102 |
+
_doing_it_wrong( __METHOD__, sprintf( esc_html__( 'Sanitizer (%s) class does not exist', 'amp' ), esc_html( $sanitizer_class ) ), '0.4.1' );
|
103 |
continue;
|
104 |
}
|
105 |
|
106 |
$sanitizer = new $sanitizer_class( $dom, array_merge( $global_args, $args ) );
|
107 |
|
108 |
if ( ! is_subclass_of( $sanitizer, 'AMP_Base_Sanitizer' ) ) {
|
109 |
+
_doing_it_wrong( __METHOD__, sprintf( esc_html__( 'Sanitizer (%s) must extend `AMP_Base_Sanitizer`', 'amp' ), esc_html( $sanitizer_class ) ), '0.1' );
|
110 |
continue;
|
111 |
}
|
112 |
|
includes/class-amp-post-template.php
CHANGED
@@ -3,22 +3,29 @@
|
|
3 |
require_once( AMP__DIR__ . '/includes/utils/class-amp-dom-utils.php' );
|
4 |
require_once( AMP__DIR__ . '/includes/utils/class-amp-html-utils.php' );
|
5 |
require_once( AMP__DIR__ . '/includes/utils/class-amp-string-utils.php' );
|
|
|
6 |
|
7 |
require_once( AMP__DIR__ . '/includes/class-amp-content.php' );
|
8 |
|
9 |
require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-style-sanitizer.php' );
|
10 |
require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-blacklist-sanitizer.php' );
|
|
|
11 |
require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-img-sanitizer.php' );
|
12 |
require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-video-sanitizer.php' );
|
13 |
require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-iframe-sanitizer.php' );
|
14 |
require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-audio-sanitizer.php' );
|
|
|
15 |
|
16 |
require_once( AMP__DIR__ . '/includes/embeds/class-amp-twitter-embed.php' );
|
17 |
require_once( AMP__DIR__ . '/includes/embeds/class-amp-youtube-embed.php' );
|
|
|
|
|
|
|
18 |
require_once( AMP__DIR__ . '/includes/embeds/class-amp-gallery-embed.php' );
|
19 |
require_once( AMP__DIR__ . '/includes/embeds/class-amp-instagram-embed.php' );
|
20 |
require_once( AMP__DIR__ . '/includes/embeds/class-amp-vine-embed.php' );
|
21 |
require_once( AMP__DIR__ . '/includes/embeds/class-amp-facebook-embed.php' );
|
|
|
22 |
|
23 |
class AMP_Post_Template {
|
24 |
const SITE_ICON_SIZE = 32;
|
@@ -70,6 +77,8 @@ class AMP_Post_Template {
|
|
70 |
'merriweather' => 'https://fonts.googleapis.com/css?family=Merriweather:400,400italic,700,700italic',
|
71 |
),
|
72 |
|
|
|
|
|
73 |
/**
|
74 |
* Add amp-analytics tags.
|
75 |
*
|
@@ -81,7 +90,7 @@ class AMP_Post_Template {
|
|
81 |
* @param object $post The current post.
|
82 |
*/
|
83 |
'amp_analytics' => apply_filters( 'amp_post_template_analytics', array(), $this->post ),
|
84 |
-
|
85 |
|
86 |
$this->build_post_content();
|
87 |
$this->build_post_data();
|
@@ -95,7 +104,7 @@ class AMP_Post_Template {
|
|
95 |
if ( isset( $this->data[ $property ] ) ) {
|
96 |
return $this->data[ $property ];
|
97 |
} else {
|
98 |
-
_doing_it_wrong( __METHOD__, sprintf(
|
99 |
}
|
100 |
|
101 |
return $default;
|
@@ -223,20 +232,26 @@ class AMP_Post_Template {
|
|
223 |
apply_filters( 'amp_content_embed_handlers', array(
|
224 |
'AMP_Twitter_Embed_Handler' => array(),
|
225 |
'AMP_YouTube_Embed_Handler' => array(),
|
|
|
|
|
|
|
226 |
'AMP_Instagram_Embed_Handler' => array(),
|
227 |
'AMP_Vine_Embed_Handler' => array(),
|
228 |
'AMP_Facebook_Embed_Handler' => array(),
|
|
|
229 |
'AMP_Gallery_Embed_Handler' => array(),
|
230 |
), $this->post ),
|
231 |
apply_filters( 'amp_content_sanitizers', array(
|
232 |
'AMP_Style_Sanitizer' => array(),
|
233 |
-
'AMP_Blacklist_Sanitizer' => array(),
|
234 |
'AMP_Img_Sanitizer' => array(),
|
235 |
'AMP_Video_Sanitizer' => array(),
|
236 |
'AMP_Audio_Sanitizer' => array(),
|
|
|
237 |
'AMP_Iframe_Sanitizer' => array(
|
238 |
'add_placeholder' => true,
|
239 |
),
|
|
|
240 |
), $this->post ),
|
241 |
array(
|
242 |
'content_max_width' => $this->get( 'content_max_width' ),
|
@@ -245,7 +260,7 @@ class AMP_Post_Template {
|
|
245 |
|
246 |
$this->add_data_by_key( 'post_amp_content', $amp_content->get_amp_content() );
|
247 |
$this->merge_data_for_key( 'amp_component_scripts', $amp_content->get_amp_scripts() );
|
248 |
-
$this->
|
249 |
}
|
250 |
|
251 |
private function build_post_featured_image() {
|
@@ -274,7 +289,7 @@ class AMP_Post_Template {
|
|
274 |
$featured_html,
|
275 |
array( 'AMP_Img_Sanitizer' => array() ),
|
276 |
array(
|
277 |
-
'content_max_width' => $this->get( 'content_max_width'
|
278 |
)
|
279 |
);
|
280 |
|
@@ -288,7 +303,7 @@ class AMP_Post_Template {
|
|
288 |
}
|
289 |
|
290 |
if ( $featured_styles ) {
|
291 |
-
$this->
|
292 |
}
|
293 |
}
|
294 |
|
@@ -381,7 +396,7 @@ class AMP_Post_Template {
|
|
381 |
|
382 |
$file = apply_filters( 'amp_post_template_file', $file, $template_type, $this->post );
|
383 |
if ( ! $this->is_valid_template( $file ) ) {
|
384 |
-
_doing_it_wrong( __METHOD__, sprintf(
|
385 |
return;
|
386 |
}
|
387 |
|
3 |
require_once( AMP__DIR__ . '/includes/utils/class-amp-dom-utils.php' );
|
4 |
require_once( AMP__DIR__ . '/includes/utils/class-amp-html-utils.php' );
|
5 |
require_once( AMP__DIR__ . '/includes/utils/class-amp-string-utils.php' );
|
6 |
+
require_once( AMP__DIR__ . '/includes/utils/class-amp-wp-utils.php' );
|
7 |
|
8 |
require_once( AMP__DIR__ . '/includes/class-amp-content.php' );
|
9 |
|
10 |
require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-style-sanitizer.php' );
|
11 |
require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-blacklist-sanitizer.php' );
|
12 |
+
require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-tag-and-attribute-sanitizer.php' );
|
13 |
require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-img-sanitizer.php' );
|
14 |
require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-video-sanitizer.php' );
|
15 |
require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-iframe-sanitizer.php' );
|
16 |
require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-audio-sanitizer.php' );
|
17 |
+
require_once( AMP__DIR__ . '/includes/sanitizers/class-amp-playbuzz-sanitizer.php' );
|
18 |
|
19 |
require_once( AMP__DIR__ . '/includes/embeds/class-amp-twitter-embed.php' );
|
20 |
require_once( AMP__DIR__ . '/includes/embeds/class-amp-youtube-embed.php' );
|
21 |
+
require_once( AMP__DIR__ . '/includes/embeds/class-amp-dailymotion-embed.php' );
|
22 |
+
require_once( AMP__DIR__ . '/includes/embeds/class-amp-vimeo-embed.php' );
|
23 |
+
require_once( AMP__DIR__ . '/includes/embeds/class-amp-soundcloud-embed.php' );
|
24 |
require_once( AMP__DIR__ . '/includes/embeds/class-amp-gallery-embed.php' );
|
25 |
require_once( AMP__DIR__ . '/includes/embeds/class-amp-instagram-embed.php' );
|
26 |
require_once( AMP__DIR__ . '/includes/embeds/class-amp-vine-embed.php' );
|
27 |
require_once( AMP__DIR__ . '/includes/embeds/class-amp-facebook-embed.php' );
|
28 |
+
require_once( AMP__DIR__ . '/includes/embeds/class-amp-pinterest-embed.php' );
|
29 |
|
30 |
class AMP_Post_Template {
|
31 |
const SITE_ICON_SIZE = 32;
|
77 |
'merriweather' => 'https://fonts.googleapis.com/css?family=Merriweather:400,400italic,700,700italic',
|
78 |
),
|
79 |
|
80 |
+
'post_amp_styles' => array(),
|
81 |
+
|
82 |
/**
|
83 |
* Add amp-analytics tags.
|
84 |
*
|
90 |
* @param object $post The current post.
|
91 |
*/
|
92 |
'amp_analytics' => apply_filters( 'amp_post_template_analytics', array(), $this->post ),
|
93 |
+
);
|
94 |
|
95 |
$this->build_post_content();
|
96 |
$this->build_post_data();
|
104 |
if ( isset( $this->data[ $property ] ) ) {
|
105 |
return $this->data[ $property ];
|
106 |
} else {
|
107 |
+
_doing_it_wrong( __METHOD__, sprintf( esc_html__( 'Called for non-existant key ("%s").', 'amp' ), esc_html( $property ) ), '0.1' );
|
108 |
}
|
109 |
|
110 |
return $default;
|
232 |
apply_filters( 'amp_content_embed_handlers', array(
|
233 |
'AMP_Twitter_Embed_Handler' => array(),
|
234 |
'AMP_YouTube_Embed_Handler' => array(),
|
235 |
+
'AMP_DailyMotion_Embed_Handler' => array(),
|
236 |
+
'AMP_Vimeo_Embed_Handler' => array(),
|
237 |
+
'AMP_SoundCloud_Embed_Handler' => array(),
|
238 |
'AMP_Instagram_Embed_Handler' => array(),
|
239 |
'AMP_Vine_Embed_Handler' => array(),
|
240 |
'AMP_Facebook_Embed_Handler' => array(),
|
241 |
+
'AMP_Pinterest_Embed_Handler' => array(),
|
242 |
'AMP_Gallery_Embed_Handler' => array(),
|
243 |
), $this->post ),
|
244 |
apply_filters( 'amp_content_sanitizers', array(
|
245 |
'AMP_Style_Sanitizer' => array(),
|
246 |
+
// 'AMP_Blacklist_Sanitizer' => array(),
|
247 |
'AMP_Img_Sanitizer' => array(),
|
248 |
'AMP_Video_Sanitizer' => array(),
|
249 |
'AMP_Audio_Sanitizer' => array(),
|
250 |
+
'AMP_Playbuzz_Sanitizer' => array(),
|
251 |
'AMP_Iframe_Sanitizer' => array(
|
252 |
'add_placeholder' => true,
|
253 |
),
|
254 |
+
'AMP_Tag_And_Attribute_Sanitizer' => array(),
|
255 |
), $this->post ),
|
256 |
array(
|
257 |
'content_max_width' => $this->get( 'content_max_width' ),
|
260 |
|
261 |
$this->add_data_by_key( 'post_amp_content', $amp_content->get_amp_content() );
|
262 |
$this->merge_data_for_key( 'amp_component_scripts', $amp_content->get_amp_scripts() );
|
263 |
+
$this->merge_data_for_key( 'post_amp_styles', $amp_content->get_amp_styles() );
|
264 |
}
|
265 |
|
266 |
private function build_post_featured_image() {
|
289 |
$featured_html,
|
290 |
array( 'AMP_Img_Sanitizer' => array() ),
|
291 |
array(
|
292 |
+
'content_max_width' => $this->get( 'content_max_width' ),
|
293 |
)
|
294 |
);
|
295 |
|
303 |
}
|
304 |
|
305 |
if ( $featured_styles ) {
|
306 |
+
$this->merge_data_for_key( 'post_amp_styles', $featured_styles );
|
307 |
}
|
308 |
}
|
309 |
|
396 |
|
397 |
$file = apply_filters( 'amp_post_template_file', $file, $template_type, $this->post );
|
398 |
if ( ! $this->is_valid_template( $file ) ) {
|
399 |
+
_doing_it_wrong( __METHOD__, sprintf( esc_html__( 'Path validation for template (%s) failed. Path cannot traverse and must be located in `%s`.', 'amp' ), esc_html( $file ), 'WP_CONTENT_DIR' ), '0.1' );
|
400 |
return;
|
401 |
}
|
402 |
|
includes/embeds/class-amp-dailymotion-embed.php
ADDED
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once( AMP__DIR__ . '/includes/embeds/class-amp-base-embed-handler.php' );
|
4 |
+
|
5 |
+
// Much of this class is borrowed from Jetpack embeds
|
6 |
+
class AMP_DailyMotion_Embed_Handler extends AMP_Base_Embed_Handler {
|
7 |
+
|
8 |
+
const URL_PATTERN = '#https?:\/\/(www\.)?dailymotion\.com\/video\/.*#i';
|
9 |
+
const RATIO = 0.5625;
|
10 |
+
|
11 |
+
protected $DEFAULT_WIDTH = 600;
|
12 |
+
protected $DEFAULT_HEIGHT = 338;
|
13 |
+
|
14 |
+
private static $script_slug = 'amp-dailymotion';
|
15 |
+
private static $script_src = 'https://cdn.ampproject.org/v0/amp-dailymotion-0.1.js';
|
16 |
+
|
17 |
+
function __construct( $args = array() ) {
|
18 |
+
parent::__construct( $args );
|
19 |
+
|
20 |
+
if ( isset( $this->args['content_max_width'] ) ) {
|
21 |
+
$max_width = $this->args['content_max_width'];
|
22 |
+
$this->args['width'] = $max_width;
|
23 |
+
$this->args['height'] = round( $max_width * self::RATIO );
|
24 |
+
}
|
25 |
+
}
|
26 |
+
|
27 |
+
function register_embed() {
|
28 |
+
wp_embed_register_handler( 'amp-dailymotion', self::URL_PATTERN, array( $this, 'oembed' ), -1 );
|
29 |
+
add_shortcode( 'dailymotion', array( $this, 'shortcode' ) );
|
30 |
+
}
|
31 |
+
|
32 |
+
public function unregister_embed() {
|
33 |
+
wp_embed_unregister_handler( 'amp-dailymotion', -1 );
|
34 |
+
remove_shortcode( 'dailymotion' );
|
35 |
+
}
|
36 |
+
|
37 |
+
public function get_scripts() {
|
38 |
+
if ( ! $this->did_convert_elements ) {
|
39 |
+
return array();
|
40 |
+
}
|
41 |
+
|
42 |
+
return array( self::$script_slug => self::$script_src );
|
43 |
+
}
|
44 |
+
|
45 |
+
public function shortcode( $attr ) {
|
46 |
+
$video_id = false;
|
47 |
+
|
48 |
+
if ( isset( $attr['id'] ) ) {
|
49 |
+
$video_id = $attr['id'];
|
50 |
+
} elseif ( isset( $attr[0] ) ) {
|
51 |
+
$video_id = $attr[0];
|
52 |
+
} elseif ( function_exists( 'shortcode_new_to_old_params' ) ) {
|
53 |
+
$video_id = shortcode_new_to_old_params( $attr );
|
54 |
+
}
|
55 |
+
|
56 |
+
if ( empty( $video_id ) ) {
|
57 |
+
return '';
|
58 |
+
}
|
59 |
+
|
60 |
+
return $this->render( array(
|
61 |
+
'video_id' => $video_id,
|
62 |
+
) );
|
63 |
+
}
|
64 |
+
|
65 |
+
public function oembed( $matches, $attr, $url, $rawattr ) {
|
66 |
+
$video_id = $this->get_video_id_from_url( $url );
|
67 |
+
return $this->render( array(
|
68 |
+
'video_id' => $video_id,
|
69 |
+
) );
|
70 |
+
}
|
71 |
+
|
72 |
+
public function render( $args ) {
|
73 |
+
$args = wp_parse_args( $args, array(
|
74 |
+
'video_id' => false,
|
75 |
+
) );
|
76 |
+
|
77 |
+
if ( empty( $args['video_id'] ) ) {
|
78 |
+
return AMP_HTML_Utils::build_tag( 'a', array( 'href' => esc_url( $args['url'] ), 'class' => 'amp-wp-embed-fallback' ), esc_html( $args['url'] ) );
|
79 |
+
}
|
80 |
+
|
81 |
+
$this->did_convert_elements = true;
|
82 |
+
|
83 |
+
return AMP_HTML_Utils::build_tag(
|
84 |
+
'amp-dailymotion',
|
85 |
+
array(
|
86 |
+
'data-videoid' => $args['video_id'],
|
87 |
+
'layout' => 'responsive',
|
88 |
+
'width' => $this->args['width'],
|
89 |
+
'height' => $this->args['height'],
|
90 |
+
)
|
91 |
+
);
|
92 |
+
}
|
93 |
+
|
94 |
+
private function get_video_id_from_url( $url ) {
|
95 |
+
$parsed_url = AMP_WP_Utils::parse_url( $url );
|
96 |
+
parse_str( $parsed_url['path'], $path );
|
97 |
+
$tok = explode( '/', $parsed_url['path'] );
|
98 |
+
$tok = explode( '_', $tok[2] );
|
99 |
+
$video_id = $tok[0];
|
100 |
+
|
101 |
+
return $video_id;
|
102 |
+
}
|
103 |
+
}
|
includes/embeds/class-amp-gallery-embed.php
CHANGED
@@ -39,7 +39,7 @@ class AMP_Gallery_Embed_Handler extends AMP_Base_Embed_Handler {
|
|
39 |
'id' => $post ? $post->ID : 0,
|
40 |
'include' => '',
|
41 |
'exclude' => '',
|
42 |
-
'size' => array( $this->args['width'], $this->args['height']
|
43 |
), $attr, 'gallery' );
|
44 |
|
45 |
$id = intval( $atts['id'] );
|
39 |
'id' => $post ? $post->ID : 0,
|
40 |
'include' => '',
|
41 |
'exclude' => '',
|
42 |
+
'size' => array( $this->args['width'], $this->args['height'] ),
|
43 |
), $attr, 'gallery' );
|
44 |
|
45 |
$id = intval( $atts['id'] );
|
includes/embeds/class-amp-instagram-embed.php
CHANGED
@@ -52,7 +52,7 @@ class AMP_Instagram_Embed_Handler extends AMP_Base_Embed_Handler {
|
|
52 |
}
|
53 |
|
54 |
public function oembed( $matches, $attr, $url, $rawattr ) {
|
55 |
-
return $this->render( array( 'url' => $url, 'instagram_id' =>
|
56 |
}
|
57 |
|
58 |
public function render( $args ) {
|
52 |
}
|
53 |
|
54 |
public function oembed( $matches, $attr, $url, $rawattr ) {
|
55 |
+
return $this->render( array( 'url' => $url, 'instagram_id' => end( $matches ) ) );
|
56 |
}
|
57 |
|
58 |
public function render( $args ) {
|
includes/embeds/class-amp-pinterest-embed.php
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once( AMP__DIR__ . '/includes/embeds/class-amp-base-embed-handler.php');
|
4 |
+
|
5 |
+
class AMP_Pinterest_Embed_Handler extends AMP_Base_Embed_Handler {
|
6 |
+
|
7 |
+
const URL_PATTERN = '#https?://(www\.)?pinterest\.com/pin/.*#i';
|
8 |
+
|
9 |
+
protected $DEFAULT_WIDTH = 450;
|
10 |
+
protected $DEFAULT_HEIGHT = 750;
|
11 |
+
|
12 |
+
private static $script_slug = 'amp-pinterest';
|
13 |
+
private static $script_src = 'https://cdn.ampproject.org/v0/amp-pinterest-0.1.js';
|
14 |
+
|
15 |
+
public function register_embed() {
|
16 |
+
wp_embed_register_handler(
|
17 |
+
'amp-pinterest',
|
18 |
+
self::URL_PATTERN,
|
19 |
+
array($this, 'oembed'),
|
20 |
+
-1);
|
21 |
+
}
|
22 |
+
|
23 |
+
public function unregister_embed() {
|
24 |
+
wp_embed_unregister_handler('amp-pinterest', -1);
|
25 |
+
}
|
26 |
+
|
27 |
+
public function get_scripts() {
|
28 |
+
if ( ! $this->did_convert_elements) {
|
29 |
+
return array();
|
30 |
+
}
|
31 |
+
|
32 |
+
return array( self::$script_slug => self::$script_src);
|
33 |
+
}
|
34 |
+
|
35 |
+
public function oembed( $matches, $attr, $url, $rawattr ) {
|
36 |
+
return $this->render( array( 'url' => $url ) );
|
37 |
+
}
|
38 |
+
|
39 |
+
public function render( $args ) {
|
40 |
+
$args = wp_parse_args( $args, array(
|
41 |
+
'url' => false,
|
42 |
+
) );
|
43 |
+
|
44 |
+
if ( empty( $args['url'] ) ) {
|
45 |
+
return '';
|
46 |
+
}
|
47 |
+
|
48 |
+
$this->did_convert_elements = true;
|
49 |
+
|
50 |
+
return AMP_HTML_Utils::build_tag(
|
51 |
+
'amp-pinterest',
|
52 |
+
array(
|
53 |
+
'width' => $this->args['width'],
|
54 |
+
'height' => $this->args['height'],
|
55 |
+
'data-do' => "embedPin",
|
56 |
+
'data-url' => $args['url'],
|
57 |
+
)
|
58 |
+
);
|
59 |
+
}
|
60 |
+
}
|
includes/embeds/class-amp-soundcloud-embed.php
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once( AMP__DIR__ . '/includes/embeds/class-amp-base-embed-handler.php' );
|
4 |
+
|
5 |
+
class AMP_SoundCloud_Embed_Handler extends AMP_Base_Embed_Handler {
|
6 |
+
const URL_PATTERN = '#https?://api\.soundcloud\.com/tracks/.*#i';
|
7 |
+
protected $DEFAULT_HEIGHT = 200;
|
8 |
+
|
9 |
+
private static $script_slug = 'amp-soundcloud';
|
10 |
+
private static $script_src = 'https://cdn.ampproject.org/v0/amp-soundcloud-0.1.js';
|
11 |
+
|
12 |
+
public function register_embed() {
|
13 |
+
wp_embed_register_handler( 'amp-soundcloud', self::URL_PATTERN, array( $this, 'oembed' ), -1 );
|
14 |
+
add_shortcode( 'soundcloud', array( $this, 'shortcode' ) );
|
15 |
+
}
|
16 |
+
|
17 |
+
public function unregister_embed() {
|
18 |
+
wp_embed_unregister_handler( 'amp-soundcloud', -1 );
|
19 |
+
remove_shortcode( 'soundcloud' );
|
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 |
+
$track_id = $this->get_track_id_from_url( $url );
|
32 |
+
return $this->render( array(
|
33 |
+
'track_id' => $track_id,
|
34 |
+
) );
|
35 |
+
}
|
36 |
+
|
37 |
+
public function shortcode( $attr ) {
|
38 |
+
|
39 |
+
$track_id = false;
|
40 |
+
|
41 |
+
if ( isset( $attr['id'] ) ) {
|
42 |
+
$track_id = $attr['id'];
|
43 |
+
} else {
|
44 |
+
$url = false;
|
45 |
+
if ( isset( $attr['url'] ) ) {
|
46 |
+
$url = $attr['url'];
|
47 |
+
} elseif ( isset( $attr[0] ) ) {
|
48 |
+
$url = $attr[0];
|
49 |
+
} elseif ( function_exists( 'shortcode_new_to_old_params' ) ) {
|
50 |
+
$url = shortcode_new_to_old_params( $attr );
|
51 |
+
}
|
52 |
+
|
53 |
+
if ( ! empty( $url ) ) {
|
54 |
+
$track_id = $this->get_track_id_from_url( $url );
|
55 |
+
}
|
56 |
+
}
|
57 |
+
|
58 |
+
if ( empty( $track_id ) ) {
|
59 |
+
return '';
|
60 |
+
}
|
61 |
+
|
62 |
+
return $this->render( array(
|
63 |
+
'track_id' => $track_id,
|
64 |
+
) );
|
65 |
+
}
|
66 |
+
|
67 |
+
public function render( $args ) {
|
68 |
+
$args = wp_parse_args( $args, array(
|
69 |
+
'track_id' => false,
|
70 |
+
) );
|
71 |
+
|
72 |
+
if ( empty( $args['track_id'] ) ) {
|
73 |
+
return AMP_HTML_Utils::build_tag( 'a', array( 'href' => esc_url( $args['url'] ), 'class' => 'amp-wp-embed-fallback' ), esc_html( $args['url'] ) );
|
74 |
+
}
|
75 |
+
|
76 |
+
$this->did_convert_elements = true;
|
77 |
+
|
78 |
+
return AMP_HTML_Utils::build_tag(
|
79 |
+
'amp-soundcloud',
|
80 |
+
array(
|
81 |
+
'data-trackid' => $args['track_id'],
|
82 |
+
'layout' => 'fixed-height',
|
83 |
+
'height' => $this->args['height'],
|
84 |
+
)
|
85 |
+
);
|
86 |
+
}
|
87 |
+
|
88 |
+
private function get_track_id_from_url( $url ) {
|
89 |
+
$parsed_url = AMP_WP_Utils::parse_url( $url );
|
90 |
+
$tok = explode( '/', $parsed_url['path'] );
|
91 |
+
$track_id = $tok[2];
|
92 |
+
|
93 |
+
return $track_id;
|
94 |
+
}
|
95 |
+
}
|
includes/embeds/class-amp-vimeo-embed.php
ADDED
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once( AMP__DIR__ . '/includes/embeds/class-amp-base-embed-handler.php' );
|
4 |
+
|
5 |
+
// Much of this class is borrowed from Jetpack embeds
|
6 |
+
class AMP_Vimeo_Embed_Handler extends AMP_Base_Embed_Handler {
|
7 |
+
|
8 |
+
const URL_PATTERN = '#https?:\/\/(www\.)?vimeo\.com\/.*#i';
|
9 |
+
|
10 |
+
const RATIO = 0.5625;
|
11 |
+
|
12 |
+
protected $DEFAULT_WIDTH = 600;
|
13 |
+
protected $DEFAULT_HEIGHT = 338;
|
14 |
+
|
15 |
+
private static $script_slug = 'amp-vimeo';
|
16 |
+
private static $script_src = 'https://cdn.ampproject.org/v0/amp-vimeo-0.1.js';
|
17 |
+
|
18 |
+
function __construct( $args = array() ) {
|
19 |
+
parent::__construct( $args );
|
20 |
+
|
21 |
+
if ( isset( $this->args['content_max_width'] ) ) {
|
22 |
+
$max_width = $this->args['content_max_width'];
|
23 |
+
$this->args['width'] = $max_width;
|
24 |
+
$this->args['height'] = round( $max_width * self::RATIO );
|
25 |
+
}
|
26 |
+
}
|
27 |
+
|
28 |
+
function register_embed() {
|
29 |
+
wp_embed_register_handler( 'amp-vimeo', self::URL_PATTERN, array( $this, 'oembed' ), -1 );
|
30 |
+
add_shortcode( 'vimeo', array( $this, 'shortcode' ) );
|
31 |
+
}
|
32 |
+
|
33 |
+
public function unregister_embed() {
|
34 |
+
wp_embed_unregister_handler( 'amp-vimeo', -1 );
|
35 |
+
remove_shortcode( 'vimeo' );
|
36 |
+
}
|
37 |
+
|
38 |
+
public function get_scripts() {
|
39 |
+
if ( ! $this->did_convert_elements ) {
|
40 |
+
return array();
|
41 |
+
}
|
42 |
+
|
43 |
+
return array( self::$script_slug => self::$script_src );
|
44 |
+
}
|
45 |
+
|
46 |
+
public function shortcode( $attr ) {
|
47 |
+
$video_id = false;
|
48 |
+
|
49 |
+
if ( isset( $attr['id'] ) ) {
|
50 |
+
$video_id = $attr['id'];
|
51 |
+
} elseif ( isset( $attr['url'] ) ) {
|
52 |
+
$video_id = $this->get_video_id_from_url($attr['url']);
|
53 |
+
}elseif ( isset( $attr[0] ) ) {
|
54 |
+
$video_id = $this->get_video_id_from_url($attr[0]);
|
55 |
+
} elseif ( function_exists( 'shortcode_new_to_old_params' ) ) {
|
56 |
+
$video_id = shortcode_new_to_old_params( $attr );
|
57 |
+
}
|
58 |
+
|
59 |
+
if ( empty( $video_id ) ) {
|
60 |
+
return '';
|
61 |
+
}
|
62 |
+
|
63 |
+
return $this->render( array(
|
64 |
+
'video_id' => $video_id,
|
65 |
+
) );
|
66 |
+
}
|
67 |
+
|
68 |
+
public function oembed( $matches, $attr, $url, $rawattr ) {
|
69 |
+
$video_id = $this->get_video_id_from_url( $url );
|
70 |
+
|
71 |
+
return $this->render( array(
|
72 |
+
'url' => $url,
|
73 |
+
'video_id' => $video_id,
|
74 |
+
) );
|
75 |
+
}
|
76 |
+
|
77 |
+
public function render( $args ) {
|
78 |
+
$args = wp_parse_args( $args, array(
|
79 |
+
'video_id' => false,
|
80 |
+
) );
|
81 |
+
|
82 |
+
if ( empty( $args['video_id'] ) ) {
|
83 |
+
return AMP_HTML_Utils::build_tag( 'a', array( 'href' => esc_url( $args['url'] ), 'class' => 'amp-wp-embed-fallback' ), esc_html( $args['url'] ) );
|
84 |
+
}
|
85 |
+
|
86 |
+
$this->did_convert_elements = true;
|
87 |
+
|
88 |
+
return AMP_HTML_Utils::build_tag(
|
89 |
+
'amp-vimeo',
|
90 |
+
array(
|
91 |
+
'data-videoid' => $args['video_id'],
|
92 |
+
'layout' => 'responsive',
|
93 |
+
'width' => $this->args['width'],
|
94 |
+
'height' => $this->args['height'],
|
95 |
+
)
|
96 |
+
);
|
97 |
+
}
|
98 |
+
|
99 |
+
// get_video_id_from_url()
|
100 |
+
// Takes the last component of a Vimeo URL
|
101 |
+
// and returns it as the associated video id
|
102 |
+
private function get_video_id_from_url( $url ) {
|
103 |
+
$parsed_url = parse_url( $url );
|
104 |
+
parse_str( $parsed_url['path'], $path );
|
105 |
+
|
106 |
+
$video_id = "";
|
107 |
+
if ( $path ) {
|
108 |
+
$tok = explode( '/', $parsed_url['path'] );
|
109 |
+
$video_id = end($tok);
|
110 |
+
}
|
111 |
+
|
112 |
+
return $video_id;
|
113 |
+
}
|
114 |
+
}
|
includes/embeds/class-amp-vine-embed.php
CHANGED
@@ -28,7 +28,7 @@ class AMP_Vine_Embed_Handler extends AMP_Base_Embed_Handler {
|
|
28 |
}
|
29 |
|
30 |
public function oembed( $matches, $attr, $url, $rawattr ) {
|
31 |
-
return $this->render( array( 'url' => $url, 'vine_id' =>
|
32 |
}
|
33 |
|
34 |
public function render( $args ) {
|
28 |
}
|
29 |
|
30 |
public function oembed( $matches, $attr, $url, $rawattr ) {
|
31 |
+
return $this->render( array( 'url' => $url, 'vine_id' => end( $matches ) ) );
|
32 |
}
|
33 |
|
34 |
public function render( $args ) {
|
includes/embeds/class-amp-youtube-embed.php
CHANGED
@@ -48,7 +48,7 @@ class AMP_YouTube_Embed_Handler extends AMP_Base_Embed_Handler {
|
|
48 |
$video_id = false;
|
49 |
if ( isset( $attr[0] ) ) {
|
50 |
$url = ltrim( $attr[0] , '=' );
|
51 |
-
} elseif ( function_exists
|
52 |
$url = shortcode_new_to_old_params( $attr );
|
53 |
}
|
54 |
|
@@ -92,7 +92,7 @@ class AMP_YouTube_Embed_Handler extends AMP_Base_Embed_Handler {
|
|
92 |
|
93 |
private function get_video_id_from_url( $url ) {
|
94 |
$video_id = false;
|
95 |
-
$parsed_url = parse_url( $url );
|
96 |
|
97 |
if ( self::SHORT_URL_HOST === substr( $parsed_url['host'], -strlen( self::SHORT_URL_HOST ) ) ) {
|
98 |
// youtu.be/{id}
|
@@ -113,7 +113,7 @@ class AMP_YouTube_Embed_Handler extends AMP_Base_Embed_Handler {
|
|
113 |
// /(v|e|embed)/{id}
|
114 |
$parts = explode( '/', $parsed_url['path'] );
|
115 |
|
116 |
-
if ( in_array( $parts[1], array( 'v', 'e', 'embed'
|
117 |
$video_id = $parts[2];
|
118 |
}
|
119 |
}
|
48 |
$video_id = false;
|
49 |
if ( isset( $attr[0] ) ) {
|
50 |
$url = ltrim( $attr[0] , '=' );
|
51 |
+
} elseif ( function_exists( 'shortcode_new_to_old_params' ) ) {
|
52 |
$url = shortcode_new_to_old_params( $attr );
|
53 |
}
|
54 |
|
92 |
|
93 |
private function get_video_id_from_url( $url ) {
|
94 |
$video_id = false;
|
95 |
+
$parsed_url = AMP_WP_Utils::parse_url( $url );
|
96 |
|
97 |
if ( self::SHORT_URL_HOST === substr( $parsed_url['host'], -strlen( self::SHORT_URL_HOST ) ) ) {
|
98 |
// youtu.be/{id}
|
113 |
// /(v|e|embed)/{id}
|
114 |
$parts = explode( '/', $parsed_url['path'] );
|
115 |
|
116 |
+
if ( in_array( $parts[1], array( 'v', 'e', 'embed' ), true ) ) {
|
117 |
$video_id = $parts[2];
|
118 |
}
|
119 |
}
|
includes/lib/class-fastimage.php
DELETED
@@ -1,253 +0,0 @@
|
|
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/lib/fasterimage/Exception/InvalidImageException.php
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php namespace FasterImage\Exception;
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Class InvalidImageException
|
5 |
+
*
|
6 |
+
* @package FasterImage\Exception
|
7 |
+
*/
|
8 |
+
class InvalidImageException extends \Exception {}
|
includes/lib/fasterimage/ExifParser.php
ADDED
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php namespace FasterImage;
|
2 |
+
|
3 |
+
use FasterImage\Exception\InvalidImageException;
|
4 |
+
use WillWashburn\Stream\StreamableInterface;
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Class ExifParser
|
8 |
+
*
|
9 |
+
* @package FasterImage
|
10 |
+
*/
|
11 |
+
class ExifParser
|
12 |
+
{
|
13 |
+
/**
|
14 |
+
* @var int
|
15 |
+
*/
|
16 |
+
protected $width;
|
17 |
+
/**
|
18 |
+
* @var int
|
19 |
+
*/
|
20 |
+
protected $height;
|
21 |
+
|
22 |
+
/**
|
23 |
+
* @var
|
24 |
+
*/
|
25 |
+
protected $short;
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @var
|
29 |
+
*/
|
30 |
+
protected $long;
|
31 |
+
|
32 |
+
/**
|
33 |
+
* @var StreamableInterface
|
34 |
+
*/
|
35 |
+
protected $stream;
|
36 |
+
|
37 |
+
/**
|
38 |
+
* @var int
|
39 |
+
*/
|
40 |
+
protected $orientation;
|
41 |
+
|
42 |
+
/**
|
43 |
+
* ExifParser constructor.
|
44 |
+
*
|
45 |
+
* @param StreamableInterface $stream
|
46 |
+
*/
|
47 |
+
public function __construct(StreamableInterface $stream)
|
48 |
+
{
|
49 |
+
$this->stream = $stream;
|
50 |
+
$this->parseExifIfd();
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* @return int
|
55 |
+
*/
|
56 |
+
public function getHeight()
|
57 |
+
{
|
58 |
+
return $this->height;
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* @return int
|
63 |
+
*/
|
64 |
+
public function getWidth()
|
65 |
+
{
|
66 |
+
return $this->width;
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* @return bool
|
71 |
+
*/
|
72 |
+
public function isRotated()
|
73 |
+
{
|
74 |
+
return (! empty($this->orientation) && $this->orientation >= 5);
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* @return bool
|
79 |
+
* @throws \FasterImage\Exception\InvalidImageException
|
80 |
+
*/
|
81 |
+
protected function parseExifIfd()
|
82 |
+
{
|
83 |
+
$byte_order = $this->stream->read(2);
|
84 |
+
|
85 |
+
switch ( $byte_order ) {
|
86 |
+
case 'II':
|
87 |
+
$this->short = 'v';
|
88 |
+
$this->long = 'V';
|
89 |
+
break;
|
90 |
+
case 'MM':
|
91 |
+
$this->short = 'n';
|
92 |
+
$this->long = 'N';
|
93 |
+
break;
|
94 |
+
default:
|
95 |
+
throw new InvalidImageException;
|
96 |
+
break;
|
97 |
+
}
|
98 |
+
|
99 |
+
$this->stream->read(2);
|
100 |
+
|
101 |
+
$offset = current(unpack($this->long, $this->stream->read(4)));
|
102 |
+
|
103 |
+
$this->stream->read($offset - 8);
|
104 |
+
|
105 |
+
$tag_count = current(unpack($this->short, $this->stream->read(2)));
|
106 |
+
|
107 |
+
for ( $i = $tag_count; $i > 0; $i-- ) {
|
108 |
+
|
109 |
+
$type = current(unpack($this->short, $this->stream->read(2)));
|
110 |
+
$this->stream->read(6);
|
111 |
+
$data = current(unpack($this->short, $this->stream->read(2)));
|
112 |
+
|
113 |
+
switch ( $type ) {
|
114 |
+
case 0x0100:
|
115 |
+
$this->width = $data;
|
116 |
+
break;
|
117 |
+
case 0x0101:
|
118 |
+
$this->height = $data;
|
119 |
+
break;
|
120 |
+
case 0x0112:
|
121 |
+
$this->orientation = $data;
|
122 |
+
break;
|
123 |
+
}
|
124 |
+
|
125 |
+
if ( isset($this->width) && isset($this->height) && isset($this->orientation) ) {
|
126 |
+
return true;
|
127 |
+
}
|
128 |
+
|
129 |
+
$this->stream->read(2);
|
130 |
+
}
|
131 |
+
|
132 |
+
return false;
|
133 |
+
}
|
134 |
+
}
|
includes/lib/fasterimage/FasterImage.php
ADDED
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php namespace FasterImage;
|
2 |
+
|
3 |
+
use FasterImage\Exception\InvalidImageException;
|
4 |
+
use WillWashburn\Stream\Exception\StreamBufferTooSmallException;
|
5 |
+
use WillWashburn\Stream\Stream;
|
6 |
+
|
7 |
+
/**
|
8 |
+
* FasterImage - Because sometimes you just want the size, and you want them in
|
9 |
+
* parallel!
|
10 |
+
*
|
11 |
+
* Based on the PHP stream implementation by Tom Moor (http://tommoor.com)
|
12 |
+
* which was based on the original Ruby Implementation by Steven Sykes
|
13 |
+
* (https://github.com/sdsykes/fastimage)
|
14 |
+
*
|
15 |
+
* MIT Licensed
|
16 |
+
*
|
17 |
+
* @version 0.01
|
18 |
+
*/
|
19 |
+
class FasterImage
|
20 |
+
{
|
21 |
+
/**
|
22 |
+
* The default timeout
|
23 |
+
*
|
24 |
+
* @var int
|
25 |
+
*/
|
26 |
+
protected $timeout = 10;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Get the size of each of the urls in a list
|
30 |
+
*
|
31 |
+
* @param array $urls
|
32 |
+
*
|
33 |
+
* @return array
|
34 |
+
* @throws \Exception
|
35 |
+
*/
|
36 |
+
public function batch(array $urls)
|
37 |
+
{
|
38 |
+
|
39 |
+
$multi = curl_multi_init();
|
40 |
+
$results = array();
|
41 |
+
|
42 |
+
// Create the curl handles and add them to the multi_request
|
43 |
+
foreach ( array_values($urls) as $count => $uri ) {
|
44 |
+
|
45 |
+
$results[$uri] = [];
|
46 |
+
|
47 |
+
$count = $this->handle($uri, $results[$uri]);
|
48 |
+
|
49 |
+
$code = curl_multi_add_handle($multi, $count);
|
50 |
+
|
51 |
+
if ( $code != CURLM_OK ) {
|
52 |
+
throw new \Exception("Curl handle for $uri could not be added");
|
53 |
+
}
|
54 |
+
}
|
55 |
+
|
56 |
+
// Perform the requests
|
57 |
+
do {
|
58 |
+
while ( ($mrc = curl_multi_exec($multi, $active)) == CURLM_CALL_MULTI_PERFORM ) ;
|
59 |
+
if ( $mrc != CURLM_OK && $mrc != CURLM_CALL_MULTI_PERFORM ) {
|
60 |
+
throw new \Exception("Curl error code: $mrc");
|
61 |
+
}
|
62 |
+
|
63 |
+
if ( $active && curl_multi_select($multi) === -1 ) {
|
64 |
+
// Perform a usleep if a select returns -1.
|
65 |
+
// See: https://bugs.php.net/bug.php?id=61141
|
66 |
+
usleep(250);
|
67 |
+
}
|
68 |
+
} while ( $active );
|
69 |
+
|
70 |
+
// Figure out why individual requests may have failed
|
71 |
+
foreach ( array_values($urls) as $count => $uri ) {
|
72 |
+
$error = curl_error($count);
|
73 |
+
|
74 |
+
if ( $error ) {
|
75 |
+
$results[$uri]['failure_reason'] = $error;
|
76 |
+
}
|
77 |
+
}
|
78 |
+
|
79 |
+
return $results;
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* @param $seconds
|
84 |
+
*/
|
85 |
+
public function setTimeout($seconds)
|
86 |
+
{
|
87 |
+
$this->timeout = $seconds;
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Create the handle for the curl request
|
92 |
+
*
|
93 |
+
* @param $url
|
94 |
+
* @param $result
|
95 |
+
*
|
96 |
+
* @return resource
|
97 |
+
*/
|
98 |
+
protected function handle($url, & $result)
|
99 |
+
{
|
100 |
+
$stream = new Stream();
|
101 |
+
$parser = new ImageParser($stream);
|
102 |
+
$result['rounds'] = 0;
|
103 |
+
$result['bytes'] = 0;
|
104 |
+
$result['size'] = 'failed';
|
105 |
+
|
106 |
+
$ch = curl_init();
|
107 |
+
curl_setopt($ch, CURLOPT_URL, $url);
|
108 |
+
curl_setopt($ch, CURLOPT_HEADER, 0);
|
109 |
+
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
110 |
+
curl_setopt($ch, CURLOPT_BUFFERSIZE, 256);
|
111 |
+
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
|
112 |
+
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
113 |
+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
114 |
+
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->timeout);
|
115 |
+
curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
|
116 |
+
|
117 |
+
# Some web servers require the useragent to be not a bot. So we are liars.
|
118 |
+
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36');
|
119 |
+
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
120 |
+
"Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
|
121 |
+
"Cache-Control: max-age=0",
|
122 |
+
"Connection: keep-alive",
|
123 |
+
"Keep-Alive: 300",
|
124 |
+
"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7",
|
125 |
+
"Accept-Language: en-us,en;q=0.5",
|
126 |
+
"Pragma: ", // browsers keep this blank.
|
127 |
+
]);
|
128 |
+
curl_setopt($ch, CURLOPT_ENCODING, "");
|
129 |
+
|
130 |
+
curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($ch, $str) use (& $result, & $parser, & $stream, $url) {
|
131 |
+
|
132 |
+
$result['rounds']++;
|
133 |
+
$result['bytes'] += strlen($str);
|
134 |
+
|
135 |
+
$stream->write($str);
|
136 |
+
|
137 |
+
try {
|
138 |
+
// store the type in the result array by looking at the bits
|
139 |
+
$result['type'] = $parser->parseType();
|
140 |
+
|
141 |
+
/*
|
142 |
+
* We try here to parse the buffer of characters we already have
|
143 |
+
* for the size.
|
144 |
+
*/
|
145 |
+
$result['size'] = $parser->parseSize() ?: 'failed';
|
146 |
+
}
|
147 |
+
catch (StreamBufferTooSmallException $e) {
|
148 |
+
/*
|
149 |
+
* If this exception is thrown, we don't have enough of the stream buffered
|
150 |
+
* so in order to tell curl to keep streaming we need to return the number
|
151 |
+
* of bytes we have already handled
|
152 |
+
*
|
153 |
+
* We set the 'size' to 'failed' in the case that we've done
|
154 |
+
* the entire image and we couldn't figure it out. Otherwise
|
155 |
+
* it'll get overwritten with the next round.
|
156 |
+
*/
|
157 |
+
$result['size'] = 'failed';
|
158 |
+
|
159 |
+
return strlen($str);
|
160 |
+
}
|
161 |
+
catch (InvalidImageException $e) {
|
162 |
+
|
163 |
+
/*
|
164 |
+
* This means we've determined that we're lost and don't know
|
165 |
+
* how to parse this image.
|
166 |
+
*
|
167 |
+
* We set the size to invalid and move on
|
168 |
+
*/
|
169 |
+
$result['size'] = 'invalid';
|
170 |
+
|
171 |
+
return -1;
|
172 |
+
}
|
173 |
+
|
174 |
+
|
175 |
+
/*
|
176 |
+
* We return -1 to abort the transfer when we have enough buffered
|
177 |
+
* to find the size
|
178 |
+
*/
|
179 |
+
//
|
180 |
+
// hey curl! this is an error. But really we just are stopping cause
|
181 |
+
// we already have what we wwant
|
182 |
+
return -1;
|
183 |
+
});
|
184 |
+
|
185 |
+
return $ch;
|
186 |
+
}
|
187 |
+
}
|
includes/lib/fasterimage/ImageParser.php
ADDED
@@ -0,0 +1,377 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php namespace FasterImage;
|
2 |
+
|
3 |
+
use WillWashburn\Stream\Exception\StreamBufferTooSmallException;
|
4 |
+
use WillWashburn\Stream\Stream;
|
5 |
+
use WillWashburn\Stream\StreamableInterface;
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Parses the stream of the image and determines the size and type of the image
|
9 |
+
*
|
10 |
+
* @package FasterImage
|
11 |
+
*/
|
12 |
+
class ImageParser
|
13 |
+
{
|
14 |
+
/**
|
15 |
+
* The type of image we've determined this is
|
16 |
+
*
|
17 |
+
* @var string
|
18 |
+
*/
|
19 |
+
protected $type;
|
20 |
+
/**
|
21 |
+
* @var StreamableInterface $stream
|
22 |
+
*/
|
23 |
+
private $stream;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* ImageParser constructor.
|
27 |
+
*
|
28 |
+
* @param StreamableInterface $stream
|
29 |
+
*/
|
30 |
+
public function __construct(StreamableInterface & $stream)
|
31 |
+
{
|
32 |
+
$this->stream = $stream;
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* @return array|bool|null
|
37 |
+
*/
|
38 |
+
public function parseSize()
|
39 |
+
{
|
40 |
+
$this->stream->resetPointer();
|
41 |
+
|
42 |
+
switch ( $this->type ) {
|
43 |
+
case 'png':
|
44 |
+
return $this->parseSizeForPNG();
|
45 |
+
case 'ico':
|
46 |
+
case 'cur':
|
47 |
+
return $this->parseSizeForIco();
|
48 |
+
case 'gif':
|
49 |
+
return $this->parseSizeForGIF();
|
50 |
+
case 'bmp':
|
51 |
+
return $this->parseSizeForBMP();
|
52 |
+
case 'jpeg':
|
53 |
+
return $this->parseSizeForJPEG();
|
54 |
+
case 'tiff':
|
55 |
+
return $this->parseSizeForTiff();
|
56 |
+
case 'psd':
|
57 |
+
return $this->parseSizeForPSD();
|
58 |
+
case 'webp':
|
59 |
+
return $this->parseSizeForWebp();
|
60 |
+
}
|
61 |
+
|
62 |
+
return null;
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* @return array
|
67 |
+
*/
|
68 |
+
public function parseSizeForIco()
|
69 |
+
{
|
70 |
+
$this->stream->read(6);
|
71 |
+
|
72 |
+
$b1 = $this->getByte();
|
73 |
+
$b2 = $this->getByte();
|
74 |
+
|
75 |
+
return [
|
76 |
+
$b1 == 0 ? 256 : $b1,
|
77 |
+
$b2 == 0 ? 256 : $b2
|
78 |
+
];
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* @return array
|
83 |
+
*/
|
84 |
+
protected function parseSizeForPSD() {
|
85 |
+
|
86 |
+
$this->stream->read(14);
|
87 |
+
$sizes = unpack("N*",$this->stream->read(12));
|
88 |
+
|
89 |
+
return [
|
90 |
+
$sizes[2],
|
91 |
+
$sizes[1]
|
92 |
+
];
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Reads and returns the type of the image
|
97 |
+
*
|
98 |
+
* @return bool|string
|
99 |
+
*/
|
100 |
+
public function parseType()
|
101 |
+
{
|
102 |
+
if ( ! $this->type ) {
|
103 |
+
$this->stream->resetPointer();
|
104 |
+
|
105 |
+
switch ( $this->stream->read(2) ) {
|
106 |
+
case "BM":
|
107 |
+
return $this->type = 'bmp';
|
108 |
+
case "GI":
|
109 |
+
return $this->type = 'gif';
|
110 |
+
case chr(0xFF) . chr(0xd8):
|
111 |
+
return $this->type = 'jpeg';
|
112 |
+
case "\0\0":
|
113 |
+
switch ( $this->readByte($this->stream->peek(1)) ) {
|
114 |
+
case 1:
|
115 |
+
return $this->type = 'ico';
|
116 |
+
case 2:
|
117 |
+
return $this->type = 'cur';
|
118 |
+
}
|
119 |
+
|
120 |
+
return false;
|
121 |
+
|
122 |
+
case chr(0x89) . 'P':
|
123 |
+
return $this->type = 'png';
|
124 |
+
case "RI":
|
125 |
+
if ( substr($this->stream->read(10), 6, 4) == 'WEBP' ) {
|
126 |
+
return $this->type = 'webp';
|
127 |
+
}
|
128 |
+
|
129 |
+
return false;
|
130 |
+
case'8B':
|
131 |
+
return $this->type = 'psd';
|
132 |
+
case "II":
|
133 |
+
case "MM":
|
134 |
+
return $this->type = 'tiff';
|
135 |
+
default:
|
136 |
+
return false;
|
137 |
+
}
|
138 |
+
}
|
139 |
+
|
140 |
+
return $this->type;
|
141 |
+
}
|
142 |
+
|
143 |
+
/**
|
144 |
+
* @return array
|
145 |
+
*/
|
146 |
+
protected function parseSizeForBMP()
|
147 |
+
{
|
148 |
+
$chars = $this->stream->read(29);
|
149 |
+
$chars = substr($chars, 14, 14);
|
150 |
+
$type = unpack('C', $chars);
|
151 |
+
|
152 |
+
$size = (reset($type) == 40) ? unpack('l*', substr($chars, 4)) : unpack('l*', substr($chars, 4, 8));
|
153 |
+
|
154 |
+
return [
|
155 |
+
current($size),
|
156 |
+
abs(next($size))
|
157 |
+
];
|
158 |
+
}
|
159 |
+
|
160 |
+
/**
|
161 |
+
* @return array
|
162 |
+
*/
|
163 |
+
protected function parseSizeForGIF()
|
164 |
+
{
|
165 |
+
$chars = $this->stream->read(11);
|
166 |
+
|
167 |
+
$size = unpack("S*", substr($chars, 6, 4));
|
168 |
+
|
169 |
+
return [
|
170 |
+
current($size),
|
171 |
+
next($size)
|
172 |
+
];
|
173 |
+
}
|
174 |
+
|
175 |
+
/**
|
176 |
+
* @return array|bool
|
177 |
+
*/
|
178 |
+
protected function parseSizeForJPEG()
|
179 |
+
{
|
180 |
+
$state = null;
|
181 |
+
|
182 |
+
while ( true ) {
|
183 |
+
switch ( $state ) {
|
184 |
+
default:
|
185 |
+
$this->stream->read(2);
|
186 |
+
$state = 'started';
|
187 |
+
break;
|
188 |
+
|
189 |
+
case 'started':
|
190 |
+
$b = $this->getByte();
|
191 |
+
if ( $b === false ) return false;
|
192 |
+
|
193 |
+
$state = $b == 0xFF ? 'sof' : 'started';
|
194 |
+
break;
|
195 |
+
|
196 |
+
case 'sof':
|
197 |
+
$b = $this->getByte();
|
198 |
+
|
199 |
+
if ( $b === 0xe1 ) {
|
200 |
+
$data = $this->stream->read($this->readInt($this->stream->read(2)) - 2);
|
201 |
+
|
202 |
+
$stream = new Stream;
|
203 |
+
$stream->write($data);
|
204 |
+
|
205 |
+
if ( $stream->read(4) === 'Exif' ) {
|
206 |
+
|
207 |
+
$stream->read(2);
|
208 |
+
|
209 |
+
// Some Exif data is broken/wrong so we'll ignore
|
210 |
+
// any exceptions here
|
211 |
+
try {
|
212 |
+
$exif = new ExifParser($stream);
|
213 |
+
} catch (\Exception $e) {}
|
214 |
+
|
215 |
+
}
|
216 |
+
|
217 |
+
break;
|
218 |
+
}
|
219 |
+
|
220 |
+
if ( in_array($b, range(0xe0, 0xef)) ) {
|
221 |
+
$state = 'skipframe';
|
222 |
+
break;
|
223 |
+
}
|
224 |
+
|
225 |
+
if ( in_array($b, array_merge(range(0xC0, 0xC3), range(0xC5, 0xC7), range(0xC9, 0xCB), range(0xCD, 0xCF))) ) {
|
226 |
+
$state = 'readsize';
|
227 |
+
break;
|
228 |
+
}
|
229 |
+
if ( $b == 0xFF ) {
|
230 |
+
$state = 'sof';
|
231 |
+
break;
|
232 |
+
}
|
233 |
+
|
234 |
+
$state = 'skipframe';
|
235 |
+
break;
|
236 |
+
|
237 |
+
case 'skipframe':
|
238 |
+
$skip = $this->readInt($this->stream->read(2)) - 2;
|
239 |
+
$this->stream->read($skip);
|
240 |
+
$state = 'started';
|
241 |
+
break;
|
242 |
+
|
243 |
+
case 'readsize':
|
244 |
+
$c = $this->stream->read(7);
|
245 |
+
|
246 |
+
$size = array($this->readInt(substr($c, 5, 2)), $this->readInt(substr($c, 3, 2)));
|
247 |
+
|
248 |
+
if ( isset($exif) && $exif->isRotated() ) {
|
249 |
+
return array_reverse($size);
|
250 |
+
}
|
251 |
+
|
252 |
+
return $size;
|
253 |
+
}
|
254 |
+
}
|
255 |
+
|
256 |
+
return false;
|
257 |
+
}
|
258 |
+
|
259 |
+
/**
|
260 |
+
* @return array
|
261 |
+
*/
|
262 |
+
protected function parseSizeForPNG()
|
263 |
+
{
|
264 |
+
$chars = $this->stream->read(25);
|
265 |
+
|
266 |
+
$size = unpack("N*", substr($chars, 16, 8));
|
267 |
+
|
268 |
+
return [
|
269 |
+
current($size),
|
270 |
+
next($size)
|
271 |
+
];
|
272 |
+
|
273 |
+
}
|
274 |
+
|
275 |
+
/**
|
276 |
+
* @return array|bool
|
277 |
+
* @throws \FasterImage\Exception\InvalidImageException
|
278 |
+
* @throws StreamBufferTooSmallException
|
279 |
+
*/
|
280 |
+
protected function parseSizeForTiff()
|
281 |
+
{
|
282 |
+
$exif = new ExifParser($this->stream);
|
283 |
+
|
284 |
+
if ( $exif->isRotated() ) {
|
285 |
+
return [$exif->getHeight(), $exif->getWidth()];
|
286 |
+
}
|
287 |
+
|
288 |
+
return [$exif->getWidth(), $exif->getHeight()];
|
289 |
+
}
|
290 |
+
|
291 |
+
/**
|
292 |
+
* @return null
|
293 |
+
* @throws StreamBufferTooSmallException
|
294 |
+
*/
|
295 |
+
protected function parseSizeForWebp()
|
296 |
+
{
|
297 |
+
$vp8 = substr($this->stream->read(16), 12, 4);
|
298 |
+
$len = unpack("V", $this->stream->read(4));
|
299 |
+
|
300 |
+
switch ( trim($vp8) ) {
|
301 |
+
|
302 |
+
case 'VP8':
|
303 |
+
$this->stream->read(6);
|
304 |
+
|
305 |
+
$width = current(unpack("v", $this->stream->read(2)));
|
306 |
+
$height = current(unpack("v", $this->stream->read(2)));
|
307 |
+
|
308 |
+
return [
|
309 |
+
$width & 0x3fff,
|
310 |
+
$height & 0x3fff
|
311 |
+
];
|
312 |
+
|
313 |
+
case 'VP8L':
|
314 |
+
$this->stream->read(1);
|
315 |
+
|
316 |
+
$b1 = $this->getByte();
|
317 |
+
$b2 = $this->getByte();
|
318 |
+
$b3 = $this->getByte();
|
319 |
+
$b4 = $this->getByte();
|
320 |
+
|