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/app_replacer.php +193 -58 3.0.1 → trunk View file →
@@ -1,6 +1,9 @@
1 1 <?php
2 2
3 +use Optimole\Sdk\Optimole;
4 +use Optimole\Sdk\ValueObject\Position;
5 +
3 6 /**
4 7 * Class Optml_App_Replacer
5 8 *
6 9 * @package \Optml\Inc
@@ -6,13 +9,14 @@
6 9 * @package \Optml\Inc
7 10 * @author Optimole <[email protected]>
8 11 */
9 12 abstract class Optml_App_Replacer {
13 + use Optml_Dam_Offload_Utils;
10 14
11 15 /**
12 16 * Filters used for lazyload.
13 17 *
14 - * @var null Lazyload filters.
18 + * @var array Lazyload filters.
15 19 */
16 20 protected static $filters = null;
17 21 /**
18 22 * Holds an array of image sizes.
@@ -56,19 +60,31 @@
56 60 * @var Optml_Settings $settings
57 61 */
58 62 public $settings = null;
59 63 /**
60 - * Defines which is the maximum width accepted in the optimization process.
64 + * Cached offloading status.
61 65 *
66 + * @var null|bool Offload status.
67 + */
68 + public static $offload_enabled = null;
69 + /**
70 + * Defines if the dimensions should be limited when images are served.
71 + *
72 + * @var bool
73 + */
74 + protected $limit_dimensions_enabled = false;
75 + /**
76 + * Defines which is the maximum width accepted when images are served.
77 + *
62 78 * @var int
63 79 */
64 - protected $max_width = 3000;
80 + protected $limit_width = 1920;
65 81 /**
66 - * Defines which is the maximum width accepted in the optimization process.
82 + * Defines which is the maximum height accepted when images are served.
67 83 *
68 84 * @var int
69 85 */
70 - protected $max_height = 3000;
86 + protected $limit_height = 1080;
71 87 /**
72 88 * Defines if css minification should be used.
73 89 *
74 90 * @var int
@@ -82,9 +98,9 @@
82 98 protected $is_js_minify_on = 0;
83 99 /**
84 100 * A cached version of `wp_upload_dir`
85 101 *
86 - * @var null
102 + * @var null|array
87 103 */
88 104 protected $upload_resource = null;
89 105
90 106 /**
@@ -118,14 +134,14 @@
118 134 * Whether the site is whitelisted or not. Used when signing the urls.
119 135 *
120 136 * @var bool Domains.
121 137 */
122 - protected $is_allowed_site = [];
138 + protected $is_allowed_site = false;
123 139
124 140 /**
125 - * Holds the most recent value for the cache buster.
141 + * Holds the most recent value for the cache buster, updated to hold only for images if active_cache_buster_assets is defined.
126 142 *
127 - * @var string Cache Buster value.
143 + * @var string Cache Buster global value if active_cache_buster_assets is undefined else the value for images.
128 144 */
129 145 protected $active_cache_buster = '';
130 146
131 147 /**
@@ -135,15 +151,21 @@
135 151 */
136 152 protected static $ignored_url_map = [];
137 153
138 154 /**
155 + * Holds the most recent value for the cache buster for assets.
156 + *
157 + * @var string Cache Buster value.
158 + */
159 + protected $active_cache_buster_assets = '';
160 +
161 + /**
139 162 * Returns possible src attributes.
140 163 *
141 164 * @return array
142 165 */
143 166 public static function possible_src_attributes() {
144 -
145 - if ( ! empty( self::$possible_src_attributes ) && is_array( self::$possible_src_attributes ) ) {
167 + if ( null !== self::$possible_src_attributes ) {
146 168 return self::$possible_src_attributes;
147 169 }
148 170
149 171 self::$possible_src_attributes = apply_filters( 'optml_possible_src_attributes', [] );
@@ -156,14 +178,13 @@
156 178 *
157 179 * @return array
158 180 */
159 181 public static function possible_lazyload_flags() {
160 -
161 - if ( ! empty( self::$ignore_lazyload_strings ) && is_array( self::$ignore_lazyload_strings ) ) {
182 + if ( null !== self::$ignore_lazyload_strings ) {
162 183 return self::$ignore_lazyload_strings;
163 184 }
164 185
165 - self::$possible_src_attributes = apply_filters( 'optml_possible_lazyload_flags', [ 'skip-lazy', 'data-skip-lazy' ] );
186 + self::$possible_src_attributes = apply_filters( 'optml_possible_lazyload_flags', [ 'skip-lazy', 'data-skip-lazy', 'data-opt-src' ] );
166 187
167 188 return array_merge( self::$possible_src_attributes, [ '<noscript' ] );
168 189 }
169 190 /**
@@ -171,16 +192,15 @@
171 192 *
172 193 * @return array
173 194 */
174 195 public static function possible_tag_flags() {
175 -
176 - if ( ! empty( self::$ignore_tag_strings ) && is_array( self::$ignore_tag_strings ) ) {
196 + if ( null !== self::$ignore_tag_strings ) {
177 197 return self::$ignore_tag_strings;
178 198 }
179 199
180 200 self::$ignore_tag_strings = apply_filters( 'optml_skip_optimizations_css_classes', [ 'skip-optimization' ] );
181 201
182 - return self::$ignore_tag_strings;
202 + return self::$ignore_tag_strings;
183 203 }
184 204 /**
185 205 * Returns possible data-opt-src ignore flags attributes.
186 206 *
@@ -186,10 +206,9 @@
186 206 *
187 207 * @return array
188 208 */
189 209 public static function possible_data_ignore_flags() {
190 -
191 - if ( ! empty( self::$ignore_data_opt_attribute ) && is_array( self::$ignore_data_opt_attribute ) ) {
210 + if ( null !== self::$ignore_data_opt_attribute ) {
192 211 return self::$ignore_data_opt_attribute;
193 212 }
194 213
195 214 self::$ignore_data_opt_attribute = apply_filters( 'optml_ignore_data_opt_flag', [] );
@@ -201,10 +220,10 @@
201 220 * Size to crop maping.
202 221 *
203 222 * @return array Size mapping.
204 223 */
205 - protected static function size_to_crop() {
206 - if ( ! empty( self::$size_to_crop ) && is_array( self::$size_to_crop ) ) {
224 + public static function size_to_crop() {
225 + if ( ! empty( self::$size_to_crop ) ) {
207 226 return self::$size_to_crop;
208 227 }
209 228
210 229 foreach ( self::image_sizes() as $size_data ) {
@@ -223,16 +242,17 @@
223 242
224 243 /**
225 244 * Set possible custom size.
226 245 *
227 - * @param null $width Width value.
228 - * @param null $height Height Value.
229 - * @param null $crop Croping.
246 + * @param int $width Width value.
247 + * @param int $height Height Value.
248 + * @param bool|array $crop Croping.
230 249 */
231 250 public static function add_size( $width = null, $height = null, $crop = null ) {
232 - if ( empty( $width ) || empty( $height ) ) {
251 + if ( is_null( $width ) || is_null( $height ) ) {
233 252 return;
234 253 }
254 +
235 255 self::$custom_size_buffer[ 'cmole' . $width . $height ] = [
236 256 'width' => (int) $width,
237 257 'height' => (int) $height,
238 258 'enlarge' => true,
@@ -237,9 +257,8 @@
237 257 'height' => (int) $height,
238 258 'enlarge' => true,
239 259 'crop' => $crop,
240 260 ];
241 -
242 261 }
243 262
244 263 /**
245 264 * Returns the array of image sizes since `get_intermediate_image_sizes` and image metadata doesn't include the
@@ -247,11 +266,10 @@
247 266 *
248 267 * @return array
249 268 * @global $wp_additional_image_sizes
250 269 */
251 - protected static function image_sizes() {
252 -
253 - if ( ! empty( self::$image_sizes ) && is_array( self::$image_sizes ) ) {
270 + public static function image_sizes() {
271 + if ( ! empty( self::$image_sizes ) ) {
254 272 return self::$image_sizes;
255 273 }
256 274
257 275 global $_wp_additional_image_sizes;
@@ -303,9 +321,9 @@
303 321 },
304 322 self::$image_sizes
305 323 );
306 324
307 - return is_array( self::$image_sizes ) ? self::$image_sizes : [];
325 + return self::$image_sizes;
308 326 }
309 327
310 328 /**
311 329 * The initialize method.
@@ -315,8 +333,16 @@
315 333 $this->set_properties();
316 334
317 335 self::$filters = $this->settings->get_filters();
318 336 add_filter(
337 + 'optml_should_avif_ext',
338 + function ( $should_avif, $ext ) {
339 + return $ext !== 'svg';
340 + },
341 + 10,
342 + 2
343 + );
344 + add_filter(
319 345 'optml_possible_lazyload_flags',
320 346 function ( $strings = [] ) {
321 347 foreach ( self::$filters[ Optml_Settings::FILTER_TYPE_LAZYLOAD ][ Optml_Settings::FILTER_CLASS ] as $rule_flag => $status ) {
322 348 $strings[] = $rule_flag;
@@ -323,10 +349,9 @@
323 349 }
324 350
325 351 return $strings;
326 352 },
327 - 10,
328 - 2
353 + 10
329 354 );
330 355 add_filter(
331 356 'optml_skip_optimizations_css_classes',
332 357 function ( $strings = [] ) {
@@ -334,11 +359,13 @@
334 359 $strings[] = $rule_flag;
335 360 }
336 361 return $strings;
337 362 },
338 - 10,
339 - 2
363 + 10
340 364 );
365 + if ( self::$offload_enabled === null ) {
366 + self::$offload_enabled = ( new Optml_Settings() )->is_offload_enabled();
367 + }
341 368 }
342 369
343 370
344 371 /**
@@ -352,21 +379,36 @@
352 379 'directory' => $upload_data['basedir'],
353 380 ];
354 381 $this->upload_resource['url_length'] = strlen( $this->upload_resource['url'] );
355 382
356 - $content_parts = parse_url( content_url() );
383 + $content_url = content_url();
357 384
358 - $this->upload_resource['content_path'] = $content_parts['path'];
359 - $this->upload_resource['content_folder'] = ltrim( $content_parts['path'], '/' );
385 + if ( strpos( $content_url, '/' ) === 0 ) {
386 + $content_url = get_site_url() . $content_url;
387 + }
388 + $content_parts = parse_url( $content_url );
389 + $this->upload_resource['content_path'] = '/';
390 + $this->upload_resource['content_folder'] = '/';
391 + if ( isset( $content_parts['path'] ) ) {
392 + $this->upload_resource['content_path'] = $content_parts['path'];
393 + $this->upload_resource['content_folder'] = ltrim( $content_parts['path'], '/' );
394 + }
395 +
360 396 $this->upload_resource['content_folder_length'] = strlen( $this->upload_resource['content_folder'] );
361 397 $this->upload_resource['content_host'] = $content_parts['scheme'] . '://' . $content_parts['host'];
362 398
363 399 $service_data = $this->settings->get( 'service_data' );
364 400
401 + $domain = '';
402 + if ( isset( $service_data['is_cname_assigned'] ) && $service_data['is_cname_assigned'] === 'yes' && ! empty( $service_data['domain'] ) ) {
403 + $domain = $service_data['domain'];
404 + }
365 405 Optml_Config::init(
366 406 [
367 - 'key' => $service_data['cdn_key'],
368 - 'secret' => $service_data['cdn_secret'],
407 + 'key' => $service_data['cdn_key'],
408 + 'secret' => $service_data['cdn_secret'],
409 + 'domain' => $domain,
410 + 'api_key' => $this->settings->get( 'api_key' ),
369 411 ]
370 412 );
371 413
372 414 if ( defined( 'OPTML_SITE_MIRROR' ) && constant( 'OPTML_SITE_MIRROR' ) ) {
@@ -374,9 +416,11 @@
374 416 }
375 417
376 418 $this->possible_sources = $this->extract_domain_from_urls(
377 419 array_merge(
378 - [ get_home_url() ],
420 + [
421 + get_home_url(),
422 + ],
379 423 array_values( $this->site_mappings ),
380 424 array_keys( $this->site_mappings )
381 425 )
382 426 );
@@ -381,9 +425,18 @@
381 425 )
382 426 );
383 427
384 428 $this->allowed_sources = $this->extract_domain_from_urls( $service_data['whitelist'] );
385 - $this->active_cache_buster = $this->settings->get( 'cache_buster' );
429 + $this->active_cache_buster = $this->settings->get( 'cache_buster_images' );
430 + $this->active_cache_buster_assets = $this->settings->get( 'cache_buster_assets' );
431 +
432 + if ( empty( $this->active_cache_buster ) ) {
433 + $this->active_cache_buster = $this->settings->get( 'cache_buster' );
434 + }
435 + if ( empty( $this->active_cache_buster_assets ) ) {
436 + $this->active_cache_buster_assets = $this->settings->get( 'cache_buster' );
437 + }
438 +
386 439 // Allways allow Photon urls.
387 440 $this->allowed_sources['i0.wp.com'] = true;
388 441 $this->allowed_sources['i1.wp.com'] = true;
389 442 $this->allowed_sources['i2.wp.com'] = true;
@@ -388,15 +441,18 @@
388 441 $this->allowed_sources['i1.wp.com'] = true;
389 442 $this->allowed_sources['i2.wp.com'] = true;
390 443 $this->is_allowed_site = count( array_diff_key( $this->possible_sources, $this->allowed_sources ) ) > 0;
391 444
392 - $this->max_height = $this->settings->get( 'max_height' );
393 - $this->max_width = $this->settings->get( 'max_width' );
445 + $this->limit_dimensions_enabled = $this->settings->get( 'limit_dimensions' ) === 'enabled';
446 + if ( $this->limit_dimensions_enabled ) {
447 + $this->limit_height = $this->settings->get( 'limit_height' );
448 + $this->limit_width = $this->settings->get( 'limit_width' );
449 + }
394 450
395 451 $this->is_css_minify_on = ( $this->settings->get( 'css_minify' ) === 'enabled' ) ? 1 : 0;
396 452 $this->is_js_minify_on = ( $this->settings->get( 'js_minify' ) === 'enabled' ) ? 1 : 0;
397 453
398 - add_filter( 'optml_strip_image_size_from_url', [ $this, 'strip_image_size_from_url' ], 10, 1 );
454 + add_filter( 'optml_strip_image_size_from_url', [ $this, 'strip_image_size_from_url' ], 10 );
399 455 add_filter(
400 456 'image_resize_dimensions',
401 457 [ __CLASS__, 'listen_to_sizes' ],
402 458 999999,
@@ -406,9 +462,9 @@
406 462
407 463 /**
408 464 * Method to expose upload resource property.
409 465 *
410 - * @return null
466 + * @return null|array
411 467 */
412 468 public function get_upload_resource() {
413 469 return $this->upload_resource;
414 470 }
@@ -424,9 +480,9 @@
424 480 * @param mixed $crop Cropping behaviour.
425 481 *
426 482 * @return mixed Original value.
427 483 */
428 - static function listen_to_sizes( $value, $orig_w, $orig_h, $dest_w, $dest_h, $crop ) {
484 + public static function listen_to_sizes( $value, $orig_w, $orig_h, $dest_w, $dest_h, $crop ) {
429 485 self::add_size( $dest_w, $dest_h, $crop );
430 486
431 487 return $value;
432 488 }
@@ -433,9 +489,9 @@
433 489
434 490 /**
435 491 * Extract domains and use them as keys for fast processing.
436 492 *
437 - * @param array $urls Input urls.
493 + * @param array|null $urls Input urls.
438 494 *
439 495 * @return array Array of domains as keys.
440 496 */
441 497 protected function extract_domain_from_urls( $urls = [] ) {
@@ -472,9 +528,9 @@
472 528
473 529 /**
474 530 * Check if we can replace the url.
475 531 *
476 - * @param string $url Url to change.
532 + * @param string|mixed $url Url to change.
477 533 *
478 534 * @return bool Either we can replace this url or not.
479 535 */
480 536 public function can_replace_url( $url ) {
@@ -482,8 +538,12 @@
482 538 if ( ! is_string( $url ) ) {
483 539 return false; // @codeCoverageIgnore
484 540 }
485 541
542 + if ( $this->url_has_dam_flag( $url ) ) {
543 + return true;
544 + }
545 +
486 546 $url_parts = parse_url( $url );
487 547
488 548 if ( ! isset( $url_parts['host'] ) ) {
489 549 return false;
@@ -509,15 +569,27 @@
509 569 *
510 570 * @return string
511 571 **/
512 572 public function strip_image_size_from_url( $url ) {
513 -
573 + if ( apply_filters( 'optml_should_skip_strip_image_size', false, $url ) === true ) {
574 + return $url;
575 + }
514 576 if ( preg_match( '#(-\d+x\d+(?:_c)?|(@2x))\.(' . implode( '|', array_keys( Optml_Config::$image_extensions ) ) . '){1}$#i', $url, $src_parts ) ) {
515 577 $stripped_url = str_replace( $src_parts[1], '', $url );
578 +
579 + if ( $this->settings->is_offload_enabled() ) {
580 + // Treat offloaded attachments differently.
581 + $id = $this->attachment_url_to_post_id( $stripped_url );
582 +
583 + if ( $id !== 0 && $this->is_new_offloaded_attachment( $id ) ) {
584 + return $stripped_url;
585 + }
586 + }
587 +
516 588 // Extracts the file path to the image minus the base url
517 589 $file_path = substr( $stripped_url, strpos( $stripped_url, $this->upload_resource['url'] ) + $this->upload_resource['url_length'] );
518 590 if ( file_exists( $this->upload_resource['directory'] . $file_path ) ) {
519 - $url = $stripped_url;
591 + return $stripped_url;
520 592 }
521 593 }
522 594
523 595 return $url;
@@ -539,8 +611,17 @@
539 611 $crop = ( isset( $width_height_string[3] ) && $width_height_string[3] === '_c' );
540 612 if ( $width && $height ) {
541 613 return [ $width, $height, $crop ];
542 614 }
615 + } else {
616 + $optimized_args = $this->parse_dimension_from_optimized_url( $src );
617 + if ( $optimized_args[0] !== false || $optimized_args[1] !== false ) {
618 + return [
619 + $optimized_args[0] !== 'auto' ? (int) $optimized_args[0] : false,
620 + $optimized_args[1] !== 'auto' ? (int) $optimized_args[1] : false,
621 + false,
622 + ];
623 + }
543 624 }
544 625
545 626 return [ false, false, false ];
546 627 }
@@ -547,17 +628,71 @@
547 628
548 629 /**
549 630 * Get the optimized urls for the wp media modal.
550 631 *
551 - * @param string $url Original url.
552 - * @param string $table_id The cloud id of the image.
553 - * @param string $width Image width.
554 - * @param string $height Image height.
555 - * @param array $resize Optml crop array.
632 + * @param string $url Original url.
633 + * @param string $table_id The cloud id of the image.
634 + * @param int|string $width Image width.
635 + * @param int|string $height Image height.
636 + * @param array $resize Optml crop array.
556 637 * @return string The optimized url.
557 638 */
558 639 public function get_media_optimized_url( $url, $table_id, $width = 'auto', $height = 'auto', $resize = [] ) {
559 - $optimized_url = ( new Optml_Image( $url, ['width' => $width, 'height' => $height, 'resize' => $resize, 'quality' => $this->settings->get_numeric_quality()], $this->settings->get( 'cache_buster' ) ) )->get_url();
560 - $optimized_url = str_replace( $url, Optml_Media_Offload::KEYS['not_processed_flag'] . 'media_cloud' . '/' . Optml_Media_Offload::KEYS['uploaded_flag'] . $table_id . '/' . $url, $optimized_url );
561 - return $optimized_url;
640 + return str_replace( $url, Optml_Media_Offload::KEYS['not_processed_flag'] . 'media_cloud' . '/' . Optml_Media_Offload::KEYS['uploaded_flag'] . $table_id . '/' . $url, $this->get_optimized_image_url( $url, $width, $height, $resize ) );
641 + }
642 +
643 + /**
644 + * Test that the url has the dam flag.
645 + *
646 + * @param string $url The image URL to check.
647 + *
648 + * @return bool
649 + */
650 + public function url_has_dam_flag( $url ) {
651 + return strpos( $url, Optml_Dam::URL_DAM_FLAG ) !== false;
652 + }
653 +
654 + /**
655 + * Get the optimized image url for the image url.
656 + *
657 + * @param string $url The image URL.
658 + * @param mixed $width The image width.
659 + * @param mixed $height The image height.
660 + * @param array<string, mixed>|mixed $resize The resize properties.
661 + *
662 + * @return string
663 + */
664 + protected function get_optimized_image_url( $url, $width, $height, $resize = [] ) {
665 + $width = is_int( $width ) ? $width : 'auto';
666 + $height = is_int( $height ) ? $height : 'auto';
667 + // If the image is already using Optimole URL, we extract the source to rebuild it.
668 + $url = $this->get_unoptimized_url( $url );
669 +
670 + $optimized_image = Optimole::image( $url, $this->settings->get( 'cache_buster' ) )
671 + ->width( $width )
672 + ->height( $height );
673 +
674 + if ( is_array( $resize ) && ! empty( $resize['type'] ) ) {
675 + $optimized_image->resize( $resize['type'], $resize['gravity'] ?? Position::CENTER, $resize['enlarge'] ?? false );
676 +
677 + }
678 +
679 + $optimized_image->quality( $this->settings->to_accepted_quality( $this->settings->get_quality() ) );
680 +
681 + return $optimized_image->getUrl();
682 + }
683 +
684 + /**
685 + * Returns an image id from the url.
686 + *
687 + * @param string $url The image URL.
688 + *
689 + * @return int
690 + */
691 + public function get_id_by_url( $url ) {
692 + $url = $this->get_unoptimized_url( $url );
693 + srand( crc32( $url ) );
694 + $random_id = rand();
695 + srand();
696 + return $random_id;
562 697 }
563 698 }