PluginProbe
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization / trunk
Optimole – Optimize Images | Convert WebP & AVIF | CDN & Lazy Load | Image Optimization vtrunk
4.2.14 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 All 135 releases
← All changes | inc/api.php +210 -122 3.1.3 → trunk 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,19 +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 - if ( $path === 'optml/v1/user/register-remote'
138 - && isset( $response['error'] )
139 - && $response['error'] === 'ERROR: This email is already registered, please choose another one.' ) {
140 - return 'email_registered';
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>' ) );
141 196 }
142 - return false;
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;
143 229 }
144 230
145 231 return $response['data'];
146 -
147 232 }
148 233
149 234 /**
150 235 * Builds Request arguments array.
@@ -171,21 +256,8 @@
171 256 return $args;
172 257 }
173 258
174 259 /**
175 - * Upload image to our servers using the generated signed url.
176 - *
177 - * @param string $upload_url The signed to url to upload the image to.
178 - * @param string $content_type Image mime type, it must match the actual mime type of the image.
179 - * @param string $image Image data from file_get_contents.
180 - * @return mixed
181 - */
182 - public function upload_image( $upload_url, $content_type, $image ) {
183 - $args = $this->build_args( 'PUT', '', ['content-type' => $content_type], $image );
184 - return wp_remote_request( $upload_url, $args );
185 - }
186 -
187 - /**
188 260 * Check if the optimized url is available.
189 261 *
190 262 * @param string $url The optimized url to check.
191 263 * @return bool Whether or not the url is valid.
@@ -190,10 +262,12 @@
190 262 * @param string $url The optimized url to check.
191 263 * @return bool Whether or not the url is valid.
192 264 */
193 265 public function check_optimized_url( $url ) {
194 - $response = wp_remote_get( $url, ['timeout' => 30] );
195 - 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 );
196 270 return false;
197 271 }
198 272 return true;
199 273 }
@@ -198,32 +272,22 @@
198 272 return true;
199 273 }
200 274
201 275 /**
202 - * Get options for the signed urls api call.
276 + * Send a list of images to upload.
203 277 *
204 - * @param string $original_url Image original url.
205 - * @param string $delete Whether to delete a bucket object or not(ie. generate signed upload url).
206 - * @param string $table_id Remote id used on our servers.
207 - * @param string $update_table False or success.
208 - * @param string $get_url Whether to return a get url or not.
209 - * @param string $width Original image width.
210 - * @param string $height Original image height.
211 - * @param int $file_size Original file size.
278 + * @param array $images List of Images.
212 279 * @return array
213 280 */
214 - 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 +
215 285 $body = [
216 - 'secret' => Optml_Config::$secret,
217 - 'userKey' => Optml_Config::$key,
218 - 'originalUrl' => $original_url,
219 - 'deleteUrl' => $delete,
220 - 'id' => $table_id,
221 - 'updateDynamo' => $update_table,
222 - 'getUrl' => $get_url,
223 - 'width' => $width,
224 - 'height' => $height,
225 - 'originalFileSize' => $file_size,
286 + 'secret' => Optml_Config::$secret,
287 + 'userKey' => Optml_Config::$key,
288 + 'images' => $images,
289 + 'cache_buster' => $token_images,
226 290 ];
227 291 $body = wp_json_encode( $body );
228 292
229 293 $options = [
@@ -235,25 +299,38 @@
235 299 'blocking' => true,
236 300 'sslverify' => false,
237 301 'data_format' => 'body',
238 302 ];
239 - return wp_remote_post( $this->upload_api_root, $options );
303 + return wp_remote_post( $this->onboard_api_root, $options );
240 304 }
305 +
306 +
241 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 + /**
242 317 * Register user remotely on optimole.com.
243 318 *
244 319 * @param string $email User email.
245 320 *
246 - * @return array|bool Api response.
321 + * @return array|bool|string|WP_Error Api response.
247 322 */
248 323 public function create_account( $email ) {
249 324 return $this->request(
250 - 'optml/v1/user/register-remote',
325 + 'optml/v2/account/complete_register_remote',
251 326 'POST',
252 327 [
253 328 'email' => $email,
254 329 'version' => OPTML_VERSION,
330 + 'sample_image' => $this->get_sample_image(),
255 331 'site' => get_home_url(),
332 + 'reference' => get_option( 'optimole_reference_key', '' ),
256 333 ]
257 334 );
258 335 }
259 336
@@ -261,92 +338,103 @@
261 338 * Get the optimized images from API.
262 339 *
263 340 * @param string $api_key the api key.
264 341 *
265 - * @return array|bool
342 + * @return array|bool|WP_Error
266 343 */
267 344 public function get_optimized_images( $api_key = '' ) {
268 345 if ( ! empty( $api_key ) ) {
269 346 $this->api_key = $api_key;
270 347 }
271 -
272 - 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 ] );
273 355 }
274 356
275 357 /**
276 - * Get the watermarks from API.
358 + * Call the images endpoint.
277 359 *
278 - * @param string $api_key The API key.
279 - *
280 - * @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.
281 364 */
282 - public function get_watermarks( $api_key = '' ) {
283 - if ( ! empty( $api_key ) ) {
284 - $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;
285 372 }
286 373
287 - 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 );
288 378 }
289 -
290 379 /**
291 - * Remove the watermark from the API.
380 + * Get offload conflicts.
292 381 *
293 - * @param integer $post_id The watermark post ID.
294 - * @param string $api_key The API key.
295 - *
296 - * @return array|bool
382 + * @return array The decoded conflicts list.
297 383 */
298 - public function remove_watermark( $post_id, $api_key = '' ) {
299 - if ( ! empty( $api_key ) ) {
300 - $this->api_key = $api_key;
301 - }
302 -
303 - 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 );
304 387 }
305 -
306 388 /**
307 - * Add watermark.
389 + * Get offload conflicts.
308 390 *
309 - * @param array $file The file to be uploaded.
310 - *
311 - * @return array|bool|mixed|object
391 + * @param array $error_response The error to send as a string.
312 392 */
313 - public function add_watermark( $file ) {
393 + public function log_offload_error( $error_response ) {
314 394
315 - $headers = [
316 - 'Content-Disposition' => 'attachment; filename=' . $file['file']['name'],
317 - ];
395 + $headers = wp_remote_retrieve_headers( $error_response );
396 + $body = wp_remote_retrieve_body( $error_response );
318 397
319 - $response = $this->request( 'wp/v2/media', 'POST', file_get_contents( $file['file']['tmp_name'] ), $headers );
320 -
321 - if ( $response === false ) {
322 - return false;
398 + $headers_to_log = 'no_headers_returned';
399 + if ( ! empty( $headers ) ) {
400 + $headers_to_log = wp_json_encode( $headers->getAll() );
323 401 }
324 -
325 - 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 + );
326 417 }
327 418
328 419 /**
329 - * Call the images endpoint.
420 + * Send Offloading Logs
330 421 *
331 - * @param integer $page Page used to advance the search.
332 - * @param array $domains Domains to filter by.
333 - * @param string $search The string to search inside the originURL.
334 - * @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
335 426 */
336 - public function get_cloud_images( $page = 0, $domains = [], $search = '' ) {
337 -
338 - $params = ['key' => Optml_Config::$key ];
339 - $params['page'] = $page;
340 - $params['size'] = 40;
341 - if ( $search !== '' ) {
342 - $params['search'] = $search;
343 - }
344 -
345 - if ( ! empty( $domains ) ) {
346 - $params['domains'] = implode( ',', $domains );
347 - }
348 - 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 + );
349 437 }
350 438
351 439 /**
352 440 * Throw error on object clone