Changeset 3398277
- Timestamp:
- 11/18/2025 06:19:54 PM (5 months ago)
- Location:
- easy-image-optimizer
- Files:
-
- 10 added
- 30 edited
- 1 copied
-
tags/4.3.0 (copied) (copied from easy-image-optimizer/trunk)
-
tags/4.3.0/changelog.txt (modified) (1 diff)
-
tags/4.3.0/classes/class-base.php (modified) (3 diffs)
-
tags/4.3.0/classes/class-buffer.php (added)
-
tags/4.3.0/classes/class-exactdn.php (modified) (32 diffs)
-
tags/4.3.0/classes/class-hs-beacon.php (modified) (1 diff)
-
tags/4.3.0/classes/class-lazy-load.php (modified) (23 diffs)
-
tags/4.3.0/classes/class-page-parser.php (modified) (5 diffs)
-
tags/4.3.0/classes/class-plugin.php (modified) (9 diffs)
-
tags/4.3.0/classes/class-settings.php (added)
-
tags/4.3.0/easy-image-optimizer.php (modified) (5 diffs)
-
tags/4.3.0/images/easyio-toon-car-with-text.png (added)
-
tags/4.3.0/images/easyio-toon-car.png (modified) (previous)
-
tags/4.3.0/includes/chart.min.js (added)
-
tags/4.3.0/includes/easyio-settings.css (added)
-
tags/4.3.0/includes/eio.js (modified) (2 diffs)
-
tags/4.3.0/includes/lazysizes-post.js (modified) (7 diffs)
-
tags/4.3.0/includes/lazysizes-pre.js (modified) (2 diffs)
-
tags/4.3.0/includes/lazysizes.min.js (modified) (1 diff)
-
tags/4.3.0/phpcs.ruleset.xml (modified) (1 diff)
-
tags/4.3.0/readme.txt (modified) (2 diffs)
-
trunk/changelog.txt (modified) (1 diff)
-
trunk/classes/class-base.php (modified) (3 diffs)
-
trunk/classes/class-buffer.php (added)
-
trunk/classes/class-exactdn.php (modified) (32 diffs)
-
trunk/classes/class-hs-beacon.php (modified) (1 diff)
-
trunk/classes/class-lazy-load.php (modified) (23 diffs)
-
trunk/classes/class-page-parser.php (modified) (5 diffs)
-
trunk/classes/class-plugin.php (modified) (9 diffs)
-
trunk/classes/class-settings.php (added)
-
trunk/easy-image-optimizer.php (modified) (5 diffs)
-
trunk/images/easyio-toon-car-with-text.png (added)
-
trunk/images/easyio-toon-car.png (modified) (previous)
-
trunk/includes/chart.min.js (added)
-
trunk/includes/easyio-settings.css (added)
-
trunk/includes/eio.js (modified) (2 diffs)
-
trunk/includes/lazysizes-post.js (modified) (7 diffs)
-
trunk/includes/lazysizes-pre.js (modified) (2 diffs)
-
trunk/includes/lazysizes.min.js (modified) (1 diff)
-
trunk/phpcs.ruleset.xml (modified) (1 diff)
-
trunk/readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
easy-image-optimizer/tags/4.3.0/changelog.txt
r3350722 r3398277 1 = 4.3.0 = 2 *Release Date - November 18, 2025* 3 4 * added: Lazy Load support for background images in external CSS files 5 * added: View CDN bandwidth usage on settings page 6 * changed: Lazy Load checks parent element for skip-lazy class 7 * changed: Lazy Load auto-sizing honors High DPI setting 8 * changed: Easy IO fills in 450px wide image when responsive (srcset) images have a gap 9 * improved: Lazy Load performance when searching for img elements 10 * improved: Lazy Load placeholder generation is faster and works better with Safari 11 * fixed: Lazy Load for iframes breaks WP Remote Users Sync plugin 12 1 13 = 4.2.1 = 2 14 *Release Date - August 26, 2025* -
easy-image-optimizer/tags/4.3.0/classes/class-base.php
r3328397 r3398277 327 327 if ( $this->is_iterable( $potential_logs ) ) { 328 328 foreach ( $potential_logs as $potential_log ) { 329 if ( $this->str_ends_with( $potential_log, '.log' ) && false !== strpos( $potential_log, strtolower( __NAMESPACE__ ) . '-debug-' ) && is_file( $this->content_dir . $potential_log ) ) {329 if ( \str_ends_with( $potential_log, '.log' ) && false !== strpos( $potential_log, strtolower( __NAMESPACE__ ) . '-debug-' ) && is_file( $this->content_dir . $potential_log ) ) { 330 330 return $this->content_dir . $potential_log; 331 331 } … … 1349 1349 1350 1350 /** 1351 * Performs a case-sensitive check indicating if 1352 * the haystack ends with needle. 1353 * 1354 * @param string $haystack The string to search in. 1355 * @param string $needle The substring to search for in the `$haystack`. 1356 * @return bool True if `$haystack` ends with `$needle`, otherwise false. 1357 */ 1358 public function str_ends_with( $haystack, $needle ) { 1359 if ( '' === $haystack && '' !== $needle ) { 1360 return false; 1361 } 1362 1363 $len = \strlen( $needle ); 1364 1365 return 0 === \substr_compare( $haystack, $needle, -$len, $len ); 1351 * Wrapper around size_format to remove the decimal from sizes in bytes. 1352 * 1353 * @param int $size A filesize in bytes. 1354 * @param int $precision Number of places after the decimal separator. 1355 * @return string Human-readable filesize. 1356 */ 1357 public function size_format( $size, $precision = 1 ) { 1358 // Convert it to human readable format. 1359 $size_str = \size_format( $size, $precision ); 1360 // Remove spaces and extra decimals when measurement is in bytes. 1361 return \preg_replace( '/\.0+ B ?/', ' B', $size_str ); 1366 1362 } 1367 1363 … … 1633 1629 return false; 1634 1630 } 1635 if ( 0 === \strpos( $url, '//' ) ) {1631 if ( \str_starts_with( $url, '//' ) ) { 1636 1632 $url = ( \is_ssl() ? 'https:' : 'http:' ) . $url; 1637 1633 } 1638 if ( false === \strpos( $url, 'http' ) && '/' !== \substr( $url, 0, 1) ) {1634 if ( ! \str_starts_with( $url, 'http' ) && ! \str_starts_with( $url, '/' ) && ! \str_starts_with( $url, '.' ) ) { 1639 1635 $url = ( \is_ssl() ? 'https://' : 'http://' ) . $url; 1640 1636 } -
easy-image-optimizer/tags/4.3.0/classes/class-exactdn.php
r3350722 r3398277 65 65 */ 66 66 public $full_width = false; 67 68 /** 69 * Indicates the local domain has changed, and Easy IO should be re-initialized. 70 * 71 * @access public 72 * @var bool $domain_mismatch 73 */ 74 public $domain_mismatch = false; 67 75 68 76 /** … … 399 407 \add_filter( 'autoptimize_filter_cssjs_multidomain', array( $this, 'add_cdn_domain' ) ); 400 408 401 if ( $this->is_as3cf_cname_active() ) { 402 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_as3cf_cname_active' ); 403 return; 404 } 409 \add_action( 'admin_notices', array( $this, 'admin_notices' ) ); 405 410 406 411 $upload_url_parts = $this->parse_url( $this->site_url ); … … 414 419 $this->set_exactdn_option( 'local_domain', \base64_encode( $this->upload_domain ) ); 415 420 $stored_local_domain = $this->upload_domain; 416 } elseif ( false !== \strpos( $stored_local_domain, '.' ) ) {421 } elseif ( \str_contains( $stored_local_domain, '.' ) ) { 417 422 $this->set_exactdn_option( 'local_domain', \base64_encode( $stored_local_domain ) ); 418 } else { 419 $stored_local_domain = \base64_decode( $stored_local_domain ); 420 } 421 $this->debug_message( "saved domain is $stored_local_domain" ); 423 } 424 $this->debug_message( "saved (local) domain is $stored_local_domain" ); 422 425 423 426 $this->debug_message( "allowing images from here: $this->upload_domain" ); … … 433 436 $this->debug_message( "removing this from urls: $this->remove_path" ); 434 437 } 435 if (436 $stored_local_domain !== $this->upload_domain &&437 ! $this->allow_image_domain( $stored_local_domain ) &&438 \is_admin()439 ) {440 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_domain_mismatch' );441 }442 438 $this->allowed_domains[] = $this->exactdn_domain; 443 439 $this->allowed_domains = \apply_filters( 'exactdn_allowed_domains', $this->allowed_domains ); … … 500 496 */ 501 497 public function cron_setup( $schedule = true ) { 502 $this->debug_message( '<b>' . __ FUNCTION__ . '()</b>' );498 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 503 499 $event = 'easyio_verification_checkin'; 504 500 // Setup scheduled optimization if the user has enabled it, and it isn't already scheduled. … … 530 526 531 527 /** 528 * Sends the useragent through filters for http requests to the EWWW IO API. 529 * 530 * @param string $useragent The current useragent used in http requests. 531 * @return string The filtered useragent. 532 */ 533 public function api_useragent( $useragent ) { 534 return apply_filters( 'exactdn_api_request_useragent', $useragent ); 535 } 536 537 /** 532 538 * Use the Site URL to get the zone domain. 533 539 */ … … 538 544 global $exactdn_activate_error; 539 545 $exactdn_activate_error = 'as3cf_cname_active'; 540 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_as3cf_cname_active' );541 546 return false; 542 547 } … … 548 553 $url = \set_url_scheme( $url, 'https' ); 549 554 } 550 \add_filter( 'http_headers_useragent', $this->prefix . 'cloud_useragent', PHP_INT_MAX );555 \add_filter( 'http_headers_useragent', array( $this, 'api_useragent' ), PHP_INT_MAX ); 551 556 $result = \wp_remote_post( 552 557 $url, … … 564 569 global $exactdn_activate_error; 565 570 $exactdn_activate_error = $error_message; 566 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_activation_error' );567 571 return false; 568 572 } elseif ( ! empty( $result['body'] ) && \strpos( $result['body'], 'domain' ) !== false ) { … … 583 587 if ( \get_option( 'exactdn_never_been_active' ) ) { 584 588 $this->set_option( $this->prefix . 'lazy_load', true ); 585 $this->set_option( 'exactdn_lossy', true );586 589 $this->set_option( 'exactdn_all_the_things', true ); 587 590 \delete_option( 'exactdn_never_been_active' ); … … 598 601 global $exactdn_activate_error; 599 602 $exactdn_activate_error = $error_message; 600 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_activation_error' );601 603 return false; 602 604 } … … 649 651 $test_url = \str_replace( $local_domain, $domain, $test_url ); 650 652 $this->debug_message( "test url is $test_url" ); 651 \add_filter( 'http_headers_useragent', $this->prefix . 'cloud_useragent', PHP_INT_MAX );653 \add_filter( 'http_headers_useragent', array( $this, 'api_useragent' ), PHP_INT_MAX ); 652 654 $test_result = \wp_remote_post( 653 655 $api_url, … … 665 667 $this->debug_message( "exactdn (1) verification request failed: $error_message" ); 666 668 $exactdn_activate_error = $error_message; 667 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_activation_error' );668 669 return false; 669 } elseif ( ! empty( $test_result['body'] ) && false === \strpos( $test_result['body'], 'error' ) ) {670 } elseif ( ! empty( $test_result['body'] ) && ! \str_contains( $test_result['body'], 'error' ) ) { 670 671 $response = \json_decode( $test_result['body'], true ); 671 672 if ( ! empty( $response['success'] ) ) { … … 677 678 $this->asset_domains = $response['asset_domains']; 678 679 } 679 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_activation_success' );680 680 return true; 681 681 } … … 689 689 \delete_site_option( $this->prefix . 'exactdn_domain' ); 690 690 } 691 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_activation_error' );692 691 return false; 693 692 } … … 695 694 $this->debug_message( 'received response code: ' . $test_result['response']['code'] ); 696 695 } 697 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_activation_error' );698 696 return false; 699 697 } 700 698 701 699 // Secondary test against the API db. 702 \add_filter( 'http_headers_useragent', $this->prefix . 'cloud_useragent', PHP_INT_MAX );700 \add_filter( 'http_headers_useragent', array( $this, 'api_useragent' ), PHP_INT_MAX ); 703 701 $result = \wp_remote_post( 704 702 $api_url, … … 715 713 $this->debug_message( "exactdn verification request failed: $error_message" ); 716 714 $exactdn_activate_error = $error_message; 717 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_activation_error' );718 715 return false; 719 } elseif ( ! empty( $result['body'] ) && false === \strpos( $result['body'], 'error' ) ) {716 } elseif ( ! empty( $result['body'] ) && ! \str_contains( $result['body'], 'error' ) ) { 720 717 $response = \json_decode( $result['body'], true ); 721 718 if ( ! empty( $response['success'] ) ) { … … 730 727 $this->debug_message( 'exactdn verification via API succeeded' ); 731 728 $this->set_exactdn_option( 'verified', 1, false ); 732 if ( empty( $last_checkin ) ) {733 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_activation_success' );734 }735 729 return true; 736 730 } … … 744 738 \delete_site_option( $this->prefix . 'exactdn_domain' ); 745 739 } 746 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_activation_error' );747 740 return false; 748 741 } … … 750 743 $this->debug_message( 'received response code: ' . $result['response']['code'] ); 751 744 } 752 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_activation_error' );753 745 return false; 754 746 } … … 762 754 // Prelim test with a known valid image to ensure http(s) connectivity. 763 755 $sim_url = 'https://optimize.exactdn.com/exactdn/testorig.jpg'; 764 \add_filter( 'http_headers_useragent', $this->prefix . 'cloud_useragent', PHP_INT_MAX );756 \add_filter( 'http_headers_useragent', array( $this, 'api_useragent' ), PHP_INT_MAX ); 765 757 $sim_result = \wp_remote_get( $sim_url ); 766 758 if ( \is_wp_error( $sim_result ) ) { … … 900 892 } 901 893 return \update_option( $this->prefix . 'exactdn_' . $option_name, $option_value, $autoload ); 894 } 895 896 /** 897 * Check for conditions that need to trigger an admin notice (action). 898 */ 899 public function admin_notices() { 900 if ( $this->is_as3cf_cname_active() ) { 901 \do_action( 'exactdn_as3cf_cname_active' ); 902 } 903 $stored_local_domain = $this->get_exactdn_option( 'local_domain' ); 904 $stored_local_domain = \base64_decode( $stored_local_domain ); 905 if ( 906 $stored_local_domain !== $this->upload_domain && 907 ! $this->allow_image_domain( $stored_local_domain ) 908 ) { 909 $this->domain_mismatch = true; 910 \do_action( 'exactdn_domain_mismatch' ); 911 } 902 912 } 903 913 … … 2952 2962 * @param array|bool $multipliers Array of multipliers to use or false to bypass. 2953 2963 */ 2954 $multipliers = \apply_filters( 'exactdn_srcset_multipliers', array( .2, .4, .6, .8, 1 ) );2964 $multipliers = \apply_filters( 'exactdn_srcset_multipliers', array( .2, .4, .6, .8, 1, 450 ) ); 2955 2965 2956 2966 if ( empty( $url ) || empty( $multipliers ) ) { … … 3039 3049 3040 3050 $newwidth = \intval( $base * $multiplier ); 3041 if ( 1920 === (int) $multiplier ) {3042 $newwidth = 1920;3043 if ( ! $w_descriptor || 1920>= $reqwidth || 'soft' !== $crop ) {3051 if ( $multiplier > 50 ) { // Not a true multiplier, but a hard-coded width. 3052 $newwidth = $multiplier; 3053 if ( ! $w_descriptor || $multiplier >= $reqwidth || 'soft' !== $crop ) { 3044 3054 $this->debug_message( "skipping $multiplier due to no w descriptor, larger than $reqwidth, or $crop !== soft" ); 3045 3055 continue; … … 3150 3160 * @param array|bool $multipliers Array of multipliers to use or false to bypass. 3151 3161 */ 3152 $multipliers = \apply_filters( 'exactdn_srcset_multipliers', array( .2, .4, .6, .8, 1 ) );3162 $multipliers = \apply_filters( 'exactdn_srcset_multipliers', array( .2, .4, .6, .8, 1, 450 ) ); 3153 3163 /** 3154 3164 * Filter the width ExactDN will use to create srcset attribute. … … 3175 3185 foreach ( $multipliers as $multiplier ) { 3176 3186 $newwidth = \intval( $width * $multiplier ); 3177 if ( 1920 === (int) $multiplier ) {3187 if ( $multiplier > 50 ) { // Not a true multiplier, but a hard-coded width. 3178 3188 if ( $multiplier >= $width ) { 3179 3189 continue; 3180 3190 } 3181 $newwidth = 1920;3191 $newwidth = $multiplier; 3182 3192 } 3183 3193 if ( $newwidth < 50 ) { … … 3569 3579 if ( $this->get_option( 'exactdn_hidpi' ) ) { 3570 3580 $this->debug_message( 'adding hidpi multipliers' ); 3571 return array( .2, .4, .6, .8, 1, 2, 3, 1920 ); 3581 $multipliers[] = 2; 3582 $multipliers[] = 3; 3583 $multipliers[] = 1920; 3572 3584 } 3573 3585 return $multipliers; … … 4317 4329 4318 4330 $more_args = array(); 4319 if ( false === \strpos( $image_url, 'strip=all' ) && $this->get_option( $this->prefix . 'metadata_remove' ) ) {4331 if ( ! \str_contains( $image_url, 'strip=all' ) && $this->get_option( $this->prefix . 'metadata_remove' ) ) { 4320 4332 $more_args['strip'] = 'all'; 4321 4333 } … … 4325 4337 } elseif ( isset( $args['lossy'] ) && false !== \strpos( $image_url, 'lossy=0' ) ) { 4326 4338 unset( $args['lossy'] ); 4327 } elseif ( false === \strpos( $image_url, 'lossy=' ) && ! $this->get_option( 'exactdn_lossy' ) ) {4328 $more_args['lossy'] = 0;4329 } elseif ( false === \strpos( $image_url, 'lossy=' ) && $this->get_option( 'exactdn_lossy' ) ) {4330 $more_args['lossy'] = \is_numeric( $this->get_option( 'exactdn_lossy' ) ) ? (int) $this->get_option( 'exactdn_lossy' ) : 1;4331 4339 } 4332 4340 if ( false === \strpos( $image_url, 'quality=' ) && ! \is_null( $jpg_quality ) && 82 !== (int) $jpg_quality ) { … … 4376 4384 4377 4385 if ( isset( $image_url_parts['scheme'] ) && 'https' === $image_url_parts['scheme'] ) { 4378 if ( \is_array( $args ) && false === \strpos( $image_url, 'ssl=' ) ) {4379 $this->debug_message( 'adding ssl=1' );4380 $args['ssl'] = 1;4381 }4382 4386 $this->debug_message( 'setting scheme to https' ); 4383 4387 $scheme = 'https'; … … 4397 4401 foreach ( $args as $arg => $value ) { 4398 4402 if ( \is_array( $value ) ) { 4399 $args[ $arg ] = \implode( ',', $value ); 4403 $value = \implode( ',', $value ); 4404 $args[ $arg ] = $value; 4400 4405 } 4401 4406 } … … 4566 4571 $url = \set_url_scheme( $url, 'https' ); 4567 4572 } 4568 \add_filter( 'http_headers_useragent', $this->prefix . 'cloud_useragent', PHP_INT_MAX );4573 \add_filter( 'http_headers_useragent', array( $this, 'api_useragent' ), PHP_INT_MAX ); 4569 4574 $result = \wp_remote_post( 4570 4575 $url, -
easy-image-optimizer/tags/4.3.0/classes/class-hs-beacon.php
r3035873 r3398277 101 101 return; 102 102 } 103 if ( \strpos( __FILE__, 'plugins/easy' ) ) { 104 \easyio_notice_beacon(); 105 } 103 \do_action( strtolower( __NAMESPACE__ ) . '_beacon_notice' ); 106 104 } 107 105 } -
easy-image-optimizer/tags/4.3.0/classes/class-lazy-load.php
r3328397 r3398277 96 96 97 97 /** 98 * A list of image tags/sections where lazy loading should not be applied. 99 * 100 * @access private 101 * @var array $forbidden_blocks 102 */ 103 private $forbidden_blocks = array(); 104 105 /** 98 106 * Request URI. 99 107 * … … 101 109 */ 102 110 public $request_uri = ''; 111 112 /** 113 * DOM Document for parsing HTML. 114 * 115 * @var \DOMDocument $doc 116 */ 117 private $doc; 118 119 /** 120 * List of img nodes from the DOMDocument. 121 * 122 * @var \DOMNodeList $img_nodes 123 */ 124 private $img_nodes; 103 125 104 126 /** … … 198 220 \add_action( 'wp_enqueue_scripts', array( $this, 'min_script' ), 1 ); 199 221 } 222 223 // Allow other plugins to get the background image exclusions via filter. 224 \add_filter( 'eio_get_lazy_bg_image_exclusions', array( $this, 'get_bgimage_exclusions' ), 10 ); 225 200 226 $this->inline_script_attrs = (array) \apply_filters( 'ewwwio_inline_script_attrs', $this->inline_script_attrs ); 201 227 $this->validate_user_exclusions(); … … 354 380 355 381 /** 382 * Check if an img/iframe tag should be excluded because it falls within a forbidden block. 383 * 384 * @param string $tag The img or iframe tag to check. 385 * @param int $position The position of the tag within the HTML. 386 * @return bool True if it is within a forbidden block, false otherwise. 387 */ 388 private function is_in_forbidden_block( $tag, $position ) { 389 if ( empty( $tag ) || empty( $position ) ) { 390 return false; 391 } 392 if ( $this->is_iterable( $this->forbidden_blocks ) ) { 393 foreach ( $this->forbidden_blocks as $forbidden_block ) { 394 if ( empty( $forbidden_block[0] ) || empty( $forbidden_block[1] ) ) { 395 continue; 396 } 397 $start = $forbidden_block[1]; 398 $end = $start + \strlen( $forbidden_block[0] ); 399 if ( $position > $start && $position < $end ) { 400 $this->debug_message( 'tag is within a forbidden block' ); 401 return true; 402 } 403 } 404 } 405 } 406 407 /** 356 408 * Search for img elements and rewrite them for Lazy Load with fallback to noscript elements. 357 409 * … … 391 443 } 392 444 445 $started_time = \microtime( true ); 393 446 $above_the_fold = (int) \apply_filters( 'eio_lazy_fold', $this->get_option( $this->prefix . 'll_abovethefold' ) ); 394 447 $images_processed = 0; 395 448 $replacements = array(); 396 449 397 // Clean the buffer of incompatible sections. 398 $search_buffer = \preg_replace( '/<div id="footer_photostream".*?\/div>/s', '', $buffer ); 399 $search_buffer = \preg_replace( '/<(picture|noscript|script).*?\/\1>/s', '', $search_buffer ); 400 401 $images = $this->get_images_from_html( $search_buffer, false ); 450 // Find all incompatible sections, and store them with their offsets. 451 $this->forbidden_blocks = array(); 452 \preg_match_all( '/<div id="footer_photostream".*?\/div>/s', $buffer, $forbidden_blocks, PREG_OFFSET_CAPTURE ); 453 \preg_match_all( '/<(picture|noscript|script).*?\/\1>/s', $buffer, $more_forbidden_blocks, PREG_OFFSET_CAPTURE ); 454 if ( ! empty( $forbidden_blocks[0] ) && ! empty( $more_forbidden_blocks[0] ) ) { 455 $forbidden_blocks[0] = \array_merge( $forbidden_blocks[0], $more_forbidden_blocks[0] ); 456 } elseif ( ! empty( $more_forbidden_blocks[0] ) ) { 457 $forbidden_blocks = $more_forbidden_blocks; 458 } 459 $this->forbidden_blocks = ! empty( $forbidden_blocks[0] ) ? $forbidden_blocks[0] : array(); 460 461 $this->doc = new \DOMDocument(); 462 libxml_use_internal_errors( true ); 463 $this->doc->loadHTML( $buffer ); 464 libxml_clear_errors(); 465 $this->img_nodes = $this->doc->getElementsByTagName( 'img' ); 466 467 $images = $this->get_images_from_html( $buffer, false, true, PREG_OFFSET_CAPTURE ); 402 468 if ( ! empty( $images[0] ) && $this->is_iterable( $images[0] ) ) { 403 469 foreach ( $images[0] as $index => $image ) { 404 $file = $images['img_url'][ $index ] ;470 $file = $images['img_url'][ $index ][0]; 405 471 $this->debug_message( "parsing an image: $file" ); 406 if ( $this->validate_image_tag( $image ) ) { 472 if ( empty( $image[0] ) || empty( $image[1] ) ) { 473 $this->debug_message( 'missing image tag or position' ); 474 continue; 475 } 476 $image_tag = $image[0]; 477 $position = $image[1]; 478 if ( $this->is_in_forbidden_block( $image_tag, $position ) ) { 479 continue; 480 } 481 if ( $this->validate_image_tag( $image_tag ) ) { 407 482 $this->debug_message( 'found a valid image tag' ); 408 $this->debug_message( "original image tag: $image " );409 $orig_img = $image;410 $ns_img = $image;411 $image = $this->parse_img_tag( $image, $file );483 $this->debug_message( "original image tag: $image_tag" ); 484 $orig_img = $image_tag; 485 $ns_img = $image_tag; 486 $image_tag = $this->parse_img_tag( $image_tag, $file ); 412 487 $this->set_attribute( $ns_img, 'data-eio', 'l', true ); 413 488 $noscript = '<noscript>' . $ns_img . '</noscript>'; 414 $position = \strpos( $buffer, $orig_img );415 if ( $position && $orig_img !== $image ) {489 if ( $position && $orig_img !== $image_tag ) { 490 $this->debug_message( "lazified image at position $position" ); 416 491 $replacements[ $position ] = array( 417 492 'orig' => $orig_img, 418 'lazy' => $image . $noscript,493 'lazy' => $image_tag . $noscript, 419 494 ); 420 495 } 421 /* $buffer = str_replace( $orig_img, $image . $noscript, $buffer ); */422 496 } 423 497 } // End foreach(). 424 498 } // End if(). 499 425 500 $element_types = \apply_filters( 'eio_allowed_background_image_elements', array( 'div', 'li', 'span', 'section', 'a' ) ); 426 501 foreach ( $element_types as $element_type ) { … … 435 510 } 436 511 } 512 437 513 if ( \in_array( 'picture', $this->user_element_exclusions, true ) ) { 438 514 $pictures = ''; 439 515 } else { 440 516 // Images listed as picture/source elements. Mostly for NextGEN, but should work anywhere. 441 $pictures = $this->get_picture_tags_from_html( $buffer );517 $pictures = $this->get_picture_tags_from_html( $buffer, PREG_OFFSET_CAPTURE ); 442 518 } 443 519 if ( $this->is_iterable( $pictures ) ) { 444 520 foreach ( $pictures as $index => $picture ) { 445 if ( ! $this->validate_image_tag( $picture ) ) { 446 continue; 447 } 448 $pimages = $this->get_images_from_html( $picture, false ); 521 if ( empty( $picture[0] ) || empty( $picture[1] ) ) { 522 $this->debug_message( 'missing picture tag or position' ); 523 continue; 524 } 525 $picture_tag = $picture[0]; 526 $position = $picture[1]; 527 if ( ! $this->validate_image_tag( $picture_tag ) ) { 528 continue; 529 } 530 $pimages = $this->get_images_from_html( $picture_tag, false ); 449 531 if ( ! empty( $pimages[0] ) && $this->is_iterable( $pimages[0] ) && ! empty( $pimages[0][0] ) ) { 450 532 $image = $pimages[0][0]; … … 458 540 $image = $this->parse_img_tag( $image, $file ); 459 541 $this->set_attribute( $ns_img, 'data-eio', 'l', true ); 460 $noscript = '<noscript>' . $ns_img . '</noscript>';461 $picture = \str_replace( $orig_img, $image, $picture) . $noscript;542 $noscript = '<noscript>' . $ns_img . '</noscript>'; 543 $picture_tag = \str_replace( $orig_img, $image, $picture_tag ) . $noscript; 462 544 } 463 545 } else { 464 546 continue; 465 547 } 466 $sources = $this->get_elements_from_html( $picture , 'source' );548 $sources = $this->get_elements_from_html( $picture_tag, 'source' ); 467 549 if ( $this->is_iterable( $sources ) ) { 468 550 foreach ( $sources as $source ) { … … 477 559 $this->set_attribute( $lazy_source, 'data-srcset', $srcset ); 478 560 $this->remove_attribute( $lazy_source, 'srcset' ); 479 $picture = \str_replace( $source, $lazy_source, $picture);561 $picture_tag = \str_replace( $source, $lazy_source, $picture_tag ); 480 562 } 481 563 } 482 $position = \strpos( $buffer, $pictures[ $index ] ); 483 if ( $position && $picture !== $pictures[ $index ] ) { 564 if ( $position && $picture_tag !== $pictures[ $index ][0] ) { 484 565 $this->debug_message( 'lazified sources for picture element' ); 485 566 $replacements[ $position ] = array( 486 'orig' => $pictures[ $index ] ,487 'lazy' => $picture ,567 'orig' => $pictures[ $index ][0], 568 'lazy' => $picture_tag, 488 569 ); 489 /* $buffer = str_replace( $pictures[ $index ], $picture, $buffer ); */490 }491 }492 }493 } 570 } 571 } 572 } 573 } 574 494 575 // Iframe elements, looking for stuff like YouTube embeds. 495 576 if ( \in_array( 'iframe', $this->user_element_exclusions, true ) ) { 496 577 $frames = ''; 497 578 } else { 498 $frames = $this->get_elements_from_html( $ search_buffer, 'iframe');579 $frames = $this->get_elements_from_html( $buffer, 'iframe', PREG_OFFSET_CAPTURE ); 499 580 } 500 581 if ( $this->is_iterable( $frames ) ) { 501 foreach ( $frames as $index => $frame ) { 582 foreach ( $frames as $index => $frame_data ) { 583 if ( empty( $frame_data[0] ) || empty( $frame_data[1] ) ) { 584 $this->debug_message( 'missing iframe tag or position' ); 585 continue; 586 } 502 587 $this->debug_message( 'parsing an iframe element' ); 588 $frame = $frame_data[0]; 589 $position = $frame_data[1]; 590 if ( $this->is_in_forbidden_block( $frame, $position ) ) { 591 continue; 592 } 503 593 $url = $this->get_attribute( $frame, 'src' ); 504 594 if ( $url && 0 === \strpos( $url, 'http' ) && $this->validate_iframe_tag( $frame ) ) { … … 507 597 $this->remove_attribute( $frame, 'src' ); 508 598 $this->set_attribute( $frame, 'class', \trim( $this->get_attribute( $frame, 'class' ) . ' lazyload' ), true ); 509 if ( $frame !== $frames[ $index ] ) { 510 $buffer = \str_replace( $frames[ $index ], $frame, $buffer ); 511 } 512 } 513 } 514 } 599 if ( $frame !== $frames[ $index ][0] ) { 600 $buffer = \str_replace( $frames[ $index ][0], $frame, $buffer ); 601 } 602 } 603 } 604 } 605 515 606 if ( $this->is_iterable( $replacements ) ) { 516 607 \ksort( $replacements ); … … 534 625 } 535 626 } 536 $this->debug_message( 'all done parsing page for lazy' ); 627 628 $elapsed_time = \microtime( true ) - $started_time; 629 $this->debug_message( "all done parsing page for lazy in $elapsed_time seconds" ); 537 630 return $buffer; 538 631 } … … 796 889 return $replacements; 797 890 } 798 $elements = $this->get_elements_from_html( \preg_replace( '/<(noscript|script).*?\/\1>/s', '', $buffer ), $tag_type);891 $elements = $this->get_elements_from_html( $buffer, $tag_type, PREG_OFFSET_CAPTURE ); 799 892 if ( $this->is_iterable( $elements ) ) { 800 foreach ( $elements as $index => $element ) { 893 foreach ( $elements as $index => $element_data ) { 894 if ( empty( $element_data[0] ) || empty( $element_data[1] ) ) { 895 $this->debug_message( 'missing element or position' ); 896 continue; 897 } 898 $element = $element_data[0]; 899 $position = $element_data[1]; 900 if ( $this->is_in_forbidden_block( $element, $position ) ) { 901 continue; 902 } 801 903 $this->debug_message( "parsing a $tag_type" ); 802 if ( false === \strpos( $element, 'background:' ) && false === \strpos( $element, 'background-image:' ) ) {904 if ( ! \str_contains( $element, 'background:' ) && ! \str_contains( $element, 'background-image:' ) ) { 803 905 $element = $this->lazify_element( $element ); 804 if ( $element !== $elements[ $index ] ) {906 if ( $element !== $elements[ $index ][0] ) { 805 907 $this->debug_message( "$tag_type lazified, replacing in html source" ); 806 $buffer = \str_replace( $elements[ $index ] , $element, $buffer );807 } 808 continue; 809 } 810 if ( false !== \strpos( $element, '--background' ) ) {908 $buffer = \str_replace( $elements[ $index ][0], $element, $buffer ); 909 } 910 continue; 911 } 912 if ( \str_contains( $element, '--background' ) ) { 811 913 $this->set_attribute( $element, 'class', $this->get_attribute( $element, 'class' ) . ' lazyload', true ); 812 if ( $element !== $elements[ $index ] ) {914 if ( $element !== $elements[ $index ][0] ) { 813 915 $this->debug_message( "$tag_type with bg var lazified, replacing in html source" ); 814 $buffer = \str_replace( $elements[ $index ] , $element, $buffer );916 $buffer = \str_replace( $elements[ $index ][0], $element, $buffer ); 815 917 } 816 918 continue; … … 853 955 } 854 956 } elseif ( ! empty( $bg_image_urls[0] ) ) { 957 list( $physical_width, $physical_height ) = $this->get_image_dimensions_by_url( $bg_image_urls[0] ); 958 $this->set_attribute( $element, 'data-back', $bg_image_urls[0] ); 959 if ( $physical_width && $physical_height ) { 960 $this->set_attribute( $element, 'data-eio-rwidth', $physical_width, true ); 961 $this->set_attribute( $element, 'data-eio-rheight', $physical_height, true ); 962 } 855 963 $webp_image_url = \apply_filters( 'eio_image_url_to_webp', $bg_image_urls[0] ); 856 $this->set_attribute( $element, 'data-back', $bg_image_urls[0] );857 964 if ( $webp_image_url && $webp_image_url !== $bg_image_urls[0] ) { 858 965 $this->set_attribute( $element, 'data-back-webp', $webp_image_url ); … … 862 969 } 863 970 } 864 $position = \strpos( $buffer, $elements[ $index ] ); 865 if ( $position && $element !== $elements[ $index ] ) { 971 if ( $position && $element !== $elements[ $index ][0] ) { 866 972 $this->debug_message( "$tag_type modified, replacing in html source" ); 867 973 $replacements[ $position ] = array( 868 'orig' => $elements[ $index ] ,974 'orig' => $elements[ $index ][0], 869 975 'lazy' => $element, 870 976 ); 871 /* $buffer = str_replace( $elements[ $index ], $element, $buffer ); */872 977 } 873 978 } … … 1018 1123 1019 1124 /** 1125 * Normalize HTML for comparison. 1126 * 1127 * @param string $html The HTML to normalize. 1128 * @return string The normalized HTML. 1129 */ 1130 public function normalize_html( $html ) { 1131 $html = str_replace( '&', '&', $html ); 1132 $html = str_replace( '&', '&', $html ); 1133 $html = str_replace( '%2C', ',', $html ); 1134 $html = str_replace( ' />', '>', $html ); 1135 $html = str_replace( "'", '"', $html ); 1136 $html = preg_replace( '/\s\s+/', ' ', $html ); 1137 $html = preg_replace( '/\s*=\s*/', '=', $html ); 1138 return $html; 1139 } 1140 1141 /** 1020 1142 * Checks if the tag is allowed to be lazy loaded. 1021 1143 * … … 1056 1178 } 1057 1179 } 1058 1180 // Check for exclusions. 1059 1181 $exclusions = \apply_filters( 1060 1182 'eio_lazy_exclusions', … … 1089 1211 ), 1090 1212 $this->user_exclusions 1091 ), 1092 $image 1213 ) 1093 1214 ); 1094 1215 foreach ( $exclusions as $exclusion ) { … … 1106 1227 } 1107 1228 } 1229 1230 foreach ( $this->img_nodes as $img_node ) { 1231 $img_html = $this->doc->saveHTML( $img_node ); 1232 if ( defined( 'EIO_IMGNODE_DEBUG' ) && EIO_IMGNODE_DEBUG ) { 1233 $this->debug_message( 'comparing to node value: ' . $this->normalize_html( $img_html ) . ' to ' . $this->normalize_html( $image ) ); 1234 } 1235 // Normalize the HTML before comparing to avoid issues with different quote styles or spacing. 1236 if ( $this->normalize_html( $img_html ) === $this->normalize_html( $image ) ) { 1237 $parent = $img_node->parentNode; 1238 if ( $parent && 'body' !== $parent->nodeName && $parent->hasAttributes() ) { 1239 $class = trim( $parent->getAttribute( 'class' ) ); 1240 $this->debug_message( "Parent class: $class" ); 1241 if ( str_contains( $class, 'skip-lazy' ) ) { 1242 $this->debug_message( "Skipping lazy load due to 'skip-lazy' class on parent" ); 1243 return false; 1244 } 1245 if ( $parent->hasAttribute( 'data-skip-lazy' ) ) { 1246 $this->debug_message( "Skipping lazy load due to 'data-skip-lazy' attribute on parent" ); 1247 return false; 1248 } 1249 } 1250 } 1251 } 1252 1108 1253 return true; 1109 1254 } 1110 1255 1111 1256 /** 1112 * Checks if a tag with a background image is allowed to be lazy loaded. 1113 * 1114 * @param string $tag The tag. 1115 * @return bool True if the tag is allowed, false otherwise. 1116 */ 1117 public function validate_bgimage_tag( $tag ) { 1118 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 1257 * Gets the exclusion list for lazy loading background images. 1258 * 1259 * @param array $exclusions The current list of exclusions. Optional. 1260 * @return array The modified list of exclusions. 1261 */ 1262 public function get_bgimage_exclusions( $exclusions = array() ) { 1263 if ( ! \is_array( $exclusions ) ) { 1264 $exclusions = array(); 1265 } 1119 1266 $exclusions = \apply_filters( 1120 1267 'eio_lazy_bg_image_exclusions', … … 1127 1274 'skip-lazy', 1128 1275 'avia-bg-style-fixed', 1276 'trustindex', 1277 ), 1278 $this->user_exclusions, 1279 $exclusions 1280 ) 1281 ); 1282 return $exclusions; 1283 } 1284 1285 /** 1286 * Checks if a tag with a background image is allowed to be lazy loaded. 1287 * 1288 * @param string $tag The tag. 1289 * @return bool True if the tag is allowed, false otherwise. 1290 */ 1291 public function validate_bgimage_tag( $tag ) { 1292 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 1293 $exclusions = $this->get_bgimage_exclusions( array() ); 1294 foreach ( $exclusions as $exclusion ) { 1295 if ( false !== \strpos( $tag, $exclusion ) ) { 1296 return false; 1297 } 1298 } 1299 return true; 1300 } 1301 1302 /** 1303 * Checks if an iframe tag is allowed to be lazy loaded. 1304 * 1305 * @param string $tag The tag. 1306 * @return bool True if the tag is allowed, false otherwise. 1307 */ 1308 public function validate_iframe_tag( $tag ) { 1309 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 1310 $exclusions = \apply_filters( 1311 'eio_lazy_iframe_exclusions', 1312 \array_merge( 1313 array( 1314 'about:blank', 1315 'data-no-lazy=', 1316 'display:none', 1317 'display: none', 1318 'googletagmanager', 1319 'lazyload', 1320 'skip-lazy', 1321 'wprus/', 1322 'vimeo', 1129 1323 ), 1130 1324 $this->user_exclusions … … 1141 1335 1142 1336 /** 1143 * Checks if an iframe tag is allowed to be lazy loaded.1144 *1145 * @param string $tag The tag.1146 * @return bool True if the tag is allowed, false otherwise.1147 */1148 public function validate_iframe_tag( $tag ) {1149 $this->debug_message( '<b>' . __METHOD__ . '()</b>' );1150 $exclusions = \apply_filters(1151 'eio_lazy_iframe_exclusions',1152 \array_merge(1153 array(1154 'data-no-lazy=',1155 'lazyload',1156 'skip-lazy',1157 'vimeo',1158 'about:blank',1159 'googletagmanager',1160 ),1161 $this->user_exclusions1162 ),1163 $tag1164 );1165 foreach ( $exclusions as $exclusion ) {1166 if ( false !== \strpos( $tag, $exclusion ) ) {1167 return false;1168 }1169 }1170 return true;1171 }1172 1173 /**1174 1337 * Build a PNG inline image placeholder. 1175 1338 * … … 1211 1374 return $exactdn->generate_url( $this->content_url . 'lazy/placeholder-' . $width . 'x' . $height . '.png' ); 1212 1375 } elseif ( ! is_file( $piip_path ) ) { 1213 // First try PIP generation via Imagick, as it is pretty efficient. 1214 if ( $this->imagick_support() ) { 1215 $placeholder = new \Imagick(); 1216 $placeholder->newimage( $width, $height, 'transparent' ); 1217 $placeholder->setimageformat( 'PNG' ); 1218 $placeholder->stripimage(); 1219 $placeholder->writeimage( $piip_path ); 1220 $placeholder->clear(); 1376 // First, try GD and then optimize it with optipng/pngout if available. 1377 // This is now the first attempt, as the Imagick placeholders are grayscale and may not work in Safari, and GD is somehow faster. 1378 if ( 1379 $this->gd_support() && 1380 $this->check_memory_available( $width * $height * 4.8 ) // 4.8 = 24-bit or 3 bytes per pixel multiplied by a factor of 1.6 for extra wiggle room. 1381 ) { 1382 $img = \imagecreatetruecolor( $width, $height ); 1383 $color = \imagecolorallocatealpha( $img, 0, 0, 0, 127 ); 1384 \imagefill( $img, 0, 0, $color ); 1385 \imagesavealpha( $img, true ); 1386 \imagecolortransparent( $img, \imagecolorat( $img, 0, 0 ) ); 1387 \imagetruecolortopalette( $img, false, 1 ); 1388 \imagepng( $img, $piip_path, 9 ); 1389 if ( 1390 \function_exists( '\ewww_image_optimizer' ) && 1391 \function_exists( '\ewwwio' ) && 1392 ! \ewwwio()->get_option( 'ewww_image_optimizer_cloud_key' ) && 1393 \ewwwio()->local->exec_check() 1394 ) { 1395 \ewww_image_optimizer( $piip_path ); 1396 } 1221 1397 } 1222 1398 // If that didn't work, and we have a premium service, use the API to generate the slimmest PIP available. … … 1234 1410 } 1235 1411 } 1236 // Last shot, use GD and then optimize it with optipng/pngout if available.1412 // Last resort, do PIP generation via Imagick, as it is pretty efficient even though Safari doesn't like the grayscale images it produces. 1237 1413 if ( 1238 1414 ! \is_file( $piip_path ) && 1239 $this->gd_support() && 1240 $this->check_memory_available( $width * $height * 4.8 ) // 4.8 = 24-bit or 3 bytes per pixel multiplied by a factor of 1.6 for extra wiggle room. 1415 $this->imagick_support() 1241 1416 ) { 1242 $img = \imagecreatetruecolor( $width, $height ); 1243 $color = \imagecolorallocatealpha( $img, 0, 0, 0, 127 ); 1244 \imagefill( $img, 0, 0, $color ); 1245 \imagesavealpha( $img, true ); 1246 \imagecolortransparent( $img, \imagecolorat( $img, 0, 0 ) ); 1247 \imagetruecolortopalette( $img, false, 1 ); 1248 \imagepng( $img, $piip_path, 9 ); 1249 if ( \function_exists( '\ewww_image_optimizer' ) ) { 1250 \ewww_image_optimizer( $piip_path ); 1251 } 1417 $placeholder = new \Imagick(); 1418 $placeholder->newimage( $width, $height, 'transparent' ); 1419 $placeholder->setimageformat( 'PNG' ); 1420 $placeholder->stripimage(); 1421 $placeholder->writeimage( $piip_path ); 1422 $placeholder->clear(); 1252 1423 } 1253 1424 } … … 1382 1553 'exactdn_domain' => ( $this->parsing_exactdn ? $this->exactdn_domain : '' ), 1383 1554 'skip_autoscale' => ( \defined( 'EIO_LL_AUTOSCALE' ) && ! EIO_LL_AUTOSCALE ? 1 : 0 ), 1555 'bg_min_dpr' => ( \defined( 'EIO_LL_BG_MIN_DPR' ) && EIO_LL_BG_MIN_DPR ? EIO_LL_BG_MIN_DPR : 1.1 ), 1384 1556 'threshold' => (int) $threshold > 50 ? (int) $threshold : 0, 1385 1557 'use_dpr' => (int) $this->get_option( 'exactdn_hidpi' ), … … 1423 1595 'exactdn_domain' => ( $this->parsing_exactdn ? $this->exactdn_domain : '' ), 1424 1596 'skip_autoscale' => ( \defined( 'EIO_LL_AUTOSCALE' ) && ! EIO_LL_AUTOSCALE ? 1 : 0 ), 1597 'bg_min_dpr' => ( \defined( 'EIO_LL_BG_MIN_DPR' ) && EIO_LL_BG_MIN_DPR ? EIO_LL_BG_MIN_DPR : 1.1 ), 1425 1598 'threshold' => (int) $threshold > 50 ? (int) $threshold : 0, 1426 1599 'use_dpr' => (int) $this->get_option( 'exactdn_hidpi' ), -
easy-image-optimizer/tags/4.3.0/classes/class-page-parser.php
r3328397 r3398277 57 57 * @param bool $hyperlinks Default true. Should we include encasing hyperlinks in our search. 58 58 * @param bool $src_required Default true. Should we look only for images with src attributes. 59 * @param int $flags Optional. Flags passed to preg_match_all. Default 0. 59 60 * @return array An array of $images matches, where $images[0] is 60 61 * an array of full matches, and the link_url, img_tag, 61 62 * and img_url keys are arrays of those matches. 62 63 */ 63 public function get_images_from_html( $content, $hyperlinks = true, $src_required = true ) {64 public function get_images_from_html( $content, $hyperlinks = true, $src_required = true, $flags = 0 ) { 64 65 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 65 66 $images = array(); … … 80 81 $unquoted_pattern = '#(?P<img_tag><img[^>]*?\s+?src\s*=\s*(?P<img_url>[^"\'\\\\<>][^\s\\\\<>]+)(?:\s[^>]*?)?>)#is'; 81 82 } 82 if ( \preg_match_all( $search_pattern, $content, $images ) ) {83 if ( \preg_match_all( $search_pattern, $content, $images, $flags ) ) { 83 84 $this->debug_message( 'found ' . \count( $images[0] ) . ' image elements with quoted pattern' ); 84 85 foreach ( $images as $key => $unused ) { … … 91 92 } 92 93 $images = \array_filter( $images ); 93 if ( $unquoted_pattern && \preg_match_all( $unquoted_pattern, $content, $unquoted_images ) ) {94 if ( $unquoted_pattern && \preg_match_all( $unquoted_pattern, $content, $unquoted_images, $flags ) ) { 94 95 $this->debug_message( 'found ' . \count( $unquoted_images[0] ) . ' image elements with unquoted pattern' ); 95 96 foreach ( $unquoted_images as $key => $unused ) { … … 147 148 * 148 149 * @param string $content Some HTML. 150 * @param int $flags Optional. Flags passed to preg_match_all. Default 0. 149 151 * @return array An array of $pictures matches, containing full elements with ending tags. 150 152 */ 151 public function get_picture_tags_from_html( $content ) {153 public function get_picture_tags_from_html( $content, $flags = 0 ) { 152 154 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 153 155 $pictures = array(); 154 if ( ! empty( $content ) && \preg_match_all( '#(?:<picture[^>]*?>\s*)(?:<source[^>]*?>)+(?:.*?</picture>)?#is', $content, $pictures ) ) {156 if ( ! empty( $content ) && \preg_match_all( '#(?:<picture[^>]*?>\s*)(?:<source[^>]*?>)+(?:.*?</picture>)?#is', $content, $pictures, $flags ) ) { 155 157 return $pictures[0]; 156 158 } … … 212 214 * @param string $content Some HTML. 213 215 * @param string $tag_name The name of the elements to retrieve. 216 * @param int $flags Optional. Flags passed to preg_match_all. Default 0. 214 217 * @return array An array of $elements. 215 218 */ 216 public function get_elements_from_html( $content, $tag_name ) {217 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 218 if ( ! \ctype_alpha( str_replace( '-', '', $tag_name ) ) ) {219 public function get_elements_from_html( $content, $tag_name, $flags = 0 ) { 220 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 221 if ( ! \ctype_alpha( \str_replace( '-', '', $tag_name ) ) ) { 219 222 return array(); 220 223 } 221 if ( ! empty( $content ) && \preg_match_all( '#<' . $tag_name . '\s[^\\\\>]+?>#is', $content, $elements ) ) {224 if ( ! empty( $content ) && \preg_match_all( '#<' . $tag_name . '\s[^\\\\>]+?>#is', $content, $elements, $flags ) ) { 222 225 return $elements[0]; 223 226 } -
easy-image-optimizer/tags/4.3.0/classes/class-plugin.php
r3197623 r3398277 28 28 29 29 /** 30 * Buffer object. 31 * 32 * @var object|\EasyIO\Buffer $buffer 33 */ 34 public $buffer; 35 36 /** 37 * Lazy Load object. 38 * 39 * @var object|\EasyIO\Lazy_Load $lazy_load 40 */ 41 public $lazy_load; 42 43 /** 30 44 * Helpscout Beacon object. 31 45 * … … 33 47 */ 34 48 public $hs_beacon; 49 50 /** 51 * Settings object. 52 * 53 * @var object|\EasyIO\Settings $settings 54 */ 55 public $settings; 35 56 36 57 /** … … 50 71 self::$instance->requires(); 51 72 self::$instance->load_children(); 73 74 if ( ! self::$instance->php_supported() ) { 75 return self::$instance; 76 } 77 if ( ! self::$instance->wp_supported() ) { 78 return self::$instance; 79 } 80 81 // Load plugin components that need to be available early. 82 \add_action( 'plugins_loaded', array( self::$instance, 'plugins_loaded' ) ); 83 // Setup page parsing, if parsers are enabled. 84 \add_action( 'init', array( self::$instance, 'parser_init' ), 99 ); 52 85 // Initializes the plugin for admin interactions, like saving network settings and scheduling cron jobs. 53 86 \add_action( 'admin_init', array( self::$instance, 'admin_init' ) ); 54 87 55 // TODO: check PHP and WP compat here. 56 // TODO: setup anything that needs to run on init/plugins_loaded. 57 // TODO: add any custom option/setting hooks here (actions that need to be taken when certain settings are saved/updated). 88 // Filters to set default permissions, admins can override these if they wish. 89 \add_filter( 'easyio_admin_permissions', array( self::$instance, 'admin_permissions' ), 8 ); 90 \add_filter( 'easyio_superadmin_permissions', array( self::$instance, 'superadmin_permissions' ), 8 ); 91 92 // Add Easy IO version to useragent for API requests. 93 \add_filter( 'exactdn_api_request_useragent', array( self::$instance, 'api_useragent' ) ); 94 // Check the current screen ID to see if temp debugging should still be enabled. 95 \add_action( 'current_screen', array( self::$instance, 'current_screen' ), 10, 1 ); 96 // Disable core WebP generation since we already do that. 97 \add_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 98 // Makes sure we flush the debug info to the log on shutdown. 99 \add_action( 'shutdown', array( self::$instance, 'debug_log' ) ); 58 100 } 59 101 … … 86 128 */ 87 129 private function requires() { 130 // Sets up the settings page and various option-related hooks/functions. 131 require_once EASYIO_PLUGIN_PATH . 'classes/class-settings.php'; 132 // Starts the HTML buffer for all other functions to parse. 133 require_once EASYIO_PLUGIN_PATH . 'classes/class-buffer.php'; 134 // Page Parsing class for working with HTML content. 135 require_once EASYIO_PLUGIN_PATH . 'classes/class-page-parser.php'; 136 // Lazy Load class for parsing image urls and deferring off-screen images. 137 require_once EASYIO_PLUGIN_PATH . 'classes/class-lazy-load.php'; 88 138 // EasyIO\HS_Beacon class for integrated help/docs. 89 139 require_once EASYIO_PLUGIN_PATH . 'classes/class-hs-beacon.php'; … … 94 144 */ 95 145 public function load_children() { 96 /* self::$instance->class = new Class(); */ 146 self::$instance->settings = new Settings(); 147 } 148 149 /** 150 * Make sure we are on a supported version of PHP. 151 * 152 * @access private 153 */ 154 private function php_supported() { 155 if ( defined( 'PHP_VERSION_ID' ) && PHP_VERSION_ID >= 80100 ) { 156 return true; 157 } 158 \add_action( 'network_admin_notices', array( self::$instance, 'unsupported_php_notice' ) ); 159 \add_action( 'admin_notices', array( self::$instance, 'unsupported_php_notice' ) ); 160 return false; 161 } 162 163 /** 164 * Make sure we are on a supported version of WordPress. 165 * 166 * @access private 167 */ 168 private function wp_supported() { 169 global $wp_version; 170 if ( \version_compare( $wp_version, '6.6' ) >= 0 ) { 171 return true; 172 } 173 \add_action( 'network_admin_notices', array( self::$instance, 'unsupported_wp_notice' ) ); 174 \add_action( 'admin_notices', array( self::$instance, 'unsupported_wp_notice' ) ); 175 return false; 176 } 177 178 /** 179 * Display a notice that the PHP version is too old. 180 */ 181 public function unsupported_php_notice() { 182 echo '<div id="easyio-warning-php" class="error"><p><a href="https://docs.ewww.io/article/55-upgrading-php" target="_blank" data-beacon-article="5ab2baa6042863478ea7c2ae">' . esc_html__( 'Easy Image Optimizer requires PHP 8.1 or greater. Newer versions of PHP are faster and more secure. If you are unsure how to upgrade to a supported version, ask your webhost for instructions.', 'easy-image-optimizer' ) . '</a></p></div>'; 183 } 184 185 /** 186 * Display a notice that the WP version is too old. 187 */ 188 public function unsupported_wp_notice() { 189 echo '<div id="swis-warning-wp" class="notice notice-error"><p>' . esc_html__( 'Easy Image Optimizer requires WordPress 6.6 or greater, please update your website.', 'easy-image-optimizer' ) . '</p></div>'; 190 } 191 192 /** 193 * Run things that need to go early, on plugins_loaded. 194 */ 195 public function plugins_loaded() { 196 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 197 198 if ( $this->get_option( 'easyio_lazy_load' ) && $this->get_option( 'easyio_ll_external_bg' ) ) { 199 $this->debug_message( 'requesting external parsing of CSS for background images via SWIS' ); 200 add_filter( 'eio_lazify_external_css', '__return_true' ); 201 } 202 } 203 204 /** 205 * Setup page parsing classes after theme functions.php is loaded and plugins have run init routines. 206 */ 207 public function parser_init() { 208 $buffer_start = false; 209 // If ExactDN is enabled. 210 if ( $this->get_option( 'easyio_exactdn' ) && ! \str_contains( \add_query_arg( '', '' ), 'exactdn_disable=1' ) ) { 211 $buffer_start = true; 212 213 // ExactDN class for parsing image urls and rewriting them. 214 require_once EASYIO_PLUGIN_PATH . 'classes/class-exactdn.php'; 215 } 216 // If Lazy Load is enabled. 217 if ( $this->get_option( 'easyio_lazy_load' ) ) { 218 $buffer_start = true; 219 220 $this->lazy_load = new Lazy_Load(); 221 } 222 if ( $buffer_start ) { 223 // Start an output buffer before any output starts. 224 $this->buffer = new Buffer(); 225 } 97 226 } 98 227 … … 102 231 public function admin_init() { 103 232 $this->hs_beacon = new HS_Beacon(); 104 \easyio_upgrade();105 $this->register_settings();106 233 107 234 if ( ! \class_exists( __NAMESPACE__ . '\ExactDN' ) || ! $this->get_option( 'easyio_exactdn' ) ) { 108 add_action( 'network_admin_notices', 'easyio_notice_inactive' ); 109 add_action( 'admin_notices', 'easyio_notice_inactive' ); 110 } 235 \add_action( 'network_admin_notices', array( $this, 'service_inactive_notice' ) ); 236 \add_action( 'admin_notices', array( $this, 'service_inactive_notice' ) ); 237 } 238 239 \add_action( 'exactdn_as3cf_cname_active', array( $this, 'exactdn_as3cf_cname_active_notice' ) ); 240 \add_action( 'exactdn_domain_mismatch', array( $this, 'exactdn_domain_mismatch_notice' ) ); 241 242 \add_action( 'easyio_beacon_notice', array( $this, 'hs_beacon_notice' ) ); 243 111 244 // Prevent ShortPixel AIO messiness. 112 245 \remove_action( 'admin_notices', 'autoptimizeMain::notice_plug_imgopt' ); … … 117 250 $ao_extra['autoptimize_imgopt_checkbox_field_1'] = 0; 118 251 \update_option( 'autoptimize_imgopt_settings', $ao_extra ); 119 \add_action( 'admin_notices', 'easyio_notice_sp_conflict');252 \add_action( 'admin_notices', array( $this, 'sp_conflict_notice' ) ); 120 253 } 121 254 } … … 124 257 if ( $this->get_option( 'easyio_exactdn' ) && \HMWP_Classes_Tools::getOption( 'hmwp_hide_version' ) && ! \HMWP_Classes_Tools::getOption( 'hmwp_hide_version_random' ) ) { 125 258 $this->debug_message( 'detected HMWP Hide Version' ); 126 \add_action( 'admin_notices', array( $this, ' notice_hmwp_hide_version' ) );259 \add_action( 'admin_notices', array( $this, 'hmwp_hide_version_notice' ) ); 127 260 } 128 261 } 129 262 130 if ( ! \defined( '\WP_CLI' ) || ! WP_CLI ) { 131 \easyio_privacy_policy_content(); 132 } 133 } 134 135 /** 136 * Save the multi-site settings, if this is the WP admin, and they've been POSTed. 137 */ 138 public function save_network_settings() { 139 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 140 // NOTE: we don't actually have a network settings screen, so... 141 if ( ! \function_exists( 'is_plugin_active_for_network' ) && \is_multisite() ) { 142 // Need to include the plugin library for the is_plugin_active function. 143 require_once ABSPATH . 'wp-admin/includes/plugin.php'; 144 } 145 // Set the common network settings if they have been POSTed. 146 if ( 147 \is_multisite() && 148 \is_plugin_active_for_network( EASYIO_PLUGIN_FILE_REL ) && 149 ! empty( $_REQUEST['_wpnonce'] ) && 150 isset( $_POST['option_page'] ) && 151 false !== \strpos( sanitize_text_field( wp_unslash( $_POST['option_page'] ) ), 'easyio_options' ) && 152 \wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'easyio_options-options' ) && 153 \current_user_can( 'manage_network_options' ) && 154 ! \get_site_option( 'easyio_allow_multisite_override' ) && 155 false === \strpos( wp_get_referer(), 'options-general' ) 156 ) { 157 $this->debug_message( 'network-wide settings, no override' ); 158 $easyio_debug = ( empty( $_POST['easyio_debug'] ) ? false : true ); 159 \update_site_option( 'easyio_debug', $easyio_debug ); 160 $easyio_metadata_remove = ( empty( $_POST['easyio_metadata_remove'] ) ? false : true ); 161 \update_site_option( 'easyio_metadata_remove', $easyio_metadata_remove ); 162 $exactdn_all_the_things = ( empty( $_POST['exactdn_all_the_things'] ) ? false : true ); 163 \update_site_option( 'exactdn_all_the_things', $exactdn_all_the_things ); 164 $exactdn_lossy = ( empty( $_POST['exactdn_lossy'] ) ? false : true ); 165 \update_site_option( 'exactdn_lossy', $exactdn_lossy ); 166 $exactdn_hidpi = ( empty( $_POST['exactdn_hidpi'] ) ? false : true ); 167 \update_site_option( 'exactdn_hidpi', $exactdn_hidpi ); 168 $exactdn_exclude = empty( $_POST['exactdn_exclude'] ) ? '' : sanitize_textarea_field( wp_unslash( $_POST['exactdn_exclude'] ) ); 169 \update_site_option( 'exactdn_exclude', $this->exclude_paths_sanitize( $exactdn_exclude ) ); 170 $easyio_add_missing_dims = ( empty( $_POST['easyio_add_missing_dims'] ) ? false : true ); 171 \update_site_option( 'easyio_add_missing_dims', $easyio_add_missing_dims ); 172 $easyio_lazy_load = ( empty( $_POST['easyio_lazy_load'] ) ? false : true ); 173 \update_site_option( 'easyio_lazy_load', $easyio_lazy_load ); 174 $easyio_ll_autoscale = ( empty( $_POST['easyio_ll_autoscale'] ) ? false : true ); 175 \update_site_option( 'easyio_ll_autoscale', $easyio_ll_autoscale ); 176 $easyio_ll_abovethefold = ! empty( $_POST['easyio_ll_abovethefold'] ) ? (int) $_POST['easyio_ll_abovethefold'] : 0; 177 \update_site_option( 'easyio_ll_abovethefold', $easyio_ll_abovethefold ); 178 $easyio_use_lqip = ( empty( $_POST['easyio_use_lqip'] ) ? false : true ); 179 \update_site_option( 'easyio_use_lqip', $easyio_use_lqip ); 180 $easyio_use_dcip = ( empty( $_POST['easyio_use_dcip'] ) ? false : true ); 181 \update_site_option( 'easyio_use_dcip', $easyio_use_dcip ); 182 $easyio_ll_exclude = empty( $_POST['easyio_ll_exclude'] ) ? '' : sanitize_textarea_field( wp_unslash( $_POST['easyio_ll_exclude'] ) ); 183 \update_site_option( 'easyio_ll_exclude', $this->exclude_paths_sanitize( $easyio_ll_exclude ) ); 184 $easyio_ll_all_things = empty( $_POST['easyio_ll_all_things'] ) ? '' : sanitize_textarea_field( wp_unslash( $_POST['easyio_ll_all_things'] ) ); 185 \update_site_option( 'easyio_ll_all_things', $easyio_ll_all_things ); 186 $easyio_allow_multisite_override = empty( $_POST['easyio_allow_multisite_override'] ) ? false : true; 187 \update_site_option( 'easyio_allow_multisite_override', $easyio_allow_multisite_override ); 188 $easyio_enable_help = empty( $_POST['easyio_enable_help'] ) ? false : true; 189 \update_site_option( 'easyio_enable_help', $easyio_enable_help ); 190 \add_action( 'network_admin_notices', 'easyio_network_settings_saved' ); 191 } elseif ( isset( $_POST['easyio_allow_multisite_override_active'] ) && \current_user_can( 'manage_network_options' ) && ! empty( $_REQUEST['_wpnonce'] ) && \wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'easyio_options-options' ) ) { 192 $this->debug_message( 'network-wide settings, single-site overriding' ); 193 $easyio_allow_multisite_override = empty( $_POST['easyio_allow_multisite_override'] ) ? false : true; 194 \update_site_option( 'easyio_allow_multisite_override', $easyio_allow_multisite_override ); 195 \add_action( 'network_admin_notices', 'easyio_network_settings_saved' ); 196 } // End if(). 197 } 198 199 /** 200 * Register all our options and sanitation functions. 201 */ 202 public function register_settings() { 203 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 204 // Register all the common Easy IO settings. 205 \register_setting( 'easyio_options', 'easyio_debug', 'boolval' ); 206 \register_setting( 'easyio_options', 'easyio_enable_help', 'boolval' ); 207 \register_setting( 'easyio_options', 'exactdn_all_the_things', 'boolval' ); 208 \register_setting( 'easyio_options', 'exactdn_lossy', 'boolval' ); 209 \register_setting( 'easyio_options', 'exactdn_hidpi', 'boolval' ); 210 \register_setting( 'easyio_options', 'exactdn_exclude', array( $this, 'exclude_paths_sanitize' ) ); 211 \register_setting( 'easyio_options', 'easyio_add_missing_dims', 'boolval' ); 212 \register_setting( 'easyio_options', 'easyio_lazy_load', 'boolval' ); 213 \register_setting( 'easyio_options', 'easyio_ll_abovethefold', 'intval' ); 214 \register_setting( 'easyio_options', 'easyio_use_lqip', 'boolval' ); 215 \register_setting( 'easyio_options', 'easyio_use_dcip', 'boolval' ); 216 \register_setting( 'easyio_options', 'easyio_ll_exclude', array( $this, 'exclude_paths_sanitize' ) ); 217 \register_setting( 'easyio_options', 'easyio_ll_all_things', 'sanitize_textarea_field' ); 218 } 219 220 /** 221 * Set some default option values. 222 */ 223 public function set_defaults() { 224 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 225 // Set defaults for all options that need to be autoloaded. 226 \add_option( 'easyio_debug', false ); 227 \add_option( 'easyio_metadata_remove', true ); 228 \add_option( 'easyio_exactdn', false ); 229 \add_option( 'easyio_plan_id', 0 ); 230 \add_option( 'exactdn_all_the_things', false ); 231 \add_option( 'exactdn_lossy', false ); 232 \add_option( 'exactdn_hidpi', false ); 233 \add_option( 'exactdn_exclude', '' ); 234 \add_option( 'exactdn_sub_folder', false ); 235 \add_option( 'exactdn_prevent_db_queries', true ); 236 \add_option( 'exactdn_asset_domains', '' ); 237 \add_option( 'easyio_add_missing_dims', false ); 238 \add_option( 'easyio_lazy_load', false ); 239 \add_option( 'easyio_use_lqip', false ); 240 \add_option( 'easyio_use_dcip', false ); 241 \add_option( 'easyio_use_siip', false ); 242 \add_option( 'easyio_ll_autoscale', true ); 243 \add_option( 'easyio_ll_abovethefold', 0 ); 244 \add_option( 'easyio_ll_exclude', '' ); 245 \add_option( 'easyio_ll_all_things', '' ); 246 247 // Set network defaults. 248 \add_site_option( 'easyio_metadata_remove', true ); 249 \add_site_option( 'easyio_add_missing_dims', true ); 250 \add_site_option( 'easyio_ll_autoscale', true ); 251 \add_site_option( 'exactdn_sub_folder', false ); 252 \add_site_option( 'exactdn_prevent_db_queries', true ); 263 if ( ! \defined( 'WP_CLI' ) || ! WP_CLI ) { 264 $this->privacy_policy_content(); 265 } 266 } 267 268 /** 269 * Adds the Easy IO version to the useragent for http requests. 270 * 271 * @param string $useragent The current useragent used in http requests. 272 * @return string The useragent with the Easy IO version appended. 273 */ 274 public function api_useragent( $useragent ) { 275 if ( ! \str_contains( $useragent, 'EIO' ) ) { 276 $useragent .= ' EIO/' . EASYIO_VERSION . ' '; 277 } 278 return $useragent; 279 } 280 281 /** 282 * Adds suggested privacy policy content for site admins. 283 * 284 * Note that this is just a suggestion, it should be customized for your site. 285 */ 286 private function privacy_policy_content() { 287 if ( ! \function_exists( 'wp_add_privacy_policy_content' ) || ! \function_exists( 'wp_kses_post' ) ) { 288 return; 289 } 290 $content = '<p class="privacy-policy-tutorial">'; 291 $content .= \wp_kses_post( \__( 'Normally, this plugin does not process any information about your visitors. However, if you accept user-submitted images and display them on your site, you can use this language to keep your visitors informed.', 'easy-image-optimizer' ) ) . '</p>'; 292 $content .= '<p>' . \wp_kses_post( \__( 'User-submitted images that are displayed on this site will be transmitted and stored on a global network of third-party servers (a CDN).', 'easy-image-optimizer' ) ) . '</p>'; 293 \wp_add_privacy_policy_content( 'Easy Image Optimizer', $content ); 294 } 295 296 /** 297 * Set default permissions for admin (configuration) and bulk operations. 298 * 299 * @param string $permissions A valid WP capability level. 300 * @return string Either the original value, unchanged, or the default capability level. 301 */ 302 public function admin_permissions( $permissions ) { 303 if ( empty( $permissions ) ) { 304 return 'activate_plugins'; 305 } 306 return $permissions; 307 } 308 309 /** 310 * Set default permissions for multisite/network admin (configuration) operations. 311 * 312 * @param string $permissions A valid WP capability level. 313 * @return string Either the original value, unchanged, or the default capability level. 314 */ 315 public function superadmin_permissions( $permissions ) { 316 if ( empty( $permissions ) ) { 317 return 'manage_network_options'; 318 } 319 return $permissions; 320 } 321 322 /** 323 * Check the current screen, used to temporarily enable debugging on settings page. 324 * 325 * @param object $screen Information about the page/screen currently being loaded. 326 */ 327 public function current_screen( $screen ) { 328 if ( $this->get_option( 'easyio_debug' ) ) { 329 return; 330 } 331 if ( \str_contains( $screen->id, 'settings_page_easy-image-optimizer' ) ) { 332 return; 333 } 334 // Otherwise, we are somewhere else and should disable temp debugging. 335 Base::$debug_data = ''; 336 Base::$temp_debug = false; 337 } 338 339 /** 340 * Let the user know they need to take action! 341 */ 342 public function service_inactive_notice() { 343 ?> 344 <div id='easyio-inactive' class='notice notice-warning'> 345 <p> 346 <a href="<?php echo \esc_url( \admin_url( 'options-general.php?page=easy-image-optimizer-options' ) ); ?>"> 347 <?php \esc_html_e( 'Please visit the settings page to complete activation of the Easy Image Optimizer.', 'easy-image-optimizer' ); ?> 348 </a> 349 </p> 350 </div> 351 <?php 352 } 353 354 /** 355 * Let the user know they need to disable the WP Offload Media CNAME. 356 */ 357 public function exactdn_as3cf_cname_active_notice() { 358 ?> 359 <div id="easyio-notice-exactdn-as3cf-cname-active" class="notice notice-error"> 360 <p> 361 <?php \esc_html_e( 'Easy IO cannot optimize your images while using a custom domain (CNAME) in WP Offload Media. Please disable the custom domain in the WP Offload Media settings.', 'easy-image-optimizer' ); ?> 362 </p> 363 </div> 364 <?php 365 } 366 367 /** 368 * Let the user know the local domain appears to have changed from what Easy IO has recorded in the db. 369 */ 370 public function exactdn_domain_mismatch_notice() { 371 global $exactdn; 372 if ( ! isset( $exactdn->upload_domain ) ) { 373 return; 374 } 375 $stored_local_domain = $this->get_option( 'easyio_exactdn_local_domain' ); 376 if ( empty( $stored_local_domain ) ) { 377 return; 378 } 379 if ( ! \str_contains( $stored_local_domain, '.' ) ) { 380 $stored_local_domain = \base64_decode( $stored_local_domain ); 381 } 382 ?> 383 <div id="easyio-notice-exactdn-domain-mismatch" class="notice notice-warning"> 384 <p> 385 <?php 386 \printf( 387 /* translators: 1: old domain name, 2: current domain name */ 388 \esc_html__( 'Easy IO detected that the Site URL has changed since the initial activation (previously %1$s, currently %2$s).', 'easy-image-optimizer' ), 389 '<strong>' . \esc_html( $stored_local_domain ) . '</strong>', 390 '<strong>' . \esc_html( $exactdn->upload_domain ) . '</strong>' 391 ); 392 ?> 393 <br> 394 <?php 395 \printf( 396 /* translators: %s: settings page */ 397 \esc_html__( 'Please visit the %s to refresh the Easy IO settings and verify activation status.', 'easy-image-optimizer' ), 398 '<a href="' . \esc_url( \admin_url( 'options-general.php?page=easy-image-optimizer-options' ) ) . '">' . \esc_html__( 'settings page', 'easy-image-optimizer' ) . '</a>' 399 ); 400 ?> 401 </p> 402 </div> 403 <?php 404 } 405 406 /** 407 * Inform the user of our beacon function so that they can opt-in. 408 */ 409 public function hs_beacon_notice() { 410 $optin_url = \wp_nonce_url( 'admin.php?action=eio_opt_into_hs_beacon', 'eio_beacon' ); 411 $optout_url = \wp_nonce_url( 'admin.php?action=eio_opt_out_of_hs_beacon', 'eio_beacon' ); 412 ?> 413 <div id="easyio-hs-beacon" class="notice notice-info"> 414 <p> 415 <?php \esc_html_e( 'Enable the Easy IO support beacon, which gives you access to documentation and our support team right from your WordPress dashboard. To assist you more efficiently, we collect the current url, IP address, browser/device information, and debugging information.', 'easy-image-optimizer' ); ?><br> 416 <a href="<?php echo \esc_url( $optin_url ); ?>" class="button-secondary"><?php esc_html_e( 'Allow', 'easy-image-optimizer' ); ?></a> 417 <a href="<?php echo \esc_url( $optout_url ); ?>" class="button-secondary"><?php esc_html_e( 'Do not allow', 'easy-image-optimizer' ); ?></a> 418 </p> 419 </div> 420 <?php 421 } 422 423 /** 424 * Inform the user that we disabled SP AIO to prevent conflicts with ExactDN. 425 */ 426 public function sp_conflict_notice() { 427 ?> 428 <div id='easyio-sp-conflict' class='notice notice-warning'> 429 <p> 430 <?php \esc_html_e( 'ShortPixel/Autoptimize image optimization has been disabled to prevent conflicts with Easy Image Optimizer).', 'easy-image-optimizer' ); ?> 431 </p> 432 </div> 433 <?php 253 434 } 254 435 … … 256 437 * Tell the user to disable Hide my WP function that removes query strings. 257 438 */ 258 public function notice_hmwp_hide_version() {439 public function hmwp_hide_version_notice() { 259 440 ?> 260 441 <div id='easy-image-optimizer-warning-hmwp-hide-version' class='notice notice-warning'> 261 442 <p> 262 443 <?php \esc_html_e( 'Please enable the Random Static Number option in Hide My WP to ensure compatibility with Easy IO or disable the Hide Version option for best performance.', 'easy-image-optimizer' ); ?> 263 <?php \easyio_help_link( 'https://docs.ewww.io/article/50-exactdn-and-query-strings', '5a3d278a2c7d3a1943677b52' ); ?>444 <?php $this->settings->help_link( 'https://docs.ewww.io/article/50-exactdn-and-query-strings', '5a3d278a2c7d3a1943677b52' ); ?> 264 445 </p> 265 446 </div> -
easy-image-optimizer/tags/4.3.0/easy-image-optimizer.php
r3350722 r3398277 14 14 Description: Easily speed up your website to better connect with your visitors. Properly compress and size/scale images. Includes lazy load and WebP auto-convert. 15 15 Author: Exactly WWW 16 Version: 4. 2.116 Version: 4.3.0 17 17 Requires at least: 6.6 18 18 Requires PHP: 8.1 … … 25 25 } 26 26 27 // Check the PHP version. 28 if ( ! defined( 'PHP_VERSION_ID' ) || PHP_VERSION_ID < 80100 ) { 29 add_action( 'network_admin_notices', 'easyio_unsupported_php' ); 30 add_action( 'admin_notices', 'easyio_unsupported_php' ); 31 } elseif ( false === strpos( add_query_arg( '', '' ), 'easyio_disable=1' ) ) { 32 define( 'EASYIO_VERSION', 421 ); 27 if ( ! class_exists( 'EasyIO\Plugin' ) && ! str_contains( add_query_arg( '', '' ), 'easyio_disable=1' ) ) { 28 define( 'EASYIO_VERSION', 430 ); 33 29 34 30 /** … … 58 54 if ( ! is_writable( WP_CONTENT_DIR ) || ! empty( $_ENV['PANTHEON_ENVIRONMENT'] ) ) { 59 55 $upload_dir = wp_get_upload_dir(); 60 if ( false === strpos( $upload_dir['basedir'], '://' ) && is_writable( $upload_dir['basedir'] ) ) {56 if ( ! str_contains( $upload_dir['basedir'], '://' ) && is_writable( $upload_dir['basedir'] ) ) { 61 57 $easyio_content_dir = trailingslashit( $upload_dir['basedir'] ) . trailingslashit( 'easyio' ); 62 58 } … … 66 62 } 67 63 68 /**69 * All the 'unique' functions for the core Easy IO plugin.70 */71 require_once EASYIO_PLUGIN_PATH . 'unique.php';72 64 /** 73 65 * All the base functions for our plugins. … … 88 80 easyio(); 89 81 } // End if(). 90 91 if ( ! function_exists( 'easyio_unsupported_php' ) ) {92 /**93 * Display a notice that the PHP version is too old.94 */95 function easyio_unsupported_php() {96 echo '<div id="easyio-warning-php" class="error"><p><a href="https://docs.ewww.io/article/55-upgrading-php" target="_blank" data-beacon-article="5ab2baa6042863478ea7c2ae">' . esc_html__( 'Easy Image Optimizer requires PHP 8.1 or greater. Newer versions of PHP are faster and more secure. If you are unsure how to upgrade to a supported version, ask your webhost for instructions.', 'easy-image-optimizer' ) . '</a></p></div>';97 }98 } -
easy-image-optimizer/tags/4.3.0/includes/eio.js
r3076002 r3398277 38 38 }); 39 39 } 40 $('#easyio-general-settings').show();41 $('li.easyio-general-nav').addClass('easyio-selected');42 $('#easyio-support-settings').hide();43 40 $('.easyio-general-nav').click(function() { 44 41 $('.easyio-tab-nav li').removeClass('easyio-selected'); … … 59 56 $('#easyio-hidden-submit').show(); 60 57 }); 61 return false; 58 $('a#easyio-activate').on( 'click', function() { 59 $('a#easyio-activate').hide(); 60 $('#easyio-activation-processing').show(); 61 activateExactDNSite(); 62 return false; 63 }); 64 function activateExactDNSite() { 65 var easyio_post_action = 'easyio_activate'; 66 var easyio_post_data = { 67 action: easyio_post_action, 68 _wpnonce: easyio_vars._wpnonce, 69 }; 70 $.post(ajaxurl, easyio_post_data, function(response) { 71 try { 72 var easyio_response = JSON.parse(response); 73 } catch (err) { 74 $('#easyio-activation-processing').hide(); 75 $('#easyio-activation-result').html(easyio_vars.invalid_response); 76 $('#easyio-activation-result').addClass('error'); 77 $('#easyio-activation-result').show(); 78 console.log( response ); 79 return false; 80 } 81 if ( easyio_response.error ) { 82 $('#easyio-activation-processing').hide(); 83 $('a#easyio-activate').show(); 84 $('#easyio-activation-result').html(easyio_response.error); 85 $('#easyio-activation-result').addClass('error'); 86 $('#easyio-activation-result').show(); 87 } else if ( ! easyio_response.success ) { 88 $('#easyio-activation-processing').hide(); 89 $('#easyio-activation-result').html(easyio_vars.invalid_response); 90 $('#easyio-activation-result').addClass('error'); 91 $('#easyio-activation-result').show(); 92 console.log( response ); 93 } else { 94 $('#easyio-activation-processing').hide(); 95 $('#easyio-status').html(easyio_response.success); 96 $('#exactdn_all_the_things').prop('checked', true); 97 $('#easyio_lazy_load').prop('checked', true); 98 $('#easyio_add_missing_dims').prop('disabled', false); 99 $('.easyio-settings-table').show(); 100 $('#easyio-hidden-submit').show(); 101 $('table.easyio-inactive').hide(); 102 } 103 }); 104 return false; 105 } 106 var easy_save_bar_width = $('#easyio-savings-fill').data('score'); 107 $('#easyio-savings-fill').animate( { 108 width: easy_save_bar_width + '%', 109 }, 1000 ); 110 var easy_bandwidth_bar_width = $('#easyio-bandwidth-fill').data('score'); 111 if ( easy_bandwidth_bar_width == 100 ) { 112 $('#easyio-bandwidth-container .easyio-bar-fill').css('background-color', '#d63638'); 113 $('#easyio-bandwidth-flex a').css('color', '#d63638'); 114 } 115 $('#easyio-bandwidth-fill').animate( { 116 width: easy_bandwidth_bar_width + '%', 117 }, 1000 ); 118 easyIORegisterStatsHandler(); 119 function easyIORegisterStatsHandler() { 120 $('#easyio-show-stats').on('click', function(){ 121 var site_id = $(this).attr('data-site-id'); 122 var easyio_post_data = { 123 action: 'easyio_get_site_stats', 124 site_id: site_id, 125 _wpnonce: easyio_vars._wpnonce, 126 }; 127 var statsContainerID = 'exactdn-stats-modal-' + site_id; 128 var statsContainer = false; 129 var statsExist = document.getElementById(statsContainerID); 130 var closeIcon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"/></svg>'; 131 if ( ! statsExist ) { 132 $('body').append('<div id="' + statsContainerID + '" style="display:none;" class="exactdn-stats-modal"><div class="exactdn-stats-modal-close">' + closeIcon + '</div><div class="exactdn-stats-modal-charts"></div><img class="exactdn-loading-image" style="display:block;margin-left: auto;margin-right:auto;width:20px;" src="' + easyio_vars.loading_image_url + '" /></div>'); 133 statsContainer = $('#' + statsContainerID); 134 $(statsContainer).on('click', '.exactdn-stats-modal-close', function() { 135 $('.exactdn-stats-modal').hide(); 136 document.body.classList.toggle('exactdn-body-unscroll'); 137 }); 138 139 $.post(ajaxurl, easyio_post_data, function(response) { 140 //console.log( response ); 141 var is_json = true; 142 try { 143 var easyio_response = $.parseJSON(response); 144 } catch (err) { 145 is_json = false; 146 } 147 if ( ! is_json ) { 148 statsContainer.children('.exactdn-stats-modal-charts').html(easyio_vars.invalid_response); 149 $('.exactdn-loading-image').hide(); 150 console.log(response); 151 } else if (easyio_response.error) { 152 statsContainer.children('.exactdn-stats-modal-charts').html('<strong>Error (contact support if necessary):</strong> ' + easyio_response.error); 153 $('.exactdn-loading-image').hide(); 154 } else if (easyio_response.html) { 155 statsContainer.children('.exactdn-stats-modal-charts').html(easyio_response.html); 156 if (easyio_response.pending) { 157 console.log('need to fetch more stats, request pending'); 158 setTimeout(fetchExtraStats, 10000, site_id); 159 } else { 160 $('.exactdn-loading-image').hide(); 161 } 162 } else { 163 statsContainer.children('.exactdn-stats-modal-charts').html(easyio_vars.invalid_response); 164 $('.exactdn-loading-image').hide(); 165 console.log(response); 166 } 167 }) 168 .fail(function() { 169 statsContainer.children('.exactdn-stats-modal-charts').html(easyio_vars.invalid_response); 170 $('.exactdn-loading-image').hide(); 171 }); 172 } else { 173 statsContainer = $('#' + statsContainerID); 174 } 175 statsContainer.show(); 176 document.body.classList.toggle('exactdn-body-unscroll'); 177 return false; 178 }); 179 } 180 var extraStatsRequests = 0; 181 function fetchExtraStats(site_id) { 182 var easyio_post_data = { 183 action: 'easyio_get_site_stats', 184 site_id: site_id, 185 require_extra: 1, 186 _wpnonce: easyio_vars._wpnonce, 187 }; 188 var statsContainerID = 'exactdn-stats-modal-' + site_id; 189 var statsContainer = false; 190 var statsExist = document.getElementById(statsContainerID); 191 if ( ! statsExist ) { 192 console.log('no container for site #' + site_id); 193 return; 194 } 195 statsContainer = $('#' + statsContainerID); 196 if ( extraStatsRequests > 11 ) { // Roughly 2 minutes of waiting. 197 $('.exactdn-loading-image').hide(); 198 statsContainer.find('.exactdn-stats-pending').text(easyio_vars.easyio_extra_stats_failed); 199 return; 200 } 201 $.post(ajaxurl, easyio_post_data, function(response) { 202 extraStatsRequests++; 203 var is_json = true; 204 try { 205 var easyio_response = $.parseJSON(response); 206 } catch (err) { 207 is_json = false; 208 } 209 if ( ! is_json ) { 210 console.log(response); 211 setTimeout(fetchExtraStats, 10000, site_id); 212 return; 213 } 214 if (easyio_response.error) { 215 console.log(easyio_response.error); 216 } else if (easyio_response.html) { 217 $('.exactdn-loading-image').hide(); 218 statsContainer.children('.exactdn-stats-modal-charts').html(easyio_response.html); 219 return; 220 } 221 setTimeout(fetchExtraStats, 10000, site_id); 222 }); 223 } 62 224 }); 63 225 function selectText(containerid) { -
easy-image-optimizer/tags/4.3.0/includes/lazysizes-post.js
r3197623 r3398277 28 28 if(e.detail.instance != lazySizes){return;} 29 29 30 var bg, bgWebP ;30 var bg, bgWebP,swisLazyId; 31 31 if(!e.defaultPrevented) { 32 32 … … 36 36 37 37 // handle data-back (so as not to conflict with the stock data-bg) 38 bg = e.target.getAttribute('data-back'); 38 bg = e.target.dataset.back; 39 // Was getAttribute('data-back'); 39 40 if (bg) { 40 if(ewww_webp_supported) {41 if(ewww_webp_supported) { 41 42 console.log('checking for data-back-webp'); 42 bgWebP = e.target.getAttribute('data-back-webp'); 43 bgWebP = e.target.dataset.backWebp; 44 // Was bgWebP = e.target.getAttribute('data-back-webp'); 43 45 if (bgWebP) { 44 46 console.log('replacing data-back with data-back-webp'); … … 46 48 } 47 49 } 48 var dPR = getdPR(); 49 var targetWidth = Math.round(e.target.offsetWidth * dPR); 50 var targetHeight = Math.round(e.target.offsetHeight * dPR); 51 if ( 0 === bg.search(/\[/) ) { 52 } else if (!shouldAutoScale(e.target)){ 53 } else if (lazySizes.hC(e.target,'wp-block-cover')) { 54 console.log('found wp-block-cover with data-back'); 55 if (lazySizes.hC(e.target,'has-parallax')) { 56 console.log('also has-parallax with data-back'); 57 targetWidth = Math.round(window.screen.width * dPR); 58 targetHeight = Math.round(window.screen.height * dPR); 59 } else if (targetHeight<300) { 60 targetHeight = 430; 61 } 62 bg = constrainSrc(bg,targetWidth,targetHeight,'bg-cover'); 63 } else if (lazySizes.hC(e.target,'cover-image')){ 64 console.log('found .cover-image with data-back'); 65 bg = constrainSrc(bg,targetWidth,targetHeight,'bg-cover'); 66 } else if (lazySizes.hC(e.target,'elementor-bg')){ 67 console.log('found elementor-bg with data-back'); 68 bg = constrainSrc(bg,targetWidth,targetHeight,'bg-cover'); 69 } else if (lazySizes.hC(e.target,'et_parallax_bg')){ 70 console.log('found et_parallax_bg with data-back'); 71 bg = constrainSrc(bg,targetWidth,targetHeight,'bg-cover'); 72 } else if (lazySizes.hC(e.target,'bg-image-crop')){ 73 console.log('found bg-image-crop with data-back'); 74 bg = constrainSrc(bg,targetWidth,targetHeight,'bg-cover'); 75 } else { 76 console.log('found other data-back'); 77 bg = constrainSrc(bg,targetWidth,targetHeight,'bg'); 78 } 50 bg = constrainBg(bg,e.target); 79 51 if ( e.target.style.backgroundImage && -1 === e.target.style.backgroundImage.search(/^initial/) ) { 80 52 // Convert JSON for multiple URLs. … … 114 86 } 115 87 } 88 // Handle CSS images from SWIS. 89 swisLazyId = e.target.dataset.swisLazyId; 90 if (swisLazyId && swisLazyId in swis_lazy_css_images) { 91 console.log('fetching CSS images for swisLazyId ' + swisLazyId); 92 var css_images = swis_lazy_css_images[swisLazyId]; 93 var swisStyle = document.querySelector('style#swis-lazy-css-styles'); 94 css_images.forEach( 95 function(css_image){ 96 if (!css_image.url) { 97 return; 98 } 99 if(ewww_webp_supported && css_image.webp_url) { 100 console.log('webp supported, using webp url for css image'); 101 css_image.url = css_image.webp_url; 102 } 103 css_image.url = constrainBg(css_image.url,e.target); 104 console.log('processing CSS image: ' + css_image.url + ' with hash ' + css_image.hash); 105 var cssRule = css_image.selector + ' {--swis-bg-' + css_image.hash + ': url(' + css_image.url + '); }'; 106 swisStyle.sheet.insertRule(cssRule); 107 } 108 ); 109 } 116 110 } 117 111 }, false); 118 112 } 113 114 var constrainBg = function(bg,target){ 115 if ( 0 === bg.search(/\[/) ) { 116 console.log('multiple URLs, not autoscaling background image'); 117 return bg; 118 } 119 if (!shouldAutoScale(target)){ 120 console.log('not autoscaling background image'); 121 return bg; 122 } 123 var dPR = getdPR(); 124 if ( dPR < eio_lazy_vars.bg_min_dpr ) { 125 dPR = eio_lazy_vars.bg_min_dpr; 126 } 127 var targetWidth = Math.round(target.offsetWidth * dPR); 128 var targetHeight = Math.round(target.offsetHeight * dPR); 129 var bgType = 'bg'; 130 if (lazySizes.hC(target,'wp-block-cover')||lazySizes.hC(target,'wp-block-cover__image-background')){ 131 console.log('found wp-block-cover with data-back'); 132 if (lazySizes.hC(target,'has-parallax')) { 133 console.log('also has-parallax with data-back'); 134 targetWidth = Math.round(window.screen.width * dPR); 135 targetHeight = Math.round(window.screen.height * dPR); 136 } else if (targetHeight<300) { 137 targetHeight = 430; 138 } 139 bgType = 'bg-cover'; 140 } else if (lazySizes.hC(target,'cover-image')){ 141 console.log('found .cover-image with data-back'); 142 bgType = 'bg-cover'; 143 } else if (lazySizes.hC(target,'elementor-bg')){ 144 console.log('found elementor-bg with data-back'); 145 bgType = 'bg-cover'; 146 } else if (lazySizes.hC(target,'et_parallax_bg')){ 147 console.log('found et_parallax_bg with data-back'); 148 bgType = 'bg-cover'; 149 } else if (lazySizes.hC(target,'bg-image-crop')){ 150 bgType = 'bg-cover'; 151 console.log('found bg-image-crop with data-back'); 152 } else { 153 console.log('found other data-back'); 154 } 155 var imgAspect = getAspectRatio(target); 156 if ('bg' == bgType && targetHeight > 1 && targetWidth > 1 && imgAspect > 0) { 157 var minimum_width = Math.ceil(targetHeight * imgAspect); 158 var minimum_height = Math.ceil(targetWidth / imgAspect); 159 console.log('minimum_width = ' + minimum_width + ', targetWidth = ' + targetWidth); 160 console.log('minimum_height = ' + minimum_height + ', targetHeight = ' + targetHeight); 161 if (targetWidth+2 < minimum_width) { 162 targetWidth = minimum_width; 163 } 164 if (targetHeight+2 < minimum_height) { 165 targetHeight = minimum_height; 166 } 167 var realDims = getRealDimensionsFromImg(target); 168 if (Math.abs(realDims.w - targetWidth) < 5 || Math.abs(realDims.h - targetHeight) < 5) { 169 console.log('real dimensions within 5px of target sizes, no scaling'); 170 return bg; 171 } 172 } 173 bg = constrainSrc(bg,targetWidth,targetHeight,bgType); 174 return bg; 175 }; 119 176 120 177 var shouldAutoScale = function(target){ … … 294 351 295 352 var getRealDimensionsFromImg = function(img){ 296 var realWidth = img. getAttribute('data-eio-rwidth');297 var realHeight = img. getAttribute('data-eio-rheight');353 var realWidth = img.dataset.eioRwidth; 354 var realHeight = img.dataset.eioRheight; 298 355 if (realWidth > 1 && realHeight > 1) { 299 356 return {w:realWidth,h:realHeight}; … … 411 468 } 412 469 if (e.target._lazysizesWidth === undefined) { 470 if (!eio_lazy_vars.use_dpr && window.devicePixelRatio > 1) { 471 console.log('use_dpr is disabled, reversing auto-sizes by dpr ' + window.devicePixelRatio); 472 e.detail.width = Math.ceil(e.detail.width / window.devicePixelRatio); 473 } 413 474 return; 414 475 } … … 417 478 console.log('no way! ' + e.detail.width + ' is smaller than ' + e.target._lazysizesWidth); 418 479 e.detail.width = e.target._lazysizesWidth; 480 } 481 if (!eio_lazy_vars.use_dpr && window.devicePixelRatio > 1) { 482 console.log('use_dpr is disabled, reversing auto-sizes by dpr ' + window.devicePixelRatio); 483 e.detail.width = Math.ceil(e.detail.width / window.devicePixelRatio); 419 484 } 420 485 }); -
easy-image-optimizer/tags/4.3.0/includes/lazysizes-pre.js
r3197623 r3398277 1 1 if (typeof ewww_webp_supported === 'undefined') { 2 2 var ewww_webp_supported = false; 3 } 4 if (typeof swis_lazy_css_images === 'undefined') { 5 var swis_lazy_css_images = {}; 3 6 } 4 7 window.lazySizesConfig = window.lazySizesConfig || {}; … … 18 21 } 19 22 console.log( 'root margin: ' + window.lazySizesConfig.expand ); 23 for ( const [css_index, css_image] of Object.entries(swis_lazy_css_images)){ 24 console.log('processing css image ' + css_index + ': ' + css_image[0].url); 25 try { 26 document.querySelectorAll(css_image[0].selector).forEach((el) => { 27 if (!el.classList.contains('lazyload')) { 28 console.log('adding lazyload to css image ' + css_index + ': ' + css_image[0].url); 29 el.classList.add('lazyload'); 30 el.dataset.swisLazyId = css_index; 31 if (css_image[0].rwidth > 5 && css_image[0].rheight > 5) { 32 el.dataset.eioRwidth = css_image[0].rwidth; 33 el.dataset.eioRheight = css_image[0].rheight; 34 } 35 } 36 }); 37 } catch (e) { 38 console.log('error processing css image(s) for "' + css_index[0].selector + '": ' + e); 39 } 40 } -
easy-image-optimizer/tags/4.3.0/includes/lazysizes.min.js
r3197623 r3398277 1 var ewww_webp_supported ;void 0===ewww_webp_supported&&(ewww_webp_supported=!1),window.lazySizesConfig=window.lazySizesConfig||{},window.lazySizesConfig.expand=500<document.documentElement.clientHeight&&500<document.documentElement.clientWidth?1e3:740,window.lazySizesConfig.iframeLoadMode=1,"undefined"==typeof eio_lazy_vars&&(eio_lazy_vars={exactdn_domain:".exactdn.com",threshold:0,skip_autoscale:0,use_dpr:0}),50<eio_lazy_vars.threshold&&(window.lazySizesConfig.expand=eio_lazy_vars.threshold),function(e,t){function a(){t(e.lazySizes),e.removeEventListener("lazyunveilread",a,!0)}t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?a():e.addEventListener("lazyunveilread",a,!0)}(window,function(e,n,o){"use strict";var s,l,d={};function c(e,t,a){var r,i;d[e]||(r=n.createElement(t?"link":"script"),i=n.getElementsByTagName("script")[0],t?(r.rel="stylesheet",r.href=e):(r.onload=function(){r.onerror=null,r.onload=null,a()},r.onerror=r.onload,r.src=e),d[e]=!0,d[r.src||r.href]=!0,i.parentNode.insertBefore(r,i))}n.addEventListener&&(l=/\(|\)|\s|'/,s=function(e,t){var a=n.createElement("img");a.onload=function(){a.onload=null,a.onerror=null,a=null,t()},a.onerror=a.onload,a.src=e,a&&a.complete&&a.onload&&a.onload()},addEventListener("lazybeforeunveil",function(e){var t,a,r;if(e.detail.instance==o&&!e.defaultPrevented){var i=e.target;if("none"==i.preload&&(i.preload=i.getAttribute("data-preload")||"auto"),null!=i.getAttribute("data-autoplay"))if(i.getAttribute("data-expand")&&!i.autoplay)try{i.play()}catch(e){}else requestAnimationFrame(function(){i.setAttribute("data-expand","-10"),o.aC(i,o.cfg.lazyClass)});(t=i.getAttribute("data-link"))&&c(t,!0),(t=i.getAttribute("data-script"))&&(e.detail.firesLoad=!0,c(t,null,function(){e.detail.firesLoad=!1,o.fire(i,"_lazyloaded",{},!0,!0)})),(t=i.getAttribute("data-require"))&&(o.cfg.requireJs?o.cfg.requireJs([t]):c(t)),(a=i.getAttribute("data-bg"))&&(e.detail.firesLoad=!0,s(a,function(){i.style.backgroundImage="url("+(l.test(a)?JSON.stringify(a):a)+")",e.detail.firesLoad=!1,o.fire(i,"_lazyloaded",{},!0,!0)})),(r=i.getAttribute("data-poster"))&&(e.detail.firesLoad=!0,s(r,function(){i.poster=r,e.detail.firesLoad=!1,o.fire(i,"_lazyloaded",{},!0,!0)}))}},!1))}),function(e,t){function a(){t(e.lazySizes),e.removeEventListener("lazyunveilread",a,!0)}t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?a():e.addEventListener("lazyunveilread",a,!0)}(window,function(u,f,g){"use strict";var n;f.addEventListener&&(n=/\(|\)|\s|'/,addEventListener("lazybeforeunveil",function(e){var t,a,r,i;e.detail.instance==g&&(e.defaultPrevented||("none"==e.target.preload&&(e.target.preload="auto"),(r=e.target.getAttribute("data-back"))&&(ewww_webp_supported&&(i=e.target.getAttribute("data-back-webp"))&&(r=i),t=v(),a=Math.round(e.target.offsetWidth*t),i=Math.round(e.target.offsetHeight*t),0===r.search(/\[/)||o(e.target)&&(r=g.hC(e.target,"wp-block-cover")?(g.hC(e.target,"has-parallax")?(a=Math.round(u.screen.width*t),i=Math.round(u.screen.height*t)):i<300&&(i=430),s(r,a,i,"bg-cover")):g.hC(e.target,"cover-image")||g.hC(e.target,"elementor-bg")||g.hC(e.target,"et_parallax_bg")||g.hC(e.target,"bg-image-crop")?s(r,a,i,"bg-cover"):s(r,a,i,"bg")),e.target.style.backgroundImage&&-1===e.target.style.backgroundImage.search(/^initial/)?0===r.search(/\[/)?((r=JSON.parse(r)).forEach(function(e){n.test(e)&&JSON.stringify(e)}),r='url("'+r.join('"), url("')+'"',i=e.target.style.backgroundImage+", "+r,e.target.style.backgroundImage=i):e.target.style.backgroundImage=e.target.style.backgroundImage+', url("'+(n.test(r)?JSON.stringify(r):r)+'")':0===r.search(/\[/)?((r=JSON.parse(r)).forEach(function(e){n.test(e)&&JSON.stringify(e)}),r='url("'+r.join('"), url("')+'"',e.target.style.backgroundImage=r):e.target.style.backgroundImage="url("+(n.test(r)?JSON.stringify(r):r)+")")))},!1));function h(e){var t=e.getAttribute("data-eio-rwidth"),e=e.getAttribute("data-eio-rheight");return 1<t&&1<e?{w:t,h:e}:{w:0,h:0}}function m(e,t=!1){var a=v(),r=Math.round(e.offsetWidth*a),i=Math.round(e.offsetHeight*a),n=e.getAttribute("data-src"),a=e.getAttribute("data-src-webp");ewww_webp_supported&&a&&-1==n.search("webp=1")&&!t&&(n=a),o(e)&&(a=e,a=g.hC(a,"et_pb_jt_filterable_grid_item_image")||g.hC(a,"ss-foreground-image")||g.hC(a,"img-crop")?"img-crop":g.hC(a,"object-cover")&&(g.hC(a,"object-top")||g.hC(a,"object-bottom"))?"img-w":g.hC(a,"object-cover")&&(g.hC(a,"object-left")||g.hC(a,"object-right"))?"img-h":g.hC(a,"ct-image")&&g.hC(a,"object-cover")||!a.getAttribute("data-srcset")&&!a.srcset&&a.offsetHeight>a.offsetWidth&&1<l(a)?"img-crop":"img",(a=s(n,r,i,a,t))&&n!=a&&(t&&e.setAttribute("src",a),e.setAttribute("data-src",a)))}var o=function(e){if(1==eio_lazy_vars.skip_autoscale)return!1;for(var t=e,a=0;a<=7;a++){if(t.hasAttributes())for(var r=t.attributes,i=/skip-autoscale/,a=r.length-1;0<=a;a--){if(i.test(r[a].name))return!1;if(i.test(r[a].value))return!1}if(!t.parentNode||1!==t.parentNode.nodeType||!t.parentNode.hasAttributes)break;t=t.parentNode}return!0},s=function(e,t,a,r,i=!1){if(null===e)return e;var n=/w=(\d+)/,o=/fit=(\d+),(\d+)/,s=/resize=(\d+),(\d+)/,l=decodeURIComponent(e);if(/\.svg(\?.+)?$/.exec(l))return e;if(0<e.search("\\?")&&0<e.search(eio_lazy_vars.exactdn_domain)){var d=s.exec(l);if(d&&(t<d[1]||i))return"img-w"===r?l.replace(s,"w="+t):"img-h"===r?l.replace(s,"h="+a):l.replace(s,"resize="+t+","+a);s=n.exec(e);if(s&&(t<=s[1]||i)){if("img-h"===r)return l.replace(n,"h="+a);if("bg-cover"!==r&&"img-crop"!==r)return e.replace(n,"w="+t);var c=Math.abs(s[1]-t);return 20<c||a<1080?e.replace(n,"resize="+t+","+a):e}c=o.exec(l);if(c&&(t<c[1]||i)){if("bg-cover"!==r&&"img-crop"!==r)return"img-w"===r?l.replace(o,"w="+t):"img-h"===r?l.replace(o,"h="+a):l.replace(o,"fit="+t+","+a);l=Math.abs(c[1]-t),o=Math.abs(c[2]-a);return 20<l||20<o?e.replace(n,"resize="+t+","+a):e}if(!s&&!c&&!d)return"img"===r?e+"&fit="+t+","+a:"bg-cover"===r||"img-crop"===r?e+"&resize="+t+","+a:"img-h"===r||t<a?e+"&h="+a:e+"&w="+t}return-1==e.search("\\?")&&0<e.search(eio_lazy_vars.exactdn_domain)?"img"===r?e+"?fit="+t+","+a:"bg-cover"===r||"img-crop"===r?e+"?resize="+t+","+a:"img-h"===r||t<a?e+"?h="+a:e+"?w="+t:e},p=function(e){e=/-(\d+)x(\d+)\./.exec(e);return e&&1<e[1]&&1<e[2]?{w:e[1],h:e[2]}:{w:0,h:0}},l=function(e){var t=e.getAttribute("width"),a=e.getAttribute("height");if(1<t&&1<a)return t/a;a=!1;if(a=(a=e.src&&-1<e.src.search("http")?e.src:a)||e.getAttribute("data-src")){var r=p(a);if(r.w&&r.h)return r.w/r.h}r=h(e);if(r.w&&r.h)return r.w/r.h;e=function(e){var t;if(e.srcset?t=e.srcset.split(","):(e=e.getAttribute("data-srcset"))&&(t=e.split(",")),t){var a=0,r=t.length;if(r){for(;a<r;a++){var i,n=t[a].trim().split(" ");!n[0].length||(n=p(n[0])).w&&n.h&&(i=n)}if(i.w&&i.h)return i}}return{w:0,h:0}}(e);return e.w&&e.h?e.w/e.h:0},v=function(){return eio_lazy_vars.use_dpr&&1<u.devicePixelRatio?u.devicePixelRatio:1};f.addEventListener("lazybeforesizes",function(e){e.target.getAttribute("data-src");var t=l(e.target);1<e.target.clientHeight&&t&&(t=Math.ceil(t*e.target.clientHeight),e.detail.width+2<t&&(e.detail.width=t)),void 0!==e.target._lazysizesWidth&&e.detail.width<e.target._lazysizesWidth&&(e.detail.width=e.target._lazysizesWidth)}),f.addEventListener("lazybeforeunveil",function(e){var t,a,r,i,n=e.target,o=n.getAttribute("data-srcset");n.naturalWidth&&!o&&1<n.naturalWidth&&1<n.naturalHeight&&(t=v(),a=n.naturalWidth,r=n.naturalHeight,(e=h(n)).w&&e.w>a&&(a=e.w,r=e.h),a=n.clientWidth&&1.25*n.clientWidth*t<a,r=n.clientHeight&&1.25*n.clientHeight*t<r,(a||r)&&m(n)),ewww_webp_supported&&(!o||(i=n.getAttribute("data-srcset-webp"))&&n.setAttribute("data-srcset",i),(i=n.getAttribute("data-src-webp"))&&n.setAttribute("data-src",i))});function e(e=!1){e.type&&"load"===e.type&&g.autoSizer.checkElems(),v();var t,a=f.getElementsByClassName(g.cfg.loadedClass),r=a.length;if(r)for(t=0;t<r;t++){var i,n,o,s,l,d,c=a[t];c.src&&!c.srcset&&1<c.naturalWidth&&1<c.naturalHeight&&1<c.clientWidth&&1<c.clientHeight&&(i=c.naturalWidth,n=c.naturalHeight,o=u.innerWidth,s=u.innerHeight,l=h(c),d=p(c.src),l.w?o=l.w:d.w&&(o=d.w),l.h?s=l.h:d.h&&(s=d.h),l=c.clientWidth,d=c.clientHeight,(1.1*i<l&&l<=o||1.1*n<d&&d<=s)&&m(c,!0))}}var t,a,r,i,d=(t=e,i=function(){a=null,t()},function(){r=Date.now(),a=a||setTimeout(c,99)});function c(){var e=Date.now()-r;e<99?setTimeout(c,99-e):(u.requestIdleCallback||i)(i)}addEventListener("load",e),addEventListener("resize",d),setTimeout(e,2e4)}),function(e,t){t=t(e,e.document,Date);e.lazySizes=t,"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:{},function(r,f,n){"use strict";var g,h;if(!function(){var e,t={lazyClass:"lazyload",loadedClass:"lazyloaded",loadingClass:"lazyloading",preloadClass:"lazypreload",errorClass:"lazyerror",autosizesClass:"lazyautosizes",fastLoadedClass:"ls-is-cached",iframeLoadMode:0,srcAttr:"data-src",srcsetAttr:"data-srcset",sizesAttr:"data-sizes",minSize:40,customMedia:{},init:!0,expFactor:1.5,hFac:.8,loadMode:2,loadHidden:!0,ricTimeout:0,throttleDelay:125};for(e in h=r.lazySizesConfig||r.lazysizesConfig||{},t)e in h||(h[e]=t[e])}(),!f||!f.getElementsByClassName)return{init:function(){},cfg:h,noSupport:!0};function c(e,t){E(e,t)||e.setAttribute("class",(e[v]("class")||"").trim()+" "+t)}function u(e,t){(t=E(e,t))&&e.setAttribute("class",(e[v]("class")||"").replace(t," "))}function m(e,t){var a;!l&&(a=r.picturefill||h.pf)?(t&&t.src&&!e[v]("srcset")&&e.setAttribute("srcset",t.src),a({reevaluate:!0,elements:[e]})):t&&t.src&&(e.src=t.src)}var a,i,t,o,s,p=f.documentElement,l=r.HTMLPictureElement,d="addEventListener",v="getAttribute",e=r[d].bind(r),y=r.setTimeout,b=r.requestAnimationFrame||y,z=r.requestIdleCallback,w=/^picture$/i,_=["load","error","lazyincluded","_lazyloaded"],C={},A=Array.prototype.forEach,E=function(e,t){return C[t]||(C[t]=new RegExp("(\\s|^)"+t+"(\\s|$)")),C[t].test(e[v]("class")||"")&&C[t]},L=function(t,a,e){var r=e?d:"removeEventListener";e&&L(t,a),_.forEach(function(e){t[r](e,a)})},x=function(e,t,a,r,i){var n=f.createEvent("Event");return(a=a||{}).instance=g,n.initEvent(t,!r,!i),n.detail=a,e.dispatchEvent(n),n},N=function(e,t){return(getComputedStyle(e,null)||{})[t]},M=function(e,t,a){for(a=a||e.offsetWidth;a<h.minSize&&t&&!e._lazysizesWidth;)a=t.offsetWidth,t=t.parentNode;return a},W=(o=[],s=t=[],k._lsFlush=S,k);function S(){var e=s;for(s=t.length?o:t,i=!(a=!0);e.length;)e.shift()();a=!1}function k(e,t){a&&!t?e.apply(this,arguments):(s.push(e),i||(i=!0,(f.hidden?y:b)(S)))}function H(a,e){return e?function(){W(a)}:function(){var e=this,t=arguments;W(function(){a.apply(e,t)})}}function I(e){function t(){var e=n.now()-r;e<99?y(t,99-e):(z||i)(i)}var a,r,i=function(){a=null,e()};return function(){r=n.now(),a=a||y(t,99)}}var T,j,B,O,R,q,F,J,P,D,$,U,G,K,Q,V,X,Y,Z,ee,te,ae,re,ie,ne,oe,se,le,de,ce,ue,fe=(Z=/^img$/i,ee=/^iframe$/i,te="onscroll"in r&&!/(gle|ing)bot/.test(navigator.userAgent),ie=-1,ne=function(e){return(U=null==U?"hidden"==N(f.body,"visibility"):U)||!("hidden"==N(e.parentNode,"visibility")&&"hidden"==N(e,"visibility"))},G=he,Q=re=ae=0,V=h.throttleDelay,X=h.ricTimeout,Y=z&&49<X?function(){z(me,{timeout:X}),X!==h.ricTimeout&&(X=h.ricTimeout)}:H(function(){y(me)},!0),se=H(pe),le=function(e){se({target:e.target})},de=H(function(t,e,a,r,i){var n,o,s,l,d;(s=x(t,"lazybeforeunveil",e)).defaultPrevented||(r&&(a?c(t,h.autosizesClass):t.setAttribute("sizes",r)),n=t[v](h.srcsetAttr),a=t[v](h.srcAttr),i&&(o=(d=t.parentNode)&&w.test(d.nodeName||"")),l=e.firesLoad||"src"in t&&(n||a||o),s={target:t},c(t,h.loadingClass),l&&(clearTimeout(B),B=y(ge,2500),L(t,le,!0)),o&&A.call(d.getElementsByTagName("source"),ve),n?t.setAttribute("srcset",n):a&&!o&&(ee.test(t.nodeName)?(r=a,0==(d=(e=t).getAttribute("data-load-mode")||h.iframeLoadMode)?e.contentWindow.location.replace(r):1==d&&(e.src=r)):t.src=a),i&&(n||o)&&m(t,{src:a})),t._lazyRace&&delete t._lazyRace,u(t,h.lazyClass),W(function(){var e=t.complete&&1<t.naturalWidth;l&&!e||(e&&c(t,h.fastLoadedClass),pe(s),t._lazyCache=!0,y(function(){"_lazyCache"in t&&delete t._lazyCache},9)),"lazy"==t.loading&&re--},!0)}),ue=I(function(){h.loadMode=3,oe()}),{_:function(){R=n.now(),g.elements=f.getElementsByClassName(h.lazyClass),T=f.getElementsByClassName(h.lazyClass+" "+h.preloadClass),e("scroll",oe,!0),e("resize",oe,!0),e("pageshow",function(e){var t;!e.persisted||(t=f.querySelectorAll("."+h.loadingClass)).length&&t.forEach&&b(function(){t.forEach(function(e){e.complete&&ce(e)})})}),r.MutationObserver?new MutationObserver(oe).observe(p,{childList:!0,subtree:!0,attributes:!0}):(p[d]("DOMNodeInserted",oe,!0),p[d]("DOMAttrModified",oe,!0),setInterval(oe,999)),e("hashchange",oe,!0),["focus","mouseover","click","load","transitionend","animationend"].forEach(function(e){f[d](e,oe,!0)}),/d$|^c/.test(f.readyState)?be():(e("load",be),f[d]("DOMContentLoaded",oe),y(be,2e4)),g.elements.length?(he(),W._lsFlush()):oe()},checkElems:oe=function(e){var t;(e=!0===e)&&(X=33),K||(K=!0,(t=V-(n.now()-Q))<0&&(t=0),e||t<9?Y():y(Y,t))},unveil:ce=function(e){var t,a,r,i;e._lazyRace||(!(i="auto"==(r=(a=Z.test(e.nodeName))&&(e[v](h.sizesAttr)||e[v]("sizes"))))&&j||!a||!e[v]("src")&&!e.srcset||e.complete||E(e,h.errorClass)||!E(e,h.lazyClass))&&(t=x(e,"lazyunveilread").detail,i&&Ce.updateElem(e,!0,e.offsetWidth),e._lazyRace=!0,re++,de(e,t,i,r,a))},_aLSL:ye});function ge(e){re--,e&&!(re<0)&&e.target||(re=0)}function he(){var e,t,a,r,i,n,o,s,l,d,c,u=g.elements;if((O=h.loadMode)&&re<8&&(e=u.length)){for(t=0,ie++;t<e;t++)if(u[t]&&!u[t]._lazyRace)if(!te||g.prematureUnveil&&g.prematureUnveil(u[t]))ce(u[t]);else if((o=u[t][v]("data-expand"))&&(i=+o)||(i=ae),l||(l=!h.expand||h.expand<1?500<p.clientHeight&&500<p.clientWidth?500:370:h.expand,d=(g._defEx=l)*h.expFactor,c=h.hFac,U=null,ae<d&&re<1&&2<ie&&2<O&&!f.hidden?(ae=d,ie=0):ae=1<O&&1<ie&&re<6?l:0),s!==i&&(q=innerWidth+i*c,F=innerHeight+i,n=-1*i,s=i),d=u[t].getBoundingClientRect(),($=d.bottom)>=n&&(J=d.top)<=F&&(D=d.right)>=n*c&&(P=d.left)<=q&&($||D||P||J)&&(h.loadHidden||ne(u[t]))&&(j&&re<3&&!o&&(O<3||ie<4)||function(e,t){var a,r=e,i=ne(e);for(J-=t,$+=t,P-=t,D+=t;i&&(r=r.offsetParent)&&r!=f.body&&r!=p;)(i=0<(N(r,"opacity")||1))&&"visible"!=N(r,"overflow")&&(a=r.getBoundingClientRect(),i=D>a.left&&P<a.right&&$>a.top-1&&J<a.bottom+1);return i}(u[t],i))){if(ce(u[t]),r=!0,9<re)break}else!r&&j&&!a&&re<4&&ie<4&&2<O&&(T[0]||h.preloadAfterLoad)&&(T[0]||!o&&($||D||P||J||"auto"!=u[t][v](h.sizesAttr)))&&(a=T[0]||u[t]);a&&!r&&ce(a)}}function me(){K=!1,Q=n.now(),G()}function pe(e){var t=e.target;t._lazyCache?delete t._lazyCache:(ge(e),c(t,h.loadedClass),u(t,h.loadingClass),L(t,le),x(t,"lazyloaded"))}function ve(e){var t,a=e[v](h.srcsetAttr);(t=h.customMedia[e[v]("data-media")||e[v]("media")])&&e.setAttribute("media",t),a&&e.setAttribute("srcset",a)}function ye(){3==h.loadMode&&(h.loadMode=2),ue()}function be(){j||(n.now()-R<999?y(be,999):(j=!0,h.loadMode=3,oe(),e("scroll",ye,!0)))}var ze,we,_e,Ce=(we=H(function(e,t,a,r){var i,n,o;if(e._lazysizesWidth=r,e.setAttribute("sizes",r+="px"),w.test(t.nodeName||""))for(n=0,o=(i=t.getElementsByTagName("source")).length;n<o;n++)i[n].setAttribute("sizes",r);a.detail.dataAttr||m(e,a.detail)}),{_:function(){ze=f.getElementsByClassName(h.autosizesClass),e("resize",_e)},checkElems:_e=I(function(){var e,t=ze.length;if(t)for(e=0;e<t;e++)Ae(ze[e])}),updateElem:Ae});function Ae(e,t,a){var r=e.parentNode;r&&(a=M(e,r,a),(t=x(e,"lazybeforesizes",{width:a,dataAttr:!!t})).defaultPrevented||(a=t.detail.width)&&a!==e._lazysizesWidth&&we(e,r,t,a))}function Ee(){!Ee.i&&f.getElementsByClassName&&(Ee.i=!0,Ce._(),fe._())}return y(function(){h.init&&Ee()}),g={cfg:h,autoSizer:Ce,loader:fe,init:Ee,uP:m,aC:c,rC:u,hC:E,fire:x,gW:M,rAF:W}});1 var ewww_webp_supported,swis_lazy_css_images;void 0===ewww_webp_supported&&(ewww_webp_supported=!1),void 0===swis_lazy_css_images&&(swis_lazy_css_images={}),window.lazySizesConfig=window.lazySizesConfig||{},window.lazySizesConfig.expand=500<document.documentElement.clientHeight&&500<document.documentElement.clientWidth?1e3:740,window.lazySizesConfig.iframeLoadMode=1,"undefined"==typeof eio_lazy_vars&&(eio_lazy_vars={exactdn_domain:".exactdn.com",threshold:0,skip_autoscale:0,use_dpr:0}),50<eio_lazy_vars.threshold&&(window.lazySizesConfig.expand=eio_lazy_vars.threshold);for(const[a,b]of Object.entries(swis_lazy_css_images))try{document.querySelectorAll(b[0].selector).forEach(e=>{e.classList.contains("lazyload")||(e.classList.add("lazyload"),e.dataset.swisLazyId=a,5<b[0].rwidth&&5<b[0].rheight&&(e.dataset.eioRwidth=b[0].rwidth,e.dataset.eioRheight=b[0].rheight))})}catch(e){}!function(e,t){function a(){t(e.lazySizes),e.removeEventListener("lazyunveilread",a,!0)}t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?a():e.addEventListener("lazyunveilread",a,!0)}(window,function(e,n,s){"use strict";var o,l,d={};function c(e,t,a){var i,r;d[e]||(i=n.createElement(t?"link":"script"),r=n.getElementsByTagName("script")[0],t?(i.rel="stylesheet",i.href=e):(i.onload=function(){i.onerror=null,i.onload=null,a()},i.onerror=i.onload,i.src=e),d[e]=!0,d[i.src||i.href]=!0,r.parentNode.insertBefore(i,r))}n.addEventListener&&(l=/\(|\)|\s|'/,o=function(e,t){var a=n.createElement("img");a.onload=function(){a.onload=null,a.onerror=null,a=null,t()},a.onerror=a.onload,a.src=e,a&&a.complete&&a.onload&&a.onload()},addEventListener("lazybeforeunveil",function(e){var t,a,i;if(e.detail.instance==s&&!e.defaultPrevented){var r=e.target;if("none"==r.preload&&(r.preload=r.getAttribute("data-preload")||"auto"),null!=r.getAttribute("data-autoplay"))if(r.getAttribute("data-expand")&&!r.autoplay)try{r.play()}catch(e){}else requestAnimationFrame(function(){r.setAttribute("data-expand","-10"),s.aC(r,s.cfg.lazyClass)});(t=r.getAttribute("data-link"))&&c(t,!0),(t=r.getAttribute("data-script"))&&(e.detail.firesLoad=!0,c(t,null,function(){e.detail.firesLoad=!1,s.fire(r,"_lazyloaded",{},!0,!0)})),(t=r.getAttribute("data-require"))&&(s.cfg.requireJs?s.cfg.requireJs([t]):c(t)),(a=r.getAttribute("data-bg"))&&(e.detail.firesLoad=!0,o(a,function(){r.style.backgroundImage="url("+(l.test(a)?JSON.stringify(a):a)+")",e.detail.firesLoad=!1,s.fire(r,"_lazyloaded",{},!0,!0)})),(i=r.getAttribute("data-poster"))&&(e.detail.firesLoad=!0,o(i,function(){r.poster=i,e.detail.firesLoad=!1,s.fire(r,"_lazyloaded",{},!0,!0)}))}},!1))}),function(e,t){function a(){t(e.lazySizes),e.removeEventListener("lazyunveilread",a,!0)}t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?a():e.addEventListener("lazyunveilread",a,!0)}(window,function(u,f,h){"use strict";var r;f.addEventListener&&(r=/\(|\)|\s|'/,addEventListener("lazybeforeunveil",function(t){var e,a,i;t.detail.instance==h&&(t.defaultPrevented||("none"==t.target.preload&&(t.target.preload="auto"),(a=t.target.dataset.back)&&(ewww_webp_supported&&(e=t.target.dataset.backWebp)&&(a=e),a=n(a,t.target),t.target.style.backgroundImage&&-1===t.target.style.backgroundImage.search(/^initial/)?0===a.search(/\[/)?((a=JSON.parse(a)).forEach(function(e){r.test(e)&&JSON.stringify(e)}),a='url("'+a.join('"), url("')+'"',e=t.target.style.backgroundImage+", "+a,t.target.style.backgroundImage=e):t.target.style.backgroundImage=t.target.style.backgroundImage+', url("'+(r.test(a)?JSON.stringify(a):a)+'")':0===a.search(/\[/)?((a=JSON.parse(a)).forEach(function(e){r.test(e)&&JSON.stringify(e)}),a='url("'+a.join('"), url("')+'"',t.target.style.backgroundImage=a):t.target.style.backgroundImage="url("+(r.test(a)?JSON.stringify(a):a)+")"),(a=t.target.dataset.swisLazyId)&&a in swis_lazy_css_images&&(a=swis_lazy_css_images[a],i=f.querySelector("style#swis-lazy-css-styles"),a.forEach(function(e){e.url&&(ewww_webp_supported&&e.webp_url&&(e.url=e.webp_url),e.url=n(e.url,t.target),e=e.selector+" {--swis-bg-"+e.hash+": url("+e.url+"); }",i.sheet.insertRule(e))}))))},!1));function g(e,t=!1){var a=y(),i=Math.round(e.offsetWidth*a),r=Math.round(e.offsetHeight*a),n=e.getAttribute("data-src"),a=e.getAttribute("data-src-webp");ewww_webp_supported&&a&&-1==n.search("webp=1")&&!t&&(n=a),o(e)&&(a=e,a=h.hC(a,"et_pb_jt_filterable_grid_item_image")||h.hC(a,"ss-foreground-image")||h.hC(a,"img-crop")?"img-crop":h.hC(a,"object-cover")&&(h.hC(a,"object-top")||h.hC(a,"object-bottom"))?"img-w":h.hC(a,"object-cover")&&(h.hC(a,"object-left")||h.hC(a,"object-right"))?"img-h":h.hC(a,"ct-image")&&h.hC(a,"object-cover")||!a.getAttribute("data-srcset")&&!a.srcset&&a.offsetHeight>a.offsetWidth&&1<d(a)?"img-crop":"img",(a=l(n,i,r,a,t))&&n!=a&&(t&&e.setAttribute("src",a),e.setAttribute("data-src",a)))}var n=function(e,t){if(0===e.search(/\[/))return e;if(!o(t))return e;var a=y();a<eio_lazy_vars.bg_min_dpr&&(a=eio_lazy_vars.bg_min_dpr);var i=Math.round(t.offsetWidth*a),r=Math.round(t.offsetHeight*a),n="bg";h.hC(t,"wp-block-cover")||h.hC(t,"wp-block-cover__image-background")?(h.hC(t,"has-parallax")?(i=Math.round(u.screen.width*a),r=Math.round(u.screen.height*a)):r<300&&(r=430),n="bg-cover"):(h.hC(t,"cover-image")||h.hC(t,"elementor-bg")||h.hC(t,"et_parallax_bg")||h.hC(t,"bg-image-crop"))&&(n="bg-cover");var s=d(t);if("bg"==n&&1<r&&1<i&&0<s){a=Math.ceil(r*s),s=Math.ceil(i/s);i+2<a&&(i=a),r+2<s&&(r=s);t=p(t);if(Math.abs(t.w-i)<5||Math.abs(t.h-r)<5)return e}return e=l(e,i,r,n)},o=function(e){if(1==eio_lazy_vars.skip_autoscale)return!1;for(var t=e,a=0;a<=7;a++){if(t.hasAttributes())for(var i=t.attributes,r=/skip-autoscale/,a=i.length-1;0<=a;a--){if(r.test(i[a].name))return!1;if(r.test(i[a].value))return!1}if(!t.parentNode||1!==t.parentNode.nodeType||!t.parentNode.hasAttributes)break;t=t.parentNode}return!0},l=function(e,t,a,i,r=!1){if(null===e)return e;var n=/w=(\d+)/,s=/fit=(\d+),(\d+)/,o=/resize=(\d+),(\d+)/,l=decodeURIComponent(e);if(/\.svg(\?.+)?$/.exec(l))return e;if(0<e.search("\\?")&&0<e.search(eio_lazy_vars.exactdn_domain)){var d=o.exec(l);if(d&&(t<d[1]||r))return"img-w"===i?l.replace(o,"w="+t):"img-h"===i?l.replace(o,"h="+a):l.replace(o,"resize="+t+","+a);o=n.exec(e);if(o&&(t<=o[1]||r)){if("img-h"===i)return l.replace(n,"h="+a);if("bg-cover"!==i&&"img-crop"!==i)return e.replace(n,"w="+t);var c=Math.abs(o[1]-t);return 20<c||a<1080?e.replace(n,"resize="+t+","+a):e}c=s.exec(l);if(c&&(t<c[1]||r)){if("bg-cover"!==i&&"img-crop"!==i)return"img-w"===i?l.replace(s,"w="+t):"img-h"===i?l.replace(s,"h="+a):l.replace(s,"fit="+t+","+a);l=Math.abs(c[1]-t),s=Math.abs(c[2]-a);return 20<l||20<s?e.replace(n,"resize="+t+","+a):e}if(!o&&!c&&!d)return"img"===i?e+"&fit="+t+","+a:"bg-cover"===i||"img-crop"===i?e+"&resize="+t+","+a:"img-h"===i||t<a?e+"&h="+a:e+"&w="+t}return-1==e.search("\\?")&&0<e.search(eio_lazy_vars.exactdn_domain)?"img"===i?e+"?fit="+t+","+a:"bg-cover"===i||"img-crop"===i?e+"?resize="+t+","+a:"img-h"===i||t<a?e+"?h="+a:e+"?w="+t:e},m=function(e){e=/-(\d+)x(\d+)\./.exec(e);return e&&1<e[1]&&1<e[2]?{w:e[1],h:e[2]}:{w:0,h:0}},p=function(e){var t=e.dataset.eioRwidth,e=e.dataset.eioRheight;return 1<t&&1<e?{w:t,h:e}:{w:0,h:0}},d=function(e){var t=e.getAttribute("width"),a=e.getAttribute("height");if(1<t&&1<a)return t/a;a=!1;if(a=(a=e.src&&-1<e.src.search("http")?e.src:a)||e.getAttribute("data-src")){var i=m(a);if(i.w&&i.h)return i.w/i.h}i=p(e);if(i.w&&i.h)return i.w/i.h;e=function(e){var t;if(e.srcset?t=e.srcset.split(","):(e=e.getAttribute("data-srcset"))&&(t=e.split(",")),t){var a=0,i=t.length;if(i){for(;a<i;a++){var r,n=t[a].trim().split(" ");!n[0].length||(n=m(n[0])).w&&n.h&&(r=n)}if(r.w&&r.h)return r}}return{w:0,h:0}}(e);return e.w&&e.h?e.w/e.h:0},y=function(){return eio_lazy_vars.use_dpr&&1<u.devicePixelRatio?u.devicePixelRatio:1};f.addEventListener("lazybeforesizes",function(e){e.target.getAttribute("data-src");var t=d(e.target);1<e.target.clientHeight&&t&&(t=Math.ceil(t*e.target.clientHeight),e.detail.width+2<t&&(e.detail.width=t)),void 0!==e.target._lazysizesWidth&&e.detail.width<e.target._lazysizesWidth&&(e.detail.width=e.target._lazysizesWidth),!eio_lazy_vars.use_dpr&&1<u.devicePixelRatio&&(e.detail.width=Math.ceil(e.detail.width/u.devicePixelRatio))}),f.addEventListener("lazybeforeunveil",function(e){var t,a,i,r,n=e.target,s=n.getAttribute("data-srcset");n.naturalWidth&&!s&&1<n.naturalWidth&&1<n.naturalHeight&&(t=y(),a=n.naturalWidth,i=n.naturalHeight,(e=p(n)).w&&e.w>a&&(a=e.w,i=e.h),a=n.clientWidth&&1.25*n.clientWidth*t<a,i=n.clientHeight&&1.25*n.clientHeight*t<i,(a||i)&&g(n)),ewww_webp_supported&&(!s||(r=n.getAttribute("data-srcset-webp"))&&n.setAttribute("data-srcset",r),(r=n.getAttribute("data-src-webp"))&&n.setAttribute("data-src",r))});function e(e=!1){e.type&&"load"===e.type&&h.autoSizer.checkElems(),y();var t,a=f.getElementsByClassName(h.cfg.loadedClass),i=a.length;if(i)for(t=0;t<i;t++){var r,n,s,o,l,d,c=a[t];c.src&&!c.srcset&&1<c.naturalWidth&&1<c.naturalHeight&&1<c.clientWidth&&1<c.clientHeight&&(r=c.naturalWidth,n=c.naturalHeight,s=u.innerWidth,o=u.innerHeight,l=p(c),d=m(c.src),l.w?s=l.w:d.w&&(s=d.w),l.h?o=l.h:d.h&&(o=d.h),l=c.clientWidth,d=c.clientHeight,(1.1*r<l&&l<=s||1.1*n<d&&d<=o)&&g(c,!0))}}var t,a,i,s,c=(t=e,s=function(){a=null,t()},function(){i=Date.now(),a=a||setTimeout(v,99)});function v(){var e=Date.now()-i;e<99?setTimeout(v,99-e):(u.requestIdleCallback||s)(s)}addEventListener("load",e),addEventListener("resize",c),setTimeout(e,2e4)}),function(e,t){t=t(e,e.document,Date);e.lazySizes=t,"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:{},function(i,f,n){"use strict";var h,g;if(!function(){var e,t={lazyClass:"lazyload",loadedClass:"lazyloaded",loadingClass:"lazyloading",preloadClass:"lazypreload",errorClass:"lazyerror",autosizesClass:"lazyautosizes",fastLoadedClass:"ls-is-cached",iframeLoadMode:0,srcAttr:"data-src",srcsetAttr:"data-srcset",sizesAttr:"data-sizes",minSize:40,customMedia:{},init:!0,expFactor:1.5,hFac:.8,loadMode:2,loadHidden:!0,ricTimeout:0,throttleDelay:125};for(e in g=i.lazySizesConfig||i.lazysizesConfig||{},t)e in g||(g[e]=t[e])}(),!f||!f.getElementsByClassName)return{init:function(){},cfg:g,noSupport:!0};function c(e,t){E(e,t)||e.setAttribute("class",(e[y]("class")||"").trim()+" "+t)}function u(e,t){(t=E(e,t))&&e.setAttribute("class",(e[y]("class")||"").replace(t," "))}function m(e,t){var a;!l&&(a=i.picturefill||g.pf)?(t&&t.src&&!e[y]("srcset")&&e.setAttribute("srcset",t.src),a({reevaluate:!0,elements:[e]})):t&&t.src&&(e.src=t.src)}var a,r,t,s,o,p=f.documentElement,l=i.HTMLPictureElement,d="addEventListener",y="getAttribute",e=i[d].bind(i),v=i.setTimeout,z=i.requestAnimationFrame||v,b=i.requestIdleCallback,w=/^picture$/i,_=["load","error","lazyincluded","_lazyloaded"],C={},A=Array.prototype.forEach,E=function(e,t){return C[t]||(C[t]=new RegExp("(\\s|^)"+t+"(\\s|$)")),C[t].test(e[y]("class")||"")&&C[t]},L=function(t,a,e){var i=e?d:"removeEventListener";e&&L(t,a),_.forEach(function(e){t[i](e,a)})},x=function(e,t,a,i,r){var n=f.createEvent("Event");return(a=a||{}).instance=h,n.initEvent(t,!i,!r),n.detail=a,e.dispatchEvent(n),n},M=function(e,t){return(getComputedStyle(e,null)||{})[t]},N=function(e,t,a){for(a=a||e.offsetWidth;a<g.minSize&&t&&!e._lazysizesWidth;)a=t.offsetWidth,t=t.parentNode;return a},S=(s=[],o=t=[],k._lsFlush=W,k);function W(){var e=o;for(o=t.length?s:t,r=!(a=!0);e.length;)e.shift()();a=!1}function k(e,t){a&&!t?e.apply(this,arguments):(o.push(e),r||(r=!0,(f.hidden?v:z)(W)))}function H(a,e){return e?function(){S(a)}:function(){var e=this,t=arguments;S(function(){a.apply(e,t)})}}function R(e){function t(){var e=n.now()-i;e<99?v(t,99-e):(b||r)(r)}var a,i,r=function(){a=null,e()};return function(){i=n.now(),a=a||v(t,99)}}var I,j,T,O,q,B,P,F,J,D,$,U,G,K,Q,V,X,Y,Z,ee,te,ae,ie,re,ne,se,oe,le,de,ce,ue,fe=(Z=/^img$/i,ee=/^iframe$/i,te="onscroll"in i&&!/(gle|ing)bot/.test(navigator.userAgent),re=-1,ne=function(e){return(U=null==U?"hidden"==M(f.body,"visibility"):U)||!("hidden"==M(e.parentNode,"visibility")&&"hidden"==M(e,"visibility"))},G=ge,Q=ie=ae=0,V=g.throttleDelay,X=g.ricTimeout,Y=b&&49<X?function(){b(me,{timeout:X}),X!==g.ricTimeout&&(X=g.ricTimeout)}:H(function(){v(me)},!0),oe=H(pe),le=function(e){oe({target:e.target})},de=H(function(t,e,a,i,r){var n,s,o,l,d;(o=x(t,"lazybeforeunveil",e)).defaultPrevented||(i&&(a?c(t,g.autosizesClass):t.setAttribute("sizes",i)),n=t[y](g.srcsetAttr),a=t[y](g.srcAttr),r&&(s=(d=t.parentNode)&&w.test(d.nodeName||"")),l=e.firesLoad||"src"in t&&(n||a||s),o={target:t},c(t,g.loadingClass),l&&(clearTimeout(T),T=v(he,2500),L(t,le,!0)),s&&A.call(d.getElementsByTagName("source"),ye),n?t.setAttribute("srcset",n):a&&!s&&(ee.test(t.nodeName)?(i=a,0==(d=(e=t).getAttribute("data-load-mode")||g.iframeLoadMode)?e.contentWindow.location.replace(i):1==d&&(e.src=i)):t.src=a),r&&(n||s)&&m(t,{src:a})),t._lazyRace&&delete t._lazyRace,u(t,g.lazyClass),S(function(){var e=t.complete&&1<t.naturalWidth;l&&!e||(e&&c(t,g.fastLoadedClass),pe(o),t._lazyCache=!0,v(function(){"_lazyCache"in t&&delete t._lazyCache},9)),"lazy"==t.loading&&ie--},!0)}),ue=R(function(){g.loadMode=3,se()}),{_:function(){q=n.now(),h.elements=f.getElementsByClassName(g.lazyClass),I=f.getElementsByClassName(g.lazyClass+" "+g.preloadClass),e("scroll",se,!0),e("resize",se,!0),e("pageshow",function(e){var t;!e.persisted||(t=f.querySelectorAll("."+g.loadingClass)).length&&t.forEach&&z(function(){t.forEach(function(e){e.complete&&ce(e)})})}),i.MutationObserver?new MutationObserver(se).observe(p,{childList:!0,subtree:!0,attributes:!0}):(p[d]("DOMNodeInserted",se,!0),p[d]("DOMAttrModified",se,!0),setInterval(se,999)),e("hashchange",se,!0),["focus","mouseover","click","load","transitionend","animationend"].forEach(function(e){f[d](e,se,!0)}),/d$|^c/.test(f.readyState)?ze():(e("load",ze),f[d]("DOMContentLoaded",se),v(ze,2e4)),h.elements.length?(ge(),S._lsFlush()):se()},checkElems:se=function(e){var t;(e=!0===e)&&(X=33),K||(K=!0,(t=V-(n.now()-Q))<0&&(t=0),e||t<9?Y():v(Y,t))},unveil:ce=function(e){var t,a,i,r;e._lazyRace||(!(r="auto"==(i=(a=Z.test(e.nodeName))&&(e[y](g.sizesAttr)||e[y]("sizes"))))&&j||!a||!e[y]("src")&&!e.srcset||e.complete||E(e,g.errorClass)||!E(e,g.lazyClass))&&(t=x(e,"lazyunveilread").detail,r&&Ce.updateElem(e,!0,e.offsetWidth),e._lazyRace=!0,ie++,de(e,t,r,i,a))},_aLSL:ve});function he(e){ie--,e&&!(ie<0)&&e.target||(ie=0)}function ge(){var e,t,a,i,r,n,s,o,l,d,c,u=h.elements;if((O=g.loadMode)&&ie<8&&(e=u.length)){for(t=0,re++;t<e;t++)if(u[t]&&!u[t]._lazyRace)if(!te||h.prematureUnveil&&h.prematureUnveil(u[t]))ce(u[t]);else if((s=u[t][y]("data-expand"))&&(r=+s)||(r=ae),l||(l=!g.expand||g.expand<1?500<p.clientHeight&&500<p.clientWidth?500:370:g.expand,d=(h._defEx=l)*g.expFactor,c=g.hFac,U=null,ae<d&&ie<1&&2<re&&2<O&&!f.hidden?(ae=d,re=0):ae=1<O&&1<re&&ie<6?l:0),o!==r&&(B=innerWidth+r*c,P=innerHeight+r,n=-1*r,o=r),d=u[t].getBoundingClientRect(),($=d.bottom)>=n&&(F=d.top)<=P&&(D=d.right)>=n*c&&(J=d.left)<=B&&($||D||J||F)&&(g.loadHidden||ne(u[t]))&&(j&&ie<3&&!s&&(O<3||re<4)||function(e,t){var a,i=e,r=ne(e);for(F-=t,$+=t,J-=t,D+=t;r&&(i=i.offsetParent)&&i!=f.body&&i!=p;)(r=0<(M(i,"opacity")||1))&&"visible"!=M(i,"overflow")&&(a=i.getBoundingClientRect(),r=D>a.left&&J<a.right&&$>a.top-1&&F<a.bottom+1);return r}(u[t],r))){if(ce(u[t]),i=!0,9<ie)break}else!i&&j&&!a&&ie<4&&re<4&&2<O&&(I[0]||g.preloadAfterLoad)&&(I[0]||!s&&($||D||J||F||"auto"!=u[t][y](g.sizesAttr)))&&(a=I[0]||u[t]);a&&!i&&ce(a)}}function me(){K=!1,Q=n.now(),G()}function pe(e){var t=e.target;t._lazyCache?delete t._lazyCache:(he(e),c(t,g.loadedClass),u(t,g.loadingClass),L(t,le),x(t,"lazyloaded"))}function ye(e){var t,a=e[y](g.srcsetAttr);(t=g.customMedia[e[y]("data-media")||e[y]("media")])&&e.setAttribute("media",t),a&&e.setAttribute("srcset",a)}function ve(){3==g.loadMode&&(g.loadMode=2),ue()}function ze(){j||(n.now()-q<999?v(ze,999):(j=!0,g.loadMode=3,se(),e("scroll",ve,!0)))}var be,we,_e,Ce=(we=H(function(e,t,a,i){var r,n,s;if(e._lazysizesWidth=i,e.setAttribute("sizes",i+="px"),w.test(t.nodeName||""))for(n=0,s=(r=t.getElementsByTagName("source")).length;n<s;n++)r[n].setAttribute("sizes",i);a.detail.dataAttr||m(e,a.detail)}),{_:function(){be=f.getElementsByClassName(g.autosizesClass),e("resize",_e)},checkElems:_e=R(function(){var e,t=be.length;if(t)for(e=0;e<t;e++)Ae(be[e])}),updateElem:Ae});function Ae(e,t,a){var i=e.parentNode;i&&(a=N(e,i,a),(t=x(e,"lazybeforesizes",{width:a,dataAttr:!!t})).defaultPrevented||(a=t.detail.width)&&a!==e._lazysizesWidth&&we(e,i,t,a))}function Ee(){!Ee.i&&f.getElementsByClassName&&(Ee.i=!0,Ce._(),fe._())}return v(function(){g.init&&Ee()}),h={cfg:g,autoSizer:Ce,loader:fe,init:Ee,uP:m,aC:c,rC:u,hC:E,fire:x,gW:N,rAF:S}}); -
easy-image-optimizer/tags/4.3.0/phpcs.ruleset.xml
r3328397 r3398277 32 32 <element value="imgQuality"/> 33 33 <element value="parentNode"/> 34 <element value="nodeName"/> 34 35 <element value="nextSibling"/> 35 36 <element value="documentElement"/> -
easy-image-optimizer/tags/4.3.0/readme.txt
r3350722 r3398277 2 2 Contributors: nosilver4u 3 3 Tags: image, resize, webp, lazy load, compress 4 Tested up to: 6. 85 Stable tag: 4. 2.14 Tested up to: 6.9 5 Stable tag: 4.3.0 6 6 License: GPLv3 7 7 … … 56 56 * If you would like to help translate this plugin in your language, get started here: https://translate.wordpress.org/projects/wp-plugins/easy-image-optimizer/ 57 57 58 = 4.3.0 = 59 *Release Date - November 18, 2025* 60 61 * added: Lazy Load support for background images in external CSS files 62 * added: View CDN bandwidth usage on settings page 63 * changed: Lazy Load checks parent element for skip-lazy class 64 * changed: Lazy Load auto-sizing honors High DPI setting 65 * changed: Easy IO fills in 450px wide image when responsive (srcset) images have a gap 66 * improved: Lazy Load performance when searching for img elements 67 * improved: Lazy Load placeholder generation is faster and works better with Safari 68 * fixed: Lazy Load for iframes breaks WP Remote Users Sync plugin 69 58 70 = 4.2.1 = 59 71 *Release Date - August 26, 2025* -
easy-image-optimizer/trunk/changelog.txt
r3350722 r3398277 1 = 4.3.0 = 2 *Release Date - November 18, 2025* 3 4 * added: Lazy Load support for background images in external CSS files 5 * added: View CDN bandwidth usage on settings page 6 * changed: Lazy Load checks parent element for skip-lazy class 7 * changed: Lazy Load auto-sizing honors High DPI setting 8 * changed: Easy IO fills in 450px wide image when responsive (srcset) images have a gap 9 * improved: Lazy Load performance when searching for img elements 10 * improved: Lazy Load placeholder generation is faster and works better with Safari 11 * fixed: Lazy Load for iframes breaks WP Remote Users Sync plugin 12 1 13 = 4.2.1 = 2 14 *Release Date - August 26, 2025* -
easy-image-optimizer/trunk/classes/class-base.php
r3328397 r3398277 327 327 if ( $this->is_iterable( $potential_logs ) ) { 328 328 foreach ( $potential_logs as $potential_log ) { 329 if ( $this->str_ends_with( $potential_log, '.log' ) && false !== strpos( $potential_log, strtolower( __NAMESPACE__ ) . '-debug-' ) && is_file( $this->content_dir . $potential_log ) ) {329 if ( \str_ends_with( $potential_log, '.log' ) && false !== strpos( $potential_log, strtolower( __NAMESPACE__ ) . '-debug-' ) && is_file( $this->content_dir . $potential_log ) ) { 330 330 return $this->content_dir . $potential_log; 331 331 } … … 1349 1349 1350 1350 /** 1351 * Performs a case-sensitive check indicating if 1352 * the haystack ends with needle. 1353 * 1354 * @param string $haystack The string to search in. 1355 * @param string $needle The substring to search for in the `$haystack`. 1356 * @return bool True if `$haystack` ends with `$needle`, otherwise false. 1357 */ 1358 public function str_ends_with( $haystack, $needle ) { 1359 if ( '' === $haystack && '' !== $needle ) { 1360 return false; 1361 } 1362 1363 $len = \strlen( $needle ); 1364 1365 return 0 === \substr_compare( $haystack, $needle, -$len, $len ); 1351 * Wrapper around size_format to remove the decimal from sizes in bytes. 1352 * 1353 * @param int $size A filesize in bytes. 1354 * @param int $precision Number of places after the decimal separator. 1355 * @return string Human-readable filesize. 1356 */ 1357 public function size_format( $size, $precision = 1 ) { 1358 // Convert it to human readable format. 1359 $size_str = \size_format( $size, $precision ); 1360 // Remove spaces and extra decimals when measurement is in bytes. 1361 return \preg_replace( '/\.0+ B ?/', ' B', $size_str ); 1366 1362 } 1367 1363 … … 1633 1629 return false; 1634 1630 } 1635 if ( 0 === \strpos( $url, '//' ) ) {1631 if ( \str_starts_with( $url, '//' ) ) { 1636 1632 $url = ( \is_ssl() ? 'https:' : 'http:' ) . $url; 1637 1633 } 1638 if ( false === \strpos( $url, 'http' ) && '/' !== \substr( $url, 0, 1) ) {1634 if ( ! \str_starts_with( $url, 'http' ) && ! \str_starts_with( $url, '/' ) && ! \str_starts_with( $url, '.' ) ) { 1639 1635 $url = ( \is_ssl() ? 'https://' : 'http://' ) . $url; 1640 1636 } -
easy-image-optimizer/trunk/classes/class-exactdn.php
r3350722 r3398277 65 65 */ 66 66 public $full_width = false; 67 68 /** 69 * Indicates the local domain has changed, and Easy IO should be re-initialized. 70 * 71 * @access public 72 * @var bool $domain_mismatch 73 */ 74 public $domain_mismatch = false; 67 75 68 76 /** … … 399 407 \add_filter( 'autoptimize_filter_cssjs_multidomain', array( $this, 'add_cdn_domain' ) ); 400 408 401 if ( $this->is_as3cf_cname_active() ) { 402 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_as3cf_cname_active' ); 403 return; 404 } 409 \add_action( 'admin_notices', array( $this, 'admin_notices' ) ); 405 410 406 411 $upload_url_parts = $this->parse_url( $this->site_url ); … … 414 419 $this->set_exactdn_option( 'local_domain', \base64_encode( $this->upload_domain ) ); 415 420 $stored_local_domain = $this->upload_domain; 416 } elseif ( false !== \strpos( $stored_local_domain, '.' ) ) {421 } elseif ( \str_contains( $stored_local_domain, '.' ) ) { 417 422 $this->set_exactdn_option( 'local_domain', \base64_encode( $stored_local_domain ) ); 418 } else { 419 $stored_local_domain = \base64_decode( $stored_local_domain ); 420 } 421 $this->debug_message( "saved domain is $stored_local_domain" ); 423 } 424 $this->debug_message( "saved (local) domain is $stored_local_domain" ); 422 425 423 426 $this->debug_message( "allowing images from here: $this->upload_domain" ); … … 433 436 $this->debug_message( "removing this from urls: $this->remove_path" ); 434 437 } 435 if (436 $stored_local_domain !== $this->upload_domain &&437 ! $this->allow_image_domain( $stored_local_domain ) &&438 \is_admin()439 ) {440 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_domain_mismatch' );441 }442 438 $this->allowed_domains[] = $this->exactdn_domain; 443 439 $this->allowed_domains = \apply_filters( 'exactdn_allowed_domains', $this->allowed_domains ); … … 500 496 */ 501 497 public function cron_setup( $schedule = true ) { 502 $this->debug_message( '<b>' . __ FUNCTION__ . '()</b>' );498 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 503 499 $event = 'easyio_verification_checkin'; 504 500 // Setup scheduled optimization if the user has enabled it, and it isn't already scheduled. … … 530 526 531 527 /** 528 * Sends the useragent through filters for http requests to the EWWW IO API. 529 * 530 * @param string $useragent The current useragent used in http requests. 531 * @return string The filtered useragent. 532 */ 533 public function api_useragent( $useragent ) { 534 return apply_filters( 'exactdn_api_request_useragent', $useragent ); 535 } 536 537 /** 532 538 * Use the Site URL to get the zone domain. 533 539 */ … … 538 544 global $exactdn_activate_error; 539 545 $exactdn_activate_error = 'as3cf_cname_active'; 540 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_as3cf_cname_active' );541 546 return false; 542 547 } … … 548 553 $url = \set_url_scheme( $url, 'https' ); 549 554 } 550 \add_filter( 'http_headers_useragent', $this->prefix . 'cloud_useragent', PHP_INT_MAX );555 \add_filter( 'http_headers_useragent', array( $this, 'api_useragent' ), PHP_INT_MAX ); 551 556 $result = \wp_remote_post( 552 557 $url, … … 564 569 global $exactdn_activate_error; 565 570 $exactdn_activate_error = $error_message; 566 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_activation_error' );567 571 return false; 568 572 } elseif ( ! empty( $result['body'] ) && \strpos( $result['body'], 'domain' ) !== false ) { … … 583 587 if ( \get_option( 'exactdn_never_been_active' ) ) { 584 588 $this->set_option( $this->prefix . 'lazy_load', true ); 585 $this->set_option( 'exactdn_lossy', true );586 589 $this->set_option( 'exactdn_all_the_things', true ); 587 590 \delete_option( 'exactdn_never_been_active' ); … … 598 601 global $exactdn_activate_error; 599 602 $exactdn_activate_error = $error_message; 600 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_activation_error' );601 603 return false; 602 604 } … … 649 651 $test_url = \str_replace( $local_domain, $domain, $test_url ); 650 652 $this->debug_message( "test url is $test_url" ); 651 \add_filter( 'http_headers_useragent', $this->prefix . 'cloud_useragent', PHP_INT_MAX );653 \add_filter( 'http_headers_useragent', array( $this, 'api_useragent' ), PHP_INT_MAX ); 652 654 $test_result = \wp_remote_post( 653 655 $api_url, … … 665 667 $this->debug_message( "exactdn (1) verification request failed: $error_message" ); 666 668 $exactdn_activate_error = $error_message; 667 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_activation_error' );668 669 return false; 669 } elseif ( ! empty( $test_result['body'] ) && false === \strpos( $test_result['body'], 'error' ) ) {670 } elseif ( ! empty( $test_result['body'] ) && ! \str_contains( $test_result['body'], 'error' ) ) { 670 671 $response = \json_decode( $test_result['body'], true ); 671 672 if ( ! empty( $response['success'] ) ) { … … 677 678 $this->asset_domains = $response['asset_domains']; 678 679 } 679 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_activation_success' );680 680 return true; 681 681 } … … 689 689 \delete_site_option( $this->prefix . 'exactdn_domain' ); 690 690 } 691 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_activation_error' );692 691 return false; 693 692 } … … 695 694 $this->debug_message( 'received response code: ' . $test_result['response']['code'] ); 696 695 } 697 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_activation_error' );698 696 return false; 699 697 } 700 698 701 699 // Secondary test against the API db. 702 \add_filter( 'http_headers_useragent', $this->prefix . 'cloud_useragent', PHP_INT_MAX );700 \add_filter( 'http_headers_useragent', array( $this, 'api_useragent' ), PHP_INT_MAX ); 703 701 $result = \wp_remote_post( 704 702 $api_url, … … 715 713 $this->debug_message( "exactdn verification request failed: $error_message" ); 716 714 $exactdn_activate_error = $error_message; 717 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_activation_error' );718 715 return false; 719 } elseif ( ! empty( $result['body'] ) && false === \strpos( $result['body'], 'error' ) ) {716 } elseif ( ! empty( $result['body'] ) && ! \str_contains( $result['body'], 'error' ) ) { 720 717 $response = \json_decode( $result['body'], true ); 721 718 if ( ! empty( $response['success'] ) ) { … … 730 727 $this->debug_message( 'exactdn verification via API succeeded' ); 731 728 $this->set_exactdn_option( 'verified', 1, false ); 732 if ( empty( $last_checkin ) ) {733 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_activation_success' );734 }735 729 return true; 736 730 } … … 744 738 \delete_site_option( $this->prefix . 'exactdn_domain' ); 745 739 } 746 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_activation_error' );747 740 return false; 748 741 } … … 750 743 $this->debug_message( 'received response code: ' . $result['response']['code'] ); 751 744 } 752 \add_action( 'admin_notices', $this->prefix . 'notice_exactdn_activation_error' );753 745 return false; 754 746 } … … 762 754 // Prelim test with a known valid image to ensure http(s) connectivity. 763 755 $sim_url = 'https://optimize.exactdn.com/exactdn/testorig.jpg'; 764 \add_filter( 'http_headers_useragent', $this->prefix . 'cloud_useragent', PHP_INT_MAX );756 \add_filter( 'http_headers_useragent', array( $this, 'api_useragent' ), PHP_INT_MAX ); 765 757 $sim_result = \wp_remote_get( $sim_url ); 766 758 if ( \is_wp_error( $sim_result ) ) { … … 900 892 } 901 893 return \update_option( $this->prefix . 'exactdn_' . $option_name, $option_value, $autoload ); 894 } 895 896 /** 897 * Check for conditions that need to trigger an admin notice (action). 898 */ 899 public function admin_notices() { 900 if ( $this->is_as3cf_cname_active() ) { 901 \do_action( 'exactdn_as3cf_cname_active' ); 902 } 903 $stored_local_domain = $this->get_exactdn_option( 'local_domain' ); 904 $stored_local_domain = \base64_decode( $stored_local_domain ); 905 if ( 906 $stored_local_domain !== $this->upload_domain && 907 ! $this->allow_image_domain( $stored_local_domain ) 908 ) { 909 $this->domain_mismatch = true; 910 \do_action( 'exactdn_domain_mismatch' ); 911 } 902 912 } 903 913 … … 2952 2962 * @param array|bool $multipliers Array of multipliers to use or false to bypass. 2953 2963 */ 2954 $multipliers = \apply_filters( 'exactdn_srcset_multipliers', array( .2, .4, .6, .8, 1 ) );2964 $multipliers = \apply_filters( 'exactdn_srcset_multipliers', array( .2, .4, .6, .8, 1, 450 ) ); 2955 2965 2956 2966 if ( empty( $url ) || empty( $multipliers ) ) { … … 3039 3049 3040 3050 $newwidth = \intval( $base * $multiplier ); 3041 if ( 1920 === (int) $multiplier ) {3042 $newwidth = 1920;3043 if ( ! $w_descriptor || 1920>= $reqwidth || 'soft' !== $crop ) {3051 if ( $multiplier > 50 ) { // Not a true multiplier, but a hard-coded width. 3052 $newwidth = $multiplier; 3053 if ( ! $w_descriptor || $multiplier >= $reqwidth || 'soft' !== $crop ) { 3044 3054 $this->debug_message( "skipping $multiplier due to no w descriptor, larger than $reqwidth, or $crop !== soft" ); 3045 3055 continue; … … 3150 3160 * @param array|bool $multipliers Array of multipliers to use or false to bypass. 3151 3161 */ 3152 $multipliers = \apply_filters( 'exactdn_srcset_multipliers', array( .2, .4, .6, .8, 1 ) );3162 $multipliers = \apply_filters( 'exactdn_srcset_multipliers', array( .2, .4, .6, .8, 1, 450 ) ); 3153 3163 /** 3154 3164 * Filter the width ExactDN will use to create srcset attribute. … … 3175 3185 foreach ( $multipliers as $multiplier ) { 3176 3186 $newwidth = \intval( $width * $multiplier ); 3177 if ( 1920 === (int) $multiplier ) {3187 if ( $multiplier > 50 ) { // Not a true multiplier, but a hard-coded width. 3178 3188 if ( $multiplier >= $width ) { 3179 3189 continue; 3180 3190 } 3181 $newwidth = 1920;3191 $newwidth = $multiplier; 3182 3192 } 3183 3193 if ( $newwidth < 50 ) { … … 3569 3579 if ( $this->get_option( 'exactdn_hidpi' ) ) { 3570 3580 $this->debug_message( 'adding hidpi multipliers' ); 3571 return array( .2, .4, .6, .8, 1, 2, 3, 1920 ); 3581 $multipliers[] = 2; 3582 $multipliers[] = 3; 3583 $multipliers[] = 1920; 3572 3584 } 3573 3585 return $multipliers; … … 4317 4329 4318 4330 $more_args = array(); 4319 if ( false === \strpos( $image_url, 'strip=all' ) && $this->get_option( $this->prefix . 'metadata_remove' ) ) {4331 if ( ! \str_contains( $image_url, 'strip=all' ) && $this->get_option( $this->prefix . 'metadata_remove' ) ) { 4320 4332 $more_args['strip'] = 'all'; 4321 4333 } … … 4325 4337 } elseif ( isset( $args['lossy'] ) && false !== \strpos( $image_url, 'lossy=0' ) ) { 4326 4338 unset( $args['lossy'] ); 4327 } elseif ( false === \strpos( $image_url, 'lossy=' ) && ! $this->get_option( 'exactdn_lossy' ) ) {4328 $more_args['lossy'] = 0;4329 } elseif ( false === \strpos( $image_url, 'lossy=' ) && $this->get_option( 'exactdn_lossy' ) ) {4330 $more_args['lossy'] = \is_numeric( $this->get_option( 'exactdn_lossy' ) ) ? (int) $this->get_option( 'exactdn_lossy' ) : 1;4331 4339 } 4332 4340 if ( false === \strpos( $image_url, 'quality=' ) && ! \is_null( $jpg_quality ) && 82 !== (int) $jpg_quality ) { … … 4376 4384 4377 4385 if ( isset( $image_url_parts['scheme'] ) && 'https' === $image_url_parts['scheme'] ) { 4378 if ( \is_array( $args ) && false === \strpos( $image_url, 'ssl=' ) ) {4379 $this->debug_message( 'adding ssl=1' );4380 $args['ssl'] = 1;4381 }4382 4386 $this->debug_message( 'setting scheme to https' ); 4383 4387 $scheme = 'https'; … … 4397 4401 foreach ( $args as $arg => $value ) { 4398 4402 if ( \is_array( $value ) ) { 4399 $args[ $arg ] = \implode( ',', $value ); 4403 $value = \implode( ',', $value ); 4404 $args[ $arg ] = $value; 4400 4405 } 4401 4406 } … … 4566 4571 $url = \set_url_scheme( $url, 'https' ); 4567 4572 } 4568 \add_filter( 'http_headers_useragent', $this->prefix . 'cloud_useragent', PHP_INT_MAX );4573 \add_filter( 'http_headers_useragent', array( $this, 'api_useragent' ), PHP_INT_MAX ); 4569 4574 $result = \wp_remote_post( 4570 4575 $url, -
easy-image-optimizer/trunk/classes/class-hs-beacon.php
r3035873 r3398277 101 101 return; 102 102 } 103 if ( \strpos( __FILE__, 'plugins/easy' ) ) { 104 \easyio_notice_beacon(); 105 } 103 \do_action( strtolower( __NAMESPACE__ ) . '_beacon_notice' ); 106 104 } 107 105 } -
easy-image-optimizer/trunk/classes/class-lazy-load.php
r3328397 r3398277 96 96 97 97 /** 98 * A list of image tags/sections where lazy loading should not be applied. 99 * 100 * @access private 101 * @var array $forbidden_blocks 102 */ 103 private $forbidden_blocks = array(); 104 105 /** 98 106 * Request URI. 99 107 * … … 101 109 */ 102 110 public $request_uri = ''; 111 112 /** 113 * DOM Document for parsing HTML. 114 * 115 * @var \DOMDocument $doc 116 */ 117 private $doc; 118 119 /** 120 * List of img nodes from the DOMDocument. 121 * 122 * @var \DOMNodeList $img_nodes 123 */ 124 private $img_nodes; 103 125 104 126 /** … … 198 220 \add_action( 'wp_enqueue_scripts', array( $this, 'min_script' ), 1 ); 199 221 } 222 223 // Allow other plugins to get the background image exclusions via filter. 224 \add_filter( 'eio_get_lazy_bg_image_exclusions', array( $this, 'get_bgimage_exclusions' ), 10 ); 225 200 226 $this->inline_script_attrs = (array) \apply_filters( 'ewwwio_inline_script_attrs', $this->inline_script_attrs ); 201 227 $this->validate_user_exclusions(); … … 354 380 355 381 /** 382 * Check if an img/iframe tag should be excluded because it falls within a forbidden block. 383 * 384 * @param string $tag The img or iframe tag to check. 385 * @param int $position The position of the tag within the HTML. 386 * @return bool True if it is within a forbidden block, false otherwise. 387 */ 388 private function is_in_forbidden_block( $tag, $position ) { 389 if ( empty( $tag ) || empty( $position ) ) { 390 return false; 391 } 392 if ( $this->is_iterable( $this->forbidden_blocks ) ) { 393 foreach ( $this->forbidden_blocks as $forbidden_block ) { 394 if ( empty( $forbidden_block[0] ) || empty( $forbidden_block[1] ) ) { 395 continue; 396 } 397 $start = $forbidden_block[1]; 398 $end = $start + \strlen( $forbidden_block[0] ); 399 if ( $position > $start && $position < $end ) { 400 $this->debug_message( 'tag is within a forbidden block' ); 401 return true; 402 } 403 } 404 } 405 } 406 407 /** 356 408 * Search for img elements and rewrite them for Lazy Load with fallback to noscript elements. 357 409 * … … 391 443 } 392 444 445 $started_time = \microtime( true ); 393 446 $above_the_fold = (int) \apply_filters( 'eio_lazy_fold', $this->get_option( $this->prefix . 'll_abovethefold' ) ); 394 447 $images_processed = 0; 395 448 $replacements = array(); 396 449 397 // Clean the buffer of incompatible sections. 398 $search_buffer = \preg_replace( '/<div id="footer_photostream".*?\/div>/s', '', $buffer ); 399 $search_buffer = \preg_replace( '/<(picture|noscript|script).*?\/\1>/s', '', $search_buffer ); 400 401 $images = $this->get_images_from_html( $search_buffer, false ); 450 // Find all incompatible sections, and store them with their offsets. 451 $this->forbidden_blocks = array(); 452 \preg_match_all( '/<div id="footer_photostream".*?\/div>/s', $buffer, $forbidden_blocks, PREG_OFFSET_CAPTURE ); 453 \preg_match_all( '/<(picture|noscript|script).*?\/\1>/s', $buffer, $more_forbidden_blocks, PREG_OFFSET_CAPTURE ); 454 if ( ! empty( $forbidden_blocks[0] ) && ! empty( $more_forbidden_blocks[0] ) ) { 455 $forbidden_blocks[0] = \array_merge( $forbidden_blocks[0], $more_forbidden_blocks[0] ); 456 } elseif ( ! empty( $more_forbidden_blocks[0] ) ) { 457 $forbidden_blocks = $more_forbidden_blocks; 458 } 459 $this->forbidden_blocks = ! empty( $forbidden_blocks[0] ) ? $forbidden_blocks[0] : array(); 460 461 $this->doc = new \DOMDocument(); 462 libxml_use_internal_errors( true ); 463 $this->doc->loadHTML( $buffer ); 464 libxml_clear_errors(); 465 $this->img_nodes = $this->doc->getElementsByTagName( 'img' ); 466 467 $images = $this->get_images_from_html( $buffer, false, true, PREG_OFFSET_CAPTURE ); 402 468 if ( ! empty( $images[0] ) && $this->is_iterable( $images[0] ) ) { 403 469 foreach ( $images[0] as $index => $image ) { 404 $file = $images['img_url'][ $index ] ;470 $file = $images['img_url'][ $index ][0]; 405 471 $this->debug_message( "parsing an image: $file" ); 406 if ( $this->validate_image_tag( $image ) ) { 472 if ( empty( $image[0] ) || empty( $image[1] ) ) { 473 $this->debug_message( 'missing image tag or position' ); 474 continue; 475 } 476 $image_tag = $image[0]; 477 $position = $image[1]; 478 if ( $this->is_in_forbidden_block( $image_tag, $position ) ) { 479 continue; 480 } 481 if ( $this->validate_image_tag( $image_tag ) ) { 407 482 $this->debug_message( 'found a valid image tag' ); 408 $this->debug_message( "original image tag: $image " );409 $orig_img = $image;410 $ns_img = $image;411 $image = $this->parse_img_tag( $image, $file );483 $this->debug_message( "original image tag: $image_tag" ); 484 $orig_img = $image_tag; 485 $ns_img = $image_tag; 486 $image_tag = $this->parse_img_tag( $image_tag, $file ); 412 487 $this->set_attribute( $ns_img, 'data-eio', 'l', true ); 413 488 $noscript = '<noscript>' . $ns_img . '</noscript>'; 414 $position = \strpos( $buffer, $orig_img );415 if ( $position && $orig_img !== $image ) {489 if ( $position && $orig_img !== $image_tag ) { 490 $this->debug_message( "lazified image at position $position" ); 416 491 $replacements[ $position ] = array( 417 492 'orig' => $orig_img, 418 'lazy' => $image . $noscript,493 'lazy' => $image_tag . $noscript, 419 494 ); 420 495 } 421 /* $buffer = str_replace( $orig_img, $image . $noscript, $buffer ); */422 496 } 423 497 } // End foreach(). 424 498 } // End if(). 499 425 500 $element_types = \apply_filters( 'eio_allowed_background_image_elements', array( 'div', 'li', 'span', 'section', 'a' ) ); 426 501 foreach ( $element_types as $element_type ) { … … 435 510 } 436 511 } 512 437 513 if ( \in_array( 'picture', $this->user_element_exclusions, true ) ) { 438 514 $pictures = ''; 439 515 } else { 440 516 // Images listed as picture/source elements. Mostly for NextGEN, but should work anywhere. 441 $pictures = $this->get_picture_tags_from_html( $buffer );517 $pictures = $this->get_picture_tags_from_html( $buffer, PREG_OFFSET_CAPTURE ); 442 518 } 443 519 if ( $this->is_iterable( $pictures ) ) { 444 520 foreach ( $pictures as $index => $picture ) { 445 if ( ! $this->validate_image_tag( $picture ) ) { 446 continue; 447 } 448 $pimages = $this->get_images_from_html( $picture, false ); 521 if ( empty( $picture[0] ) || empty( $picture[1] ) ) { 522 $this->debug_message( 'missing picture tag or position' ); 523 continue; 524 } 525 $picture_tag = $picture[0]; 526 $position = $picture[1]; 527 if ( ! $this->validate_image_tag( $picture_tag ) ) { 528 continue; 529 } 530 $pimages = $this->get_images_from_html( $picture_tag, false ); 449 531 if ( ! empty( $pimages[0] ) && $this->is_iterable( $pimages[0] ) && ! empty( $pimages[0][0] ) ) { 450 532 $image = $pimages[0][0]; … … 458 540 $image = $this->parse_img_tag( $image, $file ); 459 541 $this->set_attribute( $ns_img, 'data-eio', 'l', true ); 460 $noscript = '<noscript>' . $ns_img . '</noscript>';461 $picture = \str_replace( $orig_img, $image, $picture) . $noscript;542 $noscript = '<noscript>' . $ns_img . '</noscript>'; 543 $picture_tag = \str_replace( $orig_img, $image, $picture_tag ) . $noscript; 462 544 } 463 545 } else { 464 546 continue; 465 547 } 466 $sources = $this->get_elements_from_html( $picture , 'source' );548 $sources = $this->get_elements_from_html( $picture_tag, 'source' ); 467 549 if ( $this->is_iterable( $sources ) ) { 468 550 foreach ( $sources as $source ) { … … 477 559 $this->set_attribute( $lazy_source, 'data-srcset', $srcset ); 478 560 $this->remove_attribute( $lazy_source, 'srcset' ); 479 $picture = \str_replace( $source, $lazy_source, $picture);561 $picture_tag = \str_replace( $source, $lazy_source, $picture_tag ); 480 562 } 481 563 } 482 $position = \strpos( $buffer, $pictures[ $index ] ); 483 if ( $position && $picture !== $pictures[ $index ] ) { 564 if ( $position && $picture_tag !== $pictures[ $index ][0] ) { 484 565 $this->debug_message( 'lazified sources for picture element' ); 485 566 $replacements[ $position ] = array( 486 'orig' => $pictures[ $index ] ,487 'lazy' => $picture ,567 'orig' => $pictures[ $index ][0], 568 'lazy' => $picture_tag, 488 569 ); 489 /* $buffer = str_replace( $pictures[ $index ], $picture, $buffer ); */490 }491 }492 }493 } 570 } 571 } 572 } 573 } 574 494 575 // Iframe elements, looking for stuff like YouTube embeds. 495 576 if ( \in_array( 'iframe', $this->user_element_exclusions, true ) ) { 496 577 $frames = ''; 497 578 } else { 498 $frames = $this->get_elements_from_html( $ search_buffer, 'iframe');579 $frames = $this->get_elements_from_html( $buffer, 'iframe', PREG_OFFSET_CAPTURE ); 499 580 } 500 581 if ( $this->is_iterable( $frames ) ) { 501 foreach ( $frames as $index => $frame ) { 582 foreach ( $frames as $index => $frame_data ) { 583 if ( empty( $frame_data[0] ) || empty( $frame_data[1] ) ) { 584 $this->debug_message( 'missing iframe tag or position' ); 585 continue; 586 } 502 587 $this->debug_message( 'parsing an iframe element' ); 588 $frame = $frame_data[0]; 589 $position = $frame_data[1]; 590 if ( $this->is_in_forbidden_block( $frame, $position ) ) { 591 continue; 592 } 503 593 $url = $this->get_attribute( $frame, 'src' ); 504 594 if ( $url && 0 === \strpos( $url, 'http' ) && $this->validate_iframe_tag( $frame ) ) { … … 507 597 $this->remove_attribute( $frame, 'src' ); 508 598 $this->set_attribute( $frame, 'class', \trim( $this->get_attribute( $frame, 'class' ) . ' lazyload' ), true ); 509 if ( $frame !== $frames[ $index ] ) { 510 $buffer = \str_replace( $frames[ $index ], $frame, $buffer ); 511 } 512 } 513 } 514 } 599 if ( $frame !== $frames[ $index ][0] ) { 600 $buffer = \str_replace( $frames[ $index ][0], $frame, $buffer ); 601 } 602 } 603 } 604 } 605 515 606 if ( $this->is_iterable( $replacements ) ) { 516 607 \ksort( $replacements ); … … 534 625 } 535 626 } 536 $this->debug_message( 'all done parsing page for lazy' ); 627 628 $elapsed_time = \microtime( true ) - $started_time; 629 $this->debug_message( "all done parsing page for lazy in $elapsed_time seconds" ); 537 630 return $buffer; 538 631 } … … 796 889 return $replacements; 797 890 } 798 $elements = $this->get_elements_from_html( \preg_replace( '/<(noscript|script).*?\/\1>/s', '', $buffer ), $tag_type);891 $elements = $this->get_elements_from_html( $buffer, $tag_type, PREG_OFFSET_CAPTURE ); 799 892 if ( $this->is_iterable( $elements ) ) { 800 foreach ( $elements as $index => $element ) { 893 foreach ( $elements as $index => $element_data ) { 894 if ( empty( $element_data[0] ) || empty( $element_data[1] ) ) { 895 $this->debug_message( 'missing element or position' ); 896 continue; 897 } 898 $element = $element_data[0]; 899 $position = $element_data[1]; 900 if ( $this->is_in_forbidden_block( $element, $position ) ) { 901 continue; 902 } 801 903 $this->debug_message( "parsing a $tag_type" ); 802 if ( false === \strpos( $element, 'background:' ) && false === \strpos( $element, 'background-image:' ) ) {904 if ( ! \str_contains( $element, 'background:' ) && ! \str_contains( $element, 'background-image:' ) ) { 803 905 $element = $this->lazify_element( $element ); 804 if ( $element !== $elements[ $index ] ) {906 if ( $element !== $elements[ $index ][0] ) { 805 907 $this->debug_message( "$tag_type lazified, replacing in html source" ); 806 $buffer = \str_replace( $elements[ $index ] , $element, $buffer );807 } 808 continue; 809 } 810 if ( false !== \strpos( $element, '--background' ) ) {908 $buffer = \str_replace( $elements[ $index ][0], $element, $buffer ); 909 } 910 continue; 911 } 912 if ( \str_contains( $element, '--background' ) ) { 811 913 $this->set_attribute( $element, 'class', $this->get_attribute( $element, 'class' ) . ' lazyload', true ); 812 if ( $element !== $elements[ $index ] ) {914 if ( $element !== $elements[ $index ][0] ) { 813 915 $this->debug_message( "$tag_type with bg var lazified, replacing in html source" ); 814 $buffer = \str_replace( $elements[ $index ] , $element, $buffer );916 $buffer = \str_replace( $elements[ $index ][0], $element, $buffer ); 815 917 } 816 918 continue; … … 853 955 } 854 956 } elseif ( ! empty( $bg_image_urls[0] ) ) { 957 list( $physical_width, $physical_height ) = $this->get_image_dimensions_by_url( $bg_image_urls[0] ); 958 $this->set_attribute( $element, 'data-back', $bg_image_urls[0] ); 959 if ( $physical_width && $physical_height ) { 960 $this->set_attribute( $element, 'data-eio-rwidth', $physical_width, true ); 961 $this->set_attribute( $element, 'data-eio-rheight', $physical_height, true ); 962 } 855 963 $webp_image_url = \apply_filters( 'eio_image_url_to_webp', $bg_image_urls[0] ); 856 $this->set_attribute( $element, 'data-back', $bg_image_urls[0] );857 964 if ( $webp_image_url && $webp_image_url !== $bg_image_urls[0] ) { 858 965 $this->set_attribute( $element, 'data-back-webp', $webp_image_url ); … … 862 969 } 863 970 } 864 $position = \strpos( $buffer, $elements[ $index ] ); 865 if ( $position && $element !== $elements[ $index ] ) { 971 if ( $position && $element !== $elements[ $index ][0] ) { 866 972 $this->debug_message( "$tag_type modified, replacing in html source" ); 867 973 $replacements[ $position ] = array( 868 'orig' => $elements[ $index ] ,974 'orig' => $elements[ $index ][0], 869 975 'lazy' => $element, 870 976 ); 871 /* $buffer = str_replace( $elements[ $index ], $element, $buffer ); */872 977 } 873 978 } … … 1018 1123 1019 1124 /** 1125 * Normalize HTML for comparison. 1126 * 1127 * @param string $html The HTML to normalize. 1128 * @return string The normalized HTML. 1129 */ 1130 public function normalize_html( $html ) { 1131 $html = str_replace( '&', '&', $html ); 1132 $html = str_replace( '&', '&', $html ); 1133 $html = str_replace( '%2C', ',', $html ); 1134 $html = str_replace( ' />', '>', $html ); 1135 $html = str_replace( "'", '"', $html ); 1136 $html = preg_replace( '/\s\s+/', ' ', $html ); 1137 $html = preg_replace( '/\s*=\s*/', '=', $html ); 1138 return $html; 1139 } 1140 1141 /** 1020 1142 * Checks if the tag is allowed to be lazy loaded. 1021 1143 * … … 1056 1178 } 1057 1179 } 1058 1180 // Check for exclusions. 1059 1181 $exclusions = \apply_filters( 1060 1182 'eio_lazy_exclusions', … … 1089 1211 ), 1090 1212 $this->user_exclusions 1091 ), 1092 $image 1213 ) 1093 1214 ); 1094 1215 foreach ( $exclusions as $exclusion ) { … … 1106 1227 } 1107 1228 } 1229 1230 foreach ( $this->img_nodes as $img_node ) { 1231 $img_html = $this->doc->saveHTML( $img_node ); 1232 if ( defined( 'EIO_IMGNODE_DEBUG' ) && EIO_IMGNODE_DEBUG ) { 1233 $this->debug_message( 'comparing to node value: ' . $this->normalize_html( $img_html ) . ' to ' . $this->normalize_html( $image ) ); 1234 } 1235 // Normalize the HTML before comparing to avoid issues with different quote styles or spacing. 1236 if ( $this->normalize_html( $img_html ) === $this->normalize_html( $image ) ) { 1237 $parent = $img_node->parentNode; 1238 if ( $parent && 'body' !== $parent->nodeName && $parent->hasAttributes() ) { 1239 $class = trim( $parent->getAttribute( 'class' ) ); 1240 $this->debug_message( "Parent class: $class" ); 1241 if ( str_contains( $class, 'skip-lazy' ) ) { 1242 $this->debug_message( "Skipping lazy load due to 'skip-lazy' class on parent" ); 1243 return false; 1244 } 1245 if ( $parent->hasAttribute( 'data-skip-lazy' ) ) { 1246 $this->debug_message( "Skipping lazy load due to 'data-skip-lazy' attribute on parent" ); 1247 return false; 1248 } 1249 } 1250 } 1251 } 1252 1108 1253 return true; 1109 1254 } 1110 1255 1111 1256 /** 1112 * Checks if a tag with a background image is allowed to be lazy loaded. 1113 * 1114 * @param string $tag The tag. 1115 * @return bool True if the tag is allowed, false otherwise. 1116 */ 1117 public function validate_bgimage_tag( $tag ) { 1118 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 1257 * Gets the exclusion list for lazy loading background images. 1258 * 1259 * @param array $exclusions The current list of exclusions. Optional. 1260 * @return array The modified list of exclusions. 1261 */ 1262 public function get_bgimage_exclusions( $exclusions = array() ) { 1263 if ( ! \is_array( $exclusions ) ) { 1264 $exclusions = array(); 1265 } 1119 1266 $exclusions = \apply_filters( 1120 1267 'eio_lazy_bg_image_exclusions', … … 1127 1274 'skip-lazy', 1128 1275 'avia-bg-style-fixed', 1276 'trustindex', 1277 ), 1278 $this->user_exclusions, 1279 $exclusions 1280 ) 1281 ); 1282 return $exclusions; 1283 } 1284 1285 /** 1286 * Checks if a tag with a background image is allowed to be lazy loaded. 1287 * 1288 * @param string $tag The tag. 1289 * @return bool True if the tag is allowed, false otherwise. 1290 */ 1291 public function validate_bgimage_tag( $tag ) { 1292 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 1293 $exclusions = $this->get_bgimage_exclusions( array() ); 1294 foreach ( $exclusions as $exclusion ) { 1295 if ( false !== \strpos( $tag, $exclusion ) ) { 1296 return false; 1297 } 1298 } 1299 return true; 1300 } 1301 1302 /** 1303 * Checks if an iframe tag is allowed to be lazy loaded. 1304 * 1305 * @param string $tag The tag. 1306 * @return bool True if the tag is allowed, false otherwise. 1307 */ 1308 public function validate_iframe_tag( $tag ) { 1309 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 1310 $exclusions = \apply_filters( 1311 'eio_lazy_iframe_exclusions', 1312 \array_merge( 1313 array( 1314 'about:blank', 1315 'data-no-lazy=', 1316 'display:none', 1317 'display: none', 1318 'googletagmanager', 1319 'lazyload', 1320 'skip-lazy', 1321 'wprus/', 1322 'vimeo', 1129 1323 ), 1130 1324 $this->user_exclusions … … 1141 1335 1142 1336 /** 1143 * Checks if an iframe tag is allowed to be lazy loaded.1144 *1145 * @param string $tag The tag.1146 * @return bool True if the tag is allowed, false otherwise.1147 */1148 public function validate_iframe_tag( $tag ) {1149 $this->debug_message( '<b>' . __METHOD__ . '()</b>' );1150 $exclusions = \apply_filters(1151 'eio_lazy_iframe_exclusions',1152 \array_merge(1153 array(1154 'data-no-lazy=',1155 'lazyload',1156 'skip-lazy',1157 'vimeo',1158 'about:blank',1159 'googletagmanager',1160 ),1161 $this->user_exclusions1162 ),1163 $tag1164 );1165 foreach ( $exclusions as $exclusion ) {1166 if ( false !== \strpos( $tag, $exclusion ) ) {1167 return false;1168 }1169 }1170 return true;1171 }1172 1173 /**1174 1337 * Build a PNG inline image placeholder. 1175 1338 * … … 1211 1374 return $exactdn->generate_url( $this->content_url . 'lazy/placeholder-' . $width . 'x' . $height . '.png' ); 1212 1375 } elseif ( ! is_file( $piip_path ) ) { 1213 // First try PIP generation via Imagick, as it is pretty efficient. 1214 if ( $this->imagick_support() ) { 1215 $placeholder = new \Imagick(); 1216 $placeholder->newimage( $width, $height, 'transparent' ); 1217 $placeholder->setimageformat( 'PNG' ); 1218 $placeholder->stripimage(); 1219 $placeholder->writeimage( $piip_path ); 1220 $placeholder->clear(); 1376 // First, try GD and then optimize it with optipng/pngout if available. 1377 // This is now the first attempt, as the Imagick placeholders are grayscale and may not work in Safari, and GD is somehow faster. 1378 if ( 1379 $this->gd_support() && 1380 $this->check_memory_available( $width * $height * 4.8 ) // 4.8 = 24-bit or 3 bytes per pixel multiplied by a factor of 1.6 for extra wiggle room. 1381 ) { 1382 $img = \imagecreatetruecolor( $width, $height ); 1383 $color = \imagecolorallocatealpha( $img, 0, 0, 0, 127 ); 1384 \imagefill( $img, 0, 0, $color ); 1385 \imagesavealpha( $img, true ); 1386 \imagecolortransparent( $img, \imagecolorat( $img, 0, 0 ) ); 1387 \imagetruecolortopalette( $img, false, 1 ); 1388 \imagepng( $img, $piip_path, 9 ); 1389 if ( 1390 \function_exists( '\ewww_image_optimizer' ) && 1391 \function_exists( '\ewwwio' ) && 1392 ! \ewwwio()->get_option( 'ewww_image_optimizer_cloud_key' ) && 1393 \ewwwio()->local->exec_check() 1394 ) { 1395 \ewww_image_optimizer( $piip_path ); 1396 } 1221 1397 } 1222 1398 // If that didn't work, and we have a premium service, use the API to generate the slimmest PIP available. … … 1234 1410 } 1235 1411 } 1236 // Last shot, use GD and then optimize it with optipng/pngout if available.1412 // Last resort, do PIP generation via Imagick, as it is pretty efficient even though Safari doesn't like the grayscale images it produces. 1237 1413 if ( 1238 1414 ! \is_file( $piip_path ) && 1239 $this->gd_support() && 1240 $this->check_memory_available( $width * $height * 4.8 ) // 4.8 = 24-bit or 3 bytes per pixel multiplied by a factor of 1.6 for extra wiggle room. 1415 $this->imagick_support() 1241 1416 ) { 1242 $img = \imagecreatetruecolor( $width, $height ); 1243 $color = \imagecolorallocatealpha( $img, 0, 0, 0, 127 ); 1244 \imagefill( $img, 0, 0, $color ); 1245 \imagesavealpha( $img, true ); 1246 \imagecolortransparent( $img, \imagecolorat( $img, 0, 0 ) ); 1247 \imagetruecolortopalette( $img, false, 1 ); 1248 \imagepng( $img, $piip_path, 9 ); 1249 if ( \function_exists( '\ewww_image_optimizer' ) ) { 1250 \ewww_image_optimizer( $piip_path ); 1251 } 1417 $placeholder = new \Imagick(); 1418 $placeholder->newimage( $width, $height, 'transparent' ); 1419 $placeholder->setimageformat( 'PNG' ); 1420 $placeholder->stripimage(); 1421 $placeholder->writeimage( $piip_path ); 1422 $placeholder->clear(); 1252 1423 } 1253 1424 } … … 1382 1553 'exactdn_domain' => ( $this->parsing_exactdn ? $this->exactdn_domain : '' ), 1383 1554 'skip_autoscale' => ( \defined( 'EIO_LL_AUTOSCALE' ) && ! EIO_LL_AUTOSCALE ? 1 : 0 ), 1555 'bg_min_dpr' => ( \defined( 'EIO_LL_BG_MIN_DPR' ) && EIO_LL_BG_MIN_DPR ? EIO_LL_BG_MIN_DPR : 1.1 ), 1384 1556 'threshold' => (int) $threshold > 50 ? (int) $threshold : 0, 1385 1557 'use_dpr' => (int) $this->get_option( 'exactdn_hidpi' ), … … 1423 1595 'exactdn_domain' => ( $this->parsing_exactdn ? $this->exactdn_domain : '' ), 1424 1596 'skip_autoscale' => ( \defined( 'EIO_LL_AUTOSCALE' ) && ! EIO_LL_AUTOSCALE ? 1 : 0 ), 1597 'bg_min_dpr' => ( \defined( 'EIO_LL_BG_MIN_DPR' ) && EIO_LL_BG_MIN_DPR ? EIO_LL_BG_MIN_DPR : 1.1 ), 1425 1598 'threshold' => (int) $threshold > 50 ? (int) $threshold : 0, 1426 1599 'use_dpr' => (int) $this->get_option( 'exactdn_hidpi' ), -
easy-image-optimizer/trunk/classes/class-page-parser.php
r3328397 r3398277 57 57 * @param bool $hyperlinks Default true. Should we include encasing hyperlinks in our search. 58 58 * @param bool $src_required Default true. Should we look only for images with src attributes. 59 * @param int $flags Optional. Flags passed to preg_match_all. Default 0. 59 60 * @return array An array of $images matches, where $images[0] is 60 61 * an array of full matches, and the link_url, img_tag, 61 62 * and img_url keys are arrays of those matches. 62 63 */ 63 public function get_images_from_html( $content, $hyperlinks = true, $src_required = true ) {64 public function get_images_from_html( $content, $hyperlinks = true, $src_required = true, $flags = 0 ) { 64 65 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 65 66 $images = array(); … … 80 81 $unquoted_pattern = '#(?P<img_tag><img[^>]*?\s+?src\s*=\s*(?P<img_url>[^"\'\\\\<>][^\s\\\\<>]+)(?:\s[^>]*?)?>)#is'; 81 82 } 82 if ( \preg_match_all( $search_pattern, $content, $images ) ) {83 if ( \preg_match_all( $search_pattern, $content, $images, $flags ) ) { 83 84 $this->debug_message( 'found ' . \count( $images[0] ) . ' image elements with quoted pattern' ); 84 85 foreach ( $images as $key => $unused ) { … … 91 92 } 92 93 $images = \array_filter( $images ); 93 if ( $unquoted_pattern && \preg_match_all( $unquoted_pattern, $content, $unquoted_images ) ) {94 if ( $unquoted_pattern && \preg_match_all( $unquoted_pattern, $content, $unquoted_images, $flags ) ) { 94 95 $this->debug_message( 'found ' . \count( $unquoted_images[0] ) . ' image elements with unquoted pattern' ); 95 96 foreach ( $unquoted_images as $key => $unused ) { … … 147 148 * 148 149 * @param string $content Some HTML. 150 * @param int $flags Optional. Flags passed to preg_match_all. Default 0. 149 151 * @return array An array of $pictures matches, containing full elements with ending tags. 150 152 */ 151 public function get_picture_tags_from_html( $content ) {153 public function get_picture_tags_from_html( $content, $flags = 0 ) { 152 154 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 153 155 $pictures = array(); 154 if ( ! empty( $content ) && \preg_match_all( '#(?:<picture[^>]*?>\s*)(?:<source[^>]*?>)+(?:.*?</picture>)?#is', $content, $pictures ) ) {156 if ( ! empty( $content ) && \preg_match_all( '#(?:<picture[^>]*?>\s*)(?:<source[^>]*?>)+(?:.*?</picture>)?#is', $content, $pictures, $flags ) ) { 155 157 return $pictures[0]; 156 158 } … … 212 214 * @param string $content Some HTML. 213 215 * @param string $tag_name The name of the elements to retrieve. 216 * @param int $flags Optional. Flags passed to preg_match_all. Default 0. 214 217 * @return array An array of $elements. 215 218 */ 216 public function get_elements_from_html( $content, $tag_name ) {217 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 218 if ( ! \ctype_alpha( str_replace( '-', '', $tag_name ) ) ) {219 public function get_elements_from_html( $content, $tag_name, $flags = 0 ) { 220 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 221 if ( ! \ctype_alpha( \str_replace( '-', '', $tag_name ) ) ) { 219 222 return array(); 220 223 } 221 if ( ! empty( $content ) && \preg_match_all( '#<' . $tag_name . '\s[^\\\\>]+?>#is', $content, $elements ) ) {224 if ( ! empty( $content ) && \preg_match_all( '#<' . $tag_name . '\s[^\\\\>]+?>#is', $content, $elements, $flags ) ) { 222 225 return $elements[0]; 223 226 } -
easy-image-optimizer/trunk/classes/class-plugin.php
r3197623 r3398277 28 28 29 29 /** 30 * Buffer object. 31 * 32 * @var object|\EasyIO\Buffer $buffer 33 */ 34 public $buffer; 35 36 /** 37 * Lazy Load object. 38 * 39 * @var object|\EasyIO\Lazy_Load $lazy_load 40 */ 41 public $lazy_load; 42 43 /** 30 44 * Helpscout Beacon object. 31 45 * … … 33 47 */ 34 48 public $hs_beacon; 49 50 /** 51 * Settings object. 52 * 53 * @var object|\EasyIO\Settings $settings 54 */ 55 public $settings; 35 56 36 57 /** … … 50 71 self::$instance->requires(); 51 72 self::$instance->load_children(); 73 74 if ( ! self::$instance->php_supported() ) { 75 return self::$instance; 76 } 77 if ( ! self::$instance->wp_supported() ) { 78 return self::$instance; 79 } 80 81 // Load plugin components that need to be available early. 82 \add_action( 'plugins_loaded', array( self::$instance, 'plugins_loaded' ) ); 83 // Setup page parsing, if parsers are enabled. 84 \add_action( 'init', array( self::$instance, 'parser_init' ), 99 ); 52 85 // Initializes the plugin for admin interactions, like saving network settings and scheduling cron jobs. 53 86 \add_action( 'admin_init', array( self::$instance, 'admin_init' ) ); 54 87 55 // TODO: check PHP and WP compat here. 56 // TODO: setup anything that needs to run on init/plugins_loaded. 57 // TODO: add any custom option/setting hooks here (actions that need to be taken when certain settings are saved/updated). 88 // Filters to set default permissions, admins can override these if they wish. 89 \add_filter( 'easyio_admin_permissions', array( self::$instance, 'admin_permissions' ), 8 ); 90 \add_filter( 'easyio_superadmin_permissions', array( self::$instance, 'superadmin_permissions' ), 8 ); 91 92 // Add Easy IO version to useragent for API requests. 93 \add_filter( 'exactdn_api_request_useragent', array( self::$instance, 'api_useragent' ) ); 94 // Check the current screen ID to see if temp debugging should still be enabled. 95 \add_action( 'current_screen', array( self::$instance, 'current_screen' ), 10, 1 ); 96 // Disable core WebP generation since we already do that. 97 \add_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 98 // Makes sure we flush the debug info to the log on shutdown. 99 \add_action( 'shutdown', array( self::$instance, 'debug_log' ) ); 58 100 } 59 101 … … 86 128 */ 87 129 private function requires() { 130 // Sets up the settings page and various option-related hooks/functions. 131 require_once EASYIO_PLUGIN_PATH . 'classes/class-settings.php'; 132 // Starts the HTML buffer for all other functions to parse. 133 require_once EASYIO_PLUGIN_PATH . 'classes/class-buffer.php'; 134 // Page Parsing class for working with HTML content. 135 require_once EASYIO_PLUGIN_PATH . 'classes/class-page-parser.php'; 136 // Lazy Load class for parsing image urls and deferring off-screen images. 137 require_once EASYIO_PLUGIN_PATH . 'classes/class-lazy-load.php'; 88 138 // EasyIO\HS_Beacon class for integrated help/docs. 89 139 require_once EASYIO_PLUGIN_PATH . 'classes/class-hs-beacon.php'; … … 94 144 */ 95 145 public function load_children() { 96 /* self::$instance->class = new Class(); */ 146 self::$instance->settings = new Settings(); 147 } 148 149 /** 150 * Make sure we are on a supported version of PHP. 151 * 152 * @access private 153 */ 154 private function php_supported() { 155 if ( defined( 'PHP_VERSION_ID' ) && PHP_VERSION_ID >= 80100 ) { 156 return true; 157 } 158 \add_action( 'network_admin_notices', array( self::$instance, 'unsupported_php_notice' ) ); 159 \add_action( 'admin_notices', array( self::$instance, 'unsupported_php_notice' ) ); 160 return false; 161 } 162 163 /** 164 * Make sure we are on a supported version of WordPress. 165 * 166 * @access private 167 */ 168 private function wp_supported() { 169 global $wp_version; 170 if ( \version_compare( $wp_version, '6.6' ) >= 0 ) { 171 return true; 172 } 173 \add_action( 'network_admin_notices', array( self::$instance, 'unsupported_wp_notice' ) ); 174 \add_action( 'admin_notices', array( self::$instance, 'unsupported_wp_notice' ) ); 175 return false; 176 } 177 178 /** 179 * Display a notice that the PHP version is too old. 180 */ 181 public function unsupported_php_notice() { 182 echo '<div id="easyio-warning-php" class="error"><p><a href="https://docs.ewww.io/article/55-upgrading-php" target="_blank" data-beacon-article="5ab2baa6042863478ea7c2ae">' . esc_html__( 'Easy Image Optimizer requires PHP 8.1 or greater. Newer versions of PHP are faster and more secure. If you are unsure how to upgrade to a supported version, ask your webhost for instructions.', 'easy-image-optimizer' ) . '</a></p></div>'; 183 } 184 185 /** 186 * Display a notice that the WP version is too old. 187 */ 188 public function unsupported_wp_notice() { 189 echo '<div id="swis-warning-wp" class="notice notice-error"><p>' . esc_html__( 'Easy Image Optimizer requires WordPress 6.6 or greater, please update your website.', 'easy-image-optimizer' ) . '</p></div>'; 190 } 191 192 /** 193 * Run things that need to go early, on plugins_loaded. 194 */ 195 public function plugins_loaded() { 196 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 197 198 if ( $this->get_option( 'easyio_lazy_load' ) && $this->get_option( 'easyio_ll_external_bg' ) ) { 199 $this->debug_message( 'requesting external parsing of CSS for background images via SWIS' ); 200 add_filter( 'eio_lazify_external_css', '__return_true' ); 201 } 202 } 203 204 /** 205 * Setup page parsing classes after theme functions.php is loaded and plugins have run init routines. 206 */ 207 public function parser_init() { 208 $buffer_start = false; 209 // If ExactDN is enabled. 210 if ( $this->get_option( 'easyio_exactdn' ) && ! \str_contains( \add_query_arg( '', '' ), 'exactdn_disable=1' ) ) { 211 $buffer_start = true; 212 213 // ExactDN class for parsing image urls and rewriting them. 214 require_once EASYIO_PLUGIN_PATH . 'classes/class-exactdn.php'; 215 } 216 // If Lazy Load is enabled. 217 if ( $this->get_option( 'easyio_lazy_load' ) ) { 218 $buffer_start = true; 219 220 $this->lazy_load = new Lazy_Load(); 221 } 222 if ( $buffer_start ) { 223 // Start an output buffer before any output starts. 224 $this->buffer = new Buffer(); 225 } 97 226 } 98 227 … … 102 231 public function admin_init() { 103 232 $this->hs_beacon = new HS_Beacon(); 104 \easyio_upgrade();105 $this->register_settings();106 233 107 234 if ( ! \class_exists( __NAMESPACE__ . '\ExactDN' ) || ! $this->get_option( 'easyio_exactdn' ) ) { 108 add_action( 'network_admin_notices', 'easyio_notice_inactive' ); 109 add_action( 'admin_notices', 'easyio_notice_inactive' ); 110 } 235 \add_action( 'network_admin_notices', array( $this, 'service_inactive_notice' ) ); 236 \add_action( 'admin_notices', array( $this, 'service_inactive_notice' ) ); 237 } 238 239 \add_action( 'exactdn_as3cf_cname_active', array( $this, 'exactdn_as3cf_cname_active_notice' ) ); 240 \add_action( 'exactdn_domain_mismatch', array( $this, 'exactdn_domain_mismatch_notice' ) ); 241 242 \add_action( 'easyio_beacon_notice', array( $this, 'hs_beacon_notice' ) ); 243 111 244 // Prevent ShortPixel AIO messiness. 112 245 \remove_action( 'admin_notices', 'autoptimizeMain::notice_plug_imgopt' ); … … 117 250 $ao_extra['autoptimize_imgopt_checkbox_field_1'] = 0; 118 251 \update_option( 'autoptimize_imgopt_settings', $ao_extra ); 119 \add_action( 'admin_notices', 'easyio_notice_sp_conflict');252 \add_action( 'admin_notices', array( $this, 'sp_conflict_notice' ) ); 120 253 } 121 254 } … … 124 257 if ( $this->get_option( 'easyio_exactdn' ) && \HMWP_Classes_Tools::getOption( 'hmwp_hide_version' ) && ! \HMWP_Classes_Tools::getOption( 'hmwp_hide_version_random' ) ) { 125 258 $this->debug_message( 'detected HMWP Hide Version' ); 126 \add_action( 'admin_notices', array( $this, ' notice_hmwp_hide_version' ) );259 \add_action( 'admin_notices', array( $this, 'hmwp_hide_version_notice' ) ); 127 260 } 128 261 } 129 262 130 if ( ! \defined( '\WP_CLI' ) || ! WP_CLI ) { 131 \easyio_privacy_policy_content(); 132 } 133 } 134 135 /** 136 * Save the multi-site settings, if this is the WP admin, and they've been POSTed. 137 */ 138 public function save_network_settings() { 139 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 140 // NOTE: we don't actually have a network settings screen, so... 141 if ( ! \function_exists( 'is_plugin_active_for_network' ) && \is_multisite() ) { 142 // Need to include the plugin library for the is_plugin_active function. 143 require_once ABSPATH . 'wp-admin/includes/plugin.php'; 144 } 145 // Set the common network settings if they have been POSTed. 146 if ( 147 \is_multisite() && 148 \is_plugin_active_for_network( EASYIO_PLUGIN_FILE_REL ) && 149 ! empty( $_REQUEST['_wpnonce'] ) && 150 isset( $_POST['option_page'] ) && 151 false !== \strpos( sanitize_text_field( wp_unslash( $_POST['option_page'] ) ), 'easyio_options' ) && 152 \wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'easyio_options-options' ) && 153 \current_user_can( 'manage_network_options' ) && 154 ! \get_site_option( 'easyio_allow_multisite_override' ) && 155 false === \strpos( wp_get_referer(), 'options-general' ) 156 ) { 157 $this->debug_message( 'network-wide settings, no override' ); 158 $easyio_debug = ( empty( $_POST['easyio_debug'] ) ? false : true ); 159 \update_site_option( 'easyio_debug', $easyio_debug ); 160 $easyio_metadata_remove = ( empty( $_POST['easyio_metadata_remove'] ) ? false : true ); 161 \update_site_option( 'easyio_metadata_remove', $easyio_metadata_remove ); 162 $exactdn_all_the_things = ( empty( $_POST['exactdn_all_the_things'] ) ? false : true ); 163 \update_site_option( 'exactdn_all_the_things', $exactdn_all_the_things ); 164 $exactdn_lossy = ( empty( $_POST['exactdn_lossy'] ) ? false : true ); 165 \update_site_option( 'exactdn_lossy', $exactdn_lossy ); 166 $exactdn_hidpi = ( empty( $_POST['exactdn_hidpi'] ) ? false : true ); 167 \update_site_option( 'exactdn_hidpi', $exactdn_hidpi ); 168 $exactdn_exclude = empty( $_POST['exactdn_exclude'] ) ? '' : sanitize_textarea_field( wp_unslash( $_POST['exactdn_exclude'] ) ); 169 \update_site_option( 'exactdn_exclude', $this->exclude_paths_sanitize( $exactdn_exclude ) ); 170 $easyio_add_missing_dims = ( empty( $_POST['easyio_add_missing_dims'] ) ? false : true ); 171 \update_site_option( 'easyio_add_missing_dims', $easyio_add_missing_dims ); 172 $easyio_lazy_load = ( empty( $_POST['easyio_lazy_load'] ) ? false : true ); 173 \update_site_option( 'easyio_lazy_load', $easyio_lazy_load ); 174 $easyio_ll_autoscale = ( empty( $_POST['easyio_ll_autoscale'] ) ? false : true ); 175 \update_site_option( 'easyio_ll_autoscale', $easyio_ll_autoscale ); 176 $easyio_ll_abovethefold = ! empty( $_POST['easyio_ll_abovethefold'] ) ? (int) $_POST['easyio_ll_abovethefold'] : 0; 177 \update_site_option( 'easyio_ll_abovethefold', $easyio_ll_abovethefold ); 178 $easyio_use_lqip = ( empty( $_POST['easyio_use_lqip'] ) ? false : true ); 179 \update_site_option( 'easyio_use_lqip', $easyio_use_lqip ); 180 $easyio_use_dcip = ( empty( $_POST['easyio_use_dcip'] ) ? false : true ); 181 \update_site_option( 'easyio_use_dcip', $easyio_use_dcip ); 182 $easyio_ll_exclude = empty( $_POST['easyio_ll_exclude'] ) ? '' : sanitize_textarea_field( wp_unslash( $_POST['easyio_ll_exclude'] ) ); 183 \update_site_option( 'easyio_ll_exclude', $this->exclude_paths_sanitize( $easyio_ll_exclude ) ); 184 $easyio_ll_all_things = empty( $_POST['easyio_ll_all_things'] ) ? '' : sanitize_textarea_field( wp_unslash( $_POST['easyio_ll_all_things'] ) ); 185 \update_site_option( 'easyio_ll_all_things', $easyio_ll_all_things ); 186 $easyio_allow_multisite_override = empty( $_POST['easyio_allow_multisite_override'] ) ? false : true; 187 \update_site_option( 'easyio_allow_multisite_override', $easyio_allow_multisite_override ); 188 $easyio_enable_help = empty( $_POST['easyio_enable_help'] ) ? false : true; 189 \update_site_option( 'easyio_enable_help', $easyio_enable_help ); 190 \add_action( 'network_admin_notices', 'easyio_network_settings_saved' ); 191 } elseif ( isset( $_POST['easyio_allow_multisite_override_active'] ) && \current_user_can( 'manage_network_options' ) && ! empty( $_REQUEST['_wpnonce'] ) && \wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'easyio_options-options' ) ) { 192 $this->debug_message( 'network-wide settings, single-site overriding' ); 193 $easyio_allow_multisite_override = empty( $_POST['easyio_allow_multisite_override'] ) ? false : true; 194 \update_site_option( 'easyio_allow_multisite_override', $easyio_allow_multisite_override ); 195 \add_action( 'network_admin_notices', 'easyio_network_settings_saved' ); 196 } // End if(). 197 } 198 199 /** 200 * Register all our options and sanitation functions. 201 */ 202 public function register_settings() { 203 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 204 // Register all the common Easy IO settings. 205 \register_setting( 'easyio_options', 'easyio_debug', 'boolval' ); 206 \register_setting( 'easyio_options', 'easyio_enable_help', 'boolval' ); 207 \register_setting( 'easyio_options', 'exactdn_all_the_things', 'boolval' ); 208 \register_setting( 'easyio_options', 'exactdn_lossy', 'boolval' ); 209 \register_setting( 'easyio_options', 'exactdn_hidpi', 'boolval' ); 210 \register_setting( 'easyio_options', 'exactdn_exclude', array( $this, 'exclude_paths_sanitize' ) ); 211 \register_setting( 'easyio_options', 'easyio_add_missing_dims', 'boolval' ); 212 \register_setting( 'easyio_options', 'easyio_lazy_load', 'boolval' ); 213 \register_setting( 'easyio_options', 'easyio_ll_abovethefold', 'intval' ); 214 \register_setting( 'easyio_options', 'easyio_use_lqip', 'boolval' ); 215 \register_setting( 'easyio_options', 'easyio_use_dcip', 'boolval' ); 216 \register_setting( 'easyio_options', 'easyio_ll_exclude', array( $this, 'exclude_paths_sanitize' ) ); 217 \register_setting( 'easyio_options', 'easyio_ll_all_things', 'sanitize_textarea_field' ); 218 } 219 220 /** 221 * Set some default option values. 222 */ 223 public function set_defaults() { 224 $this->debug_message( '<b>' . __METHOD__ . '()</b>' ); 225 // Set defaults for all options that need to be autoloaded. 226 \add_option( 'easyio_debug', false ); 227 \add_option( 'easyio_metadata_remove', true ); 228 \add_option( 'easyio_exactdn', false ); 229 \add_option( 'easyio_plan_id', 0 ); 230 \add_option( 'exactdn_all_the_things', false ); 231 \add_option( 'exactdn_lossy', false ); 232 \add_option( 'exactdn_hidpi', false ); 233 \add_option( 'exactdn_exclude', '' ); 234 \add_option( 'exactdn_sub_folder', false ); 235 \add_option( 'exactdn_prevent_db_queries', true ); 236 \add_option( 'exactdn_asset_domains', '' ); 237 \add_option( 'easyio_add_missing_dims', false ); 238 \add_option( 'easyio_lazy_load', false ); 239 \add_option( 'easyio_use_lqip', false ); 240 \add_option( 'easyio_use_dcip', false ); 241 \add_option( 'easyio_use_siip', false ); 242 \add_option( 'easyio_ll_autoscale', true ); 243 \add_option( 'easyio_ll_abovethefold', 0 ); 244 \add_option( 'easyio_ll_exclude', '' ); 245 \add_option( 'easyio_ll_all_things', '' ); 246 247 // Set network defaults. 248 \add_site_option( 'easyio_metadata_remove', true ); 249 \add_site_option( 'easyio_add_missing_dims', true ); 250 \add_site_option( 'easyio_ll_autoscale', true ); 251 \add_site_option( 'exactdn_sub_folder', false ); 252 \add_site_option( 'exactdn_prevent_db_queries', true ); 263 if ( ! \defined( 'WP_CLI' ) || ! WP_CLI ) { 264 $this->privacy_policy_content(); 265 } 266 } 267 268 /** 269 * Adds the Easy IO version to the useragent for http requests. 270 * 271 * @param string $useragent The current useragent used in http requests. 272 * @return string The useragent with the Easy IO version appended. 273 */ 274 public function api_useragent( $useragent ) { 275 if ( ! \str_contains( $useragent, 'EIO' ) ) { 276 $useragent .= ' EIO/' . EASYIO_VERSION . ' '; 277 } 278 return $useragent; 279 } 280 281 /** 282 * Adds suggested privacy policy content for site admins. 283 * 284 * Note that this is just a suggestion, it should be customized for your site. 285 */ 286 private function privacy_policy_content() { 287 if ( ! \function_exists( 'wp_add_privacy_policy_content' ) || ! \function_exists( 'wp_kses_post' ) ) { 288 return; 289 } 290 $content = '<p class="privacy-policy-tutorial">'; 291 $content .= \wp_kses_post( \__( 'Normally, this plugin does not process any information about your visitors. However, if you accept user-submitted images and display them on your site, you can use this language to keep your visitors informed.', 'easy-image-optimizer' ) ) . '</p>'; 292 $content .= '<p>' . \wp_kses_post( \__( 'User-submitted images that are displayed on this site will be transmitted and stored on a global network of third-party servers (a CDN).', 'easy-image-optimizer' ) ) . '</p>'; 293 \wp_add_privacy_policy_content( 'Easy Image Optimizer', $content ); 294 } 295 296 /** 297 * Set default permissions for admin (configuration) and bulk operations. 298 * 299 * @param string $permissions A valid WP capability level. 300 * @return string Either the original value, unchanged, or the default capability level. 301 */ 302 public function admin_permissions( $permissions ) { 303 if ( empty( $permissions ) ) { 304 return 'activate_plugins'; 305 } 306 return $permissions; 307 } 308 309 /** 310 * Set default permissions for multisite/network admin (configuration) operations. 311 * 312 * @param string $permissions A valid WP capability level. 313 * @return string Either the original value, unchanged, or the default capability level. 314 */ 315 public function superadmin_permissions( $permissions ) { 316 if ( empty( $permissions ) ) { 317 return 'manage_network_options'; 318 } 319 return $permissions; 320 } 321 322 /** 323 * Check the current screen, used to temporarily enable debugging on settings page. 324 * 325 * @param object $screen Information about the page/screen currently being loaded. 326 */ 327 public function current_screen( $screen ) { 328 if ( $this->get_option( 'easyio_debug' ) ) { 329 return; 330 } 331 if ( \str_contains( $screen->id, 'settings_page_easy-image-optimizer' ) ) { 332 return; 333 } 334 // Otherwise, we are somewhere else and should disable temp debugging. 335 Base::$debug_data = ''; 336 Base::$temp_debug = false; 337 } 338 339 /** 340 * Let the user know they need to take action! 341 */ 342 public function service_inactive_notice() { 343 ?> 344 <div id='easyio-inactive' class='notice notice-warning'> 345 <p> 346 <a href="<?php echo \esc_url( \admin_url( 'options-general.php?page=easy-image-optimizer-options' ) ); ?>"> 347 <?php \esc_html_e( 'Please visit the settings page to complete activation of the Easy Image Optimizer.', 'easy-image-optimizer' ); ?> 348 </a> 349 </p> 350 </div> 351 <?php 352 } 353 354 /** 355 * Let the user know they need to disable the WP Offload Media CNAME. 356 */ 357 public function exactdn_as3cf_cname_active_notice() { 358 ?> 359 <div id="easyio-notice-exactdn-as3cf-cname-active" class="notice notice-error"> 360 <p> 361 <?php \esc_html_e( 'Easy IO cannot optimize your images while using a custom domain (CNAME) in WP Offload Media. Please disable the custom domain in the WP Offload Media settings.', 'easy-image-optimizer' ); ?> 362 </p> 363 </div> 364 <?php 365 } 366 367 /** 368 * Let the user know the local domain appears to have changed from what Easy IO has recorded in the db. 369 */ 370 public function exactdn_domain_mismatch_notice() { 371 global $exactdn; 372 if ( ! isset( $exactdn->upload_domain ) ) { 373 return; 374 } 375 $stored_local_domain = $this->get_option( 'easyio_exactdn_local_domain' ); 376 if ( empty( $stored_local_domain ) ) { 377 return; 378 } 379 if ( ! \str_contains( $stored_local_domain, '.' ) ) { 380 $stored_local_domain = \base64_decode( $stored_local_domain ); 381 } 382 ?> 383 <div id="easyio-notice-exactdn-domain-mismatch" class="notice notice-warning"> 384 <p> 385 <?php 386 \printf( 387 /* translators: 1: old domain name, 2: current domain name */ 388 \esc_html__( 'Easy IO detected that the Site URL has changed since the initial activation (previously %1$s, currently %2$s).', 'easy-image-optimizer' ), 389 '<strong>' . \esc_html( $stored_local_domain ) . '</strong>', 390 '<strong>' . \esc_html( $exactdn->upload_domain ) . '</strong>' 391 ); 392 ?> 393 <br> 394 <?php 395 \printf( 396 /* translators: %s: settings page */ 397 \esc_html__( 'Please visit the %s to refresh the Easy IO settings and verify activation status.', 'easy-image-optimizer' ), 398 '<a href="' . \esc_url( \admin_url( 'options-general.php?page=easy-image-optimizer-options' ) ) . '">' . \esc_html__( 'settings page', 'easy-image-optimizer' ) . '</a>' 399 ); 400 ?> 401 </p> 402 </div> 403 <?php 404 } 405 406 /** 407 * Inform the user of our beacon function so that they can opt-in. 408 */ 409 public function hs_beacon_notice() { 410 $optin_url = \wp_nonce_url( 'admin.php?action=eio_opt_into_hs_beacon', 'eio_beacon' ); 411 $optout_url = \wp_nonce_url( 'admin.php?action=eio_opt_out_of_hs_beacon', 'eio_beacon' ); 412 ?> 413 <div id="easyio-hs-beacon" class="notice notice-info"> 414 <p> 415 <?php \esc_html_e( 'Enable the Easy IO support beacon, which gives you access to documentation and our support team right from your WordPress dashboard. To assist you more efficiently, we collect the current url, IP address, browser/device information, and debugging information.', 'easy-image-optimizer' ); ?><br> 416 <a href="<?php echo \esc_url( $optin_url ); ?>" class="button-secondary"><?php esc_html_e( 'Allow', 'easy-image-optimizer' ); ?></a> 417 <a href="<?php echo \esc_url( $optout_url ); ?>" class="button-secondary"><?php esc_html_e( 'Do not allow', 'easy-image-optimizer' ); ?></a> 418 </p> 419 </div> 420 <?php 421 } 422 423 /** 424 * Inform the user that we disabled SP AIO to prevent conflicts with ExactDN. 425 */ 426 public function sp_conflict_notice() { 427 ?> 428 <div id='easyio-sp-conflict' class='notice notice-warning'> 429 <p> 430 <?php \esc_html_e( 'ShortPixel/Autoptimize image optimization has been disabled to prevent conflicts with Easy Image Optimizer).', 'easy-image-optimizer' ); ?> 431 </p> 432 </div> 433 <?php 253 434 } 254 435 … … 256 437 * Tell the user to disable Hide my WP function that removes query strings. 257 438 */ 258 public function notice_hmwp_hide_version() {439 public function hmwp_hide_version_notice() { 259 440 ?> 260 441 <div id='easy-image-optimizer-warning-hmwp-hide-version' class='notice notice-warning'> 261 442 <p> 262 443 <?php \esc_html_e( 'Please enable the Random Static Number option in Hide My WP to ensure compatibility with Easy IO or disable the Hide Version option for best performance.', 'easy-image-optimizer' ); ?> 263 <?php \easyio_help_link( 'https://docs.ewww.io/article/50-exactdn-and-query-strings', '5a3d278a2c7d3a1943677b52' ); ?>444 <?php $this->settings->help_link( 'https://docs.ewww.io/article/50-exactdn-and-query-strings', '5a3d278a2c7d3a1943677b52' ); ?> 264 445 </p> 265 446 </div> -
easy-image-optimizer/trunk/easy-image-optimizer.php
r3350722 r3398277 14 14 Description: Easily speed up your website to better connect with your visitors. Properly compress and size/scale images. Includes lazy load and WebP auto-convert. 15 15 Author: Exactly WWW 16 Version: 4. 2.116 Version: 4.3.0 17 17 Requires at least: 6.6 18 18 Requires PHP: 8.1 … … 25 25 } 26 26 27 // Check the PHP version. 28 if ( ! defined( 'PHP_VERSION_ID' ) || PHP_VERSION_ID < 80100 ) { 29 add_action( 'network_admin_notices', 'easyio_unsupported_php' ); 30 add_action( 'admin_notices', 'easyio_unsupported_php' ); 31 } elseif ( false === strpos( add_query_arg( '', '' ), 'easyio_disable=1' ) ) { 32 define( 'EASYIO_VERSION', 421 ); 27 if ( ! class_exists( 'EasyIO\Plugin' ) && ! str_contains( add_query_arg( '', '' ), 'easyio_disable=1' ) ) { 28 define( 'EASYIO_VERSION', 430 ); 33 29 34 30 /** … … 58 54 if ( ! is_writable( WP_CONTENT_DIR ) || ! empty( $_ENV['PANTHEON_ENVIRONMENT'] ) ) { 59 55 $upload_dir = wp_get_upload_dir(); 60 if ( false === strpos( $upload_dir['basedir'], '://' ) && is_writable( $upload_dir['basedir'] ) ) {56 if ( ! str_contains( $upload_dir['basedir'], '://' ) && is_writable( $upload_dir['basedir'] ) ) { 61 57 $easyio_content_dir = trailingslashit( $upload_dir['basedir'] ) . trailingslashit( 'easyio' ); 62 58 } … … 66 62 } 67 63 68 /**69 * All the 'unique' functions for the core Easy IO plugin.70 */71 require_once EASYIO_PLUGIN_PATH . 'unique.php';72 64 /** 73 65 * All the base functions for our plugins. … … 88 80 easyio(); 89 81 } // End if(). 90 91 if ( ! function_exists( 'easyio_unsupported_php' ) ) {92 /**93 * Display a notice that the PHP version is too old.94 */95 function easyio_unsupported_php() {96 echo '<div id="easyio-warning-php" class="error"><p><a href="https://docs.ewww.io/article/55-upgrading-php" target="_blank" data-beacon-article="5ab2baa6042863478ea7c2ae">' . esc_html__( 'Easy Image Optimizer requires PHP 8.1 or greater. Newer versions of PHP are faster and more secure. If you are unsure how to upgrade to a supported version, ask your webhost for instructions.', 'easy-image-optimizer' ) . '</a></p></div>';97 }98 } -
easy-image-optimizer/trunk/includes/eio.js
r3076002 r3398277 38 38 }); 39 39 } 40 $('#easyio-general-settings').show();41 $('li.easyio-general-nav').addClass('easyio-selected');42 $('#easyio-support-settings').hide();43 40 $('.easyio-general-nav').click(function() { 44 41 $('.easyio-tab-nav li').removeClass('easyio-selected'); … … 59 56 $('#easyio-hidden-submit').show(); 60 57 }); 61 return false; 58 $('a#easyio-activate').on( 'click', function() { 59 $('a#easyio-activate').hide(); 60 $('#easyio-activation-processing').show(); 61 activateExactDNSite(); 62 return false; 63 }); 64 function activateExactDNSite() { 65 var easyio_post_action = 'easyio_activate'; 66 var easyio_post_data = { 67 action: easyio_post_action, 68 _wpnonce: easyio_vars._wpnonce, 69 }; 70 $.post(ajaxurl, easyio_post_data, function(response) { 71 try { 72 var easyio_response = JSON.parse(response); 73 } catch (err) { 74 $('#easyio-activation-processing').hide(); 75 $('#easyio-activation-result').html(easyio_vars.invalid_response); 76 $('#easyio-activation-result').addClass('error'); 77 $('#easyio-activation-result').show(); 78 console.log( response ); 79 return false; 80 } 81 if ( easyio_response.error ) { 82 $('#easyio-activation-processing').hide(); 83 $('a#easyio-activate').show(); 84 $('#easyio-activation-result').html(easyio_response.error); 85 $('#easyio-activation-result').addClass('error'); 86 $('#easyio-activation-result').show(); 87 } else if ( ! easyio_response.success ) { 88 $('#easyio-activation-processing').hide(); 89 $('#easyio-activation-result').html(easyio_vars.invalid_response); 90 $('#easyio-activation-result').addClass('error'); 91 $('#easyio-activation-result').show(); 92 console.log( response ); 93 } else { 94 $('#easyio-activation-processing').hide(); 95 $('#easyio-status').html(easyio_response.success); 96 $('#exactdn_all_the_things').prop('checked', true); 97 $('#easyio_lazy_load').prop('checked', true); 98 $('#easyio_add_missing_dims').prop('disabled', false); 99 $('.easyio-settings-table').show(); 100 $('#easyio-hidden-submit').show(); 101 $('table.easyio-inactive').hide(); 102 } 103 }); 104 return false; 105 } 106 var easy_save_bar_width = $('#easyio-savings-fill').data('score'); 107 $('#easyio-savings-fill').animate( { 108 width: easy_save_bar_width + '%', 109 }, 1000 ); 110 var easy_bandwidth_bar_width = $('#easyio-bandwidth-fill').data('score'); 111 if ( easy_bandwidth_bar_width == 100 ) { 112 $('#easyio-bandwidth-container .easyio-bar-fill').css('background-color', '#d63638'); 113 $('#easyio-bandwidth-flex a').css('color', '#d63638'); 114 } 115 $('#easyio-bandwidth-fill').animate( { 116 width: easy_bandwidth_bar_width + '%', 117 }, 1000 ); 118 easyIORegisterStatsHandler(); 119 function easyIORegisterStatsHandler() { 120 $('#easyio-show-stats').on('click', function(){ 121 var site_id = $(this).attr('data-site-id'); 122 var easyio_post_data = { 123 action: 'easyio_get_site_stats', 124 site_id: site_id, 125 _wpnonce: easyio_vars._wpnonce, 126 }; 127 var statsContainerID = 'exactdn-stats-modal-' + site_id; 128 var statsContainer = false; 129 var statsExist = document.getElementById(statsContainerID); 130 var closeIcon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"/></svg>'; 131 if ( ! statsExist ) { 132 $('body').append('<div id="' + statsContainerID + '" style="display:none;" class="exactdn-stats-modal"><div class="exactdn-stats-modal-close">' + closeIcon + '</div><div class="exactdn-stats-modal-charts"></div><img class="exactdn-loading-image" style="display:block;margin-left: auto;margin-right:auto;width:20px;" src="' + easyio_vars.loading_image_url + '" /></div>'); 133 statsContainer = $('#' + statsContainerID); 134 $(statsContainer).on('click', '.exactdn-stats-modal-close', function() { 135 $('.exactdn-stats-modal').hide(); 136 document.body.classList.toggle('exactdn-body-unscroll'); 137 }); 138 139 $.post(ajaxurl, easyio_post_data, function(response) { 140 //console.log( response ); 141 var is_json = true; 142 try { 143 var easyio_response = $.parseJSON(response); 144 } catch (err) { 145 is_json = false; 146 } 147 if ( ! is_json ) { 148 statsContainer.children('.exactdn-stats-modal-charts').html(easyio_vars.invalid_response); 149 $('.exactdn-loading-image').hide(); 150 console.log(response); 151 } else if (easyio_response.error) { 152 statsContainer.children('.exactdn-stats-modal-charts').html('<strong>Error (contact support if necessary):</strong> ' + easyio_response.error); 153 $('.exactdn-loading-image').hide(); 154 } else if (easyio_response.html) { 155 statsContainer.children('.exactdn-stats-modal-charts').html(easyio_response.html); 156 if (easyio_response.pending) { 157 console.log('need to fetch more stats, request pending'); 158 setTimeout(fetchExtraStats, 10000, site_id); 159 } else { 160 $('.exactdn-loading-image').hide(); 161 } 162 } else { 163 statsContainer.children('.exactdn-stats-modal-charts').html(easyio_vars.invalid_response); 164 $('.exactdn-loading-image').hide(); 165 console.log(response); 166 } 167 }) 168 .fail(function() { 169 statsContainer.children('.exactdn-stats-modal-charts').html(easyio_vars.invalid_response); 170 $('.exactdn-loading-image').hide(); 171 }); 172 } else { 173 statsContainer = $('#' + statsContainerID); 174 } 175 statsContainer.show(); 176 document.body.classList.toggle('exactdn-body-unscroll'); 177 return false; 178 }); 179 } 180 var extraStatsRequests = 0; 181 function fetchExtraStats(site_id) { 182 var easyio_post_data = { 183 action: 'easyio_get_site_stats', 184 site_id: site_id, 185 require_extra: 1, 186 _wpnonce: easyio_vars._wpnonce, 187 }; 188 var statsContainerID = 'exactdn-stats-modal-' + site_id; 189 var statsContainer = false; 190 var statsExist = document.getElementById(statsContainerID); 191 if ( ! statsExist ) { 192 console.log('no container for site #' + site_id); 193 return; 194 } 195 statsContainer = $('#' + statsContainerID); 196 if ( extraStatsRequests > 11 ) { // Roughly 2 minutes of waiting. 197 $('.exactdn-loading-image').hide(); 198 statsContainer.find('.exactdn-stats-pending').text(easyio_vars.easyio_extra_stats_failed); 199 return; 200 } 201 $.post(ajaxurl, easyio_post_data, function(response) { 202 extraStatsRequests++; 203 var is_json = true; 204 try { 205 var easyio_response = $.parseJSON(response); 206 } catch (err) { 207 is_json = false; 208 } 209 if ( ! is_json ) { 210 console.log(response); 211 setTimeout(fetchExtraStats, 10000, site_id); 212 return; 213 } 214 if (easyio_response.error) { 215 console.log(easyio_response.error); 216 } else if (easyio_response.html) { 217 $('.exactdn-loading-image').hide(); 218 statsContainer.children('.exactdn-stats-modal-charts').html(easyio_response.html); 219 return; 220 } 221 setTimeout(fetchExtraStats, 10000, site_id); 222 }); 223 } 62 224 }); 63 225 function selectText(containerid) { -
easy-image-optimizer/trunk/includes/lazysizes-post.js
r3197623 r3398277 28 28 if(e.detail.instance != lazySizes){return;} 29 29 30 var bg, bgWebP ;30 var bg, bgWebP,swisLazyId; 31 31 if(!e.defaultPrevented) { 32 32 … … 36 36 37 37 // handle data-back (so as not to conflict with the stock data-bg) 38 bg = e.target.getAttribute('data-back'); 38 bg = e.target.dataset.back; 39 // Was getAttribute('data-back'); 39 40 if (bg) { 40 if(ewww_webp_supported) {41 if(ewww_webp_supported) { 41 42 console.log('checking for data-back-webp'); 42 bgWebP = e.target.getAttribute('data-back-webp'); 43 bgWebP = e.target.dataset.backWebp; 44 // Was bgWebP = e.target.getAttribute('data-back-webp'); 43 45 if (bgWebP) { 44 46 console.log('replacing data-back with data-back-webp'); … … 46 48 } 47 49 } 48 var dPR = getdPR(); 49 var targetWidth = Math.round(e.target.offsetWidth * dPR); 50 var targetHeight = Math.round(e.target.offsetHeight * dPR); 51 if ( 0 === bg.search(/\[/) ) { 52 } else if (!shouldAutoScale(e.target)){ 53 } else if (lazySizes.hC(e.target,'wp-block-cover')) { 54 console.log('found wp-block-cover with data-back'); 55 if (lazySizes.hC(e.target,'has-parallax')) { 56 console.log('also has-parallax with data-back'); 57 targetWidth = Math.round(window.screen.width * dPR); 58 targetHeight = Math.round(window.screen.height * dPR); 59 } else if (targetHeight<300) { 60 targetHeight = 430; 61 } 62 bg = constrainSrc(bg,targetWidth,targetHeight,'bg-cover'); 63 } else if (lazySizes.hC(e.target,'cover-image')){ 64 console.log('found .cover-image with data-back'); 65 bg = constrainSrc(bg,targetWidth,targetHeight,'bg-cover'); 66 } else if (lazySizes.hC(e.target,'elementor-bg')){ 67 console.log('found elementor-bg with data-back'); 68 bg = constrainSrc(bg,targetWidth,targetHeight,'bg-cover'); 69 } else if (lazySizes.hC(e.target,'et_parallax_bg')){ 70 console.log('found et_parallax_bg with data-back'); 71 bg = constrainSrc(bg,targetWidth,targetHeight,'bg-cover'); 72 } else if (lazySizes.hC(e.target,'bg-image-crop')){ 73 console.log('found bg-image-crop with data-back'); 74 bg = constrainSrc(bg,targetWidth,targetHeight,'bg-cover'); 75 } else { 76 console.log('found other data-back'); 77 bg = constrainSrc(bg,targetWidth,targetHeight,'bg'); 78 } 50 bg = constrainBg(bg,e.target); 79 51 if ( e.target.style.backgroundImage && -1 === e.target.style.backgroundImage.search(/^initial/) ) { 80 52 // Convert JSON for multiple URLs. … … 114 86 } 115 87 } 88 // Handle CSS images from SWIS. 89 swisLazyId = e.target.dataset.swisLazyId; 90 if (swisLazyId && swisLazyId in swis_lazy_css_images) { 91 console.log('fetching CSS images for swisLazyId ' + swisLazyId); 92 var css_images = swis_lazy_css_images[swisLazyId]; 93 var swisStyle = document.querySelector('style#swis-lazy-css-styles'); 94 css_images.forEach( 95 function(css_image){ 96 if (!css_image.url) { 97 return; 98 } 99 if(ewww_webp_supported && css_image.webp_url) { 100 console.log('webp supported, using webp url for css image'); 101 css_image.url = css_image.webp_url; 102 } 103 css_image.url = constrainBg(css_image.url,e.target); 104 console.log('processing CSS image: ' + css_image.url + ' with hash ' + css_image.hash); 105 var cssRule = css_image.selector + ' {--swis-bg-' + css_image.hash + ': url(' + css_image.url + '); }'; 106 swisStyle.sheet.insertRule(cssRule); 107 } 108 ); 109 } 116 110 } 117 111 }, false); 118 112 } 113 114 var constrainBg = function(bg,target){ 115 if ( 0 === bg.search(/\[/) ) { 116 console.log('multiple URLs, not autoscaling background image'); 117 return bg; 118 } 119 if (!shouldAutoScale(target)){ 120 console.log('not autoscaling background image'); 121 return bg; 122 } 123 var dPR = getdPR(); 124 if ( dPR < eio_lazy_vars.bg_min_dpr ) { 125 dPR = eio_lazy_vars.bg_min_dpr; 126 } 127 var targetWidth = Math.round(target.offsetWidth * dPR); 128 var targetHeight = Math.round(target.offsetHeight * dPR); 129 var bgType = 'bg'; 130 if (lazySizes.hC(target,'wp-block-cover')||lazySizes.hC(target,'wp-block-cover__image-background')){ 131 console.log('found wp-block-cover with data-back'); 132 if (lazySizes.hC(target,'has-parallax')) { 133 console.log('also has-parallax with data-back'); 134 targetWidth = Math.round(window.screen.width * dPR); 135 targetHeight = Math.round(window.screen.height * dPR); 136 } else if (targetHeight<300) { 137 targetHeight = 430; 138 } 139 bgType = 'bg-cover'; 140 } else if (lazySizes.hC(target,'cover-image')){ 141 console.log('found .cover-image with data-back'); 142 bgType = 'bg-cover'; 143 } else if (lazySizes.hC(target,'elementor-bg')){ 144 console.log('found elementor-bg with data-back'); 145 bgType = 'bg-cover'; 146 } else if (lazySizes.hC(target,'et_parallax_bg')){ 147 console.log('found et_parallax_bg with data-back'); 148 bgType = 'bg-cover'; 149 } else if (lazySizes.hC(target,'bg-image-crop')){ 150 bgType = 'bg-cover'; 151 console.log('found bg-image-crop with data-back'); 152 } else { 153 console.log('found other data-back'); 154 } 155 var imgAspect = getAspectRatio(target); 156 if ('bg' == bgType && targetHeight > 1 && targetWidth > 1 && imgAspect > 0) { 157 var minimum_width = Math.ceil(targetHeight * imgAspect); 158 var minimum_height = Math.ceil(targetWidth / imgAspect); 159 console.log('minimum_width = ' + minimum_width + ', targetWidth = ' + targetWidth); 160 console.log('minimum_height = ' + minimum_height + ', targetHeight = ' + targetHeight); 161 if (targetWidth+2 < minimum_width) { 162 targetWidth = minimum_width; 163 } 164 if (targetHeight+2 < minimum_height) { 165 targetHeight = minimum_height; 166 } 167 var realDims = getRealDimensionsFromImg(target); 168 if (Math.abs(realDims.w - targetWidth) < 5 || Math.abs(realDims.h - targetHeight) < 5) { 169 console.log('real dimensions within 5px of target sizes, no scaling'); 170 return bg; 171 } 172 } 173 bg = constrainSrc(bg,targetWidth,targetHeight,bgType); 174 return bg; 175 }; 119 176 120 177 var shouldAutoScale = function(target){ … … 294 351 295 352 var getRealDimensionsFromImg = function(img){ 296 var realWidth = img. getAttribute('data-eio-rwidth');297 var realHeight = img. getAttribute('data-eio-rheight');353 var realWidth = img.dataset.eioRwidth; 354 var realHeight = img.dataset.eioRheight; 298 355 if (realWidth > 1 && realHeight > 1) { 299 356 return {w:realWidth,h:realHeight}; … … 411 468 } 412 469 if (e.target._lazysizesWidth === undefined) { 470 if (!eio_lazy_vars.use_dpr && window.devicePixelRatio > 1) { 471 console.log('use_dpr is disabled, reversing auto-sizes by dpr ' + window.devicePixelRatio); 472 e.detail.width = Math.ceil(e.detail.width / window.devicePixelRatio); 473 } 413 474 return; 414 475 } … … 417 478 console.log('no way! ' + e.detail.width + ' is smaller than ' + e.target._lazysizesWidth); 418 479 e.detail.width = e.target._lazysizesWidth; 480 } 481 if (!eio_lazy_vars.use_dpr && window.devicePixelRatio > 1) { 482 console.log('use_dpr is disabled, reversing auto-sizes by dpr ' + window.devicePixelRatio); 483 e.detail.width = Math.ceil(e.detail.width / window.devicePixelRatio); 419 484 } 420 485 }); -
easy-image-optimizer/trunk/includes/lazysizes-pre.js
r3197623 r3398277 1 1 if (typeof ewww_webp_supported === 'undefined') { 2 2 var ewww_webp_supported = false; 3 } 4 if (typeof swis_lazy_css_images === 'undefined') { 5 var swis_lazy_css_images = {}; 3 6 } 4 7 window.lazySizesConfig = window.lazySizesConfig || {}; … … 18 21 } 19 22 console.log( 'root margin: ' + window.lazySizesConfig.expand ); 23 for ( const [css_index, css_image] of Object.entries(swis_lazy_css_images)){ 24 console.log('processing css image ' + css_index + ': ' + css_image[0].url); 25 try { 26 document.querySelectorAll(css_image[0].selector).forEach((el) => { 27 if (!el.classList.contains('lazyload')) { 28 console.log('adding lazyload to css image ' + css_index + ': ' + css_image[0].url); 29 el.classList.add('lazyload'); 30 el.dataset.swisLazyId = css_index; 31 if (css_image[0].rwidth > 5 && css_image[0].rheight > 5) { 32 el.dataset.eioRwidth = css_image[0].rwidth; 33 el.dataset.eioRheight = css_image[0].rheight; 34 } 35 } 36 }); 37 } catch (e) { 38 console.log('error processing css image(s) for "' + css_index[0].selector + '": ' + e); 39 } 40 } -
easy-image-optimizer/trunk/includes/lazysizes.min.js
r3197623 r3398277 1 var ewww_webp_supported ;void 0===ewww_webp_supported&&(ewww_webp_supported=!1),window.lazySizesConfig=window.lazySizesConfig||{},window.lazySizesConfig.expand=500<document.documentElement.clientHeight&&500<document.documentElement.clientWidth?1e3:740,window.lazySizesConfig.iframeLoadMode=1,"undefined"==typeof eio_lazy_vars&&(eio_lazy_vars={exactdn_domain:".exactdn.com",threshold:0,skip_autoscale:0,use_dpr:0}),50<eio_lazy_vars.threshold&&(window.lazySizesConfig.expand=eio_lazy_vars.threshold),function(e,t){function a(){t(e.lazySizes),e.removeEventListener("lazyunveilread",a,!0)}t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?a():e.addEventListener("lazyunveilread",a,!0)}(window,function(e,n,o){"use strict";var s,l,d={};function c(e,t,a){var r,i;d[e]||(r=n.createElement(t?"link":"script"),i=n.getElementsByTagName("script")[0],t?(r.rel="stylesheet",r.href=e):(r.onload=function(){r.onerror=null,r.onload=null,a()},r.onerror=r.onload,r.src=e),d[e]=!0,d[r.src||r.href]=!0,i.parentNode.insertBefore(r,i))}n.addEventListener&&(l=/\(|\)|\s|'/,s=function(e,t){var a=n.createElement("img");a.onload=function(){a.onload=null,a.onerror=null,a=null,t()},a.onerror=a.onload,a.src=e,a&&a.complete&&a.onload&&a.onload()},addEventListener("lazybeforeunveil",function(e){var t,a,r;if(e.detail.instance==o&&!e.defaultPrevented){var i=e.target;if("none"==i.preload&&(i.preload=i.getAttribute("data-preload")||"auto"),null!=i.getAttribute("data-autoplay"))if(i.getAttribute("data-expand")&&!i.autoplay)try{i.play()}catch(e){}else requestAnimationFrame(function(){i.setAttribute("data-expand","-10"),o.aC(i,o.cfg.lazyClass)});(t=i.getAttribute("data-link"))&&c(t,!0),(t=i.getAttribute("data-script"))&&(e.detail.firesLoad=!0,c(t,null,function(){e.detail.firesLoad=!1,o.fire(i,"_lazyloaded",{},!0,!0)})),(t=i.getAttribute("data-require"))&&(o.cfg.requireJs?o.cfg.requireJs([t]):c(t)),(a=i.getAttribute("data-bg"))&&(e.detail.firesLoad=!0,s(a,function(){i.style.backgroundImage="url("+(l.test(a)?JSON.stringify(a):a)+")",e.detail.firesLoad=!1,o.fire(i,"_lazyloaded",{},!0,!0)})),(r=i.getAttribute("data-poster"))&&(e.detail.firesLoad=!0,s(r,function(){i.poster=r,e.detail.firesLoad=!1,o.fire(i,"_lazyloaded",{},!0,!0)}))}},!1))}),function(e,t){function a(){t(e.lazySizes),e.removeEventListener("lazyunveilread",a,!0)}t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?a():e.addEventListener("lazyunveilread",a,!0)}(window,function(u,f,g){"use strict";var n;f.addEventListener&&(n=/\(|\)|\s|'/,addEventListener("lazybeforeunveil",function(e){var t,a,r,i;e.detail.instance==g&&(e.defaultPrevented||("none"==e.target.preload&&(e.target.preload="auto"),(r=e.target.getAttribute("data-back"))&&(ewww_webp_supported&&(i=e.target.getAttribute("data-back-webp"))&&(r=i),t=v(),a=Math.round(e.target.offsetWidth*t),i=Math.round(e.target.offsetHeight*t),0===r.search(/\[/)||o(e.target)&&(r=g.hC(e.target,"wp-block-cover")?(g.hC(e.target,"has-parallax")?(a=Math.round(u.screen.width*t),i=Math.round(u.screen.height*t)):i<300&&(i=430),s(r,a,i,"bg-cover")):g.hC(e.target,"cover-image")||g.hC(e.target,"elementor-bg")||g.hC(e.target,"et_parallax_bg")||g.hC(e.target,"bg-image-crop")?s(r,a,i,"bg-cover"):s(r,a,i,"bg")),e.target.style.backgroundImage&&-1===e.target.style.backgroundImage.search(/^initial/)?0===r.search(/\[/)?((r=JSON.parse(r)).forEach(function(e){n.test(e)&&JSON.stringify(e)}),r='url("'+r.join('"), url("')+'"',i=e.target.style.backgroundImage+", "+r,e.target.style.backgroundImage=i):e.target.style.backgroundImage=e.target.style.backgroundImage+', url("'+(n.test(r)?JSON.stringify(r):r)+'")':0===r.search(/\[/)?((r=JSON.parse(r)).forEach(function(e){n.test(e)&&JSON.stringify(e)}),r='url("'+r.join('"), url("')+'"',e.target.style.backgroundImage=r):e.target.style.backgroundImage="url("+(n.test(r)?JSON.stringify(r):r)+")")))},!1));function h(e){var t=e.getAttribute("data-eio-rwidth"),e=e.getAttribute("data-eio-rheight");return 1<t&&1<e?{w:t,h:e}:{w:0,h:0}}function m(e,t=!1){var a=v(),r=Math.round(e.offsetWidth*a),i=Math.round(e.offsetHeight*a),n=e.getAttribute("data-src"),a=e.getAttribute("data-src-webp");ewww_webp_supported&&a&&-1==n.search("webp=1")&&!t&&(n=a),o(e)&&(a=e,a=g.hC(a,"et_pb_jt_filterable_grid_item_image")||g.hC(a,"ss-foreground-image")||g.hC(a,"img-crop")?"img-crop":g.hC(a,"object-cover")&&(g.hC(a,"object-top")||g.hC(a,"object-bottom"))?"img-w":g.hC(a,"object-cover")&&(g.hC(a,"object-left")||g.hC(a,"object-right"))?"img-h":g.hC(a,"ct-image")&&g.hC(a,"object-cover")||!a.getAttribute("data-srcset")&&!a.srcset&&a.offsetHeight>a.offsetWidth&&1<l(a)?"img-crop":"img",(a=s(n,r,i,a,t))&&n!=a&&(t&&e.setAttribute("src",a),e.setAttribute("data-src",a)))}var o=function(e){if(1==eio_lazy_vars.skip_autoscale)return!1;for(var t=e,a=0;a<=7;a++){if(t.hasAttributes())for(var r=t.attributes,i=/skip-autoscale/,a=r.length-1;0<=a;a--){if(i.test(r[a].name))return!1;if(i.test(r[a].value))return!1}if(!t.parentNode||1!==t.parentNode.nodeType||!t.parentNode.hasAttributes)break;t=t.parentNode}return!0},s=function(e,t,a,r,i=!1){if(null===e)return e;var n=/w=(\d+)/,o=/fit=(\d+),(\d+)/,s=/resize=(\d+),(\d+)/,l=decodeURIComponent(e);if(/\.svg(\?.+)?$/.exec(l))return e;if(0<e.search("\\?")&&0<e.search(eio_lazy_vars.exactdn_domain)){var d=s.exec(l);if(d&&(t<d[1]||i))return"img-w"===r?l.replace(s,"w="+t):"img-h"===r?l.replace(s,"h="+a):l.replace(s,"resize="+t+","+a);s=n.exec(e);if(s&&(t<=s[1]||i)){if("img-h"===r)return l.replace(n,"h="+a);if("bg-cover"!==r&&"img-crop"!==r)return e.replace(n,"w="+t);var c=Math.abs(s[1]-t);return 20<c||a<1080?e.replace(n,"resize="+t+","+a):e}c=o.exec(l);if(c&&(t<c[1]||i)){if("bg-cover"!==r&&"img-crop"!==r)return"img-w"===r?l.replace(o,"w="+t):"img-h"===r?l.replace(o,"h="+a):l.replace(o,"fit="+t+","+a);l=Math.abs(c[1]-t),o=Math.abs(c[2]-a);return 20<l||20<o?e.replace(n,"resize="+t+","+a):e}if(!s&&!c&&!d)return"img"===r?e+"&fit="+t+","+a:"bg-cover"===r||"img-crop"===r?e+"&resize="+t+","+a:"img-h"===r||t<a?e+"&h="+a:e+"&w="+t}return-1==e.search("\\?")&&0<e.search(eio_lazy_vars.exactdn_domain)?"img"===r?e+"?fit="+t+","+a:"bg-cover"===r||"img-crop"===r?e+"?resize="+t+","+a:"img-h"===r||t<a?e+"?h="+a:e+"?w="+t:e},p=function(e){e=/-(\d+)x(\d+)\./.exec(e);return e&&1<e[1]&&1<e[2]?{w:e[1],h:e[2]}:{w:0,h:0}},l=function(e){var t=e.getAttribute("width"),a=e.getAttribute("height");if(1<t&&1<a)return t/a;a=!1;if(a=(a=e.src&&-1<e.src.search("http")?e.src:a)||e.getAttribute("data-src")){var r=p(a);if(r.w&&r.h)return r.w/r.h}r=h(e);if(r.w&&r.h)return r.w/r.h;e=function(e){var t;if(e.srcset?t=e.srcset.split(","):(e=e.getAttribute("data-srcset"))&&(t=e.split(",")),t){var a=0,r=t.length;if(r){for(;a<r;a++){var i,n=t[a].trim().split(" ");!n[0].length||(n=p(n[0])).w&&n.h&&(i=n)}if(i.w&&i.h)return i}}return{w:0,h:0}}(e);return e.w&&e.h?e.w/e.h:0},v=function(){return eio_lazy_vars.use_dpr&&1<u.devicePixelRatio?u.devicePixelRatio:1};f.addEventListener("lazybeforesizes",function(e){e.target.getAttribute("data-src");var t=l(e.target);1<e.target.clientHeight&&t&&(t=Math.ceil(t*e.target.clientHeight),e.detail.width+2<t&&(e.detail.width=t)),void 0!==e.target._lazysizesWidth&&e.detail.width<e.target._lazysizesWidth&&(e.detail.width=e.target._lazysizesWidth)}),f.addEventListener("lazybeforeunveil",function(e){var t,a,r,i,n=e.target,o=n.getAttribute("data-srcset");n.naturalWidth&&!o&&1<n.naturalWidth&&1<n.naturalHeight&&(t=v(),a=n.naturalWidth,r=n.naturalHeight,(e=h(n)).w&&e.w>a&&(a=e.w,r=e.h),a=n.clientWidth&&1.25*n.clientWidth*t<a,r=n.clientHeight&&1.25*n.clientHeight*t<r,(a||r)&&m(n)),ewww_webp_supported&&(!o||(i=n.getAttribute("data-srcset-webp"))&&n.setAttribute("data-srcset",i),(i=n.getAttribute("data-src-webp"))&&n.setAttribute("data-src",i))});function e(e=!1){e.type&&"load"===e.type&&g.autoSizer.checkElems(),v();var t,a=f.getElementsByClassName(g.cfg.loadedClass),r=a.length;if(r)for(t=0;t<r;t++){var i,n,o,s,l,d,c=a[t];c.src&&!c.srcset&&1<c.naturalWidth&&1<c.naturalHeight&&1<c.clientWidth&&1<c.clientHeight&&(i=c.naturalWidth,n=c.naturalHeight,o=u.innerWidth,s=u.innerHeight,l=h(c),d=p(c.src),l.w?o=l.w:d.w&&(o=d.w),l.h?s=l.h:d.h&&(s=d.h),l=c.clientWidth,d=c.clientHeight,(1.1*i<l&&l<=o||1.1*n<d&&d<=s)&&m(c,!0))}}var t,a,r,i,d=(t=e,i=function(){a=null,t()},function(){r=Date.now(),a=a||setTimeout(c,99)});function c(){var e=Date.now()-r;e<99?setTimeout(c,99-e):(u.requestIdleCallback||i)(i)}addEventListener("load",e),addEventListener("resize",d),setTimeout(e,2e4)}),function(e,t){t=t(e,e.document,Date);e.lazySizes=t,"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:{},function(r,f,n){"use strict";var g,h;if(!function(){var e,t={lazyClass:"lazyload",loadedClass:"lazyloaded",loadingClass:"lazyloading",preloadClass:"lazypreload",errorClass:"lazyerror",autosizesClass:"lazyautosizes",fastLoadedClass:"ls-is-cached",iframeLoadMode:0,srcAttr:"data-src",srcsetAttr:"data-srcset",sizesAttr:"data-sizes",minSize:40,customMedia:{},init:!0,expFactor:1.5,hFac:.8,loadMode:2,loadHidden:!0,ricTimeout:0,throttleDelay:125};for(e in h=r.lazySizesConfig||r.lazysizesConfig||{},t)e in h||(h[e]=t[e])}(),!f||!f.getElementsByClassName)return{init:function(){},cfg:h,noSupport:!0};function c(e,t){E(e,t)||e.setAttribute("class",(e[v]("class")||"").trim()+" "+t)}function u(e,t){(t=E(e,t))&&e.setAttribute("class",(e[v]("class")||"").replace(t," "))}function m(e,t){var a;!l&&(a=r.picturefill||h.pf)?(t&&t.src&&!e[v]("srcset")&&e.setAttribute("srcset",t.src),a({reevaluate:!0,elements:[e]})):t&&t.src&&(e.src=t.src)}var a,i,t,o,s,p=f.documentElement,l=r.HTMLPictureElement,d="addEventListener",v="getAttribute",e=r[d].bind(r),y=r.setTimeout,b=r.requestAnimationFrame||y,z=r.requestIdleCallback,w=/^picture$/i,_=["load","error","lazyincluded","_lazyloaded"],C={},A=Array.prototype.forEach,E=function(e,t){return C[t]||(C[t]=new RegExp("(\\s|^)"+t+"(\\s|$)")),C[t].test(e[v]("class")||"")&&C[t]},L=function(t,a,e){var r=e?d:"removeEventListener";e&&L(t,a),_.forEach(function(e){t[r](e,a)})},x=function(e,t,a,r,i){var n=f.createEvent("Event");return(a=a||{}).instance=g,n.initEvent(t,!r,!i),n.detail=a,e.dispatchEvent(n),n},N=function(e,t){return(getComputedStyle(e,null)||{})[t]},M=function(e,t,a){for(a=a||e.offsetWidth;a<h.minSize&&t&&!e._lazysizesWidth;)a=t.offsetWidth,t=t.parentNode;return a},W=(o=[],s=t=[],k._lsFlush=S,k);function S(){var e=s;for(s=t.length?o:t,i=!(a=!0);e.length;)e.shift()();a=!1}function k(e,t){a&&!t?e.apply(this,arguments):(s.push(e),i||(i=!0,(f.hidden?y:b)(S)))}function H(a,e){return e?function(){W(a)}:function(){var e=this,t=arguments;W(function(){a.apply(e,t)})}}function I(e){function t(){var e=n.now()-r;e<99?y(t,99-e):(z||i)(i)}var a,r,i=function(){a=null,e()};return function(){r=n.now(),a=a||y(t,99)}}var T,j,B,O,R,q,F,J,P,D,$,U,G,K,Q,V,X,Y,Z,ee,te,ae,re,ie,ne,oe,se,le,de,ce,ue,fe=(Z=/^img$/i,ee=/^iframe$/i,te="onscroll"in r&&!/(gle|ing)bot/.test(navigator.userAgent),ie=-1,ne=function(e){return(U=null==U?"hidden"==N(f.body,"visibility"):U)||!("hidden"==N(e.parentNode,"visibility")&&"hidden"==N(e,"visibility"))},G=he,Q=re=ae=0,V=h.throttleDelay,X=h.ricTimeout,Y=z&&49<X?function(){z(me,{timeout:X}),X!==h.ricTimeout&&(X=h.ricTimeout)}:H(function(){y(me)},!0),se=H(pe),le=function(e){se({target:e.target})},de=H(function(t,e,a,r,i){var n,o,s,l,d;(s=x(t,"lazybeforeunveil",e)).defaultPrevented||(r&&(a?c(t,h.autosizesClass):t.setAttribute("sizes",r)),n=t[v](h.srcsetAttr),a=t[v](h.srcAttr),i&&(o=(d=t.parentNode)&&w.test(d.nodeName||"")),l=e.firesLoad||"src"in t&&(n||a||o),s={target:t},c(t,h.loadingClass),l&&(clearTimeout(B),B=y(ge,2500),L(t,le,!0)),o&&A.call(d.getElementsByTagName("source"),ve),n?t.setAttribute("srcset",n):a&&!o&&(ee.test(t.nodeName)?(r=a,0==(d=(e=t).getAttribute("data-load-mode")||h.iframeLoadMode)?e.contentWindow.location.replace(r):1==d&&(e.src=r)):t.src=a),i&&(n||o)&&m(t,{src:a})),t._lazyRace&&delete t._lazyRace,u(t,h.lazyClass),W(function(){var e=t.complete&&1<t.naturalWidth;l&&!e||(e&&c(t,h.fastLoadedClass),pe(s),t._lazyCache=!0,y(function(){"_lazyCache"in t&&delete t._lazyCache},9)),"lazy"==t.loading&&re--},!0)}),ue=I(function(){h.loadMode=3,oe()}),{_:function(){R=n.now(),g.elements=f.getElementsByClassName(h.lazyClass),T=f.getElementsByClassName(h.lazyClass+" "+h.preloadClass),e("scroll",oe,!0),e("resize",oe,!0),e("pageshow",function(e){var t;!e.persisted||(t=f.querySelectorAll("."+h.loadingClass)).length&&t.forEach&&b(function(){t.forEach(function(e){e.complete&&ce(e)})})}),r.MutationObserver?new MutationObserver(oe).observe(p,{childList:!0,subtree:!0,attributes:!0}):(p[d]("DOMNodeInserted",oe,!0),p[d]("DOMAttrModified",oe,!0),setInterval(oe,999)),e("hashchange",oe,!0),["focus","mouseover","click","load","transitionend","animationend"].forEach(function(e){f[d](e,oe,!0)}),/d$|^c/.test(f.readyState)?be():(e("load",be),f[d]("DOMContentLoaded",oe),y(be,2e4)),g.elements.length?(he(),W._lsFlush()):oe()},checkElems:oe=function(e){var t;(e=!0===e)&&(X=33),K||(K=!0,(t=V-(n.now()-Q))<0&&(t=0),e||t<9?Y():y(Y,t))},unveil:ce=function(e){var t,a,r,i;e._lazyRace||(!(i="auto"==(r=(a=Z.test(e.nodeName))&&(e[v](h.sizesAttr)||e[v]("sizes"))))&&j||!a||!e[v]("src")&&!e.srcset||e.complete||E(e,h.errorClass)||!E(e,h.lazyClass))&&(t=x(e,"lazyunveilread").detail,i&&Ce.updateElem(e,!0,e.offsetWidth),e._lazyRace=!0,re++,de(e,t,i,r,a))},_aLSL:ye});function ge(e){re--,e&&!(re<0)&&e.target||(re=0)}function he(){var e,t,a,r,i,n,o,s,l,d,c,u=g.elements;if((O=h.loadMode)&&re<8&&(e=u.length)){for(t=0,ie++;t<e;t++)if(u[t]&&!u[t]._lazyRace)if(!te||g.prematureUnveil&&g.prematureUnveil(u[t]))ce(u[t]);else if((o=u[t][v]("data-expand"))&&(i=+o)||(i=ae),l||(l=!h.expand||h.expand<1?500<p.clientHeight&&500<p.clientWidth?500:370:h.expand,d=(g._defEx=l)*h.expFactor,c=h.hFac,U=null,ae<d&&re<1&&2<ie&&2<O&&!f.hidden?(ae=d,ie=0):ae=1<O&&1<ie&&re<6?l:0),s!==i&&(q=innerWidth+i*c,F=innerHeight+i,n=-1*i,s=i),d=u[t].getBoundingClientRect(),($=d.bottom)>=n&&(J=d.top)<=F&&(D=d.right)>=n*c&&(P=d.left)<=q&&($||D||P||J)&&(h.loadHidden||ne(u[t]))&&(j&&re<3&&!o&&(O<3||ie<4)||function(e,t){var a,r=e,i=ne(e);for(J-=t,$+=t,P-=t,D+=t;i&&(r=r.offsetParent)&&r!=f.body&&r!=p;)(i=0<(N(r,"opacity")||1))&&"visible"!=N(r,"overflow")&&(a=r.getBoundingClientRect(),i=D>a.left&&P<a.right&&$>a.top-1&&J<a.bottom+1);return i}(u[t],i))){if(ce(u[t]),r=!0,9<re)break}else!r&&j&&!a&&re<4&&ie<4&&2<O&&(T[0]||h.preloadAfterLoad)&&(T[0]||!o&&($||D||P||J||"auto"!=u[t][v](h.sizesAttr)))&&(a=T[0]||u[t]);a&&!r&&ce(a)}}function me(){K=!1,Q=n.now(),G()}function pe(e){var t=e.target;t._lazyCache?delete t._lazyCache:(ge(e),c(t,h.loadedClass),u(t,h.loadingClass),L(t,le),x(t,"lazyloaded"))}function ve(e){var t,a=e[v](h.srcsetAttr);(t=h.customMedia[e[v]("data-media")||e[v]("media")])&&e.setAttribute("media",t),a&&e.setAttribute("srcset",a)}function ye(){3==h.loadMode&&(h.loadMode=2),ue()}function be(){j||(n.now()-R<999?y(be,999):(j=!0,h.loadMode=3,oe(),e("scroll",ye,!0)))}var ze,we,_e,Ce=(we=H(function(e,t,a,r){var i,n,o;if(e._lazysizesWidth=r,e.setAttribute("sizes",r+="px"),w.test(t.nodeName||""))for(n=0,o=(i=t.getElementsByTagName("source")).length;n<o;n++)i[n].setAttribute("sizes",r);a.detail.dataAttr||m(e,a.detail)}),{_:function(){ze=f.getElementsByClassName(h.autosizesClass),e("resize",_e)},checkElems:_e=I(function(){var e,t=ze.length;if(t)for(e=0;e<t;e++)Ae(ze[e])}),updateElem:Ae});function Ae(e,t,a){var r=e.parentNode;r&&(a=M(e,r,a),(t=x(e,"lazybeforesizes",{width:a,dataAttr:!!t})).defaultPrevented||(a=t.detail.width)&&a!==e._lazysizesWidth&&we(e,r,t,a))}function Ee(){!Ee.i&&f.getElementsByClassName&&(Ee.i=!0,Ce._(),fe._())}return y(function(){h.init&&Ee()}),g={cfg:h,autoSizer:Ce,loader:fe,init:Ee,uP:m,aC:c,rC:u,hC:E,fire:x,gW:M,rAF:W}});1 var ewww_webp_supported,swis_lazy_css_images;void 0===ewww_webp_supported&&(ewww_webp_supported=!1),void 0===swis_lazy_css_images&&(swis_lazy_css_images={}),window.lazySizesConfig=window.lazySizesConfig||{},window.lazySizesConfig.expand=500<document.documentElement.clientHeight&&500<document.documentElement.clientWidth?1e3:740,window.lazySizesConfig.iframeLoadMode=1,"undefined"==typeof eio_lazy_vars&&(eio_lazy_vars={exactdn_domain:".exactdn.com",threshold:0,skip_autoscale:0,use_dpr:0}),50<eio_lazy_vars.threshold&&(window.lazySizesConfig.expand=eio_lazy_vars.threshold);for(const[a,b]of Object.entries(swis_lazy_css_images))try{document.querySelectorAll(b[0].selector).forEach(e=>{e.classList.contains("lazyload")||(e.classList.add("lazyload"),e.dataset.swisLazyId=a,5<b[0].rwidth&&5<b[0].rheight&&(e.dataset.eioRwidth=b[0].rwidth,e.dataset.eioRheight=b[0].rheight))})}catch(e){}!function(e,t){function a(){t(e.lazySizes),e.removeEventListener("lazyunveilread",a,!0)}t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?a():e.addEventListener("lazyunveilread",a,!0)}(window,function(e,n,s){"use strict";var o,l,d={};function c(e,t,a){var i,r;d[e]||(i=n.createElement(t?"link":"script"),r=n.getElementsByTagName("script")[0],t?(i.rel="stylesheet",i.href=e):(i.onload=function(){i.onerror=null,i.onload=null,a()},i.onerror=i.onload,i.src=e),d[e]=!0,d[i.src||i.href]=!0,r.parentNode.insertBefore(i,r))}n.addEventListener&&(l=/\(|\)|\s|'/,o=function(e,t){var a=n.createElement("img");a.onload=function(){a.onload=null,a.onerror=null,a=null,t()},a.onerror=a.onload,a.src=e,a&&a.complete&&a.onload&&a.onload()},addEventListener("lazybeforeunveil",function(e){var t,a,i;if(e.detail.instance==s&&!e.defaultPrevented){var r=e.target;if("none"==r.preload&&(r.preload=r.getAttribute("data-preload")||"auto"),null!=r.getAttribute("data-autoplay"))if(r.getAttribute("data-expand")&&!r.autoplay)try{r.play()}catch(e){}else requestAnimationFrame(function(){r.setAttribute("data-expand","-10"),s.aC(r,s.cfg.lazyClass)});(t=r.getAttribute("data-link"))&&c(t,!0),(t=r.getAttribute("data-script"))&&(e.detail.firesLoad=!0,c(t,null,function(){e.detail.firesLoad=!1,s.fire(r,"_lazyloaded",{},!0,!0)})),(t=r.getAttribute("data-require"))&&(s.cfg.requireJs?s.cfg.requireJs([t]):c(t)),(a=r.getAttribute("data-bg"))&&(e.detail.firesLoad=!0,o(a,function(){r.style.backgroundImage="url("+(l.test(a)?JSON.stringify(a):a)+")",e.detail.firesLoad=!1,s.fire(r,"_lazyloaded",{},!0,!0)})),(i=r.getAttribute("data-poster"))&&(e.detail.firesLoad=!0,o(i,function(){r.poster=i,e.detail.firesLoad=!1,s.fire(r,"_lazyloaded",{},!0,!0)}))}},!1))}),function(e,t){function a(){t(e.lazySizes),e.removeEventListener("lazyunveilread",a,!0)}t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?a():e.addEventListener("lazyunveilread",a,!0)}(window,function(u,f,h){"use strict";var r;f.addEventListener&&(r=/\(|\)|\s|'/,addEventListener("lazybeforeunveil",function(t){var e,a,i;t.detail.instance==h&&(t.defaultPrevented||("none"==t.target.preload&&(t.target.preload="auto"),(a=t.target.dataset.back)&&(ewww_webp_supported&&(e=t.target.dataset.backWebp)&&(a=e),a=n(a,t.target),t.target.style.backgroundImage&&-1===t.target.style.backgroundImage.search(/^initial/)?0===a.search(/\[/)?((a=JSON.parse(a)).forEach(function(e){r.test(e)&&JSON.stringify(e)}),a='url("'+a.join('"), url("')+'"',e=t.target.style.backgroundImage+", "+a,t.target.style.backgroundImage=e):t.target.style.backgroundImage=t.target.style.backgroundImage+', url("'+(r.test(a)?JSON.stringify(a):a)+'")':0===a.search(/\[/)?((a=JSON.parse(a)).forEach(function(e){r.test(e)&&JSON.stringify(e)}),a='url("'+a.join('"), url("')+'"',t.target.style.backgroundImage=a):t.target.style.backgroundImage="url("+(r.test(a)?JSON.stringify(a):a)+")"),(a=t.target.dataset.swisLazyId)&&a in swis_lazy_css_images&&(a=swis_lazy_css_images[a],i=f.querySelector("style#swis-lazy-css-styles"),a.forEach(function(e){e.url&&(ewww_webp_supported&&e.webp_url&&(e.url=e.webp_url),e.url=n(e.url,t.target),e=e.selector+" {--swis-bg-"+e.hash+": url("+e.url+"); }",i.sheet.insertRule(e))}))))},!1));function g(e,t=!1){var a=y(),i=Math.round(e.offsetWidth*a),r=Math.round(e.offsetHeight*a),n=e.getAttribute("data-src"),a=e.getAttribute("data-src-webp");ewww_webp_supported&&a&&-1==n.search("webp=1")&&!t&&(n=a),o(e)&&(a=e,a=h.hC(a,"et_pb_jt_filterable_grid_item_image")||h.hC(a,"ss-foreground-image")||h.hC(a,"img-crop")?"img-crop":h.hC(a,"object-cover")&&(h.hC(a,"object-top")||h.hC(a,"object-bottom"))?"img-w":h.hC(a,"object-cover")&&(h.hC(a,"object-left")||h.hC(a,"object-right"))?"img-h":h.hC(a,"ct-image")&&h.hC(a,"object-cover")||!a.getAttribute("data-srcset")&&!a.srcset&&a.offsetHeight>a.offsetWidth&&1<d(a)?"img-crop":"img",(a=l(n,i,r,a,t))&&n!=a&&(t&&e.setAttribute("src",a),e.setAttribute("data-src",a)))}var n=function(e,t){if(0===e.search(/\[/))return e;if(!o(t))return e;var a=y();a<eio_lazy_vars.bg_min_dpr&&(a=eio_lazy_vars.bg_min_dpr);var i=Math.round(t.offsetWidth*a),r=Math.round(t.offsetHeight*a),n="bg";h.hC(t,"wp-block-cover")||h.hC(t,"wp-block-cover__image-background")?(h.hC(t,"has-parallax")?(i=Math.round(u.screen.width*a),r=Math.round(u.screen.height*a)):r<300&&(r=430),n="bg-cover"):(h.hC(t,"cover-image")||h.hC(t,"elementor-bg")||h.hC(t,"et_parallax_bg")||h.hC(t,"bg-image-crop"))&&(n="bg-cover");var s=d(t);if("bg"==n&&1<r&&1<i&&0<s){a=Math.ceil(r*s),s=Math.ceil(i/s);i+2<a&&(i=a),r+2<s&&(r=s);t=p(t);if(Math.abs(t.w-i)<5||Math.abs(t.h-r)<5)return e}return e=l(e,i,r,n)},o=function(e){if(1==eio_lazy_vars.skip_autoscale)return!1;for(var t=e,a=0;a<=7;a++){if(t.hasAttributes())for(var i=t.attributes,r=/skip-autoscale/,a=i.length-1;0<=a;a--){if(r.test(i[a].name))return!1;if(r.test(i[a].value))return!1}if(!t.parentNode||1!==t.parentNode.nodeType||!t.parentNode.hasAttributes)break;t=t.parentNode}return!0},l=function(e,t,a,i,r=!1){if(null===e)return e;var n=/w=(\d+)/,s=/fit=(\d+),(\d+)/,o=/resize=(\d+),(\d+)/,l=decodeURIComponent(e);if(/\.svg(\?.+)?$/.exec(l))return e;if(0<e.search("\\?")&&0<e.search(eio_lazy_vars.exactdn_domain)){var d=o.exec(l);if(d&&(t<d[1]||r))return"img-w"===i?l.replace(o,"w="+t):"img-h"===i?l.replace(o,"h="+a):l.replace(o,"resize="+t+","+a);o=n.exec(e);if(o&&(t<=o[1]||r)){if("img-h"===i)return l.replace(n,"h="+a);if("bg-cover"!==i&&"img-crop"!==i)return e.replace(n,"w="+t);var c=Math.abs(o[1]-t);return 20<c||a<1080?e.replace(n,"resize="+t+","+a):e}c=s.exec(l);if(c&&(t<c[1]||r)){if("bg-cover"!==i&&"img-crop"!==i)return"img-w"===i?l.replace(s,"w="+t):"img-h"===i?l.replace(s,"h="+a):l.replace(s,"fit="+t+","+a);l=Math.abs(c[1]-t),s=Math.abs(c[2]-a);return 20<l||20<s?e.replace(n,"resize="+t+","+a):e}if(!o&&!c&&!d)return"img"===i?e+"&fit="+t+","+a:"bg-cover"===i||"img-crop"===i?e+"&resize="+t+","+a:"img-h"===i||t<a?e+"&h="+a:e+"&w="+t}return-1==e.search("\\?")&&0<e.search(eio_lazy_vars.exactdn_domain)?"img"===i?e+"?fit="+t+","+a:"bg-cover"===i||"img-crop"===i?e+"?resize="+t+","+a:"img-h"===i||t<a?e+"?h="+a:e+"?w="+t:e},m=function(e){e=/-(\d+)x(\d+)\./.exec(e);return e&&1<e[1]&&1<e[2]?{w:e[1],h:e[2]}:{w:0,h:0}},p=function(e){var t=e.dataset.eioRwidth,e=e.dataset.eioRheight;return 1<t&&1<e?{w:t,h:e}:{w:0,h:0}},d=function(e){var t=e.getAttribute("width"),a=e.getAttribute("height");if(1<t&&1<a)return t/a;a=!1;if(a=(a=e.src&&-1<e.src.search("http")?e.src:a)||e.getAttribute("data-src")){var i=m(a);if(i.w&&i.h)return i.w/i.h}i=p(e);if(i.w&&i.h)return i.w/i.h;e=function(e){var t;if(e.srcset?t=e.srcset.split(","):(e=e.getAttribute("data-srcset"))&&(t=e.split(",")),t){var a=0,i=t.length;if(i){for(;a<i;a++){var r,n=t[a].trim().split(" ");!n[0].length||(n=m(n[0])).w&&n.h&&(r=n)}if(r.w&&r.h)return r}}return{w:0,h:0}}(e);return e.w&&e.h?e.w/e.h:0},y=function(){return eio_lazy_vars.use_dpr&&1<u.devicePixelRatio?u.devicePixelRatio:1};f.addEventListener("lazybeforesizes",function(e){e.target.getAttribute("data-src");var t=d(e.target);1<e.target.clientHeight&&t&&(t=Math.ceil(t*e.target.clientHeight),e.detail.width+2<t&&(e.detail.width=t)),void 0!==e.target._lazysizesWidth&&e.detail.width<e.target._lazysizesWidth&&(e.detail.width=e.target._lazysizesWidth),!eio_lazy_vars.use_dpr&&1<u.devicePixelRatio&&(e.detail.width=Math.ceil(e.detail.width/u.devicePixelRatio))}),f.addEventListener("lazybeforeunveil",function(e){var t,a,i,r,n=e.target,s=n.getAttribute("data-srcset");n.naturalWidth&&!s&&1<n.naturalWidth&&1<n.naturalHeight&&(t=y(),a=n.naturalWidth,i=n.naturalHeight,(e=p(n)).w&&e.w>a&&(a=e.w,i=e.h),a=n.clientWidth&&1.25*n.clientWidth*t<a,i=n.clientHeight&&1.25*n.clientHeight*t<i,(a||i)&&g(n)),ewww_webp_supported&&(!s||(r=n.getAttribute("data-srcset-webp"))&&n.setAttribute("data-srcset",r),(r=n.getAttribute("data-src-webp"))&&n.setAttribute("data-src",r))});function e(e=!1){e.type&&"load"===e.type&&h.autoSizer.checkElems(),y();var t,a=f.getElementsByClassName(h.cfg.loadedClass),i=a.length;if(i)for(t=0;t<i;t++){var r,n,s,o,l,d,c=a[t];c.src&&!c.srcset&&1<c.naturalWidth&&1<c.naturalHeight&&1<c.clientWidth&&1<c.clientHeight&&(r=c.naturalWidth,n=c.naturalHeight,s=u.innerWidth,o=u.innerHeight,l=p(c),d=m(c.src),l.w?s=l.w:d.w&&(s=d.w),l.h?o=l.h:d.h&&(o=d.h),l=c.clientWidth,d=c.clientHeight,(1.1*r<l&&l<=s||1.1*n<d&&d<=o)&&g(c,!0))}}var t,a,i,s,c=(t=e,s=function(){a=null,t()},function(){i=Date.now(),a=a||setTimeout(v,99)});function v(){var e=Date.now()-i;e<99?setTimeout(v,99-e):(u.requestIdleCallback||s)(s)}addEventListener("load",e),addEventListener("resize",c),setTimeout(e,2e4)}),function(e,t){t=t(e,e.document,Date);e.lazySizes=t,"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:{},function(i,f,n){"use strict";var h,g;if(!function(){var e,t={lazyClass:"lazyload",loadedClass:"lazyloaded",loadingClass:"lazyloading",preloadClass:"lazypreload",errorClass:"lazyerror",autosizesClass:"lazyautosizes",fastLoadedClass:"ls-is-cached",iframeLoadMode:0,srcAttr:"data-src",srcsetAttr:"data-srcset",sizesAttr:"data-sizes",minSize:40,customMedia:{},init:!0,expFactor:1.5,hFac:.8,loadMode:2,loadHidden:!0,ricTimeout:0,throttleDelay:125};for(e in g=i.lazySizesConfig||i.lazysizesConfig||{},t)e in g||(g[e]=t[e])}(),!f||!f.getElementsByClassName)return{init:function(){},cfg:g,noSupport:!0};function c(e,t){E(e,t)||e.setAttribute("class",(e[y]("class")||"").trim()+" "+t)}function u(e,t){(t=E(e,t))&&e.setAttribute("class",(e[y]("class")||"").replace(t," "))}function m(e,t){var a;!l&&(a=i.picturefill||g.pf)?(t&&t.src&&!e[y]("srcset")&&e.setAttribute("srcset",t.src),a({reevaluate:!0,elements:[e]})):t&&t.src&&(e.src=t.src)}var a,r,t,s,o,p=f.documentElement,l=i.HTMLPictureElement,d="addEventListener",y="getAttribute",e=i[d].bind(i),v=i.setTimeout,z=i.requestAnimationFrame||v,b=i.requestIdleCallback,w=/^picture$/i,_=["load","error","lazyincluded","_lazyloaded"],C={},A=Array.prototype.forEach,E=function(e,t){return C[t]||(C[t]=new RegExp("(\\s|^)"+t+"(\\s|$)")),C[t].test(e[y]("class")||"")&&C[t]},L=function(t,a,e){var i=e?d:"removeEventListener";e&&L(t,a),_.forEach(function(e){t[i](e,a)})},x=function(e,t,a,i,r){var n=f.createEvent("Event");return(a=a||{}).instance=h,n.initEvent(t,!i,!r),n.detail=a,e.dispatchEvent(n),n},M=function(e,t){return(getComputedStyle(e,null)||{})[t]},N=function(e,t,a){for(a=a||e.offsetWidth;a<g.minSize&&t&&!e._lazysizesWidth;)a=t.offsetWidth,t=t.parentNode;return a},S=(s=[],o=t=[],k._lsFlush=W,k);function W(){var e=o;for(o=t.length?s:t,r=!(a=!0);e.length;)e.shift()();a=!1}function k(e,t){a&&!t?e.apply(this,arguments):(o.push(e),r||(r=!0,(f.hidden?v:z)(W)))}function H(a,e){return e?function(){S(a)}:function(){var e=this,t=arguments;S(function(){a.apply(e,t)})}}function R(e){function t(){var e=n.now()-i;e<99?v(t,99-e):(b||r)(r)}var a,i,r=function(){a=null,e()};return function(){i=n.now(),a=a||v(t,99)}}var I,j,T,O,q,B,P,F,J,D,$,U,G,K,Q,V,X,Y,Z,ee,te,ae,ie,re,ne,se,oe,le,de,ce,ue,fe=(Z=/^img$/i,ee=/^iframe$/i,te="onscroll"in i&&!/(gle|ing)bot/.test(navigator.userAgent),re=-1,ne=function(e){return(U=null==U?"hidden"==M(f.body,"visibility"):U)||!("hidden"==M(e.parentNode,"visibility")&&"hidden"==M(e,"visibility"))},G=ge,Q=ie=ae=0,V=g.throttleDelay,X=g.ricTimeout,Y=b&&49<X?function(){b(me,{timeout:X}),X!==g.ricTimeout&&(X=g.ricTimeout)}:H(function(){v(me)},!0),oe=H(pe),le=function(e){oe({target:e.target})},de=H(function(t,e,a,i,r){var n,s,o,l,d;(o=x(t,"lazybeforeunveil",e)).defaultPrevented||(i&&(a?c(t,g.autosizesClass):t.setAttribute("sizes",i)),n=t[y](g.srcsetAttr),a=t[y](g.srcAttr),r&&(s=(d=t.parentNode)&&w.test(d.nodeName||"")),l=e.firesLoad||"src"in t&&(n||a||s),o={target:t},c(t,g.loadingClass),l&&(clearTimeout(T),T=v(he,2500),L(t,le,!0)),s&&A.call(d.getElementsByTagName("source"),ye),n?t.setAttribute("srcset",n):a&&!s&&(ee.test(t.nodeName)?(i=a,0==(d=(e=t).getAttribute("data-load-mode")||g.iframeLoadMode)?e.contentWindow.location.replace(i):1==d&&(e.src=i)):t.src=a),r&&(n||s)&&m(t,{src:a})),t._lazyRace&&delete t._lazyRace,u(t,g.lazyClass),S(function(){var e=t.complete&&1<t.naturalWidth;l&&!e||(e&&c(t,g.fastLoadedClass),pe(o),t._lazyCache=!0,v(function(){"_lazyCache"in t&&delete t._lazyCache},9)),"lazy"==t.loading&&ie--},!0)}),ue=R(function(){g.loadMode=3,se()}),{_:function(){q=n.now(),h.elements=f.getElementsByClassName(g.lazyClass),I=f.getElementsByClassName(g.lazyClass+" "+g.preloadClass),e("scroll",se,!0),e("resize",se,!0),e("pageshow",function(e){var t;!e.persisted||(t=f.querySelectorAll("."+g.loadingClass)).length&&t.forEach&&z(function(){t.forEach(function(e){e.complete&&ce(e)})})}),i.MutationObserver?new MutationObserver(se).observe(p,{childList:!0,subtree:!0,attributes:!0}):(p[d]("DOMNodeInserted",se,!0),p[d]("DOMAttrModified",se,!0),setInterval(se,999)),e("hashchange",se,!0),["focus","mouseover","click","load","transitionend","animationend"].forEach(function(e){f[d](e,se,!0)}),/d$|^c/.test(f.readyState)?ze():(e("load",ze),f[d]("DOMContentLoaded",se),v(ze,2e4)),h.elements.length?(ge(),S._lsFlush()):se()},checkElems:se=function(e){var t;(e=!0===e)&&(X=33),K||(K=!0,(t=V-(n.now()-Q))<0&&(t=0),e||t<9?Y():v(Y,t))},unveil:ce=function(e){var t,a,i,r;e._lazyRace||(!(r="auto"==(i=(a=Z.test(e.nodeName))&&(e[y](g.sizesAttr)||e[y]("sizes"))))&&j||!a||!e[y]("src")&&!e.srcset||e.complete||E(e,g.errorClass)||!E(e,g.lazyClass))&&(t=x(e,"lazyunveilread").detail,r&&Ce.updateElem(e,!0,e.offsetWidth),e._lazyRace=!0,ie++,de(e,t,r,i,a))},_aLSL:ve});function he(e){ie--,e&&!(ie<0)&&e.target||(ie=0)}function ge(){var e,t,a,i,r,n,s,o,l,d,c,u=h.elements;if((O=g.loadMode)&&ie<8&&(e=u.length)){for(t=0,re++;t<e;t++)if(u[t]&&!u[t]._lazyRace)if(!te||h.prematureUnveil&&h.prematureUnveil(u[t]))ce(u[t]);else if((s=u[t][y]("data-expand"))&&(r=+s)||(r=ae),l||(l=!g.expand||g.expand<1?500<p.clientHeight&&500<p.clientWidth?500:370:g.expand,d=(h._defEx=l)*g.expFactor,c=g.hFac,U=null,ae<d&&ie<1&&2<re&&2<O&&!f.hidden?(ae=d,re=0):ae=1<O&&1<re&&ie<6?l:0),o!==r&&(B=innerWidth+r*c,P=innerHeight+r,n=-1*r,o=r),d=u[t].getBoundingClientRect(),($=d.bottom)>=n&&(F=d.top)<=P&&(D=d.right)>=n*c&&(J=d.left)<=B&&($||D||J||F)&&(g.loadHidden||ne(u[t]))&&(j&&ie<3&&!s&&(O<3||re<4)||function(e,t){var a,i=e,r=ne(e);for(F-=t,$+=t,J-=t,D+=t;r&&(i=i.offsetParent)&&i!=f.body&&i!=p;)(r=0<(M(i,"opacity")||1))&&"visible"!=M(i,"overflow")&&(a=i.getBoundingClientRect(),r=D>a.left&&J<a.right&&$>a.top-1&&F<a.bottom+1);return r}(u[t],r))){if(ce(u[t]),i=!0,9<ie)break}else!i&&j&&!a&&ie<4&&re<4&&2<O&&(I[0]||g.preloadAfterLoad)&&(I[0]||!s&&($||D||J||F||"auto"!=u[t][y](g.sizesAttr)))&&(a=I[0]||u[t]);a&&!i&&ce(a)}}function me(){K=!1,Q=n.now(),G()}function pe(e){var t=e.target;t._lazyCache?delete t._lazyCache:(he(e),c(t,g.loadedClass),u(t,g.loadingClass),L(t,le),x(t,"lazyloaded"))}function ye(e){var t,a=e[y](g.srcsetAttr);(t=g.customMedia[e[y]("data-media")||e[y]("media")])&&e.setAttribute("media",t),a&&e.setAttribute("srcset",a)}function ve(){3==g.loadMode&&(g.loadMode=2),ue()}function ze(){j||(n.now()-q<999?v(ze,999):(j=!0,g.loadMode=3,se(),e("scroll",ve,!0)))}var be,we,_e,Ce=(we=H(function(e,t,a,i){var r,n,s;if(e._lazysizesWidth=i,e.setAttribute("sizes",i+="px"),w.test(t.nodeName||""))for(n=0,s=(r=t.getElementsByTagName("source")).length;n<s;n++)r[n].setAttribute("sizes",i);a.detail.dataAttr||m(e,a.detail)}),{_:function(){be=f.getElementsByClassName(g.autosizesClass),e("resize",_e)},checkElems:_e=R(function(){var e,t=be.length;if(t)for(e=0;e<t;e++)Ae(be[e])}),updateElem:Ae});function Ae(e,t,a){var i=e.parentNode;i&&(a=N(e,i,a),(t=x(e,"lazybeforesizes",{width:a,dataAttr:!!t})).defaultPrevented||(a=t.detail.width)&&a!==e._lazysizesWidth&&we(e,i,t,a))}function Ee(){!Ee.i&&f.getElementsByClassName&&(Ee.i=!0,Ce._(),fe._())}return v(function(){g.init&&Ee()}),h={cfg:g,autoSizer:Ce,loader:fe,init:Ee,uP:m,aC:c,rC:u,hC:E,fire:x,gW:N,rAF:S}}); -
easy-image-optimizer/trunk/phpcs.ruleset.xml
r3328397 r3398277 32 32 <element value="imgQuality"/> 33 33 <element value="parentNode"/> 34 <element value="nodeName"/> 34 35 <element value="nextSibling"/> 35 36 <element value="documentElement"/> -
easy-image-optimizer/trunk/readme.txt
r3350722 r3398277 2 2 Contributors: nosilver4u 3 3 Tags: image, resize, webp, lazy load, compress 4 Tested up to: 6. 85 Stable tag: 4. 2.14 Tested up to: 6.9 5 Stable tag: 4.3.0 6 6 License: GPLv3 7 7 … … 56 56 * If you would like to help translate this plugin in your language, get started here: https://translate.wordpress.org/projects/wp-plugins/easy-image-optimizer/ 57 57 58 = 4.3.0 = 59 *Release Date - November 18, 2025* 60 61 * added: Lazy Load support for background images in external CSS files 62 * added: View CDN bandwidth usage on settings page 63 * changed: Lazy Load checks parent element for skip-lazy class 64 * changed: Lazy Load auto-sizing honors High DPI setting 65 * changed: Easy IO fills in 450px wide image when responsive (srcset) images have a gap 66 * improved: Lazy Load performance when searching for img elements 67 * improved: Lazy Load placeholder generation is faster and works better with Safari 68 * fixed: Lazy Load for iframes breaks WP Remote Users Sync plugin 69 58 70 = 4.2.1 = 59 71 *Release Date - August 26, 2025*
Note: See TracChangeset
for help on using the changeset viewer.