PluginProbe
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization / 3.0.1
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization v3.0.1
4.2.13 4.2.12 4.2.11 4.2.10 4.2.9 4.2.8 4.2.7 4.2.6 4.2.5 2.5.5 2.5.6 2.5.7 3.0.0 3.0.1 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.11.0 3.11.1 3.11.2 3.11.3 3.12.0 3.12.1 All 134 releases
optimole-wp / inc / rest.php

rest.php in Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization 3.0.1, at inc/rest.php

781 lines 21.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Optimole Rest related actions.
4 *
5 * @package Optimole/Inc
6 * @copyright Copyright (c) 2017, Marius Cristea
7 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
8 */
9
10 /**
11 * Class Optml_Rest
12 *
13 * @codeCoverageIgnore
14 */
15 class Optml_Rest {
16 /**
17 * Rest api namespace.
18 *
19 * @var string Namespace.
20 */
21 private $namespace;
22
23 /**
24 * Optml_Rest constructor.
25 */
26 public function __construct() {
27 $this->namespace = OPTML_NAMESPACE . '/v1';
28 add_action( 'rest_api_init', [ $this, 'register' ] );
29 }
30
31 /**
32 * Register rest routes.
33 */
34 public function register() {
35
36 $this->register_service_routes();
37
38 register_rest_route(
39 $this->namespace,
40 '/update_option',
41 [
42 [
43 'methods' => \WP_REST_Server::CREATABLE,
44 'permission_callback' => function () {
45 return current_user_can( 'manage_options' );
46 },
47 'callback' => [ $this, 'update_option' ],
48 ],
49 ]
50 );
51
52 register_rest_route(
53 $this->namespace,
54 '/request_update',
55 [
56 [
57 'methods' => \WP_REST_Server::READABLE,
58 'permission_callback' => function () {
59 return current_user_can( 'manage_options' );
60 },
61 'callback' => [ $this, 'request_update' ],
62 ],
63 ]
64 );
65 register_rest_route(
66 $this->namespace,
67 '/check_redirects',
68 [
69 [
70 'methods' => \WP_REST_Server::EDITABLE,
71 'permission_callback' => function () {
72 return current_user_can( 'manage_options' );
73 },
74 'callback' => [ $this, 'check_redirects' ],
75 ],
76 ]
77 );
78
79 $this->register_image_routes();
80 $this->register_watermark_routes();
81 $this->register_conflict_routes();
82 $this->register_cache_routes();
83 $this->register_media_offload_routes();
84 }
85
86 /**
87 * Method to register service specific routes.
88 */
89 public function register_service_routes() {
90 register_rest_route(
91 $this->namespace,
92 '/connect',
93 [
94 [
95 'methods' => \WP_REST_Server::CREATABLE,
96 'permission_callback' => function () {
97 return current_user_can( 'manage_options' );
98 },
99 'callback' => [ $this, 'connect' ],
100 'args' => [
101 'api_key' => [
102 'type' => 'string',
103 'required' => true,
104 ],
105 ],
106 ],
107 ]
108 );
109 register_rest_route(
110 $this->namespace,
111 '/register',
112 [
113 [
114 'methods' => \WP_REST_Server::CREATABLE,
115 'permission_callback' => function () {
116 return current_user_can( 'manage_options' );
117 },
118 'callback' => [ $this, 'register_service' ],
119 'args' => [
120 'email' => [
121 'type' => 'string',
122 'required' => true,
123 ],
124 ],
125 ],
126 ]
127 );
128 register_rest_route(
129 $this->namespace,
130 '/disconnect',
131 [
132 [
133 'methods' => \WP_REST_Server::READABLE,
134 'permission_callback' => function () {
135 return current_user_can( 'manage_options' );
136 },
137 'callback' => [ $this, 'disconnect' ],
138 ],
139 ]
140 );
141 }
142
143 /**
144 * Method to register image specific routes.
145 */
146 public function register_image_routes() {
147 register_rest_route(
148 $this->namespace,
149 '/poll_optimized_images',
150 [
151 [
152 'methods' => \WP_REST_Server::READABLE,
153 'permission_callback' => function () {
154 return current_user_can( 'manage_options' );
155 },
156 'callback' => [ $this, 'poll_optimized_images' ],
157 ],
158 ]
159 );
160 register_rest_route(
161 $this->namespace,
162 '/images-sample-rate',
163 [
164 [
165 'methods' => \WP_REST_Server::CREATABLE,
166 'permission_callback' => function () {
167 return current_user_can( 'manage_options' );
168 },
169 'callback' => [ $this, 'get_sample_rate' ],
170 ],
171 ]
172 );
173 }
174 /**
175 * Method to register media offload specific routes.
176 */
177 public function register_media_offload_routes() {
178 register_rest_route(
179 $this->namespace,
180 '/offload_images',
181 [
182 [
183 'methods' => \WP_REST_Server::CREATABLE,
184 'permission_callback' => function () {
185 return current_user_can( 'manage_options' );
186 },
187 'callback' => [ $this, 'offload_images' ],
188 ],
189 ]
190 );
191 register_rest_route(
192 $this->namespace,
193 '/rollback_images',
194 [
195 [
196 'methods' => \WP_REST_Server::CREATABLE,
197 'permission_callback' => function () {
198 return current_user_can( 'manage_options' );
199 },
200 'callback' => [ $this, 'rollback_images' ],
201 ],
202 ]
203 );
204 register_rest_route(
205 $this->namespace,
206 '/number_of_library_images',
207 [
208 [
209 'methods' => \WP_REST_Server::CREATABLE,
210 'permission_callback' => function () {
211 return current_user_can( 'manage_options' );
212 },
213 'callback' => [ $this, 'number_of_library_images' ],
214 ],
215 ]
216 );
217 }
218
219 /**
220 * Method to register watermark specific routes.
221 */
222 public function register_watermark_routes() {
223 register_rest_route(
224 $this->namespace,
225 '/poll_watermarks',
226 [
227 [
228 'methods' => \WP_REST_Server::READABLE,
229 'permission_callback' => function () {
230 return current_user_can( 'manage_options' );
231 },
232 'callback' => [ $this, 'poll_watermarks' ],
233 ],
234 ]
235 );
236 register_rest_route(
237 $this->namespace,
238 '/add_watermark',
239 [
240 [
241 'methods' => \WP_REST_Server::CREATABLE,
242 'permission_callback' => function () {
243 return current_user_can( 'manage_options' );
244 },
245 'callback' => [ $this, 'add_watermark' ],
246 ],
247 ]
248 );
249 register_rest_route(
250 $this->namespace,
251 '/remove_watermark',
252 [
253 [
254 'methods' => \WP_REST_Server::CREATABLE,
255 'permission_callback' => function () {
256 return current_user_can( 'manage_options' );
257 },
258 'callback' => [ $this, 'remove_watermark' ],
259 ],
260 ]
261 );
262 }
263
264 /**
265 * Method to register conflicts specific routes.
266 */
267 public function register_conflict_routes() {
268 register_rest_route(
269 $this->namespace,
270 '/poll_conflicts',
271 [
272 [
273 'methods' => \WP_REST_Server::READABLE,
274 'permission_callback' => function () {
275 return current_user_can( 'manage_options' );
276 },
277 'callback' => [ $this, 'poll_conflicts' ],
278 ],
279 ]
280 );
281 register_rest_route(
282 $this->namespace,
283 '/dismiss_conflict',
284 [
285 [
286 'methods' => \WP_REST_Server::CREATABLE,
287 'permission_callback' => function () {
288 return current_user_can( 'manage_options' );
289 },
290 'callback' => [ $this, 'dismiss_conflict' ],
291 ],
292 ]
293 );
294 }
295
296 /**
297 * Method to register cache specific routes.
298 */
299 public function register_cache_routes() {
300 register_rest_route(
301 $this->namespace,
302 '/clear_cache',
303 [
304 [
305 'methods' => \WP_REST_Server::CREATABLE,
306 'permission_callback' => function () {
307 return current_user_can( 'manage_options' );
308 },
309 'callback' => [ $this, 'clear_cache_request' ],
310 ],
311 ]
312 );
313 }
314
315 /**
316 * Clear Cache request.
317 *
318 * @param WP_REST_Request $request clear cache rest request.
319 *
320 * @return WP_Error|WP_REST_Response
321 */
322 public function clear_cache_request( WP_REST_Request $request ) {
323 $settings = new Optml_Settings();
324 $token = $settings->get( 'cache_buster' );
325 $request = new Optml_Api();
326 $data = $request->get_cache_token( $token );
327 if ( $data === false || is_wp_error( $data ) || empty( $data ) || ! isset( $data['token'] ) ) {
328 $extra = '';
329 if ( is_wp_error( $data ) ) {
330 /**
331 * Error from api.
332 *
333 * @var WP_Error $data Error object.
334 */
335 $extra = sprintf( __( '. ERROR details: %s', 'optimole-wp' ), $data->get_error_message() );
336 }
337 wp_send_json_error( __( 'Can not get new token from Optimole service', 'optimole-wp' ) . $extra );
338 }
339
340 set_transient( 'optml_cache_lock', 'yes', 5 * MINUTE_IN_SECONDS );
341 $settings->update( 'cache_buster', $data['token'] );
342
343 return $this->response( $data['token'], '200' );
344 }
345
346 /**
347 * Connect to optimole service.
348 *
349 * @param WP_REST_Request $request connect rest request.
350 *
351 * @return WP_Error|WP_REST_Response
352 */
353 public function connect( WP_REST_Request $request ) {
354 $api_key = $request->get_param( 'api_key' );
355 $request = new Optml_Api();
356 $data = $request->get_user_data( $api_key );
357 if ( $data === false || is_wp_error( $data ) ) {
358 $extra = '';
359 if ( is_wp_error( $data ) ) {
360 /**
361 * Error from api.
362 *
363 * @var WP_Error $data Error object.
364 */
365 $extra = sprintf( __( '. ERROR details: %s', 'optimole-wp' ), $data->get_error_message() );
366 }
367 wp_send_json_error( __( 'Can not connect to Optimole service', 'optimole-wp' ) . $extra );
368 }
369 $settings = new Optml_Settings();
370 $settings->update( 'service_data', $data );
371 $settings->update( 'api_key', $api_key );
372
373 return $this->response( $data );
374 }
375
376 /**
377 * Wrapper for api response.
378 *
379 * @param mixed $data data from api.
380 *
381 * @return WP_REST_Response
382 */
383 private function response( $data, $code = 'success' ) {
384 return new WP_REST_Response( [ 'data' => $data, 'code' => $code ], 200 );
385 }
386
387 /**
388 * Connect to optimole service.
389 *
390 * @param WP_REST_Request $request connect rest request.
391 *
392 * @return WP_Error|WP_REST_Response
393 */
394 public function register_service( WP_REST_Request $request ) {
395 $email = $request->get_param( 'email' );
396 $api = new Optml_Api();
397 $user = $api->create_account( $email );
398 if ( $user === false ) {
399 return new WP_REST_Response(
400 [
401 'data' => null,
402 'message' => __( 'Error creating account.', 'optimole-wp' ),
403 'code' => 'error',
404 ],
405 200
406 );
407
408 }
409
410 return $this->response( $user );
411 }
412
413 /**
414 * Return image samples.
415 *
416 * @param WP_REST_Request $request Rest request.
417 *
418 * @return WP_REST_Response Image urls.
419 */
420 public function get_sample_rate( WP_REST_Request $request ) {
421
422 add_filter( 'optml_dont_replace_url', '__return_true' );
423 $image_sample = get_transient( 'optimole_sample_image' );
424 if ( $image_sample === false || $request->get_param( 'force' ) === 'yes' ) {
425 $image_sample = $this->fetch_sample_image();
426 set_transient( 'optimole_sample_image', $image_sample );
427 }
428 $image = [ 'id' => $image_sample['id'] ];
429
430 $image['original'] = $image_sample['url'];
431
432 remove_filter( 'optml_dont_replace_url', '__return_true' );
433
434 $image['optimized'] = apply_filters(
435 'optml_replace_image',
436 $image['original'],
437 [
438 'width' => $image_sample['width'],
439 'height' => $image_sample['height'],
440 'quality' => $request->get_param( 'quality' ),
441 ]
442 );
443
444 $optimized = wp_remote_get(
445 $image['optimized'],
446 [
447 'timeout' => 10,
448 'headers' => [
449 'Accept' => 'text/html,application/xhtml+xml,image/webp,image/apng ',
450 ],
451 ]
452 );
453
454 $original = wp_remote_get( $image['original'] );
455
456 $image['optimized_size'] = (int) wp_remote_retrieve_header( $optimized, 'content-length' );
457 $image['original_size'] = (int) wp_remote_retrieve_header( $original, 'content-length' );
458
459 return $this->response( $image );
460 }
461
462 /**
463 * Return sample image data.
464 *
465 * @return array Image data.
466 */
467 private function fetch_sample_image() {
468 $accepted_mimes = [ 'image/jpeg' ];
469 $args = [
470 'post_type' => 'attachment',
471 'post_status' => 'any',
472 'number' => '5',
473 'no_found_rows' => true,
474 'fields' => 'ids',
475 'post_mime_type' => $accepted_mimes,
476 'post_parent__not_in' => [ 0 ],
477 ];
478 $image_result = new WP_Query( $args );
479 if ( empty( $image_result->posts ) ) {
480 $rand_id = rand( 1, 3 );
481 $original_image_url = OPTML_URL . 'assets/img/' . $rand_id . '.jpg';
482
483 return [
484 'url' => $original_image_url,
485 'width' => '700',
486 'height' => '465',
487 'id' => - 1,
488 ];
489 }
490 $attachment_id = $image_result->posts[ array_rand( $image_result->posts, 1 ) ];
491
492 $original_image_url = wp_get_attachment_image_url( $attachment_id, 'full' );
493
494 $metadata = wp_get_attachment_metadata( $attachment_id );
495
496 $width = 'auto';
497 $height = 'auto';
498 $size = 'full';
499 if ( isset( $metadata['sizes'] ) && isset( $metadata['sizes'][ $size ] ) ) {
500 $width = $metadata['sizes'][ $size ]['width'];
501 $height = $metadata['sizes'][ $size ]['height'];
502 }
503
504 return [
505 'url' => $original_image_url,
506 'id' => $attachment_id,
507 'width' => $width,
508 'height' => $height,
509 ];
510 }
511
512 /**
513 * Disconnect from optimole service.
514 *
515 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
516 * @param WP_REST_Request $request disconnect rest request.
517 */
518 public function disconnect( WP_REST_Request $request ) {
519 $settings = new Optml_Settings();
520 $settings->reset();
521 wp_send_json_success( 'Disconnected' );
522 }
523
524 /**
525 * Get optimized images from API.
526 *
527 * @param WP_REST_Request $request rest request.
528 *
529 * @return WP_REST_Response
530 */
531 public function poll_optimized_images( WP_REST_Request $request ) {
532 $api_key = $request->get_param( 'api_key' );
533 $request = new Optml_Api();
534 $images = $request->get_optimized_images( $api_key );
535 if ( ! isset( $images['list'] ) || empty( $images['list'] ) ) {
536 return $this->response( [] );
537 }
538
539 $final_images = array_splice( $images['list'], 0, 10 );
540 $media = new Optml_Media_Offload();
541
542 foreach ( $final_images as $index => $value ) {
543 $final_images[ $index ]['url'] = $media->get_media_optimized_url( $value['url'], $value['key'] );
544 unset( $final_images[ $index ]['key'] );
545 }
546
547 return $this->response( $final_images );
548 }
549
550 /**
551 * Get watermarks from API.
552 *
553 * @param WP_REST_Request $request rest request.
554 *
555 * @return WP_REST_Response
556 */
557 public function poll_watermarks( WP_REST_Request $request ) {
558 $api_key = $request->get_param( 'api_key' );
559 $request = new Optml_Api();
560 $watermarks = $request->get_watermarks( $api_key );
561 if ( ! isset( $watermarks['watermarks'] ) || empty( $watermarks['watermarks'] ) ) {
562 return $this->response( [] );
563 }
564 $final_images = array_splice( $watermarks['watermarks'], 0, 10 );
565
566 return $this->response( $final_images );
567 }
568
569 /**
570 * Add watermark.
571 *
572 * @param WP_REST_Request $request rest request.
573 *
574 * @return WP_REST_Response
575 */
576 public function add_watermark( WP_REST_Request $request ) {
577 $file = $request->get_file_params();
578 $request = new Optml_Api();
579 $response = $request->add_watermark( $file );
580 if ( $response === false ) {
581 return $this->response( __( 'Error uploading image. Please try again.', 'optimole-wp' ), 'error' );
582 }
583
584 return $this->response( __( 'Watermark image uploaded succesfully ! ', 'optimole-wp' ) );
585 }
586
587 /**
588 * Remove watermark.
589 *
590 * @param WP_REST_Request $request rest request.
591 *
592 * @return WP_REST_Response
593 */
594 public function remove_watermark( WP_REST_Request $request ) {
595 $post_id = $request->get_param( 'postID' );
596 $api_key = $request->get_param( 'api_key' );
597 $request = new Optml_Api();
598
599 return $this->response( $request->remove_watermark( $post_id, $api_key ) );
600 }
601
602 /**
603 * Get conflicts from API.
604 *
605 * @param WP_REST_Request $request rest request.
606 *
607 * @return WP_REST_Response
608 */
609 public function poll_conflicts( WP_REST_Request $request ) {
610 $conflicts_to_register = apply_filters( 'optml_register_conflicts', [] );
611 $manager = new Optml_Conflict_Manager( $conflicts_to_register );
612
613 return $this->response(
614 [
615 'count' => $manager->get_conflict_count(),
616 'conflicts' => $manager->get_conflict_list(),
617 ]
618 );
619 }
620
621 /**
622 * Dismiss conflict.
623 *
624 * @param WP_REST_Request $request rest request.
625 *
626 * @return WP_REST_Response
627 */
628 public function dismiss_conflict( WP_REST_Request $request ) {
629 $conflict_id = $request->get_param( 'conflictID' );
630 $conflicts_to_register = apply_filters( 'optml_register_conflicts', [] );
631 $manager = new Optml_Conflict_Manager( $conflicts_to_register );
632 $manager->dismiss_conflict( $conflict_id );
633
634 return $this->response(
635 [
636 'count' => $manager->get_conflict_count(),
637 'conflicts' => $manager->get_conflict_list(),
638 ]
639 );
640 }
641
642 /**
643 * Request stats update for app.
644 *
645 * @param WP_REST_Request $request rest request.
646 *
647 * @return WP_REST_Response
648 */
649 public function request_update( WP_REST_Request $request ) {
650 do_action( 'optml_daily_sync' );
651 $settings = new Optml_Settings();
652
653 return $this->response( $settings->get( 'service_data' ) );
654 }
655
656 /**
657 * Update options method.
658 *
659 * @param WP_REST_Request $request option update rest request.
660 *
661 * @return WP_REST_Response
662 */
663 public function update_option( WP_REST_Request $request ) {
664 $new_settings = $request->get_param( 'settings' );
665
666 if ( empty( $new_settings ) ) {
667 wp_send_json_error( 'No option key set.' );
668 }
669
670 $settings = new Optml_Settings();
671 $sanitized = $settings->parse_settings( $new_settings );
672
673 return $this->response( $sanitized );
674 }
675
676 /**
677 * Update options method.
678 *
679 * @param WP_REST_Request $request option update rest request.
680 *
681 * @return WP_REST_Response
682 */
683 public function check_redirects( WP_REST_Request $request ) {
684 if ( empty( $request->get_param( 'images' ) ) ) {
685 return $this->response( __( 'No images available on the current page.' ), 'noImagesFound' );
686 }
687 // 'ok' if no issues found, 'log' is there are issues we need to notify, 'deactivated' if the user's account is disabled
688 $status = 'ok';
689 $result = '';
690 foreach ( $request->get_param( 'images' ) as $domain => $value ) {
691 $args = [
692 'method' => 'GET',
693 'redirection' => 0,
694 ];
695 $processed_images = 0;
696 if ( isset( $value['src'] ) ) {
697 $processed_images = count( $value['src'] );
698 }
699 if ( isset( $value['ignoredUrls'] ) && $value['ignoredUrls'] > $processed_images ) {
700 $result .= '<li>❌ ' . sprintf( __( 'The images from: %1$s are not optimized by Optimole. If you would like to do so, you can follow this: %2$sWhy Optimole does not optimize all the images from my site?%3$s.', 'optimole-wp' ), $domain, '<a target="_blank" href="https://docs.optimole.com/article/1290-how-to-optimize-images-using-optimole-from-my-domain">', '</a>' ) . '</li>';
701 $status = 'log';
702 continue;
703 }
704
705 if ( $processed_images > 0 ) {
706 $response = wp_remote_get( $value['src'][ rand( 0, $processed_images - 1 ) ], $args );
707 if ( is_array( $response ) && ! is_wp_error( $response ) ) {
708 $headers = $response['headers']; // array of http header lines
709 $status_code = $response['response']['code'];
710 if ( $status_code === 301 ) {
711 $status = 'deactivated';
712 $result = '<li>❌ ' . sprintf( __( 'Your account is currently disabled due to exceeding quota and Optimole is no longer able to optimize the images. In order to fix this you will need to %1$supgrade%2$s.', 'optimole-wp' ), '<a target="_blank" href="https://optimole.com/pricing">', '</a>' ) . '</li>';
713 break;
714 }
715 if ( $status_code === 302 ) {
716 if ( isset( $headers['x-redirect-o'] ) ) {
717 $optimole_code = (int) $headers['x-redirect-o'];
718 if ( $optimole_code === 1 ) {
719 $status = 'log';
720 $result .= '<li>❌ ' . sprintf( __( 'The domain: %1$s is not allowed to optimize images using your Optimole account. You can add this to the allowed list %2$shere%3$s.', 'optimole-wp' ), '<b>' . $domain . '</b>', '<a target="_blank" href="https://dashboard.optimole.com/whitelist">', '</a>' ) . '</li>';
721 }
722 if ( $optimole_code === 4 ) {
723 $status = 'log';
724 $result .= '<li>❌ ' . sprintf( __( 'We are not able to download the images from %1$s. Please check %2$sthis%3$s document for a more advanced guide on how to solve this. ', 'optimole-wp' ), '<b>' . $domain . '</b>', '<a target="_blank" href="https://docs.optimole.com/article/1291-why-optimole-is-not-able-to-download-the-images-from-my-site">', '</a>' ) . '<br />' . '</li>';
725 }
726 }
727 }
728 }
729 }
730 }
731 if ( $result === '' ) {
732 $result = __( 'No issues detected, everything is running smoothly.', 'optimole-wp' );
733 }
734
735 return $this->response( '<ul>' . $result . '</ul>', $status );
736 }
737
738 /**
739 * Push existing image our servers.
740 *
741 * @param WP_REST_Request $request rest request object.
742 *
743 * @return WP_REST_Response
744 */
745 public function offload_images( WP_REST_Request $request ) {
746 $batch = 300;
747 if ( ! empty( $request->get_param( 'batch' ) ) ) {
748 $batch = $request->get_param( 'batch' );
749 }
750 return $this->response( Optml_Media_Offload::upload_images( $batch ) );
751 }
752 /**
753 * Rollback images to media library.
754 *
755 * @param WP_REST_Request $request rest request object.
756 *
757 * @return WP_REST_Response
758 */
759 public function rollback_images( WP_REST_Request $request ) {
760 $batch = 300;
761 if ( ! empty( $request->get_param( 'batch' ) ) ) {
762 $batch = $request->get_param( 'batch' );
763 }
764 return $this->response( Optml_Media_Offload::rollback_images( $batch ) );
765 }
766 /**
767 * Get total number of images.
768 *
769 * @param WP_REST_Request $request rest request object.
770 *
771 * @return WP_REST_Response
772 */
773 public function number_of_library_images( WP_REST_Request $request ) {
774 $action = 'offload_images';
775 if ( ! empty( $request->get_param( 'action' ) ) ) {
776 $action = $request->get_param( 'action' );
777 }
778 return $this->response( Optml_Media_Offload::number_of_library_images( $action ) );
779 }
780 }
781