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-utils.php +114 -38 4.5.2 → 4.7.0 View file →
@@ -10,31 +10,67 @@
10 10
11 11 class WPO_WebP_Utils {
12 12
13 13 /**
14 - * Determines whether we can do webp conversion or not
14 + * Minimum Firefox version that supports WebP images.
15 15 *
16 + * @see https://caniuse.com/webp
17 + */
18 + const MIN_FIREFOX_VERSION_FOR_WEBP = '65.0.0';
19 +
20 + /**
21 + * Warning message patterns to suppress during WebP conversion.
22 + *
23 + * @var array<string>
24 + */
25 + private static $suppressed_warning_patterns = array(
26 + '/unlink\(.+\): No such file or directory/',
27 + '/rename\(.+\): No such file or directory/',
28 + '/filesize\(\): stat failed for/',
29 + );
30 +
31 + /**
32 + * Determines whether we can do webp conversion or not.
33 + *
16 34 * @return bool
17 35 */
18 - public static function can_do_webp_conversion() {
19 - $webp_conversion = WP_Optimize()->get_options()->get_option('webp_conversion');
20 - $webp_converters = WP_Optimize()->get_options()->get_option('webp_converters');
36 + public static function can_do_webp_conversion(): bool {
37 + $options = WP_Optimize()->get_options();
38 + $webp_conversion = $options->get_option('webp_conversion');
39 + $webp_converters = $options->get_option('webp_converters');
40 +
21 41 return $webp_conversion && !empty($webp_converters);
22 42 }
23 43
24 44 /**
25 - * Convert given image file to webp format
45 + * Convert given image file to webp format.
26 46 *
27 - * @param string $source Path of image file
47 + * @param string $source Path of image file.
48 + * @param bool $convert_if_exists Whether to convert if the webp file already exists or not.
28 49 *
29 50 * @return void
30 51 */
31 - public static function do_webp_conversion($source) {
32 - $webp_converter = new WPO_WebP_Convert();
52 + public static function do_webp_conversion($source, $convert_if_exists = false): void {
53 + if (file_exists(self::get_destination_path($source)) && !$convert_if_exists) {
54 + return;
55 + }
56 +
57 + $webp_converter = WPO_WebP_Convert::get_instance();
33 58 $webp_converter->convert($source);
34 59 }
35 60
36 61 /**
62 + * Returns the destination full path.
63 + *
64 + * @param string $source Path of the source file.
65 + *
66 + * @return string Path of destination file.
67 + */
68 + public static function get_destination_path($source): string {
69 + return dirname($source) . '/' . basename($source) . '.webp';
70 + }
71 +
72 + /**
37 73 * Converts an image to WebP format using a specified converter.
38 74 *
39 75 * This method acts as a wrapper for the `WebPConvert\Convert\Converters\AbstractConverter::doConvert()` method
40 76 * from the `webp-convert` library.
@@ -41,67 +77,107 @@
41 77 *
42 78 * @param string $converter The converter to be used for the conversion process.
43 79 * @param string $source The path to the source image file.
44 80 * @param string $destination The path to the destination WebP image file.
81 + *
82 + * @return void
45 83 */
46 - public static function perform_webp_conversion($converter, $source, $destination) {
47 - $converter_instance = ConverterFactory::makeConverter(
48 - $converter,
49 - $source,
50 - $destination
51 - );
84 + public static function perform_webp_conversion($converter, $source, $destination): void {
85 + set_error_handler(array(__CLASS__, 'handle_webp_conversion_warnings'), E_WARNING); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler -- This is needed in order to suppress PHP warnings thrown by third party library
52 86
53 - set_error_handler(array(__CLASS__, 'handle_webp_conversion_warnings'), E_WARNING); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler -- This is needed in order to suppress PHP warnings thrown by third party library
87 + try {
88 + $converter_instance = ConverterFactory::makeConverter(
89 + $converter,
90 + $source,
91 + $destination
92 + );
54 93
55 - $converter_instance->doConvert();
94 + $converter_instance->doConvert();
56 95
57 - restore_error_handler();
96 + restore_error_handler();
97 + } catch (Exception $e) {
98 + restore_error_handler(); // Make sure we restore even if an exception occurs
99 +
100 + $log_details = 'Converter: '.$converter. ', '.WP_Optimize_Utils::get_wp_relative_path($source).' => '.WP_Optimize_Utils::get_wp_relative_path($destination);
101 + WP_Optimize_WebP::get_instance()->log('Failed to convert to WebP: '. $log_details);
102 + throw new Exception(esc_html(__('Failed to convert to WebP.', 'wp-optimize')));
103 + }
58 104 }
59 105
60 106 /**
61 107 * Custom error handler for handling PHP warnings during the WebP conversion process.
62 108 *
63 - * @param int $errno The level of the error raised, as an integer.
109 + * @param int $errno The level of the error raised.
64 110 * @param string $errstr The error message.
65 111 *
66 112 * @return bool
67 113 */
68 - public static function handle_webp_conversion_warnings($errno, $errstr) {
69 - $patterns = array(
70 - '/unlink\(.+\): No such file or directory/',
71 - '/rename\(.+\): No such file or directory/',
72 - '/filesize\(\): stat failed for/',
73 - );
74 -
75 - foreach ($patterns as $pattern) {
114 + public static function handle_webp_conversion_warnings($errno, $errstr): bool {
115 + foreach (self::$suppressed_warning_patterns as $pattern) {
76 116 if (preg_match($pattern, $errstr)) {
77 - // Suppress the warning by returning true
78 117 return true;
79 118 }
80 119 }
81 120
82 - // For other PHP warnings, use the default PHP error handler by returning false
83 121 return false;
84 122 }
85 -
123 +
86 124 /**
87 - * Decide whether the browser requesting the URL can accept webp images or not
125 + * Decide whether the browser requesting the URL can accept webp images or not.
88 126 *
89 127 * @return bool
90 128 */
91 - public static function is_browser_accepting_webp() {
92 - $http_accept = TeamUpdraft\WP_Optimize\Includes\Fragments\fetch_superglobal('server', 'HTTP_ACCEPT', 'string', 'sanitize_text_field', '');
93 - if (false !== strpos($http_accept, 'image/webp')) {
129 + public static function is_browser_accepting_webp(): bool {
130 + if (self::browser_accepts_webp_header()) {
94 131 return true;
95 132 }
96 133
97 - // Link to compatibility site - https://caniuse.com/webp
98 - $user_agent = TeamUpdraft\WP_Optimize\Includes\Fragments\fetch_superglobal('server', 'HTTP_USER_AGENT', 'string', 'sanitize_text_field', '');
99 - if (empty($user_agent)) return false;
134 + return self::user_agent_supports_webp();
135 + }
100 136
101 - // Check Firefox version number
137 + /**
138 + * Check if the HTTP Accept header indicates WebP support.
139 + *
140 + * @return bool
141 + */
142 + private static function browser_accepts_webp_header(): bool {
143 + $http_accept = TeamUpdraft\WP_Optimize\Includes\Fragments\fetch_superglobal(
144 + 'server',
145 + 'HTTP_ACCEPT',
146 + 'string',
147 + 'sanitize_text_field',
148 + ''
149 + );
150 +
151 + if (!is_string($http_accept)) {
152 + return false;
153 + }
154 +
155 + return false !== strpos($http_accept, 'image/webp');
156 + }
157 +
158 + /**
159 + * Check if the user agent indicates WebP support based on known browser versions.
160 + *
161 + * @return bool
162 + */
163 + private static function user_agent_supports_webp(): bool {
164 + $user_agent = TeamUpdraft\WP_Optimize\Includes\Fragments\fetch_superglobal(
165 + 'server',
166 + 'HTTP_USER_AGENT',
167 + 'string',
168 + 'sanitize_text_field',
169 + ''
170 + );
171 +
172 + if (empty($user_agent) || !is_string($user_agent)) {
173 + return false;
174 + }
175 +
102 176 if (preg_match('/Firefox\/([\d\.]+[a-z\d]*)/', $user_agent, $matches)) {
103 - if (version_compare('65.0.0', $matches[1], '<=')) return true;
177 + if (version_compare(self::MIN_FIREFOX_VERSION_FOR_WEBP, $matches[1], '<=')) {
178 + return true;
179 + }
104 180 }
105 181
106 182 return false;
107 183 }