PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.7.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.7.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.7.0, at webp/class-wpo-webp-alter-html.php

191 lines 4.6 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 // MAX_FILE_SIZE is defined in simple_html_dom.
55 // For safety, we make sure it is defined before using
56 defined('MAX_FILE_SIZE') || define('MAX_FILE_SIZE', 600000);
57
58 $dom = WP_Optimize_Utils::get_simple_html_dom_object($html);
59
60 if (false === $dom) {
61 if (strlen($html) > MAX_FILE_SIZE) {
62 return $html . "\n" . "<!-- Alter HTML was skipped because the HTML is too big to process! " .
63 "(limit is set to " . MAX_FILE_SIZE . " bytes) -->";
64 }
65 return $html . "\n" . "<!-- Alter HTML was skipped because the helper library refused to process the html -->";
66 }
67
68 // Replace attributes (src, srcset, data-src, etc)
69 foreach ($this->tags as $tag) {
70 $elems = $dom->find($tag);
71 foreach ($elems as $elem) {
72 $attributes = $elem->getAllAttributes();
73 foreach ($attributes as $attr_name => $attr_value) {
74 if ($this->is_image_attribute($attr_name)) {
75 $elem->setAttribute($attr_name, $this->handle_attribute($attr_value));
76 }
77 }
78 }
79 }
80
81 return $dom->save();
82 }
83
84 /**
85 * Append image urls with `.webp` extension
86 *
87 * @param strinng $url - Image URL
88 * @return string
89 */
90 private function replace_url($url) {
91 return $url . '.webp';
92 }
93
94 /**
95 * If webp version for supplied image url is available then replace extension
96 *
97 * @param string $url - URL of image
98 * @return string
99 */
100 private function maybe_replace_url($url) {
101 if ($this->is_webp_version_available($url)) {
102 $url = $this->replace_url($url);
103 }
104 return $url;
105 }
106
107 /**
108 * Modifies src attribute value, if needed
109 *
110 * @param string $attr_value
111 * @return string
112 */
113 private function handle_src($attr_value) {
114 return $this->maybe_replace_url($attr_value);
115 }
116
117 /**
118 * Modified `srcset` attribute value, if needed
119 *
120 * @param string $attr_value
121 * @return string
122 */
123 private function handle_srcset($attr_value) {
124 // $attr_value is ie: <img data-x="1.jpg 1000w, 2.jpg">
125 $srcset_arr = explode(',', $attr_value);
126 foreach ($srcset_arr as $i => $srcset_entry) {
127 // $srcset_entry is ie "image.jpg 520w", but can also lack width, ie just "image.jpg"
128 // it can also be ie "image.jpg 2x"
129 $srcset_entry = trim($srcset_entry);
130 $entry_parts = preg_split('/\s+/', $srcset_entry, 2);
131 if (count($entry_parts) == 2) {
132 list($src, $descriptors) = $entry_parts;
133 } else {
134 $src = $srcset_entry;
135 $descriptors = null;
136 }
137
138 $url = $this->maybe_replace_url($src);
139 $srcset_arr[$i] = $url . (isset($descriptors) ? ' ' . $descriptors : '');
140 }
141 return implode(', ', $srcset_arr);
142 }
143
144 /**
145 * Decides whether given value is a `srcset` or not
146 *
147 * @return bool
148 */
149 private function looks_like_srcset($value) {
150 if (preg_match('#\s\d*(w|x)#', $value)) {
151 return true;
152 }
153 return false;
154 }
155
156 /**
157 * Handle attribute value based on attribute name, src or srcset
158 *
159 * @return string
160 */
161 private function handle_attribute($value) {
162 if ($this->looks_like_srcset($value)) {
163 return $this->handle_srcset($value);
164 }
165 return $this->handle_src($value);
166 }
167
168 /**
169 * Decide whether given attribute name is an image attribute or not
170 *
171 * @return bool
172 */
173 private function is_image_attribute($attr_name) {
174 return preg_match('#^(src|srcset|poster|(data-[^=]*(lazy|small|slide|img|large|src|thumb|source|set|bg-url)[^=]*))$#i', $attr_name);
175 }
176
177 /**
178 * Does webp image file exists
179 *
180 * @param string $url
181 * @return boolean
182 */
183 private function is_webp_version_available($url) {
184 $filename = WP_Optimize_Utils::get_file_path($url);
185 if (empty($filename)) return false;
186 return file_exists($filename . '.webp');
187 }
188 }
189
190 endif;
191