PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.5.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.5.0
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / webp / class-wpo-webp-alter-html.php

class-wpo-webp-alter-html.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 3.5.0, at webp/class-wpo-webp-alter-html.php

203 lines 5.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('WPO_VERSION')) die('No direct access allowed');
4
5 if (!class_exists('WPO_WebP_Alter_HTML')) :
6
7 class WPO_WebP_Alter_HTML {
8
9 private $tags = array('img', 'source', 'input', 'iframe', 'div', 'li', 'link', 'a', 'section', 'video');
10
11 /**
12 * Constructor
13 */
14 private function __construct() {
15 add_action('template_redirect', array($this, 'start'), 9999);
16 }
17
18 /**
19 * Returns singleton instance
20 *
21 * @return WPO_WebP_Alter_HTML
22 */
23 public static function get_instance() {
24 static $_instance = null;
25 if (null === $_instance) {
26 $_instance = new self();
27 }
28 return $_instance;
29 }
30
31 /**
32 * Start to alter html in output buffer
33 */
34 public function start() {
35 if (apply_filters('wpo_disable_webp_alter_html', false)) {
36 return;
37 }
38
39 if (!is_admin() || (defined('DOING_AJAX') && DOING_AJAX)) {
40 ob_start(array(__CLASS__, 'alter_html'));
41 }
42 }
43
44 /**
45 * Alter html to change image related tags to specify webp images
46 *
47 * @param string $html - HTML document as string
48 * @return string
49 */
50 public function alter_html($html) {
51
52 if (!WP_Optimize_Utils::is_valid_html($html)) return $html;
53
54 $this->maybe_include_simple_html_dom();
55
56 $dom = str_get_html($html, false, false, 'UTF-8', false, DEFAULT_BR_TEXT, DEFAULT_SPAN_TEXT, false);
57
58 // MAX_FILE_SIZE is defined in simple_html_dom.
59 // For safety sake, we make sure it is defined before using
60 defined('MAX_FILE_SIZE') || define('MAX_FILE_SIZE', 600000);
61
62 if (false === $dom) {
63 if (strlen($html) > MAX_FILE_SIZE) {
64 return '<!-- Alter HTML was skipped because the HTML is too big to process! ' .
65 '(limit is set to ' . MAX_FILE_SIZE . ' bytes) -->' . "\n" . $html;
66 }
67 return '<!-- Alter HTML was skipped because the helper library refused to process the html -->' .
68 "\n" . $html;
69 }
70
71 // Replace attributes (src, srcset, data-src, etc)
72 foreach ($this->tags as $tag) {
73 $elems = $dom->find($tag);
74 foreach ($elems as $elem) {
75 $attributes = $elem->getAllAttributes();
76 foreach ($attributes as $attr_name => $attr_value) {
77 if ($this->is_image_attribute($attr_name)) {
78 $elem->setAttribute($attr_name, $this->handle_attribute($attr_value));
79 }
80 }
81 }
82 }
83
84 return $dom->save();
85 }
86
87 /**
88 * Include simple html dom script if not available
89 */
90 private function maybe_include_simple_html_dom() {
91 if (!function_exists('str_get_html')) {
92 require_once WPO_PLUGIN_MAIN_PATH . 'vendor/simplehtmldom/simplehtmldom/simple_html_dom.php';
93 }
94 }
95
96 /**
97 * Append image urls with `.webp` extension
98 *
99 * @param strinng $url - Image URL
100 * @return string
101 */
102 private function replace_url($url) {
103 return $url . '.webp';
104 }
105
106 /**
107 * If webp version for supplied image url is available then replace extension
108 *
109 * @param string $url - URL of image
110 * @return string
111 */
112 private function maybe_replace_url($url) {
113 if ($this->is_webp_version_available($url)) {
114 $url = $this->replace_url($url);
115 }
116 return $url;
117 }
118
119 /**
120 * Modifies src attribute value, if needed
121 *
122 * @param string $attr_value
123 * @return string
124 */
125 private function handle_src($attr_value) {
126 return $this->maybe_replace_url($attr_value);
127 }
128
129 /**
130 * Modified `srcset` attribute value, if needed
131 *
132 * @param string $attr_value
133 * @return string
134 */
135 private function handle_srcset($attr_value) {
136 // $attr_value is ie: <img data-x="1.jpg 1000w, 2.jpg">
137 $srcset_arr = explode(',', $attr_value);
138 foreach ($srcset_arr as $i => $srcset_entry) {
139 // $srcset_entry is ie "image.jpg 520w", but can also lack width, ie just "image.jpg"
140 // it can also be ie "image.jpg 2x"
141 $srcset_entry = trim($srcset_entry);
142 $entry_parts = preg_split('/\s+/', $srcset_entry, 2);
143 if (count($entry_parts) == 2) {
144 list($src, $descriptors) = $entry_parts;
145 } else {
146 $src = $srcset_entry;
147 $descriptors = null;
148 }
149
150 $url = $this->maybe_replace_url($src);
151 $srcset_arr[$i] = $url . (isset($descriptors) ? ' ' . $descriptors : '');
152 }
153 return implode(', ', $srcset_arr);
154 }
155
156 /**
157 * Decides whether given value is a `srcset` or not
158 *
159 * @return bool
160 */
161 private function looks_like_srcset($value) {
162 if (preg_match('#\s\d*(w|x)#', $value)) {
163 return true;
164 }
165 return false;
166 }
167
168 /**
169 * Handle attribute value based on attribute name, src or srcset
170 *
171 * @return string
172 */
173 private function handle_attribute($value) {
174 if ($this->looks_like_srcset($value)) {
175 return $this->handle_srcset($value);
176 }
177 return $this->handle_src($value);
178 }
179
180 /**
181 * Decide whether given attribute name is an image attribute or not
182 *
183 * @return bool
184 */
185 private function is_image_attribute($attr_name) {
186 return preg_match('#^(src|srcset|poster|(data-[^=]*(lazy|small|slide|img|large|src|thumb|source|set|bg-url)[^=]*))$#i', $attr_name);
187 }
188
189 /**
190 * Does webp image file exists
191 *
192 * @param string $url
193 * @return boolean
194 */
195 private function is_webp_version_available($url) {
196 $filename = WP_Optimize_Utils::get_file_path($url);
197 if (empty($filename)) return false;
198 return file_exists($filename . '.webp');
199 }
200 }
201
202 endif;
203