add wp-rocket
This commit is contained in:
@@ -0,0 +1,290 @@
|
||||
<?php
|
||||
/**
|
||||
* Handle the lazyload required assets: inline CSS and JS
|
||||
*
|
||||
* @package RocketLazyload
|
||||
*/
|
||||
|
||||
namespace WP_Rocket\Dependencies\RocketLazyload;
|
||||
|
||||
/**
|
||||
* Class containing the methods to return or print the assets needed for lazyloading
|
||||
*/
|
||||
class Assets {
|
||||
|
||||
/**
|
||||
* Inserts the lazyload script in the HTML
|
||||
*
|
||||
* @param array $args Array of arguments to populate the lazyload script tag.
|
||||
* @return void
|
||||
*/
|
||||
public function insertLazyloadScript( $args = [] ) {
|
||||
echo $this->getLazyloadScript( $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the inline lazyload script configuration
|
||||
*
|
||||
* @param array $args Array of arguments to populate the lazyload script options.
|
||||
* @return string
|
||||
*/
|
||||
public function getInlineLazyloadScript( $args = [] ) {
|
||||
$defaults = [
|
||||
'elements' => [
|
||||
'img',
|
||||
'iframe',
|
||||
],
|
||||
'threshold' => 300,
|
||||
'options' => [],
|
||||
];
|
||||
|
||||
$allowed_options = [
|
||||
'container' => 1,
|
||||
'thresholds' => 1,
|
||||
'data_bg' => 1,
|
||||
'class_error' => 1,
|
||||
'cancel_on_exit' => 1,
|
||||
'unobserve_completed' => 1,
|
||||
'callback_enter' => 1,
|
||||
'callback_exit' => 1,
|
||||
'callback_loading' => 1,
|
||||
'callback_error' => 1,
|
||||
'callback_finish' => 1,
|
||||
'use_native' => 1,
|
||||
];
|
||||
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
$script = '';
|
||||
|
||||
$args['options'] = array_intersect_key( $args['options'], $allowed_options );
|
||||
|
||||
$script .= 'window.lazyLoadOptions = {
|
||||
elements_selector: "' . esc_attr( implode( ',', $args['elements'] ) ) . '",
|
||||
data_src: "lazy-src",
|
||||
data_srcset: "lazy-srcset",
|
||||
data_sizes: "lazy-sizes",
|
||||
class_loading: "lazyloading",
|
||||
class_loaded: "lazyloaded",
|
||||
threshold: ' . esc_attr( $args['threshold'] ) . ',
|
||||
callback_loaded: function(element) {
|
||||
if ( element.tagName === "IFRAME" && element.dataset.rocketLazyload == "fitvidscompatible" ) {
|
||||
if (element.classList.contains("lazyloaded") ) {
|
||||
if (typeof window.jQuery != "undefined") {
|
||||
if (jQuery.fn.fitVids) {
|
||||
jQuery(element).parent().fitVids();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}';
|
||||
|
||||
if ( ! empty( $args['options'] ) ) {
|
||||
$script .= ',' . PHP_EOL;
|
||||
|
||||
foreach ( $args['options'] as $option => $value ) {
|
||||
$script .= $option . ': ' . $value . ',';
|
||||
}
|
||||
|
||||
$script = rtrim( $script, ',' );
|
||||
}
|
||||
|
||||
$script .= '};';
|
||||
|
||||
$script .= '
|
||||
window.addEventListener(\'LazyLoad::Initialized\', function (e) {
|
||||
var lazyLoadInstance = e.detail.instance;
|
||||
|
||||
if (window.MutationObserver) {
|
||||
var observer = new MutationObserver(function(mutations) {
|
||||
var image_count = 0;
|
||||
var iframe_count = 0;
|
||||
var rocketlazy_count = 0;
|
||||
|
||||
mutations.forEach(function(mutation) {
|
||||
for (i = 0; i < mutation.addedNodes.length; i++) {
|
||||
if (typeof mutation.addedNodes[i].getElementsByTagName !== \'function\') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (typeof mutation.addedNodes[i].getElementsByClassName !== \'function\') {
|
||||
continue;
|
||||
}
|
||||
|
||||
images = mutation.addedNodes[i].getElementsByTagName(\'img\');
|
||||
is_image = mutation.addedNodes[i].tagName == "IMG";
|
||||
iframes = mutation.addedNodes[i].getElementsByTagName(\'iframe\');
|
||||
is_iframe = mutation.addedNodes[i].tagName == "IFRAME";
|
||||
rocket_lazy = mutation.addedNodes[i].getElementsByClassName(\'rocket-lazyload\');
|
||||
|
||||
image_count += images.length;
|
||||
iframe_count += iframes.length;
|
||||
rocketlazy_count += rocket_lazy.length;
|
||||
|
||||
if(is_image){
|
||||
image_count += 1;
|
||||
}
|
||||
|
||||
if(is_iframe){
|
||||
iframe_count += 1;
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
if(image_count > 0 || iframe_count > 0 || rocketlazy_count > 0){
|
||||
lazyLoadInstance.update();
|
||||
}
|
||||
} );
|
||||
|
||||
var b = document.getElementsByTagName("body")[0];
|
||||
var config = { childList: true, subtree: true };
|
||||
|
||||
observer.observe(b, config);
|
||||
}
|
||||
}, false);';
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lazyload inline script
|
||||
*
|
||||
* @param array $args Array of arguments to populate the lazyload script options.
|
||||
* @return string
|
||||
*/
|
||||
public function getLazyloadScript( $args = [] ) {
|
||||
$defaults = [
|
||||
'base_url' => '',
|
||||
'version' => '',
|
||||
'polyfill' => false,
|
||||
];
|
||||
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
$min = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
|
||||
$script = '';
|
||||
|
||||
if ( isset( $args['polyfill'] ) && $args['polyfill'] ) {
|
||||
$script .= '<script crossorigin="anonymous" src="https://polyfill.io/v3/polyfill.min.js?flags=gated&features=default%2CIntersectionObserver%2CIntersectionObserverEntry"></script>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the script tag for the lazyload script
|
||||
*
|
||||
* @since 2.2.6
|
||||
*
|
||||
* @param $script_tag HTML tag for the lazyload script.
|
||||
*/
|
||||
$script .= apply_filters( 'rocket_lazyload_script_tag', '<script data-no-minify="1" async src="' . $args['base_url'] . $args['version'] . '/lazyload' . $min . '.js"></script>' );
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts in the HTML the script to replace the Youtube thumbnail by the iframe.
|
||||
*
|
||||
* @param array $args Array of arguments to populate the script options.
|
||||
* @return void
|
||||
*/
|
||||
public function insertYoutubeThumbnailScript( $args = [] ) {
|
||||
echo $this->getYoutubeThumbnailScript( $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Youtube Thumbnail inline script
|
||||
*
|
||||
* @param array $args Array of arguments to populate the script options.
|
||||
* @return string
|
||||
*/
|
||||
public function getYoutubeThumbnailScript( $args = [] ) {
|
||||
$defaults = [
|
||||
'resolution' => 'hqdefault',
|
||||
'lazy_image' => false,
|
||||
];
|
||||
|
||||
$allowed_resolutions = [
|
||||
'default' => [
|
||||
'width' => 120,
|
||||
'height' => 90,
|
||||
],
|
||||
'mqdefault' => [
|
||||
'width' => 320,
|
||||
'height' => 180,
|
||||
],
|
||||
'hqdefault' => [
|
||||
'width' => 480,
|
||||
'height' => 360,
|
||||
],
|
||||
'sddefault' => [
|
||||
'width' => 640,
|
||||
'height' => 480,
|
||||
],
|
||||
|
||||
'maxresdefault' => [
|
||||
'width' => 1280,
|
||||
'height' => 720,
|
||||
],
|
||||
];
|
||||
|
||||
$args['resolution'] = ( isset( $args['resolution'] ) && isset( $allowed_resolutions[ $args['resolution'] ] ) ) ? $args['resolution'] : 'hqdefault';
|
||||
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
|
||||
$image = '<img src="https://i.ytimg.com/vi/ID/' . $args['resolution'] . '.jpg" alt="" width="' . $allowed_resolutions[ $args['resolution'] ]['width'] . '" height="' . $allowed_resolutions[ $args['resolution'] ]['height'] . '">';
|
||||
|
||||
if ( isset( $args['lazy_image'] ) && $args['lazy_image'] ) {
|
||||
$image = '<img loading="lazy" data-lazy-src="https://i.ytimg.com/vi/ID/' . $args['resolution'] . '.jpg" alt="" width="' . $allowed_resolutions[ $args['resolution'] ]['width'] . '" height="' . $allowed_resolutions[ $args['resolution'] ]['height'] . '"><noscript><img src="https://i.ytimg.com/vi/ID/' . $args['resolution'] . '.jpg" alt="" width="' . $allowed_resolutions[ $args['resolution'] ]['width'] . '" height="' . $allowed_resolutions[ $args['resolution'] ]['height'] . '"></noscript>';
|
||||
}
|
||||
|
||||
return "<script>function lazyLoadThumb(e){var t='{$image}',a='<div class=\"play\"></div>';return t.replace(\"ID\",e)+a}function lazyLoadYoutubeIframe(){var e=document.createElement(\"iframe\"),t=\"ID?autoplay=1\";t+=0===this.dataset.query.length?'':'&'+this.dataset.query;e.setAttribute(\"src\",t.replace(\"ID\",this.dataset.src)),e.setAttribute(\"frameborder\",\"0\"),e.setAttribute(\"allowfullscreen\",\"1\"),e.setAttribute(\"allow\", \"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\"),this.parentNode.replaceChild(e,this)}document.addEventListener(\"DOMContentLoaded\",function(){var e,t,a=document.getElementsByClassName(\"rll-youtube-player\");for(t=0;t<a.length;t++)e=document.createElement(\"div\"),e.setAttribute(\"data-id\",a[t].dataset.id),e.setAttribute(\"data-query\", a[t].dataset.query),e.setAttribute(\"data-src\", a[t].dataset.src),e.innerHTML=lazyLoadThumb(a[t].dataset.id),e.onclick=lazyLoadYoutubeIframe,a[t].appendChild(e)});</script>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the CSS to style the Youtube thumbnail container
|
||||
*
|
||||
* @param array $args Array of arguments to populate the CSS.
|
||||
* @return void
|
||||
*/
|
||||
public function insertYoutubeThumbnailCSS( $args = [] ) {
|
||||
wp_register_style( 'rocket-lazyload', false );
|
||||
wp_enqueue_style( 'rocket-lazyload' );
|
||||
wp_add_inline_style( 'rocket-lazyload', $this->getYoutubeThumbnailCSS( $args ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the CSS for the Youtube Thumbnail
|
||||
*
|
||||
* @param array $args Array of arguments to populate the CSS.
|
||||
* @return string
|
||||
*/
|
||||
public function getYoutubeThumbnailCSS( $args = [] ) {
|
||||
$defaults = [
|
||||
'base_url' => '',
|
||||
'responsive_embeds' => true,
|
||||
];
|
||||
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
|
||||
$css = '.rll-youtube-player{position:relative;padding-bottom:56.23%;height:0;overflow:hidden;max-width:100%;}.rll-youtube-player iframe{position:absolute;top:0;left:0;width:100%;height:100%;z-index:100;background:0 0}.rll-youtube-player img{bottom:0;display:block;left:0;margin:auto;max-width:100%;width:100%;position:absolute;right:0;top:0;border:none;height:auto;cursor:pointer;-webkit-transition:.4s all;-moz-transition:.4s all;transition:.4s all}.rll-youtube-player img:hover{-webkit-filter:brightness(75%)}.rll-youtube-player .play{height:72px;width:72px;left:50%;top:50%;margin-left:-36px;margin-top:-36px;position:absolute;background:url(' . $args['base_url'] . 'img/youtube.png) no-repeat;cursor:pointer}';
|
||||
|
||||
if ( $args['responsive_embeds'] ) {
|
||||
$css .= '.wp-has-aspect-ratio .rll-youtube-player{position:absolute;padding-bottom:0;width:100%;height:100%;top:0;bottom:0;left:0;right:0}';
|
||||
}
|
||||
|
||||
return $css;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the CSS needed when Javascript is not enabled to keep the display correct
|
||||
*/
|
||||
public function insertNoJSCSS() {
|
||||
echo $this->getNoJSCSS();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the CSS to correctly display images when JavaScript is disabled
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNoJSCSS() {
|
||||
return '<noscript><style id="rocket-lazyload-nojs-css">.rll-youtube-player, [data-lazy-src]{display:none !important;}</style></noscript>';
|
||||
}
|
||||
}
|
@@ -0,0 +1,232 @@
|
||||
<?php
|
||||
/**
|
||||
* Handles lazyloading of iframes
|
||||
*
|
||||
* @package RocketLazyload
|
||||
*/
|
||||
|
||||
namespace WP_Rocket\Dependencies\RocketLazyload;
|
||||
|
||||
/**
|
||||
* A class to provide the methods needed to lazyload iframes in WP Rocket and Lazyload by WP Rocket
|
||||
*/
|
||||
class Iframe {
|
||||
|
||||
/**
|
||||
* Finds iframes in the HTML provided and call the methods to lazyload them
|
||||
*
|
||||
* @param string $html Original HTML.
|
||||
* @param string $buffer Content to parse.
|
||||
* @param array $args Array of arguments to use.
|
||||
* @return string
|
||||
*/
|
||||
public function lazyloadIframes( $html, $buffer, $args = [] ) {
|
||||
$defaults = [
|
||||
'youtube' => false,
|
||||
];
|
||||
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
|
||||
if ( ! preg_match_all( '@<iframe(?<atts>\s.+)>.*</iframe>@iUs', $buffer, $iframes, PREG_SET_ORDER ) ) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
$iframes = array_unique( $iframes, SORT_REGULAR );
|
||||
|
||||
foreach ( $iframes as $iframe ) {
|
||||
if ( $this->isIframeExcluded( $iframe ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Given the previous regex pattern, $iframe['atts'] starts with a whitespace character.
|
||||
if ( ! preg_match( '@\ssrc\s*=\s*(\'|")(?<src>.*)\1@iUs', $iframe['atts'], $atts ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$iframe['src'] = trim( $atts['src'] );
|
||||
|
||||
if ( '' === $iframe['src'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $args['youtube'] ) {
|
||||
$iframe_lazyload = $this->replaceYoutubeThumbnail( $iframe );
|
||||
}
|
||||
|
||||
if ( empty( $iframe_lazyload ) ) {
|
||||
$iframe_lazyload = $this->replaceIframe( $iframe );
|
||||
}
|
||||
|
||||
$html = str_replace( $iframe[0], $iframe_lazyload, $html );
|
||||
|
||||
unset( $iframe_lazyload );
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the provided iframe is excluded from lazyload
|
||||
*
|
||||
* @param array $iframe Array of matched patterns.
|
||||
* @return boolean
|
||||
*/
|
||||
public function isIframeExcluded( $iframe ) {
|
||||
|
||||
foreach ( $this->getExcludedPatterns() as $excluded_pattern ) {
|
||||
if ( strpos( $iframe[0], $excluded_pattern ) !== false ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets patterns excluded from lazyload for iframes
|
||||
*
|
||||
* @since 2.1.1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getExcludedPatterns() {
|
||||
/**
|
||||
* Filters the patterns excluded from lazyload for iframes
|
||||
*
|
||||
* @since 2.1.1
|
||||
*
|
||||
* @param array $excluded_patterns Array of excluded patterns.
|
||||
*/
|
||||
return apply_filters(
|
||||
'rocket_lazyload_iframe_excluded_patterns',
|
||||
[
|
||||
'gform_ajax_frame',
|
||||
'data-no-lazy=',
|
||||
'recaptcha/api/fallback',
|
||||
'loading="eager"',
|
||||
'data-skip-lazy',
|
||||
'skip-lazy',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies lazyload on the iframe provided
|
||||
*
|
||||
* @param array $iframe Array of matched elements.
|
||||
* @return string
|
||||
*/
|
||||
private function replaceIframe( $iframe ) {
|
||||
/**
|
||||
* Filter the LazyLoad placeholder on src attribute
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param string $placeholder placeholder that will be printed.
|
||||
*/
|
||||
$placeholder = apply_filters( 'rocket_lazyload_placeholder', 'about:blank' );
|
||||
|
||||
$placeholder_atts = str_replace( $iframe['src'], $placeholder, $iframe['atts'] );
|
||||
$iframe_lazyload = str_replace( $iframe['atts'], $placeholder_atts . ' data-rocket-lazyload="fitvidscompatible" data-lazy-src="' . esc_url( $iframe['src'] ) . '"', $iframe[0] );
|
||||
|
||||
if ( ! preg_match( '@\sloading\s*=\s*(\'|")(?:lazy|auto)\1@i', $iframe_lazyload ) ) {
|
||||
$iframe_lazyload = str_replace( '<iframe', '<iframe loading="lazy"', $iframe_lazyload );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the LazyLoad HTML output on iframes
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param array $html Output that will be printed.
|
||||
*/
|
||||
$iframe_lazyload = apply_filters( 'rocket_lazyload_iframe_html', $iframe_lazyload );
|
||||
$iframe_lazyload .= '<noscript>' . $iframe[0] . '</noscript>';
|
||||
|
||||
return $iframe_lazyload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the iframe provided by the Youtube thumbnail
|
||||
*
|
||||
* @param array $iframe Array of matched elements.
|
||||
* @return bool|string
|
||||
*/
|
||||
private function replaceYoutubeThumbnail( $iframe ) {
|
||||
$youtube_id = $this->getYoutubeIDFromURL( $iframe['src'] );
|
||||
|
||||
if ( ! $youtube_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$query = wp_parse_url( htmlspecialchars_decode( $iframe['src'] ), PHP_URL_QUERY );
|
||||
|
||||
$youtube_url = $this->changeYoutubeUrlForYoutuDotBe( $iframe['src'] );
|
||||
$youtube_url = $this->cleanYoutubeUrl( $iframe['src'] );
|
||||
/**
|
||||
* Filter the LazyLoad HTML output on Youtube iframes
|
||||
*
|
||||
* @since 2.11
|
||||
*
|
||||
* @param array $html Output that will be printed.
|
||||
*/
|
||||
$youtube_lazyload = apply_filters( 'rocket_lazyload_youtube_html', '<div class="rll-youtube-player" data-src="' . esc_attr( $youtube_url ) . '" data-id="' . esc_attr( $youtube_id ) . '" data-query="' . esc_attr( $query ) . '"></div>' );
|
||||
$youtube_lazyload .= '<noscript>' . $iframe[0] . '</noscript>';
|
||||
|
||||
return $youtube_lazyload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Youtube ID from the URL provided
|
||||
*
|
||||
* @param string $url URL to search.
|
||||
* @return bool|string
|
||||
*/
|
||||
public function getYoutubeIDFromURL( $url ) {
|
||||
$pattern = '#^(?:https?:)?(?://)?(?:www\.)?(?:youtu\.be|youtube\.com|youtube-nocookie\.com)/(?:embed/|v/|watch/?\?v=)?([\w-]{11})#iU';
|
||||
$result = preg_match( $pattern, $url, $matches );
|
||||
|
||||
if ( ! $result ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// exclude playlist.
|
||||
if ( 'videoseries' === $matches[1] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes URL youtu.be/ID to youtube.com/embed/ID
|
||||
*
|
||||
* @param string $url URL to replace.
|
||||
* @return string Unchanged URL or modified URL.
|
||||
*/
|
||||
public function changeYoutubeUrlForYoutuDotBe( $url ) {
|
||||
$pattern = '#^(?:https?:)?(?://)?(?:www\.)?(?:youtu\.be)/(?:embed/|v/|watch/?\?v=)?([\w-]{11})#iU';
|
||||
$result = preg_match( $pattern, $url, $matches );
|
||||
|
||||
if ( ! $result ) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
return 'https://www.youtube.com/embed/' . $matches[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans Youtube URL. Keeps only scheme, host and path.
|
||||
*
|
||||
* @param string $url URL to be cleaned.
|
||||
* @return string Cleaned URL
|
||||
*/
|
||||
public function cleanYoutubeUrl( $url ) {
|
||||
$parsed_url = wp_parse_url( $url, -1 );
|
||||
$scheme = isset( $parsed_url['scheme'] ) ? $parsed_url['scheme'] . '://' : '//';
|
||||
$host = isset( $parsed_url['host'] ) ? $parsed_url['host'] : '';
|
||||
$path = isset( $parsed_url['path'] ) ? $parsed_url['path'] : '';
|
||||
|
||||
return $scheme . $host . $path;
|
||||
}
|
||||
}
|
@@ -0,0 +1,602 @@
|
||||
<?php
|
||||
/**
|
||||
* Handles lazyloading of images
|
||||
*
|
||||
* @package RocketLazyload
|
||||
*/
|
||||
|
||||
namespace WP_Rocket\Dependencies\RocketLazyload;
|
||||
|
||||
/**
|
||||
* A class to provide the methods needed to lazyload images in WP Rocket and Lazyload by WP Rocket
|
||||
*/
|
||||
class Image {
|
||||
|
||||
/**
|
||||
* Finds the images to be lazyloaded and call the callback method to replace them.
|
||||
*
|
||||
* @param string $html Original HTML.
|
||||
* @param string $buffer Content to parse.
|
||||
* @return string
|
||||
*/
|
||||
public function lazyloadImages( $html, $buffer ) {
|
||||
$clean_buffer = preg_replace( '/<script\b(?:[^>]*)>(?:.+)?<\/script>/Umsi', '', $html );
|
||||
$clean_buffer = preg_replace( '#<noscript>(?:.+)</noscript>#Umsi', '', $clean_buffer );
|
||||
if (! preg_match_all('#<img(?<atts>\s.+)\s?/?>#iUs', $clean_buffer, $images, PREG_SET_ORDER)) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
$images = array_unique( $images, SORT_REGULAR );
|
||||
|
||||
foreach ( $images as $image ) {
|
||||
$image = $this->canLazyload( $image );
|
||||
|
||||
if ( ! $image ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$image_lazyload = $this->replaceImage( $image );
|
||||
$image_lazyload .= $this->noscript( $image[0] );
|
||||
$html = str_replace( $image[0], $image_lazyload, $html );
|
||||
|
||||
unset( $image_lazyload );
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies lazyload on background images defined in style attributes
|
||||
*
|
||||
* @param string $html Original HTML.
|
||||
* @param string $buffer Content to parse.
|
||||
* @return string
|
||||
*/
|
||||
public function lazyloadBackgroundImages( $html, $buffer ) {
|
||||
if ( ! preg_match_all( '#<(?<tag>div|figure|section|span|li|a)\s+(?<before>[^>]+[\'"\s])?style\s*=\s*([\'"])(?<styles>.*?)\3(?<after>[^>]*)>#is', $buffer, $elements, PREG_SET_ORDER ) ) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
foreach ( $elements as $element ) {
|
||||
if ( $this->isExcluded( $element['before'] . $element['after'], $this->getExcludedAttributes() ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! preg_match( '#background-image\s*:\s*(?<attr>\s*url\s*\((?<url>[^)]+)\))\s*;?#is', $element['styles'], $url ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$url['url'] = esc_url(
|
||||
trim(
|
||||
strip_tags(
|
||||
html_entity_decode(
|
||||
$url['url'], ENT_QUOTES|ENT_HTML5
|
||||
)
|
||||
), '\'" '
|
||||
)
|
||||
);
|
||||
|
||||
if ( $this->isExcluded( $url['url'], $this->getExcludedSrc() ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$lazy_bg = $this->addLazyCLass( $element[0] );
|
||||
$lazy_bg = str_replace( $url[0], '', $lazy_bg );
|
||||
$lazy_bg = str_replace( '<' . $element['tag'], '<' . $element['tag'] . ' data-bg="' . esc_attr( $url['url'] ) . '"', $lazy_bg );
|
||||
|
||||
$html = str_replace( $element[0], $lazy_bg, $html );
|
||||
unset( $lazy_bg );
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the identifier class to the element
|
||||
*
|
||||
* @param string $element Element to add the class to.
|
||||
* @return string
|
||||
*/
|
||||
private function addLazyClass( $element ) {
|
||||
$class = $this->getClasses( $element );
|
||||
if ( empty( $class ) ) {
|
||||
return preg_replace( '#<(img|div|figure|section|li|span|a)([^>]*)>#is', '<\1 class="rocket-lazyload"\2>', $element );
|
||||
}
|
||||
|
||||
if ( empty( $class['attribute'] ) || empty( $class['classes'] ) ) {
|
||||
return str_replace( $class['attribute'], 'class="rocket-lazyload"', $element );
|
||||
}
|
||||
|
||||
$quotes = $this->getAttributeQuotes( $class['classes'] );
|
||||
$classes = $this->trimOuterQuotes( $class['classes'], $quotes );
|
||||
|
||||
if ( empty( $classes ) ) {
|
||||
return str_replace( $class['attribute'], 'class="rocket-lazyload"', $element );
|
||||
}
|
||||
|
||||
$classes .= ' rocket-lazyload';
|
||||
|
||||
return str_replace(
|
||||
$class['attribute'],
|
||||
'class=' . $this->normalizeClasses( $classes, $quotes ),
|
||||
$element
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the attribute value's outer quotation mark, if one exists, i.e. " or '.
|
||||
*
|
||||
* @param string $attribute_value The target attribute's value.
|
||||
*
|
||||
* @return bool|string quotation character; else false when no quotation mark.
|
||||
*/
|
||||
private function getAttributeQuotes( $attribute_value ) {
|
||||
$attribute_value = trim( $attribute_value );
|
||||
$first_char = $attribute_value[0];
|
||||
|
||||
if ( '"' === $first_char || "'" === $first_char ) {
|
||||
return $first_char;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the class attribute and values from the given element, if it exists.
|
||||
*
|
||||
* @param string $element Given HTML element to extract classes from.
|
||||
*
|
||||
* @return bool|string[] {
|
||||
* @type string $attribute Class attribute and value, e.g. class="value"
|
||||
* @type string $classes String of class attribute's value(s)
|
||||
* }; else, false when no class attribute exists.
|
||||
*/
|
||||
private function getClasses( $element ) {
|
||||
if ( ! preg_match( '#class\s*=\s*(?<classes>["\'].*?["\']|[^\s]+)#is', $element, $class ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( empty( $class ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $class['classes'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return [
|
||||
'attribute' => $class[0],
|
||||
'classes' => $class['classes'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes outer single or double quotations.
|
||||
*
|
||||
* @param string $string String to strip quotes from.
|
||||
* @param string $quotes The outer quotes to remove.
|
||||
*
|
||||
* @return string string without quotes.
|
||||
*/
|
||||
private function trimOuterQuotes( $string, $quotes ) {
|
||||
$string = trim( $string );
|
||||
if ( empty( $string ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( empty( $quotes ) ) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
$string = ltrim( $string, $quotes );
|
||||
$string = rtrim( $string, $quotes );
|
||||
return trim( $string );
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the class attribute values to ensure well-formed.
|
||||
*
|
||||
* @param string $classes String of class attribute value(s).
|
||||
* @param string|bool $quotes Optional. Quotation mark to wrap around the classes.
|
||||
*
|
||||
* @return string well-formed class attributes.
|
||||
*/
|
||||
private function normalizeClasses( $classes, $quotes = '"' ) {
|
||||
$array_of_classes = $this->stringToArray( $classes );
|
||||
$classes = implode( ' ', $array_of_classes );
|
||||
|
||||
if ( false === $quotes ) {
|
||||
$quotes = '"';
|
||||
}
|
||||
|
||||
return $quotes . $classes . $quotes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given string into an array of strings.
|
||||
*
|
||||
* Note:
|
||||
* 1. Removes empties.
|
||||
* 2. Trims each string.
|
||||
*
|
||||
* @param string $string The target string to convert.
|
||||
* @param string $delimiter Optional. Default: ' ' empty string.
|
||||
*
|
||||
* @return array An array of trimmed strings.
|
||||
*/
|
||||
private function stringToArray( $string, $delimiter = ' ' ) {
|
||||
if ( empty( $string ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$array = explode( $delimiter, $string );
|
||||
$array = array_map('trim', $array );
|
||||
|
||||
// Remove empties.
|
||||
return array_filter( $array );
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies lazyload on picture elements found in the HTML.
|
||||
*
|
||||
* @param string $html Original HTML.
|
||||
* @param string $buffer Content to parse.
|
||||
* @return string
|
||||
*/
|
||||
public function lazyloadPictures( $html, $buffer ) {
|
||||
if ( ! preg_match_all( '#<picture(?:.*)?>(?<sources>.*)</picture>#iUs', $buffer, $pictures, PREG_SET_ORDER ) ) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
$pictures = array_unique( $pictures, SORT_REGULAR );
|
||||
$excluded = array_merge( $this->getExcludedAttributes(), $this->getExcludedSrc() );
|
||||
|
||||
foreach ( $pictures as $picture ) {
|
||||
if ( $this->isExcluded( $picture[0], $excluded ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( preg_match_all( '#<source(?<atts>\s.+)>#iUs', $picture['sources'], $sources, PREG_SET_ORDER ) ) {
|
||||
$sources = array_unique( $sources, SORT_REGULAR );
|
||||
|
||||
$lazy_sources = 0;
|
||||
|
||||
foreach ( $sources as $source ) {
|
||||
$lazyload_srcset = preg_replace( '/([\s"\'])srcset/i', '\1data-lazy-srcset', $source[0] );
|
||||
$html = str_replace( $source[0], $lazyload_srcset, $html );
|
||||
|
||||
unset( $lazyload_srcset );
|
||||
$lazy_sources++;
|
||||
}
|
||||
}
|
||||
|
||||
if ( 0 === $lazy_sources ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! preg_match( '#<img(?<atts>\s.+)\s?/?>#iUs', $picture[0], $img ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$img = $this->canLazyload( $img );
|
||||
|
||||
if ( ! $img ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$img_lazy = $this->replaceImage( $img );
|
||||
$img_lazy .= $this->noscript( $img[0] );
|
||||
$safe_img = str_replace('/', '\/', preg_quote( $img[0], '#' ));
|
||||
$html = preg_replace( '#<noscript[^>]*>.*' . $safe_img . '.*<\/noscript>(*SKIP)(*FAIL)|' . $safe_img . '#iU', $img_lazy, $html );
|
||||
|
||||
unset( $img_lazy );
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the image can be lazyloaded
|
||||
*
|
||||
* @param Array $image Array of image data coming from Regex.
|
||||
* @return bool|Array
|
||||
*/
|
||||
private function canLazyload( $image ) {
|
||||
if ( $this->isExcluded( $image['atts'], $this->getExcludedAttributes() ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Given the previous regex pattern, $image['atts'] starts with a whitespace character.
|
||||
if ( ! preg_match( '@\ssrc\s*=\s*(\'|")(?<src>.*)\1@iUs', $image['atts'], $atts ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$image['src'] = trim( $atts['src'] );
|
||||
|
||||
if ( '' === $image['src'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $this->isExcluded( $image['src'], $this->getExcludedSrc() ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't apply LazyLoad on images from WP Retina x2.
|
||||
if ( function_exists( 'wr2x_picture_rewrite' ) ) {
|
||||
if ( wr2x_get_retina( trailingslashit( ABSPATH ) . wr2x_get_pathinfo_from_image_src( trim( $image['src'], '"' ) ) ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the provided string matches with the provided excluded patterns
|
||||
*
|
||||
* @param string $string String to check.
|
||||
* @param array $excluded_values Patterns to match against.
|
||||
* @return boolean
|
||||
*/
|
||||
public function isExcluded( $string, $excluded_values ) {
|
||||
if ( ! is_array( $excluded_values ) ) {
|
||||
(array) $excluded_values;
|
||||
}
|
||||
|
||||
if ( empty( $excluded_values ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ( $excluded_values as $excluded_value ) {
|
||||
if ( strpos( $string, $excluded_value ) !== false ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of excluded attributes
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getExcludedAttributes() {
|
||||
/**
|
||||
* Filters the attributes used to prevent lazylad from being applied
|
||||
*
|
||||
* @since 1.0
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @param array $excluded_attributes An array of excluded attributes.
|
||||
*/
|
||||
return apply_filters(
|
||||
'rocket_lazyload_excluded_attributes',
|
||||
[
|
||||
'data-src=',
|
||||
'data-no-lazy=',
|
||||
'data-lazy-original=',
|
||||
'data-lazy-src=',
|
||||
'data-lazysrc=',
|
||||
'data-lazyload=',
|
||||
'data-bgposition=',
|
||||
'data-envira-src=',
|
||||
'fullurl=',
|
||||
'lazy-slider-img=',
|
||||
'data-srcset=',
|
||||
'class="ls-l',
|
||||
'class="ls-bg',
|
||||
'soliloquy-image',
|
||||
'loading="eager"',
|
||||
'swatch-img',
|
||||
'data-height-percentage',
|
||||
'data-large_image',
|
||||
'avia-bg-style-fixed',
|
||||
'data-skip-lazy',
|
||||
'skip-lazy',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of excluded src
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getExcludedSrc() {
|
||||
/**
|
||||
* Filters the src used to prevent lazylad from being applied
|
||||
*
|
||||
* @since 1.0
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @param array $excluded_src An array of excluded src.
|
||||
*/
|
||||
return apply_filters(
|
||||
'rocket_lazyload_excluded_src',
|
||||
[
|
||||
'/wpcf7_captcha/',
|
||||
'timthumb.php?src',
|
||||
'woocommerce/assets/images/placeholder.png',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the original image by the lazyload one
|
||||
*
|
||||
* @param array $image Array of matches elements.
|
||||
* @return string
|
||||
*/
|
||||
private function replaceImage( $image ) {
|
||||
$width = 0;
|
||||
$height = 0;
|
||||
|
||||
if ( preg_match( '@[\s"\']width\s*=\s*(\'|")(?<width>.*)\1@iUs', $image['atts'], $atts ) ) {
|
||||
$width = absint( $atts['width'] );
|
||||
}
|
||||
|
||||
if ( preg_match( '@[\s"\']height\s*=\s*(\'|")(?<height>.*)\1@iUs', $image['atts'], $atts ) ) {
|
||||
$height = absint( $atts['height'] );
|
||||
}
|
||||
|
||||
$placeholder_atts = preg_replace( '@\ssrc\s*=\s*(\'|")(?<src>.*)\1@iUs', ' src="' . $this->getPlaceholder( $width, $height ) . '"', $image['atts'] );
|
||||
|
||||
$image_lazyload = str_replace( $image['atts'], $placeholder_atts . ' data-lazy-src="' . $image['src'] . '"', $image[0] );
|
||||
|
||||
if ( ! preg_match( '@\sloading\s*=\s*(\'|")(?:lazy|auto)\1@i', $image_lazyload ) && apply_filters( 'rocket_use_native_lazyload', false ) ) {
|
||||
$image_lazyload = str_replace( '<img', '<img loading="lazy"', $image_lazyload );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the LazyLoad HTML output
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @param string $html Output that will be printed
|
||||
*/
|
||||
$image_lazyload = apply_filters( 'rocket_lazyload_html', $image_lazyload );
|
||||
|
||||
return $image_lazyload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTML tag wrapped inside noscript tags
|
||||
*
|
||||
* @param string $element Element to wrap.
|
||||
* @return string
|
||||
*/
|
||||
private function noscript( $element ) {
|
||||
return '<noscript>' . $element . '</noscript>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies lazyload on srcset and sizes attributes
|
||||
*
|
||||
* @param string $html HTML image tag.
|
||||
* @return string
|
||||
*/
|
||||
public function lazyloadResponsiveAttributes( $html ) {
|
||||
$html = preg_replace( '/[\s|"|\'](srcset)\s*=\s*("|\')([^"|\']+)\2/i', ' data-lazy-$1=$2$3$2', $html );
|
||||
$html = preg_replace( '/[\s|"|\'](sizes)\s*=\s*("|\')([^"|\']+)\2/i', ' data-lazy-$1=$2$3$2', $html );
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds patterns matching smiley and call the callback method to replace them with the image
|
||||
*
|
||||
* @param string $text Content to search in.
|
||||
* @return string
|
||||
*/
|
||||
public function convertSmilies( $text ) {
|
||||
global $wp_smiliessearch;
|
||||
|
||||
if ( ! get_option( 'use_smilies' ) || empty( $wp_smiliessearch ) ) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
$output = '';
|
||||
// HTML loop taken from texturize function, could possible be consolidated.
|
||||
$textarr = preg_split( '/(<.*>)/U', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // capture the tags as well as in between.
|
||||
$stop = count( $textarr );// loop stuff.
|
||||
|
||||
// Ignore proessing of specific tags.
|
||||
$tags_to_ignore = 'code|pre|style|script|textarea';
|
||||
$ignore_block_element = '';
|
||||
|
||||
for ( $i = 0; $i < $stop; $i++ ) {
|
||||
$content = $textarr[ $i ];
|
||||
|
||||
// If we're in an ignore block, wait until we find its closing tag.
|
||||
if ( '' === $ignore_block_element && preg_match( '/^<(' . $tags_to_ignore . ')>/', $content, $matches ) ) {
|
||||
$ignore_block_element = $matches[1];
|
||||
}
|
||||
|
||||
// If it's not a tag and not in ignore block.
|
||||
if ( '' === $ignore_block_element && strlen( $content ) > 0 && '<' !== $content[0] ) {
|
||||
$content = preg_replace_callback( $wp_smiliessearch, [ $this, 'translateSmiley' ], $content );
|
||||
}
|
||||
|
||||
// did we exit ignore block.
|
||||
if ( '' !== $ignore_block_element && '</' . $ignore_block_element . '>' === $content ) {
|
||||
$ignore_block_element = '';
|
||||
}
|
||||
|
||||
$output .= $content;
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace matches by smiley image, lazyloaded
|
||||
*
|
||||
* @param array $matches Array of matches.
|
||||
* @return string
|
||||
*/
|
||||
private function translateSmiley( $matches ) {
|
||||
global $wpsmiliestrans;
|
||||
|
||||
if ( count( $matches ) === 0 ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$smiley = trim( reset( $matches ) );
|
||||
$img = $wpsmiliestrans[ $smiley ];
|
||||
|
||||
$matches = [];
|
||||
$ext = preg_match( '/\.([^.]+)$/', $img, $matches ) ? strtolower( $matches[1] ) : false;
|
||||
$image_exts = [ 'jpg', 'jpeg', 'jpe', 'gif', 'png' ];
|
||||
|
||||
// Don't convert smilies that aren't images - they're probably emoji.
|
||||
if ( ! in_array( $ext, $image_exts, true ) ) {
|
||||
return $img;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the Smiley image URL before it's used in the image element.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param string $smiley_url URL for the smiley image.
|
||||
* @param string $img Filename for the smiley image.
|
||||
* @param string $site_url Site URL, as returned by site_url().
|
||||
*/
|
||||
$src_url = apply_filters( 'smilies_src', includes_url( "images/smilies/$img" ), $img, site_url() );
|
||||
|
||||
// Don't LazyLoad if process is stopped for these reasons.
|
||||
if ( is_feed() || is_preview() ) {
|
||||
return sprintf( ' <img src="%s" alt="%s" class="wp-smiley" /> ', esc_url( $src_url ), esc_attr( $smiley ) );
|
||||
}
|
||||
|
||||
return sprintf( ' <img src="%s" data-lazy-src="%s" alt="%s" class="wp-smiley" /> ', $this->getPlaceholder(), esc_url( $src_url ), esc_attr( $smiley ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the placeholder for the src attribute
|
||||
*
|
||||
* @since 1.2
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @param int $width Width of the placeholder image. Default 0.
|
||||
* @param int $height Height of the placeholder image. Default 0.
|
||||
* @return string
|
||||
*/
|
||||
public function getPlaceholder( $width = 0, $height = 0 ) {
|
||||
$width = 0 === $width ? 0 : absint( $width );
|
||||
$height = 0 === $height ? 0 : absint( $height );
|
||||
|
||||
$placeholder = str_replace( ' ', '%20', "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 $width $height'%3E%3C/svg%3E" );
|
||||
/**
|
||||
* Filter the image lazyLoad placeholder on src attribute
|
||||
*
|
||||
* @since 1.1
|
||||
*
|
||||
* @param string $placeholder Placeholder that will be printed.
|
||||
* @param int $width Placeholder width.
|
||||
* @param int $height Placeholder height.
|
||||
*/
|
||||
return apply_filters( 'rocket_lazyload_placeholder', $placeholder, $width, $height );
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user