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-wp-optimize-webp.php +429 -128 3.2.20 → 4.7.0 View file →
@@ -1,145 +1,290 @@
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('WP_Optimize_WebP')) :
6 6
7 7 class WP_Optimize_WebP {
8 8
9 - private $_htaccess = null;
9 + /**
10 + * @var WP_Optimize_Htaccess
11 + */
12 + private $_htaccess;
10 13
11 - private $_should_use_webp = false;
14 + /**
15 + * Set to true when webp is enabled and vice versa
16 + *
17 + * @var boolean
18 + */
19 + private $_should_use_webp;
12 20
13 21 /**
22 + * The logger for this instance
23 + *
24 + * @var Updraft_File_Logger
25 + */
26 + private $logger;
27 +
28 + /**
14 29 * Constructor
15 30 */
16 31 private function __construct() {
17 - if ($this->should_run_webp_conversion_test()) {
18 - $this->set_converter_status();
19 - }
32 + $this->_should_use_webp = (bool) WP_Optimize()->get_options()->get_option('webp_conversion');
20 33
21 - if ($this->get_webp_conversion_test_result()) {
22 - $this->maybe_setup_htaccess_file();
23 - if (!is_admin()) {
24 - $this->maybe_decide_webp_serve_method();
25 - }
26 - } else {
27 - $this->empty_htaccess_file();
28 - }
34 + $this->logger = new Updraft_File_Logger($this->get_logfile_path());
29 35
30 - $this->init_webp_cron_scheduler();
36 + add_action('wpo_reset_webp_conversion_test_result', array($this, 'reset_webp_serving_method'));
37 + add_action('wpo_prune_webp_logs', array($this, 'prune_webp_logs'));
38 + $task_manager = WPO_Webp_Task_Manager::get_instance();
39 + add_action('wpo_webp_convert_compressed_images', array($task_manager, 'webp_convert_compressed_images'));
31 40 }
32 41
33 42 /**
34 43 * Returns singleton instance
35 44 *
36 - * @return WP_Optimize_WebP
45 + * @return self
37 46 */
38 - public static function get_instance() {
47 + public static function get_instance(): self {
39 48 static $instance = null;
40 49 if (null === $instance) {
41 - $instance = new WP_Optimize_WebP();
50 + $instance = new self();
42 51 }
43 52 return $instance;
44 53 }
45 54
46 55 /**
47 - * Test Run and find converter status
56 + * Evaluate WebP conversion capability.
57 + *
58 + * @return array{is_available: bool, reason: string, message: string, converter_status: array<string, array<string>>, test_ran: bool}
48 59 */
49 - private function set_converter_status() {
50 - if (!class_exists('WPO_WebP_Test_Run')) {
51 - require_once WPO_PLUGIN_MAIN_PATH . 'webp/class-wpo-webp-test-run.php';
60 + public function evaluate_webp_capability(): array {
61 + $converter_status = array();
62 + $test_ran = false;
63 + if ($this->is_only_shell_converters_available() && !$this->shell_functions_available()) {
64 + return array(
65 + 'is_available' => false,
66 + 'reason' => 'update_failed_no_shell_functions',
67 + 'message' => __('Required WebP shell functions are not available on the server.', 'wp-optimize'),
68 + 'converter_status' => $converter_status,
69 + 'test_ran' => $test_ran,
70 + );
52 71 }
53 - $converter_status = WPO_WebP_Test_Run::get_converter_status();
54 - if ($this->is_webp_conversion_successful()) {
55 - WP_Optimize()->get_options()->update_option('webp_conversion_test', true);
56 - WP_Optimize()->get_options()->update_option('webp_converters', $converter_status['working_converters']);
72 +
73 + if ($this->should_run_webp_conversion_test()) {
74 + $test_ran = true;
75 + $converter_status = WPO_WebP_Test_Run::get_converter_status();
76 + if (!$this->is_webp_conversion_successful()) {
77 + return array(
78 + 'is_available' => false,
79 + 'reason' => 'update_failed_no_working_webp_converter',
80 + 'message' => __('No working WebP converter was found on the server.', 'wp-optimize'),
81 + 'converter_status' => $converter_status,
82 + 'test_ran' => $test_ran,
83 + );
84 + }
57 85 }
86 +
87 + return array(
88 + 'is_available' => true,
89 + 'reason' => '',
90 + 'message' => '',
91 + 'converter_status' => $converter_status,
92 + 'test_ran' => $test_ran,
93 + );
58 94 }
59 95
60 96 /**
61 - * May be set up `uploads/.htaccess` file
97 + * Try to enable webp conversion, upon failure disable webp conversion
98 + *
99 + * @param array<string, string> $data - Data webp_conversion (true|false)
100 + * @return WP_Error|bool - information about the operation or WP_Error object on failure
62 101 */
63 - private function maybe_setup_htaccess_file() {
64 - $this->_should_use_webp = WP_Optimize()->get_options()->get_option('webp_conversion');
65 - if ($this->_should_use_webp) {
66 - $this->setup_htaccess_file();
67 - }
68 - }
102 + private function configure_webp_conversion($data) {
69 103
70 - /**
71 - * If webp images should be used, then decide whether it is possible to server webp
72 - * using rewrite rules or using altered html method
73 - */
74 - private function maybe_decide_webp_serve_method() {
75 - if (!$this->_should_use_webp) {
76 - $this->empty_htaccess_file();
77 - } else {
104 + $options = array();
105 + $options['webp_conversion'] = isset($data['webp_conversion']) ? filter_var($data['webp_conversion'], FILTER_VALIDATE_BOOLEAN) : false;
106 +
107 + if ($options['webp_conversion']) {
108 + $capability = $this->evaluate_webp_capability();
109 +
110 + if (!$capability['is_available']) {
111 + $this->disable_webp_conversion();
112 + $message = $capability['message'];
113 + $reason = $capability['reason'];
114 + $this->log($message);
115 + return new WP_Error($reason, $message);
116 + }
117 +
118 + // Only update the test result and converters if the test actually ran
119 + if ($capability['test_ran']) {
120 + $options['webp_conversion_test'] = true;
121 + $options['webp_converters'] = $capability['converter_status']['working_converters'] ?? array();
122 + }
123 +
124 + // Run serving methods tests and set necessary option values
125 + // Not possible to test alter HTML since the test is browser-based
78 126 $this->save_htaccess_rules();
79 127 if (!$this->is_webp_redirection_possible()) {
80 128 $this->empty_htaccess_file();
81 - $this->maybe_use_alter_html();
129 + $options['redirection_possible'] = 'false';
130 + } else {
131 + $options['redirection_possible'] = 'true';
82 132 }
83 133 }
134 + $smush_manager = Updraft_Smush_Manager::instance();
135 + $success = $smush_manager->update_smush_options($options);
136 +
137 + if (!$success) {
138 + $this->disable_webp_conversion();
139 + $message = __('WebP options could not be updated.', 'wp-optimize');
140 + $this->log($message);
141 + return new WP_Error('update_failed', $message);
142 + }
143 +
144 + // Set up daily CRON only when enabling WebP and Delete daily CRON when disabling WebP
145 + if ($options['webp_conversion']) {
146 + $this->init_webp_cron_scheduler();
147 + } else {
148 + $this->remove_webp_cron_schedules();
149 + $this->empty_htaccess_file();
150 + }
151 + return $success;
84 152 }
85 153
86 154 /**
87 - * If alter html method is possible, then use it
155 + * Save WebP settings and trigger related actions.
156 + *
157 + * @param array<string, string> $data WebP settings (expects 'webp_conversion').
158 + * @return bool|WP_Error True on success, WP_Error on failure.
88 159 */
89 - private function maybe_use_alter_html() {
90 - if ($this->is_alter_html_possible()) {
91 - $this->use_alter_html();
160 + public function save_webp_settings($data) {
161 +
162 + if (!is_array($data)) {
163 + return new WP_Error('invalid_data', __('Invalid WebP settings data.', 'wp-optimize'));
92 164 }
165 +
166 + $result = $this->configure_webp_conversion($data);
167 +
168 + if (!is_wp_error($result)) {
169 + do_action('wpo_save_images_settings');
170 + }
171 +
172 + return $result;
93 173 }
94 174
95 175 /**
96 - * Even if server support .htaccess rewrite, sometimes it is not possible
97 - * to serve webp images. So, find it webp redirection is possible or not
176 + * Returns the path to the logfile
98 177 *
99 - * @return bool
178 + * @return string - file path
100 179 */
101 - private function is_webp_redirection_possible() {
102 - $redirection_possible = WP_Optimize()->get_options()->get_option('redirection_possible');
103 - if (!empty($redirection_possible)) return 'true' === $redirection_possible;
104 - return $this->run_webp_serving_self_test();
180 + private function get_logfile_path(): string {
181 + return WP_Optimize_Utils::get_log_file_path('webp');
105 182 }
106 183
107 184 /**
108 - * Decide whether the browser requesting the URL can accept webp images or not
185 + * Logging of interesting messages related to WebP.
109 186 *
110 - * @return bool
187 + * @param string $message Log message
188 + * @param string $level Log level (e.g., 'info', 'warning', 'error')
189 + *
190 + * @return void
111 191 */
112 - private function is_browser_accepting_webp() {
113 - return (isset($_SERVER['HTTP_ACCEPT']) && false !== strpos($_SERVER['HTTP_ACCEPT'], 'image/webp'));
192 + public function log(string $message, string $level = 'info'): void {
193 + $this->logger->log($message, $level);
114 194 }
115 -
195 +
116 196 /**
117 - * Detect whether using alter HTML method is possible or not
197 + * Prunes the log file
118 198 *
119 - * @return bool
199 + * @return void
120 200 */
121 - private function is_alter_html_possible() {
122 - if ($this->is_browser_accepting_webp()) {
123 - return true;
201 + public function prune_webp_logs(): void {
202 + $this->log("Pruning the WebP log file");
203 + $this->logger->prune_logs();
204 + }
205 +
206 + /**
207 + * Test Run and find converter status
208 + *
209 + * @return void
210 + */
211 + private function set_converter_status(): void {
212 + $converter_status = WPO_WebP_Test_Run::get_converter_status();
213 + if ($this->is_webp_conversion_successful()) {
214 + WP_Optimize()->get_options()->update_option('webp_conversion_test', true);
215 + WP_Optimize()->get_options()->update_option('webp_converters', $converter_status['working_converters']);
124 216 }
125 - return false;
126 217 }
127 218
128 219 /**
129 - * Setup alter html method
220 + * If .htaccess redirection is not possible, attempts to use the alter_html method.
221 + *
222 + * @param string $buffer Page HTML
223 + *
224 + * @return string
130 225 */
131 - private function use_alter_html() {
132 - if (!class_exists('WPO_WebP_Alter_HTML')) {
133 - require_once WPO_PLUGIN_MAIN_PATH . 'webp/class-wpo-webp-alter-html.php';
226 + public function maybe_decide_webp_serve_method(string $buffer): string {
227 + if (!$this->is_webp_redirection_possible()) {
228 + $buffer = $this->maybe_use_alter_html($buffer);
134 229 }
135 - WPO_WebP_Alter_HTML::get_instance();
230 + return $buffer;
136 231 }
137 232
138 233 /**
234 + * If alter HTML method is possible, apply it to the buffer.
235 + *
236 + * @param string $buffer Page HTML
237 + *
238 + * @return string
239 + */
240 + private function maybe_use_alter_html(string $buffer): string {
241 + if ($this->is_alter_html_possible()) {
242 + $this->empty_htaccess_file();
243 + $buffer = WPO_WebP_Alter_HTML::get_instance()->alter_html($buffer);
244 + }
245 + return $buffer;
246 + }
247 +
248 + /**
249 + * Even if the server supports .htaccess rewrite, sometimes it is not possible
250 + * to serve webp images. This method determines whether webp redirection is possible.
251 + *
252 + * Also applies `wpo_force_webp_serve_using_altered_html` filter for users to be able to
253 + * force the Altered HTML method.
254 + *
255 + * @return bool
256 + */
257 + public function is_webp_redirection_possible(): bool {
258 + if (apply_filters('wpo_force_webp_serve_using_altered_html', false)) {
259 + return false;
260 + }
261 +
262 + $redirection_possible = WP_Optimize()->get_options()->get_option('redirection_possible');
263 +
264 + // If a previous test result exists, use it; otherwise, run the self test
265 + if (!empty($redirection_possible)) {
266 + return 'true' === $redirection_possible;
267 + }
268 +
269 + return $this->run_webp_serving_self_test();
270 + }
271 +
272 + /**
273 + * Detect whether using alter HTML method is possible or not
274 + *
275 + * @return bool
276 + */
277 + private function is_alter_html_possible(): bool {
278 + return WPO_WebP_Utils::is_browser_accepting_webp();
279 + }
280 +
281 + /**
139 282 * Initialize .htaccess
283 + *
284 + * @return void
140 285 */
141 - private function setup_htaccess_file() {
286 + private function setup_htaccess_file(): void {
142 287 if (null !== $this->_htaccess) return;
143 288 $wp_uploads = wp_get_upload_dir();
144 289 $htaccess_file = $wp_uploads['basedir'] . '/.htaccess';
145 290 if (!file_exists($htaccess_file)) {
@@ -144,11 +289,8 @@
144 289 $htaccess_file = $wp_uploads['basedir'] . '/.htaccess';
145 290 if (!file_exists($htaccess_file)) {
146 291 file_put_contents($htaccess_file, '');
147 292 }
148 - if (!class_exists('WP_Optimize_Htaccess')) {
149 - require_once WPO_PLUGIN_MAIN_PATH . 'includes/class-wp-optimize-htaccess.php';
150 - }
151 293 $this->_htaccess = new WP_Optimize_Htaccess($htaccess_file);
152 294 }
153 295
154 296 /**
@@ -155,20 +297,26 @@
155 297 * Save .htaccess rules
156 298 *
157 299 * @return void
158 300 */
159 - private function save_htaccess_rules() {
301 + private function save_htaccess_rules(): void {
302 + $this->setup_htaccess_file();
160 303 $this->add_webp_mime_type();
161 304 $htaccess_comment_section = 'WP-Optimize WebP Rules';
162 305 if ($this->_htaccess->is_commented_section_exists($htaccess_comment_section)) return;
163 306 $this->_htaccess->update_commented_section($this->prepare_webp_htaccess_rules(), $htaccess_comment_section);
164 307 $this->_htaccess->write_file();
308 + WP_Optimize()->get_options()->update_option('htaccess_has_webp_rules', true);
165 309 }
166 310
167 311 /**
168 312 * Empty .htaccess file
313 + *
314 + * @return void
169 315 */
170 - public function empty_htaccess_file() {
316 + private function empty_htaccess_file(): void {
317 + // Setting default to true, so on initial run (when option is not yet present in the DB) we don't break the function here
318 + if (!WP_Optimize()->get_options()->get_option('htaccess_has_webp_rules', true)) return;
171 319 $this->setup_htaccess_file();
172 320 $htaccess_comment_sections = array(
173 321 'WP-Optimize WebP Rules',
174 322 'Register webp mime type',
@@ -173,17 +321,19 @@
173 321 'WP-Optimize WebP Rules',
174 322 'Register webp mime type',
175 323 );
176 324 foreach ($htaccess_comment_sections as $htaccess_comment_section) {
325 + if (!$this->_htaccess->is_commented_section_exists($htaccess_comment_section)) continue;
177 326 $this->_htaccess->remove_commented_section($htaccess_comment_section);
178 327 $this->_htaccess->write_file();
179 328 }
329 + WP_Optimize()->get_options()->update_option('htaccess_has_webp_rules', false);
180 330 }
181 331
182 332 /**
183 333 * Prepare array of htaccess rules to use webp images.
184 334 *
185 - * @return array
335 + * @return array<int, array<array<array<string>|string>|string>>
186 336 */
187 337 private function prepare_webp_htaccess_rules() {
188 338 return array(
189 339 array(
@@ -237,10 +387,12 @@
237 387 }
238 388
239 389 /**
240 390 * Add webp mime type to htaccess rules.
391 + *
392 + * @return void
241 393 */
242 - private function add_webp_mime_type() {
394 + private function add_webp_mime_type(): void {
243 395 $htaccess_comment_section = 'Register webp mime type';
244 396 if ($this->_htaccess->is_exists() && !$this->_htaccess->is_commented_section_exists($htaccess_comment_section)) {
245 397 $webp_mime_type = array(
246 398 array(
@@ -254,33 +406,42 @@
254 406 }
255 407 }
256 408
257 409 /**
258 - * Checks whether webp conversion test is successful or not
410 + * Returns the path to the WebP test image file.
259 411 *
412 + * @return string
413 + */
414 + private function get_webp_test_image_path(): string {
415 + $upload_dir = wp_upload_dir();
416 + return $upload_dir['basedir'] . '/wpo/images/wpo_logo_small.png.webp';
417 + }
418 +
419 + /**
420 + * Checks whether a webp conversion test is successful or not
421 + *
260 422 * @return bool
261 423 */
262 - private function is_webp_conversion_successful() {
263 - $upload_dir = wp_upload_dir();
264 - $destination = $upload_dir['basedir']. '/wpo/images/wpo_logo_small.png.webp';
265 - return file_exists($destination);
424 + private function is_webp_conversion_successful(): bool {
425 + return file_exists($this->get_webp_test_image_path());
266 426 }
267 427
268 428 /**
269 - * Checks whether sample webp conversion test should be run or not
429 + * Checks whether a sample webp conversion test should be run or not
270 430 *
271 - * @return bool Returns true if sample test should be run, false otherwise
431 + * @return bool Returns true if the sample test should be run, false otherwise
272 432 */
273 - private function should_run_webp_conversion_test() {
274 - $webp_conversion_test = $this->get_webp_conversion_test_result();
275 - return (true != $webp_conversion_test);
433 + private function should_run_webp_conversion_test(): bool {
434 + return !$this->get_webp_conversion_test_result();
276 435 }
277 436
278 437 /**
279 438 * Returns webp conversion test result
439 + *
440 + * @return bool Returns the value of the webp_conversion_test saved in the options table
280 441 */
281 - private function get_webp_conversion_test_result() {
282 - return WP_Optimize()->get_options()->get_option('webp_conversion_test');
442 + public function get_webp_conversion_test_result(): bool {
443 + return (bool) WP_Optimize()->get_options()->get_option('webp_conversion_test');
283 444 }
284 445
285 446 /**
286 447 * Checks whether the webp redirection is possible or not and sets flag
@@ -286,9 +447,9 @@
286 447 * Checks whether the webp redirection is possible or not and sets flag
287 448 *
288 449 * @return bool Returns true if webp is served successfully, false otherwise
289 450 */
290 - private function run_webp_serving_self_test() {
451 + private function run_webp_serving_self_test(): bool {
291 452 $self_test = WPO_WebP_Self_Test::get_instance();
292 453
293 454 if ($self_test->is_webp_served()) {
294 455 WP_Optimize()->get_options()->update_option('redirection_possible', 'true');
@@ -300,36 +461,48 @@
300 461 }
301 462
302 463 /**
303 464 * Resets webp serving method by running self test, if needed purges cache and empties `uploads/.htaccess` file
465 + *
466 + * @return void
304 467 */
305 - public function reset_webp_serving_method() {
306 - $this->reset_webp_options();
307 - $this->run_self_test();
308 - list($old_redirection_possible, $new_redirection_possible) = $this->get_old_and_new_redirection_possibility();
309 - $this->maybe_purge_cache($old_redirection_possible, $new_redirection_possible);
310 - $this->maybe_empty_htaccess_file($new_redirection_possible);
468 + public function reset_webp_serving_method(): void {
469 + if ($this->_should_use_webp) {
470 + $this->reset_webp_options();
471 + $this->run_self_test();
472 + list($old_redirection_possible, $new_redirection_possible) = $this->get_old_and_new_redirection_possibility();
473 + $this->maybe_purge_cache($old_redirection_possible, $new_redirection_possible);
474 + $this->maybe_empty_htaccess_file($new_redirection_possible);
475 + }
311 476 }
312 477
313 478 /**
314 479 * Resets WebP related options
480 + *
481 + * @return void
315 482 */
316 - private function reset_webp_options() {
483 + private function reset_webp_options(): void {
317 484 $options = WP_Optimize()->get_options();
318 485 $options->update_option('old_redirection_possible', $options->get_option('redirection_possible'));
319 486 $options->update_option('webp_conversion_test', false);
320 487 $options->update_option('webp_converters', false);
321 488 $options->update_option('redirection_possible', false);
489 + $this->remove_webp_test_image_file();
322 490 }
323 491
324 492 /**
325 493 * Running self test to find available converters and possibility of serving webp using redirection method
494 + *
495 + * @return void
326 496 */
327 - private function run_self_test() {
497 + private function run_self_test(): void {
328 498 $this->set_converter_status();
329 499 if ($this->get_webp_conversion_test_result()) {
330 500 $this->save_htaccess_rules();
331 501 $this->run_webp_serving_self_test();
502 + } else {
503 + $this->disable_webp_conversion();
504 + $this->log("No working WebP converter was found on the server when running self-test, disabling WebP conversion");
332 505 }
333 506 }
334 507
335 508 /**
@@ -334,9 +507,9 @@
334 507
335 508 /**
336 509 * Gets old and new redirection possibility values
337 510 *
338 - * @return array
511 + * @return array<string>
339 512 */
340 513 private function get_old_and_new_redirection_possibility() {
341 514 $options = WP_Optimize()->get_options();
342 515 return array(
@@ -347,15 +520,25 @@
347 520
348 521 /**
349 522 * Cache is cleared when there is a change in the potential for serving WebP using redirection.
350 523 *
351 - * @param string $old_redirection_possible
352 - * @param string $new_redirection_possible
524 + * @param string $old_redirection_possible Previous redirection possibility value
525 + * @param string $new_redirection_possible Current redirection possibility value
526 + * @return void
353 527 */
354 - private function maybe_purge_cache($old_redirection_possible, $new_redirection_possible) {
355 - if ($old_redirection_possible !== $new_redirection_possible) {
356 - WP_Optimize()->get_page_cache()->purge();
528 + private function maybe_purge_cache($old_redirection_possible, $new_redirection_possible): void {
529 + if ($old_redirection_possible === $new_redirection_possible) {
530 + return;
357 531 }
532 +
533 + $is_cache_purged = WP_Optimize()->get_page_cache()->purge();
534 + $log_old_value = empty($old_redirection_possible) ? 'null' : $old_redirection_possible;
535 + $log_new_value = empty($new_redirection_possible) ? 'null' : $new_redirection_possible;
536 + $this->log("Purging cache because redirection_possible value changed from: {$log_old_value} to {$log_new_value}");
537 +
538 + if ($is_cache_purged) {
539 + WP_Optimize()->get_page_cache()->file_log('Full Cache Purge due to change in the value of WebP redirection');
540 + }
358 541 }
359 542
360 543 /**
361 544 * Remove redirection rules from `uploads/.htaccess` file if redirection is not possible
@@ -360,10 +543,11 @@
360 543 /**
361 544 * Remove redirection rules from `uploads/.htaccess` file if redirection is not possible
362 545 *
363 546 * @param string $new_redirection_possible
547 + * @return void
364 548 */
365 - private function maybe_empty_htaccess_file($new_redirection_possible) {
549 + private function maybe_empty_htaccess_file($new_redirection_possible): void {
366 550 if ('false' === $new_redirection_possible) {
367 551 $this->empty_htaccess_file();
368 552 }
369 553 }
@@ -369,45 +553,162 @@
369 553 }
370 554
371 555 /**
372 556 * Initialize cron scheduler
557 + *
558 + * @return void
373 559 */
374 - private function init_webp_cron_scheduler() {
375 - WPO_WebP_Cron_Scheduler::get_instance();
560 + public function init_webp_cron_scheduler(): void {
561 + if (!wp_next_scheduled('wpo_reset_webp_conversion_test_result')) {
562 + wp_schedule_event(time(), 'wpo_daily', 'wpo_reset_webp_conversion_test_result');
563 + }
564 + if (!wp_next_scheduled('wpo_prune_webp_logs')) {
565 + wp_schedule_event(time(), 'weekly', 'wpo_prune_webp_logs');
566 + }
567 + if (!wp_next_scheduled('wpo_webp_convert_compressed_images')) {
568 + wp_schedule_event(strtotime('midnight'), 'daily', 'wpo_webp_convert_compressed_images');
569 + }
376 570 }
377 571
378 572 /**
379 - * Determines whether the php shell functions are available or not
573 + * Remove all cron schedules
380 574 *
575 + * @return void
576 + */
577 + public function remove_webp_cron_schedules(): void {
578 + wp_clear_scheduled_hook('wpo_reset_webp_conversion_test_result');
579 + wp_clear_scheduled_hook('wpo_prune_webp_logs');
580 + wp_clear_scheduled_hook('wpo_webp_convert_compressed_images');
581 + }
582 +
583 + /**
584 + * Return the true if webp conversion is enabled and vice versa
585 + *
381 586 * @return bool
382 587 */
383 - public static function is_shell_functions_available() {
384 - $shell_functions = self::get_shell_functions();
385 - foreach ($shell_functions as $shell_function) {
386 - if (!function_exists($shell_function)) return false;
588 + public function is_webp_conversion_enabled(): bool {
589 + return $this->_should_use_webp;
590 + }
591 +
592 + /**
593 + * Set the webp_conversion option value to false and remove webp cron schedules
594 + *
595 + * @return void
596 + */
597 + public function disable_webp_conversion(): void {
598 + $this->empty_htaccess_file();
599 + WP_Optimize()->get_options()->update_option("webp_conversion", false);
600 + $this->remove_webp_cron_schedules();
601 + $message = __('Disabling the webp conversion.', 'wp-optimize');
602 + $this->log($message);
603 + }
604 +
605 + /**
606 + * Remove webp converted test image file
607 + *
608 + * @return void
609 + */
610 + private function remove_webp_test_image_file(): void {
611 + $destination = $this->get_webp_test_image_path();
612 + wp_delete_file($destination);
613 + }
614 +
615 + /**
616 + * Run during plugin deactivation
617 + *
618 + * @return void
619 + */
620 + public function plugin_deactivate(): void {
621 + $this->empty_htaccess_file();
622 + $this->remove_webp_test_image_file();
623 + }
624 +
625 + /**
626 + * Determines whether one of the PHP shell functions required for WebP conversion is available or not.
627 + *
628 + * @return bool
629 + */
630 + public function shell_functions_available(): bool {
631 + $has_escapeshellarg = function_exists('escapeshellarg');
632 + $has_exec_or_passthru = $this->any_function_exists(array('exec', 'passthru'));
633 + $has_proc_functions = $this->all_functions_exist(array('proc_open', 'proc_close'));
634 + $has_popen_functions = $this->all_functions_exist(array('popen', 'pclose'));
635 +
636 + return $has_escapeshellarg && ($has_exec_or_passthru || $has_proc_functions || $has_popen_functions);
637 + }
638 +
639 + /**
640 + * Checks if only shell converters available for WebP conversion.
641 + *
642 + * @return boolean
643 + */
644 + private function is_only_shell_converters_available(): bool {
645 + $available_converters = WP_Optimize()->get_options()->get_option('webp_converters');
646 + /** @var array<string> $available_converters */
647 + $available_converters = is_array($available_converters) ? $available_converters : array();
648 + $converters_with_shell = WPO_WebP_Test_Run::get_converters_with_shell();
649 + $available_with_shell = array_intersect($available_converters, $converters_with_shell);
650 +
651 + return count($available_converters) > 0 && count($available_converters) === count($available_with_shell);
652 + }
653 +
654 + /**
655 + * Determines whether one of the PHP shell functions required for WebP conversion is available or not.
656 + *
657 + * @deprecated 3.6.0
658 + * @return bool
659 + */
660 + public static function is_shell_functions_available(): bool {
661 + _deprecated_function(__METHOD__, '3.6.0', 'WP_Optimize_WebP::shell_functions_available');
662 + return WP_Optimize_WebP::get_instance()->shell_functions_available();
663 + }
664 +
665 + /**
666 + * Check if all the functions from the list is available.
667 + *
668 + * @param array<string> $functions
669 + * @return bool
670 + */
671 + private function all_functions_exist($functions): bool {
672 + foreach ($functions as $function) {
673 + if (!function_exists($function)) return false;
387 674 }
388 675 return true;
389 676 }
390 677
391 678 /**
392 - * List of php shell function names
679 + * Check if one of the functions from the list is available.
393 680 *
394 - * @return string[]
681 + * @param array<string> $functions
682 + * @return bool
395 683 */
396 - public static function get_shell_functions() {
397 - return array(
398 - 'escapeshellarg',
399 - 'escapeshellcmd',
400 - 'exec',
401 - 'passthru',
402 - 'proc_close',
403 - 'proc_get_status',
404 - 'proc_nice',
405 - 'proc_open',
406 - 'proc_terminate',
407 - 'shell_exec',
408 - 'system',
409 - );
684 + private function any_function_exists($functions): bool {
685 + foreach ($functions as $function) {
686 + if (function_exists($function)) return true;
687 + }
688 + return false;
689 + }
690 +
691 + /**
692 + * Return true if webp conversion is enabled and vice versa.
693 + *
694 + * @return bool
695 + */
696 + public function is_webp_enabled(): bool {
697 + _deprecated_function(__METHOD__, '4.5.4', 'WP_Optimize_WebP::is_webp_conversion_enabled');
698 + return $this->is_webp_conversion_enabled();
699 + }
700 +
701 + /**
702 + * Actions to be performed upon plugin activation
703 + *
704 + * @return void
705 + */
706 + public function plugin_activate(): void {
707 + if ($this->is_webp_conversion_enabled()) {
708 + $this->init_webp_cron_scheduler();
709 + $this->reset_webp_serving_method();
710 + }
410 711 }
411 712 }
412 713
413 714 endif;