-
Notifications
You must be signed in to change notification settings - Fork 0
/
native-lazy-load.php
169 lines (144 loc) · 5.05 KB
/
native-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
162
163
164
165
166
167
168
169
<?php
/**
* Plugin Name: Native Lazy Load
* Plugin URI: https://github.com/wphandle/native-lazy-load
* Description: Native image lazy-loading for the web!
* Author: WP Handle, Mustafa Uysal
* Author URI: https://wphandle.com
* Text Domain: native-lazy-load
* Domain Path: /languages
* Version: 0.1.0
*
* Ported form https://github.com/Angrycreative/bj-lazy-load
*
* ############# Extremely Experimental #############
*
* @package Native_Lazy_Load
*/
class WPH_Native_Lazy_Load {
function __construct() {
add_action( 'wp', array( $this, 'init' ), PHP_INT_MAX ); // run this as late as possible
}
public static function load_type() {
return apply_filters( 'native_lazy_load_load_type', 'lazy' );
}
public function init() {
add_filter( 'native_lazy_load_filter', array( __CLASS__, 'filter_images' ) );
add_filter( 'native_lazy_load_filter', array( __CLASS__, 'filter_iframes' ) );
add_filter( 'the_content', array( __CLASS__, 'filter' ), 200 );
add_filter( 'widget_text', array( __CLASS__, 'filter' ), 200 );
add_filter( 'post_thumbnail_html', array( __CLASS__, 'filter' ), 200 );
add_filter( 'get_avatar', array( __CLASS__, 'filter' ), 200 );
add_filter( 'native_lazy_load_html', array( __CLASS__, 'filter' ) );
}
public static function filter_images( $content ) {
$match_content = self::_get_content_haystack( $content );
$matches = array();
preg_match_all( '/<img[\s\r\n]+.*?>/is', $match_content, $matches );
foreach ( $matches[0] as $imgHTML ) {
// don't to the replacement if the image is a data-uri
if ( ! preg_match( "/src=['\"]data:image/is", $imgHTML ) ) {
$replace = str_replace( '<img ', '<img loading="' . self::load_type() . '" ', $imgHTML );
$content = str_replace( $imgHTML, $replace, $content );
}
}
return $content;
}
public static function filter( $content ) {
// Last chance to bail out before running the filter
$run_filter = apply_filters( 'native_lazy_load_run_filter', true );
if ( ! $run_filter ) {
return $content;
}
/**
* Filter the content
*
* @param string $content The HTML string to filter
*/
$content = apply_filters( 'native_lazy_load_filter', $content );
return $content;
}
/**
* Replace iframes with placeholders in the content
*
* @param string $content The HTML to do the filtering on
*
* @return string The HTML with the iframes replaced
*/
public static function filter_iframes( $content ) {
$content = str_replace( '<iframe', '<iframe loading="' . self::load_type() . '"', $content );
return $content;
}
protected static function _get_content_haystack( $content ) {
$content = self::remove_noscript( $content );
$content = self::remove_skip_classes_elements( $content );
return $content;
}
/**
* Remove <noscript> elements from HTML string
*
* @author sigginet
*
* @param string $content The HTML string
*
* @return string The HTML string without <noscript> elements
*/
public static function remove_noscript( $content ) {
return preg_replace( '/<noscript.*?(\/noscript>)/i', '', $content );
}
/**
* Remove HTML elements with certain classnames (or IDs) from HTML string
*
* @param string $content The HTML string
*
* @return string The HTML string without the unwanted elements
*/
public static function remove_skip_classes_elements( $content ) {
$skip_classes = self::_get_skip_classes( 'html' );
/*
http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454
We can’t do this, but we still do it.
*/
$skip_classes_quoted = array_map( 'preg_quote', $skip_classes );
$skip_classes_ORed = implode( '|', $skip_classes_quoted );
$regex = '/<\s*\w*\s*class\s*=\s*[\'"]?(|.*\s)?' . $skip_classes_ORed . '(|\s.*)?[\'"]?.*?>/isU';
return preg_replace( $regex, '', $content );
}
/**
* Get the skip classes
*
* @param string $content_type The content type (image/iframe etc)
*
* @return array An array of strings with the class names
*/
protected static function _get_skip_classes( $content_type ) {
/**
* Filter the class names to skip
*
* @param array $skip_classes The current classes to skip
* @param string $content_type The current content type
*/
$skip_classes = apply_filters( 'native_lazy_load_skip_classes', array( 'lazy' ), $content_type );
return $skip_classes;
}
}
new WPH_Native_Lazy_Load();
add_action( 'wp_footer', 'native_lazy_load_compat_js' );
function native_lazy_load_compat_js() {
?>
<script>
if ('loading' in HTMLImageElement.prototype) {
const images = document.querySelectorAll('img.lazyload');
images.forEach(img => {
img.src = img.dataset.src;
});
} else {
// Dynamically import the LazySizes library
const script = document.createElement('script');
script.src =
'https://cdnjs.cloudflare.com/ajax/libs/lazysizes/4.1.8/lazysizes.min.js';
document.body.appendChild(script);
}
</script>
<?php
}