PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.7.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.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
← All changes | webp/class-wpo-webp-alter-html.php +83 -77 3.7.0 → 4.7.0 View file →
@@ -1,27 +1,35 @@
1 1 <?php
2 2
3 -if (!defined('WPO_VERSION')) die('No direct access allowed');
3 +if (!defined('ABSPATH')) die('No direct access allowed');
4 4
5 5 if (!class_exists('WPO_WebP_Alter_HTML')) :
6 6
7 7 class WPO_WebP_Alter_HTML {
8 8
9 - private $tags = array('img', 'source', 'input', 'iframe', 'div', 'li', 'link', 'a', 'section', 'video');
9 + /**
10 + * HTML tags that may contain image-related attributes eligible for WebP replacement.
11 + */
12 + const SUPPORTED_TAGS = array('img', 'source', 'input', 'iframe', 'div', 'li', 'link', 'a', 'section', 'video');
10 13
11 14 /**
12 - * Constructor
15 + * Regex pattern to identify image-related attribute names such as src, srcset,
16 + * poster, and common data-* attributes used for lazy loading or responsive images.
13 17 */
18 + const IMAGE_ATTRIBUTE_PATTERN = '#^(src|srcset|poster|(data-[^=]*(lazy|small|slide|img|large|src|thumb|source|set|bg-url)[^=]*))$#i';
19 +
20 + /**
21 + * Constructor — private to enforce singleton pattern.
22 + */
14 23 private function __construct() {
15 - add_action('template_redirect', array($this, 'start'), 9999);
16 24 }
17 25
18 26 /**
19 - * Returns singleton instance
27 + * Returns singleton instance.
20 28 *
21 - * @return WPO_WebP_Alter_HTML
29 + * @return self
22 30 */
23 - public static function get_instance() {
31 + public static function get_instance(): self {
24 32 static $_instance = null;
25 33 if (null === $_instance) {
26 34 $_instance = new self();
27 35 }
@@ -26,50 +34,45 @@
26 34 $_instance = new self();
27 35 }
28 36 return $_instance;
29 37 }
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 38
39 - if (!is_admin() || (defined('DOING_AJAX') && DOING_AJAX)) {
40 - ob_start(array(__CLASS__, 'alter_html'));
41 - }
42 - }
43 -
44 39 /**
45 - * Alter html to change image related tags to specify webp images
40 + * Alter HTML to replace image-related attributes with WebP URLs where available.
46 41 *
47 - * @param string $html - HTML document as string
42 + * @param string $html HTML document as string.
48 43 * @return string
49 44 */
50 - public function alter_html($html) {
51 -
52 - if (!WP_Optimize_Utils::is_valid_html($html)) return $html;
45 + public function alter_html(string $html): string {
46 + if (apply_filters('wpo_disable_webp_alter_html', false)) {
47 + return $html;
48 + }
53 49
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);
50 + // MAX_FILE_SIZE is defined in simple_html_dom — ensure it has a safe default.
51 + WP_Optimize_Utils::define_maxfile_size_constant();
57 52
58 53 $dom = WP_Optimize_Utils::get_simple_html_dom_object($html);
59 54
60 55 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 -->";
56 + return $this->get_skipped_html($html);
66 57 }
67 58
68 - // Replace attributes (src, srcset, data-src, etc)
69 - foreach ($this->tags as $tag) {
70 - $elems = $dom->find($tag);
71 - foreach ($elems as $elem) {
59 + $this->replace_image_attributes($dom);
60 +
61 + return $dom->save();
62 + }
63 +
64 + /**
65 + * Walks all supported tags in the DOM and replaces image attribute values
66 + * with their WebP counterparts when available.
67 + *
68 + * @param simplehtmldom\HtmlDocument $dom A simple_html_dom instance.
69 + *
70 + * @return void
71 + */
72 + private function replace_image_attributes($dom): void {
73 + foreach (self::SUPPORTED_TAGS as $tag) {
74 + foreach ($dom->find($tag) as $elem) {
72 75 $attributes = $elem->getAllAttributes();
73 76 foreach ($attributes as $attr_name => $attr_value) {
74 77 if ($this->is_image_attribute($attr_name)) {
75 78 $elem->setAttribute($attr_name, $this->handle_attribute($attr_value));
@@ -76,52 +79,49 @@
76 79 }
77 80 }
78 81 }
79 82 }
80 -
81 - return $dom->save();
82 83 }
83 84
84 85 /**
85 - * Append image urls with `.webp` extension
86 + * Returns the original HTML annotated with a comment explaining why
87 + * the WebP alteration was skipped.
86 88 *
87 - * @param strinng $url - Image URL
89 + * @param string $html The original HTML document.
88 90 * @return string
89 91 */
90 - private function replace_url($url) {
91 - return $url . '.webp';
92 + private function get_skipped_html($html): string {
93 + if (strlen($html) > MAX_FILE_SIZE) {
94 + return $html . "\n" . "<!-- Alter HTML was skipped because the HTML is too big to process! " .
95 + "(limit is set to " . MAX_FILE_SIZE . " bytes) -->";
96 + }
97 + return $html . "\n" . "<!-- Alter HTML was skipped because the helper library refused to process the html -->";
92 98 }
93 99
94 100 /**
95 - * If webp version for supplied image url is available then replace extension
101 + * Returns the URL with a .webp extension appended if a WebP version exists on disk.
96 102 *
97 - * @param string $url - URL of image
103 + * @param string $url URL of the original image.
98 104 * @return string
99 105 */
100 - private function maybe_replace_url($url) {
106 + private function maybe_replace_url($url): string {
101 107 if ($this->is_webp_version_available($url)) {
102 - $url = $this->replace_url($url);
108 + $url .= '.webp';
103 109 }
104 110 return $url;
105 111 }
106 112
107 113 /**
108 - * Modifies src attribute value, if needed
114 + * Processes a srcset attribute value, replacing each image URL with its
115 + * WebP counterpart when available.
109 116 *
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
117 + * A srcset value is a comma-separated list of entries such as
118 + * "image.jpg 520w" or "image.jpg 2x" or just "image.jpg".
119 119 *
120 - * @param string $attr_value
120 + * @param string $attr_value The raw srcset attribute value.
121 121 * @return string
122 122 */
123 - private function handle_srcset($attr_value) {
123 + private function handle_srcset($attr_value): string {
124 124 // $attr_value is ie: <img data-x="1.jpg 1000w, 2.jpg">
125 125 $srcset_arr = explode(',', $attr_value);
126 126 foreach ($srcset_arr as $i => $srcset_entry) {
127 127 // $srcset_entry is ie "image.jpg 520w", but can also lack width, ie just "image.jpg"
@@ -127,9 +127,10 @@
127 127 // $srcset_entry is ie "image.jpg 520w", but can also lack width, ie just "image.jpg"
128 128 // it can also be ie "image.jpg 2x"
129 129 $srcset_entry = trim($srcset_entry);
130 130 $entry_parts = preg_split('/\s+/', $srcset_entry, 2);
131 - if (count($entry_parts) == 2) {
131 +
132 + if (is_array($entry_parts) && 2 === count($entry_parts)) {
132 133 list($src, $descriptors) = $entry_parts;
133 134 } else {
134 135 $src = $srcset_entry;
135 136 $descriptors = null;
@@ -141,49 +142,54 @@
141 142 return implode(', ', $srcset_arr);
142 143 }
143 144
144 145 /**
145 - * Decides whether given value is a `srcset` or not
146 + * Determines whether an attribute value resembles a srcset declaration
147 + * (contains a width or pixel-density descriptor).
146 148 *
149 + * @param string $value The attribute value to inspect.
147 150 * @return bool
148 151 */
149 - private function looks_like_srcset($value) {
150 - if (preg_match('#\s\d*(w|x)#', $value)) {
151 - return true;
152 - }
153 - return false;
152 + private function looks_like_srcset($value): bool {
153 + return (bool) preg_match('#\s\d*(w|x)#', $value);
154 154 }
155 155
156 156 /**
157 - * Handle attribute value based on attribute name, src or srcset
157 + * Dispatches attribute value handling based on whether it looks like a
158 + * srcset or a plain image source URL.
158 159 *
160 + * @param string $value The attribute value.
159 161 * @return string
160 162 */
161 - private function handle_attribute($value) {
163 + private function handle_attribute($value): string {
162 164 if ($this->looks_like_srcset($value)) {
163 165 return $this->handle_srcset($value);
164 166 }
165 - return $this->handle_src($value);
167 + return $this->maybe_replace_url($value);
166 168 }
167 169
168 170 /**
169 - * Decide whether given attribute name is an image attribute or not
171 + * Determines whether an attribute name is image-related and should be
172 + * considered for WebP replacement.
170 173 *
174 + * @param string $attr_name The attribute name.
171 175 * @return bool
172 176 */
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);
177 + private function is_image_attribute($attr_name): bool {
178 + return (bool) preg_match(self::IMAGE_ATTRIBUTE_PATTERN, $attr_name);
175 179 }
176 180
177 181 /**
178 - * Does webp image file exists
182 + * Checks whether a WebP version of the given image URL exists on disk.
179 183 *
180 - * @param string $url
181 - * @return boolean
184 + * @param string $url The original image URL.
185 + * @return bool
182 186 */
183 - private function is_webp_version_available($url) {
187 + private function is_webp_version_available($url): bool {
184 188 $filename = WP_Optimize_Utils::get_file_path($url);
185 - if (empty($filename)) return false;
189 + if (empty($filename)) {
190 + return false;
191 + }
186 192 return file_exists($filename . '.webp');
187 193 }
188 194 }
189 195