PluginProbe
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization / trunk
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization vtrunk
4.2.14 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 All 135 releases
← All changes | inc/lazyload_replacer.php +178 -61 3.1.0 → trunk View file →
@@ -1,6 +1,9 @@
1 1 <?php
2 2
3 +use OptimoleWP\PageProfiler\Profile;
4 +use OptimoleWP\Preload\Links;
5 +
3 6 /**
4 7 * The class handles the img tag replacements for lazyload.
5 8 *
6 9 * @package \Optml\Inc
@@ -8,8 +11,9 @@
8 11 */
9 12 final class Optml_Lazyload_Replacer extends Optml_App_Replacer {
10 13 use Optml_Normalizer;
11 14 use Optml_Validator;
15 + use Optml_Dam_Offload_Utils;
12 16
13 17 const IFRAME_PLACEHOLDER_CLASS = '
14 18 iframe[data-opt-src]:not([data-opt-lazy-loaded]) {
15 19 background-color: #ffffff;
@@ -26,9 +30,9 @@
26 30 const IFRAME_PLACEHOLDER_STYLE = '<style type="text/css">' . self::IFRAME_PLACEHOLDER_CLASS . '</style>';
27 31
28 32 const IFRAME_TEMP_COMMENT = '/** optmliframelazyloadplaceholder */';
29 33
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%3C%2Fsvg%3E';
34 + 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 35 /**
32 36 * If frame lazyload is present on page.
33 37 *
34 38 * @var bool Whether or not at least one iframe has been lazyloaded.
@@ -36,9 +40,9 @@
36 40 private static $found_iframe = false;
37 41 /**
38 42 * Cached object instance.
39 43 *
40 - * @var Optml_Tag_Replacer
44 + * @var Optml_Lazyload_Replacer
41 45 */
42 46 protected static $instance = null;
43 47 /**
44 48 * Holds the number of images to skip from lazyload.
@@ -81,13 +85,8 @@
81 85 *
82 86 * @var bool Lazyload placeholder flag.
83 87 */
84 88 private static $is_lazyload_placeholder = false;
85 - /**
86 - * Holds flags which remove noscript tag bundle causing issues on render, i.e slider plugins.
87 - *
88 - * @var array Noscript flags.
89 - */
90 89
91 90 /**
92 91 * Class instance method.
93 92 *
@@ -92,9 +91,9 @@
92 91 * Class instance method.
93 92 *
94 93 * @codeCoverageIgnore
95 94 * @static
96 - * @return Optml_Tag_Replacer
95 + * @return Optml_Lazyload_Replacer
97 96 * @since 1.0.0
98 97 * @access public
99 98 */
100 99 public static function instance() {
@@ -111,21 +110,26 @@
111 110 *
112 111 * @return array Lazyload selectors.
113 112 */
114 113 public static function get_background_lazyload_selectors() {
114 + if ( null !== self::$background_lazyload_selectors ) {
115 + return self::$background_lazyload_selectors;
116 + }
115 117
116 - if ( ! empty( self::$background_lazyload_selectors ) && is_array( self::$background_lazyload_selectors ) ) {
118 + if ( self::instance()->settings === null ) {
119 + self::$background_lazyload_selectors = [];
120 +
117 121 return self::$background_lazyload_selectors;
118 122 }
119 123 if ( self::instance()->settings->get( 'bg_replacer' ) === 'disabled' ) {
120 124 self::$background_lazyload_selectors = [];
121 -
122 125 return self::$background_lazyload_selectors;
123 126 }
124 127 $default_watchers = [
125 - '.elementor-section[data-settings*="background_background"]',
126 - '.elementor-section > .elementor-background-overlay',
127 - '.wp-block-cover[style*="background-image"]',
128 + '[class*="wp-block-cover"][style*="background-image"]',
129 + '[style*="background-image:url("]', '[style*="background-image: url("]',
130 + '[style*="background:url("]', '[style*="background: url("]',
131 + '[class*="wp-block-group"][style*="background-image"]',
128 132 ];
129 133
130 134 $saved_watchers = self::instance()->settings->get_watchers();
131 135
@@ -150,10 +154,9 @@
150 154 *
151 155 * @return array
152 156 */
153 157 public static function get_lazyload_bg_classes() {
154 -
155 - if ( ! empty( self::$lazyload_background_classes ) && is_array( self::$lazyload_background_classes ) ) {
158 + if ( null !== self::$lazyload_background_classes ) {
156 159 return self::$lazyload_background_classes;
157 160 }
158 161
159 162 self::$lazyload_background_classes = apply_filters( 'optml_lazyload_bg_classes', [] );
@@ -169,8 +172,9 @@
169 172
170 173 if ( self::$skip_lazyload_images !== null ) {
171 174 return self::$skip_lazyload_images;
172 175 }
176 +
173 177 self::$skip_lazyload_images = apply_filters( 'optml_lazyload_images_skip', self::instance()->settings->get( 'skip_lazyload_images' ) );
174 178 return self::$skip_lazyload_images;
175 179 }
176 180 /**
@@ -178,10 +182,9 @@
178 182 *
179 183 * @return array
180 184 */
181 185 public static function get_watcher_lz_classes() {
182 -
183 - if ( ! empty( self::$lazyload_watcher_classes ) && is_array( self::$lazyload_watcher_classes ) ) {
186 + if ( null !== self::$lazyload_watcher_classes ) {
184 187 return self::$lazyload_watcher_classes;
185 188 }
186 189
187 190 self::$lazyload_watcher_classes = apply_filters( 'optml_watcher_lz_classes', [] );
@@ -197,24 +200,18 @@
197 200
198 201 if ( ! $this->settings->use_lazyload() ) {
199 202 return;
200 203 }
201 - if ( ! Optml_Filters::should_do_page( self::$filters[ Optml_Settings::FILTER_TYPE_LAZYLOAD ][ Optml_Settings::FILTER_URL ] ) ) {
204 + $filters = $this->settings->get_filters();
205 + 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 ] ) ) {
202 206 return;
203 207 }
204 208
205 - add_filter(
206 - 'max_srcset_image_width',
207 - function () {
208 - return 1;
209 - }
210 - );
211 209 self::$is_lazyload_placeholder = self::$instance->settings->get( 'lazyload_placeholder' ) === 'enabled';
212 210
213 211 add_filter( 'optml_tag_replace', [ $this, 'lazyload_tag_replace' ], 2, 6 );
214 212
215 - add_filter( 'optml_video_replace', [$this, 'lazyload_video_replace'], 2, 1 );
216 -
213 + add_filter( 'optml_video_replace', [ $this, 'lazyload_video_replace' ], 2, 1 );
217 214 }
218 215 /**
219 216 * Check if there are lazyloaded iframes.
220 217 *
@@ -224,8 +221,25 @@
224 221 return self::$found_iframe;
225 222 }
226 223
227 224 /**
225 + * Check if the img tag should be lazyloaded early.
226 + *
227 + * @param string $image_tag The image tag.
228 + * @return bool Whether the image tag should be lazyloaded early or not.
229 + */
230 + public function should_lazyload_early( $image_tag ) {
231 + $flags = apply_filters( 'optml_lazyload_early_flags', [] );
232 +
233 + foreach ( $flags as $flag ) {
234 + if ( strpos( $image_tag, $flag ) !== false ) {
235 + return true;
236 + }
237 + }
238 +
239 + return false;
240 + }
241 + /**
228 242 * Replaces the tags with lazyload tags.
229 243 *
230 244 * @param string $new_tag The new tag.
231 245 * @param string $original_url The original URL.
@@ -238,16 +252,49 @@
238 252 */
239 253 public function lazyload_tag_replace( $new_tag, $original_url, $new_url, $optml_args, $is_slashed = false, $full_tag = '' ) {
240 254
241 255 if ( ! $this->can_lazyload_for( $original_url, $full_tag ) ) {
256 +
242 257 return Optml_Tag_Replacer::instance()->regular_tag_replace( $new_tag, $original_url, $new_url, $optml_args, $is_slashed );
243 258 }
259 + // Remove fetchpriority high attribute when the image is lazyloaded
260 + if ( strpos( $new_tag, 'fetchpriority' ) !== false ) {
261 + $new_tag = str_ireplace(
262 + [
263 + 'fetchpriority=high',
264 + 'fetchpriority="high"',
265 + "fetchpriority='high'",
266 + 'fetchpriority=\"high\"',
267 + "fetchpriority=\'high\'",
268 + ],
269 + '',
270 + $new_tag
271 + );
272 + }
273 +
274 + if ( self::instance()->settings->get( 'native_lazyload' ) === 'enabled' ) {
275 + // First check if loading attribute already exists
276 + if ( strpos( $new_tag, 'loading=' ) !== false ) {
277 + // Replace existing loading attribute with lazy
278 + $loading_attr = $is_slashed ? 'loading=\"lazy\"' : 'loading="lazy"';
279 + $new_tag = preg_replace( '/loading=(["\'])[^"\']*\1/i', $loading_attr, $new_tag );
280 + } else {
281 + // No loading attribute exists, add it after <img
282 + $loading_attr = $is_slashed ? ' loading=\"lazy\"' : ' loading="lazy"';
283 + $new_tag = preg_replace( '/<img/i', '<img' . $loading_attr, $new_tag, 1 );
284 + }
285 + return $new_tag;
286 + }
287 +
288 + // we remove the loading attribute if it exists with strpos
289 + $new_tag = preg_replace( '/loading=(["\'])[^"\']*\1/i', '', $new_tag );
290 +
244 291 $should_ignore_rescale = ! $this->is_valid_mimetype_from_url( $original_url, [ 'gif' => true, 'svg' => true ] );
245 292
246 293 if ( ! self::$is_lazyload_placeholder && ! $should_ignore_rescale ) {
247 294 $optml_args['quality'] = 'eco';
248 295 $optml_args['resize'] = [];
249 - $low_url = apply_filters( 'optml_content_url', $original_url, $optml_args );
296 + $low_url = apply_filters( 'optml_content_url', $this->get_unoptimized_url( $original_url ), $optml_args );
250 297 $low_url = $is_slashed ? addcslashes( $low_url, '/' ) : $low_url;
251 298 } else {
252 299 $low_url = $this->get_svg_for(
253 300 isset( $optml_args['width'] ) ? $optml_args['width'] : '100%',
@@ -254,20 +301,28 @@
254 301 isset( $optml_args['height'] ) ? $optml_args['height'] : '100%',
255 302 ( $should_ignore_rescale ? null : $original_url )
256 303 );
257 304 }
258 -
259 305 $opt_format = '';
260 306
261 307 if ( $this->should_add_data_tag( $full_tag ) ) {
262 308 $opt_format = ' data-opt-src="%s" ';
309 + $custom_class = '';
310 +
263 311 if ( $should_ignore_rescale ) {
312 + $custom_class .= 'optimole-lazy-only ';
313 + }
314 + if ( $this->should_lazyload_early( $full_tag ) ) {
315 + $custom_class .= 'optimole-load-early';
316 + }
317 +
318 + if ( ! empty( $custom_class ) ) {
264 319 if ( strpos( $new_tag, 'class=' ) === false ) {
265 - $opt_format .= ' class="optimole-lazy-only" ';
320 + $opt_format .= ' class="' . $custom_class . '" ';
266 321 } else {
267 322 $new_tag = str_replace(
268 323 ( $is_slashed ? 'class=\"' : 'class="' ),
269 - ( $is_slashed ? 'class=\"optimole-lazy-only ' : 'class="optimole-lazy-only ' ),
324 + ( $is_slashed ? 'class=\"' . $custom_class . ' ' : 'class="' . $custom_class . ' ' ),
270 325 $new_tag
271 326 );
272 327 }
273 328 }
@@ -293,12 +348,16 @@
293 348 ],
294 349 $new_tag,
295 350 1
296 351 );
352 +
353 + // We remove srcset and sizes attributes since our lazyload does not need them.
354 + $pattern = '/\s+(?:srcset|sizes)=("[^"]*"|\'[^\']*\'|\\\\"[^\\\\"]*\\\\")/i';
355 + $new_tag = preg_replace( $pattern, '', $new_tag );
356 +
357 + // We keep this for srcset lazyload compatibility that might break our mechanism.
297 358 $new_tag = str_replace( 'srcset=', 'old-srcset=', $new_tag );
298 - if ( strpos( $new_tag, 'loading=' ) === false && self::instance()->settings->get( 'native_lazyload' ) === 'enabled' ) {
299 - $new_tag = preg_replace( '/<img/im', $is_slashed ? '<img loading=\"lazy\"' : '<img loading="lazy"', $new_tag );
300 - }
359 +
301 360 if ( ! $this->should_add_noscript( $new_tag ) ) {
302 361 return $new_tag;
303 362 }
304 363
@@ -315,14 +374,16 @@
315 374 $video_tags = [];
316 375 $iframes = [];
317 376 $videos = [];
318 377 preg_match_all( '#(?:<noscript\s*>\s*)?<iframe(.*?)></iframe>(?:\s*</noscript\s*>)?#is', $content, $iframes );
319 - preg_match_all( '#(?:<noscript\s*>\s*)?<video(.*?)video>(?:\s*</noscript\s*>)?#is', $content, $videos );
378 + preg_match_all( '#(?:<noscript\s*>\s*)?<video(.*?)>.*?</video>(?:\s*</noscript\s*>)?#is', $content, $videos );
320 379 $video_tags = array_merge( $iframes[0], $videos[0] );
321 380
322 381 $search = [];
323 382 $replace = [];
383 +
324 384 foreach ( $video_tags as $video_tag ) {
385 +
325 386 if ( ! $this->should_lazyload_iframe( $video_tag ) ) {
326 387 continue;
327 388 }
328 389 if ( preg_match( "/ data-opt-src=['\"]/is", $video_tag ) ) {
@@ -327,20 +388,29 @@
327 388 }
328 389 if ( preg_match( "/ data-opt-src=['\"]/is", $video_tag ) ) {
329 390 continue;
330 391 }
331 - array_push( $search, $video_tag );
332 - $no_script = $video_tag;
392 + $should_add_noscript = true;
393 + $original_tag = $video_tag;
333 394 // replace the src and add the data-opt-src attribute
334 395 if ( strpos( $video_tag, 'iframe' ) !== false ) {
335 396 $video_tag = preg_replace( '/iframe(.*?)src=/is', 'iframe$1 src="about:blank" data-opt-src=', $video_tag );
336 397 } elseif ( strpos( $video_tag, 'video' ) !== false ) {
337 - $video_tag = preg_replace( '/video(.*?)src=/is', 'video$1 data-opt-src=', $video_tag );
398 + if ( strpos( $video_tag, 'source' ) !== false ) {
399 + if ( strpos( $video_tag, 'preload' ) === false ) {
400 + $video_tag = preg_replace( '/video(.*?)>/is', 'video$1 preload="metadata">', $video_tag, 1 );
401 + $should_add_noscript = false;
402 + } else {
403 + continue;
404 + }
405 + } else {
406 + $video_tag = preg_replace( '/video(.*?)src=/is', 'video$1 data-opt-src=', $video_tag );
407 + }
338 408 }
339 -
340 - if ( $this->should_add_noscript( $video_tag ) ) {
341 - $video_tag .= '<noscript>' . $no_script . '</noscript>';
409 + if ( $this->should_add_noscript( $video_tag ) && $should_add_noscript ) {
410 + $video_tag .= '<noscript>' . $original_tag . '</noscript>';
342 411 }
412 + array_push( $search, $original_tag );
343 413 array_push( $replace, $video_tag );
344 414 self::$found_iframe = true;
345 415 }
346 416 $search = array_unique( $search );
@@ -357,8 +427,11 @@
357 427 *
358 428 * @return bool We can lazyload?
359 429 */
360 430 public function can_lazyload_for( $url, $tag = '' ) {
431 + if ( OPTML_DEBUG ) {
432 + do_action( 'optml_log', 'can_lazyload_for: ' . $url . ' ' . $tag );
433 + }
361 434 foreach ( self::possible_lazyload_flags() as $banned_string ) {
362 435 if ( strpos( $tag, $banned_string ) !== false ) {
363 436 return false;
364 437 }
@@ -372,9 +445,9 @@
372 445 basename( $url ),
373 446 Optml_Config::$image_extensions
374 447 );
375 448
376 - if ( ! isset( $type['ext'] ) || empty( $type['ext'] ) ) {
449 + if ( empty( $type['ext'] ) ) {
377 450 return false;
378 451 }
379 452
380 453 if ( false === Optml_Filters::should_do_extension( self::$filters[ Optml_Settings::FILTER_TYPE_LAZYLOAD ][ Optml_Settings::FILTER_EXT ], $type['ext'] ) ) {
@@ -383,9 +456,35 @@
383 456
384 457 if ( defined( 'OPTML_DISABLE_PNG_LAZYLOAD' ) && OPTML_DISABLE_PNG_LAZYLOAD ) {
385 458 return $type['ext'] !== 'png';
386 459 }
387 - if ( Optml_Tag_Replacer::$lazyload_skipped_images < self::get_skip_lazyload_limit() ) {
460 +
461 + $no_viewport_data_available = true;
462 +
463 + if ( $this->settings->is_lazyload_type_viewport() ) {
464 + $image_id = $this->get_id_by_url( $url );
465 + $is_in_all_viewports = Optml_Manager::instance()->page_profiler->is_in_all_viewports( $image_id );
466 + $is_lcp_image = Optml_Manager::instance()->page_profiler->is_lcp_image_in_all_viewports( $image_id );
467 + $no_viewport_data_available = ! Optml_Manager::instance()->page_profiler->is_data_available();
468 +
469 + if ( OPTML_DEBUG ) {
470 + if ( $is_in_all_viewports ) {
471 + do_action( 'optml_log', 'Lazyload skipped image is in all viewports ' . $url . '|' . $image_id );
472 + } elseif ( $is_lcp_image ) {
473 + do_action( 'optml_log', 'Lazyload skipped image is LCP ' . $url . '|' . $image_id );
474 + }
475 + }
476 +
477 + if ( $is_in_all_viewports || $is_lcp_image ) {
478 + return false;
479 + }
480 + }
481 +
482 + if (
483 + $no_viewport_data_available &&
484 + $this->settings->is_lazyload_type_fixed() &&
485 + Optml_Tag_Replacer::$lazyload_skipped_images < self::get_skip_lazyload_limit()
486 + ) {
388 487 return false;
389 488 }
390 489 return true;
391 490 }
@@ -409,10 +508,10 @@
409 508
410 509 /**
411 510 * Get SVG markup with specific width/height.
412 511 *
413 - * @param int $width Markup Width.
414 - * @param int $height Markup Height.
512 + * @param int|string $width Markup Width.
513 + * @param int|string $height Markup Height.
415 514 * @param string|null $url Original URL.
416 515 *
417 516 * @return string SVG code.
418 517 */
@@ -429,23 +528,39 @@
429 528 $sizes = getimagesize( $filepath );
430 529 wp_cache_add( $key, [ $sizes[0], $sizes[1] ], 'optml_sources', DAY_IN_SECONDS );
431 530 }
432 531 }
433 - list( $width, $height ) = $sizes;
532 + // Check if $sizes is an array before list() assignment to prevent fatal error on PHP 8.2+
533 + // when the image file is missing (e.g., offloaded to CDN or deleted).
534 + if ( is_array( $sizes ) ) {
535 + list( $width, $height ) = $sizes;
536 + }
434 537 }
538 + // If the width is not found the url might be an offloaded attachment so we can get the width and height from the metadata.
539 + if ( ! is_numeric( $width ) && ! empty( $url ) ) {
540 + $attachment_id = $this->attachment_url_to_post_id( $url );
541 + $meta = wp_get_attachment_metadata( $attachment_id );
542 + $width = $meta['width'] ?? false;
543 + $height = $meta['height'] ?? false;
544 + }
435 545
436 546 $width = ! is_numeric( $width ) ? '100%' : $width;
437 547 $height = ! is_numeric( $height ) ? '100%' : $height;
548 + $fill = $this->settings->get( 'placeholder_color' );
438 549
439 - return
440 - str_replace(
441 - [ '#width#', '#height#' ],
442 - [
443 - $width,
444 - $height,
445 - ],
446 - self::SVG_PLACEHOLDER
447 - );
550 + if ( empty( $fill ) ) {
551 + $fill = 'transparent';
552 + }
553 +
554 + return str_replace(
555 + [ '#width#', '#height#', '#fill#' ],
556 + [
557 + $width,
558 + $height,
559 + urlencode( $fill ),
560 + ],
561 + self::SVG_PLACEHOLDER
562 + );
448 563 }
449 564
450 565 /**
451 566 * Check if we should add the noscript tag.
@@ -454,8 +569,11 @@
454 569 *
455 570 * @return bool Should add?
456 571 */
457 572 public function should_add_noscript( $tag ) {
573 + if ( $this->settings->get( 'no_script' ) === 'disabled' ) {
574 + return false;
575 + }
458 576 foreach ( self::get_ignore_noscript_flags() as $banned_string ) {
459 577 if ( strpos( $tag, $banned_string ) !== false ) {
460 578 return false;
461 579 }
@@ -470,8 +588,9 @@
470 588 *
471 589 * @return bool Should add?
472 590 */
473 591 public function should_lazyload_iframe( $tag ) {
592 +
474 593 foreach ( self::get_iframe_lazyload_flags() as $banned_string ) {
475 594 if ( strpos( $tag, $banned_string ) !== false ) {
476 595 return false;
477 596 }
@@ -485,14 +604,13 @@
485 604 *
486 605 * @return array
487 606 */
488 607 public static function get_ignore_noscript_flags() {
489 -
490 - if ( ! empty( self::$ignore_no_script_flags ) && is_array( self::$ignore_no_script_flags ) ) {
608 + if ( null !== self::$ignore_no_script_flags ) {
491 609 return self::$ignore_no_script_flags;
492 610 }
493 611
494 - self::$ignore_no_script_flags = apply_filters( 'optml_ignore_noscript_on', [] );
612 + self::$ignore_no_script_flags = apply_filters( 'optml_ignore_noscript_on', [ '<noscript' ] );
495 613
496 614 return self::$ignore_no_script_flags;
497 615 }
498 616 /**
@@ -500,14 +618,14 @@
500 618 *
501 619 * @return array
502 620 */
503 621 public static function get_iframe_lazyload_flags() {
504 -
505 - if ( ! empty( self::$iframe_lazyload_flags ) && is_array( self::$iframe_lazyload_flags ) ) {
622 + if ( null !== self::$iframe_lazyload_flags ) {
506 623 return self::$iframe_lazyload_flags;
507 624 }
508 625
509 - self::$iframe_lazyload_flags = apply_filters( 'optml_iframe_lazyload_flags', [ 'gform_ajax_frame', '<noscript', 'recaptcha', 'original-src' ] );
626 + self::$iframe_lazyload_flags = self::possible_lazyload_flags();
627 + self::$iframe_lazyload_flags = array_merge( self::$iframe_lazyload_flags, apply_filters( 'optml_iframe_lazyload_flags', [ 'gform_ajax_frame', '<noscript', 'recaptcha', '-src' ] ) );
510 628
511 629 return self::$iframe_lazyload_flags;
512 630 }
513 631 /**
@@ -537,6 +655,5 @@
537 655 public function __wakeup() {
538 656 // Unserializing instances of the class is forbidden.
539 657 _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin&#8217; huh?', 'optimole-wp' ), '1.0.0' );
540 658 }
541 -
542 659 }