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