-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclass-youtube-oembed-lazy-load.php
161 lines (136 loc) · 5.35 KB
/
class-youtube-oembed-lazy-load.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit( 0 );
}
/**
* YouTube_oEmbed_Lazy_Load
*/
class YouTube_oEmbed_Lazy_Load {
protected static $instance;
protected $version = '1.0.0';
/**
* Constructor.
*/
private function __construct() {
add_filter( 'oembed_dataparse', array( $this, 'render_oembed_html' ), 20, 3 );
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_styles' ) );
add_filter( 'mce_css', array( $this, 'editor_styles' ), 10, 1 );
}
/**
* Get class instance.
*
* @return YouTube_oEmbed_Lazy_Load
*/
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new YouTube_oEmbed_Lazy_Load();
}
return self::$instance;
}
/**
* Enqueue CSS and JavaScript files.
*/
public function enqueue_styles() {
wp_enqueue_style( 'fontawesome', 'https://use.fontawesome.com/releases/v5.6.1/css/all.css', false, YOUTUBE_OEMBED_LAZY_LOAD_VERSION );
wp_enqueue_style( 'yt-oembed-lazyload', plugins_url( 'assets/dist/css/youtube-oembed-lazy-load.css', __FILE__ ), false, YOUTUBE_OEMBED_LAZY_LOAD_VERSION );
wp_enqueue_script( 'yt-oembed-lazyload', plugins_url( 'assets/dist/js/youtube-oembed-lazy-load.js', __FILE__ ), false, YOUTUBE_OEMBED_LAZY_LOAD_VERSION );
}
/**
* Add stylesheets to the WP (classic) editor.
*
* @param string $stylesheets Comma seperated list of stylesheet URL's.
* @return string
*/
public function editor_styles( $stylesheets ) {
return $stylesheets . ',' . implode(
',',
array(
plugins_url( 'assets/dist/css/youtube-oembed-lazy-load.css', __FILE__ ),
'https://use.fontawesome.com/releases/v5.6.1/css/all.css',
)
);
}
/**
* Clear YouTube oEmbed caches.
*/
public function clear_youtube_oembed_cache() {
global $wpdb;
// Get all post_meta with a YouTube oEmbed code.
$query = "SELECT meta_id, meta_key, meta_value FROM $wpdb->postmeta WHERE $wpdb->postmeta.meta_key LIKE '_oembed_%' AND $wpdb->postmeta.meta_value LIKE '%youtube%';";
$results = $wpdb->get_results( $query, OBJECT );
// Create a list of all meta_keys we have to remove.
$where_clauses = array();
foreach ( $results as $result ) {
$oembed_hash = str_replace( '_oembed_', '', $result->meta_key );
$where_clauses[] = '_oembed_' . $oembed_hash;
$where_clauses[] = '_oembed_time_' . $oembed_hash;
}
// Delete all oEmbed caches which contain YouTube data.
if ( ! empty( $where_clauses ) ) {
$query = "DELETE FROM $wpdb->postmeta WHERE $wpdb->postmeta.meta_key IN (" . implode( ', ', array_fill( 0, count( $where_clauses ), '%s' ) ) . ')';
if ( false === $wpdb->query( call_user_func_array( array( $wpdb, 'prepare' ), array_merge( array( $query ), $where_clauses ) ) ) ) {
// @todo logging?
}
}
}
/**
* Embed YouTube only with a still image until someone clicks on the image.
* Only then the YouTube iframe is loaded.
*
* @param string $return HTML which is the oEmbed data.
* @param object $data Data received from the oEmbed API.
* @param string $url Original URL that was embedded.
*
* @return string HTML oEmbed code.
*/
public function render_oembed_html( $return, $data, $url ) {
if ( 'YouTube' !== $data->provider_name ) {
return $return;
}
// we are going to parse HTML with the PHP DOM classes.
$dom = new DOMDocument();
// load the WordPress post.
$dom->loadHTML( $return, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD );
// regular expression to find any Youtube URL's + the video ID.
$youtube_regex = '@https?://(www\.)?youtu(\.be|be(-nocookie)?\.com)/(embed/)?([^/"?]+)@i';
// loop all iframes for possible YouTube video's.
foreach ( $dom->getElementsByTagName( 'iframe' ) as $iframe ) {
// only alter iframes with an YouTube URL.
if ( preg_match( $youtube_regex, $iframe->getAttribute( 'src' ), $matches ) ) {
// YouTube movie ID.
$video_id = $matches[5];
// YouTube video src url.
$youtube_src = $iframe->getAttribute( 'src' );
// get thumbnail url and calculate aspect ratio.
$thumbnail_url = $data->thumbnail_url;
$aspect_ratio = floor( $data->height * 100 / $data->width );
if ( $aspect_ratio > 50 && $aspect_ratio < 60 ) {
$aspect_ratio = '56.25';
$aspect_ratio_class = 'aspect-ratio-16x9';
} else {
$aspect_ratio = '75';
$aspect_ratio_class = 'aspect-ratio-4x3';
}
// create dom node for image still.
$img_still = $dom->createElement( 'span' );
$img_still->setAttribute( 'class', 'youtube-still ' . $aspect_ratio_class );
$img_still->setAttribute( 'style', 'padding-top: ' . $aspect_ratio . "%; background-image: url('" . $thumbnail_url . "');" );
$img_still->setAttribute( 'data-id', $video_id );
// create empty div to load the YouTube player in.
$div = $dom->createElement( 'div' );
$div->setAttribute( 'id', 'youtube-' . $video_id );
// create empty container div for the YouTube iframe.
$container_div = $dom->createElement( 'div' );
$container_div->setAttribute( 'class', 'yt-iframe-container ' . $aspect_ratio_class );
$container_div->setAttribute( 'style', 'display:none;' );
$container_div->appendChild( $div );
// insert still and div node.
$iframe->parentNode->insertBefore( $img_still, $iframe );
$iframe->parentNode->insertBefore( $container_div, $iframe );
// remove the iframe node.
$iframe->parentNode->removeChild( $iframe );
}
}
return $dom->saveHTML();
}
}