PluginProbe
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization / 4.2.13
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization v4.2.13
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 / api.php

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

466 lines 12.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * The class defines way of connecting this user to the Optimole Dashboard.
5 *
6 * @codeCoverageIgnore
7 * @package \Optimole\Inc
8 * @author Optimole <friends@optimole.com>
9 */
10 final class Optml_Api {
11
12 /**
13 * Optimole root api url.
14 *
15 * @var string Api root.
16 */
17 private $api_root = 'https://dashboard.optimole.com/api/';
18 /**
19 * Optimole onboard api root url.
20 *
21 * @var string Api root.
22 */
23 private $onboard_api_root = 'https://onboard.i.optimole.com/onboard_api/';
24 /**
25 * Optimole offload conflicts api root url.
26 *
27 * @var string Api root.
28 */
29 private $upload_conflicts_api = 'https://conflicts.i.optimole.com/offload_api/';
30 /**
31 * Hold the user api key.
32 *
33 * @var string Api key.
34 */
35 private $api_key;
36 /**
37 * Optml_Api constructor.
38 */
39 public function __construct() {
40 $settings = new Optml_Settings();
41 $this->api_key = $settings->get( 'api_key' );
42 if ( defined( 'OPTIML_API_ROOT' ) ) {
43 $this->api_root = constant( 'OPTIML_API_ROOT' );
44 }
45 if ( defined( 'OPTIML_ONBOARD_API_ROOT' ) ) {
46 $this->onboard_api_root = constant( 'OPTIML_ONBOARD_API_ROOT' );
47 }
48 if ( defined( 'OPTIML_UPLOAD_CONFLICTS_API_ROOT' ) ) {
49 $this->upload_conflicts_api = constant( 'OPTIML_UPLOAD_CONFLICTS_API_ROOT' );
50 }
51 }
52
53 /**
54 * Connect to the service.
55 *
56 * @param string $api_key Api key.
57 *
58 * @return array|bool|WP_Error
59 */
60 public function connect( $api_key = '' ) {
61 if ( ! empty( $api_key ) ) {
62 $this->api_key = $api_key;
63 }
64
65 return $this->request( '/optml/v2/account/connect', 'POST', [ 'sample_image' => $this->get_sample_image() ] );
66 }
67
68 /**
69 * Get sample image.
70 *
71 * @return string
72 */
73 private function get_sample_image() {
74 $accepted_mimes = [ 'image/jpeg', 'image/png', 'image/webp' ];
75 $args = [
76 'post_type' => 'attachment',
77 'post_status' => 'any',
78 'number' => '1',
79 'no_found_rows' => true,
80 'fields' => 'ids',
81 'post_mime_type' => $accepted_mimes,
82 'post_parent__not_in' => [ 0 ],
83 ];
84 $image_result = new WP_Query( $args );
85 $original_image_url = 'none';
86 if ( ! empty( $image_result->posts ) ) {
87 $original_image_url = wp_get_attachment_image_url( $image_result->posts[0], 'full' );
88 }
89
90 return $original_image_url;
91 }
92 /**
93 * Get user data from service.
94 *
95 * @return array|string|bool|WP_Error User data.
96 */
97 public function get_user_data( $api_key = '', $application = '' ) {
98 if ( ! empty( $api_key ) ) {
99 $this->api_key = $api_key;
100 }
101
102 return $this->request( '/optml/v2/account/details', 'POST', [ 'application' => $application ] );
103 }
104
105 /**
106 * Toggle the extra visits.
107 *
108 * @param string $api_key Api key.
109 * @param string $status Status of the visits toggle.
110 *
111 * @return array|bool|string
112 */
113 public function update_extra_visits( $api_key = '', $status = 'enabled', $application = '' ) {
114 if ( ! empty( $api_key ) ) {
115 $this->api_key = $api_key;
116 }
117
118 return $this->request( '/optml/v2/account/extra_visits', 'POST', [ 'extra_visits' => $status, 'application' => $application ] );
119 }
120
121 /**
122 * Get cache token from service.
123 *
124 * @return array|bool|WP_Error User data.
125 */
126 public function get_cache_token( $token = '', $type = '', $api_key = '' ) {
127 if ( ! empty( $api_key ) ) {
128 $this->api_key = $api_key;
129 }
130 $lock = '';
131 if ( empty( $type ) || $type === 'images' ) {
132 $lock = get_transient( 'optml_cache_lock' );
133 } elseif ( $type === 'assets' ) {
134 $lock = get_transient( 'optml_cache_lock_assets' );
135 } else {
136 $type = 'images';
137 }
138
139 if ( $lock === 'yes' ) {
140 return new WP_Error( 'cache_throttle', __( 'You can clear cache only once per 5 minutes.', 'optimole-wp' ) );
141 }
142 return $this->request( '/optml/v1/cache/tokens', 'POST', [ 'token' => $token, 'type' => $type ] );
143 }
144
145 /**
146 * Request constructor.
147 *
148 * @param string $path The request url.
149 * @param string $method The request method type.
150 * @param array|string $params The request method type.
151 *
152 * @return array|string|boolean|WP_Error Api data.
153 */
154 public function request( $path, $method = 'GET', $params = [], $extra_headers = [] ) {
155
156 $headers = [
157 'Optml-Site' => get_home_url(),
158 ];
159 update_option( 'optimole_wp_logger_flag', 'yes' );
160 if ( ! empty( $this->api_key ) ) {
161 $headers['Authorization'] = 'Bearer ' . $this->api_key;
162 }
163 $headers = array_merge( $headers, $extra_headers );
164 $url = trailingslashit( $this->api_root ) . ltrim( $path, '/' );
165 // If there is a extra, add that as a url var.
166 if ( 'GET' === $method && ! empty( $params ) ) {
167 foreach ( $params as $key => $val ) {
168 $url = add_query_arg( [ $key => $val ], $url );
169 }
170 }
171 $url = tsdk_translate_link( $url, 'query' );
172
173 $args = $this->build_args( $method, $url, $headers, $params );
174
175 $response = wp_remote_request( $url, $args );
176 if ( is_wp_error( $response ) ) {
177 return $response;
178 }
179
180 $response = wp_remote_retrieve_body( $response );
181 if ( empty( $response ) ) {
182 return false;
183 }
184 $response = json_decode( $response, true );
185
186 if ( isset( $response['id'] ) && is_numeric( $response['id'] ) ) {
187 return true;
188 }
189 if ( ! isset( $response['code'] ) ) {
190 return false;
191 }
192
193 if ( intval( $response['code'] ) !== 200 ) {
194 if ( isset( $response['error'] ) && $response['error'] === 'domain_not_accessible' ) {
195 return new WP_Error( 'domain_not_accessible', sprintf( /* translators: 1 start of the italic tag, 2 is the end of italic tag, 3 is starting anchor tag, 4 is the ending anchor tag. */ __( 'It seems Optimole is having trouble reaching your website. This issue often occurs if your website is private, local, or protected by a firewall. But don\'t stress – it\'s an easy fix! Ensure your website is live and accessible to the public. If a firewall is in place, just tweak the settings to allow the %1$sOptimole(1.0)%2$s user agent access to your website. %3$sLearn More%4$s', 'optimole-wp' ), '<i>', '</i>', '<a href="https://docs.optimole.com/article/1976-resolving-optimole-access-to-your-website" target="_blank">', '</a>' ) );
196 }
197 if ( $path === 'optml/v2/account/complete_register_remote' && isset( $response['error'] ) ) {
198 if ( strpos( $response['error'], 'This email address is already registered.' ) !== false ) {
199 return 'email_registered';
200 }
201
202 if ( $response['error'] === 'ERROR: Site already whitelisted.' ) {
203 return 'site_exists';
204 }
205 }
206
207 if ( $path === '/optml/v2/account/details'
208 && isset( $response['code'] ) && $response['code'] === 'not_allowed' ) {
209 return 'disconnect';
210 }
211
212 if ( $path === '/optml/v2/account/details'
213 && isset( $response['error'] ) && $response['error'] === 'whitelist_limit_reached' ) {
214 return 'disconnect';
215 }
216
217 return isset( $response['error'] ) ? new WP_Error(
218 'api_error',
219 wp_kses(
220 $response['error'],
221 [
222 'a' => [
223 'href' => [],
224 'target' => [],
225 ],
226 ]
227 )
228 ) : false;
229 }
230
231 return $response['data'];
232 }
233
234 /**
235 * Builds Request arguments array.
236 *
237 * @param string $method Request method (GET | POST | PUT | UPDATE | DELETE).
238 * @param string $url Request URL.
239 * @param array $headers Headers Array.
240 * @param array|string $params Additional params for the Request.
241 *
242 * @return array
243 */
244 private function build_args( $method, $url, $headers, $params ) {
245 $args = [
246 'method' => $method,
247 'timeout' => 45,
248 'user-agent' => 'Optimle WP (v' . OPTML_VERSION . ') ',
249 'sslverify' => false,
250 'headers' => $headers,
251 ];
252 if ( $method !== 'GET' ) {
253 $args['body'] = $params;
254 }
255
256 return $args;
257 }
258
259 /**
260 * Check if the optimized url is available.
261 *
262 * @param string $url The optimized url to check.
263 * @return bool Whether or not the url is valid.
264 */
265 public function check_optimized_url( $url ) {
266 $response = wp_remote_get( $url, [ 'timeout' => 30 ] );
267
268 if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 || ! empty( wp_remote_retrieve_header( $response, 'x-not-found-o' ) ) ) {
269 $this->log_offload_error( $response );
270 return false;
271 }
272 return true;
273 }
274
275 /**
276 * Send a list of images to upload.
277 *
278 * @param array $images List of Images.
279 * @return array
280 */
281 public function call_onboard_api( $images = [] ) {
282 $settings = new Optml_Settings();
283 $token_images = $settings->get( 'cache_buster_images' );
284
285 $body = [
286 'secret' => Optml_Config::$secret,
287 'userKey' => Optml_Config::$key,
288 'images' => $images,
289 'cache_buster' => $token_images,
290 ];
291 $body = wp_json_encode( $body );
292
293 $options = [
294 'body' => $body,
295 'headers' => [
296 'Content-Type' => 'application/json',
297 ],
298 'timeout' => 60,
299 'blocking' => true,
300 'sslverify' => false,
301 'data_format' => 'body',
302 ];
303 return wp_remote_post( $this->onboard_api_root, $options );
304 }
305
306
307 /**
308 * Send a list of images with alt/title values to update.
309 *
310 * @param array $images List of images.
311 * @return array
312 */
313 public function call_data_enrich_api( $images = [] ) {
314 return $this->request( 'optml/v2/media/add_data', 'POST', [ 'images' => $images, 'key' => Optml_Config::$key ] );
315 }
316 /**
317 * Register user remotely on optimole.com.
318 *
319 * @param string $email User email.
320 *
321 * @return array|bool|string|WP_Error Api response.
322 */
323 public function create_account( $email ) {
324 return $this->request(
325 'optml/v2/account/complete_register_remote',
326 'POST',
327 [
328 'email' => $email,
329 'version' => OPTML_VERSION,
330 'sample_image' => $this->get_sample_image(),
331 'site' => get_home_url(),
332 'reference' => get_option( 'optimole_reference_key', '' ),
333 ]
334 );
335 }
336
337 /**
338 * Get the optimized images from API.
339 *
340 * @param string $api_key the api key.
341 *
342 * @return array|bool|WP_Error
343 */
344 public function get_optimized_images( $api_key = '' ) {
345 if ( ! empty( $api_key ) ) {
346 $this->api_key = $api_key;
347 }
348 $app_key = '';
349 $settings = new Optml_Settings();
350 $service_data = $settings->get( 'service_data' );
351 if ( isset( $service_data['cdn_key'] ) ) {
352 $app_key = $service_data['cdn_key'];
353 }
354 return $this->request( '/optml/v1/stats/images', 'GET', [], [ 'application' => $app_key ] );
355 }
356
357 /**
358 * Call the images endpoint.
359 *
360 * @param integer $page Page used to advance the search.
361 * @param array $domains Domains to filter by.
362 * @param string $search The string to search inside the originURL.
363 * @return mixed The decoded json response from the api.
364 */
365 public function get_cloud_images( $page = 0, $domains = [], $search = '' ) {
366
367 $params = [ 'key' => Optml_Config::$key ];
368 $params['page'] = $page;
369 $params['size'] = 40;
370 if ( $search !== '' ) {
371 $params['search'] = $search;
372 }
373
374 if ( ! empty( $domains ) ) {
375 $params['domains'] = implode( ',', $domains );
376 }
377 return $this->request( 'optml/v2/media/browser', 'GET', $params );
378 }
379 /**
380 * Get offload conflicts.
381 *
382 * @return array The decoded conflicts list.
383 */
384 public function get_offload_conflicts() {
385 $conflicts_list = wp_remote_retrieve_body( wp_remote_get( $this->upload_conflicts_api ) );
386 return json_decode( $conflicts_list, true );
387 }
388 /**
389 * Get offload conflicts.
390 *
391 * @param array $error_response The error to send as a string.
392 */
393 public function log_offload_error( $error_response ) {
394
395 $headers = wp_remote_retrieve_headers( $error_response );
396 $body = wp_remote_retrieve_body( $error_response );
397
398 $headers_to_log = 'no_headers_returned';
399 if ( ! empty( $headers ) ) {
400 $headers_to_log = wp_json_encode( $headers->getAll() );
401 }
402 wp_remote_post(
403 $this->upload_conflicts_api,
404 [
405 'headers' => [ 'Content-Type' => 'application/json' ],
406 'timeout' => 15,
407 'blocking' => true,
408 'sslverify' => false,
409 'data_format' => 'body',
410 'body' => [
411 'error_body' => wp_json_encode( $body ),
412 'error_headers' => $headers_to_log,
413 'error_site' => wp_json_encode( get_home_url() ),
414 ],
415 ]
416 );
417 }
418
419 /**
420 * Send Offloading Logs
421 *
422 * @param string $type Type of log (offload/rollback).
423 * @param string $message Log message.
424 *
425 * @return mixed
426 */
427 public function send_log( $type, $message ) {
428 return $this->request(
429 'optml/v2/logs',
430 'POST',
431 [
432 'type' => $type,
433 'message' => $message,
434 'site' => get_home_url(),
435 ]
436 );
437 }
438
439 /**
440 * Throw error on object clone
441 *
442 * The whole idea of the singleton design pattern is that there is a single
443 * object therefore, we don't want the object to be cloned.
444 *
445 * @access public
446 * @return void
447 * @since 1.0.0
448 */
449 public function __clone() {
450 // Cloning instances of the class is forbidden.
451 _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin&#8217; huh?', 'optimole-wp' ), '1.0.0' );
452 }
453
454 /**
455 * Disable unserializing of the class
456 *
457 * @access public
458 * @return void
459 * @since 1.0.0
460 */
461 public function __wakeup() {
462 // Unserializing instances of the class is forbidden.
463 _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin&#8217; huh?', 'optimole-wp' ), '1.0.0' );
464 }
465 }
466