PluginProbe
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization / 3.11.1
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization v3.11.1
4.2.13 4.2.12 4.2.11 4.2.10 4.2.9 4.2.8 4.2.7 4.2.6 4.2.5 2.5.5 2.5.6 2.5.7 3.0.0 3.0.1 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.11.0 3.11.1 3.11.2 3.11.3 3.12.0 3.12.1 All 134 releases
optimole-wp / inc / lazyload_replacer.php

lazyload_replacer.php in Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization 3.11.1, at inc/lazyload_replacer.php

588 lines 20.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * The class handles the img tag replacements for lazyload.
5 *
6 * @package \Optml\Inc
7 * @author Optimole <friends@optimole.com>
8 */
9 final class Optml_Lazyload_Replacer extends Optml_App_Replacer {
10 use Optml_Normalizer;
11 use Optml_Validator;
12
13 const IFRAME_PLACEHOLDER_CLASS = '
14 iframe[data-opt-src]:not([data-opt-lazy-loaded]) {
15 background-color: #ffffff;
16 background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2240%22%20height%3D%2240%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20style%3D%22-webkit-transform-origin%3A50%25%2050%25%3B-webkit-animation%3Aspin%201.5s%20linear%20infinite%3B-webkit-backface-visibility%3Ahidden%3Banimation%3Aspin%201.5s%20linear%20infinite%22%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20stroke-linejoin%3D%22round%22%20stroke-miterlimit%3D%221.414%22%3E%3Cdefs%3E%3Cstyle%3E%3C%21%5BCDATA%5B%40-webkit-keyframes%20spin%7Bfrom%7B-webkit-transform%3Arotate%280deg%29%7Dto%7B-webkit-transform%3Arotate%28-359deg%29%7D%7D%40keyframes%20spin%7Bfrom%7Btransform%3Arotate%280deg%29%7Dto%7Btransform%3Arotate%28-359deg%29%7D%7D%5D%5D%3E%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22outer%22%3E%3Cpath%20d%3D%22M20%200a3.994%203.994%200%20110%207.988A3.994%203.994%200%200120%200z%22%2F%3E%3Cpath%20d%3D%22M5.858%205.858a3.994%203.994%200%20115.648%205.648%203.994%203.994%200%2001-5.648-5.648z%22%20fill%3D%22%23d2d2d2%22%2F%3E%3Cpath%20d%3D%22M20%2032.012A3.994%203.994%200%201120%2040a3.994%203.994%200%20010-7.988z%22%20fill%3D%22%23828282%22%2F%3E%3Cpath%20d%3D%22M28.494%2028.494a3.994%203.994%200%20115.648%205.648%203.994%203.994%200%2001-5.648-5.648z%22%20fill%3D%22%23656565%22%2F%3E%3Cpath%20d%3D%22M3.994%2016.006a3.994%203.994%200%20110%207.988%203.994%203.994%200%20010-7.988z%22%20fill%3D%22%23bbb%22%2F%3E%3Cpath%20d%3D%22M5.858%2028.494a3.994%203.994%200%20115.648%205.648%203.994%203.994%200%2001-5.648-5.648z%22%20fill%3D%22%23a4a4a4%22%2F%3E%3Cpath%20d%3D%22M36.006%2016.006a3.994%203.994%200%20110%207.988%203.994%203.994%200%20010-7.988z%22%20fill%3D%22%234a4a4a%22%2F%3E%3Cpath%20d%3D%22M28.494%205.858a3.994%203.994%200%20115.648%205.648%203.994%203.994%200%2001-5.648-5.648z%22%20fill%3D%22%23323232%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
17 background-repeat: no-repeat;
18 background-position: 50% 50%;
19 }
20 video[data-opt-src]:not([data-opt-lazy-loaded]) {
21 background-color: #ffffff;
22 background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2240%22%20height%3D%2240%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20style%3D%22-webkit-transform-origin%3A50%25%2050%25%3B-webkit-animation%3Aspin%201.5s%20linear%20infinite%3B-webkit-backface-visibility%3Ahidden%3Banimation%3Aspin%201.5s%20linear%20infinite%22%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20stroke-linejoin%3D%22round%22%20stroke-miterlimit%3D%221.414%22%3E%3Cdefs%3E%3Cstyle%3E%3C%21%5BCDATA%5B%40-webkit-keyframes%20spin%7Bfrom%7B-webkit-transform%3Arotate%280deg%29%7Dto%7B-webkit-transform%3Arotate%28-359deg%29%7D%7D%40keyframes%20spin%7Bfrom%7Btransform%3Arotate%280deg%29%7Dto%7Btransform%3Arotate%28-359deg%29%7D%7D%5D%5D%3E%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22outer%22%3E%3Cpath%20d%3D%22M20%200a3.994%203.994%200%20110%207.988A3.994%203.994%200%200120%200z%22%2F%3E%3Cpath%20d%3D%22M5.858%205.858a3.994%203.994%200%20115.648%205.648%203.994%203.994%200%2001-5.648-5.648z%22%20fill%3D%22%23d2d2d2%22%2F%3E%3Cpath%20d%3D%22M20%2032.012A3.994%203.994%200%201120%2040a3.994%203.994%200%20010-7.988z%22%20fill%3D%22%23828282%22%2F%3E%3Cpath%20d%3D%22M28.494%2028.494a3.994%203.994%200%20115.648%205.648%203.994%203.994%200%2001-5.648-5.648z%22%20fill%3D%22%23656565%22%2F%3E%3Cpath%20d%3D%22M3.994%2016.006a3.994%203.994%200%20110%207.988%203.994%203.994%200%20010-7.988z%22%20fill%3D%22%23bbb%22%2F%3E%3Cpath%20d%3D%22M5.858%2028.494a3.994%203.994%200%20115.648%205.648%203.994%203.994%200%2001-5.648-5.648z%22%20fill%3D%22%23a4a4a4%22%2F%3E%3Cpath%20d%3D%22M36.006%2016.006a3.994%203.994%200%20110%207.988%203.994%203.994%200%20010-7.988z%22%20fill%3D%22%234a4a4a%22%2F%3E%3Cpath%20d%3D%22M28.494%205.858a3.994%203.994%200%20115.648%205.648%203.994%203.994%200%2001-5.648-5.648z%22%20fill%3D%22%23323232%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
23 background-repeat: no-repeat;
24 background-position: 50% 50%;
25 }';
26 const IFRAME_PLACEHOLDER_STYLE = '<style type="text/css">' . self::IFRAME_PLACEHOLDER_CLASS . '</style>';
27
28 const IFRAME_TEMP_COMMENT = '/** optmliframelazyloadplaceholder */';
29
30 const SVG_PLACEHOLDER = 'data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%20#width#%20#height#%22%20width%3D%22#width#%22%20height%3D%22#height#%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Crect%20width%3D%22#width#%22%20height%3D%22#height#%22%20fill%3D%22#fill#%22%2F%3E%3C%2Fsvg%3E';
31 /**
32 * If frame lazyload is present on page.
33 *
34 * @var bool Whether or not at least one iframe has been lazyloaded.
35 */
36 private static $found_iframe = false;
37 /**
38 * Cached object instance.
39 *
40 * @var Optml_Lazyload_Replacer
41 */
42 protected static $instance = null;
43 /**
44 * Holds the number of images to skip from lazyload.
45 *
46 * @var integer The number image tags to skip.
47 */
48 private static $skip_lazyload_images = null;
49 /**
50 * Holds classes for listening to lazyload on background.
51 *
52 * @var array Lazyload background classes.
53 */
54 private static $lazyload_background_classes = null;
55 /**
56 * Selectors used for background lazyload.
57 *
58 * @var array Lazyload background CSS selectors.
59 */
60 private static $background_lazyload_selectors = null;
61 /**
62 * Holds flags which remove noscript tag bundle causing issues on render, i.e slider plugins.
63 *
64 * @var array Noscript flags.
65 */
66 private static $ignore_no_script_flags = null;
67 /**
68 * Holds possible iframe lazyload flags where we should ignore our lazyload.
69 *
70 * @var array
71 */
72 protected static $iframe_lazyload_flags = null;
73 /**
74 * Holds classes responsabile for watching lazyload behaviour.
75 *
76 * @var array Lazyload classes.
77 */
78 private static $lazyload_watcher_classes = null;
79 /**
80 * Should we use the generic placeholder?
81 *
82 * @var bool Lazyload placeholder flag.
83 */
84 private static $is_lazyload_placeholder = false;
85
86 /**
87 * Class instance method.
88 *
89 * @codeCoverageIgnore
90 * @static
91 * @return Optml_Lazyload_Replacer
92 * @since 1.0.0
93 * @access public
94 */
95 public static function instance() {
96 if ( null === self::$instance ) {
97 self::$instance = new self();
98 add_action( 'optml_replacer_setup', [ self::$instance, 'init' ] );
99 }
100
101 return self::$instance;
102 }
103
104 /**
105 * Return lazyload selectors for background images.
106 *
107 * @return array Lazyload selectors.
108 */
109 public static function get_background_lazyload_selectors() {
110 if ( null !== self::$background_lazyload_selectors ) {
111 return self::$background_lazyload_selectors;
112 }
113
114 if ( self::instance()->settings->get( 'bg_replacer' ) === 'disabled' ) {
115 self::$background_lazyload_selectors = [];
116 return self::$background_lazyload_selectors;
117 }
118 $default_watchers = [
119 '.elementor-section[data-settings*="background_background"]',
120 '.elementor-section > .elementor-background-overlay',
121 '[class*="wp-block-cover"][style*="background-image"]',
122 ];
123
124 $saved_watchers = self::instance()->settings->get_watchers();
125
126 $saved_watchers = str_replace( [ "\n", "\r" ], ',', $saved_watchers );
127 $saved_watchers = explode( ',', $saved_watchers );
128 $all_watchers = array_merge( $default_watchers, $saved_watchers );
129 $all_watchers = apply_filters( 'optml_lazyload_bg_selectors', $all_watchers );
130 $all_watchers = array_filter(
131 $all_watchers,
132 function ( $value ) {
133 return ! empty( $value ) && strlen( $value ) >= 2;
134 }
135 );
136
137 self::$background_lazyload_selectors = $all_watchers;
138
139 return self::$background_lazyload_selectors;
140 }
141
142 /**
143 * Returns background classes for lazyload.
144 *
145 * @return array
146 */
147 public static function get_lazyload_bg_classes() {
148 if ( null !== self::$lazyload_background_classes ) {
149 return self::$lazyload_background_classes;
150 }
151
152 self::$lazyload_background_classes = apply_filters( 'optml_lazyload_bg_classes', [] );
153
154 return self::$lazyload_background_classes;
155 }
156 /**
157 * Returns the number of images to skip from lazyload.
158 *
159 * @return integer
160 */
161 public static function get_skip_lazyload_limit() {
162
163 if ( self::$skip_lazyload_images !== null ) {
164 return self::$skip_lazyload_images;
165 }
166 self::$skip_lazyload_images = apply_filters( 'optml_lazyload_images_skip', self::instance()->settings->get( 'skip_lazyload_images' ) );
167 return self::$skip_lazyload_images;
168 }
169 /**
170 * Returns classes for lazyload additional watch.
171 *
172 * @return array
173 */
174 public static function get_watcher_lz_classes() {
175 if ( null !== self::$lazyload_watcher_classes ) {
176 return self::$lazyload_watcher_classes;
177 }
178
179 self::$lazyload_watcher_classes = apply_filters( 'optml_watcher_lz_classes', [] );
180
181 return self::$lazyload_watcher_classes;
182 }
183
184 /**
185 * The initialize method.
186 */
187 public function init() {
188 parent::init();
189
190 if ( ! $this->settings->use_lazyload() ) {
191 return;
192 }
193 $filters = $this->settings->get_filters();
194 if ( ! Optml_Filters::should_do_page( $filters[ Optml_Settings::FILTER_TYPE_LAZYLOAD ][ Optml_Settings::FILTER_URL ], $filters[ Optml_Settings::FILTER_TYPE_LAZYLOAD ][ Optml_Settings::FILTER_URL_MATCH ] ) ) {
195 return;
196 }
197
198 add_filter(
199 'max_srcset_image_width',
200 function () {
201 return 1;
202 }
203 );
204 self::$is_lazyload_placeholder = self::$instance->settings->get( 'lazyload_placeholder' ) === 'enabled';
205
206 add_filter( 'optml_tag_replace', [ $this, 'lazyload_tag_replace' ], 2, 6 );
207
208 add_filter( 'optml_video_replace', [$this, 'lazyload_video_replace'], 2, 1 );
209
210 }
211 /**
212 * Check if there are lazyloaded iframes.
213 *
214 * @return bool Whether an iframe was lazyloaded on the page or not.
215 */
216 public static function found_iframe() {
217 return self::$found_iframe;
218 }
219
220 /**
221 * Check if the img tag should be lazyloaded early.
222 *
223 * @param string $image_tag The image tag.
224 * @return bool Whether the image tag should be lazyloaded early or not.
225 */
226 public function should_lazyload_early( $image_tag ) {
227 $flags = apply_filters( 'optml_lazyload_early_flags', [] );
228
229 foreach ( $flags as $flag ) {
230 if ( strpos( $image_tag, $flag ) !== false ) {
231 return true;
232 }
233 }
234
235 return false;
236 }
237 /**
238 * Replaces the tags with lazyload tags.
239 *
240 * @param string $new_tag The new tag.
241 * @param string $original_url The original URL.
242 * @param string $new_url The optimized URL.
243 * @param array $optml_args Options passed for URL optimization.
244 * @param bool $is_slashed If the url needs slashes.
245 * @param string $full_tag Full tag, wrapper included.
246 *
247 * @return string
248 */
249 public function lazyload_tag_replace( $new_tag, $original_url, $new_url, $optml_args, $is_slashed = false, $full_tag = '' ) {
250
251 if ( ! $this->can_lazyload_for( $original_url, $full_tag ) ) {
252 return Optml_Tag_Replacer::instance()->regular_tag_replace( $new_tag, $original_url, $new_url, $optml_args, $is_slashed );
253 }
254
255 if ( self::instance()->settings->get( 'native_lazyload' ) === 'enabled' ) {
256 if ( strpos( $new_tag, 'loading=' ) === false ) {
257 $new_tag = preg_replace( '/<img/im', $is_slashed ? '<img loading=\"lazy\"' : '<img loading="lazy"', $new_tag );
258 }
259 return $new_tag;
260 }
261
262 $should_ignore_rescale = ! $this->is_valid_mimetype_from_url( $original_url, [ 'gif' => true, 'svg' => true ] );
263
264 if ( ! self::$is_lazyload_placeholder && ! $should_ignore_rescale ) {
265 $optml_args['quality'] = 'eco';
266 $optml_args['resize'] = [];
267 $low_url = apply_filters( 'optml_content_url', $original_url, $optml_args );
268 $low_url = $is_slashed ? addcslashes( $low_url, '/' ) : $low_url;
269 } else {
270 $low_url = $this->get_svg_for(
271 isset( $optml_args['width'] ) ? $optml_args['width'] : '100%',
272 isset( $optml_args['height'] ) ? $optml_args['height'] : '100%',
273 ( $should_ignore_rescale ? null : $original_url )
274 );
275 }
276
277 $opt_format = '';
278
279 if ( $this->should_add_data_tag( $full_tag ) ) {
280 $opt_format = ' data-opt-src="%s" ';
281 $custom_class = '';
282
283 if ( $should_ignore_rescale ) {
284 $custom_class .= 'optimole-lazy-only ';
285 }
286 if ( $this->should_lazyload_early( $full_tag ) ) {
287 $custom_class .= 'optimole-load-early';
288 }
289
290 if ( ! empty( $custom_class ) ) {
291 if ( strpos( $new_tag, 'class=' ) === false ) {
292 $opt_format .= ' class="' . $custom_class . '" ';
293 } else {
294 $new_tag = str_replace(
295 ( $is_slashed ? 'class=\"' : 'class="' ),
296 ( $is_slashed ? 'class=\"' . $custom_class . ' ' : 'class="' . $custom_class . ' ' ),
297 $new_tag
298 );
299 }
300 }
301 $opt_format = $is_slashed ? addslashes( $opt_format ) : $opt_format;
302 }
303 $new_url = $is_slashed ? addcslashes( $new_url, '/' ) : $new_url;
304
305 $opt_src = sprintf( $opt_format, $new_url );
306
307 $no_script_tag = str_replace(
308 $original_url,
309 $new_url,
310 $new_tag
311 );
312 $new_tag = preg_replace(
313 [
314 '/((?:\s|\'|"){1,}src(?>=|"|\'|\s|\\\\)*)' . preg_quote( $original_url, '/' ) . '/m',
315 '/<img/im',
316 ],
317 [
318 "$1$low_url",
319 '<img' . $opt_src,
320 ],
321 $new_tag,
322 1
323 );
324 $new_tag = str_replace( 'srcset=', 'old-srcset=', $new_tag );
325
326 if ( ! $this->should_add_noscript( $new_tag ) ) {
327 return $new_tag;
328 }
329
330 return $new_tag . '<noscript>' . $no_script_tag . '</noscript>';
331 }
332 /**
333 * Replaces video embeds with lazyload embeds.
334 *
335 * @param string $content Html page content.
336 *
337 * @return string
338 */
339 public function lazyload_video_replace( $content ) {
340 $video_tags = [];
341 $iframes = [];
342 $videos = [];
343 preg_match_all( '#(?:<noscript\s*>\s*)?<iframe(.*?)></iframe>(?:\s*</noscript\s*>)?#is', $content, $iframes );
344 preg_match_all( '#(?:<noscript\s*>\s*)?<video(.*?)>.*?</video>(?:\s*</noscript\s*>)?#is', $content, $videos );
345 $video_tags = array_merge( $iframes[0], $videos[0] );
346
347 $search = [];
348 $replace = [];
349
350 foreach ( $video_tags as $video_tag ) {
351
352 if ( ! $this->should_lazyload_iframe( $video_tag ) ) {
353 continue;
354 }
355 if ( preg_match( "/ data-opt-src=['\"]/is", $video_tag ) ) {
356 continue;
357 }
358 $should_add_noscript = true;
359 $original_tag = $video_tag;
360 // replace the src and add the data-opt-src attribute
361 if ( strpos( $video_tag, 'iframe' ) !== false ) {
362 $video_tag = preg_replace( '/iframe(.*?)src=/is', 'iframe$1 src="about:blank" data-opt-src=', $video_tag );
363 } elseif ( strpos( $video_tag, 'video' ) !== false ) {
364 if ( strpos( $video_tag, 'source' ) !== false ) {
365 if ( strpos( $video_tag, 'preload' ) === false ) {
366 $video_tag = preg_replace( '/video(.*?)>/is', 'video$1 preload="metadata">', $video_tag, 1 );
367 $should_add_noscript = false;
368 } else {
369 continue;
370 }
371 } else {
372 $video_tag = preg_replace( '/video(.*?)src=/is', 'video$1 data-opt-src=', $video_tag );
373 }
374 }
375 if ( $this->should_add_noscript( $video_tag ) && $should_add_noscript ) {
376 $video_tag .= '<noscript>' . $original_tag . '</noscript>';
377 }
378 array_push( $search, $original_tag );
379 array_push( $replace, $video_tag );
380 self::$found_iframe = true;
381 }
382 $search = array_unique( $search );
383 $replace = array_unique( $replace );
384 $content = str_replace( $search, $replace, $content );
385 return $content;
386 }
387
388 /**
389 * Check if the lazyload is allowed for this url.
390 *
391 * @param string $url Url.
392 * @param string $tag Html tag.
393 *
394 * @return bool We can lazyload?
395 */
396 public function can_lazyload_for( $url, $tag = '' ) {
397 foreach ( self::possible_lazyload_flags() as $banned_string ) {
398 if ( strpos( $tag, $banned_string ) !== false ) {
399 return false;
400 }
401 }
402 if ( false === Optml_Filters::should_do_image( $url, self::$filters[ Optml_Settings::FILTER_TYPE_LAZYLOAD ][ Optml_Settings::FILTER_FILENAME ] ) ) {
403 return false;
404 }
405 $url = strtok( $url, '?' );
406
407 $type = wp_check_filetype(
408 basename( $url ),
409 Optml_Config::$image_extensions
410 );
411
412 if ( empty( $type['ext'] ) ) {
413 return false;
414 }
415
416 if ( false === Optml_Filters::should_do_extension( self::$filters[ Optml_Settings::FILTER_TYPE_LAZYLOAD ][ Optml_Settings::FILTER_EXT ], $type['ext'] ) ) {
417 return false;
418 }
419
420 if ( defined( 'OPTML_DISABLE_PNG_LAZYLOAD' ) && OPTML_DISABLE_PNG_LAZYLOAD ) {
421 return $type['ext'] !== 'png';
422 }
423 if ( Optml_Tag_Replacer::$lazyload_skipped_images < self::get_skip_lazyload_limit() ) {
424 return false;
425 }
426 return true;
427 }
428
429 /**
430 * Check if we should add the data-opt-tag.
431 *
432 * @param string $tag Html tag.
433 *
434 * @return bool Should add?
435 */
436 public function should_add_data_tag( $tag ) {
437 foreach ( self::possible_data_ignore_flags() as $banned_string ) {
438 if ( strpos( $tag, $banned_string ) !== false ) {
439 return false;
440 }
441 }
442
443 return true;
444 }
445
446 /**
447 * Get SVG markup with specific width/height.
448 *
449 * @param int|string $width Markup Width.
450 * @param int|string $height Markup Height.
451 * @param string|null $url Original URL.
452 *
453 * @return string SVG code.
454 */
455 public function get_svg_for( $width, $height, $url = null ) {
456
457 if ( $url !== null && ! is_numeric( $width ) ) {
458 $url = strtok( $url, '?' );
459 $key = crc32( $url );
460 $sizes = wp_cache_get( $key, 'optml_sources' );
461 if ( $sizes === false ) {
462 $filepath = substr( $url, strpos( $url, $this->upload_resource['content_folder'] ) + $this->upload_resource['content_folder_length'] );
463 $filepath = WP_CONTENT_DIR . $filepath;
464 if ( is_file( $filepath ) ) {
465 $sizes = getimagesize( $filepath );
466 wp_cache_add( $key, [ $sizes[0], $sizes[1] ], 'optml_sources', DAY_IN_SECONDS );
467 }
468 }
469 list( $width, $height ) = $sizes;
470 }
471
472 $width = ! is_numeric( $width ) ? '100%' : $width;
473 $height = ! is_numeric( $height ) ? '100%' : $height;
474 $fill = $this->settings->get( 'placeholder_color' );
475
476 if ( empty( $fill ) ) {
477 $fill = 'transparent';
478 }
479
480 return
481 str_replace(
482 [ '#width#', '#height#', '#fill#' ],
483 [
484 $width,
485 $height,
486 urlencode( $fill ),
487 ],
488 self::SVG_PLACEHOLDER
489 );
490 }
491
492 /**
493 * Check if we should add the noscript tag.
494 *
495 * @param string $tag Html tag.
496 *
497 * @return bool Should add?
498 */
499 public function should_add_noscript( $tag ) {
500 if ( $this->settings->get( 'no_script' ) === 'disabled' ) {
501 return false;
502 }
503 foreach ( self::get_ignore_noscript_flags() as $banned_string ) {
504 if ( strpos( $tag, $banned_string ) !== false ) {
505 return false;
506 }
507 }
508
509 return true;
510 }
511 /**
512 * Check if we should lazyload iframe.
513 *
514 * @param string $tag Html tag.
515 *
516 * @return bool Should add?
517 */
518 public function should_lazyload_iframe( $tag ) {
519
520 foreach ( self::get_iframe_lazyload_flags() as $banned_string ) {
521 if ( strpos( $tag, $banned_string ) !== false ) {
522 return false;
523 }
524 }
525
526 return true;
527 }
528
529 /**
530 * Returns flags for ignoring noscript tag additional watch.
531 *
532 * @return array
533 */
534 public static function get_ignore_noscript_flags() {
535 if ( null !== self::$ignore_no_script_flags ) {
536 return self::$ignore_no_script_flags;
537 }
538
539 self::$ignore_no_script_flags = apply_filters( 'optml_ignore_noscript_on', [] );
540
541 return self::$ignore_no_script_flags;
542 }
543 /**
544 * Returns possible lazyload flags for iframes.
545 *
546 * @return array
547 */
548 public static function get_iframe_lazyload_flags() {
549 if ( null !== self::$iframe_lazyload_flags ) {
550 return self::$iframe_lazyload_flags;
551 }
552
553 self::$iframe_lazyload_flags = self::possible_lazyload_flags();
554 self::$iframe_lazyload_flags = array_merge( self::$iframe_lazyload_flags, apply_filters( 'optml_iframe_lazyload_flags', [ 'gform_ajax_frame', '<noscript', 'recaptcha', '-src' ] ) );
555
556 return self::$iframe_lazyload_flags;
557 }
558 /**
559 * Throw error on object clone
560 *
561 * The whole idea of the singleton design pattern is that there is a single
562 * object therefore, we don't want the object to be cloned.
563 *
564 * @codeCoverageIgnore
565 * @access public
566 * @return void
567 * @since 1.0.0
568 */
569 public function __clone() {
570 // Cloning instances of the class is forbidden.
571 _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin&#8217; huh?', 'optimole-wp' ), '1.0.0' );
572 }
573
574 /**
575 * Disable unserializing of the class
576 *
577 * @codeCoverageIgnore
578 * @access public
579 * @return void
580 * @since 1.0.0
581 */
582 public function __wakeup() {
583 // Unserializing instances of the class is forbidden.
584 _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin&#8217; huh?', 'optimole-wp' ), '1.0.0' );
585 }
586
587 }
588