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
← All changes | inc/api.php +211 -118 3.1.04.2.13 View file →
@@ -15,14 +15,20 @@
15 15 * @var string Api root.
16 16 */
17 17 private $api_root = 'https://dashboard.optimole.com/api/';
18 18 /**
19 - * Optimole upload api root url.
19 + * Optimole onboard api root url.
20 20 *
21 21 * @var string Api root.
22 22 */
23 - private $upload_api_root = 'https://generateurls-prod.i.optimole.com/upload';
23 + private $onboard_api_root = 'https://onboard.i.optimole.com/onboard_api/';
24 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 + /**
25 31 * Hold the user api key.
26 32 *
27 33 * @var string Api key.
28 34 */
@@ -32,14 +38,17 @@
32 38 */
33 39 public function __construct() {
34 40 $settings = new Optml_Settings();
35 41 $this->api_key = $settings->get( 'api_key' );
36 - if ( defined( 'OPTIML_API_ROOT' ) && constant( 'OPTIML_API_ROOT' ) ) {
42 + if ( defined( 'OPTIML_API_ROOT' ) ) {
37 43 $this->api_root = constant( 'OPTIML_API_ROOT' );
38 44 }
39 - if ( defined( 'OPTIML_UPLOAD_API_ROOT' ) && constant( 'OPTIML_UPLOAD_API_ROOT' ) ) {
40 - $this->upload_api_root = constant( 'OPTIML_UPLOAD_API_ROOT' );
45 + if ( defined( 'OPTIML_ONBOARD_API_ROOT' ) ) {
46 + $this->onboard_api_root = constant( 'OPTIML_ONBOARD_API_ROOT' );
41 47 }
48 + if ( defined( 'OPTIML_UPLOAD_CONFLICTS_API_ROOT' ) ) {
49 + $this->upload_conflicts_api = constant( 'OPTIML_UPLOAD_CONFLICTS_API_ROOT' );
50 + }
42 51 }
43 52
44 53 /**
45 54 * Connect to the service.
@@ -45,9 +54,9 @@
45 54 * Connect to the service.
46 55 *
47 56 * @param string $api_key Api key.
48 57 *
49 - * @return array|bool
58 + * @return array|bool|WP_Error
50 59 */
51 60 public function connect( $api_key = '' ) {
52 61 if ( ! empty( $api_key ) ) {
53 62 $this->api_key = $api_key;
@@ -52,15 +61,39 @@
52 61 if ( ! empty( $api_key ) ) {
53 62 $this->api_key = $api_key;
54 63 }
55 64
56 - return $this->request( '/optml/v2/account/connect', 'POST' );
65 + return $this->request( '/optml/v2/account/connect', 'POST', [ 'sample_image' => $this->get_sample_image() ] );
57 66 }
58 67
59 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 + /**
60 93 * Get user data from service.
61 94 *
62 - * @return array|bool User data.
95 + * @return array|string|bool|WP_Error User data.
63 96 */
64 97 public function get_user_data( $api_key = '', $application = '' ) {
65 98 if ( ! empty( $api_key ) ) {
66 99 $this->api_key = $api_key;
@@ -69,43 +102,66 @@
69 102 return $this->request( '/optml/v2/account/details', 'POST', [ 'application' => $application ] );
70 103 }
71 104
72 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 + /**
73 122 * Get cache token from service.
74 123 *
75 - * @return array|bool User data.
124 + * @return array|bool|WP_Error User data.
76 125 */
77 - public function get_cache_token( $token = '', $api_key = '' ) {
126 + public function get_cache_token( $token = '', $type = '', $api_key = '' ) {
78 127 if ( ! empty( $api_key ) ) {
79 128 $this->api_key = $api_key;
80 129 }
81 - $lock = get_transient( 'optml_cache_lock' );
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 +
82 139 if ( $lock === 'yes' ) {
83 140 return new WP_Error( 'cache_throttle', __( 'You can clear cache only once per 5 minutes.', 'optimole-wp' ) );
84 141 }
85 - return $this->request( '/optml/v1/cache/tokens', 'POST', [ 'token' => $token ] );
142 + return $this->request( '/optml/v1/cache/tokens', 'POST', [ 'token' => $token, 'type' => $type ] );
86 143 }
87 144
88 145 /**
89 146 * Request constructor.
90 147 *
91 - * @param string $path The request url.
92 - * @param string $method The request method type.
93 - * @param array $params The request method type.
148 + * @param string $path The request url.
149 + * @param string $method The request method type.
150 + * @param array|string $params The request method type.
94 151 *
95 - * @return array|boolean Api data.
152 + * @return array|string|boolean|WP_Error Api data.
96 153 */
97 - private function request( $path, $method = 'GET', $params = [], $extra_headers = [] ) {
154 + public function request( $path, $method = 'GET', $params = [], $extra_headers = [] ) {
98 155
99 156 $headers = [
100 157 'Optml-Site' => get_home_url(),
101 158 ];
159 + update_option( 'optimole_wp_logger_flag', 'yes' );
102 160 if ( ! empty( $this->api_key ) ) {
103 161 $headers['Authorization'] = 'Bearer ' . $this->api_key;
104 162 }
105 - if ( ! empty( $headers ) && is_array( $headers ) ) {
106 - $headers = array_merge( $headers, $extra_headers );
107 - }
163 + $headers = array_merge( $headers, $extra_headers );
108 164 $url = trailingslashit( $this->api_root ) . ltrim( $path, '/' );
109 165 // If there is a extra, add that as a url var.
110 166 if ( 'GET' === $method && ! empty( $params ) ) {
111 167 foreach ( $params as $key => $val ) {
@@ -111,18 +167,18 @@
111 167 foreach ( $params as $key => $val ) {
112 168 $url = add_query_arg( [ $key => $val ], $url );
113 169 }
114 170 }
171 + $url = tsdk_translate_link( $url, 'query' );
172 +
115 173 $args = $this->build_args( $method, $url, $headers, $params );
116 174
117 175 $response = wp_remote_request( $url, $args );
118 -
119 176 if ( is_wp_error( $response ) ) {
120 177 return $response;
121 178 }
122 179
123 180 $response = wp_remote_retrieve_body( $response );
124 -
125 181 if ( empty( $response ) ) {
126 182 return false;
127 183 }
128 184 $response = json_decode( $response, true );
@@ -132,14 +188,48 @@
132 188 }
133 189 if ( ! isset( $response['code'] ) ) {
134 190 return false;
135 191 }
192 +
136 193 if ( intval( $response['code'] ) !== 200 ) {
137 - return false;
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;
138 229 }
139 230
140 231 return $response['data'];
141 -
142 232 }
143 233
144 234 /**
145 235 * Builds Request arguments array.
@@ -166,21 +256,8 @@
166 256 return $args;
167 257 }
168 258
169 259 /**
170 - * Upload image to our servers using the generated signed url.
171 - *
172 - * @param string $upload_url The signed to url to upload the image to.
173 - * @param string $content_type Image mime type, it must match the actual mime type of the image.
174 - * @param string $image Image data from file_get_contents.
175 - * @return mixed
176 - */
177 - public function upload_image( $upload_url, $content_type, $image ) {
178 - $args = $this->build_args( 'PUT', '', ['content-type' => $content_type], $image );
179 - return wp_remote_request( $upload_url, $args );
180 - }
181 -
182 - /**
183 260 * Check if the optimized url is available.
184 261 *
185 262 * @param string $url The optimized url to check.
186 263 * @return bool Whether or not the url is valid.
@@ -185,10 +262,12 @@
185 262 * @param string $url The optimized url to check.
186 263 * @return bool Whether or not the url is valid.
187 264 */
188 265 public function check_optimized_url( $url ) {
189 - $response = wp_remote_get( $url, ['timeout' => 30] );
190 - if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) {
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 );
191 270 return false;
192 271 }
193 272 return true;
194 273 }
@@ -193,32 +272,22 @@
193 272 return true;
194 273 }
195 274
196 275 /**
197 - * Get options for the signed urls api call.
276 + * Send a list of images to upload.
198 277 *
199 - * @param string $original_url Image original url.
200 - * @param string $delete Whether to delete a bucket object or not(ie. generate signed upload url).
201 - * @param string $table_id Remote id used on our servers.
202 - * @param string $update_table False or success.
203 - * @param string $get_url Whether to return a get url or not.
204 - * @param string $width Original image width.
205 - * @param string $height Original image height.
206 - * @param int $file_size Original file size.
278 + * @param array $images List of Images.
207 279 * @return array
208 280 */
209 - public function call_upload_api( $original_url = '', $delete = 'false', $table_id = '', $update_table = 'false', $get_url = 'false', $width = 'auto', $height = 'auto', $file_size = 0 ) {
281 + public function call_onboard_api( $images = [] ) {
282 + $settings = new Optml_Settings();
283 + $token_images = $settings->get( 'cache_buster_images' );
284 +
210 285 $body = [
211 - 'secret' => Optml_Config::$secret,
212 - 'userKey' => Optml_Config::$key,
213 - 'originalUrl' => $original_url,
214 - 'deleteUrl' => $delete,
215 - 'id' => $table_id,
216 - 'updateDynamo' => $update_table,
217 - 'getUrl' => $get_url,
218 - 'width' => $width,
219 - 'height' => $height,
220 - 'originalFileSize' => $file_size,
286 + 'secret' => Optml_Config::$secret,
287 + 'userKey' => Optml_Config::$key,
288 + 'images' => $images,
289 + 'cache_buster' => $token_images,
221 290 ];
222 291 $body = wp_json_encode( $body );
223 292
224 293 $options = [
@@ -230,25 +299,38 @@
230 299 'blocking' => true,
231 300 'sslverify' => false,
232 301 'data_format' => 'body',
233 302 ];
234 - return wp_remote_post( $this->upload_api_root, $options );
303 + return wp_remote_post( $this->onboard_api_root, $options );
235 304 }
305 +
306 +
236 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 + /**
237 317 * Register user remotely on optimole.com.
238 318 *
239 319 * @param string $email User email.
240 320 *
241 - * @return array|bool Api response.
321 + * @return array|bool|string|WP_Error Api response.
242 322 */
243 323 public function create_account( $email ) {
244 324 return $this->request(
245 - 'optml/v1/user/register-remote',
325 + 'optml/v2/account/complete_register_remote',
246 326 'POST',
247 327 [
248 328 'email' => $email,
249 329 'version' => OPTML_VERSION,
330 + 'sample_image' => $this->get_sample_image(),
250 331 'site' => get_home_url(),
332 + 'reference' => get_option( 'optimole_reference_key', '' ),
251 333 ]
252 334 );
253 335 }
254 336
@@ -256,92 +338,103 @@
256 338 * Get the optimized images from API.
257 339 *
258 340 * @param string $api_key the api key.
259 341 *
260 - * @return array|bool
342 + * @return array|bool|WP_Error
261 343 */
262 344 public function get_optimized_images( $api_key = '' ) {
263 345 if ( ! empty( $api_key ) ) {
264 346 $this->api_key = $api_key;
265 347 }
266 -
267 - return $this->request( '/optml/v1/stats/images' );
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 ] );
268 355 }
269 356
270 357 /**
271 - * Get the watermarks from API.
358 + * Call the images endpoint.
272 359 *
273 - * @param string $api_key The API key.
274 - *
275 - * @return array|bool
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.
276 364 */
277 - public function get_watermarks( $api_key = '' ) {
278 - if ( ! empty( $api_key ) ) {
279 - $this->api_key = $api_key;
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;
280 372 }
281 373
282 - return $this->request( '/optml/v1/settings/watermark' );
374 + if ( ! empty( $domains ) ) {
375 + $params['domains'] = implode( ',', $domains );
376 + }
377 + return $this->request( 'optml/v2/media/browser', 'GET', $params );
283 378 }
284 -
285 379 /**
286 - * Remove the watermark from the API.
380 + * Get offload conflicts.
287 381 *
288 - * @param integer $post_id The watermark post ID.
289 - * @param string $api_key The API key.
290 - *
291 - * @return array|bool
382 + * @return array The decoded conflicts list.
292 383 */
293 - public function remove_watermark( $post_id, $api_key = '' ) {
294 - if ( ! empty( $api_key ) ) {
295 - $this->api_key = $api_key;
296 - }
297 -
298 - return $this->request( '/optml/v1/settings/watermark', 'DELETE', [ 'watermark' => $post_id ] );
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 );
299 387 }
300 -
301 388 /**
302 - * Add watermark.
389 + * Get offload conflicts.
303 390 *
304 - * @param array $file The file to be uploaded.
305 - *
306 - * @return array|bool|mixed|object
391 + * @param array $error_response The error to send as a string.
307 392 */
308 - public function add_watermark( $file ) {
393 + public function log_offload_error( $error_response ) {
309 394
310 - $headers = [
311 - 'Content-Disposition' => 'attachment; filename=' . $file['file']['name'],
312 - ];
395 + $headers = wp_remote_retrieve_headers( $error_response );
396 + $body = wp_remote_retrieve_body( $error_response );
313 397
314 - $response = $this->request( 'wp/v2/media', 'POST', file_get_contents( $file['file']['tmp_name'] ), $headers );
315 -
316 - if ( $response === false ) {
317 - return false;
398 + $headers_to_log = 'no_headers_returned';
399 + if ( ! empty( $headers ) ) {
400 + $headers_to_log = wp_json_encode( $headers->getAll() );
318 401 }
319 -
320 - return $response;
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 + );
321 417 }
322 418
323 419 /**
324 - * Call the images endpoint.
420 + * Send Offloading Logs
325 421 *
326 - * @param integer $page Page used to advance the search.
327 - * @param array $domains Domains to filter by.
328 - * @param string $search The string to search inside the originURL.
329 - * @return mixed The decoded json response from the api.
422 + * @param string $type Type of log (offload/rollback).
423 + * @param string $message Log message.
424 + *
425 + * @return mixed
330 426 */
331 - public function get_cloud_images( $page = 0, $domains = [], $search = '' ) {
332 -
333 - $params = ['key' => Optml_Config::$key ];
334 - $params['page'] = $page;
335 - $params['size'] = 40;
336 - if ( $search !== '' ) {
337 - $params['search'] = $search;
338 - }
339 -
340 - if ( ! empty( $domains ) ) {
341 - $params['domains'] = implode( ',', $domains );
342 - }
343 - return $this->request( 'optml/v2/media/browser', 'GET', $params );
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 + );
344 437 }
345 438
346 439 /**
347 440 * Throw error on object clone