Version Description
- moved image optimization to a separate tab and move all code to a separate file.
- added lazyloading (using lazysizes)
- added webp support (requires image optimization and lazyloading to be active)
- added option to enable/ disable the minification of excluded JS/ CSS files (on by default)
- misc. bugfixes and smaller improvements
Download this release
Release Info
Developer | futtta |
Plugin | Autoptimize |
Version | 2.5.0 |
Comparing to | |
See all releases |
Code changes from version 2.4.4 to 2.5.0
- autoptimize.php +3 -3
- classes/autoptimizeBase.php +3 -3
- classes/autoptimizeCache.php +35 -9
- classes/autoptimizeCacheChecker.php +7 -7
- classes/autoptimizeConfig.php +59 -23
- classes/autoptimizeExtra.php +27 -601
- classes/autoptimizeImages.php +1174 -0
- classes/autoptimizeMain.php +43 -29
- classes/autoptimizeScripts.php +38 -27
- classes/autoptimizeStyles.php +42 -29
- classes/autoptimizeToolbar.php +2 -1
- classes/autoptimizeUtils.php +21 -1
- classes/autoptimizeVersionUpdatesHandler.php +15 -0
- classes/external/js/lazysizes.min.js +2 -0
- readme.txt +30 -23
autoptimize.php
CHANGED
@@ -2,8 +2,8 @@
|
|
2 |
/*
|
3 |
Plugin Name: Autoptimize
|
4 |
Plugin URI: https://autoptimize.com/
|
5 |
-
Description:
|
6 |
-
Version: 2.
|
7 |
Author: Frank Goossens (futtta)
|
8 |
Author URI: https://autoptimize.com/
|
9 |
Text Domain: autoptimize
|
@@ -20,7 +20,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|
20 |
exit;
|
21 |
}
|
22 |
|
23 |
-
define( 'AUTOPTIMIZE_PLUGIN_VERSION', '2.
|
24 |
|
25 |
// plugin_dir_path() returns the trailing slash!
|
26 |
define( 'AUTOPTIMIZE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
|
2 |
/*
|
3 |
Plugin Name: Autoptimize
|
4 |
Plugin URI: https://autoptimize.com/
|
5 |
+
Description: Makes your site faster by optimizing CSS, JS, Images, Google fonts and more.
|
6 |
+
Version: 2.5.0
|
7 |
Author: Frank Goossens (futtta)
|
8 |
Author URI: https://autoptimize.com/
|
9 |
Text Domain: autoptimize
|
20 |
exit;
|
21 |
}
|
22 |
|
23 |
+
define( 'AUTOPTIMIZE_PLUGIN_VERSION', '2.5.0' );
|
24 |
|
25 |
// plugin_dir_path() returns the trailing slash!
|
26 |
define( 'AUTOPTIMIZE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
|
classes/autoptimizeBase.php
CHANGED
@@ -419,7 +419,7 @@ abstract class autoptimizeBase
|
|
419 |
// Grab the parts we need.
|
420 |
$parts = explode( '|', $matches[1] );
|
421 |
if ( ! empty( $parts ) ) {
|
422 |
-
$filepath = isset( $parts[0] ) ? base64_decode($parts[0]) : null;
|
423 |
$filehash = isset( $parts[1] ) ? $parts[1] : null;
|
424 |
}
|
425 |
|
@@ -559,7 +559,7 @@ abstract class autoptimizeBase
|
|
559 |
*
|
560 |
* @return string
|
561 |
*/
|
562 |
-
|
563 |
{
|
564 |
$found = false;
|
565 |
|
@@ -591,7 +591,7 @@ abstract class autoptimizeBase
|
|
591 |
*
|
592 |
* @return string
|
593 |
*/
|
594 |
-
|
595 |
{
|
596 |
if ( false !== strpos( $content, $marker ) ) {
|
597 |
$content = preg_replace_callback(
|
419 |
// Grab the parts we need.
|
420 |
$parts = explode( '|', $matches[1] );
|
421 |
if ( ! empty( $parts ) ) {
|
422 |
+
$filepath = isset( $parts[0] ) ? base64_decode( $parts[0] ) : null;
|
423 |
$filehash = isset( $parts[1] ) ? $parts[1] : null;
|
424 |
}
|
425 |
|
559 |
*
|
560 |
* @return string
|
561 |
*/
|
562 |
+
public static function replace_contents_with_marker_if_exists( $marker, $search, $re_replace_pattern, $content )
|
563 |
{
|
564 |
$found = false;
|
565 |
|
591 |
*
|
592 |
* @return string
|
593 |
*/
|
594 |
+
public static function restore_marked_content( $marker, $content )
|
595 |
{
|
596 |
if ( false !== strpos( $content, $marker ) ) {
|
597 |
$content = preg_replace_callback(
|
classes/autoptimizeCache.php
CHANGED
@@ -90,6 +90,14 @@ class autoptimizeCache
|
|
90 |
*/
|
91 |
public function cache( $data, $mime )
|
92 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
if ( false === $this->nogzip ) {
|
94 |
// We handle gzipping ourselves.
|
95 |
$file = 'default.php';
|
@@ -104,6 +112,10 @@ class autoptimizeCache
|
|
104 |
if ( apply_filters( 'autoptimize_filter_cache_create_static_gzip', false ) ) {
|
105 |
// Create an additional cached gzip file.
|
106 |
file_put_contents( $this->cachedir . $this->filename . '.gz', gzencode( $data, 9, FORCE_GZIP ) );
|
|
|
|
|
|
|
|
|
107 |
}
|
108 |
}
|
109 |
}
|
@@ -363,7 +375,8 @@ class autoptimizeCache
|
|
363 |
}
|
364 |
|
365 |
// Warm cache (part of speedupper)!
|
366 |
-
if ( apply_filters( 'autoptimize_filter_speedupper', true ) ) {
|
|
|
367 |
$url = site_url() . '/?ao_speedup_cachebuster=' . rand( 1, 100000 );
|
368 |
$cache = @wp_remote_get( $url ); // @codingStandardsIgnoreLine
|
369 |
unset( $cache );
|
@@ -481,17 +494,10 @@ class autoptimizeCache
|
|
481 |
*/
|
482 |
public static function cacheavail()
|
483 |
{
|
484 |
-
if (
|
485 |
-
// We didn't set a cache.
|
486 |
return false;
|
487 |
}
|
488 |
|
489 |
-
foreach ( array( '', 'js', 'css' ) as $dir ) {
|
490 |
-
if ( ! self::check_cache_dir( AUTOPTIMIZE_CACHE_DIR . $dir ) ) {
|
491 |
-
return false;
|
492 |
-
}
|
493 |
-
}
|
494 |
-
|
495 |
// Using .htaccess inside our cache folder to overrule wp-super-cache.
|
496 |
$htaccess = AUTOPTIMIZE_CACHE_DIR . '/.htaccess';
|
497 |
if ( ! is_file( $htaccess ) ) {
|
@@ -563,6 +569,26 @@ class autoptimizeCache
|
|
563 |
return true;
|
564 |
}
|
565 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
566 |
/**
|
567 |
* Ensures the specified `$dir` exists and is writeable.
|
568 |
* Returns false if that's not the case.
|
90 |
*/
|
91 |
public function cache( $data, $mime )
|
92 |
{
|
93 |
+
// off by default; check if cachedirs exist every time before caching
|
94 |
+
//
|
95 |
+
// to be activated for users that experience these ugly errors;
|
96 |
+
// PHP Warning: file_put_contents failed to open stream: No such file or directory.
|
97 |
+
if ( apply_filters( 'autoptimize_filter_cache_checkdirs_on_write', false ) ) {
|
98 |
+
$this->check_and_create_dirs();
|
99 |
+
}
|
100 |
+
|
101 |
if ( false === $this->nogzip ) {
|
102 |
// We handle gzipping ourselves.
|
103 |
$file = 'default.php';
|
112 |
if ( apply_filters( 'autoptimize_filter_cache_create_static_gzip', false ) ) {
|
113 |
// Create an additional cached gzip file.
|
114 |
file_put_contents( $this->cachedir . $this->filename . '.gz', gzencode( $data, 9, FORCE_GZIP ) );
|
115 |
+
// If PHP Brotli extension is installed, create an additional cached Brotli file.
|
116 |
+
if ( function_exists( 'brotli_compress' ) ) {
|
117 |
+
file_put_contents( $this->cachedir . $this->filename . '.br', brotli_compress( $data, 11, BROTLI_GENERIC ) );
|
118 |
+
}
|
119 |
}
|
120 |
}
|
121 |
}
|
375 |
}
|
376 |
|
377 |
// Warm cache (part of speedupper)!
|
378 |
+
if ( apply_filters( 'autoptimize_filter_speedupper', true ) && false == get_transient( 'autoptimize_cache_warmer_protector' ) ) {
|
379 |
+
set_transient( 'autoptimize_cache_warmer_protector', 'I shall not warm cache for another 10 minutes.', 60 * 10 );
|
380 |
$url = site_url() . '/?ao_speedup_cachebuster=' . rand( 1, 100000 );
|
381 |
$cache = @wp_remote_get( $url ); // @codingStandardsIgnoreLine
|
382 |
unset( $cache );
|
494 |
*/
|
495 |
public static function cacheavail()
|
496 |
{
|
497 |
+
if ( false === autoptimizeCache::check_and_create_dirs() ) {
|
|
|
498 |
return false;
|
499 |
}
|
500 |
|
|
|
|
|
|
|
|
|
|
|
|
|
501 |
// Using .htaccess inside our cache folder to overrule wp-super-cache.
|
502 |
$htaccess = AUTOPTIMIZE_CACHE_DIR . '/.htaccess';
|
503 |
if ( ! is_file( $htaccess ) ) {
|
569 |
return true;
|
570 |
}
|
571 |
|
572 |
+
/**
|
573 |
+
* Checks if cache dirs exist and create if not.
|
574 |
+
* Returns false if not succesful.
|
575 |
+
*
|
576 |
+
* @return bool
|
577 |
+
*/
|
578 |
+
public static function check_and_create_dirs() {
|
579 |
+
if ( ! defined( 'AUTOPTIMIZE_CACHE_DIR' ) ) {
|
580 |
+
// We didn't set a cache.
|
581 |
+
return false;
|
582 |
+
}
|
583 |
+
|
584 |
+
foreach ( array( '', 'js', 'css' ) as $dir ) {
|
585 |
+
if ( ! self::check_cache_dir( AUTOPTIMIZE_CACHE_DIR . $dir ) ) {
|
586 |
+
return false;
|
587 |
+
}
|
588 |
+
}
|
589 |
+
return true;
|
590 |
+
}
|
591 |
+
|
592 |
/**
|
593 |
* Ensures the specified `$dir` exists and is writeable.
|
594 |
* Returns false if that's not the case.
|
classes/autoptimizeCacheChecker.php
CHANGED
@@ -60,11 +60,11 @@ class autoptimizeCacheChecker
|
|
60 |
if ( ( $cache_size > $max_size ) && ( $do_cache_check ) ) {
|
61 |
update_option( 'autoptimize_cachesize_notice', true );
|
62 |
if ( apply_filters( 'autoptimize_filter_cachecheck_sendmail', true ) ) {
|
63 |
-
$
|
64 |
$ao_mailto = apply_filters( 'autoptimize_filter_cachecheck_mailto', get_option( 'admin_email', '' ) );
|
65 |
|
66 |
-
$ao_mailsubject = __( 'Autoptimize cache size warning', 'autoptimize' ) . ' (' . $
|
67 |
-
$ao_mailbody = __( 'Autoptimize\'s cache size is getting big, consider purging the cache. Have a look at https://wordpress.org/plugins/autoptimize/faq/ to see how you can keep the cache size under control.', 'autoptimize' ) . ' (site: ' . $
|
68 |
|
69 |
if ( ! empty( $ao_mailto ) ) {
|
70 |
$ao_mailresult = wp_mail( $ao_mailto, $ao_mailsubject, $ao_mailbody );
|
@@ -78,11 +78,11 @@ class autoptimizeCacheChecker
|
|
78 |
// Check if 3rd party services (e.g. image proxy) are up.
|
79 |
autoptimizeUtils::check_service_availability();
|
80 |
|
81 |
-
// Check image optimization stats.
|
82 |
-
autoptimizeExtra::get_img_provider_stats();
|
83 |
-
|
84 |
// Nukes advanced cache clearing artifacts if they exists...
|
85 |
autoptimizeCache::delete_advanced_cache_clear_artifacts();
|
|
|
|
|
|
|
86 |
}
|
87 |
|
88 |
public function show_admin_notice()
|
@@ -95,7 +95,7 @@ class autoptimizeCacheChecker
|
|
95 |
}
|
96 |
|
97 |
// Notice for image proxy usage.
|
98 |
-
$_imgopt_notice =
|
99 |
if ( current_user_can( 'manage_options' ) && is_array( $_imgopt_notice ) && array_key_exists( 'status', $_imgopt_notice ) && in_array( $_imgopt_notice['status'], array( 1, -1, -2 ) ) ) {
|
100 |
$_dismissible = 'ao-img-opt-notice-';
|
101 |
$_hide_notice = '7';
|
60 |
if ( ( $cache_size > $max_size ) && ( $do_cache_check ) ) {
|
61 |
update_option( 'autoptimize_cachesize_notice', true );
|
62 |
if ( apply_filters( 'autoptimize_filter_cachecheck_sendmail', true ) ) {
|
63 |
+
$home_url = esc_url( home_url() );
|
64 |
$ao_mailto = apply_filters( 'autoptimize_filter_cachecheck_mailto', get_option( 'admin_email', '' ) );
|
65 |
|
66 |
+
$ao_mailsubject = __( 'Autoptimize cache size warning', 'autoptimize' ) . ' (' . $home_url . ')';
|
67 |
+
$ao_mailbody = __( 'Autoptimize\'s cache size is getting big, consider purging the cache. Have a look at https://wordpress.org/plugins/autoptimize/faq/ to see how you can keep the cache size under control.', 'autoptimize' ) . ' (site: ' . $home_url . ')';
|
68 |
|
69 |
if ( ! empty( $ao_mailto ) ) {
|
70 |
$ao_mailresult = wp_mail( $ao_mailto, $ao_mailsubject, $ao_mailbody );
|
78 |
// Check if 3rd party services (e.g. image proxy) are up.
|
79 |
autoptimizeUtils::check_service_availability();
|
80 |
|
|
|
|
|
|
|
81 |
// Nukes advanced cache clearing artifacts if they exists...
|
82 |
autoptimizeCache::delete_advanced_cache_clear_artifacts();
|
83 |
+
|
84 |
+
// Check image optimization stats.
|
85 |
+
autoptimizeImages::instance()->query_img_provider_stats();
|
86 |
}
|
87 |
|
88 |
public function show_admin_notice()
|
95 |
}
|
96 |
|
97 |
// Notice for image proxy usage.
|
98 |
+
$_imgopt_notice = autoptimizeImages::instance()->get_status_notice();
|
99 |
if ( current_user_can( 'manage_options' ) && is_array( $_imgopt_notice ) && array_key_exists( 'status', $_imgopt_notice ) && in_array( $_imgopt_notice['status'], array( 1, -1, -2 ) ) ) {
|
100 |
$_dismissible = 'ao-img-opt-notice-';
|
101 |
$_hide_notice = '7';
|
classes/autoptimizeConfig.php
CHANGED
@@ -209,21 +209,6 @@ input[type=url]:invalid {color: red; border-color:red;} .form-table th{font-weig
|
|
209 |
|
210 |
<ul>
|
211 |
|
212 |
-
<li class="itemDetail">
|
213 |
-
<h2 class="itemTitle"><?php _e('HTML Options','autoptimize'); ?></h2>
|
214 |
-
<table class="form-table">
|
215 |
-
<tr valign="top">
|
216 |
-
<th scope="row"><?php _e('Optimize HTML Code?','autoptimize'); ?></th>
|
217 |
-
<td><input type="checkbox" id="autoptimize_html" name="autoptimize_html" <?php echo get_option('autoptimize_html')?'checked="checked" ':''; ?>/></td>
|
218 |
-
</tr>
|
219 |
-
<tr class="<?php echo $hiddenClass;?>html_sub ao_adv" valign="top">
|
220 |
-
<th scope="row"><?php _e('Keep HTML comments?','autoptimize'); ?></th>
|
221 |
-
<td><label class="cb_label"><input type="checkbox" name="autoptimize_html_keepcomments" <?php echo get_option('autoptimize_html_keepcomments')?'checked="checked" ':''; ?>/>
|
222 |
-
<?php _e('Enable this if you want HTML comments to remain in the page.','autoptimize'); ?></label></td>
|
223 |
-
</tr>
|
224 |
-
</table>
|
225 |
-
</li>
|
226 |
-
|
227 |
<li class="itemDetail">
|
228 |
<h2 class="itemTitle"><?php _e('JavaScript Options','autoptimize'); ?></h2>
|
229 |
<table class="form-table">
|
@@ -253,9 +238,9 @@ input[type=url]:invalid {color: red; border-color:red;} .form-table th{font-weig
|
|
253 |
<?php _e('Mostly useful in combination with previous option when using jQuery-based templates, but might help keeping cache size under control.','autoptimize'); ?></label></td>
|
254 |
</tr>
|
255 |
<?php } ?>
|
256 |
-
<tr valign="top" class="<?php echo $hiddenClass;?>js_sub ao_adv
|
257 |
<th scope="row"><?php _e('Exclude scripts from Autoptimize:','autoptimize'); ?></th>
|
258 |
-
<td><label><input type="text" style="width:100%;" name="autoptimize_js_exclude" value="<?php echo get_option('autoptimize_js_exclude',"
|
259 |
<?php _e('A comma-separated list of scripts you want to exclude from being optimized, for example \'whatever.js, another.js\' (without the quotes) to exclude those scripts from being aggregated by Autoptimize.','autoptimize'); ?></label></td>
|
260 |
</tr>
|
261 |
<tr valign="top" class="<?php echo $hiddenClass;?>js_sub ao_adv js_aggregate">
|
@@ -317,7 +302,7 @@ if ( function_exists( 'is_plugin_active' ) && ! is_plugin_active( 'autoptimize-c
|
|
317 |
<td><label class="cb_label"><input type="checkbox" id="autoptimize_css_inline" name="autoptimize_css_inline" <?php echo get_option('autoptimize_css_inline')?'checked="checked" ':''; ?>/>
|
318 |
<?php _e('Inlining all CSS can improve performance for sites with a low pageviews/ visitor-rate, but may slow down performance otherwise.','autoptimize'); ?></label></td>
|
319 |
</tr>
|
320 |
-
<tr valign="top" class="<?php echo $hiddenClass;?>ao_adv css_sub
|
321 |
<th scope="row"><?php _e('Exclude CSS from Autoptimize:','autoptimize'); ?></th>
|
322 |
<td><label><input type="text" style="width:100%;" name="autoptimize_css_exclude" value="<?php echo get_option('autoptimize_css_exclude','wp-content/cache/, wp-content/uploads/, admin-bar.min.css, dashicons.min.css'); ?>"/><br />
|
323 |
<?php _e('A comma-separated list of CSS you want to exclude from being optimized.','autoptimize'); ?></label></td>
|
@@ -325,6 +310,21 @@ if ( function_exists( 'is_plugin_active' ) && ! is_plugin_active( 'autoptimize-c
|
|
325 |
</table>
|
326 |
</li>
|
327 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
328 |
<li class="itemDetail">
|
329 |
<h2 class="itemTitle"><?php _e('CDN Options','autoptimize'); ?></h2>
|
330 |
<table class="form-table">
|
@@ -372,6 +372,17 @@ if ( function_exists( 'is_plugin_active' ) && ! is_plugin_active( 'autoptimize-c
|
|
372 |
<td><label class="cb_label"><input type="checkbox" name="autoptimize_cache_nogzip" <?php echo get_option('autoptimize_cache_nogzip','1')?'checked="checked" ':''; ?>/>
|
373 |
<?php _e('By default files saved are static css/js, uncheck this option if your webserver doesn\'t properly handle the compression and expiry.','autoptimize'); ?></label></td>
|
374 |
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
375 |
<tr valign="top" class="<?php echo $hiddenClass;?>ao_adv">
|
376 |
<th scope="row"><?php _e('Also optimize for logged in users?','autoptimize'); ?></th>
|
377 |
<td><label class="cb_label"><input type="checkbox" name="autoptimize_optimize_logged" <?php echo get_option('autoptimize_optimize_logged','1')?'checked="checked" ':''; ?>/>
|
@@ -517,8 +528,12 @@ if ( function_exists( 'is_plugin_active' ) && ! is_plugin_active( 'autoptimize-c
|
|
517 |
jQuery( "#autoptimize_js_aggregate" ).change(function() {
|
518 |
if (this.checked && jQuery("#autoptimize_js").attr('checked')) {
|
519 |
jQuery(".js_aggregate:visible").fadeTo("fast",1);
|
|
|
520 |
} else {
|
521 |
jQuery(".js_aggregate:visible").fadeTo("fast",.33);
|
|
|
|
|
|
|
522 |
}
|
523 |
});
|
524 |
|
@@ -533,8 +548,12 @@ if ( function_exists( 'is_plugin_active' ) && ! is_plugin_active( 'autoptimize-c
|
|
533 |
jQuery( "#autoptimize_css_aggregate" ).change(function() {
|
534 |
if (this.checked && jQuery("#autoptimize_css").attr('checked')) {
|
535 |
jQuery(".css_aggregate:visible").fadeTo("fast",1);
|
|
|
536 |
} else {
|
537 |
jQuery(".css_aggregate:visible").fadeTo("fast",.33);
|
|
|
|
|
|
|
538 |
}
|
539 |
});
|
540 |
|
@@ -649,6 +668,7 @@ if ( function_exists( 'is_plugin_active' ) && ! is_plugin_active( 'autoptimize-c
|
|
649 |
register_setting( 'autoptimize', 'autoptimize_show_adv' );
|
650 |
register_setting( 'autoptimize', 'autoptimize_optimize_logged' );
|
651 |
register_setting( 'autoptimize', 'autoptimize_optimize_checkout' );
|
|
|
652 |
}
|
653 |
|
654 |
public function setmeta($links, $file = null)
|
@@ -686,7 +706,7 @@ if ( function_exists( 'is_plugin_active' ) && ! is_plugin_active( 'autoptimize-c
|
|
686 |
'autoptimize_html_keepcomments' => 0,
|
687 |
'autoptimize_js' => 0,
|
688 |
'autoptimize_js_aggregate' => 1,
|
689 |
-
'autoptimize_js_exclude' => '
|
690 |
'autoptimize_js_trycatch' => 0,
|
691 |
'autoptimize_js_justhead' => 0,
|
692 |
'autoptimize_js_include_inline' => 0,
|
@@ -704,7 +724,8 @@ if ( function_exists( 'is_plugin_active' ) && ! is_plugin_active( 'autoptimize-c
|
|
704 |
'autoptimize_cache_nogzip' => 1,
|
705 |
'autoptimize_show_adv' => 0,
|
706 |
'autoptimize_optimize_logged' => 1,
|
707 |
-
'autoptimize_optimize_checkout' => 1
|
|
|
708 |
);
|
709 |
|
710 |
return $config;
|
@@ -723,13 +744,28 @@ if ( function_exists( 'is_plugin_active' ) && ! is_plugin_active( 'autoptimize-c
|
|
723 |
'autoptimize_extra_radio_field_4' => '1',
|
724 |
'autoptimize_extra_text_field_2' => '',
|
725 |
'autoptimize_extra_text_field_3' => '',
|
726 |
-
'autoptimize_extra_checkbox_field_5' => '0',
|
727 |
-
'autoptimize_extra_select_field_6' => '2',
|
728 |
);
|
729 |
|
730 |
return $defaults;
|
731 |
}
|
732 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
733 |
/**
|
734 |
* Returns preload polyfill JS.
|
735 |
*
|
@@ -809,7 +845,7 @@ if ( function_exists( 'is_plugin_active' ) && ! is_plugin_active( 'autoptimize-c
|
|
809 |
// based on http://wordpress.stackexchange.com/a/58826
|
810 |
static function ao_admin_tabs()
|
811 |
{
|
812 |
-
$tabs = apply_filters( 'autoptimize_filter_settingsscreen_tabs' ,array( 'autoptimize' => __( '
|
813 |
$tabContent = '';
|
814 |
$tabs_count = count($tabs);
|
815 |
if ( $tabs_count > 1 ) {
|
209 |
|
210 |
<ul>
|
211 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
212 |
<li class="itemDetail">
|
213 |
<h2 class="itemTitle"><?php _e('JavaScript Options','autoptimize'); ?></h2>
|
214 |
<table class="form-table">
|
238 |
<?php _e('Mostly useful in combination with previous option when using jQuery-based templates, but might help keeping cache size under control.','autoptimize'); ?></label></td>
|
239 |
</tr>
|
240 |
<?php } ?>
|
241 |
+
<tr valign="top" class="<?php echo $hiddenClass;?>js_sub ao_adv">
|
242 |
<th scope="row"><?php _e('Exclude scripts from Autoptimize:','autoptimize'); ?></th>
|
243 |
+
<td><label><input type="text" style="width:100%;" name="autoptimize_js_exclude" value="<?php echo get_option('autoptimize_js_exclude',"wp-includes/js/dist/, wp-includes/js/tinymce/, js/jquery/jquery.js"); ?>"/><br />
|
244 |
<?php _e('A comma-separated list of scripts you want to exclude from being optimized, for example \'whatever.js, another.js\' (without the quotes) to exclude those scripts from being aggregated by Autoptimize.','autoptimize'); ?></label></td>
|
245 |
</tr>
|
246 |
<tr valign="top" class="<?php echo $hiddenClass;?>js_sub ao_adv js_aggregate">
|
302 |
<td><label class="cb_label"><input type="checkbox" id="autoptimize_css_inline" name="autoptimize_css_inline" <?php echo get_option('autoptimize_css_inline')?'checked="checked" ':''; ?>/>
|
303 |
<?php _e('Inlining all CSS can improve performance for sites with a low pageviews/ visitor-rate, but may slow down performance otherwise.','autoptimize'); ?></label></td>
|
304 |
</tr>
|
305 |
+
<tr valign="top" class="<?php echo $hiddenClass;?>ao_adv css_sub">
|
306 |
<th scope="row"><?php _e('Exclude CSS from Autoptimize:','autoptimize'); ?></th>
|
307 |
<td><label><input type="text" style="width:100%;" name="autoptimize_css_exclude" value="<?php echo get_option('autoptimize_css_exclude','wp-content/cache/, wp-content/uploads/, admin-bar.min.css, dashicons.min.css'); ?>"/><br />
|
308 |
<?php _e('A comma-separated list of CSS you want to exclude from being optimized.','autoptimize'); ?></label></td>
|
310 |
</table>
|
311 |
</li>
|
312 |
|
313 |
+
<li class="itemDetail">
|
314 |
+
<h2 class="itemTitle"><?php _e('HTML Options','autoptimize'); ?></h2>
|
315 |
+
<table class="form-table">
|
316 |
+
<tr valign="top">
|
317 |
+
<th scope="row"><?php _e('Optimize HTML Code?','autoptimize'); ?></th>
|
318 |
+
<td><input type="checkbox" id="autoptimize_html" name="autoptimize_html" <?php echo get_option('autoptimize_html')?'checked="checked" ':''; ?>/></td>
|
319 |
+
</tr>
|
320 |
+
<tr class="<?php echo $hiddenClass;?>html_sub ao_adv" valign="top">
|
321 |
+
<th scope="row"><?php _e('Keep HTML comments?','autoptimize'); ?></th>
|
322 |
+
<td><label class="cb_label"><input type="checkbox" name="autoptimize_html_keepcomments" <?php echo get_option('autoptimize_html_keepcomments')?'checked="checked" ':''; ?>/>
|
323 |
+
<?php _e('Enable this if you want HTML comments to remain in the page.','autoptimize'); ?></label></td>
|
324 |
+
</tr>
|
325 |
+
</table>
|
326 |
+
</li>
|
327 |
+
|
328 |
<li class="itemDetail">
|
329 |
<h2 class="itemTitle"><?php _e('CDN Options','autoptimize'); ?></h2>
|
330 |
<table class="form-table">
|
372 |
<td><label class="cb_label"><input type="checkbox" name="autoptimize_cache_nogzip" <?php echo get_option('autoptimize_cache_nogzip','1')?'checked="checked" ':''; ?>/>
|
373 |
<?php _e('By default files saved are static css/js, uncheck this option if your webserver doesn\'t properly handle the compression and expiry.','autoptimize'); ?></label></td>
|
374 |
</tr>
|
375 |
+
<?php
|
376 |
+
$_min_excl_class = 'ao_adv';
|
377 |
+
if ( !$conf->get( 'autoptimize_css_aggregate' ) && !$conf->get( 'autoptimize_js_aggregate' ) ) {
|
378 |
+
$_min_excl_class = ' hidden';
|
379 |
+
}
|
380 |
+
?>
|
381 |
+
<tr valign="top" id="min_excl_row" class="<?php echo $hiddenClass.$_min_excl_class; ?>">
|
382 |
+
<th scope="row"><?php _e('Minify excluded CSS and JS files?','autoptimize'); ?></th>
|
383 |
+
<td><label class="cb_label"><input type="checkbox" name="autoptimize_minify_excluded" <?php echo get_option('autoptimize_minify_excluded','1')?'checked="checked" ':''; ?>/>
|
384 |
+
<?php _e('When aggregating JS or CSS, excluded files that are not minified (based on filename) are by default minified by Autoptimize despite being excluded. Uncheck this option if anything breaks despite excluding.','autoptimize'); ?></label></td>
|
385 |
+
</tr>
|
386 |
<tr valign="top" class="<?php echo $hiddenClass;?>ao_adv">
|
387 |
<th scope="row"><?php _e('Also optimize for logged in users?','autoptimize'); ?></th>
|
388 |
<td><label class="cb_label"><input type="checkbox" name="autoptimize_optimize_logged" <?php echo get_option('autoptimize_optimize_logged','1')?'checked="checked" ':''; ?>/>
|
528 |
jQuery( "#autoptimize_js_aggregate" ).change(function() {
|
529 |
if (this.checked && jQuery("#autoptimize_js").attr('checked')) {
|
530 |
jQuery(".js_aggregate:visible").fadeTo("fast",1);
|
531 |
+
jQuery( "#min_excl_row" ).show();
|
532 |
} else {
|
533 |
jQuery(".js_aggregate:visible").fadeTo("fast",.33);
|
534 |
+
if ( jQuery( "#autoptimize_css_aggregate" ).prop('checked') == false ) {
|
535 |
+
jQuery( "#min_excl_row" ).hide();
|
536 |
+
}
|
537 |
}
|
538 |
});
|
539 |
|
548 |
jQuery( "#autoptimize_css_aggregate" ).change(function() {
|
549 |
if (this.checked && jQuery("#autoptimize_css").attr('checked')) {
|
550 |
jQuery(".css_aggregate:visible").fadeTo("fast",1);
|
551 |
+
jQuery( "#min_excl_row" ).show();
|
552 |
} else {
|
553 |
jQuery(".css_aggregate:visible").fadeTo("fast",.33);
|
554 |
+
if ( jQuery( "#autoptimize_js_aggregate" ).prop('checked') == false ) {
|
555 |
+
jQuery( "#min_excl_row" ).hide();
|
556 |
+
}
|
557 |
}
|
558 |
});
|
559 |
|
668 |
register_setting( 'autoptimize', 'autoptimize_show_adv' );
|
669 |
register_setting( 'autoptimize', 'autoptimize_optimize_logged' );
|
670 |
register_setting( 'autoptimize', 'autoptimize_optimize_checkout' );
|
671 |
+
register_setting( 'autoptimize', 'autoptimize_minify_excluded' );
|
672 |
}
|
673 |
|
674 |
public function setmeta($links, $file = null)
|
706 |
'autoptimize_html_keepcomments' => 0,
|
707 |
'autoptimize_js' => 0,
|
708 |
'autoptimize_js_aggregate' => 1,
|
709 |
+
'autoptimize_js_exclude' => 'wp-includes/js/dist/, wp-includes/js/tinymce/, js/jquery/jquery.js',
|
710 |
'autoptimize_js_trycatch' => 0,
|
711 |
'autoptimize_js_justhead' => 0,
|
712 |
'autoptimize_js_include_inline' => 0,
|
724 |
'autoptimize_cache_nogzip' => 1,
|
725 |
'autoptimize_show_adv' => 0,
|
726 |
'autoptimize_optimize_logged' => 1,
|
727 |
+
'autoptimize_optimize_checkout' => 1,
|
728 |
+
'autoptimize_minify_excluded' => 1,
|
729 |
);
|
730 |
|
731 |
return $config;
|
744 |
'autoptimize_extra_radio_field_4' => '1',
|
745 |
'autoptimize_extra_text_field_2' => '',
|
746 |
'autoptimize_extra_text_field_3' => '',
|
|
|
|
|
747 |
);
|
748 |
|
749 |
return $defaults;
|
750 |
}
|
751 |
|
752 |
+
/**
|
753 |
+
* Returns default option values for autoptimizeExtra.
|
754 |
+
*
|
755 |
+
* @return array
|
756 |
+
*/
|
757 |
+
public static function get_ao_imgopt_default_options()
|
758 |
+
{
|
759 |
+
$defaults = array(
|
760 |
+
'autoptimize_imgopt_checkbox_field_1' => '0', // imgopt off.
|
761 |
+
'autoptimize_imgopt_select_field_2' => '2', // quality glossy.
|
762 |
+
'autoptimize_imgopt_checkbox_field_3' => '0', // lazy load off.
|
763 |
+
'autoptimize_imgopt_checkbox_field_4' => '0', // webp off (might be removed).
|
764 |
+
'autoptimize_imgopt_text_field_5' => '', // lazy load exclusions empty.
|
765 |
+
);
|
766 |
+
return $defaults;
|
767 |
+
}
|
768 |
+
|
769 |
/**
|
770 |
* Returns preload polyfill JS.
|
771 |
*
|
845 |
// based on http://wordpress.stackexchange.com/a/58826
|
846 |
static function ao_admin_tabs()
|
847 |
{
|
848 |
+
$tabs = apply_filters( 'autoptimize_filter_settingsscreen_tabs' ,array( 'autoptimize' => __( 'JS, CSS & HTML', 'autoptimize' ) ) );
|
849 |
$tabContent = '';
|
850 |
$tabs_count = count($tabs);
|
851 |
if ( $tabs_count > 1 ) {
|
classes/autoptimizeExtra.php
CHANGED
@@ -24,7 +24,7 @@ class autoptimizeExtra
|
|
24 |
public function __construct( $options = array() )
|
25 |
{
|
26 |
if ( empty( $options ) ) {
|
27 |
-
$options =
|
28 |
}
|
29 |
|
30 |
$this->options = $options;
|
@@ -40,7 +40,7 @@ class autoptimizeExtra
|
|
40 |
}
|
41 |
}
|
42 |
|
43 |
-
|
44 |
{
|
45 |
$value = get_option( 'autoptimize_extra_settings' );
|
46 |
if ( empty( $value ) ) {
|
@@ -48,13 +48,6 @@ class autoptimizeExtra
|
|
48 |
$value = autoptimizeConfig::get_ao_extra_default_options();
|
49 |
}
|
50 |
|
51 |
-
// get service availability.
|
52 |
-
$value['availabilities'] = get_option( 'autoptimize_service_availablity' );
|
53 |
-
|
54 |
-
if ( empty( $value['availabilities'] ) ) {
|
55 |
-
$value['availabilities'] = autoptimizeUtils::check_service_availability( true );
|
56 |
-
}
|
57 |
-
|
58 |
return $value;
|
59 |
}
|
60 |
|
@@ -85,7 +78,8 @@ class autoptimizeExtra
|
|
85 |
}
|
86 |
}
|
87 |
|
88 |
-
public function filter_remove_qs( $src )
|
|
|
89 |
if ( strpos( $src, '?ver=' ) ) {
|
90 |
$src = remove_query_arg( 'ver', $src );
|
91 |
}
|
@@ -128,15 +122,8 @@ class autoptimizeExtra
|
|
128 |
add_filter( 'style_loader_src', array( $this, 'filter_remove_qs' ), 15, 1 );
|
129 |
}
|
130 |
|
131 |
-
// Making sure is_plugin_active() exists when we need it.
|
132 |
-
if ( ! function_exists( 'is_plugin_active' ) ) {
|
133 |
-
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
134 |
-
}
|
135 |
// Avoiding conflicts of interest when async-javascript plugin is active!
|
136 |
-
$async_js_plugin_active =
|
137 |
-
if ( function_exists( 'is_plugin_active' ) && is_plugin_active( 'async-javascript/async-javascript.php' ) ) {
|
138 |
-
$async_js_plugin_active = true;
|
139 |
-
}
|
140 |
if ( ! empty( $options['autoptimize_extra_text_field_3'] ) && ! $async_js_plugin_active ) {
|
141 |
add_filter( 'autoptimize_filter_js_exclude', array( $this, 'extra_async_js' ), 10, 1 );
|
142 |
}
|
@@ -152,31 +139,6 @@ class autoptimizeExtra
|
|
152 |
if ( ! empty( $options['autoptimize_extra_text_field_2'] ) || has_filter( 'autoptimize_extra_filter_tobepreconn' ) ) {
|
153 |
add_filter( 'wp_resource_hints', array( $this, 'filter_preconnect' ), 10, 2 );
|
154 |
}
|
155 |
-
|
156 |
-
// Optimize Images kicks in if;
|
157 |
-
// * the option is activated by user.
|
158 |
-
// * imgopt user stats does not have status -2.
|
159 |
-
// * imgopt status is not "down".
|
160 |
-
// * imgopt status is not "launch" or imgopt_launch_ok() returns be true.
|
161 |
-
$_do_cdn = true;
|
162 |
-
$_userstatus = $this->get_imgopt_provider_userstatus();
|
163 |
-
if ( -2 == $_userstatus['Status'] ) {
|
164 |
-
$_do_cdn = false;
|
165 |
-
}
|
166 |
-
|
167 |
-
if ( ! empty( $options['autoptimize_extra_checkbox_field_5'] ) && $_do_cdn && 'down' !== $options['availabilities']['extra_imgopt']['status'] && ( 'launch' !== $options['availabilities']['extra_imgopt']['status'] || $this->imgopt_launch_ok() ) ) {
|
168 |
-
if ( apply_filters( 'autoptimize_filter_extra_imgopt_do', true ) ) {
|
169 |
-
add_filter( 'autoptimize_html_after_minify', array( $this, 'filter_optimize_images' ), 10, 1 );
|
170 |
-
$_imgopt_active = true;
|
171 |
-
}
|
172 |
-
if ( apply_filters( 'autoptimize_filter_extra_imgopt_do_css', true ) ) {
|
173 |
-
add_filter( 'autoptimize_filter_base_replace_cdn', array( $this, 'filter_optimize_css_images' ), 10, 1 );
|
174 |
-
$_imgopt_active = true;
|
175 |
-
}
|
176 |
-
if ( $_imgopt_active ) {
|
177 |
-
add_filter( 'autoptimize_extra_filter_tobepreconn', array( $this, 'filter_preconnect_imgopt_url' ), 10, 1 );
|
178 |
-
}
|
179 |
-
}
|
180 |
}
|
181 |
|
182 |
public function filter_remove_emoji_dns_prefetch( $urls, $relation_type )
|
@@ -296,7 +258,8 @@ class autoptimizeExtra
|
|
296 |
}
|
297 |
|
298 |
// Replace back in markup.
|
299 |
-
$
|
|
|
300 |
unset( $fonts_collection );
|
301 |
|
302 |
// and insert preload polyfill if "link preload" and if the polyfill isn't there yet (courtesy of inline&defer).
|
@@ -318,7 +281,6 @@ class autoptimizeExtra
|
|
318 |
// Walk array, extract domain and add to new array with crossorigin attribute.
|
319 |
foreach ( $preconns as $preconn ) {
|
320 |
$parsed = parse_url( $preconn );
|
321 |
-
|
322 |
if ( is_array( $parsed ) && empty( $parsed['scheme'] ) ) {
|
323 |
$domain = '//' . $parsed['host'];
|
324 |
} elseif ( is_array( $parsed ) ) {
|
@@ -361,436 +323,16 @@ class autoptimizeExtra
|
|
361 |
return $in;
|
362 |
}
|
363 |
|
364 |
-
public function filter_optimize_images( $in )
|
365 |
-
{
|
366 |
-
/*
|
367 |
-
* potential future functional improvements:
|
368 |
-
*
|
369 |
-
* picture element.
|
370 |
-
* filter for critical CSS.
|
371 |
-
*/
|
372 |
-
|
373 |
-
$imgopt_base_url = $this->get_imgopt_base_url();
|
374 |
-
$to_replace = array();
|
375 |
-
|
376 |
-
// extract img tags.
|
377 |
-
if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $in, $matches ) ) {
|
378 |
-
foreach ( $matches[0] as $tag ) {
|
379 |
-
$orig_tag = $tag;
|
380 |
-
$imgopt_w = '';
|
381 |
-
$imgopt_h = '';
|
382 |
-
|
383 |
-
// first do (data-)srcsets.
|
384 |
-
if ( preg_match_all( '#srcset=("|\')(.*)("|\')#Usmi', $tag, $allsrcsets, PREG_SET_ORDER ) ) {
|
385 |
-
foreach ( $allsrcsets as $srcset ) {
|
386 |
-
$srcset = $srcset[2];
|
387 |
-
$srcsets = explode( ',', $srcset );
|
388 |
-
foreach ( $srcsets as $indiv_srcset ) {
|
389 |
-
$indiv_srcset_parts = explode( ' ', trim( $indiv_srcset ) );
|
390 |
-
if ( $indiv_srcset_parts[1] && rtrim( $indiv_srcset_parts[1], 'w' ) !== $indiv_srcset_parts[1] ) {
|
391 |
-
$imgopt_w = rtrim( $indiv_srcset_parts[1], 'w' );
|
392 |
-
}
|
393 |
-
if ( $this->can_optimize_image( $indiv_srcset_parts[0] ) ) {
|
394 |
-
$imgopt_url = $this->build_imgopt_url( $indiv_srcset_parts[0], $imgopt_w, '' );
|
395 |
-
$tag = str_replace( $indiv_srcset_parts[0], $imgopt_url, $tag );
|
396 |
-
$to_replace[ $orig_tag ] = $tag;
|
397 |
-
}
|
398 |
-
}
|
399 |
-
}
|
400 |
-
}
|
401 |
-
|
402 |
-
// proceed with img src.
|
403 |
-
// first reset and then get width and height and add to $imgopt_size.
|
404 |
-
$imgopt_w = '';
|
405 |
-
$imgopt_h = '';
|
406 |
-
if ( preg_match( '#width=("|\')(.*)("|\')#Usmi', $tag, $width ) ) {
|
407 |
-
$imgopt_w = $width[2];
|
408 |
-
}
|
409 |
-
if ( preg_match( '#height=("|\')(.*)("|\')#Usmi', $tag, $height ) ) {
|
410 |
-
$imgopt_h = $height[2];
|
411 |
-
}
|
412 |
-
|
413 |
-
// then start replacing images src.
|
414 |
-
if ( preg_match_all( '#src=(?:"|\')(?!data)(.*)(?:"|\')#Usmi', $tag, $urls, PREG_SET_ORDER ) ) {
|
415 |
-
foreach ( $urls as $url ) {
|
416 |
-
$full_src_orig = $url[0];
|
417 |
-
$url = $url[1];
|
418 |
-
if ( $this->can_optimize_image( $url ) ) {
|
419 |
-
$imgopt_url = $this->build_imgopt_url( $url, $imgopt_w, $imgopt_h );
|
420 |
-
$full_imgopt_src = str_replace( $url, $imgopt_url, $full_src_orig );
|
421 |
-
$tag = str_replace( $full_src_orig, $full_imgopt_src, $tag );
|
422 |
-
$to_replace[ $orig_tag ] = $tag;
|
423 |
-
}
|
424 |
-
}
|
425 |
-
}
|
426 |
-
}
|
427 |
-
}
|
428 |
-
$out = str_replace( array_keys( $to_replace ), array_values( $to_replace ), $in );
|
429 |
-
|
430 |
-
// img thumbnails in e.g. woocommerce.
|
431 |
-
if ( strpos( $out, 'data-thumb' ) !== false && apply_filters( 'autoptimize_filter_extra_imgopt_datathumbs', true ) ) {
|
432 |
-
$out = preg_replace_callback(
|
433 |
-
'/\<div(?:[^>]?)\sdata-thumb\=(?:\"|\')(.+?)(?:\"|\')(?:[^>]*)?\>/s',
|
434 |
-
array( $this, 'replace_data_thumbs' ),
|
435 |
-
$out
|
436 |
-
);
|
437 |
-
}
|
438 |
-
|
439 |
-
return $out;
|
440 |
-
}
|
441 |
-
|
442 |
-
public function filter_optimize_css_images( $in )
|
443 |
-
{
|
444 |
-
$imgopt_base_url = $this->get_imgopt_base_url();
|
445 |
-
$in = $this->normalize_img_urls( $in );
|
446 |
-
|
447 |
-
if ( $this->can_optimize_image( $in ) ) {
|
448 |
-
return $this->build_imgopt_url( $in, '', '' );
|
449 |
-
} else {
|
450 |
-
return $in;
|
451 |
-
}
|
452 |
-
}
|
453 |
-
|
454 |
-
private function get_imgopt_base_url()
|
455 |
-
{
|
456 |
-
static $imgopt_base_url = null;
|
457 |
-
|
458 |
-
if ( is_null( $imgopt_base_url ) ) {
|
459 |
-
$imgopt_host = $this->get_imgopt_host();
|
460 |
-
$quality = $this->get_img_quality_string();
|
461 |
-
$ret_val = apply_filters( 'autoptimize_filter_extra_imgopt_wait', 'ret_img' ); // values: ret_wait, ret_img, ret_json, ret_blank.
|
462 |
-
$imgopt_base_url = $imgopt_host . 'client/' . $quality . ',' . $ret_val;
|
463 |
-
$imgopt_base_url = apply_filters( 'autoptimize_filter_extra_imgopt_base_url', $imgopt_base_url );
|
464 |
-
}
|
465 |
-
|
466 |
-
return $imgopt_base_url;
|
467 |
-
}
|
468 |
-
|
469 |
-
private function can_optimize_image( $url )
|
470 |
-
{
|
471 |
-
static $cdn_url = null;
|
472 |
-
static $nopti_images = null;
|
473 |
-
|
474 |
-
if ( is_null( $cdn_url ) ) {
|
475 |
-
$cdn_url = apply_filters( 'autoptimize_filter_base_cdnurl', get_option( 'autoptimize_cdn_url', '' ) );
|
476 |
-
}
|
477 |
-
|
478 |
-
if ( is_null( $nopti_images ) ) {
|
479 |
-
$nopti_images = apply_filters( 'autoptimize_filter_extra_imgopt_noptimize', '' );
|
480 |
-
}
|
481 |
-
|
482 |
-
$imgopt_base_url = $this->get_imgopt_base_url();
|
483 |
-
$site_host = AUTOPTIMIZE_SITE_DOMAIN;
|
484 |
-
$url_parsed = parse_url( $url );
|
485 |
-
|
486 |
-
if ( array_key_exists( 'host', $url_parsed ) && $url_parsed['host'] !== $site_host && empty( $cdn_url ) ) {
|
487 |
-
return false;
|
488 |
-
} elseif ( ! empty( $cdn_url ) && strpos( $url, $cdn_url ) === false && array_key_exists( 'host', $url_parsed ) && $url_parsed['host'] !== $site_host ) {
|
489 |
-
return false;
|
490 |
-
} elseif ( strpos( $url, '.php' ) !== false ) {
|
491 |
-
return false;
|
492 |
-
} elseif ( str_ireplace( array( '.png', '.gif', '.jpg', '.jpeg', '.webp' ), '', $url_parsed['path'] ) === $url_parsed['path'] ) {
|
493 |
-
// fixme: better check against end of string.
|
494 |
-
return false;
|
495 |
-
} elseif ( ! empty( $nopti_images ) ) {
|
496 |
-
$nopti_images_array = array_filter( array_map( 'trim', explode( ',', $nopti_images ) ) );
|
497 |
-
foreach ( $nopti_images_array as $nopti_image ) {
|
498 |
-
if ( strpos( $url, $nopti_image ) !== false ) {
|
499 |
-
return false;
|
500 |
-
}
|
501 |
-
}
|
502 |
-
}
|
503 |
-
return true;
|
504 |
-
}
|
505 |
-
|
506 |
-
private function build_imgopt_url( $orig_url, $width = 0, $height = 0 )
|
507 |
-
{
|
508 |
-
// sanitize width and height.
|
509 |
-
if ( strpos( $width, '%' ) !== false ) {
|
510 |
-
$width = 0;
|
511 |
-
}
|
512 |
-
if ( strpos( $height, '%' ) !== false ) {
|
513 |
-
$height = 0;
|
514 |
-
}
|
515 |
-
$width = (int) $width;
|
516 |
-
$height = (int) $height;
|
517 |
-
|
518 |
-
$filtered_url = apply_filters( 'autoptimize_filter_extra_imgopt_build_url', $orig_url, $width, $height );
|
519 |
-
|
520 |
-
if ( $filtered_url !== $orig_url ) {
|
521 |
-
return $filtered_url;
|
522 |
-
}
|
523 |
-
|
524 |
-
$orig_url = $this->normalize_img_urls( $orig_url );
|
525 |
-
$imgopt_base_url = $this->get_imgopt_base_url();
|
526 |
-
$imgopt_size = '';
|
527 |
-
|
528 |
-
if ( $width && 0 !== $width ) {
|
529 |
-
$imgopt_size = ',w_' . $width;
|
530 |
-
}
|
531 |
-
|
532 |
-
if ( $height && 0 !== $height ) {
|
533 |
-
$imgopt_size .= ',h_' . $height;
|
534 |
-
}
|
535 |
-
|
536 |
-
$url = $imgopt_base_url . $imgopt_size . '/' . $orig_url;
|
537 |
-
|
538 |
-
return $url;
|
539 |
-
}
|
540 |
-
|
541 |
-
public function replace_data_thumbs( $matches )
|
542 |
-
{
|
543 |
-
if ( $this->can_optimize_image( $matches[1] ) ) {
|
544 |
-
return str_replace( $matches[1], $this->build_imgopt_url( $matches[1], 150, 150 ), $matches[0] );
|
545 |
-
} else {
|
546 |
-
return $matches[0];
|
547 |
-
}
|
548 |
-
}
|
549 |
-
|
550 |
-
public function filter_preconnect_imgopt_url( $in )
|
551 |
-
{
|
552 |
-
$imgopt_url_array = parse_url( $this->get_imgopt_base_url() );
|
553 |
-
$in[] = $imgopt_url_array['scheme'] . '://' . $imgopt_url_array['host'];
|
554 |
-
|
555 |
-
return $in;
|
556 |
-
}
|
557 |
-
|
558 |
-
private function normalize_img_urls( $in )
|
559 |
-
{
|
560 |
-
static $cdn_domain = null;
|
561 |
-
if ( is_null( $cdn_domain ) ) {
|
562 |
-
$cdn_url = apply_filters( 'autoptimize_filter_base_cdnurl', get_option( 'autoptimize_cdn_url', '' ) );
|
563 |
-
if ( ! empty( $cdn_url ) ) {
|
564 |
-
$cdn_domain = parse_url( $cdn_url, PHP_URL_HOST );
|
565 |
-
} else {
|
566 |
-
$cdn_domain = '';
|
567 |
-
}
|
568 |
-
}
|
569 |
-
|
570 |
-
$parsed_site_url = parse_url( site_url() );
|
571 |
-
|
572 |
-
if ( strpos( $in, 'http' ) !== 0 && strpos( $in, '//' ) === 0 ) {
|
573 |
-
$in = $parsed_site_url['scheme'] . ':' . $in;
|
574 |
-
} elseif ( strpos( $in, '/' ) === 0 ) {
|
575 |
-
$in = $parsed_site_url['scheme'] . '://' . $parsed_site_url['host'] . $in;
|
576 |
-
} elseif ( ! empty( $cdn_domain ) && strpos( $in, $cdn_domain ) !== 0 ) {
|
577 |
-
$in = str_replace( $cdn_domain, $parsed_site_url['host'], $in );
|
578 |
-
}
|
579 |
-
|
580 |
-
return apply_filters( 'autoptimize_filter_extra_imgopt_normalized_url', $in );
|
581 |
-
}
|
582 |
-
|
583 |
-
private function get_img_quality_array()
|
584 |
-
{
|
585 |
-
static $img_quality_array = null;
|
586 |
-
|
587 |
-
if ( is_null( $img_quality_array ) ) {
|
588 |
-
$img_quality_array = array(
|
589 |
-
'1' => 'lossy',
|
590 |
-
'2' => 'glossy',
|
591 |
-
'3' => 'lossless',
|
592 |
-
);
|
593 |
-
$img_quality_array = apply_filters( 'autoptimize_filter_extra_imgopt_quality_array', $img_quality_array );
|
594 |
-
}
|
595 |
-
|
596 |
-
return $img_quality_array;
|
597 |
-
}
|
598 |
-
|
599 |
-
private function get_img_quality_setting()
|
600 |
-
{
|
601 |
-
static $_img_q = null;
|
602 |
-
|
603 |
-
if ( is_null( $_img_q ) ) {
|
604 |
-
if ( is_array( $this->options ) && array_key_exists( 'autoptimize_extra_select_field_6', $this->options ) ) {
|
605 |
-
$_setting = $this->options['autoptimize_extra_select_field_6'];
|
606 |
-
}
|
607 |
-
|
608 |
-
if ( ! isset( $_setting ) || empty( $_setting ) || ( '1' !== $_setting && '3' !== $_setting ) ) {
|
609 |
-
// default image opt. value is 2 ("glossy").
|
610 |
-
$_img_q = '2';
|
611 |
-
} else {
|
612 |
-
$_img_q = $_setting;
|
613 |
-
}
|
614 |
-
}
|
615 |
-
|
616 |
-
return $_img_q;
|
617 |
-
}
|
618 |
-
|
619 |
-
private function get_img_quality_string()
|
620 |
-
{
|
621 |
-
static $_img_q_string = null;
|
622 |
-
|
623 |
-
if ( is_null( $_img_q_string ) ) {
|
624 |
-
$_quality_array = $this->get_img_quality_array();
|
625 |
-
$_setting = $this->get_img_quality_setting();
|
626 |
-
$_img_q_string = apply_filters( 'autoptimize_filter_extra_imgopt_quality', 'q_' . $_quality_array[ $_setting ] );
|
627 |
-
}
|
628 |
-
|
629 |
-
return $_img_q_string;
|
630 |
-
}
|
631 |
-
|
632 |
-
public static function get_img_provider_stats()
|
633 |
-
{
|
634 |
-
// wrapper around query_img_provider_stats() so we can get to $this->options from cronjob() in autoptimizeCacheChecker.
|
635 |
-
$self = new self();
|
636 |
-
return $self->query_img_provider_stats();
|
637 |
-
}
|
638 |
-
|
639 |
-
public function query_img_provider_stats()
|
640 |
-
{
|
641 |
-
if ( ! empty( $this->options['autoptimize_extra_checkbox_field_5'] ) ) {
|
642 |
-
$_img_provider_stat_url = '';
|
643 |
-
$_img_provider_endpoint = $this->get_imgopt_host() . 'read-domain/';
|
644 |
-
$_site_host = AUTOPTIMIZE_SITE_DOMAIN;
|
645 |
-
|
646 |
-
// make sure parse_url result makes sense, keeping $_img_provider_stat_url empty if not.
|
647 |
-
if ( $_site_host && ! empty( $_site_host ) ) {
|
648 |
-
$_img_provider_stat_url = $_img_provider_endpoint . $_site_host;
|
649 |
-
}
|
650 |
-
|
651 |
-
$_img_provider_stat_url = apply_filters( 'autoptimize_filter_extra_imgopt_stat_url', $_img_provider_stat_url );
|
652 |
-
|
653 |
-
// only do the remote call if $_img_provider_stat_url is not empty to make sure no parse_url weirdness results in useless calls.
|
654 |
-
if ( ! empty( $_img_provider_stat_url ) ) {
|
655 |
-
$_img_stat_resp = wp_remote_get( $_img_provider_stat_url );
|
656 |
-
if ( ! is_wp_error( $_img_stat_resp ) ) {
|
657 |
-
if ( '200' == wp_remote_retrieve_response_code( $_img_stat_resp ) ) {
|
658 |
-
$_img_provider_stat = json_decode( wp_remote_retrieve_body( $_img_stat_resp ), true );
|
659 |
-
$_img_provider_stat['timestamp'] = time();
|
660 |
-
update_option( 'autoptimize_imgopt_provider_stat', $_img_provider_stat );
|
661 |
-
}
|
662 |
-
}
|
663 |
-
}
|
664 |
-
}
|
665 |
-
}
|
666 |
-
|
667 |
-
public function imgopt_launch_ok()
|
668 |
-
{
|
669 |
-
static $launch_status = null;
|
670 |
-
|
671 |
-
if ( is_null( $launch_status ) ) {
|
672 |
-
$avail_imgopt = $this->options['availabilities']['extra_imgopt'];
|
673 |
-
$magic_number = intval( substr( md5( parse_url( AUTOPTIMIZE_WP_SITE_URL, PHP_URL_HOST ) ), 0, 3 ), 16 );
|
674 |
-
$has_launched = get_option( 'autoptimize_imgopt_launched', '' );
|
675 |
-
if ( $has_launched || ( is_array( $avail_imgopt ) && array_key_exists( 'launch-threshold', $avail_imgopt ) && $magic_number < $avail_imgopt['launch-threshold'] ) ) {
|
676 |
-
$launch_status = true;
|
677 |
-
if ( ! $has_launched ) {
|
678 |
-
update_option( 'autoptimize_imgopt_launched', 'on' );
|
679 |
-
}
|
680 |
-
} else {
|
681 |
-
$launch_status = false;
|
682 |
-
}
|
683 |
-
}
|
684 |
-
|
685 |
-
return $launch_status;
|
686 |
-
}
|
687 |
-
|
688 |
-
public static function imgopt_launch_ok_wrapper()
|
689 |
-
{
|
690 |
-
// needed for "plug" notice in autoptimizeMain.php.
|
691 |
-
$self = new self();
|
692 |
-
return $self->imgopt_launch_ok();
|
693 |
-
}
|
694 |
-
|
695 |
-
public function get_imgopt_host()
|
696 |
-
{
|
697 |
-
static $imgopt_host = null;
|
698 |
-
|
699 |
-
if ( is_null( $imgopt_host ) ) {
|
700 |
-
$avail_imgopt = $this->options['availabilities']['extra_imgopt'];
|
701 |
-
if ( ! empty( $avail_imgopt ) && array_key_exists( 'hosts', $avail_imgopt ) && is_array( $avail_imgopt['hosts'] ) ) {
|
702 |
-
$imgopt_host = array_rand( array_flip( $avail_imgopt['hosts'] ) );
|
703 |
-
} else {
|
704 |
-
$imgopt_host = 'https://cdn.shortpixel.ai/';
|
705 |
-
}
|
706 |
-
}
|
707 |
-
|
708 |
-
return $imgopt_host;
|
709 |
-
}
|
710 |
-
|
711 |
-
public static function get_imgopt_host_wrapper()
|
712 |
-
{
|
713 |
-
// needed for CI tests.
|
714 |
-
$self = new self();
|
715 |
-
return $self->get_imgopt_host();
|
716 |
-
}
|
717 |
-
|
718 |
-
public function get_imgopt_status_notice() {
|
719 |
-
$_extra_options = $this->options;
|
720 |
-
if ( ! empty( $_extra_options ) && is_array( $_extra_options ) && array_key_exists( 'autoptimize_extra_checkbox_field_5', $_extra_options ) && ! empty( $_extra_options['autoptimize_extra_checkbox_field_5'] ) ) {
|
721 |
-
$_imgopt_notice = '';
|
722 |
-
$_stat = $this->get_imgopt_provider_userstatus();
|
723 |
-
$_site_host = AUTOPTIMIZE_SITE_DOMAIN;
|
724 |
-
$_imgopt_upsell = 'https://shortpixel.com/aospai/af/GWRGFLW109483/' . $_site_host;
|
725 |
-
|
726 |
-
if ( is_array( $_stat ) ) {
|
727 |
-
if ( 1 == $_stat['Status'] ) {
|
728 |
-
// translators: "add more credits" will appear in a "a href".
|
729 |
-
$_imgopt_notice = sprintf( __( 'Your ShortPixel image optimization and CDN quota is almost used, make sure you %1$sadd more credits%2$s to avoid slowing down your website.', 'autoptimize' ), '<a href="' . $_imgopt_upsell . '" target="_blank">', '</a>' );
|
730 |
-
} elseif ( -1 == $_stat['Status'] || -2 == $_stat['Status'] ) {
|
731 |
-
// translators: "add more credits" will appear in a "a href".
|
732 |
-
$_imgopt_notice = sprintf( __( 'Your ShortPixel image optimization and CDN quota was used, %1$sadd more credits%2$s to keep fast serving optimized images on your site', 'autoptimize' ), '<a href="' . $_imgopt_upsell . '" target="_blank">', '</a>' );
|
733 |
-
$_imgopt_stats_refresh_url = add_query_arg( array(
|
734 |
-
'page' => 'autoptimize_extra',
|
735 |
-
'refreshImgProvStats' => '1',
|
736 |
-
), admin_url( 'options-general.php' ) );
|
737 |
-
if ( $_stat && array_key_exists( 'timestamp', $_stat ) && ! empty( $_stat['timestamp'] ) ) {
|
738 |
-
$_imgopt_stats_last_run = __( 'based on status at ', 'autoptimize' ) . date_i18n( get_option( 'time_format' ), $_stat['timestamp'] );
|
739 |
-
} else {
|
740 |
-
$_imgopt_stats_last_run = __( 'based on previously fetched data', 'autoptimize' );
|
741 |
-
}
|
742 |
-
$_imgopt_notice .= ' (' . $_imgopt_stats_last_run . ', ';
|
743 |
-
// translators: "here to refresh" links to the Autoptimize Extra page and forces a refresh of the img opt stats.
|
744 |
-
$_imgopt_notice .= sprintf( __( 'click %1$shere to refresh%2$s', 'autoptimize' ), '<a href="' . $_imgopt_stats_refresh_url . '">', '</a>).' );
|
745 |
-
} else {
|
746 |
-
$_imgopt_upsell = 'https://shortpixel.com/g/af/GWRGFLW109483';
|
747 |
-
// translators: "log in to check your account" will appear in a "a href".
|
748 |
-
$_imgopt_notice = sprintf( __( 'Your ShortPixel image optimization and CDN quota are in good shape, %1$slog in to check your account%2$s.', 'autoptimize' ), '<a href="' . $_imgopt_upsell . '" target="_blank">', '</a>' );
|
749 |
-
}
|
750 |
-
$_imgopt_notice = apply_filters( 'autoptimize_filter_imgopt_notice', $_imgopt_notice );
|
751 |
-
|
752 |
-
return array(
|
753 |
-
'status' => $_stat['Status'],
|
754 |
-
'notice' => $_imgopt_notice,
|
755 |
-
);
|
756 |
-
}
|
757 |
-
}
|
758 |
-
return false;
|
759 |
-
}
|
760 |
-
|
761 |
-
public static function get_imgopt_status_notice_wrapper() {
|
762 |
-
// needed for notice being shown in autoptimizeCacheChecker.php.
|
763 |
-
$self = new self();
|
764 |
-
return $self->get_imgopt_status_notice();
|
765 |
-
}
|
766 |
-
|
767 |
-
public function get_imgopt_provider_userstatus() {
|
768 |
-
static $_provider_userstatus = null;
|
769 |
-
|
770 |
-
if ( is_null( $_provider_userstatus ) ) {
|
771 |
-
$_stat = get_option( 'autoptimize_imgopt_provider_stat', '' );
|
772 |
-
if ( is_array( $_stat ) ) {
|
773 |
-
if ( array_key_exists( 'Status', $_stat ) ) {
|
774 |
-
$_provider_userstatus['Status'] = $_stat['Status'];
|
775 |
-
} else {
|
776 |
-
// if no stats then we assume all is well.
|
777 |
-
$_provider_userstatus['Status'] = 2;
|
778 |
-
}
|
779 |
-
if ( array_key_exists( 'timestamp', $_stat ) ) {
|
780 |
-
$_provider_userstatus['timestamp'] = $_stat['timestamp'];
|
781 |
-
} else {
|
782 |
-
// if no timestamp then we return "".
|
783 |
-
$_provider_userstatus['timestamp'] = '';
|
784 |
-
}
|
785 |
-
}
|
786 |
-
}
|
787 |
-
|
788 |
-
return $_provider_userstatus;
|
789 |
-
}
|
790 |
-
|
791 |
public function admin_menu()
|
792 |
{
|
793 |
-
add_submenu_page(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
794 |
register_setting( 'autoptimize_extra_settings', 'autoptimize_extra_settings' );
|
795 |
}
|
796 |
|
@@ -803,19 +345,13 @@ class autoptimizeExtra
|
|
803 |
|
804 |
public function options_page()
|
805 |
{
|
806 |
-
// Check querystring for "refreshCacheChecker" and call cachechecker if so.
|
807 |
-
if ( array_key_exists( 'refreshImgProvStats', $_GET ) && 1 == $_GET['refreshImgProvStats'] ) {
|
808 |
-
$this->query_img_provider_stats();
|
809 |
-
}
|
810 |
-
|
811 |
// Working with actual option values from the database here.
|
812 |
// That way any saves are still processed as expected, but we can still
|
813 |
// override behavior by using `new autoptimizeExtra($custom_options)` and not have that custom
|
814 |
// behavior being persisted in the DB even if save is done here.
|
815 |
-
$options
|
816 |
-
$gfonts
|
817 |
-
|
818 |
-
?>
|
819 |
<style>
|
820 |
#ao_settings_form {background: white;border: 1px solid #ccc;padding: 1px 15px;margin: 15px 10px 10px 0;}
|
821 |
#ao_settings_form .form-table th {font-weight: normal;}
|
@@ -823,40 +359,13 @@ class autoptimizeExtra
|
|
823 |
</style>
|
824 |
<div class="wrap">
|
825 |
<h1><?php _e( 'Autoptimize Settings', 'autoptimize' ); ?></h1>
|
826 |
-
|
827 |
-
|
828 |
-
|
829 |
-
|
830 |
-
|
831 |
-
<?php
|
832 |
-
_e( 'Most of below Extra optimizations require at least one of HTML, JS or CSS autoptimizations being active.', 'autoptimize' );
|
833 |
-
?>
|
834 |
-
</p></div>
|
835 |
-
<?php
|
836 |
-
}
|
837 |
|
838 |
-
if ( 'down' === $options['availabilities']['extra_imgopt']['status'] ) {
|
839 |
-
?>
|
840 |
-
<div class="notice-warning notice"><p>
|
841 |
-
<?php
|
842 |
-
// translators: "Autoptimize support forum" will appear in a "a href".
|
843 |
-
echo sprintf( __( 'The image optimization service is currently down, image optimization will be skipped until further notice. Check the %1$sAutoptimize support forum%2$s for more info.', 'autoptimize' ), '<a href="https://wordpress.org/support/plugin/autoptimize/" target="_blank">', '</a>' );
|
844 |
-
?>
|
845 |
-
</p></div>
|
846 |
-
<?php
|
847 |
-
}
|
848 |
-
|
849 |
-
if ( 'launch' === $options['availabilities']['extra_imgopt']['status'] && ! $this->imgopt_launch_ok() ) {
|
850 |
-
?>
|
851 |
-
<div class="notice-warning notice"><p>
|
852 |
-
<?php
|
853 |
-
_e( 'The image optimization service is launching, but not yet available for this domain, it should become available in the next couple of days.', 'autoptimize' );
|
854 |
-
?>
|
855 |
-
</p></div>
|
856 |
-
<?php
|
857 |
-
}
|
858 |
-
|
859 |
-
?>
|
860 |
<form id='ao_settings_form' action='options.php' method='post'>
|
861 |
<?php settings_fields( 'autoptimize_extra_settings' ); ?>
|
862 |
<h2><?php _e( 'Extra Auto-Optimizations', 'autoptimize' ); ?></h2>
|
@@ -872,78 +381,6 @@ class autoptimizeExtra
|
|
872 |
<input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="4" <?php checked( 4, $gfonts, true ); ?> ><?php _e( 'Combine and load fonts asynchronously with <a href="https://github.com/typekit/webfontloader#readme" target="_blank">webfont.js</a>', 'autoptimize' ); ?><br/>
|
873 |
</td>
|
874 |
</tr>
|
875 |
-
<tr>
|
876 |
-
<th scope="row"><?php _e( 'Optimize Images', 'autoptimize' ); ?></th>
|
877 |
-
<td>
|
878 |
-
<label><input id='autoptimize_imgopt_checkbox' type='checkbox' name='autoptimize_extra_settings[autoptimize_extra_checkbox_field_5]' <?php if ( ! empty( $options['autoptimize_extra_checkbox_field_5'] ) && '1' === $options['autoptimize_extra_checkbox_field_5'] ) { echo 'checked="checked"'; } ?> value='1'><?php _e( 'Optimize images on the fly and serve them from a CDN.', 'autoptimize' ); ?></label>
|
879 |
-
<?php
|
880 |
-
// show shortpixel status.
|
881 |
-
$_notice = $this->get_imgopt_status_notice();
|
882 |
-
if ( $_notice ) {
|
883 |
-
switch ( $_notice['status'] ) {
|
884 |
-
case 2:
|
885 |
-
$_notice_color = 'green';
|
886 |
-
break;
|
887 |
-
case 1:
|
888 |
-
$_notice_color = 'orange';
|
889 |
-
break;
|
890 |
-
case -1:
|
891 |
-
$_notice_color = 'red';
|
892 |
-
break;
|
893 |
-
case -2:
|
894 |
-
$_notice_color = 'red';
|
895 |
-
break;
|
896 |
-
default:
|
897 |
-
$_notice_color = 'green';
|
898 |
-
}
|
899 |
-
echo apply_filters( 'autoptimize_filter_imgopt_settings_status', '<p><strong><span style="color:' . $_notice_color . ';">' . __( 'Shortpixel status: ', 'autoptimize' ) . '</span></strong>' . $_notice['notice'] . '</p>' );
|
900 |
-
} else {
|
901 |
-
// translators: link points to shortpixel.
|
902 |
-
$upsell_msg_1 = '<p>' . sprintf( __( 'Get more Google love and improve your website\'s loading speed by having the images optimized on the fly by %1$sShortPixel%2$s and then cached and served fast from a CDN.', 'autoptimize' ), '<a href="https://shortpixel.com/aospai' . $sp_url_suffix . '" target="_blank">', '</a>' );
|
903 |
-
if ( 'launch' === $options['availabilities']['extra_imgopt']['status'] ) {
|
904 |
-
$upsell_msg_2 = __( 'For a limited time only, this service is offered free for all Autoptimize users, <b>don\'t miss the chance to test it</b> and see how much it could improve your site\'s speed.', 'autoptimize' );
|
905 |
-
} else {
|
906 |
-
// translators: link points to shortpixel.
|
907 |
-
$upsell_msg_2 = sprintf( __( '%1$sSign-up now%2$s to receive a 1 000 bonus + 50% more image optimization credits regardless of the traffic used. More image optimizations can be purchased starting with $4.99.', 'autoptimize' ), '<a href="https://shortpixel.com/aospai' . $sp_url_suffix . '" target="_blank">', '</a>' );
|
908 |
-
}
|
909 |
-
echo apply_filters( 'autoptimize_extra_imgopt_settings_copy', $upsell_msg_1 . ' ' . $upsell_msg_2 . '</p>' );
|
910 |
-
}
|
911 |
-
// translators: link points to shortpixel FAQ.
|
912 |
-
$faqcopy = sprintf( __( '<strong>Questions</strong>? Have a look at the %1$sShortPixel FAQ%2$s!', 'autoptimize' ), '<strong><a href="https://shortpixel.helpscoutdocs.com/category/60-shortpixel-ai-cdn" target="_blank">', '</strong></a>' );
|
913 |
-
// translators: links points to shortpixel TOS & Privacy Policy.
|
914 |
-
$toscopy = sprintf( __( 'Usage of this feature is subject to Shortpixel\'s %1$sTerms of Use%2$s and %3$sPrivacy policy%4$s.', 'autoptimize' ), '<a href="https://shortpixel.com/tos' . $sp_url_suffix . '" target="_blank">', '</a>', '<a href="https://shortpixel.com/pp' . $sp_url_suffix . '" target="_blank">', '</a>' );
|
915 |
-
echo apply_filters( 'autoptimize_extra_imgopt_settings_tos', '<p>' . $faqcopy . ' ' . $toscopy . '</p>' );
|
916 |
-
?>
|
917 |
-
</td>
|
918 |
-
</tr>
|
919 |
-
<tr id='autoptimize_imgopt_quality' <?php if ( ! array_key_exists( 'autoptimize_extra_checkbox_field_5', $options ) || ( ! empty( $options['autoptimize_extra_checkbox_field_5'] ) && '1' !== $options['autoptimize_extra_checkbox_field_5'] ) ) { echo 'class="hidden"'; } ?>>
|
920 |
-
<th scope="row"><?php _e( 'Image Optimization quality', 'autoptimize' ); ?></th>
|
921 |
-
<td>
|
922 |
-
<label>
|
923 |
-
<select name='autoptimize_extra_settings[autoptimize_extra_select_field_6]'>
|
924 |
-
<?php
|
925 |
-
$_imgopt_array = $this->get_img_quality_array();
|
926 |
-
$_imgopt_val = $this->get_img_quality_setting();
|
927 |
-
|
928 |
-
foreach ( $_imgopt_array as $key => $value ) {
|
929 |
-
echo '<option value="' . $key . '"';
|
930 |
-
if ( $_imgopt_val == $key ) {
|
931 |
-
echo ' selected';
|
932 |
-
}
|
933 |
-
echo '>' . ucfirst( $value ) . '</option>';
|
934 |
-
}
|
935 |
-
echo "\n";
|
936 |
-
?>
|
937 |
-
</select>
|
938 |
-
</label>
|
939 |
-
<p>
|
940 |
-
<?php
|
941 |
-
// translators: link points to shortpixel image test page.
|
942 |
-
echo apply_filters( 'autoptimize_extra_imgopt_quality_copy', sprintf( __( 'You can %1$stest compression levels here%2$s.', 'autoptimize' ), '<a href="https://shortpixel.com/oic' . $sp_url_suffix . '" target="_blank">', '</a>' ) );
|
943 |
-
?>
|
944 |
-
</p>
|
945 |
-
</td>
|
946 |
-
</tr>
|
947 |
<tr>
|
948 |
<th scope="row"><?php _e( 'Remove emojis', 'autoptimize' ); ?></th>
|
949 |
<td>
|
@@ -966,7 +403,7 @@ class autoptimizeExtra
|
|
966 |
<th scope="row"><?php _e( 'Async Javascript-files <em>(advanced users)</em>', 'autoptimize' ); ?></th>
|
967 |
<td>
|
968 |
<?php
|
969 |
-
if (
|
970 |
// translators: link points Async Javascript settings page.
|
971 |
printf( __( 'You have "Async JavaScript" installed, %1$sconfiguration of async javascript is best done there%2$s.', 'autoptimize' ), '<a href="' . 'options-general.php?page=async-javascript' . '">', '</a>' );
|
972 |
} else {
|
@@ -987,7 +424,7 @@ class autoptimizeExtra
|
|
987 |
<th scope="row"><?php _e( 'Optimize YouTube videos', 'autoptimize' ); ?></th>
|
988 |
<td>
|
989 |
<?php
|
990 |
-
if (
|
991 |
_e( 'Great, you have WP YouTube Lyte installed.', 'autoptimize' );
|
992 |
$lyte_config_url = 'options-general.php?page=lyte_settings_page';
|
993 |
echo sprintf( ' <a href="' . $lyte_config_url . '">%s</a>', __( 'Click here to configure it.', 'autoptimize' ) );
|
@@ -1003,17 +440,6 @@ class autoptimizeExtra
|
|
1003 |
</table>
|
1004 |
<p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="<?php _e( 'Save Changes', 'autoptimize' ); ?>" /></p>
|
1005 |
</form>
|
1006 |
-
|
1007 |
-
jQuery(document).ready(function() {
|
1008 |
-
jQuery( "#autoptimize_imgopt_checkbox" ).change(function() {
|
1009 |
-
if (this.checked) {
|
1010 |
-
jQuery("#autoptimize_imgopt_quality").show("slow");
|
1011 |
-
} else {
|
1012 |
-
jQuery("#autoptimize_imgopt_quality").hide("slow");
|
1013 |
-
}
|
1014 |
-
});
|
1015 |
-
});
|
1016 |
-
</script>
|
1017 |
-
<?php
|
1018 |
}
|
1019 |
}
|
24 |
public function __construct( $options = array() )
|
25 |
{
|
26 |
if ( empty( $options ) ) {
|
27 |
+
$options = self::fetch_options();
|
28 |
}
|
29 |
|
30 |
$this->options = $options;
|
40 |
}
|
41 |
}
|
42 |
|
43 |
+
public static function fetch_options()
|
44 |
{
|
45 |
$value = get_option( 'autoptimize_extra_settings' );
|
46 |
if ( empty( $value ) ) {
|
48 |
$value = autoptimizeConfig::get_ao_extra_default_options();
|
49 |
}
|
50 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
return $value;
|
52 |
}
|
53 |
|
78 |
}
|
79 |
}
|
80 |
|
81 |
+
public function filter_remove_qs( $src )
|
82 |
+
{
|
83 |
if ( strpos( $src, '?ver=' ) ) {
|
84 |
$src = remove_query_arg( 'ver', $src );
|
85 |
}
|
122 |
add_filter( 'style_loader_src', array( $this, 'filter_remove_qs' ), 15, 1 );
|
123 |
}
|
124 |
|
|
|
|
|
|
|
|
|
125 |
// Avoiding conflicts of interest when async-javascript plugin is active!
|
126 |
+
$async_js_plugin_active = autoptimizeUtils::is_plugin_active( 'async-javascript/async-javascript.php' );
|
|
|
|
|
|
|
127 |
if ( ! empty( $options['autoptimize_extra_text_field_3'] ) && ! $async_js_plugin_active ) {
|
128 |
add_filter( 'autoptimize_filter_js_exclude', array( $this, 'extra_async_js' ), 10, 1 );
|
129 |
}
|
139 |
if ( ! empty( $options['autoptimize_extra_text_field_2'] ) || has_filter( 'autoptimize_extra_filter_tobepreconn' ) ) {
|
140 |
add_filter( 'wp_resource_hints', array( $this, 'filter_preconnect' ), 10, 2 );
|
141 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
142 |
}
|
143 |
|
144 |
public function filter_remove_emoji_dns_prefetch( $urls, $relation_type )
|
258 |
}
|
259 |
|
260 |
// Replace back in markup.
|
261 |
+
$inject_point = apply_filters( 'autoptimize_filter_extra_gfont_injectpoint', '<link' );
|
262 |
+
$out = substr_replace( $in, $fonts_markup . $inject_point, strpos( $in, $inject_point ), strlen( $inject_point ) );
|
263 |
unset( $fonts_collection );
|
264 |
|
265 |
// and insert preload polyfill if "link preload" and if the polyfill isn't there yet (courtesy of inline&defer).
|
281 |
// Walk array, extract domain and add to new array with crossorigin attribute.
|
282 |
foreach ( $preconns as $preconn ) {
|
283 |
$parsed = parse_url( $preconn );
|
|
|
284 |
if ( is_array( $parsed ) && empty( $parsed['scheme'] ) ) {
|
285 |
$domain = '//' . $parsed['host'];
|
286 |
} elseif ( is_array( $parsed ) ) {
|
323 |
return $in;
|
324 |
}
|
325 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
326 |
public function admin_menu()
|
327 |
{
|
328 |
+
add_submenu_page(
|
329 |
+
null,
|
330 |
+
'autoptimize_extra',
|
331 |
+
'autoptimize_extra',
|
332 |
+
'manage_options',
|
333 |
+
'autoptimize_extra',
|
334 |
+
array( $this, 'options_page' )
|
335 |
+
);
|
336 |
register_setting( 'autoptimize_extra_settings', 'autoptimize_extra_settings' );
|
337 |
}
|
338 |
|
345 |
|
346 |
public function options_page()
|
347 |
{
|
|
|
|
|
|
|
|
|
|
|
348 |
// Working with actual option values from the database here.
|
349 |
// That way any saves are still processed as expected, but we can still
|
350 |
// override behavior by using `new autoptimizeExtra($custom_options)` and not have that custom
|
351 |
// behavior being persisted in the DB even if save is done here.
|
352 |
+
$options = $this->fetch_options();
|
353 |
+
$gfonts = $options['autoptimize_extra_radio_field_4'];
|
354 |
+
?>
|
|
|
355 |
<style>
|
356 |
#ao_settings_form {background: white;border: 1px solid #ccc;padding: 1px 15px;margin: 15px 10px 10px 0;}
|
357 |
#ao_settings_form .form-table th {font-weight: normal;}
|
359 |
</style>
|
360 |
<div class="wrap">
|
361 |
<h1><?php _e( 'Autoptimize Settings', 'autoptimize' ); ?></h1>
|
362 |
+
<?php echo autoptimizeConfig::ao_admin_tabs(); ?>
|
363 |
+
<?php if ( 'on' !== get_option( 'autoptimize_js' ) && 'on' !== get_option( 'autoptimize_css' ) && 'on' !== get_option( 'autoptimize_html' ) && ! autoptimizeImages::imgopt_active() ) { ?>
|
364 |
+
<div class="notice-warning notice"><p>
|
365 |
+
<?php _e( 'Most of below Extra optimizations require at least one of HTML, JS, CSS or Image autoptimizations being active.', 'autoptimize' ); ?>
|
366 |
+
</p></div>
|
367 |
+
<?php } ?>
|
|
|
|
|
|
|
|
|
|
|
368 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
369 |
<form id='ao_settings_form' action='options.php' method='post'>
|
370 |
<?php settings_fields( 'autoptimize_extra_settings' ); ?>
|
371 |
<h2><?php _e( 'Extra Auto-Optimizations', 'autoptimize' ); ?></h2>
|
381 |
<input type="radio" name="autoptimize_extra_settings[autoptimize_extra_radio_field_4]" value="4" <?php checked( 4, $gfonts, true ); ?> ><?php _e( 'Combine and load fonts asynchronously with <a href="https://github.com/typekit/webfontloader#readme" target="_blank">webfont.js</a>', 'autoptimize' ); ?><br/>
|
382 |
</td>
|
383 |
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
384 |
<tr>
|
385 |
<th scope="row"><?php _e( 'Remove emojis', 'autoptimize' ); ?></th>
|
386 |
<td>
|
403 |
<th scope="row"><?php _e( 'Async Javascript-files <em>(advanced users)</em>', 'autoptimize' ); ?></th>
|
404 |
<td>
|
405 |
<?php
|
406 |
+
if ( autoptimizeUtils::is_plugin_active( 'async-javascript/async-javascript.php' ) ) {
|
407 |
// translators: link points Async Javascript settings page.
|
408 |
printf( __( 'You have "Async JavaScript" installed, %1$sconfiguration of async javascript is best done there%2$s.', 'autoptimize' ), '<a href="' . 'options-general.php?page=async-javascript' . '">', '</a>' );
|
409 |
} else {
|
424 |
<th scope="row"><?php _e( 'Optimize YouTube videos', 'autoptimize' ); ?></th>
|
425 |
<td>
|
426 |
<?php
|
427 |
+
if ( autoptimizeUtils::is_plugin_active( 'wp-youtube-lyte/wp-youtube-lyte.php' ) ) {
|
428 |
_e( 'Great, you have WP YouTube Lyte installed.', 'autoptimize' );
|
429 |
$lyte_config_url = 'options-general.php?page=lyte_settings_page';
|
430 |
echo sprintf( ' <a href="' . $lyte_config_url . '">%s</a>', __( 'Click here to configure it.', 'autoptimize' ) );
|
440 |
</table>
|
441 |
<p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="<?php _e( 'Save Changes', 'autoptimize' ); ?>" /></p>
|
442 |
</form>
|
443 |
+
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
444 |
}
|
445 |
}
|
classes/autoptimizeImages.php
ADDED
@@ -0,0 +1,1174 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Handles optimizing images.
|
4 |
+
*/
|
5 |
+
|
6 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
7 |
+
exit;
|
8 |
+
}
|
9 |
+
|
10 |
+
class autoptimizeImages
|
11 |
+
{
|
12 |
+
/**
|
13 |
+
* Options.
|
14 |
+
*
|
15 |
+
* @var array
|
16 |
+
*/
|
17 |
+
protected $options = array();
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Singleton instance.
|
21 |
+
*
|
22 |
+
* @var self|null
|
23 |
+
*/
|
24 |
+
protected static $instance = null;
|
25 |
+
|
26 |
+
public function __construct( array $options = array() )
|
27 |
+
{
|
28 |
+
// If options are not provided, fetch them.
|
29 |
+
if ( empty( $options ) ) {
|
30 |
+
$options = $this->fetch_options();
|
31 |
+
}
|
32 |
+
|
33 |
+
$this->set_options( $options );
|
34 |
+
}
|
35 |
+
|
36 |
+
public function set_options( array $options )
|
37 |
+
{
|
38 |
+
$this->options = $options;
|
39 |
+
|
40 |
+
return $this;
|
41 |
+
}
|
42 |
+
|
43 |
+
public static function fetch_options()
|
44 |
+
{
|
45 |
+
$value = get_option( 'autoptimize_imgopt_settings' );
|
46 |
+
if ( empty( $value ) ) {
|
47 |
+
// Fallback to returning defaults when no stored option exists yet.
|
48 |
+
$value = autoptimizeConfig::get_ao_imgopt_default_options();
|
49 |
+
}
|
50 |
+
|
51 |
+
// get service availability and add it to the options-array.
|
52 |
+
$value['availabilities'] = get_option( 'autoptimize_service_availablity' );
|
53 |
+
|
54 |
+
if ( empty( $value['availabilities'] ) ) {
|
55 |
+
$value['availabilities'] = autoptimizeUtils::check_service_availability( true );
|
56 |
+
}
|
57 |
+
|
58 |
+
return $value;
|
59 |
+
}
|
60 |
+
|
61 |
+
public static function imgopt_active()
|
62 |
+
{
|
63 |
+
// function to quickly check if imgopt is active, used below but also in
|
64 |
+
// autoptimizeMain.php to start ob_ even if no HTML, JS or CSS optimizing is done
|
65 |
+
// and does not use/ request the availablity data (which could slow things down).
|
66 |
+
static $imgopt_active = null;
|
67 |
+
|
68 |
+
if ( null === $imgopt_active ) {
|
69 |
+
$opts = get_option( 'autoptimize_imgopt_settings', '' );
|
70 |
+
if ( ! empty( $opts ) && is_array( $opts ) && array_key_exists( 'autoptimize_imgopt_checkbox_field_1', $opts ) && ! empty( $opts['autoptimize_imgopt_checkbox_field_1'] ) && '1' === $opts['autoptimize_imgopt_checkbox_field_1'] ) {
|
71 |
+
$imgopt_active = true;
|
72 |
+
} else {
|
73 |
+
$imgopt_active = false;
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
return $imgopt_active;
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Helper for getting a singleton instance. While being an
|
82 |
+
* anti-pattern generally, it comes in handy for now from a
|
83 |
+
* readability/maintainability perspective, until we get some
|
84 |
+
* proper dependency injection going.
|
85 |
+
*
|
86 |
+
* @return self
|
87 |
+
*/
|
88 |
+
public static function instance()
|
89 |
+
{
|
90 |
+
if ( null === self::$instance ) {
|
91 |
+
self::$instance = new self();
|
92 |
+
}
|
93 |
+
|
94 |
+
return self::$instance;
|
95 |
+
}
|
96 |
+
|
97 |
+
public function run()
|
98 |
+
{
|
99 |
+
if ( is_admin() ) {
|
100 |
+
add_action( 'admin_menu', array( $this, 'imgopt_admin_menu' ) );
|
101 |
+
add_filter( 'autoptimize_filter_settingsscreen_tabs', array( $this, 'add_imgopt_tab' ), 9 );
|
102 |
+
} else {
|
103 |
+
$this->run_on_frontend();
|
104 |
+
}
|
105 |
+
}
|
106 |
+
|
107 |
+
public function run_on_frontend() {
|
108 |
+
if ( ! $this->should_run() ) {
|
109 |
+
if ( $this->should_lazyload() ) {
|
110 |
+
add_filter(
|
111 |
+
'autoptimize_html_after_minify',
|
112 |
+
array( $this, 'filter_lazyload_images' ),
|
113 |
+
10,
|
114 |
+
1
|
115 |
+
);
|
116 |
+
add_action(
|
117 |
+
'wp_footer',
|
118 |
+
array( $this, 'add_lazyload_js_footer' ),
|
119 |
+
10,
|
120 |
+
0
|
121 |
+
);
|
122 |
+
}
|
123 |
+
return;
|
124 |
+
}
|
125 |
+
|
126 |
+
$active = false;
|
127 |
+
|
128 |
+
if ( apply_filters( 'autoptimize_filter_imgopt_do', true ) ) {
|
129 |
+
add_filter(
|
130 |
+
'autoptimize_html_after_minify',
|
131 |
+
array( $this, 'filter_optimize_images' ),
|
132 |
+
10,
|
133 |
+
1
|
134 |
+
);
|
135 |
+
$active = true;
|
136 |
+
}
|
137 |
+
|
138 |
+
if ( apply_filters( 'autoptimize_filter_imgopt_do_css', true ) ) {
|
139 |
+
add_filter(
|
140 |
+
'autoptimize_filter_base_replace_cdn',
|
141 |
+
array( $this, 'filter_optimize_css_images' ),
|
142 |
+
10,
|
143 |
+
1
|
144 |
+
);
|
145 |
+
$active = true;
|
146 |
+
}
|
147 |
+
|
148 |
+
if ( $active ) {
|
149 |
+
add_filter(
|
150 |
+
'autoptimize_extra_filter_tobepreconn',
|
151 |
+
array( $this, 'filter_preconnect_imgopt_url' ),
|
152 |
+
10,
|
153 |
+
1
|
154 |
+
);
|
155 |
+
}
|
156 |
+
|
157 |
+
if ( $this->should_lazyload() ) {
|
158 |
+
add_action(
|
159 |
+
'wp_footer',
|
160 |
+
array( $this, 'add_lazyload_js_footer' )
|
161 |
+
);
|
162 |
+
}
|
163 |
+
}
|
164 |
+
|
165 |
+
/**
|
166 |
+
* Basic checks before we can run.
|
167 |
+
*
|
168 |
+
* @return bool
|
169 |
+
*/
|
170 |
+
protected function should_run()
|
171 |
+
{
|
172 |
+
$opts = $this->options;
|
173 |
+
$service_not_down = ( 'down' !== $opts['availabilities']['extra_imgopt']['status'] );
|
174 |
+
$not_launch_status = ( 'launch' !== $opts['availabilities']['extra_imgopt']['status'] );
|
175 |
+
|
176 |
+
$do_cdn = true;
|
177 |
+
$_userstatus = $this->get_imgopt_provider_userstatus();
|
178 |
+
if ( -2 == $_userstatus['Status'] ) {
|
179 |
+
$do_cdn = false;
|
180 |
+
}
|
181 |
+
|
182 |
+
if (
|
183 |
+
$this->imgopt_active()
|
184 |
+
&& $do_cdn
|
185 |
+
&& $service_not_down
|
186 |
+
&& ( $not_launch_status || $this->launch_ok() )
|
187 |
+
) {
|
188 |
+
return true;
|
189 |
+
}
|
190 |
+
return false;
|
191 |
+
}
|
192 |
+
|
193 |
+
public function get_imgopt_host()
|
194 |
+
{
|
195 |
+
static $imgopt_host = null;
|
196 |
+
|
197 |
+
if ( null === $imgopt_host ) {
|
198 |
+
$imgopt_host = 'https://cdn.shortpixel.ai/';
|
199 |
+
$avail_imgopt = $this->options['availabilities']['extra_imgopt'];
|
200 |
+
if ( ! empty( $avail_imgopt ) && array_key_exists( 'hosts', $avail_imgopt ) && is_array( $avail_imgopt['hosts'] ) ) {
|
201 |
+
$imgopt_host = array_rand( array_flip( $avail_imgopt['hosts'] ) );
|
202 |
+
}
|
203 |
+
}
|
204 |
+
|
205 |
+
return $imgopt_host;
|
206 |
+
}
|
207 |
+
|
208 |
+
public static function get_imgopt_host_wrapper()
|
209 |
+
{
|
210 |
+
// needed for CI tests.
|
211 |
+
$self = new self();
|
212 |
+
return $self->get_imgopt_host();
|
213 |
+
}
|
214 |
+
|
215 |
+
public static function get_service_url_suffix()
|
216 |
+
{
|
217 |
+
$suffix = '/af/GWRGFLW109483/' . AUTOPTIMIZE_SITE_DOMAIN;
|
218 |
+
|
219 |
+
return $suffix;
|
220 |
+
}
|
221 |
+
|
222 |
+
public function get_img_quality_string()
|
223 |
+
{
|
224 |
+
static $quality = null;
|
225 |
+
|
226 |
+
if ( null === $quality ) {
|
227 |
+
$q_array = $this->get_img_quality_array();
|
228 |
+
$setting = $this->get_img_quality_setting();
|
229 |
+
$quality = apply_filters(
|
230 |
+
'autoptimize_filter_imgopt_quality',
|
231 |
+
'q_' . $q_array[ $setting ]
|
232 |
+
);
|
233 |
+
}
|
234 |
+
|
235 |
+
return $quality;
|
236 |
+
}
|
237 |
+
|
238 |
+
public function get_img_quality_array()
|
239 |
+
{
|
240 |
+
static $map = null;
|
241 |
+
|
242 |
+
if ( null === $map ) {
|
243 |
+
$map = array(
|
244 |
+
'1' => 'lossy',
|
245 |
+
'2' => 'glossy',
|
246 |
+
'3' => 'lossless',
|
247 |
+
);
|
248 |
+
$map = apply_filters(
|
249 |
+
'autoptimize_filter_imgopt_quality_array',
|
250 |
+
$map
|
251 |
+
);
|
252 |
+
}
|
253 |
+
|
254 |
+
return $map;
|
255 |
+
}
|
256 |
+
|
257 |
+
public function get_img_quality_setting()
|
258 |
+
{
|
259 |
+
static $q = null;
|
260 |
+
|
261 |
+
if ( null === $q ) {
|
262 |
+
if ( is_array( $this->options ) && array_key_exists( 'autoptimize_imgopt_select_field_2', $this->options ) ) {
|
263 |
+
$setting = $this->options['autoptimize_imgopt_select_field_2'];
|
264 |
+
}
|
265 |
+
|
266 |
+
if ( ! isset( $setting ) || empty( $setting ) || ( '1' !== $setting && '3' !== $setting ) ) {
|
267 |
+
// default image opt. value is 2 ("glossy").
|
268 |
+
$q = '2';
|
269 |
+
} else {
|
270 |
+
$q = $setting;
|
271 |
+
}
|
272 |
+
}
|
273 |
+
|
274 |
+
return $q;
|
275 |
+
}
|
276 |
+
|
277 |
+
public function filter_preconnect_imgopt_url( array $in )
|
278 |
+
{
|
279 |
+
$url_parts = parse_url( $this->get_imgopt_base_url() );
|
280 |
+
$in[] = $url_parts['scheme'] . '://' . $url_parts['host'];
|
281 |
+
|
282 |
+
return $in;
|
283 |
+
}
|
284 |
+
|
285 |
+
/**
|
286 |
+
* Makes sure given url contains the full scheme and hostname
|
287 |
+
* in case they're not present already.
|
288 |
+
*
|
289 |
+
* @param string $in Image url to normalize.
|
290 |
+
*
|
291 |
+
* @return string
|
292 |
+
*/
|
293 |
+
private function normalize_img_url( $in )
|
294 |
+
{
|
295 |
+
// Only parse the site url once.
|
296 |
+
static $parsed_site_url = null;
|
297 |
+
if ( null === $parsed_site_url ) {
|
298 |
+
$parsed_site_url = parse_url( site_url() );
|
299 |
+
}
|
300 |
+
|
301 |
+
// get CDN domain once.
|
302 |
+
static $cdn_domain = null;
|
303 |
+
if ( is_null( $cdn_domain ) ) {
|
304 |
+
$cdn_url = apply_filters( 'autoptimize_filter_base_cdnurl', get_option( 'autoptimize_cdn_url', '' ) );
|
305 |
+
if ( ! empty( $cdn_url ) ) {
|
306 |
+
$cdn_domain = parse_url( $cdn_url, PHP_URL_HOST );
|
307 |
+
} else {
|
308 |
+
$cdn_domain = '';
|
309 |
+
}
|
310 |
+
}
|
311 |
+
|
312 |
+
/**
|
313 |
+
* This method gets called a lot, often for identical urls it seems.
|
314 |
+
* `filter_optimize_css_images()` calls us, uses the resulting url and
|
315 |
+
* gives it to `can_optimize_image()`, and if that returns trueish
|
316 |
+
* then `build_imgopt_url()` is called (which, again, calls this method).
|
317 |
+
* Until we dig deeper into whether this all must really happen that
|
318 |
+
* way, having an internal cache here helps (to avoid doing repeated
|
319 |
+
* identical string operations).
|
320 |
+
*/
|
321 |
+
static $cache = null;
|
322 |
+
if ( null === $cache ) {
|
323 |
+
$cache = array();
|
324 |
+
}
|
325 |
+
|
326 |
+
// Do the work on cache miss only.
|
327 |
+
if ( ! isset( $cache[ $in ] ) ) {
|
328 |
+
// Default to what was given to us.
|
329 |
+
$result = $in;
|
330 |
+
if ( autoptimizeUtils::is_protocol_relative( $in ) ) {
|
331 |
+
$result = $parsed_site_url['scheme'] . ':' . $in;
|
332 |
+
} elseif ( 0 === strpos( $in, '/' ) ) {
|
333 |
+
// Root-relative...
|
334 |
+
$result = $parsed_site_url['scheme'] . '://' . $parsed_site_url['host'];
|
335 |
+
// Add the path for subfolder installs.
|
336 |
+
if ( isset( $parsed_site_url['path'] ) ) {
|
337 |
+
$result .= $parsed_site_url['path'];
|
338 |
+
}
|
339 |
+
$result .= $in;
|
340 |
+
} elseif ( ! empty( $cdn_domain ) && strpos( $in, $cdn_domain ) !== 0 ) {
|
341 |
+
$result = str_replace( $cdn_domain, $parsed_site_url['host'], $in );
|
342 |
+
}
|
343 |
+
|
344 |
+
$result = apply_filters( 'autoptimize_filter_imgopt_normalized_url', $result );
|
345 |
+
|
346 |
+
// Store in cache.
|
347 |
+
$cache[ $in ] = $result;
|
348 |
+
}
|
349 |
+
|
350 |
+
return $cache[ $in ];
|
351 |
+
}
|
352 |
+
|
353 |
+
public function filter_optimize_css_images( $in )
|
354 |
+
{
|
355 |
+
$in = $this->normalize_img_url( $in );
|
356 |
+
|
357 |
+
if ( $this->can_optimize_image( $in ) ) {
|
358 |
+
return $this->build_imgopt_url( $in, '', '' );
|
359 |
+
} else {
|
360 |
+
return $in;
|
361 |
+
}
|
362 |
+
}
|
363 |
+
|
364 |
+
private function get_imgopt_base_url()
|
365 |
+
{
|
366 |
+
static $imgopt_base_url = null;
|
367 |
+
|
368 |
+
if ( null === $imgopt_base_url ) {
|
369 |
+
$imgopt_host = $this->get_imgopt_host();
|
370 |
+
$quality = $this->get_img_quality_string();
|
371 |
+
$ret_val = apply_filters( 'autoptimize_filter_imgopt_wait', 'ret_img' ); // values: ret_wait, ret_img, ret_json, ret_blank.
|
372 |
+
$imgopt_base_url = $imgopt_host . 'client/' . $quality . ',' . $ret_val;
|
373 |
+
$imgopt_base_url = apply_filters( 'autoptimize_filter_imgopt_base_url', $imgopt_base_url );
|
374 |
+
}
|
375 |
+
|
376 |
+
return $imgopt_base_url;
|
377 |
+
}
|
378 |
+
|
379 |
+
private function can_optimize_image( $url )
|
380 |
+
{
|
381 |
+
static $cdn_url = null;
|
382 |
+
static $nopti_images = null;
|
383 |
+
|
384 |
+
if ( null === $cdn_url ) {
|
385 |
+
$cdn_url = apply_filters(
|
386 |
+
'autoptimize_filter_base_cdnurl',
|
387 |
+
get_option( 'autoptimize_cdn_url', '' )
|
388 |
+
);
|
389 |
+
}
|
390 |
+
|
391 |
+
if ( null === $nopti_images ) {
|
392 |
+
$nopti_images = apply_filters( 'autoptimize_filter_imgopt_noptimize', '' );
|
393 |
+
}
|
394 |
+
|
395 |
+
$site_host = AUTOPTIMIZE_SITE_DOMAIN;
|
396 |
+
$url = $this->normalize_img_url( $url );
|
397 |
+
$url_parsed = parse_url( $url );
|
398 |
+
|
399 |
+
if ( array_key_exists( 'host', $url_parsed ) && $url_parsed['host'] !== $site_host && empty( $cdn_url ) ) {
|
400 |
+
return false;
|
401 |
+
} elseif ( ! empty( $cdn_url ) && strpos( $url, $cdn_url ) === false && array_key_exists( 'host', $url_parsed ) && $url_parsed['host'] !== $site_host ) {
|
402 |
+
return false;
|
403 |
+
} elseif ( strpos( $url, '.php' ) !== false ) {
|
404 |
+
return false;
|
405 |
+
} elseif ( str_ireplace( array( '.png', '.gif', '.jpg', '.jpeg', '.webp' ), '', $url_parsed['path'] ) === $url_parsed['path'] ) {
|
406 |
+
// fixme: better check against end of string.
|
407 |
+
return false;
|
408 |
+
} elseif ( ! empty( $nopti_images ) ) {
|
409 |
+
$nopti_images_array = array_filter( array_map( 'trim', explode( ',', $nopti_images ) ) );
|
410 |
+
foreach ( $nopti_images_array as $nopti_image ) {
|
411 |
+
if ( strpos( $url, $nopti_image ) !== false ) {
|
412 |
+
return false;
|
413 |
+
}
|
414 |
+
}
|
415 |
+
}
|
416 |
+
return true;
|
417 |
+
}
|
418 |
+
|
419 |
+
private function build_imgopt_url( $orig_url, $width = 0, $height = 0 )
|
420 |
+
{
|
421 |
+
// sanitize width and height.
|
422 |
+
if ( strpos( $width, '%' ) !== false ) {
|
423 |
+
$width = 0;
|
424 |
+
}
|
425 |
+
if ( strpos( $height, '%' ) !== false ) {
|
426 |
+
$height = 0;
|
427 |
+
}
|
428 |
+
$width = (int) $width;
|
429 |
+
$height = (int) $height;
|
430 |
+
|
431 |
+
$filtered_url = apply_filters(
|
432 |
+
'autoptimize_filter_imgopt_build_url',
|
433 |
+
$orig_url,
|
434 |
+
$width,
|
435 |
+
$height
|
436 |
+
);
|
437 |
+
|
438 |
+
// If filter modified the url, return that.
|
439 |
+
if ( $filtered_url !== $orig_url ) {
|
440 |
+
return $filtered_url;
|
441 |
+
}
|
442 |
+
|
443 |
+
$orig_url = $this->normalize_img_url( $orig_url );
|
444 |
+
$imgopt_base_url = $this->get_imgopt_base_url();
|
445 |
+
$imgopt_size = '';
|
446 |
+
|
447 |
+
if ( $width && 0 !== $width ) {
|
448 |
+
$imgopt_size = ',w_' . $width;
|
449 |
+
}
|
450 |
+
|
451 |
+
if ( $height && 0 !== $height ) {
|
452 |
+
$imgopt_size .= ',h_' . $height;
|
453 |
+
}
|
454 |
+
|
455 |
+
$url = $imgopt_base_url . $imgopt_size . '/' . $orig_url;
|
456 |
+
|
457 |
+
return $url;
|
458 |
+
}
|
459 |
+
|
460 |
+
public function replace_data_thumbs( $matches )
|
461 |
+
{
|
462 |
+
return $this->replace_img_callback( $matches, 150, 150 );
|
463 |
+
}
|
464 |
+
|
465 |
+
public function replace_img_callback( $matches, $width = 0, $height = 0 )
|
466 |
+
{
|
467 |
+
if ( $this->can_optimize_image( $matches[1] ) ) {
|
468 |
+
return str_replace( $matches[1], $this->build_imgopt_url( $matches[1], $width, $height ), $matches[0] );
|
469 |
+
} else {
|
470 |
+
return $matches[0];
|
471 |
+
}
|
472 |
+
}
|
473 |
+
|
474 |
+
public function filter_optimize_images( $in )
|
475 |
+
{
|
476 |
+
/*
|
477 |
+
* potential future functional improvements:
|
478 |
+
*
|
479 |
+
* picture element.
|
480 |
+
* filter for critical CSS.
|
481 |
+
*/
|
482 |
+
$to_replace = array();
|
483 |
+
|
484 |
+
// hide noscript tags to avoid nesting noscript tags (as lazyloaded images add noscript).
|
485 |
+
if ( $this->should_lazyload() ) {
|
486 |
+
$in = autoptimizeBase::replace_contents_with_marker_if_exists(
|
487 |
+
'NOSCRIPT',
|
488 |
+
'<noscript',
|
489 |
+
'#<noscript.*?<\/noscript>#is',
|
490 |
+
$in
|
491 |
+
);
|
492 |
+
}
|
493 |
+
|
494 |
+
// extract img tags.
|
495 |
+
if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $in, $matches ) ) {
|
496 |
+
foreach ( $matches[0] as $tag ) {
|
497 |
+
$orig_tag = $tag;
|
498 |
+
$imgopt_w = '';
|
499 |
+
$imgopt_h = '';
|
500 |
+
|
501 |
+
// first do (data-)srcsets.
|
502 |
+
if ( preg_match_all( '#srcset=("|\')(.*)("|\')#Usmi', $tag, $allsrcsets, PREG_SET_ORDER ) ) {
|
503 |
+
foreach ( $allsrcsets as $srcset ) {
|
504 |
+
$srcset = $srcset[2];
|
505 |
+
$srcsets = explode( ',', $srcset );
|
506 |
+
foreach ( $srcsets as $indiv_srcset ) {
|
507 |
+
$indiv_srcset_parts = explode( ' ', trim( $indiv_srcset ) );
|
508 |
+
if ( isset( $indiv_srcset_parts[1] ) && rtrim( $indiv_srcset_parts[1], 'w' ) !== $indiv_srcset_parts[1] ) {
|
509 |
+
$imgopt_w = rtrim( $indiv_srcset_parts[1], 'w' );
|
510 |
+
}
|
511 |
+
if ( $this->can_optimize_image( $indiv_srcset_parts[0] ) ) {
|
512 |
+
$imgopt_url = $this->build_imgopt_url( $indiv_srcset_parts[0], $imgopt_w, '' );
|
513 |
+
$tag = str_replace( $indiv_srcset_parts[0], $imgopt_url, $tag );
|
514 |
+
}
|
515 |
+
}
|
516 |
+
}
|
517 |
+
}
|
518 |
+
|
519 |
+
// proceed with img src.
|
520 |
+
// get width and height and add to $imgopt_size.
|
521 |
+
$_get_size = $this->get_size_from_tag( $tag );
|
522 |
+
$imgopt_w = $_get_size['width'];
|
523 |
+
$imgopt_h = $_get_size['height'];
|
524 |
+
|
525 |
+
// then start replacing images src.
|
526 |
+
if ( preg_match_all( '#src=(?:"|\')(?!data)(.*)(?:"|\')#Usmi', $tag, $urls, PREG_SET_ORDER ) ) {
|
527 |
+
foreach ( $urls as $url ) {
|
528 |
+
$full_src_orig = $url[0];
|
529 |
+
$url = $url[1];
|
530 |
+
if ( $this->can_optimize_image( $url ) ) {
|
531 |
+
$imgopt_url = $this->build_imgopt_url( $url, $imgopt_w, $imgopt_h );
|
532 |
+
$full_imgopt_src = str_replace( $url, $imgopt_url, $full_src_orig );
|
533 |
+
$tag = str_replace( $full_src_orig, $full_imgopt_src, $tag );
|
534 |
+
}
|
535 |
+
}
|
536 |
+
}
|
537 |
+
|
538 |
+
// do lazyload stuff.
|
539 |
+
if ( $this->should_lazyload() && str_ireplace( $this->get_lazyload_exclusions(), '', $tag ) === $tag ) {
|
540 |
+
$noscript_tag = '<noscript>' . $tag . '</noscript>';
|
541 |
+
$tag = str_replace( 'srcset=', 'data-srcset=', $tag );
|
542 |
+
|
543 |
+
// add lazyload class.
|
544 |
+
$tag = $this->inject_classes_in_tag( $tag, 'lazyload ' );
|
545 |
+
|
546 |
+
// set placeholder.
|
547 |
+
if ( strpos( $url, $this->get_imgopt_host() ) === 0 ) {
|
548 |
+
// if all img src have been replaced during srcset, we have to extract the
|
549 |
+
// origin url from the imgopt one to be able to set a lqip placeholder.
|
550 |
+
$_url = substr( $url, strpos( $url, '/http' ) + 1 );
|
551 |
+
} else {
|
552 |
+
$_url = $url;
|
553 |
+
}
|
554 |
+
if ( $this->can_optimize_image( $_url ) && apply_filters( 'autoptimize_filter_imgopt_lazyload_dolqip', true ) ) {
|
555 |
+
$placeholder = $this->get_imgopt_host() . 'client/q_lqip,ret_wait,w_' . $imgopt_w . ',h_' . $imgopt_h . '/' . $_url;
|
556 |
+
} else {
|
557 |
+
$placeholder = $this->get_default_lazyload_placeholder( $imgopt_w, $imgopt_h );
|
558 |
+
}
|
559 |
+
$placeholder = ' src=\'' . apply_filters( 'autoptimize_filter_imgopt_lazyload_placeholder', $placeholder );
|
560 |
+
|
561 |
+
// add min-heigth off by default as it can deform images, can be enabled with filter.
|
562 |
+
$min_height = '';
|
563 |
+
if ( apply_filters( 'autoptimize_filter_imgopt_lazyload_addminheight', false ) ) {
|
564 |
+
$min_height = ' style="min-height:' . $imgopt_h . 'px;"';
|
565 |
+
}
|
566 |
+
|
567 |
+
// add noscript & placeholder.
|
568 |
+
$tag = $noscript_tag . str_replace( ' src=', $min_height . $placeholder . '\' data-src=', $tag );
|
569 |
+
$tag = apply_filters( 'autoptimize_filter_imgopt_lazyloaded_img', $tag );
|
570 |
+
}
|
571 |
+
|
572 |
+
// add tag to array for later replacement.
|
573 |
+
if ( $tag !== $orig_tag ) {
|
574 |
+
$to_replace[ $orig_tag ] = $tag;
|
575 |
+
}
|
576 |
+
}
|
577 |
+
}
|
578 |
+
|
579 |
+
// and replace all.
|
580 |
+
$out = str_replace( array_keys( $to_replace ), array_values( $to_replace ), $in );
|
581 |
+
|
582 |
+
// img thumbnails in e.g. woocommerce.
|
583 |
+
if ( strpos( $out, 'data-thumb' ) !== false && apply_filters( 'autoptimize_filter_imgopt_datathumbs', true ) ) {
|
584 |
+
$out = preg_replace_callback(
|
585 |
+
'/\<div(?:[^>]?)\sdata-thumb\=(?:\"|\')(.+?)(?:\"|\')(?:[^>]*)?\>/s',
|
586 |
+
array( $this, 'replace_data_thumbs' ),
|
587 |
+
$out
|
588 |
+
);
|
589 |
+
}
|
590 |
+
|
591 |
+
// background-image in inline style.
|
592 |
+
if ( strpos( $out, 'background-image:' ) !== false && apply_filters( 'autoptimize_filter_imgopt_backgroundimages', true ) ) {
|
593 |
+
$out = preg_replace_callback(
|
594 |
+
'/style=(?:"|\').*?background-image:\s?url\((?:"|\')?([^"\')]*)(?:"|\')?\)/',
|
595 |
+
array( $this, 'replace_img_callback' ),
|
596 |
+
$out
|
597 |
+
);
|
598 |
+
}
|
599 |
+
|
600 |
+
// and restore noscript tags if these were hidden for lazyload purposes.
|
601 |
+
if ( $this->should_lazyload() ) {
|
602 |
+
$out = autoptimizeBase::restore_marked_content(
|
603 |
+
'NOSCRIPT',
|
604 |
+
$out
|
605 |
+
);
|
606 |
+
}
|
607 |
+
|
608 |
+
return $out;
|
609 |
+
}
|
610 |
+
|
611 |
+
public function get_size_from_tag( $tag ) {
|
612 |
+
// reusable function to extract widht and height from an image tag
|
613 |
+
// enforcing a filterable maximum width and height (default 4999X4999).
|
614 |
+
$width = '';
|
615 |
+
$height = '';
|
616 |
+
|
617 |
+
if ( preg_match( '#width=("|\')(.*)("|\')#Usmi', $tag, $_width ) ) {
|
618 |
+
if ( strpos( $_width[2], '%' ) === false ) {
|
619 |
+
$width = (int) $_width[2];
|
620 |
+
}
|
621 |
+
}
|
622 |
+
if ( preg_match( '#height=("|\')(.*)("|\')#Usmi', $tag, $_height ) ) {
|
623 |
+
if ( strpos( $_height[2], '%' ) === false ) {
|
624 |
+
$height = (int) $_height[2];
|
625 |
+
}
|
626 |
+
}
|
627 |
+
|
628 |
+
// check for and enforce (filterable) max sizes.
|
629 |
+
$_max_width = apply_filters( 'autoptimize_filter_imgopt_max_width', 4999 );
|
630 |
+
if ( $width > $_max_width ) {
|
631 |
+
$_width = $_max_width;
|
632 |
+
$height = $_width / $width * $height;
|
633 |
+
$width = $_width;
|
634 |
+
}
|
635 |
+
$_max_height = apply_filters( 'autoptimize_filter_imgopt_max_height', 4999 );
|
636 |
+
if ( $height > $_max_height ) {
|
637 |
+
$_height = $_max_height;
|
638 |
+
$width = $_height / $height * $width;
|
639 |
+
$height = $_height;
|
640 |
+
}
|
641 |
+
|
642 |
+
return array(
|
643 |
+
'width' => $width,
|
644 |
+
'height' => $height,
|
645 |
+
);
|
646 |
+
}
|
647 |
+
|
648 |
+
/**
|
649 |
+
* Lazyload functions
|
650 |
+
*/
|
651 |
+
public function should_lazyload() {
|
652 |
+
if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_3'] ) ) {
|
653 |
+
$lazyload_return = true;
|
654 |
+
} else {
|
655 |
+
$lazyload_return = false;
|
656 |
+
}
|
657 |
+
|
658 |
+
return $lazyload_return;
|
659 |
+
}
|
660 |
+
|
661 |
+
public static function should_lazyload_wrapper() {
|
662 |
+
// needed in autoptimizeMain.php.
|
663 |
+
$self = new self();
|
664 |
+
return $self->should_lazyload();
|
665 |
+
}
|
666 |
+
|
667 |
+
public function filter_lazyload_images( $in )
|
668 |
+
{
|
669 |
+
// only used is image optimization is NOT active but lazyload is.
|
670 |
+
$to_replace = array();
|
671 |
+
|
672 |
+
// hide noscript tags to avoid nesting noscript tags (as lazyloaded images add noscript).
|
673 |
+
$out = autoptimizeBase::replace_contents_with_marker_if_exists(
|
674 |
+
'NOSCRIPT',
|
675 |
+
'<noscript',
|
676 |
+
'#<noscript.*?<\/noscript>#is',
|
677 |
+
$in
|
678 |
+
);
|
679 |
+
|
680 |
+
// extract img tags and add lazyload attribs.
|
681 |
+
if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $out, $matches ) ) {
|
682 |
+
foreach ( $matches[0] as $tag ) {
|
683 |
+
$to_replace[ $tag ] = $this->add_lazyload( $tag );
|
684 |
+
}
|
685 |
+
$out = str_replace( array_keys( $to_replace ), array_values( $to_replace ), $out );
|
686 |
+
}
|
687 |
+
|
688 |
+
// restore noscript tags.
|
689 |
+
$out = autoptimizeBase::restore_marked_content(
|
690 |
+
'NOSCRIPT',
|
691 |
+
$out
|
692 |
+
);
|
693 |
+
|
694 |
+
return $out;
|
695 |
+
}
|
696 |
+
|
697 |
+
public function add_lazyload( $tag ) {
|
698 |
+
// adds actual lazyload-attributes to an image node.
|
699 |
+
if ( str_ireplace( $this->get_lazyload_exclusions(), '', $tag ) === $tag ) {
|
700 |
+
// store original tag for use in noscript version.
|
701 |
+
$noscript_tag = '<noscript>' . $tag . '</noscript>';
|
702 |
+
|
703 |
+
// insert lazyload class.
|
704 |
+
$tag = $this->inject_classes_in_tag( $tag, 'lazyload ' );
|
705 |
+
|
706 |
+
// get image width & heigth for placeholder fun (and to prevent content reflow).
|
707 |
+
$_get_size = $this->get_size_from_tag( $tag );
|
708 |
+
$width = $_get_size['width'];
|
709 |
+
$height = $_get_size['height'];
|
710 |
+
if ( false === $width ) {
|
711 |
+
$widht = 210; // default width for SVG placeholder.
|
712 |
+
}
|
713 |
+
if ( false === $height ) {
|
714 |
+
$heigth = $width / 3 * 2; // if no height, base it on width using the 3/2 aspect ratio.
|
715 |
+
}
|
716 |
+
|
717 |
+
// insert the actual lazyload stuff.
|
718 |
+
// see https://css-tricks.com/preventing-content-reflow-from-lazy-loaded-images/ for great read on why we're using empty svg's.
|
719 |
+
$placeholder = apply_filters( 'autoptimize_filter_imgopt_lazyload_placeholder', $this->get_default_lazyload_placeholder( $width, $height ) );
|
720 |
+
$tag = str_replace( ' src=', ' src=\'' . $placeholder . '\' data-src=', $tag );
|
721 |
+
$tag = str_replace( ' srcset=', ' data-srcset=', $tag );
|
722 |
+
|
723 |
+
// add the noscript-tag from earlier.
|
724 |
+
$tag = $noscript_tag . $tag;
|
725 |
+
$tag = apply_filters( 'autoptimize_filter_imgopt_lazyloaded_img', $tag );
|
726 |
+
}
|
727 |
+
|
728 |
+
return $tag;
|
729 |
+
}
|
730 |
+
|
731 |
+
public function add_lazyload_js_footer() {
|
732 |
+
// The JS will by default be excluded form autoptimization but this can be changed with a filter.
|
733 |
+
$noptimize_flag = '';
|
734 |
+
if ( apply_filters( 'autoptimize_filter_imgopt_lazyload_js_noptimize', true ) ) {
|
735 |
+
$noptimize_flag = ' data-noptimize="1"';
|
736 |
+
}
|
737 |
+
|
738 |
+
// Adds lazyload CSS & JS to footer, using echo because wp_enqueue_script seems not to support pushing attributes (async).
|
739 |
+
echo apply_filters( 'autoptimize_filter_imgopt_lazyload_cssoutput', '<style>.lazyload,.lazyloading{opacity:0;}.lazyloaded{opacity:1;transition:opacity 300ms;}</style><noscript><style>.lazyload{display:none;}</style></noscript>' );
|
740 |
+
echo apply_filters( 'autoptimize_filter_imgopt_lazyload_jsconfig', '<script' . $noptimize_flag . '>window.lazySizesConfig=window.lazySizesConfig||{};window.lazySizesConfig.loadMode=1;</script>' );
|
741 |
+
echo '<script async' . $noptimize_flag . ' src=\'' . plugins_url( 'external/js/lazysizes.min.js', __FILE__ ) . '\'></script>';
|
742 |
+
|
743 |
+
// And add webp detection and loading JS.
|
744 |
+
if ( $this->should_webp() ) {
|
745 |
+
$_webp_detect = "function c_webp(A){var n=new Image;n.onload=function(){var e=0<n.width&&0<n.height;A(e)},n.onerror=function(){A(!1)},n.src='data:image/webp;base64,UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA=='}function s_webp(e){window.supportsWebP=e}c_webp(s_webp);";
|
746 |
+
$_webp_load = "document.addEventListener('lazybeforeunveil',function({target:c}){supportsWebP&&['data-src','data-srcset'].forEach(function(a){attr=c.getAttribute(a),null!==attr&&c.setAttribute(a,attr.replace(/\/client\//,'/client/to_webp,'))})});";
|
747 |
+
echo apply_filters( 'autoptimize_filter_imgopt_webp_js', '<script' . $noptimize_flag . '>' . $_webp_detect . $_webp_load . '</script>' );
|
748 |
+
}
|
749 |
+
}
|
750 |
+
|
751 |
+
public function get_lazyload_exclusions() {
|
752 |
+
// returns array of strings that if found in an <img tag will stop the img from being lazy-loaded.
|
753 |
+
static $exclude_lazyload_array = null;
|
754 |
+
|
755 |
+
if ( null === $exclude_lazyload_array ) {
|
756 |
+
$options = $this->options;
|
757 |
+
|
758 |
+
// set default exclusions.
|
759 |
+
$exclude_lazyload_array = array( 'skip-lazy', 'data-no-lazy', 'notlazy', 'data-src', 'data-srcset' );
|
760 |
+
|
761 |
+
// add from setting.
|
762 |
+
if ( array_key_exists( 'autoptimize_imgopt_text_field_5', $options ) ) {
|
763 |
+
$exclude_lazyload_option = $options['autoptimize_imgopt_text_field_5'];
|
764 |
+
if ( ! empty( $exclude_lazyload_option ) ) {
|
765 |
+
$exclude_lazyload_array = array_merge( $exclude_lazyload_array, array_filter( array_map( 'trim', explode( ',', $options['autoptimize_imgopt_text_field_5'] ) ) ) );
|
766 |
+
}
|
767 |
+
}
|
768 |
+
|
769 |
+
// and filter for developer-initiated changes.
|
770 |
+
$exclude_lazyload_array = apply_filters( 'autoptimize_filter_imgopt_lazyload_exclude_array', $exclude_lazyload_array );
|
771 |
+
}
|
772 |
+
|
773 |
+
return $exclude_lazyload_array;
|
774 |
+
}
|
775 |
+
|
776 |
+
public function inject_classes_in_tag( $tag, $target_class ) {
|
777 |
+
if ( strpos( $tag, 'class=' ) !== false ) {
|
778 |
+
$tag = preg_replace( '/(\sclass\s?=\s?("|\'))/', '$1' . $target_class, $tag );
|
779 |
+
} else {
|
780 |
+
$tag = str_replace( '<img ', '<img class="' . trim( $target_class ) . '" ', $tag );
|
781 |
+
}
|
782 |
+
|
783 |
+
return $tag;
|
784 |
+
}
|
785 |
+
|
786 |
+
public function get_default_lazyload_placeholder( $imgopt_w, $imgopt_h ) {
|
787 |
+
return 'data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%20' . $imgopt_w . '%20' . $imgopt_h . '%22%3E%3C/svg%3E';
|
788 |
+
}
|
789 |
+
|
790 |
+
public function should_webp() {
|
791 |
+
static $webp_return = null;
|
792 |
+
|
793 |
+
if ( is_null( $webp_return ) ) {
|
794 |
+
// webp only works if imgopt and lazyload are also active.
|
795 |
+
if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_4'] ) && ! empty( $this->options['autoptimize_imgopt_checkbox_field_3'] ) && $this->imgopt_active() ) {
|
796 |
+
$webp_return = true;
|
797 |
+
} else {
|
798 |
+
$webp_return = false;
|
799 |
+
}
|
800 |
+
}
|
801 |
+
|
802 |
+
return $webp_return;
|
803 |
+
}
|
804 |
+
|
805 |
+
/**
|
806 |
+
* Admin page logic and related functions below.
|
807 |
+
*/
|
808 |
+
public function imgopt_admin_menu()
|
809 |
+
{
|
810 |
+
add_submenu_page(
|
811 |
+
null,
|
812 |
+
'autoptimize_imgopt',
|
813 |
+
'autoptimize_imgopt',
|
814 |
+
'manage_options',
|
815 |
+
'autoptimize_imgopt',
|
816 |
+
array( $this, 'imgopt_options_page' )
|
817 |
+
);
|
818 |
+
register_setting( 'autoptimize_imgopt_settings', 'autoptimize_imgopt_settings' );
|
819 |
+
}
|
820 |
+
|
821 |
+
public function add_imgopt_tab( $in )
|
822 |
+
{
|
823 |
+
$in = array_merge( $in, array( 'autoptimize_imgopt' => __( 'Images', 'autoptimize' ) ) );
|
824 |
+
|
825 |
+
return $in;
|
826 |
+
}
|
827 |
+
|
828 |
+
public function imgopt_options_page()
|
829 |
+
{
|
830 |
+
// Check querystring for "refreshCacheChecker" and call cachechecker if so.
|
831 |
+
if ( array_key_exists( 'refreshImgProvStats', $_GET ) && 1 == $_GET['refreshImgProvStats'] ) {
|
832 |
+
$this->query_img_provider_stats();
|
833 |
+
}
|
834 |
+
|
835 |
+
$options = $this->fetch_options();
|
836 |
+
$sp_url_suffix = $this->get_service_url_suffix();
|
837 |
+
?>
|
838 |
+
<style>
|
839 |
+
#ao_settings_form {background: white;border: 1px solid #ccc;padding: 1px 15px;margin: 15px 10px 10px 0;}
|
840 |
+
#ao_settings_form .form-table th {font-weight: normal;}
|
841 |
+
#autoptimize_imgopt_descr{font-size: 120%;}
|
842 |
+
</style>
|
843 |
+
<div class="wrap">
|
844 |
+
<h1><?php _e( 'Autoptimize Settings', 'autoptimize' ); ?></h1>
|
845 |
+
<?php echo autoptimizeConfig::ao_admin_tabs(); ?>
|
846 |
+
<?php if ( 'down' === $options['availabilities']['extra_imgopt']['status'] ) { ?>
|
847 |
+
<div class="notice-warning notice"><p>
|
848 |
+
<?php
|
849 |
+
// translators: "Autoptimize support forum" will appear in a "a href".
|
850 |
+
echo sprintf( __( 'The image optimization service is currently down, image optimization will be skipped until further notice. Check the %1$sAutoptimize support forum%2$s for more info.', 'autoptimize' ), '<a href="https://wordpress.org/support/plugin/autoptimize/" target="_blank">', '</a>' );
|
851 |
+
?>
|
852 |
+
</p></div>
|
853 |
+
<?php } ?>
|
854 |
+
|
855 |
+
<?php if ( 'launch' === $options['availabilities']['extra_imgopt']['status'] && ! autoptimizeImages::instance()->launch_ok() ) { ?>
|
856 |
+
<div class="notice-warning notice"><p>
|
857 |
+
<?php _e( 'The image optimization service is launching, but not yet available for this domain, it should become available in the next couple of days.', 'autoptimize' ); ?>
|
858 |
+
</p></div>
|
859 |
+
<?php } ?>
|
860 |
+
|
861 |
+
<?php if ( class_exists( 'Jetpack' ) && method_exists( 'Jetpack', 'get_active_modules' ) && in_array( 'photon', Jetpack::get_active_modules() ) ) { ?>
|
862 |
+
<div class="notice-warning notice"><p>
|
863 |
+
<?php
|
864 |
+
// translators: "disable Jetpack's site accelerator for images" will appear in a "a href" linking to the jetpack settings page.
|
865 |
+
echo sprintf( __( 'Please %1$sdisable Jetpack\'s site accelerator for images%2$s to be able to use Autoptomize\'s advanced image optimization features below.', 'autoptimize' ), '<a href="admin.php?page=jetpack#/settings">', '</a>' );
|
866 |
+
?>
|
867 |
+
</p></div>
|
868 |
+
<?php } ?>
|
869 |
+
<form id='ao_settings_form' action='options.php' method='post'>
|
870 |
+
<?php settings_fields( 'autoptimize_imgopt_settings' ); ?>
|
871 |
+
<h2><?php _e( 'Image optimization', 'autoptimize' ); ?></h2>
|
872 |
+
<span id='autoptimize_imgopt_descr'><?php _e( 'Make your site significantly faster by just ticking a couple of checkboxes to optimize and lazy load your images, WebP support included!', 'autoptimize' ); ?></span>
|
873 |
+
<table class="form-table">
|
874 |
+
<tr>
|
875 |
+
<th scope="row"><?php _e( 'Optimize Images', 'autoptimize' ); ?></th>
|
876 |
+
<td>
|
877 |
+
<label><input id='autoptimize_imgopt_checkbox' type='checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_1]' <?php if ( ! empty( $options['autoptimize_imgopt_checkbox_field_1'] ) && '1' === $options['autoptimize_imgopt_checkbox_field_1'] ) { echo 'checked="checked"'; } ?> value='1'><?php _e( 'Optimize images on the fly and serve them from Shortpixel\'s global CDN.', 'autoptimize' ); ?></label>
|
878 |
+
<?php
|
879 |
+
// show shortpixel status.
|
880 |
+
$_notice = autoptimizeImages::instance()->get_status_notice();
|
881 |
+
if ( $_notice ) {
|
882 |
+
switch ( $_notice['status'] ) {
|
883 |
+
case 2:
|
884 |
+
$_notice_color = 'green';
|
885 |
+
break;
|
886 |
+
case 1:
|
887 |
+
$_notice_color = 'orange';
|
888 |
+
break;
|
889 |
+
case -1:
|
890 |
+
$_notice_color = 'red';
|
891 |
+
break;
|
892 |
+
case -2:
|
893 |
+
$_notice_color = 'red';
|
894 |
+
break;
|
895 |
+
default:
|
896 |
+
$_notice_color = 'green';
|
897 |
+
}
|
898 |
+
echo apply_filters( 'autoptimize_filter_imgopt_settings_status', '<p><strong><span style="color:' . $_notice_color . ';">' . __( 'Shortpixel status: ', 'autoptimize' ) . '</span></strong>' . $_notice['notice'] . '</p>' );
|
899 |
+
} else {
|
900 |
+
// translators: link points to shortpixel.
|
901 |
+
$upsell_msg_1 = '<p>' . sprintf( __( 'Get more Google love and improve your website\'s loading speed by having the images optimized on the fly (also in the "next-gen" WebP image format) by %1$sShortPixel%2$s and then cached and served fast from Shortpixel\'s global CDN.', 'autoptimize' ), '<a href="https://shortpixel.com/aospai' . $sp_url_suffix . '" target="_blank">', '</a>' );
|
902 |
+
if ( 'launch' === $options['availabilities']['extra_imgopt']['status'] ) {
|
903 |
+
$upsell_msg_2 = __( 'For a limited time only, this service is offered free for all Autoptimize users, <b>don\'t miss the chance to test it</b> and see how much it could improve your site\'s speed.', 'autoptimize' );
|
904 |
+
} else {
|
905 |
+
// translators: link points to shortpixel.
|
906 |
+
$upsell_msg_2 = sprintf( __( '%1$sSign-up now%2$s to receive a 1 000 bonus + 50% more image optimization credits regardless of the traffic used. More image optimizations can be purchased starting with $4.99.', 'autoptimize' ), '<a href="https://shortpixel.com/aospai' . $sp_url_suffix . '" target="_blank">', '</a>' );
|
907 |
+
}
|
908 |
+
echo apply_filters( 'autoptimize_imgopt_imgopt_settings_copy', $upsell_msg_1 . ' ' . $upsell_msg_2 . '</p>' );
|
909 |
+
}
|
910 |
+
// translators: link points to shortpixel FAQ.
|
911 |
+
$faqcopy = sprintf( __( '<strong>Questions</strong>? Have a look at the %1$sShortPixel FAQ%2$s!', 'autoptimize' ), '<strong><a href="https://shortpixel.helpscoutdocs.com/category/60-shortpixel-ai-cdn" target="_blank">', '</strong></a>' );
|
912 |
+
// translators: links points to shortpixel TOS & Privacy Policy.
|
913 |
+
$toscopy = sprintf( __( 'Usage of this feature is subject to Shortpixel\'s %1$sTerms of Use%2$s and %3$sPrivacy policy%4$s.', 'autoptimize' ), '<a href="https://shortpixel.com/tos' . $sp_url_suffix . '" target="_blank">', '</a>', '<a href="https://shortpixel.com/pp' . $sp_url_suffix . '" target="_blank">', '</a>' );
|
914 |
+
echo apply_filters( 'autoptimize_imgopt_imgopt_settings_tos', '<p>' . $faqcopy . ' ' . $toscopy . '</p>' );
|
915 |
+
?>
|
916 |
+
</td>
|
917 |
+
</tr>
|
918 |
+
<tr id='autoptimize_imgopt_quality' <?php if ( ! array_key_exists( 'autoptimize_imgopt_checkbox_field_1', $options ) || ( isset( $options['autoptimize_imgopt_checkbox_field_1'] ) && '1' !== $options['autoptimize_imgopt_checkbox_field_1'] ) ) { echo 'class="hidden"'; } ?>>
|
919 |
+
<th scope="row"><?php _e( 'Image Optimization quality', 'autoptimize' ); ?></th>
|
920 |
+
<td>
|
921 |
+
<label>
|
922 |
+
<select name='autoptimize_imgopt_settings[autoptimize_imgopt_select_field_2]'>
|
923 |
+
<?php
|
924 |
+
$_imgopt_array = autoptimizeImages::instance()->get_img_quality_array();
|
925 |
+
$_imgopt_val = autoptimizeImages::instance()->get_img_quality_setting();
|
926 |
+
|
927 |
+
foreach ( $_imgopt_array as $key => $value ) {
|
928 |
+
echo '<option value="' . $key . '"';
|
929 |
+
if ( $_imgopt_val == $key ) {
|
930 |
+
echo ' selected';
|
931 |
+
}
|
932 |
+
echo '>' . ucfirst( $value ) . '</option>';
|
933 |
+
}
|
934 |
+
echo "\n";
|
935 |
+
?>
|
936 |
+
</select>
|
937 |
+
</label>
|
938 |
+
<p>
|
939 |
+
<?php
|
940 |
+
// translators: link points to shortpixel image test page.
|
941 |
+
echo apply_filters( 'autoptimize_imgopt_imgopt_quality_copy', sprintf( __( 'You can %1$stest compression levels here%2$s.', 'autoptimize' ), '<a href="https://shortpixel.com/oic' . $sp_url_suffix . '" target="_blank">', '</a>' ) );
|
942 |
+
?>
|
943 |
+
</p>
|
944 |
+
</td>
|
945 |
+
</tr>
|
946 |
+
<tr id='autoptimize_imgopt_webp' <?php if ( ! array_key_exists( 'autoptimize_imgopt_checkbox_field_1', $options ) || ( isset( $options['autoptimize_imgopt_checkbox_field_1'] ) && '1' !== $options['autoptimize_imgopt_checkbox_field_1'] ) ) { echo 'class="hidden"'; } ?>>
|
947 |
+
<th scope="row"><?php _e( 'Load WebP in supported browsers?', 'autoptimize' ); ?></th>
|
948 |
+
<td>
|
949 |
+
<label><input type='checkbox' id='autoptimize_imgopt_webp_checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_4]' <?php if ( ! empty( $options['autoptimize_imgopt_checkbox_field_4'] ) && '1' === $options['autoptimize_imgopt_checkbox_field_3'] ) { echo 'checked="checked"'; } ?> value='1'><?php _e( 'Automatically serve "next-gen" WebP image format to any browser that supports it (requires lazy load to be active).', 'autoptimize' ); ?></label>
|
950 |
+
</td>
|
951 |
+
</tr>
|
952 |
+
<tr>
|
953 |
+
<th scope="row"><?php _e( 'Lazy-load images?', 'autoptimize' ); ?></th>
|
954 |
+
<td>
|
955 |
+
<label><input type='checkbox' id='autoptimize_imgopt_lazyload_checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_3]' <?php if ( ! empty( $options['autoptimize_imgopt_checkbox_field_3'] ) && '1' === $options['autoptimize_imgopt_checkbox_field_3'] ) { echo 'checked="checked"'; } ?> value='1'><?php _e( 'Image lazy-loading will delay the loading of non-visible images to allow the browser to optimally load all resources for the "above the fold"-page first.', 'autoptimize' ); ?></label>
|
956 |
+
</td>
|
957 |
+
</tr>
|
958 |
+
<tr id='autoptimize_imgopt_lazyload_exclusions' <?php if ( ! array_key_exists( 'autoptimize_imgopt_checkbox_field_3', $options ) || ( isset( $options['autoptimize_imgopt_checkbox_field_3'] ) && '1' !== $options['autoptimize_imgopt_checkbox_field_3'] ) ) { echo 'class="hidden"'; } ?>>
|
959 |
+
<th scope="row"><?php _e( 'Lazy-load exclusions', 'autoptimize' ); ?></th>
|
960 |
+
<td>
|
961 |
+
<label><input type='text' style='width:80%' id='autoptimize_imgopt_lazyload_exclusions' name='autoptimize_imgopt_settings[autoptimize_imgopt_text_field_5]' value='<?php if ( ! empty( $options['autoptimize_imgopt_text_field_5'] ) ) { echo esc_attr( $options['autoptimize_imgopt_text_field_5'] ); } ?>'><br /><?php _e( 'Comma-separated list of to be excluded image classes or filenames.', 'autoptimize' ); ?></label>
|
962 |
+
</td>
|
963 |
+
</tr>
|
964 |
+
</table>
|
965 |
+
<p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="<?php _e( 'Save Changes', 'autoptimize' ); ?>" /></p>
|
966 |
+
</form>
|
967 |
+
<script>
|
968 |
+
jQuery(document).ready(function() {
|
969 |
+
jQuery("#autoptimize_imgopt_checkbox").change(function() {
|
970 |
+
if (this.checked) {
|
971 |
+
jQuery("#autoptimize_imgopt_quality").show("slow");
|
972 |
+
jQuery("#autoptimize_imgopt_webp").show("slow");
|
973 |
+
} else {
|
974 |
+
jQuery("#autoptimize_imgopt_quality").hide("slow");
|
975 |
+
jQuery("#autoptimize_imgopt_webp").hide("slow");
|
976 |
+
}
|
977 |
+
});
|
978 |
+
jQuery("#autoptimize_imgopt_webp_checkbox").change(function() {
|
979 |
+
if (this.checked) {
|
980 |
+
jQuery("#autoptimize_imgopt_lazyload_checkbox")[0].checked = true;
|
981 |
+
jQuery("#autoptimize_imgopt_lazyload_exclusions").show("slow");
|
982 |
+
}
|
983 |
+
});
|
984 |
+
jQuery("#autoptimize_imgopt_lazyload_checkbox").change(function() {
|
985 |
+
if (this.checked) {
|
986 |
+
jQuery("#autoptimize_imgopt_lazyload_exclusions").show("slow");
|
987 |
+
} else {
|
988 |
+
jQuery("#autoptimize_imgopt_lazyload_exclusions").hide("slow");
|
989 |
+
jQuery("#autoptimize_imgopt_webp_checkbox")[0].checked = false;
|
990 |
+
}
|
991 |
+
});
|
992 |
+
});
|
993 |
+
</script>
|
994 |
+
<?php
|
995 |
+
}
|
996 |
+
|
997 |
+
/**
|
998 |
+
* Ïmg opt status as used on dashboard.
|
999 |
+
*/
|
1000 |
+
public function get_imgopt_status_notice() {
|
1001 |
+
if ( $this->imgopt_active() ) {
|
1002 |
+
$_imgopt_notice = '';
|
1003 |
+
$_stat = get_option( 'autoptimize_imgopt_provider_stat', '' );
|
1004 |
+
$_site_host = AUTOPTIMIZE_SITE_DOMAIN;
|
1005 |
+
$_imgopt_upsell = 'https://shortpixel.com/aospai/af/GWRGFLW109483/' . $_site_host;
|
1006 |
+
|
1007 |
+
if ( is_array( $_stat ) ) {
|
1008 |
+
if ( 1 == $_stat['Status'] ) {
|
1009 |
+
// translators: "add more credits" will appear in a "a href".
|
1010 |
+
$_imgopt_notice = sprintf( __( 'Your ShortPixel image optimization and CDN quota is almost used, make sure you %1$sadd more credits%2$s to avoid slowing down your website.', 'autoptimize' ), '<a href="' . $_imgopt_upsell . '" target="_blank">', '</a>' );
|
1011 |
+
} elseif ( -1 == $_stat['Status'] || -2 == $_stat['Status'] ) {
|
1012 |
+
// translators: "add more credits" will appear in a "a href".
|
1013 |
+
$_imgopt_notice = sprintf( __( 'Your ShortPixel image optimization and CDN quota was used, %1$sadd more credits%2$s to keep fast serving optimized images on your site', 'autoptimize' ), '<a href="' . $_imgopt_upsell . '" target="_blank">', '</a>' );
|
1014 |
+
$_imgopt_stats_refresh_url = add_query_arg( array(
|
1015 |
+
'page' => 'autoptimize_imgopt',
|
1016 |
+
'refreshImgProvStats' => '1',
|
1017 |
+
), admin_url( 'options-general.php' ) );
|
1018 |
+
if ( $_stat && array_key_exists( 'timestamp', $_stat ) && ! empty( $_stat['timestamp'] ) ) {
|
1019 |
+
$_imgopt_stats_last_run = __( 'based on status at ', 'autoptimize' ) . date_i18n( get_option( 'time_format' ), $_stat['timestamp'] );
|
1020 |
+
} else {
|
1021 |
+
$_imgopt_stats_last_run = __( 'based on previously fetched data', 'autoptimize' );
|
1022 |
+
}
|
1023 |
+
$_imgopt_notice .= ' (' . $_imgopt_stats_last_run . ', ';
|
1024 |
+
// translators: "here to refresh" links to the Autoptimize Extra page and forces a refresh of the img opt stats.
|
1025 |
+
$_imgopt_notice .= sprintf( __( 'click %1$shere to refresh%2$s', 'autoptimize' ), '<a href="' . $_imgopt_stats_refresh_url . '">', '</a>).' );
|
1026 |
+
} else {
|
1027 |
+
$_imgopt_upsell = 'https://shortpixel.com/g/af/GWRGFLW109483';
|
1028 |
+
// translators: "log in to check your account" will appear in a "a href".
|
1029 |
+
$_imgopt_notice = sprintf( __( 'Your ShortPixel image optimization and CDN quota are in good shape, %1$slog in to check your account%2$s.', 'autoptimize' ), '<a href="' . $_imgopt_upsell . '" target="_blank">', '</a>' );
|
1030 |
+
}
|
1031 |
+
$_imgopt_notice = apply_filters( 'autoptimize_filter_imgopt_notice', $_imgopt_notice );
|
1032 |
+
|
1033 |
+
return array(
|
1034 |
+
'status' => $_stat['Status'],
|
1035 |
+
'notice' => $_imgopt_notice,
|
1036 |
+
);
|
1037 |
+
}
|
1038 |
+
}
|
1039 |
+
return false;
|
1040 |
+
}
|
1041 |
+
|
1042 |
+
public static function get_imgopt_status_notice_wrapper() {
|
1043 |
+
// needed for notice being shown in autoptimizeCacheChecker.php.
|
1044 |
+
$self = new self();
|
1045 |
+
return $self->get_imgopt_status_notice();
|
1046 |
+
}
|
1047 |
+
|
1048 |
+
/**
|
1049 |
+
* Get img provider stats (used to display notice).
|
1050 |
+
*/
|
1051 |
+
public function query_img_provider_stats() {
|
1052 |
+
if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_1'] ) ) {
|
1053 |
+
$url = '';
|
1054 |
+
$endpoint = $this->get_imgopt_host() . 'read-domain/';
|
1055 |
+
$domain = AUTOPTIMIZE_SITE_DOMAIN;
|
1056 |
+
|
1057 |
+
// make sure parse_url result makes sense, keeping $url empty if not.
|
1058 |
+
if ( $domain && ! empty( $domain ) ) {
|
1059 |
+
$url = $endpoint . $domain;
|
1060 |
+
}
|
1061 |
+
|
1062 |
+
$url = apply_filters(
|
1063 |
+
'autoptimize_filter_imgopt_stat_url',
|
1064 |
+
$url
|
1065 |
+
);
|
1066 |
+
|
1067 |
+
// only do the remote call if $url is not empty to make sure no parse_url
|
1068 |
+
// weirdness results in useless calls.
|
1069 |
+
if ( ! empty( $url ) ) {
|
1070 |
+
$response = wp_remote_get( $url );
|
1071 |
+
if ( ! is_wp_error( $response ) ) {
|
1072 |
+
if ( '200' == wp_remote_retrieve_response_code( $response ) ) {
|
1073 |
+
$stats = json_decode( wp_remote_retrieve_body( $response ), true );
|
1074 |
+
update_option( 'autoptimize_imgopt_provider_stat', $stats );
|
1075 |
+
}
|
1076 |
+
}
|
1077 |
+
}
|
1078 |
+
}
|
1079 |
+
}
|
1080 |
+
|
1081 |
+
public static function get_img_provider_stats()
|
1082 |
+
{
|
1083 |
+
// wrapper around query_img_provider_stats() so we can get to $this->options from cronjob() in autoptimizeCacheChecker.
|
1084 |
+
$self = new self();
|
1085 |
+
return $self->query_img_provider_stats();
|
1086 |
+
}
|
1087 |
+
|
1088 |
+
/**
|
1089 |
+
* Determines and returns the service launch status.
|
1090 |
+
*
|
1091 |
+
* @return bool
|
1092 |
+
*/
|
1093 |
+
public function launch_ok()
|
1094 |
+
{
|
1095 |
+
static $launch_status = null;
|
1096 |
+
|
1097 |
+
if ( null === $launch_status ) {
|
1098 |
+
$avail_imgopt = $this->options['availabilities']['extra_imgopt'];
|
1099 |
+
$magic_number = intval( substr( md5( parse_url( AUTOPTIMIZE_WP_SITE_URL, PHP_URL_HOST ) ), 0, 3 ), 16 );
|
1100 |
+
$has_launched = get_option( 'autoptimize_imgopt_launched', '' );
|
1101 |
+
$launch_status = false;
|
1102 |
+
if ( $has_launched || ( is_array( $avail_imgopt ) && array_key_exists( 'launch-threshold', $avail_imgopt ) && $magic_number < $avail_imgopt['launch-threshold'] ) ) {
|
1103 |
+
$launch_status = true;
|
1104 |
+
if ( ! $has_launched ) {
|
1105 |
+
update_option( 'autoptimize_imgopt_launched', 'on' );
|
1106 |
+
}
|
1107 |
+
}
|
1108 |
+
}
|
1109 |
+
|
1110 |
+
return $launch_status;
|
1111 |
+
}
|
1112 |
+
|
1113 |
+
public static function launch_ok_wrapper() {
|
1114 |
+
// needed for "plug" notice in autoptimizeMain.php.
|
1115 |
+
$self = new self();
|
1116 |
+
return $self->launch_ok();
|
1117 |
+
}
|
1118 |
+
|
1119 |
+
public function get_imgopt_provider_userstatus() {
|
1120 |
+
static $_provider_userstatus = null;
|
1121 |
+
|
1122 |
+
if ( is_null( $_provider_userstatus ) ) {
|
1123 |
+
$_stat = get_option( 'autoptimize_imgopt_provider_stat', '' );
|
1124 |
+
if ( is_array( $_stat ) ) {
|
1125 |
+
if ( array_key_exists( 'Status', $_stat ) ) {
|
1126 |
+
$_provider_userstatus['Status'] = $_stat['Status'];
|
1127 |
+
} else {
|
1128 |
+
// if no stats then we assume all is well.
|
1129 |
+
$_provider_userstatus['Status'] = 2;
|
1130 |
+
}
|
1131 |
+
if ( array_key_exists( 'timestamp', $_stat ) ) {
|
1132 |
+
$_provider_userstatus['timestamp'] = $_stat['timestamp'];
|
1133 |
+
} else {
|
1134 |
+
// if no timestamp then we return "".
|
1135 |
+
$_provider_userstatus['timestamp'] = '';
|
1136 |
+
}
|
1137 |
+
}
|
1138 |
+
}
|
1139 |
+
|
1140 |
+
return $_provider_userstatus;
|
1141 |
+
}
|
1142 |
+
|
1143 |
+
public function get_status_notice() {
|
1144 |
+
if ( $this->imgopt_active() ) {
|
1145 |
+
$notice = '';
|
1146 |
+
$stat = $this->get_imgopt_provider_userstatus();
|
1147 |
+
$upsell = 'https://shortpixel.com/aospai/af/GWRGFLW109483/' . AUTOPTIMIZE_SITE_DOMAIN;
|
1148 |
+
$assoc = 'https://shortpixel.helpscoutdocs.com/article/94-how-to-associate-a-domain-to-my-account';
|
1149 |
+
|
1150 |
+
if ( is_array( $stat ) ) {
|
1151 |
+
if ( 1 == $stat['Status'] ) {
|
1152 |
+
// translators: "add more credits" will appear in a "a href".
|
1153 |
+
$notice = sprintf( __( 'Your ShortPixel image optimization and CDN quota is almost used, make sure you %1$sadd more credits%2$s to avoid slowing down your website.', 'autoptimize' ), '<a rel="noopener noreferrer" href="' . $upsell . '" target="_blank">', '</a>' );
|
1154 |
+
} elseif ( -1 == $stat['Status'] || -2 == $stat['Status'] ) {
|
1155 |
+
// translators: "add more credits" will appear in a "a href".
|
1156 |
+
$notice = sprintf( __( 'Your ShortPixel image optimization and CDN quota was used, %1$sadd more credits%2$s to keep fast serving optimized images on your site.', 'autoptimize' ), '<a rel="noopener noreferrer" href="' . $upsell . '" target="_blank">', '</a>' );
|
1157 |
+
// translators: "associate your domain" will appear in a "a href".
|
1158 |
+
$notice = $notice . ' ' . sprintf( __( 'If you already have enough credits then you may need to %1$sassociate your domain%2$s to your Shortpixel account.', 'autoptimize' ), '<a rel="noopener noreferrer" href="' . $assoc . '" target="_blank">', '</a>' );
|
1159 |
+
} else {
|
1160 |
+
$upsell = 'https://shortpixel.com/g/af/GWRGFLW109483';
|
1161 |
+
// translators: "log in to check your account" will appear in a "a href".
|
1162 |
+
$notice = sprintf( __( 'Your ShortPixel image optimization and CDN quota are in good shape, %1$slog in to check your account%2$s.', 'autoptimize' ), '<a rel="noopener noreferrer" href="' . $upsell . '" target="_blank">', '</a>' );
|
1163 |
+
}
|
1164 |
+
$notice = apply_filters( 'autoptimize_filter_imgopt_notice', $notice );
|
1165 |
+
|
1166 |
+
return array(
|
1167 |
+
'status' => $stat['Status'],
|
1168 |
+
'notice' => $notice,
|
1169 |
+
);
|
1170 |
+
}
|
1171 |
+
}
|
1172 |
+
return false;
|
1173 |
+
}
|
1174 |
+
}
|
classes/autoptimizeMain.php
CHANGED
@@ -50,7 +50,12 @@ class autoptimizeMain
|
|
50 |
|
51 |
protected function add_hooks()
|
52 |
{
|
53 |
-
|
|
|
|
|
|
|
|
|
|
|
54 |
|
55 |
add_action( 'autoptimize_setup_done', array( $this, 'version_upgrades_check' ) );
|
56 |
add_action( 'autoptimize_setup_done', array( $this, 'check_cache_and_run' ) );
|
@@ -58,7 +63,6 @@ class autoptimizeMain
|
|
58 |
add_action( 'autoptimize_setup_done', array( $this, 'maybe_run_partners_tab' ) );
|
59 |
|
60 |
add_action( 'init', array( $this, 'load_textdomain' ) );
|
61 |
-
add_action( 'plugins_loaded', array( $this, 'hook_page_cache_purge' ) );
|
62 |
add_action( 'admin_init', array( 'PAnD', 'init' ) );
|
63 |
|
64 |
register_activation_hook( $this->filepath, array( $this, 'on_activate' ) );
|
@@ -154,7 +158,7 @@ class autoptimizeMain
|
|
154 |
{
|
155 |
if ( autoptimizeCache::cacheavail() ) {
|
156 |
$conf = autoptimizeConfig::instance();
|
157 |
-
if ( $conf->get( 'autoptimize_html' ) || $conf->get( 'autoptimize_js' ) || $conf->get( 'autoptimize_css' ) ) {
|
158 |
// Hook into WordPress frontend.
|
159 |
if ( defined( 'AUTOPTIMIZE_INIT_EARLIER' ) ) {
|
160 |
add_action(
|
@@ -172,6 +176,11 @@ class autoptimizeMain
|
|
172 |
self::DEFAULT_HOOK_PRIORITY
|
173 |
);
|
174 |
}
|
|
|
|
|
|
|
|
|
|
|
175 |
}
|
176 |
} else {
|
177 |
add_action( 'admin_notices', 'autoptimizeMain::notice_cache_unavailable' );
|
@@ -181,6 +190,8 @@ class autoptimizeMain
|
|
181 |
public function maybe_run_ao_extra()
|
182 |
{
|
183 |
if ( apply_filters( 'autoptimize_filter_extra_activate', true ) ) {
|
|
|
|
|
184 |
$ao_extra = new autoptimizeExtra();
|
185 |
$ao_extra->run();
|
186 |
|
@@ -378,6 +389,11 @@ class autoptimizeMain
|
|
378 |
*/
|
379 |
public static function is_amp_markup( $content )
|
380 |
{
|
|
|
|
|
|
|
|
|
|
|
381 |
$is_amp_markup = preg_match( '/<html[^>]*(?:amp|⚡)/i', $content );
|
382 |
|
383 |
return (bool) $is_amp_markup;
|
@@ -414,25 +430,27 @@ class autoptimizeMain
|
|
414 |
|
415 |
$classoptions = array(
|
416 |
'autoptimizeScripts' => array(
|
417 |
-
'aggregate'
|
418 |
-
'justhead'
|
419 |
-
'forcehead'
|
420 |
-
'trycatch'
|
421 |
-
'js_exclude'
|
422 |
-
'cdn_url'
|
423 |
-
'include_inline'
|
|
|
424 |
),
|
425 |
'autoptimizeStyles' => array(
|
426 |
-
'aggregate'
|
427 |
-
'justhead'
|
428 |
-
'datauris'
|
429 |
-
'defer'
|
430 |
-
'defer_inline'
|
431 |
-
'inline'
|
432 |
-
'css_exclude'
|
433 |
-
'cdn_url'
|
434 |
-
'include_inline'
|
435 |
-
'nogooglefont'
|
|
|
436 |
),
|
437 |
'autoptimizeHTML' => array(
|
438 |
'keepcomments' => $conf->get( 'autoptimize_html_keepcomments' ),
|
@@ -492,6 +510,8 @@ class autoptimizeMain
|
|
492 |
'autoptimize_service_availablity',
|
493 |
'autoptimize_imgopt_provider_stat',
|
494 |
'autoptimize_imgopt_launched',
|
|
|
|
|
495 |
);
|
496 |
|
497 |
if ( ! is_multisite() ) {
|
@@ -541,17 +561,11 @@ class autoptimizeMain
|
|
541 |
public static function notice_plug_imgopt()
|
542 |
{
|
543 |
// Translators: the URL added points to the Autopmize Extra settings.
|
544 |
-
$_ao_imgopt_plug_notice = sprintf( __( 'Did you know Autoptimize includes on-the-fly image optimization and CDN via ShortPixel? Check out the %1$sAutoptimize
|
545 |
$_ao_imgopt_plug_notice = apply_filters( 'autoptimize_filter_main_imgopt_plug_notice', $_ao_imgopt_plug_notice );
|
546 |
-
$_ao_imgopt_launch_ok =
|
547 |
$_ao_imgopt_plug_dismissible = 'ao-img-opt-plug-123';
|
548 |
-
|
549 |
-
// check if AO is optimizing images already.
|
550 |
-
$_ao_imgopt_active = false;
|
551 |
-
$_ao_extra_options = get_option( 'autoptimize_extra_settings', '' );
|
552 |
-
if ( is_array( $_ao_extra_options ) && array_key_exists( 'autoptimize_extra_checkbox_field_5', $_ao_extra_options ) && ! empty( $_ao_extra_options['autoptimize_extra_checkbox_field_5'] ) ) {
|
553 |
-
$_ao_imgopt_active = true;
|
554 |
-
}
|
555 |
|
556 |
if ( current_user_can( 'manage_options' ) && '' !== $_ao_imgopt_plug_notice && ! $_ao_imgopt_active && $_ao_imgopt_launch_ok && PAnD::is_admin_notice_active( $_ao_imgopt_plug_dismissible ) ) {
|
557 |
echo '<div class="notice notice-info is-dismissible" data-dismissible="' . $_ao_imgopt_plug_dismissible . '"><p>';
|
50 |
|
51 |
protected function add_hooks()
|
52 |
{
|
53 |
+
if ( ! defined( 'AUTOPTIMIZE_SETUP_INITHOOK' ) ) {
|
54 |
+
define( 'AUTOPTIMIZE_SETUP_INITHOOK', 'plugins_loaded' );
|
55 |
+
}
|
56 |
+
|
57 |
+
add_action( AUTOPTIMIZE_SETUP_INITHOOK, array( $this, 'setup' ) );
|
58 |
+
add_action( AUTOPTIMIZE_SETUP_INITHOOK, array( $this, 'hook_page_cache_purge' ) );
|
59 |
|
60 |
add_action( 'autoptimize_setup_done', array( $this, 'version_upgrades_check' ) );
|
61 |
add_action( 'autoptimize_setup_done', array( $this, 'check_cache_and_run' ) );
|
63 |
add_action( 'autoptimize_setup_done', array( $this, 'maybe_run_partners_tab' ) );
|
64 |
|
65 |
add_action( 'init', array( $this, 'load_textdomain' ) );
|
|
|
66 |
add_action( 'admin_init', array( 'PAnD', 'init' ) );
|
67 |
|
68 |
register_activation_hook( $this->filepath, array( $this, 'on_activate' ) );
|
158 |
{
|
159 |
if ( autoptimizeCache::cacheavail() ) {
|
160 |
$conf = autoptimizeConfig::instance();
|
161 |
+
if ( $conf->get( 'autoptimize_html' ) || $conf->get( 'autoptimize_js' ) || $conf->get( 'autoptimize_css' ) || autoptimizeImages::imgopt_active() || autoptimizeImages::should_lazyload_wrapper() ) {
|
162 |
// Hook into WordPress frontend.
|
163 |
if ( defined( 'AUTOPTIMIZE_INIT_EARLIER' ) ) {
|
164 |
add_action(
|
176 |
self::DEFAULT_HOOK_PRIORITY
|
177 |
);
|
178 |
}
|
179 |
+
|
180 |
+
// And disable Jetpack's site accelerator if JS or CSS opt. are active.
|
181 |
+
if ( class_exists( 'Jetpack' ) && apply_filters( 'autoptimize_filter_main_disable_jetpack_cdn', true ) && ( $conf->get( 'autoptimize_js' ) || $conf->get( 'autoptimize_css' ) ) ) {
|
182 |
+
add_filter( 'jetpack_force_disable_site_accelerator', '__return_true' );
|
183 |
+
}
|
184 |
}
|
185 |
} else {
|
186 |
add_action( 'admin_notices', 'autoptimizeMain::notice_cache_unavailable' );
|
190 |
public function maybe_run_ao_extra()
|
191 |
{
|
192 |
if ( apply_filters( 'autoptimize_filter_extra_activate', true ) ) {
|
193 |
+
$ao_imgopt = new autoptimizeImages();
|
194 |
+
$ao_imgopt->run();
|
195 |
$ao_extra = new autoptimizeExtra();
|
196 |
$ao_extra->run();
|
197 |
|
389 |
*/
|
390 |
public static function is_amp_markup( $content )
|
391 |
{
|
392 |
+
// Short-circuit when a function is available to determine whether the response is (or will be) an AMP page.
|
393 |
+
if ( function_exists( 'is_amp_endpoint' ) ) {
|
394 |
+
return is_amp_endpoint();
|
395 |
+
}
|
396 |
+
|
397 |
$is_amp_markup = preg_match( '/<html[^>]*(?:amp|⚡)/i', $content );
|
398 |
|
399 |
return (bool) $is_amp_markup;
|
430 |
|
431 |
$classoptions = array(
|
432 |
'autoptimizeScripts' => array(
|
433 |
+
'aggregate' => $conf->get( 'autoptimize_js_aggregate' ),
|
434 |
+
'justhead' => $conf->get( 'autoptimize_js_justhead' ),
|
435 |
+
'forcehead' => $conf->get( 'autoptimize_js_forcehead' ),
|
436 |
+
'trycatch' => $conf->get( 'autoptimize_js_trycatch' ),
|
437 |
+
'js_exclude' => $conf->get( 'autoptimize_js_exclude' ),
|
438 |
+
'cdn_url' => $conf->get( 'autoptimize_cdn_url' ),
|
439 |
+
'include_inline' => $conf->get( 'autoptimize_js_include_inline' ),
|
440 |
+
'minify_excluded' => $conf->get( 'autoptimize_minify_excluded' ),
|
441 |
),
|
442 |
'autoptimizeStyles' => array(
|
443 |
+
'aggregate' => $conf->get( 'autoptimize_css_aggregate' ),
|
444 |
+
'justhead' => $conf->get( 'autoptimize_css_justhead' ),
|
445 |
+
'datauris' => $conf->get( 'autoptimize_css_datauris' ),
|
446 |
+
'defer' => $conf->get( 'autoptimize_css_defer' ),
|
447 |
+
'defer_inline' => $conf->get( 'autoptimize_css_defer_inline' ),
|
448 |
+
'inline' => $conf->get( 'autoptimize_css_inline' ),
|
449 |
+
'css_exclude' => $conf->get( 'autoptimize_css_exclude' ),
|
450 |
+
'cdn_url' => $conf->get( 'autoptimize_cdn_url' ),
|
451 |
+
'include_inline' => $conf->get( 'autoptimize_css_include_inline' ),
|
452 |
+
'nogooglefont' => $conf->get( 'autoptimize_css_nogooglefont' ),
|
453 |
+
'minify_excluded' => $conf->get( 'autoptimize_minify_excluded' ),
|
454 |
),
|
455 |
'autoptimizeHTML' => array(
|
456 |
'keepcomments' => $conf->get( 'autoptimize_html_keepcomments' ),
|
510 |
'autoptimize_service_availablity',
|
511 |
'autoptimize_imgopt_provider_stat',
|
512 |
'autoptimize_imgopt_launched',
|
513 |
+
'autoptimize_imgopt_settings',
|
514 |
+
'autoptimize_minify_excluded',
|
515 |
);
|
516 |
|
517 |
if ( ! is_multisite() ) {
|
561 |
public static function notice_plug_imgopt()
|
562 |
{
|
563 |
// Translators: the URL added points to the Autopmize Extra settings.
|
564 |
+
$_ao_imgopt_plug_notice = sprintf( __( 'Did you know Autoptimize includes on-the-fly image optimization (with support for WebP) and CDN via ShortPixel? Check out the %1$sAutoptimize Image settings%2$s to activate this option.', 'autoptimize' ), '<a href="options-general.php?page=autoptimize_imgopt">', '</a>' );
|
565 |
$_ao_imgopt_plug_notice = apply_filters( 'autoptimize_filter_main_imgopt_plug_notice', $_ao_imgopt_plug_notice );
|
566 |
+
$_ao_imgopt_launch_ok = autoptimizeImages::launch_ok_wrapper();
|
567 |
$_ao_imgopt_plug_dismissible = 'ao-img-opt-plug-123';
|
568 |
+
$_ao_imgopt_active = autoptimizeImages::imgopt_active();
|
|
|
|
|
|
|
|
|
|
|
|
|
569 |
|
570 |
if ( current_user_can( 'manage_options' ) && '' !== $_ao_imgopt_plug_notice && ! $_ao_imgopt_active && $_ao_imgopt_launch_ok && PAnD::is_admin_notice_active( $_ao_imgopt_plug_dismissible ) ) {
|
571 |
echo '<div class="notice notice-info is-dismissible" data-dismissible="' . $_ao_imgopt_plug_dismissible . '"><p>';
|
classes/autoptimizeScripts.php
CHANGED
@@ -39,8 +39,9 @@ class autoptimizeScripts extends autoptimizeBase
|
|
39 |
private $whitelist = '';
|
40 |
private $jsremovables = array();
|
41 |
private $inject_min_late = '';
|
|
|
42 |
|
43 |
-
// Reads the page and collects script tags
|
44 |
public function read($options)
|
45 |
{
|
46 |
$noptimizeJS = apply_filters( 'autoptimize_filter_js_noptimize', false, $this->content );
|
@@ -54,7 +55,7 @@ class autoptimizeScripts extends autoptimizeBase
|
|
54 |
$this->whitelist = array_filter( array_map( 'trim', explode( ',', $whitelistJS ) ) );
|
55 |
}
|
56 |
|
57 |
-
// is there JS we should simply remove
|
58 |
$removableJS = apply_filters( 'autoptimize_filter_js_removables', '', $this->content );
|
59 |
if (!empty($removableJS)) {
|
60 |
$this->jsremovables = array_filter( array_map( 'trim', explode( ',', $removableJS ) ) );
|
@@ -81,15 +82,20 @@ class autoptimizeScripts extends autoptimizeBase
|
|
81 |
$this->include_inline = true;
|
82 |
}
|
83 |
|
84 |
-
// filter to "late inject minified JS", default to true for now (it is faster)
|
85 |
$this->inject_min_late = apply_filters( 'autoptimize_filter_js_inject_min_late', true );
|
86 |
|
87 |
-
// filters to override hardcoded do(nt)move(last) array contents (array in, array out!)
|
88 |
$this->dontmove = apply_filters( 'autoptimize_filter_js_dontmove', $this->dontmove );
|
89 |
$this->domovelast = apply_filters( 'autoptimize_filter_js_movelast', $this->domovelast );
|
90 |
$this->domove = apply_filters( 'autoptimize_filter_js_domove', $this->domove );
|
91 |
|
92 |
-
//
|
|
|
|
|
|
|
|
|
|
|
93 |
$excludeJS = $options['js_exclude'];
|
94 |
$excludeJS = apply_filters( 'autoptimize_filter_js_exclude', $excludeJS, $this->content );
|
95 |
|
@@ -122,22 +128,22 @@ class autoptimizeScripts extends autoptimizeBase
|
|
122 |
|
123 |
$this->forcehead = apply_filters( 'autoptimize_filter_js_forcehead', $this->forcehead );
|
124 |
|
125 |
-
// get cdn url
|
126 |
$this->cdn_url = $options['cdn_url'];
|
127 |
|
128 |
-
// noptimize me
|
129 |
$this->content = $this->hide_noptimize($this->content);
|
130 |
|
131 |
-
// Save IE hacks
|
132 |
$this->content = $this->hide_iehacks($this->content);
|
133 |
|
134 |
-
// comments
|
135 |
$this->content = $this->hide_comments($this->content);
|
136 |
|
137 |
-
// Get script files
|
138 |
if ( preg_match_all( '#<script.*</script>#Usmi', $this->content, $matches ) ) {
|
139 |
foreach( $matches[0] as $tag ) {
|
140 |
-
// only consider script aggregation for types whitelisted in should_aggregate-function
|
141 |
$should_aggregate = $this->should_aggregate($tag);
|
142 |
if ( ! $should_aggregate ) {
|
143 |
$tag = '';
|
@@ -145,7 +151,7 @@ class autoptimizeScripts extends autoptimizeBase
|
|
145 |
}
|
146 |
|
147 |
if ( preg_match( '#<script[^>]*src=("|\')([^>]*)("|\')#Usmi', $tag, $source ) ) {
|
148 |
-
// non-inline script
|
149 |
if ( $this->isremovable($tag, $this->jsremovables) ) {
|
150 |
$this->content = str_replace( $tag, '', $this->content );
|
151 |
continue;
|
@@ -155,13 +161,13 @@ class autoptimizeScripts extends autoptimizeBase
|
|
155 |
$url = current( explode( '?', $source[2], 2 ) );
|
156 |
$path = $this->getpath($url);
|
157 |
if ( false !== $path && preg_match( '#\.js$#', $path ) && $this->ismergeable($tag) ) {
|
158 |
-
// ok to optimize, add to array
|
159 |
$this->scripts[] = $path;
|
160 |
} else {
|
161 |
$origTag = $tag;
|
162 |
$newTag = $tag;
|
163 |
|
164 |
-
// non-mergeable script (excluded or dynamic or external)
|
165 |
if ( is_array( $excludeJS ) ) {
|
166 |
// should we add flags?
|
167 |
foreach ( $excludeJS as $exclTag => $exclFlags) {
|
@@ -172,39 +178,44 @@ class autoptimizeScripts extends autoptimizeBase
|
|
172 |
}
|
173 |
|
174 |
// Should we minify the non-aggregated script?
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
|
|
|
|
|
|
|
|
|
|
180 |
}
|
181 |
}
|
182 |
|
183 |
if ( $this->ismovable($newTag) ) {
|
184 |
-
// can be moved, flags and all
|
185 |
if ( $this->movetolast($newTag) ) {
|
186 |
$this->move['last'][] = $newTag;
|
187 |
} else {
|
188 |
$this->move['first'][] = $newTag;
|
189 |
}
|
190 |
} else {
|
191 |
-
// cannot be moved, so if flag was added re-inject altered tag immediately
|
192 |
if ( $origTag !== $newTag ) {
|
193 |
$this->content = str_replace( $origTag, $newTag, $this->content );
|
194 |
$origTag = '';
|
195 |
}
|
196 |
-
// and forget about the $tag (not to be touched any more)
|
197 |
$tag = '';
|
198 |
}
|
199 |
}
|
200 |
} else {
|
201 |
-
// Inline script
|
202 |
if ( $this->isremovable($tag, $this->jsremovables) ) {
|
203 |
$this->content = str_replace( $tag, '', $this->content );
|
204 |
continue;
|
205 |
}
|
206 |
|
207 |
-
// unhide comments, as javascript may be wrapped in comment-tags for old times' sake
|
208 |
$tag = $this->restore_comments($tag);
|
209 |
if ( $this->ismergeable($tag) && $this->include_inline ) {
|
210 |
preg_match( '#<script.*>(.*)</script>#Usmi', $tag , $code );
|
@@ -221,15 +232,15 @@ class autoptimizeScripts extends autoptimizeBase
|
|
221 |
$this->move['first'][] = $tag;
|
222 |
}
|
223 |
} else {
|
224 |
-
// We shouldn't touch this
|
225 |
$tag = '';
|
226 |
}
|
227 |
}
|
228 |
-
// Re-hide comments to be able to do the removal based on tag from $this->content
|
229 |
$tag = $this->hide_comments($tag);
|
230 |
}
|
231 |
|
232 |
-
//Remove the original script tag
|
233 |
$this->content = str_replace( $tag, '', $this->content );
|
234 |
}
|
235 |
|
39 |
private $whitelist = '';
|
40 |
private $jsremovables = array();
|
41 |
private $inject_min_late = '';
|
42 |
+
private $minify_excluded = true;
|
43 |
|
44 |
+
// Reads the page and collects script tags.
|
45 |
public function read($options)
|
46 |
{
|
47 |
$noptimizeJS = apply_filters( 'autoptimize_filter_js_noptimize', false, $this->content );
|
55 |
$this->whitelist = array_filter( array_map( 'trim', explode( ',', $whitelistJS ) ) );
|
56 |
}
|
57 |
|
58 |
+
// is there JS we should simply remove?
|
59 |
$removableJS = apply_filters( 'autoptimize_filter_js_removables', '', $this->content );
|
60 |
if (!empty($removableJS)) {
|
61 |
$this->jsremovables = array_filter( array_map( 'trim', explode( ',', $removableJS ) ) );
|
82 |
$this->include_inline = true;
|
83 |
}
|
84 |
|
85 |
+
// filter to "late inject minified JS", default to true for now (it is faster).
|
86 |
$this->inject_min_late = apply_filters( 'autoptimize_filter_js_inject_min_late', true );
|
87 |
|
88 |
+
// filters to override hardcoded do(nt)move(last) array contents (array in, array out!).
|
89 |
$this->dontmove = apply_filters( 'autoptimize_filter_js_dontmove', $this->dontmove );
|
90 |
$this->domovelast = apply_filters( 'autoptimize_filter_js_movelast', $this->domovelast );
|
91 |
$this->domove = apply_filters( 'autoptimize_filter_js_domove', $this->domove );
|
92 |
|
93 |
+
// Determine whether excluded files should be minified if not yet so.
|
94 |
+
if ( ! $options['minify_excluded'] && $options['aggregate'] ) {
|
95 |
+
$this->minify_excluded = false;
|
96 |
+
}
|
97 |
+
|
98 |
+
// get extra exclusions settings or filter.
|
99 |
$excludeJS = $options['js_exclude'];
|
100 |
$excludeJS = apply_filters( 'autoptimize_filter_js_exclude', $excludeJS, $this->content );
|
101 |
|
128 |
|
129 |
$this->forcehead = apply_filters( 'autoptimize_filter_js_forcehead', $this->forcehead );
|
130 |
|
131 |
+
// get cdn url.
|
132 |
$this->cdn_url = $options['cdn_url'];
|
133 |
|
134 |
+
// noptimize me.
|
135 |
$this->content = $this->hide_noptimize($this->content);
|
136 |
|
137 |
+
// Save IE hacks.
|
138 |
$this->content = $this->hide_iehacks($this->content);
|
139 |
|
140 |
+
// comments.
|
141 |
$this->content = $this->hide_comments($this->content);
|
142 |
|
143 |
+
// Get script files.
|
144 |
if ( preg_match_all( '#<script.*</script>#Usmi', $this->content, $matches ) ) {
|
145 |
foreach( $matches[0] as $tag ) {
|
146 |
+
// only consider script aggregation for types whitelisted in should_aggregate-function.
|
147 |
$should_aggregate = $this->should_aggregate($tag);
|
148 |
if ( ! $should_aggregate ) {
|
149 |
$tag = '';
|
151 |
}
|
152 |
|
153 |
if ( preg_match( '#<script[^>]*src=("|\')([^>]*)("|\')#Usmi', $tag, $source ) ) {
|
154 |
+
// non-inline script.
|
155 |
if ( $this->isremovable($tag, $this->jsremovables) ) {
|
156 |
$this->content = str_replace( $tag, '', $this->content );
|
157 |
continue;
|
161 |
$url = current( explode( '?', $source[2], 2 ) );
|
162 |
$path = $this->getpath($url);
|
163 |
if ( false !== $path && preg_match( '#\.js$#', $path ) && $this->ismergeable($tag) ) {
|
164 |
+
// ok to optimize, add to array.
|
165 |
$this->scripts[] = $path;
|
166 |
} else {
|
167 |
$origTag = $tag;
|
168 |
$newTag = $tag;
|
169 |
|
170 |
+
// non-mergeable script (excluded or dynamic or external).
|
171 |
if ( is_array( $excludeJS ) ) {
|
172 |
// should we add flags?
|
173 |
foreach ( $excludeJS as $exclTag => $exclFlags) {
|
178 |
}
|
179 |
|
180 |
// Should we minify the non-aggregated script?
|
181 |
+
// -> if aggregate is on and exclude minify is on
|
182 |
+
// -> if aggregate is off and the file is not in dontmove.
|
183 |
+
if ( $path && ( $this->minify_excluded || apply_filters( 'autoptimize_filter_js_minify_excluded', false, $url ) ) ) {
|
184 |
+
$consider_minified_array = apply_filters( 'autoptimize_filter_js_consider_minified', false );
|
185 |
+
if ( ( false === $this->aggregate && str_replace( $this->dontmove, '', $path ) === $path ) || ( true === $this->aggregate && ( false === $consider_minified_array || str_replace( $consider_minified_array, '', $path ) === $path ) ) ) {
|
186 |
+
$minified_url = $this->minify_single( $path );
|
187 |
+
// replace orig URL with minified URL from cache if so.
|
188 |
+
if ( ! empty( $minified_url ) ) {
|
189 |
+
$newTag = str_replace( $url, $minified_url, $newTag );
|
190 |
+
}
|
191 |
}
|
192 |
}
|
193 |
|
194 |
if ( $this->ismovable($newTag) ) {
|
195 |
+
// can be moved, flags and all.
|
196 |
if ( $this->movetolast($newTag) ) {
|
197 |
$this->move['last'][] = $newTag;
|
198 |
} else {
|
199 |
$this->move['first'][] = $newTag;
|
200 |
}
|
201 |
} else {
|
202 |
+
// cannot be moved, so if flag was added re-inject altered tag immediately.
|
203 |
if ( $origTag !== $newTag ) {
|
204 |
$this->content = str_replace( $origTag, $newTag, $this->content );
|
205 |
$origTag = '';
|
206 |
}
|
207 |
+
// and forget about the $tag (not to be touched any more).
|
208 |
$tag = '';
|
209 |
}
|
210 |
}
|
211 |
} else {
|
212 |
+
// Inline script.
|
213 |
if ( $this->isremovable($tag, $this->jsremovables) ) {
|
214 |
$this->content = str_replace( $tag, '', $this->content );
|
215 |
continue;
|
216 |
}
|
217 |
|
218 |
+
// unhide comments, as javascript may be wrapped in comment-tags for old times' sake.
|
219 |
$tag = $this->restore_comments($tag);
|
220 |
if ( $this->ismergeable($tag) && $this->include_inline ) {
|
221 |
preg_match( '#<script.*>(.*)</script>#Usmi', $tag , $code );
|
232 |
$this->move['first'][] = $tag;
|
233 |
}
|
234 |
} else {
|
235 |
+
// We shouldn't touch this.
|
236 |
$tag = '';
|
237 |
}
|
238 |
}
|
239 |
+
// Re-hide comments to be able to do the removal based on tag from $this->content.
|
240 |
$tag = $this->hide_comments($tag);
|
241 |
}
|
242 |
|
243 |
+
//Remove the original script tag.
|
244 |
$this->content = str_replace( $tag, '', $this->content );
|
245 |
}
|
246 |
|
classes/autoptimizeStyles.php
CHANGED
@@ -44,6 +44,7 @@ class autoptimizeStyles extends autoptimizeBase
|
|
44 |
private $cssremovables = array();
|
45 |
private $include_inline = false;
|
46 |
private $inject_min_late = '';
|
|
|
47 |
|
48 |
// public $cdn_url; // Used all over the place implicitly, so will have to be either public or protected :/ .
|
49 |
|
@@ -122,6 +123,11 @@ class autoptimizeStyles extends autoptimizeBase
|
|
122 |
// Store data: URIs setting for later use.
|
123 |
$this->datauris = $options['datauris'];
|
124 |
|
|
|
|
|
|
|
|
|
|
|
125 |
// noptimize me.
|
126 |
$this->content = $this->hide_noptimize( $this->content );
|
127 |
|
@@ -201,25 +207,30 @@ class autoptimizeStyles extends autoptimizeBase
|
|
201 |
// Remove the original style tag.
|
202 |
$this->content = str_replace( $tag, '', $this->content );
|
203 |
} else {
|
204 |
-
// Excluded CSS, minify
|
|
|
|
|
205 |
if ( preg_match( '#<link.*href=("|\')(.*)("|\')#Usmi', $tag, $source ) ) {
|
206 |
$exploded_url = explode( '?', $source[2], 2 );
|
207 |
$url = $exploded_url[0];
|
208 |
$path = $this->getpath( $url );
|
209 |
|
210 |
-
if ( $path && apply_filters( 'autoptimize_filter_css_minify_excluded',
|
211 |
-
$
|
212 |
-
if (
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
|
|
|
|
218 |
|
219 |
-
|
220 |
|
221 |
-
|
222 |
-
|
|
|
223 |
}
|
224 |
}
|
225 |
}
|
@@ -797,19 +808,7 @@ class autoptimizeStyles extends autoptimizeBase
|
|
797 |
// Returns the content.
|
798 |
public function getcontent()
|
799 |
{
|
800 |
-
//
|
801 |
-
$this->content = $this->restore_comments( $this->content );
|
802 |
-
|
803 |
-
// restore IE hacks.
|
804 |
-
$this->content = $this->restore_iehacks( $this->content );
|
805 |
-
|
806 |
-
// restore (no)script.
|
807 |
-
$this->content = $this->restore_marked_content( 'SCRIPT', $this->content );
|
808 |
-
|
809 |
-
// Restore noptimize.
|
810 |
-
$this->content = $this->restore_noptimize( $this->content );
|
811 |
-
|
812 |
-
// Restore the full content.
|
813 |
if ( ! empty( $this->restofcontent ) ) {
|
814 |
$this->content .= $this->restofcontent;
|
815 |
$this->restofcontent = '';
|
@@ -847,8 +846,9 @@ class autoptimizeStyles extends autoptimizeBase
|
|
847 |
}
|
848 |
}
|
849 |
}
|
850 |
-
|
851 |
-
|
|
|
852 |
}
|
853 |
}
|
854 |
|
@@ -874,16 +874,29 @@ class autoptimizeStyles extends autoptimizeBase
|
|
874 |
if ( $this->defer ) {
|
875 |
$preload_polyfill = autoptimizeConfig::get_ao_css_preload_polyfill();
|
876 |
$noScriptCssBlock .= '</noscript>';
|
877 |
-
|
|
|
878 |
|
879 |
// Adds preload polyfill at end of body tag.
|
880 |
$this->inject_in_html(
|
881 |
apply_filters( 'autoptimize_css_preload_polyfill', $preload_polyfill ),
|
882 |
-
array( '</body>', 'before' )
|
883 |
);
|
884 |
}
|
885 |
}
|
886 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
887 |
// Return the modified stylesheet.
|
888 |
return $this->content;
|
889 |
}
|
44 |
private $cssremovables = array();
|
45 |
private $include_inline = false;
|
46 |
private $inject_min_late = '';
|
47 |
+
private $minify_excluded = true;
|
48 |
|
49 |
// public $cdn_url; // Used all over the place implicitly, so will have to be either public or protected :/ .
|
50 |
|
123 |
// Store data: URIs setting for later use.
|
124 |
$this->datauris = $options['datauris'];
|
125 |
|
126 |
+
// Determine whether excluded files should be minified if not yet so.
|
127 |
+
if ( ! $options['minify_excluded'] && $options['aggregate'] ) {
|
128 |
+
$this->minify_excluded = false;
|
129 |
+
}
|
130 |
+
|
131 |
// noptimize me.
|
132 |
$this->content = $this->hide_noptimize( $this->content );
|
133 |
|
207 |
// Remove the original style tag.
|
208 |
$this->content = str_replace( $tag, '', $this->content );
|
209 |
} else {
|
210 |
+
// Excluded CSS, minify that file:
|
211 |
+
// -> if aggregate is on and exclude minify is on
|
212 |
+
// -> if aggregate is off and the file is not in dontmove.
|
213 |
if ( preg_match( '#<link.*href=("|\')(.*)("|\')#Usmi', $tag, $source ) ) {
|
214 |
$exploded_url = explode( '?', $source[2], 2 );
|
215 |
$url = $exploded_url[0];
|
216 |
$path = $this->getpath( $url );
|
217 |
|
218 |
+
if ( $path && ( $this->minify_excluded || apply_filters( 'autoptimize_filter_css_minify_excluded', false, $url ) ) ) {
|
219 |
+
$consider_minified_array = apply_filters( 'autoptimize_filter_css_consider_minified', false );
|
220 |
+
if ( ( false === $this->aggregate && str_replace( $this->dontmove, '', $path ) === $path ) || ( true === $this->aggregate && ( false === $consider_minified_array || str_replace( $consider_minified_array, '', $path ) === $path ) ) ) {
|
221 |
+
$minified_url = $this->minify_single( $path );
|
222 |
+
if ( ! empty( $minified_url ) ) {
|
223 |
+
// Replace orig URL with cached minified URL.
|
224 |
+
$new_tag = str_replace( $url, $minified_url, $tag );
|
225 |
+
} else {
|
226 |
+
$new_tag = $tag;
|
227 |
+
}
|
228 |
|
229 |
+
$new_tag = $this->optionally_defer_excluded( $new_tag, $url );
|
230 |
|
231 |
+
// And replace!
|
232 |
+
$this->content = str_replace( $tag, $new_tag, $this->content );
|
233 |
+
}
|
234 |
}
|
235 |
}
|
236 |
}
|
808 |
// Returns the content.
|
809 |
public function getcontent()
|
810 |
{
|
811 |
+
// Restore the full content (only applies when "autoptimize_filter_css_justhead" filter is true).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
812 |
if ( ! empty( $this->restofcontent ) ) {
|
813 |
$this->content .= $this->restofcontent;
|
814 |
$this->restofcontent = '';
|
846 |
}
|
847 |
}
|
848 |
}
|
849 |
+
// inlined critical css set here, but injected when full CSS is injected
|
850 |
+
// to avoid CSS containing SVG with <title tag receiving the full CSS link.
|
851 |
+
$inlined_ccss_block = '<style type="text/css" id="aoatfcss" media="all">' . $defer_inline_code . '</style>';
|
852 |
}
|
853 |
}
|
854 |
|
874 |
if ( $this->defer ) {
|
875 |
$preload_polyfill = autoptimizeConfig::get_ao_css_preload_polyfill();
|
876 |
$noScriptCssBlock .= '</noscript>';
|
877 |
+
// Inject inline critical CSS, the preloaded full CSS and the noscript-CSS.
|
878 |
+
$this->inject_in_html( $inlined_ccss_block . $preloadCssBlock . $noScriptCssBlock, $replaceTag );
|
879 |
|
880 |
// Adds preload polyfill at end of body tag.
|
881 |
$this->inject_in_html(
|
882 |
apply_filters( 'autoptimize_css_preload_polyfill', $preload_polyfill ),
|
883 |
+
apply_filters( 'autoptimize_css_preload_polyfill_injectat', array( '</body>', 'before' ) )
|
884 |
);
|
885 |
}
|
886 |
}
|
887 |
|
888 |
+
// restore comments.
|
889 |
+
$this->content = $this->restore_comments( $this->content );
|
890 |
+
|
891 |
+
// restore IE hacks.
|
892 |
+
$this->content = $this->restore_iehacks( $this->content );
|
893 |
+
|
894 |
+
// restore (no)script.
|
895 |
+
$this->content = $this->restore_marked_content( 'SCRIPT', $this->content );
|
896 |
+
|
897 |
+
// Restore noptimize.
|
898 |
+
$this->content = $this->restore_noptimize( $this->content );
|
899 |
+
|
900 |
// Return the modified stylesheet.
|
901 |
return $this->content;
|
902 |
}
|
classes/autoptimizeToolbar.php
CHANGED
@@ -133,7 +133,8 @@ class autoptimizeToolbar
|
|
133 |
// Needed for the AJAX to work properly on the frontend.
|
134 |
wp_localize_script( 'autoptimize-toolbar', 'autoptimize_ajax_object', array(
|
135 |
'ajaxurl' => admin_url( 'admin-ajax.php' ),
|
136 |
-
|
|
|
137 |
'dismiss_msg' => __( 'Dismiss this notice.' ),
|
138 |
'nonce' => wp_create_nonce( 'ao_delcache_nonce' ),
|
139 |
) );
|
133 |
// Needed for the AJAX to work properly on the frontend.
|
134 |
wp_localize_script( 'autoptimize-toolbar', 'autoptimize_ajax_object', array(
|
135 |
'ajaxurl' => admin_url( 'admin-ajax.php' ),
|
136 |
+
// translators: links to the Autoptimize settings page.
|
137 |
+
'error_msg' => sprintf( __( 'Your Autoptimize cache might not have been purged successfully, please check on the <a href="%s">Autoptimize settings page</a>.', 'autoptimize' ), admin_url( 'options-general.php?page=autoptimize' ) . ' style="white-space:nowrap;"' ),
|
138 |
'dismiss_msg' => __( 'Dismiss this notice.' ),
|
139 |
'nonce' => wp_create_nonce( 'ao_delcache_nonce' ),
|
140 |
) );
|
classes/autoptimizeUtils.php
CHANGED
@@ -267,7 +267,7 @@ class autoptimizeUtils
|
|
267 |
$result = false;
|
268 |
|
269 |
if ( ! empty( $url ) ) {
|
270 |
-
$result = (
|
271 |
}
|
272 |
|
273 |
return $result;
|
@@ -336,4 +336,24 @@ class autoptimizeUtils
|
|
336 |
|
337 |
return $is_regex;
|
338 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
339 |
}
|
267 |
$result = false;
|
268 |
|
269 |
if ( ! empty( $url ) ) {
|
270 |
+
$result = ( 0 === strpos( $url, '//' ) );
|
271 |
}
|
272 |
|
273 |
return $result;
|
336 |
|
337 |
return $is_regex;
|
338 |
}
|
339 |
+
|
340 |
+
/**
|
341 |
+
* Returns true if a certain WP plugin is active/loaded.
|
342 |
+
*
|
343 |
+
* @param string $plugin_file Main plugin file.
|
344 |
+
*
|
345 |
+
* @return bool
|
346 |
+
*/
|
347 |
+
public static function is_plugin_active( $plugin_file )
|
348 |
+
{
|
349 |
+
static $ipa_exists = null;
|
350 |
+
if ( null === $ipa_exists ) {
|
351 |
+
if ( ! function_exists( '\is_plugin_active' ) ) {
|
352 |
+
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
353 |
+
}
|
354 |
+
$ipa_exists = function_exists( '\is_plugin_active' );
|
355 |
+
}
|
356 |
+
|
357 |
+
return $ipa_exists && \is_plugin_active( $plugin_file );
|
358 |
+
}
|
359 |
}
|
classes/autoptimizeVersionUpdatesHandler.php
CHANGED
@@ -50,6 +50,7 @@ class autoptimizeVersionUpdatesHandler
|
|
50 |
if ( get_option( 'autoptimize_version', 'none' ) == '2.4.2' ) {
|
51 |
$this->upgrade_from_2_4_2();
|
52 |
}
|
|
|
53 |
$major_update = false;
|
54 |
// No break, intentionally, so all upgrades are ran during a single request...
|
55 |
}
|
@@ -230,4 +231,18 @@ class autoptimizeVersionUpdatesHandler
|
|
230 |
// Save the data.
|
231 |
_set_cron_array( $jobs );
|
232 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
233 |
}
|
50 |
if ( get_option( 'autoptimize_version', 'none' ) == '2.4.2' ) {
|
51 |
$this->upgrade_from_2_4_2();
|
52 |
}
|
53 |
+
$this->upgrade_from_2_4();
|
54 |
$major_update = false;
|
55 |
// No break, intentionally, so all upgrades are ran during a single request...
|
56 |
}
|
231 |
// Save the data.
|
232 |
_set_cron_array( $jobs );
|
233 |
}
|
234 |
+
|
235 |
+
/**
|
236 |
+
* Migrate imgopt options from autoptimize_extra_settings to autoptimize_imgopt_settings
|
237 |
+
*/
|
238 |
+
private function upgrade_from_2_4() {
|
239 |
+
$extra_settings = get_option( 'autoptimize_extra_settings' );
|
240 |
+
$imgopt_settings = get_option( 'autoptimize_imgopt_settings' );
|
241 |
+
if ( empty( $imgopt_settings ) ) {
|
242 |
+
$imgopt_settings = autoptimizeConfig::get_ao_imgopt_default_options();
|
243 |
+
$imgopt_settings['autoptimize_imgopt_checkbox_field_1'] = $extra_settings['autoptimize_extra_checkbox_field_5'];
|
244 |
+
$imgopt_settings['autoptimize_imgopt_select_field_2'] = $extra_settings['autoptimize_extra_select_field_6'];
|
245 |
+
update_option( 'autoptimize_imgopt_settings', $imgopt_settings );
|
246 |
+
}
|
247 |
+
}
|
248 |
}
|
classes/external/js/lazysizes.min.js
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
1 |
+
/*! lazysizes - v4.1.7 */
|
2 |
+
!function(a,b){var c=b(a,a.document);a.lazySizes=c,"object"==typeof module&&module.exports&&(module.exports=c)}(window,function(a,b){"use strict";if(b.getElementsByClassName){var c,d,e=b.documentElement,f=a.Date,g=a.HTMLPictureElement,h="addEventListener",i="getAttribute",j=a[h],k=a.setTimeout,l=a.requestAnimationFrame||k,m=a.requestIdleCallback,n=/^picture$/i,o=["load","error","lazyincluded","_lazyloaded"],p={},q=Array.prototype.forEach,r=function(a,b){return p[b]||(p[b]=new RegExp("(\\s|^)"+b+"(\\s|$)")),p[b].test(a[i]("class")||"")&&p[b]},s=function(a,b){r(a,b)||a.setAttribute("class",(a[i]("class")||"").trim()+" "+b)},t=function(a,b){var c;(c=r(a,b))&&a.setAttribute("class",(a[i]("class")||"").replace(c," "))},u=function(a,b,c){var d=c?h:"removeEventListener";c&&u(a,b),o.forEach(function(c){a[d](c,b)})},v=function(a,d,e,f,g){var h=b.createEvent("Event");return e||(e={}),e.instance=c,h.initEvent(d,!f,!g),h.detail=e,a.dispatchEvent(h),h},w=function(b,c){var e;!g&&(e=a.picturefill||d.pf)?(c&&c.src&&!b[i]("srcset")&&b.setAttribute("srcset",c.src),e({reevaluate:!0,elements:[b]})):c&&c.src&&(b.src=c.src)},x=function(a,b){return(getComputedStyle(a,null)||{})[b]},y=function(a,b,c){for(c=c||a.offsetWidth;c<d.minSize&&b&&!a._lazysizesWidth;)c=b.offsetWidth,b=b.parentNode;return c},z=function(){var a,c,d=[],e=[],f=d,g=function(){var b=f;for(f=d.length?e:d,a=!0,c=!1;b.length;)b.shift()();a=!1},h=function(d,e){a&&!e?d.apply(this,arguments):(f.push(d),c||(c=!0,(b.hidden?k:l)(g)))};return h._lsFlush=g,h}(),A=function(a,b){return b?function(){z(a)}:function(){var b=this,c=arguments;z(function(){a.apply(b,c)})}},B=function(a){var b,c=0,e=d.throttleDelay,g=d.ricTimeout,h=function(){b=!1,c=f.now(),a()},i=m&&g>49?function(){m(h,{timeout:g}),g!==d.ricTimeout&&(g=d.ricTimeout)}:A(function(){k(h)},!0);return function(a){var d;(a=!0===a)&&(g=33),b||(b=!0,d=e-(f.now()-c),d<0&&(d=0),a||d<9?i():k(i,d))}},C=function(a){var b,c,d=99,e=function(){b=null,a()},g=function(){var a=f.now()-c;a<d?k(g,d-a):(m||e)(e)};return function(){c=f.now(),b||(b=k(g,d))}};!function(){var b,c={lazyClass:"lazyload",loadedClass:"lazyloaded",loadingClass:"lazyloading",preloadClass:"lazypreload",errorClass:"lazyerror",autosizesClass:"lazyautosizes",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};d=a.lazySizesConfig||a.lazysizesConfig||{};for(b in c)b in d||(d[b]=c[b]);a.lazySizesConfig=d,k(function(){d.init&&F()})}();var D=function(){var g,l,m,o,p,y,D,F,G,H,I,J,K=/^img$/i,L=/^iframe$/i,M="onscroll"in a&&!/(gle|ing)bot/.test(navigator.userAgent),N=0,O=0,P=0,Q=-1,R=function(a){P--,(!a||P<0||!a.target)&&(P=0)},S=function(a){return null==J&&(J="hidden"==x(b.body,"visibility")),J||"hidden"!=x(a.parentNode,"visibility")&&"hidden"!=x(a,"visibility")},T=function(a,c){var d,f=a,g=S(a);for(F-=c,I+=c,G-=c,H+=c;g&&(f=f.offsetParent)&&f!=b.body&&f!=e;)(g=(x(f,"opacity")||1)>0)&&"visible"!=x(f,"overflow")&&(d=f.getBoundingClientRect(),g=H>d.left&&G<d.right&&I>d.top-1&&F<d.bottom+1);return g},U=function(){var a,f,h,j,k,m,n,p,q,r,s,t,u=c.elements;if((o=d.loadMode)&&P<8&&(a=u.length)){for(f=0,Q++,r=!d.expand||d.expand<1?e.clientHeight>500&&e.clientWidth>500?500:370:d.expand,c._defEx=r,s=r*d.expFactor,t=d.hFac,J=null,O<s&&P<1&&Q>2&&o>2&&!b.hidden?(O=s,Q=0):O=o>1&&Q>1&&P<6?r:N;f<a;f++)if(u[f]&&!u[f]._lazyRace)if(M)if((p=u[f][i]("data-expand"))&&(m=1*p)||(m=O),q!==m&&(y=innerWidth+m*t,D=innerHeight+m,n=-1*m,q=m),h=u[f].getBoundingClientRect(),(I=h.bottom)>=n&&(F=h.top)<=D&&(H=h.right)>=n*t&&(G=h.left)<=y&&(I||H||G||F)&&(d.loadHidden||S(u[f]))&&(l&&P<3&&!p&&(o<3||Q<4)||T(u[f],m))){if(aa(u[f]),k=!0,P>9)break}else!k&&l&&!j&&P<4&&Q<4&&o>2&&(g[0]||d.preloadAfterLoad)&&(g[0]||!p&&(I||H||G||F||"auto"!=u[f][i](d.sizesAttr)))&&(j=g[0]||u[f]);else aa(u[f]);j&&!k&&aa(j)}},V=B(U),W=function(a){var b=a.target;if(b._lazyCache)return void delete b._lazyCache;R(a),s(b,d.loadedClass),t(b,d.loadingClass),u(b,Y),v(b,"lazyloaded")},X=A(W),Y=function(a){X({target:a.target})},Z=function(a,b){try{a.contentWindow.location.replace(b)}catch(c){a.src=b}},$=function(a){var b,c=a[i](d.srcsetAttr);(b=d.customMedia[a[i]("data-media")||a[i]("media")])&&a.setAttribute("media",b),c&&a.setAttribute("srcset",c)},_=A(function(a,b,c,e,f){var g,h,j,l,o,p;(o=v(a,"lazybeforeunveil",b)).defaultPrevented||(e&&(c?s(a,d.autosizesClass):a.setAttribute("sizes",e)),h=a[i](d.srcsetAttr),g=a[i](d.srcAttr),f&&(j=a.parentNode,l=j&&n.test(j.nodeName||"")),p=b.firesLoad||"src"in a&&(h||g||l),o={target:a},s(a,d.loadingClass),p&&(clearTimeout(m),m=k(R,2500),u(a,Y,!0)),l&&q.call(j.getElementsByTagName("source"),$),h?a.setAttribute("srcset",h):g&&!l&&(L.test(a.nodeName)?Z(a,g):a.src=g),f&&(h||l)&&w(a,{src:g})),a._lazyRace&&delete a._lazyRace,t(a,d.lazyClass),z(function(){(!p||a.complete&&a.naturalWidth>1)&&(W(o),a._lazyCache=!0,k(function(){"_lazyCache"in a&&delete a._lazyCache},9))},!0)}),aa=function(a){var b,c=K.test(a.nodeName),e=c&&(a[i](d.sizesAttr)||a[i]("sizes")),f="auto"==e;(!f&&l||!c||!a[i]("src")&&!a.srcset||a.complete||r(a,d.errorClass)||!r(a,d.lazyClass))&&(b=v(a,"lazyunveilread").detail,f&&E.updateElem(a,!0,a.offsetWidth),a._lazyRace=!0,P++,_(a,b,f,e,c))},ba=function(){if(!l){if(f.now()-p<999)return void k(ba,999);var a=C(function(){d.loadMode=3,V()});l=!0,d.loadMode=3,V(),j("scroll",function(){3==d.loadMode&&(d.loadMode=2),a()},!0)}};return{_:function(){p=f.now(),c.elements=b.getElementsByClassName(d.lazyClass),g=b.getElementsByClassName(d.lazyClass+" "+d.preloadClass),j("scroll",V,!0),j("resize",V,!0),a.MutationObserver?new MutationObserver(V).observe(e,{childList:!0,subtree:!0,attributes:!0}):(e[h]("DOMNodeInserted",V,!0),e[h]("DOMAttrModified",V,!0),setInterval(V,999)),j("hashchange",V,!0),["focus","mouseover","click","load","transitionend","animationend","webkitAnimationEnd"].forEach(function(a){b[h](a,V,!0)}),/d$|^c/.test(b.readyState)?ba():(j("load",ba),b[h]("DOMContentLoaded",V),k(ba,2e4)),c.elements.length?(U(),z._lsFlush()):V()},checkElems:V,unveil:aa}}(),E=function(){var a,c=A(function(a,b,c,d){var e,f,g;if(a._lazysizesWidth=d,d+="px",a.setAttribute("sizes",d),n.test(b.nodeName||""))for(e=b.getElementsByTagName("source"),f=0,g=e.length;f<g;f++)e[f].setAttribute("sizes",d);c.detail.dataAttr||w(a,c.detail)}),e=function(a,b,d){var e,f=a.parentNode;f&&(d=y(a,f,d),e=v(a,"lazybeforesizes",{width:d,dataAttr:!!b}),e.defaultPrevented||(d=e.detail.width)&&d!==a._lazysizesWidth&&c(a,f,e,d))},f=function(){var b,c=a.length;if(c)for(b=0;b<c;b++)e(a[b])},g=C(f);return{_:function(){a=b.getElementsByClassName(d.autosizesClass),j("resize",g)},checkElems:g,updateElem:e}}(),F=function(){F.i||(F.i=!0,E._(),D._())};return c={cfg:d,autoSizer:E,loader:D,init:F,uP:w,aC:s,rC:t,hC:r,fire:v,gW:y,rAF:z}}});
|
readme.txt
CHANGED
@@ -1,17 +1,17 @@
|
|
1 |
=== Autoptimize ===
|
2 |
Contributors: futtta, optimizingmatters, zytzagoo, turl
|
3 |
-
Tags: optimize, minify, performance, pagespeed,
|
4 |
Donate link: http://blog.futtta.be/2013/10/21/do-not-donate-to-me/
|
5 |
Requires at least: 4.0
|
6 |
-
Tested up to: 5.
|
7 |
Requires PHP: 5.3
|
8 |
-
Stable tag: 2.
|
9 |
|
10 |
-
Autoptimize speeds up your website by optimizing JS, CSS, HTML, Google Fonts and
|
11 |
|
12 |
== Description ==
|
13 |
|
14 |
-
Autoptimize makes optimizing your site really easy. It can aggregate, minify and cache scripts and styles, injects CSS in the page head by default
|
15 |
|
16 |
If you consider performance important, you really should use one of the many caching plugins to do page caching. Some good candidates to complement Autoptimize that way are e.g. [WP Super Cache](http://wordpress.org/plugins/wp-super-cache/), [HyperCache](http://wordpress.org/plugins/hyper-cache/), [Comet Cache](https://wordpress.org/plugins/comet-cache/) or [KeyCDN's Cache Enabler](https://wordpress.org/plugins/cache-enabler).
|
17 |
|
@@ -91,6 +91,10 @@ When clicking the "Delete Cache" link in the Autoptimize dropdown in the admin t
|
|
91 |
|
92 |
Moreover don't worry if your cache never is down to 0 files/ 0KB, as Autoptimize (as from version 2.2) will automatically preload the cache immediately after it has been cleared to speed further minification significantly up.
|
93 |
|
|
|
|
|
|
|
|
|
94 |
= Can I still use Cloudflare's Rocket Loader? =
|
95 |
|
96 |
Cloudflare Rocket Loader is a pretty advanced but invasive way to make JavaScript non-render-blocking, which [Cloudflare still considers Beta](https://wordpress.org/support/topic/rocket-loader-breaking-onload-js-on-linked-css/#post-9263738). Sometimes Autoptimize & Rocket Loader work together, sometimes they don't. The best approach is to disable Rocket Loader, configure Autoptimize and re-enable Rocket Loader (if you think it can help) after that and test if everything still works.
|
@@ -99,7 +103,7 @@ At the moment (June 2017) it seems RocketLoader might break AO's "inline & defer
|
|
99 |
|
100 |
= I tried Autoptimize but my Google Pagespeed Scored barely improved =
|
101 |
|
102 |
-
Autoptimize is not a simple "fix my Pagespeed-problems" plugin; it "only" aggregates & minifies (local) JS & CSS and allows for some nice extra's as removing Google Fonts and deferring the loading of the CSS. As such Autoptimize will allow you to improve your performance (load time measured in seconds) and will probably also help you tackle some specific Pagespeed warnings. If you want to improve further, you will probably also have to look into e.g. page caching
|
103 |
|
104 |
= What can I do with the API? =
|
105 |
|
@@ -139,13 +143,17 @@ After having installed and activated the plugin, you'll have access to an admin
|
|
139 |
|
140 |
If your blog doesn't function normally after having turned on Autoptimize, here are some pointers to identify & solve such issues using "advanced settings":
|
141 |
|
142 |
-
* If all works but you notice your blog is slower, ensure you have a page caching plugin installed (WP Super Cache or similar) and check the info on cache size (the
|
143 |
-
* In case your blog looks weird, i.e. when the layout gets messed up, there is problem with CSS optimization.
|
144 |
* In case some functionality on your site stops working (a carroussel, a menu, the search input, ...) you're likely hitting JavaScript optimization trouble. Change the "Aggregate inline JS" and/ or "Force JavaScript in head?" settings and try again. Excluding 'js/jquery/jquery.js' from optimization (see below) and optionally activating "[Add try/catch wrapping](http://blog.futtta.be/2014/08/18/when-should-you-trycatch-javascript/)") can also help. Alternatively -for the technically savvy- you can exclude specific scripts from being treated (moved and/ or aggregated) by Autoptimize by adding a string that will match the offending Javascript or excluding it from within your template files or widgets by wrapping the code between noptimize-tags. Identifying the offending JavaScript and choosing the correct exclusion-string can be trial and error, but in the majority of cases JavaScript optimization issues can be solved this way. When debugging JavaScript issues, your browsers error console is the most important tool to help you understand what is going on.
|
145 |
* If your theme or plugin require jQuery, you can try either forcing all in head and/ or excluding jquery.js (and jQuery-plugins if needed).
|
146 |
* If you can't get either CSS or JS optimization working, you can off course always continue using the other two optimization-techniques.
|
147 |
* If you tried the troubleshooting tips above and you still can't get CSS and JS working at all, you can ask for support on the [WordPress Autoptimize support forum](http://wordpress.org/support/plugin/autoptimize). See below for a description of what information you should provide in your "trouble ticket"
|
148 |
|
|
|
|
|
|
|
|
|
149 |
= Help, I have a blank page or an internal server error after enabling Autoptimize!! =
|
150 |
|
151 |
Make sure you're not running other HTML, CSS or JS minification plugins (BWP minify, WP minify, ...) simultaneously with Autoptimize or disable that functionality your page caching plugin (W3 Total Cache, WP Fastest Cache, ...). Try enabling only CSS or only JS optimization to see which one causes the server error and follow the generic troubleshooting steps to find a workaround.
|
@@ -154,6 +162,12 @@ Make sure you're not running other HTML, CSS or JS minification plugins (BWP min
|
|
154 |
|
155 |
If you are running Apache, the htaccess file written by Autoptimize can in some cases conflict with the AllowOverrides settings of your Apache configuration (as is the case with the default configuration of some Ubuntu installations), which results in "internal server errors" on the autoptimize CSS- and JS-files. This can be solved by [setting AllowOverrides to All](http://httpd.apache.org/docs/2.4/mod/core.html#allowoverride).
|
156 |
|
|
|
|
|
|
|
|
|
|
|
|
|
157 |
= I get no error, but my pages are not optimized at all? =
|
158 |
|
159 |
Autoptimize does a number of checks before actually optimizing. When one of the following is true, your pages won't be optimized:
|
@@ -217,7 +231,7 @@ Although some online performance assessement tools will single out "query string
|
|
217 |
|
218 |
= (How) should I optimize Google Fonts? =
|
219 |
|
220 |
-
Google Fonts are typically loaded by a "render blocking" linked CSS-file. If you have a theme and plugins that use Google Fonts, you might end up with multiple such CSS-files. Autoptimize (since version 2.3) now let's you lessen the impact of Google Fonts by either removing them alltogether or by optimizing the way they are loaded. There are two optimization-flavors; the first one is "combine and link", which replaces all requests for Google Fonts into one request, which will still be render-blocking but will allow the fonts to be loaded immediately (meaning you won't see fonts change while the page is loading). The alternative is "combine and load async" which uses JavaScript to load the fonts in a non-render blocking manner but which might cause a "flash of unstyled text".
|
221 |
|
222 |
= Should I use "preconnect" =
|
223 |
|
@@ -235,14 +249,6 @@ When image optimization is on, Autoptimize will look for png, gif, jpeg (.jpg) f
|
|
235 |
|
236 |
Have a look at [Shortpixel's FAQ](https://shortpixel.helpscoutdocs.com/category/60-shortpixel-ai-cdn).
|
237 |
|
238 |
-
= Can I disable the minification of excluded JS/ CSS? =
|
239 |
-
|
240 |
-
As from AO 2.4 excluded JS/ CSS are minified if the (filename indicates the) file is not minified yet. You can disable this with these filters;
|
241 |
-
|
242 |
-
`
|
243 |
-
add_filter('autoptimize_filter_js_minify_excluded','__return_false');
|
244 |
-
add_filter('autoptimize_filter_css_minify_excluded','__return_false');`
|
245 |
-
|
246 |
= Can I disable AO listening to page cache purges? =
|
247 |
|
248 |
As from AO 2.4 AO "listens" to page cache purges to clear its own cache. You can disable this behavior with this filter;
|
@@ -261,12 +267,6 @@ By default AO uses non multibyte-safe string methods, but if your PHP has the mb
|
|
261 |
`
|
262 |
add_filter('autoptimize_filter_main_use_mbstring', '__return_true');`
|
263 |
|
264 |
-
= The Shortpixel image optimizing notice cannot be dismissed? =
|
265 |
-
|
266 |
-
In some rare cases the logic to dismiss the notice does not work due to the transient (WordPress cache) not keeping the dismissed state. If this happens you can use this code snippet to make the notice go away;
|
267 |
-
|
268 |
-
`add_filter( 'autoptimize_filter_main_imgopt_plug_notice', '__return_empty_string' );`
|
269 |
-
|
270 |
= Where can I get help? =
|
271 |
|
272 |
You can get help on the [wordpress.org support forum](http://wordpress.org/support/plugin/autoptimize). If you are 100% sure this your problem cannot be solved using Autoptimize configuration and that you in fact discovered a bug in the code, you can [create an issue on GitHub](https://github.com/futtta/autoptimize/issues). If you're looking for premium support, check out our [Autoptimize Pro Support and Web Performance Optimization services](http://autoptimize.com/).
|
@@ -283,6 +283,13 @@ Just [fork Autoptimize on Github](https://github.com/futtta/autoptimize) and cod
|
|
283 |
|
284 |
== Changelog ==
|
285 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
286 |
= 2.4.4 =
|
287 |
* bugfix: safer way of removing extra cronjobs
|
288 |
|
1 |
=== Autoptimize ===
|
2 |
Contributors: futtta, optimizingmatters, zytzagoo, turl
|
3 |
+
Tags: optimize, minify, performance, pagespeed, images, google fonts
|
4 |
Donate link: http://blog.futtta.be/2013/10/21/do-not-donate-to-me/
|
5 |
Requires at least: 4.0
|
6 |
+
Tested up to: 5.2
|
7 |
Requires PHP: 5.3
|
8 |
+
Stable tag: 2.5.0
|
9 |
|
10 |
+
Autoptimize speeds up your website by optimizing JS, CSS, images, HTML, Google Fonts and async-ing JS, removing emoji cruft and more.
|
11 |
|
12 |
== Description ==
|
13 |
|
14 |
+
Autoptimize makes optimizing your site really easy. It can aggregate, minify and cache scripts and styles, injects CSS in the page head by default but can also inline critical CSS and defer the aggregated full CSS, moves and defers scripts to the footer and minifies HTML. You can optimize and lazyload images, optimize Google Fonts, async non-aggregated JavaScript, remove WordPress core emoji cruft and more. As such it can improve your site's performance even when already on HTTP/2! There is extensive API available to enable you to tailor Autoptimize to each and every site's specific needs.
|
15 |
|
16 |
If you consider performance important, you really should use one of the many caching plugins to do page caching. Some good candidates to complement Autoptimize that way are e.g. [WP Super Cache](http://wordpress.org/plugins/wp-super-cache/), [HyperCache](http://wordpress.org/plugins/hyper-cache/), [Comet Cache](https://wordpress.org/plugins/comet-cache/) or [KeyCDN's Cache Enabler](https://wordpress.org/plugins/cache-enabler).
|
17 |
|
91 |
|
92 |
Moreover don't worry if your cache never is down to 0 files/ 0KB, as Autoptimize (as from version 2.2) will automatically preload the cache immediately after it has been cleared to speed further minification significantly up.
|
93 |
|
94 |
+
= My site looks broken when I purge Autoptimize's cache! =
|
95 |
+
|
96 |
+
When clearing AO's cache, no page cache should contain pages (HTML) that refers to the removed optimized CSS/ JS. Although for that purpose there is integretion between Autoptimize and some page caches, this integration does not cover 100% of setups so you might need to purge your page cache manually.
|
97 |
+
|
98 |
= Can I still use Cloudflare's Rocket Loader? =
|
99 |
|
100 |
Cloudflare Rocket Loader is a pretty advanced but invasive way to make JavaScript non-render-blocking, which [Cloudflare still considers Beta](https://wordpress.org/support/topic/rocket-loader-breaking-onload-js-on-linked-css/#post-9263738). Sometimes Autoptimize & Rocket Loader work together, sometimes they don't. The best approach is to disable Rocket Loader, configure Autoptimize and re-enable Rocket Loader (if you think it can help) after that and test if everything still works.
|
103 |
|
104 |
= I tried Autoptimize but my Google Pagespeed Scored barely improved =
|
105 |
|
106 |
+
Autoptimize is not a simple "fix my Pagespeed-problems" plugin; it "only" aggregates & minifies (local) JS & CSS and images and allows for some nice extra's as removing Google Fonts and deferring the loading of the CSS. As such Autoptimize will allow you to improve your performance (load time measured in seconds) and will probably also help you tackle some specific Pagespeed warnings. If you want to improve further, you will probably also have to look into e.g. page caching and your webserver configuration, which will improve real performance (again, load time as measured by e.g. https://webpagetest.org) and your "performance best practise" pagespeed ratings.
|
107 |
|
108 |
= What can I do with the API? =
|
109 |
|
143 |
|
144 |
If your blog doesn't function normally after having turned on Autoptimize, here are some pointers to identify & solve such issues using "advanced settings":
|
145 |
|
146 |
+
* If all works but you notice your blog is slower, ensure you have a page caching plugin installed (WP Super Cache or similar) and check the info on cache size (the soution for that problem also impacts performance for uncached pages) in this FAQ as well.
|
147 |
+
* In case your blog looks weird, i.e. when the layout gets messed up, there is problem with CSS optimization. Try excluding one or more CSS-files from being optimized. You can also force CSS not to be aggregated by wrapping it in noptimize-tags in your theme or widget or by adding filename (for external stylesheets) or string (for inline styles) to the exclude-list.
|
148 |
* In case some functionality on your site stops working (a carroussel, a menu, the search input, ...) you're likely hitting JavaScript optimization trouble. Change the "Aggregate inline JS" and/ or "Force JavaScript in head?" settings and try again. Excluding 'js/jquery/jquery.js' from optimization (see below) and optionally activating "[Add try/catch wrapping](http://blog.futtta.be/2014/08/18/when-should-you-trycatch-javascript/)") can also help. Alternatively -for the technically savvy- you can exclude specific scripts from being treated (moved and/ or aggregated) by Autoptimize by adding a string that will match the offending Javascript or excluding it from within your template files or widgets by wrapping the code between noptimize-tags. Identifying the offending JavaScript and choosing the correct exclusion-string can be trial and error, but in the majority of cases JavaScript optimization issues can be solved this way. When debugging JavaScript issues, your browsers error console is the most important tool to help you understand what is going on.
|
149 |
* If your theme or plugin require jQuery, you can try either forcing all in head and/ or excluding jquery.js (and jQuery-plugins if needed).
|
150 |
* If you can't get either CSS or JS optimization working, you can off course always continue using the other two optimization-techniques.
|
151 |
* If you tried the troubleshooting tips above and you still can't get CSS and JS working at all, you can ask for support on the [WordPress Autoptimize support forum](http://wordpress.org/support/plugin/autoptimize). See below for a description of what information you should provide in your "trouble ticket"
|
152 |
|
153 |
+
= I excluded files but they are still being autoptimized? =
|
154 |
+
|
155 |
+
AO minifies excluded JS/ CSS if the filename indicates the file is not minified yet. As of AO 2.5 you can disable this on the "JS, CSS & HTML"-tab under misc. options by unticking "minify excluded files".
|
156 |
+
|
157 |
= Help, I have a blank page or an internal server error after enabling Autoptimize!! =
|
158 |
|
159 |
Make sure you're not running other HTML, CSS or JS minification plugins (BWP minify, WP minify, ...) simultaneously with Autoptimize or disable that functionality your page caching plugin (W3 Total Cache, WP Fastest Cache, ...). Try enabling only CSS or only JS optimization to see which one causes the server error and follow the generic troubleshooting steps to find a workaround.
|
162 |
|
163 |
If you are running Apache, the htaccess file written by Autoptimize can in some cases conflict with the AllowOverrides settings of your Apache configuration (as is the case with the default configuration of some Ubuntu installations), which results in "internal server errors" on the autoptimize CSS- and JS-files. This can be solved by [setting AllowOverrides to All](http://httpd.apache.org/docs/2.4/mod/core.html#allowoverride).
|
164 |
|
165 |
+
= Can't log in on domain mapped multisites =
|
166 |
+
|
167 |
+
Domain mapped multisites require Autoptimize to be initialized at a different WordPress action, add this line of code to your wp-config.php to make it so to hook into `setup_theme` for example:
|
168 |
+
|
169 |
+
`define( 'AUTOPTIMIZE_SETUP_INITHOOK', 'setup_theme' );`
|
170 |
+
|
171 |
= I get no error, but my pages are not optimized at all? =
|
172 |
|
173 |
Autoptimize does a number of checks before actually optimizing. When one of the following is true, your pages won't be optimized:
|
231 |
|
232 |
= (How) should I optimize Google Fonts? =
|
233 |
|
234 |
+
Google Fonts are typically loaded by a "render blocking" linked CSS-file. If you have a theme and plugins that use Google Fonts, you might end up with multiple such CSS-files. Autoptimize (since version 2.3) now let's you lessen the impact of Google Fonts by either removing them alltogether or by optimizing the way they are loaded. There are two optimization-flavors; the first one is "combine and link", which replaces all requests for Google Fonts into one request, which will still be render-blocking but will allow the fonts to be loaded immediately (meaning you won't see fonts change while the page is loading). The alternative is "combine and load async" which uses JavaScript to load the fonts in a non-render blocking manner but which might cause a "flash of unstyled text".
|
235 |
|
236 |
= Should I use "preconnect" =
|
237 |
|
249 |
|
250 |
Have a look at [Shortpixel's FAQ](https://shortpixel.helpscoutdocs.com/category/60-shortpixel-ai-cdn).
|
251 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
252 |
= Can I disable AO listening to page cache purges? =
|
253 |
|
254 |
As from AO 2.4 AO "listens" to page cache purges to clear its own cache. You can disable this behavior with this filter;
|
267 |
`
|
268 |
add_filter('autoptimize_filter_main_use_mbstring', '__return_true');`
|
269 |
|
|
|
|
|
|
|
|
|
|
|
|
|
270 |
= Where can I get help? =
|
271 |
|
272 |
You can get help on the [wordpress.org support forum](http://wordpress.org/support/plugin/autoptimize). If you are 100% sure this your problem cannot be solved using Autoptimize configuration and that you in fact discovered a bug in the code, you can [create an issue on GitHub](https://github.com/futtta/autoptimize/issues). If you're looking for premium support, check out our [Autoptimize Pro Support and Web Performance Optimization services](http://autoptimize.com/).
|
283 |
|
284 |
== Changelog ==
|
285 |
|
286 |
+
= 2.5.0 =
|
287 |
+
* moved image optimization to a separate tab and move all code to a separate file.
|
288 |
+
* added lazyloading (using lazysizes)
|
289 |
+
* added webp support (requires image optimization and lazyloading to be active)
|
290 |
+
* added option to enable/ disable the minification of excluded JS/ CSS files (on by default)
|
291 |
+
* misc. bugfixes and smaller improvements
|
292 |
+
|
293 |
= 2.4.4 =
|
294 |
* bugfix: safer way of removing extra cronjobs
|
295 |
|