Breeze – WordPress Cache Plugin - Version 1.1.3

Version Description

  • Fix: Undefine error for inline JS when JS Group file is enabled.
  • Fix: Several files displayed when Group Files was enabled.
  • Fix: Varnish auto purge slowed down admin area while varnish is not running.
  • Fix: PDF files are not downloadable with CDN enabled.
  • Fix: miscellaneous UI issues.
  • Add: The Google Analytics script/tag is now excluded form Minification.
  • Add: Option to enable cache for admin user.
  • Add: Handling of 404 error of JS/CSS/HTML when cache files are not writeable.
  • Add: Exclude @import directive from CSS Minification.
Download this release

Release Info

Developer adeelkhan
Plugin Icon 128x128 Breeze – WordPress Cache Plugin
Version 1.1.3
Comparing to
See all releases

Code changes from version 1.1.2 to 1.1.3

assets/css/notice.css ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #breeze-plugins-notice {
2
+ /*padding: 10px 12px;*/
3
+ }
4
+
5
+ #breeze-plugins-notice .button,
6
+ #breeze-plugins-notice .button:hover {
7
+ text-decoration: none;
8
+ line-height: 20px;
9
+ height: 18px;
10
+ transform: scale(0.9);
11
+ }
12
+
13
+ #breeze-plugins-notice li {
14
+ line-height: 18px;
15
+ }
16
+
17
+ #breeze-plugins-notice .text-error {
18
+ color: #dc3232;
19
+ }
20
+
21
+ #breeze-plugins-notice ul{
22
+ list-style: disc;
23
+ padding-left: 10px;
24
+ }
assets/css/style.css CHANGED
@@ -325,3 +325,7 @@
325
  color: #fff;
326
  text-decoration: none;
327
  }
 
 
 
 
325
  color: #fff;
326
  text-decoration: none;
327
  }
328
+
329
+ .wp-core-ui .button-primary.focus, .wp-core-ui .button-primary.breeze-submit-btn:focus{
330
+ box-shadow:none;
331
+ }
assets/js/breeze-backend.js CHANGED
@@ -1,4 +1,27 @@
1
  jQuery(document).ready(function ($) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  // Topbar action
3
  $('#wp-admin-bar-breeze-purge-varnish-group').click(function(){
4
  breeze_purgeVarnish_callAjax();
@@ -101,4 +124,18 @@ jQuery(document).ready(function ($) {
101
  $('#breeze-hide-install-msg').unbind('click').click(function () {
102
  $(this).closest('div.notice').fadeOut();
103
  })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  });
1
  jQuery(document).ready(function ($) {
2
+
3
+ var $compatibility_warning = $('#breeze-plugins-notice');
4
+ if ($compatibility_warning.length) {
5
+ $(document).on('click tap', '.notice-dismiss', function () {
6
+ $.ajax({
7
+ type: "POST",
8
+ url: ajaxurl,
9
+ data: {action: "compatibility_warning_close", 'breeze_close_warning': '1'},
10
+ dataType: "json", // xml, html, script, json, jsonp, text
11
+ success: function (data) {
12
+
13
+ },
14
+ error: function (jqXHR, textStatus, errorThrown) {
15
+
16
+ },
17
+ // called when the request finishes (after success and error callbacks are executed)
18
+ complete: function (jqXHR, textStatus) {
19
+
20
+ }
21
+ });
22
+ });
23
+ }
24
+
25
  // Topbar action
26
  $('#wp-admin-bar-breeze-purge-varnish-group').click(function(){
27
  breeze_purgeVarnish_callAjax();
124
  $('#breeze-hide-install-msg').unbind('click').click(function () {
125
  $(this).closest('div.notice').fadeOut();
126
  })
127
+
128
+
129
+ function current_url_clean() {
130
+ var query_search = location.search;
131
+ if (query_search.indexOf('breeze_purge=1') !== -1 && query_search.indexOf('_wpnonce') !== -1) {
132
+ var params = new URLSearchParams(location.search);
133
+ params.delete('breeze_purge')
134
+ params.delete('_wpnonce')
135
+ history.replaceState(null, '', '?' + params + location.hash)
136
+ }
137
+ }
138
+
139
+ current_url_clean();
140
+
141
  });
assets/js/breeze-configuration.js CHANGED
@@ -1,4 +1,4 @@
1
- jQuery(document).ready(function($){
2
  // database clean tabs
3
  $('input[name="all_control"]').click(function () {
4
  var checked = $(this).is(':checked');
@@ -25,6 +25,7 @@ jQuery(document).ready(function($){
25
  });
26
  });
27
  }
 
28
  initRemoveBtn();
29
 
30
  function initSortableHandle() {
@@ -33,6 +34,7 @@ jQuery(document).ready(function($){
33
  stop: validateMoveButtons
34
  });
35
  }
 
36
  initSortableHandle();
37
 
38
  function initMoveButtons() {
@@ -47,6 +49,7 @@ jQuery(document).ready(function($){
47
  validateMoveButtons();
48
  });
49
  }
 
50
  initMoveButtons();
51
 
52
  function validateMoveButtons() {
@@ -55,6 +58,7 @@ jQuery(document).ready(function($){
55
  listURL.find('.breeze-input-group:first-child').find('.moveUp').addClass('blur');
56
  listURL.find('.breeze-input-group:last-child').find('.moveDown').addClass('blur');
57
  }
 
58
  validateMoveButtons();
59
 
60
  $('button.add-url').unbind('click').click(function () {
@@ -81,14 +85,14 @@ jQuery(document).ready(function($){
81
  html += ' <span class="dashicons dashicons-arrow-down moveDown"></span>';
82
  html += ' </span>';
83
  html += ' <input type="text" size="98"';
84
- html += 'class="breeze-input-url"';
85
  if (!defer) {
86
- html += 'name="move-to-footer-js[]"';
87
  } else {
88
- html += 'name="defer-js[]"';
89
  }
90
- html += 'placeholder="Enter URL..."';
91
- html += 'value="" />';
92
  html += ' <span class="dashicons dashicons-no item-remove" title="Remove"></span>';
93
  html += '</div>';
94
 
@@ -127,7 +131,7 @@ jQuery(document).ready(function($){
127
  // Cookie do
128
  function setTabFromCookie() {
129
  active_tab = getCookie('breeze_active_tab');
130
- if (!active_tab){
131
  active_tab = 'basic';
132
  }
133
 
@@ -166,98 +170,98 @@ jQuery(document).ready(function($){
166
  return "";
167
  }
168
 
169
- setTabFromCookie();
170
-
171
- // Sub-site settings toggle.
172
- var global_tabs = [
173
- 'faq'
174
- ];
175
- var save_settings_inherit_form_on_submit = true;
176
- var settings_inherit_form_did_change = false;
177
- var $settings_inherit_form = $( '#breeze-inherit-settings-toggle' );
178
- if ( $settings_inherit_form.length ) {
179
- $( 'input', $settings_inherit_form ).on( 'change', function() {
180
- var inherit = $( this ).val() == '1';
181
-
182
- $( '#breeze-tabs' ).toggleClass( 'tabs-hidden', inherit );
183
- $( '#breeze-tabs-content' ).toggleClass( 'tabs-hidden', inherit );
184
-
185
- $( '#breeze-tabs .nav-tab' ).each( function() {
186
- var tab_id = $( this ).data( 'tab-id' );
187
-
188
- if ( $.inArray( tab_id, global_tabs ) === -1 ) {
189
- $( this ).toggleClass( 'inactive', inherit );
190
- $( '#breeze-tabs-content #tab-content-' + tab_id ).toggleClass( 'inactive', inherit );
191
- }
192
- } );
193
-
194
- settings_inherit_form_did_change = ! $( this ).parents( '.radio-field' ).hasClass( 'active' );
195
-
196
- $( 'p.disclaimer', $settings_inherit_form ).toggle( settings_inherit_form_did_change );
197
- } );
198
-
199
- $( '#breeze-tabs-content form' ).on( 'submit', function( event ) {
200
- var $form = $( this );
201
-
202
- if ( save_settings_inherit_form_on_submit && settings_inherit_form_did_change ) {
203
- event.preventDefault();
204
-
205
- $.ajax( {
206
- url: window.location,
207
- method: 'post',
208
- data: $settings_inherit_form.serializeArray(),
209
-
210
- beforeSend: function() {
211
- $settings_inherit_form.addClass( 'loading' );
212
- },
213
-
214
- complete: function() {
215
- $settings_inherit_form.removeClass( 'loading' );
216
-
217
- // Continue form submit.
218
- settings_inherit_form_did_change = false;
219
- $form.submit();
220
- },
221
-
222
- success: function() {
223
- $( 'input:checked', $settings_inherit_form ).parents( '.radio-field' ).addClass( 'active' ).siblings().removeClass( 'active' );
224
- }
225
- } );
226
- } else {
227
- return;
228
- }
229
- } );
230
- }
231
-
232
- // Database optimization.
233
- $( '#breeze-database-optimize' ).on( 'click', function( event ) {
234
- save_settings_inherit_form_on_submit = false;
235
- } );
236
- $( '#tab-content-database .submit input' ).on( 'click', function( event ) {
237
- $( '#tab-content-database input[type=checkbox]' ).attr( 'checked', false );
238
- } );
239
-
240
- function remove_query_arg( url, arg ) {
241
- var urlparts = url.split( '?' );
242
- if ( urlparts.length >= 2 ) {
243
- var prefix = encodeURIComponent( arg ) + '=';
244
- var pars = urlparts[1].split( /[&;]/g );
245
-
246
- for ( var i = pars.length; i-- > 0; ) {
247
- if ( pars[i].lastIndexOf( prefix, 0 ) !== -1 ) {
248
- pars.splice( i, 1 );
249
- }
250
- }
251
-
252
- return urlparts[0] + ( pars.length > 0 ? '?' + pars.join( '&' ) : '' );
253
- }
254
- return url;
255
- }
256
-
257
- // Remove notice query args from URL.
258
- if ( window.history && typeof window.history.pushState === 'function' ) {
259
- var clean_url = remove_query_arg( window.location.href, 'save-settings' );
260
- clean_url = remove_query_arg( clean_url, 'database-cleanup' );
261
- window.history.pushState( null, null, clean_url );
262
- }
263
- });
1
+ jQuery(document).ready(function ($) {
2
  // database clean tabs
3
  $('input[name="all_control"]').click(function () {
4
  var checked = $(this).is(':checked');
25
  });
26
  });
27
  }
28
+
29
  initRemoveBtn();
30
 
31
  function initSortableHandle() {
34
  stop: validateMoveButtons
35
  });
36
  }
37
+
38
  initSortableHandle();
39
 
40
  function initMoveButtons() {
49
  validateMoveButtons();
50
  });
51
  }
52
+
53
  initMoveButtons();
54
 
55
  function validateMoveButtons() {
58
  listURL.find('.breeze-input-group:first-child').find('.moveUp').addClass('blur');
59
  listURL.find('.breeze-input-group:last-child').find('.moveDown').addClass('blur');
60
  }
61
+
62
  validateMoveButtons();
63
 
64
  $('button.add-url').unbind('click').click(function () {
85
  html += ' <span class="dashicons dashicons-arrow-down moveDown"></span>';
86
  html += ' </span>';
87
  html += ' <input type="text" size="98"';
88
+ html += 'class="breeze-input-url"';
89
  if (!defer) {
90
+ html += 'name="move-to-footer-js[]"';
91
  } else {
92
+ html += 'name="defer-js[]"';
93
  }
94
+ html += 'placeholder="Enter URL..."';
95
+ html += 'value="" />';
96
  html += ' <span class="dashicons dashicons-no item-remove" title="Remove"></span>';
97
  html += '</div>';
98
 
131
  // Cookie do
132
  function setTabFromCookie() {
133
  active_tab = getCookie('breeze_active_tab');
134
+ if (!active_tab) {
135
  active_tab = 'basic';
136
  }
137
 
170
  return "";
171
  }
172
 
173
+ setTabFromCookie();
174
+
175
+ // Sub-site settings toggle.
176
+ var global_tabs = [
177
+ 'faq'
178
+ ];
179
+ var save_settings_inherit_form_on_submit = true;
180
+ var settings_inherit_form_did_change = false;
181
+ var $settings_inherit_form = $('#breeze-inherit-settings-toggle');
182
+ if ($settings_inherit_form.length) {
183
+ $('input', $settings_inherit_form).on('change', function () {
184
+ var inherit = $(this).val() == '1';
185
+
186
+ $('#breeze-tabs').toggleClass('tabs-hidden', inherit);
187
+ $('#breeze-tabs-content').toggleClass('tabs-hidden', inherit);
188
+
189
+ $('#breeze-tabs .nav-tab').each(function () {
190
+ var tab_id = $(this).data('tab-id');
191
+
192
+ if ($.inArray(tab_id, global_tabs) === -1) {
193
+ $(this).toggleClass('inactive', inherit);
194
+ $('#breeze-tabs-content #tab-content-' + tab_id).toggleClass('inactive', inherit);
195
+ }
196
+ });
197
+
198
+ settings_inherit_form_did_change = !$(this).parents('.radio-field').hasClass('active');
199
+
200
+ $('p.disclaimer', $settings_inherit_form).toggle(settings_inherit_form_did_change);
201
+ });
202
+
203
+ $('#breeze-tabs-content form').on('submit', function (event) {
204
+ var $form = $(this);
205
+
206
+ if (save_settings_inherit_form_on_submit && settings_inherit_form_did_change) {
207
+ event.preventDefault();
208
+
209
+ $.ajax({
210
+ url: window.location,
211
+ method: 'post',
212
+ data: $settings_inherit_form.serializeArray(),
213
+
214
+ beforeSend: function () {
215
+ $settings_inherit_form.addClass('loading');
216
+ },
217
+
218
+ complete: function () {
219
+ $settings_inherit_form.removeClass('loading');
220
+
221
+ // Continue form submit.
222
+ settings_inherit_form_did_change = false;
223
+ $form.submit();
224
+ },
225
+
226
+ success: function () {
227
+ $('input:checked', $settings_inherit_form).parents('.radio-field').addClass('active').siblings().removeClass('active');
228
+ }
229
+ });
230
+ } else {
231
+ return;
232
+ }
233
+ });
234
+ }
235
+
236
+ // Database optimization.
237
+ $('#breeze-database-optimize').on('click', function (event) {
238
+ save_settings_inherit_form_on_submit = false;
239
+ });
240
+ $('#tab-content-database .submit input').on('click', function (event) {
241
+ $('#tab-content-database input[type=checkbox]').attr('checked', false);
242
+ });
243
+
244
+ function remove_query_arg(url, arg) {
245
+ var urlparts = url.split('?');
246
+ if (urlparts.length >= 2) {
247
+ var prefix = encodeURIComponent(arg) + '=';
248
+ var pars = urlparts[1].split(/[&;]/g);
249
+
250
+ for (var i = pars.length; i-- > 0;) {
251
+ if (pars[i].lastIndexOf(prefix, 0) !== -1) {
252
+ pars.splice(i, 1);
253
+ }
254
+ }
255
+
256
+ return urlparts[0] + (pars.length > 0 ? '?' + pars.join('&') : '');
257
+ }
258
+ return url;
259
+ }
260
+
261
+ // Remove notice query args from URL.
262
+ if (window.history && typeof window.history.pushState === 'function') {
263
+ var clean_url = remove_query_arg(window.location.href, 'save-settings');
264
+ clean_url = remove_query_arg(clean_url, 'database-cleanup');
265
+ window.history.pushState(null, null, clean_url);
266
+ }
267
+ });
breeze.php CHANGED
@@ -2,7 +2,7 @@
2
  /**
3
  * Plugin Name: Breeze
4
  * Description: Breeze is a WordPress cache plugin with extensive options to speed up your website. All the options including Varnish Cache are compatible with Cloudways hosting.
5
- * Version: 1.1.2
6
  * Text Domain: breeze
7
  * Domain Path: /languages
8
  * Author: Cloudways
@@ -33,86 +33,149 @@
33
 
34
  defined('ABSPATH') || die('No direct script access allowed!');
35
 
36
- if (!defined('BREEZE_PLUGIN_DIR'))
37
- define('BREEZE_PLUGIN_DIR', plugin_dir_path(__FILE__));
38
- if (!defined('BREEZE_VERSION'))
39
- define('BREEZE_VERSION','1.1.2');
40
- if (!defined('BREEZE_SITEURL'))
41
- define('BREEZE_SITEURL', get_site_url());
42
- if (!defined('BREEZE_MINIFICATION_CACHE'))
43
- define('BREEZE_MINIFICATION_CACHE', WP_CONTENT_DIR . '/cache/breeze-minification/');
44
- if (!defined('BREEZE_CACHEFILE_PREFIX'))
45
- define('BREEZE_CACHEFILE_PREFIX', 'breeze_');
46
- if (!defined('BREEZE_CACHE_CHILD_DIR'))
47
- define('BREEZE_CACHE_CHILD_DIR', '/cache/breeze-minification/');
48
- if (!defined('BREEZE_WP_CONTENT_NAME'))
49
- define('BREEZE_WP_CONTENT_NAME', '/' . wp_basename(WP_CONTENT_DIR));
50
- if (!defined('BREEZE_BASENAME'))
51
- define('BREEZE_BASENAME',plugin_basename(__FILE__));
52
-
53
- define('BREEZE_CACHE_DELAY', true);
54
- define('BREEZE_CACHE_NOGZIP', true);
55
- define('BREEZE_ROOT_DIR', str_replace(BREEZE_WP_CONTENT_NAME, '', WP_CONTENT_DIR));
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
  // Helper functions.
58
  require_once BREEZE_PLUGIN_DIR . 'inc/helpers.php';
59
  require_once BREEZE_PLUGIN_DIR . 'inc/functions.php';
60
 
61
  //action to purge cache
62
- require_once(BREEZE_PLUGIN_DIR . 'inc/cache/purge-varnish.php');
63
- require_once(BREEZE_PLUGIN_DIR . 'inc/cache/purge-cache.php');
64
- require_once(BREEZE_PLUGIN_DIR . 'inc/cache/purge-per-time.php');
65
 
66
  // Activate plugin hook
67
- register_activation_hook(__FILE__,array('Breeze_Admin','plugin_active_hook'));
68
  //Deactivate plugin hook
69
- register_deactivation_hook(__FILE__,array('Breeze_Admin','plugin_deactive_hook'));
70
 
 
71
 
72
- if(is_admin()){
73
- require_once(BREEZE_PLUGIN_DIR . 'inc/breeze-admin.php');
74
- require_once(BREEZE_PLUGIN_DIR . 'inc/breeze-configuration.php');
75
- //config to cache
76
- require_once(BREEZE_PLUGIN_DIR . 'inc/cache/config-cache.php');
77
 
78
  //cache when ecommerce installed
79
- require_once( BREEZE_PLUGIN_DIR . 'inc/cache/ecommerce-cache.php');
80
- new Breeze_Ecommerce_Cache();
81
- }else{
82
- $cdn_conf = breeze_get_option( 'cdn_integration' );
83
- $basic_conf = breeze_get_option( 'basic_settings' );
84
-
85
- if(!empty($cdn_conf['cdn-active']) || !empty($basic_conf['breeze-minify-js']) || !empty($basic_conf['breeze-minify-css']) || !empty($basic_conf['breeze-minify-html'])) {
86
- // Call back ob start
87
- ob_start('breeze_ob_start_callback');
88
- }
 
 
 
89
  }
90
 
91
  // Call back ob start - stack
92
- function breeze_ob_start_callback($buffer){
93
- $conf = breeze_get_option( 'cdn_integration' );
94
- // Get buffer from minify
95
- $buffer = apply_filters('breeze_minify_content_return',$buffer);
96
-
97
- if(!empty($conf) || !empty($conf['cdn-active'])){
98
- // Get buffer after remove query strings
99
- $buffer = apply_filters('breeze_cdn_content_return',$buffer);
100
- }
101
- // Return content
102
- return $buffer;
 
103
  }
104
 
105
  // Minify
106
- require_once(BREEZE_PLUGIN_DIR . 'inc/minification/breeze-minify-main.php');
107
- require_once(BREEZE_PLUGIN_DIR . 'inc/minification/breeze-minification-cache.php');
108
- new Breeze_Minify();
 
 
 
 
109
  // CDN Integration
110
- if( !class_exists('Breeze_CDN_Integration')){
111
- require_once ( BREEZE_PLUGIN_DIR. 'inc/cdn-integration/breeze-cdn-integration.php');
112
- require_once ( BREEZE_PLUGIN_DIR. 'inc/cdn-integration/breeze-cdn-rewrite.php');
113
- new Breeze_CDN_Integration();
 
 
114
  }
115
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  // @TODO: remove debug code.
117
  if ( isset( $_GET['settings_debug'] ) ) {
118
  $settings = array(
2
  /**
3
  * Plugin Name: Breeze
4
  * Description: Breeze is a WordPress cache plugin with extensive options to speed up your website. All the options including Varnish Cache are compatible with Cloudways hosting.
5
+ * Version: 1.1.3
6
  * Text Domain: breeze
7
  * Domain Path: /languages
8
  * Author: Cloudways
33
 
34
  defined('ABSPATH') || die('No direct script access allowed!');
35
 
36
+ if ( ! defined( 'BREEZE_PLUGIN_DIR' ) ) {
37
+ define( 'BREEZE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
38
+ }
39
+ if ( ! defined( 'BREEZE_VERSION' ) ) {
40
+ define( 'BREEZE_VERSION', '1.1.3' );
41
+ }
42
+ if ( ! defined( 'BREEZE_SITEURL' ) ) {
43
+ define( 'BREEZE_SITEURL', get_site_url() );
44
+ }
45
+ if ( ! defined( 'BREEZE_MINIFICATION_CACHE' ) ) {
46
+ define( 'BREEZE_MINIFICATION_CACHE', WP_CONTENT_DIR . '/cache/breeze-minification/' );
47
+ }
48
+ if ( ! defined( 'BREEZE_CACHEFILE_PREFIX' ) ) {
49
+ define( 'BREEZE_CACHEFILE_PREFIX', 'breeze_' );
50
+ }
51
+ if ( ! defined( 'BREEZE_CACHE_CHILD_DIR' ) ) {
52
+ define( 'BREEZE_CACHE_CHILD_DIR', '/cache/breeze-minification/' );
53
+ }
54
+ if ( ! defined( 'BREEZE_WP_CONTENT_NAME' ) ) {
55
+ define( 'BREEZE_WP_CONTENT_NAME', '/' . wp_basename( WP_CONTENT_DIR ) );
56
+ }
57
+ if ( ! defined( 'BREEZE_BASENAME' ) ) {
58
+ define( 'BREEZE_BASENAME', plugin_basename( __FILE__ ) );
59
+ }
60
+
61
+ define( 'BREEZE_CACHE_DELAY', true );
62
+ define( 'BREEZE_CACHE_NOGZIP', true );
63
+ define( 'BREEZE_ROOT_DIR', str_replace( BREEZE_WP_CONTENT_NAME, '', WP_CONTENT_DIR ) );
64
+
65
+
66
+ // Compatibility checks
67
+ require_once BREEZE_PLUGIN_DIR . 'inc/plugin-incompatibility/class-breeze-incompatibility-plugins.php';
68
 
69
  // Helper functions.
70
  require_once BREEZE_PLUGIN_DIR . 'inc/helpers.php';
71
  require_once BREEZE_PLUGIN_DIR . 'inc/functions.php';
72
 
73
  //action to purge cache
74
+ require_once( BREEZE_PLUGIN_DIR . 'inc/cache/purge-varnish.php' );
75
+ require_once( BREEZE_PLUGIN_DIR . 'inc/cache/purge-cache.php' );
76
+ require_once( BREEZE_PLUGIN_DIR . 'inc/cache/purge-per-time.php' );
77
 
78
  // Activate plugin hook
79
+ register_activation_hook( __FILE__, array( 'Breeze_Admin', 'plugin_active_hook' ) );
80
  //Deactivate plugin hook
81
+ register_deactivation_hook( __FILE__, array( 'Breeze_Admin', 'plugin_deactive_hook' ) );
82
 
83
+ require_once( BREEZE_PLUGIN_DIR . 'inc/breeze-admin.php' );
84
 
85
+ if ( is_admin() ) {
86
+
87
+ require_once( BREEZE_PLUGIN_DIR . 'inc/breeze-configuration.php' );
88
+ //config to cache
89
+ require_once( BREEZE_PLUGIN_DIR . 'inc/cache/config-cache.php' );
90
 
91
  //cache when ecommerce installed
92
+ require_once( BREEZE_PLUGIN_DIR . 'inc/cache/ecommerce-cache.php' );
93
+ add_action( 'init', function () {
94
+ new Breeze_Ecommerce_Cache();
95
+ }, 0 );
96
+
97
+ } else {
98
+ $cdn_conf = breeze_get_option( 'cdn_integration' );
99
+ $basic_conf = breeze_get_option( 'basic_settings' );
100
+
101
+ if ( ! empty( $cdn_conf['cdn-active'] ) || ! empty( $basic_conf['breeze-minify-js'] ) || ! empty( $basic_conf['breeze-minify-css'] ) || ! empty( $basic_conf['breeze-minify-html'] ) ) {
102
+ // Call back ob start
103
+ ob_start( 'breeze_ob_start_callback' );
104
+ }
105
  }
106
 
107
  // Call back ob start - stack
108
+ function breeze_ob_start_callback( $buffer ) {
109
+ $conf = breeze_get_option( 'cdn_integration' );
110
+ // Get buffer from minify
111
+ $buffer = apply_filters( 'breeze_minify_content_return', $buffer );
112
+
113
+ if ( ! empty( $conf ) || ! empty( $conf['cdn-active'] ) ) {
114
+ // Get buffer after remove query strings
115
+ $buffer = apply_filters( 'breeze_cdn_content_return', $buffer );
116
+ }
117
+
118
+ // Return content
119
+ return $buffer;
120
  }
121
 
122
  // Minify
123
+
124
+ require_once( BREEZE_PLUGIN_DIR . 'inc/minification/breeze-minify-main.php' );
125
+ require_once( BREEZE_PLUGIN_DIR . 'inc/minification/breeze-minification-cache.php' );
126
+ add_action( 'init', function () {
127
+ new Breeze_Minify();
128
+
129
+ }, 0 );
130
  // CDN Integration
131
+ if ( ! class_exists( 'Breeze_CDN_Integration' ) ) {
132
+ require_once( BREEZE_PLUGIN_DIR . 'inc/cdn-integration/breeze-cdn-integration.php' );
133
+ require_once( BREEZE_PLUGIN_DIR . 'inc/cdn-integration/breeze-cdn-rewrite.php' );
134
+ add_action( 'init', function () {
135
+ new Breeze_CDN_Integration();
136
+ }, 0 );
137
  }
138
 
139
+
140
+ /**
141
+ * This function will update htaccess files after the plugin update is done.
142
+ *
143
+ * This function runs when WordPress completes its upgrade process.
144
+ * It iterates through each plugin updated to see if ours is included.
145
+ *
146
+ * The plugin must be active while updating, otherwise this will do nothing.
147
+ *
148
+ * @see https://codex.wordpress.org/Plugin_API/Action_Reference/upgrader_process_complete
149
+ * @since 1.1.3
150
+ *
151
+ * @param array $upgrader_object
152
+ * @param array $options
153
+ */
154
+ function breeze_after_plugin_update_done( $upgrader_object, $options ) {
155
+ // If an update has taken place and the updated type is plugins and the plugins element exists.
156
+ if ( $options['action'] == 'update' && $options['type'] == 'plugin' && isset( $options['plugins'] ) ) {
157
+ // Iterate through the plugins being updated and check if ours is there
158
+ foreach ( $options['plugins'] as $plugin ) {
159
+ if ( $plugin == BREEZE_BASENAME ) {
160
+ // Add a new option to inform the install that a new version was installed.
161
+ add_option( 'breeze_new_update', 'yes', '', false );
162
+ }
163
+ }
164
+ }
165
+ }
166
+
167
+ add_action( 'upgrader_process_complete', 'breeze_after_plugin_update_done', 10, 2 );
168
+
169
+ function breeze_check_for_new_version() {
170
+ if ( ! empty( get_option( 'breeze_new_update', '' ) ) ) {
171
+ if(class_exists('Breeze_Configuration') && method_exists('Breeze_Configuration','update_htaccess'))
172
+ Breeze_Configuration::update_htaccess();
173
+ delete_option( 'breeze_new_update' );
174
+ }
175
+ }
176
+
177
+ add_action( 'init', 'breeze_check_for_new_version', 99 );
178
+
179
  // @TODO: remove debug code.
180
  if ( isset( $_GET['settings_debug'] ) ) {
181
  $settings = array(
inc/breeze-admin.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * @copyright 2017 Cloudways https://www.cloudways.com
4
  *
5
  * This plugin is inspired from WP Speed of Light by JoomUnited.
6
  *
@@ -18,84 +18,92 @@
18
  * along with this program; if not, write to the Free Software
19
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
  */
21
- defined('ABSPATH') || die('No direct script access allowed!');
22
 
23
  class Breeze_Admin {
24
- public function __construct(){
25
- add_action('init', function(){
26
- load_plugin_textdomain('breeze', false, dirname(plugin_basename(__FILE__)) . '/languages/');
27
- });
28
-
29
- // Add our custom action to clear cache
30
- add_action('breeze_clear_all_cache', array($this, 'breeze_clear_all_cache'));
31
- add_action('breeze_clear_varnish', array($this, 'breeze_clear_varnish'));
32
-
33
- add_action('admin_init', array($this, 'admin_init'));
34
- //register menu
35
- add_action('admin_menu', array($this, 'register_menu_page'));
36
- add_action('network_admin_menu', array($this, 'register_network_menu_page'));
37
-
38
- // Add notice when installing plugin
39
- $first_install = get_option('breeze_first_install');
40
- if ($first_install === false) {
41
- add_option('breeze_first_install', 'yes');
42
- }
43
- if ($first_install == 'yes') {
44
- add_action('admin_notices', array($this, 'installing_notices'));
45
- }
46
-
47
- $config = breeze_get_option( 'basic_settings' );
48
-
49
- if(isset($config['breeze-display-clean']) && $config['breeze-display-clean']){
50
- //register top bar menu
51
- add_action('admin_bar_menu', array($this, 'register_admin_bar_menu'), 999);
52
- }
53
-
54
- /** Load admin js * */
55
- add_action('admin_enqueue_scripts', array($this, 'loadAdminScripts'));
56
-
57
- add_action('wp_head', array($this,'define_ajaxurl'));
58
- $this->ajaxHandle();
59
-
60
- // Add setting buttons to plugins list page
61
- add_filter('plugin_action_links_' . BREEZE_BASENAME, array($this, 'breeze_add_action_links'));
62
- add_filter('network_admin_plugin_action_links_' . BREEZE_BASENAME, array($this, 'breeze_add_action_links_network'));
63
- }
64
-
65
- /**
66
- * Admin Init
67
- *
68
- */
69
- public function admin_init()
70
- {
71
- //Check plugin requirements
72
- if (version_compare(PHP_VERSION, '5.3', '<')) {
73
- if (current_user_can('activate_plugins') && is_plugin_active(plugin_basename(__FILE__))) {
74
- deactivate_plugins(__FILE__);
75
- add_action('admin_notices', array($this, 'breeze_show_error'));
76
- unset($_GET['activate']);
77
- }
78
- }
79
- //Do not load anything more
80
- return;
81
- }
82
-
83
- //define ajaxurl
84
- function define_ajaxurl() {
85
- if(current_user_can('manage_options')){
86
- echo '<script type="text/javascript">
87
- var ajaxurl = "' . admin_url('admin-ajax.php') . '";
 
 
 
 
 
 
 
 
88
  </script>';
89
- }
90
- }
91
 
92
- // Add notice message when install plugin
93
  public function installing_notices() {
94
- $class = 'notice notice-success';
95
- $message = __('Thanks for installing Breeze. It is always recommended not to use more than one caching plugin at the same time. We recommend you to purge cache if necessary.', 'breeze');
96
 
97
- printf( '<div class="%1$s"><p>%2$s <button class="button" id="breeze-hide-install-msg">'.__("Hide message", "breeze").'</button></p></div>', esc_attr( $class ), esc_html( $message ));
98
- update_option('breeze_first_install', 'no');
99
  }
100
 
101
 
@@ -103,47 +111,46 @@ class Breeze_Admin {
103
  if ( ! wp_script_is( 'jquery', 'enqueued' ) ) {
104
  wp_enqueue_script( 'jquery' );
105
  }
106
- wp_enqueue_script('breeze-backend', plugins_url('assets/js/breeze-backend.js', dirname(__FILE__)), array('jquery'), BREEZE_VERSION, true);
107
- wp_enqueue_style('breeze-topbar', plugins_url('assets/css/topbar.css', dirname(__FILE__)));
108
- $current_screen = get_current_screen();
109
- if($current_screen->base == 'settings_page_breeze' || $current_screen->base == 'settings_page_breeze-network'){
110
- //add css
111
- wp_enqueue_style('breeze-style', plugins_url('assets/css/style.css', dirname(__FILE__)));
112
- //js
113
- wp_enqueue_script('breeze-configuration', plugins_url('assets/js/breeze-configuration.js', dirname(__FILE__)), array('jquery'), BREEZE_VERSION, true);
 
114
 
115
  // Include the required jQuery UI Core & Libraries
116
- wp_enqueue_script( 'jquery-ui-core' );
117
- wp_enqueue_script( 'jquery-ui-tabs' );
118
- wp_enqueue_script( 'jquery-ui-accordion' );
119
- wp_enqueue_script( 'jquery-ui-sortable' );
120
- wp_enqueue_script( 'jquery-ui-widget' );
121
- }
122
-
123
- $token_name = array(
124
- 'breeze_purge_varnish' => wp_create_nonce("_breeze_purge_varnish"),
125
- 'breeze_purge_database' => wp_create_nonce("_breeze_purge_database"),
126
- 'breeze_purge_cache' => wp_create_nonce("_breeze_purge_cache"),
127
- );
128
-
129
- wp_localize_script('breeze-backend','breeze_token_name',$token_name);
130
- }
131
-
132
- /**
133
- * Register menu
134
- *
135
- */
136
- function register_menu_page()
137
- {
138
- //add submenu for cloudsway
139
- add_submenu_page( 'options-general.php', __('Breeze', 'breeze'), __('Breeze', 'breeze'), 'manage_options', 'breeze', array($this, 'breeze_load_page') );
140
- }
141
-
142
- function register_network_menu_page()
143
- {
144
- //add submenu for multisite network
145
- add_submenu_page('settings.php', __('Breeze', 'breeze'), __('Breeze', 'breeze'), 'manage_options', 'breeze', array($this, 'breeze_load_page'));
146
- }
147
 
148
 
149
  /**
@@ -168,12 +175,20 @@ class Breeze_Admin {
168
  );
169
  $wp_admin_bar->add_node( $args );
170
 
 
 
 
 
 
 
 
 
171
  // add purge all item
172
  $args = array(
173
  'id' => 'breeze-purge-all',
174
  'title' => ( ! is_multisite() || $is_network ) ? esc_html__( 'Purge All Cache', 'breeze' ) : esc_html__( 'Purge Site Cache', 'breeze' ),
175
  'parent' => 'breeze-topbar',
176
- 'href' => wp_nonce_url( add_query_arg( 'breeze_purge', 1, $is_network ? network_admin_url() : admin_url() ), 'breeze_purge_cache' ),
177
  'meta' => array( 'class' => 'breeze-toolbar-group' ),
178
  );
179
  $wp_admin_bar->add_node( $args );
@@ -192,7 +207,6 @@ class Breeze_Admin {
192
  );
193
  $wp_admin_bar->add_node( $args );
194
 
195
-
196
  // add child item (Purge Modules)
197
  $args = array(
198
  'id' => 'breeze-purge-varnish-group',
@@ -233,151 +247,160 @@ class Breeze_Admin {
233
  $wp_admin_bar->add_node( $args );
234
  }
235
 
236
- function breeze_load_page()
237
- {
238
- if (isset($_GET['page']) && $_GET['page'] == 'breeze') {
239
- require_once (BREEZE_PLUGIN_DIR . 'views/breeze-setting-views.php');
240
- }
241
- }
242
-
243
- public function breeze_show_error()
244
- {
245
- echo '<div class="error"><p><strong>Breeze</strong> need at least PHP 5.3 version, please update php before installing the plugin.</p></div>';
246
- }
247
- //ajax admin
248
- function ajaxHandle() {
249
- add_action('wp_ajax_breeze_purge_varnish', array('Breeze_Configuration', 'purge_varnish_action'));
250
- add_action('wp_ajax_breeze_purge_file', array('Breeze_Configuration', 'breeze_ajax_clean_cache'));
251
- add_action('wp_ajax_breeze_purge_database', array('Breeze_Configuration', 'breeze_ajax_purge_database'));
252
- }
253
- /*
254
- * Register active plugin hook
255
- */
256
- public static function plugin_active_hook(){
257
- WP_Filesystem();
258
- // Default basic
259
- $basic = breeze_get_option( 'basic_settings' );
260
- if(empty($basic)) $basic = array();
261
- $default_basic = array(
262
- 'breeze-active' => '1',
263
- 'breeze-ttl' => '',
264
- 'breeze-minify-html' => '0',
265
- 'breeze-minify-css' => '0',
266
- 'breeze-minify-js' => '0',
267
- 'breeze-gzip-compression' => '1',
268
- 'breeze-desktop-cache' => '1',
269
- 'breeze-browser-cache' => '1',
270
- 'breeze-mobile-cache' => '1',
271
- 'breeze-disable-admin' => '1',
272
- 'breeze-display-clean' => '1',
273
- 'breeze-include-inline-js' => '0',
274
- 'breeze-include-inline-css' => '0',
275
- );
276
- $basic= array_merge($default_basic,$basic);
277
-
278
- // Default Advanced
279
- $advanced = breeze_get_option( 'advanced_settings' );
280
- if(empty($advanced)) $advanced = array();
281
- $default_advanced = array(
282
- 'breeze-exclude-urls' => array(),
283
- 'breeze-group-css' => '0',
284
- 'breeze-group-js' => '0',
285
- 'breeze-exclude-css' => array(),
286
- 'breeze-exclude-js' => array(),
287
- 'breeze-move-to-footer-js' => array(),
288
- 'breeze-defer-js' => array()
289
- );
290
- $advanced= array_merge($default_advanced,$advanced);
291
-
292
- //CDN default
293
- $cdn = breeze_get_option( 'cdn_integration' );
294
- if(empty($cdn)) $cdn = array();
295
- $wp_content = substr(WP_CONTENT_DIR,strlen(ABSPATH));
296
- $default_cdn = array(
297
- 'cdn-active' => '0',
298
- 'cdn-url' =>'',
299
- 'cdn-content' => array('wp-includes',$wp_content),
300
- 'cdn-exclude-content' => array('.php'),
301
- 'cdn-relative-path' =>'1',
302
- );
303
- $cdn= array_merge($default_cdn,$cdn);
304
-
305
- // Varnish default
306
- $varnish = breeze_get_option( 'varnish_cache' );
307
- if(empty($varnish)) $varnish = array();
308
- $default_varnish = array(
309
- 'auto-purge-varnish' => '1',
310
- );
311
- $varnish= array_merge($default_varnish,$varnish);
312
-
313
- if(is_multisite()){
314
- $blogs = get_sites();
315
- foreach ($blogs as $blog){
316
- update_blog_option((int)$blog->blog_id,'breeze_basic_settings', $basic);
317
- update_blog_option((int)$blog->blog_id,'breeze_advanced_settings', $advanced);
318
- update_blog_option((int)$blog->blog_id,'breeze_cdn_integration', $cdn);
319
- update_blog_option((int)$blog->blog_id,'breeze_varnish_cache', $varnish);
320
- }
321
- }else{
322
- update_option('breeze_basic_settings', $basic);
323
- update_option('breeze_advanced_settings', $advanced);
324
- update_option('breeze_cdn_integration', $cdn);
325
- update_option('breeze_varnish_cache', $varnish);
326
- }
327
-
328
- //add header to htaccess if setting is enabled or by default if first installed
 
 
 
 
 
 
 
 
329
  Breeze_Configuration::update_htaccess();
330
- //automatic config start cache
331
- Breeze_ConfigCache::factory()->write();
332
- Breeze_ConfigCache::factory()->write_config_cache();
333
-
334
- if ( !empty($basic) && !empty($basic['breeze-active'] )) {
335
- Breeze_ConfigCache::factory()->toggle_caching( true );
336
- }
337
- }
338
-
339
- /*
340
- * Register deactive plugin hook
341
- */
342
- public static function plugin_deactive_hook(){
343
- WP_Filesystem();
344
- Breeze_ConfigCache::factory()->clean_up();
345
- Breeze_ConfigCache::factory()->clean_config();
346
- Breeze_ConfigCache::factory()->toggle_caching(false);
347
- Breeze_Configuration::update_htaccess( true );
348
- }
349
-
350
- /*
351
- * Render tab
352
- */
353
- public static function render($tab){
354
- require_once (BREEZE_PLUGIN_DIR . 'views/tabs/'.$tab.'.php');
355
- }
356
-
357
- // Check varnish cache exist
358
- public static function check_varnish(){
359
- if(isset($_SERVER['HTTP_X_VARNISH'])){
360
- return true;
361
- }
362
- return false;
363
- }
364
-
365
- // Applied to the list of links to display on the plugins page
366
- public function breeze_add_action_links($links){
367
- $mylinks = array(
368
- '<a href="' . admin_url( 'options-general.php?page=breeze' ) . '">Settings</a>',
369
- );
370
-
371
- return array_merge($mylinks, $links);
372
- }
 
373
 
374
  // Applied to the list of links to display on the network plugins page
375
- public function breeze_add_action_links_network($links){
376
  $mylinks = array(
377
  '<a href="' . network_admin_url( 'settings.php?page=breeze' ) . '">Settings</a>',
378
  );
379
 
380
- return array_merge($mylinks, $links);
381
  }
382
 
383
  // Clear all cache action
@@ -394,14 +417,14 @@ class Breeze_Admin {
394
  public function breeze_clear_varnish() {
395
  $main = new Breeze_PurgeVarnish();
396
 
397
- $is_network = ( is_network_admin() || ( ! empty( $_POST['is_network'] ) && 'true' === $_POST['is_network'] ) );
398
 
399
  if ( is_multisite() && $is_network ) {
400
  $sites = get_sites();
401
- foreach ($sites as $site) {
402
- switch_to_blog($site->blog_id);
403
- $homepage = home_url().'/?breeze';
404
- $main->purge_cache($homepage);
405
  restore_current_blog();
406
  }
407
  } else {
@@ -411,4 +434,10 @@ class Breeze_Admin {
411
  }
412
  }
413
 
414
- $admin = new Breeze_Admin();
 
 
 
 
 
 
1
  <?php
2
  /**
3
+ * @copyright 2017 Cloudways https://www.cloudways.com
4
  *
5
  * This plugin is inspired from WP Speed of Light by JoomUnited.
6
  *
18
  * along with this program; if not, write to the Free Software
19
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
  */
21
+ defined( 'ABSPATH' ) || die( 'No direct script access allowed!' );
22
 
23
  class Breeze_Admin {
24
+ public function __construct() {
25
+ add_action(
26
+ 'init',
27
+ function () {
28
+ load_plugin_textdomain( 'breeze', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
29
+ }
30
+ );
31
+
32
+ // Add our custom action to clear cache
33
+ add_action( 'breeze_clear_all_cache', array( $this, 'breeze_clear_all_cache' ) );
34
+ add_action( 'breeze_clear_varnish', array( $this, 'breeze_clear_varnish' ) );
35
+
36
+ if ( is_admin() ) {
37
+ add_action( 'admin_init', array( $this, 'admin_init' ) );
38
+
39
+ //register menu
40
+ add_action( 'admin_menu', array( $this, 'register_menu_page' ) );
41
+ add_action( 'network_admin_menu', array( $this, 'register_network_menu_page' ) );
42
+
43
+ // Add notice when installing plugin
44
+ $first_install = get_option( 'breeze_first_install' );
45
+
46
+ if ( $first_install === false ) {
47
+ add_option( 'breeze_first_install', 'yes' );
48
+ }
49
+
50
+ if ( $first_install == 'yes' ) {
51
+ add_action( 'admin_notices', array( $this, 'installing_notices' ) );
52
+ }
53
+
54
+ $config = breeze_get_option( 'basic_settings' );
55
+
56
+ if ( isset( $config['breeze-display-clean'] ) && $config['breeze-display-clean'] ) {
57
+ //register top bar menu
58
+ add_action( 'admin_bar_menu', array( $this, 'register_admin_bar_menu' ), 999 );
59
+ }
60
+ /** Load admin js * */
61
+ add_action( 'admin_enqueue_scripts', array( $this, 'loadAdminScripts' ) );
62
+
63
+ add_action( 'wp_head', array( $this, 'define_ajaxurl' ) );
64
+ $this->ajaxHandle();
65
+
66
+ // Add setting buttons to plugins list page
67
+ add_filter( 'plugin_action_links_' . BREEZE_BASENAME, array( $this, 'breeze_add_action_links' ) );
68
+ add_filter( 'network_admin_plugin_action_links_' . BREEZE_BASENAME, array( $this, 'breeze_add_action_links_network' ) );
69
+ }
70
+
71
+ }
72
+
73
+ /**
74
+ * Admin Init
75
+ *
76
+ */
77
+ public function admin_init() {
78
+ //Check plugin requirements
79
+ if ( version_compare( PHP_VERSION, '5.3', '<' ) ) {
80
+ if ( current_user_can( 'activate_plugins' ) && is_plugin_active( plugin_basename( __FILE__ ) ) ) {
81
+ deactivate_plugins( __FILE__ );
82
+ add_action( 'admin_notices', array( $this, 'breeze_show_error' ) );
83
+ unset( $_GET['activate'] );
84
+ }
85
+ }
86
+
87
+ //Do not load anything more
88
+ return;
89
+ }
90
+
91
+ //define ajaxurl
92
+ function define_ajaxurl() {
93
+ if ( current_user_can( 'manage_options' ) ) {
94
+ echo '<script type="text/javascript">
95
+ var ajaxurl = "' . admin_url( 'admin-ajax.php' ) . '";
96
  </script>';
97
+ }
98
+ }
99
 
100
+ // Add notice message when install plugin
101
  public function installing_notices() {
102
+ $class = 'notice notice-success';
103
+ $message = __( 'Thanks for installing Breeze. It is always recommended not to use more than one caching plugin at the same time. We recommend you to purge cache if necessary.', 'breeze' );
104
 
105
+ printf( '<div class="%1$s"><p>%2$s <button class="button" id="breeze-hide-install-msg">' . __( 'Hide message', 'breeze' ) . '</button></p></div>', esc_attr( $class ), esc_html( $message ) );
106
+ update_option( 'breeze_first_install', 'no' );
107
  }
108
 
109
 
111
  if ( ! wp_script_is( 'jquery', 'enqueued' ) ) {
112
  wp_enqueue_script( 'jquery' );
113
  }
114
+ wp_enqueue_script( 'breeze-backend', plugins_url( 'assets/js/breeze-backend.js', dirname( __FILE__ ) ), array( 'jquery' ), BREEZE_VERSION, true );
115
+ wp_enqueue_style( 'breeze-topbar', plugins_url( 'assets/css/topbar.css', dirname( __FILE__ ) ) );
116
+ wp_enqueue_style( 'breeze-notice', plugins_url( 'assets/css/notice.css', dirname( __FILE__ ) ) );
117
+ $current_screen = get_current_screen();
118
+ if ( $current_screen->base == 'settings_page_breeze' || $current_screen->base == 'settings_page_breeze-network' ) {
119
+ //add css
120
+ wp_enqueue_style( 'breeze-style', plugins_url( 'assets/css/style.css', dirname( __FILE__ ) ) );
121
+ //js
122
+ wp_enqueue_script( 'breeze-configuration', plugins_url( 'assets/js/breeze-configuration.js', dirname( __FILE__ ) ), array( 'jquery' ), BREEZE_VERSION, true );
123
 
124
  // Include the required jQuery UI Core & Libraries
125
+ wp_enqueue_script( 'jquery-ui-core' );
126
+ wp_enqueue_script( 'jquery-ui-tabs' );
127
+ wp_enqueue_script( 'jquery-ui-accordion' );
128
+ wp_enqueue_script( 'jquery-ui-sortable' );
129
+ wp_enqueue_script( 'jquery-ui-widget' );
130
+ }
131
+
132
+ $token_name = array(
133
+ 'breeze_purge_varnish' => wp_create_nonce( '_breeze_purge_varnish' ),
134
+ 'breeze_purge_database' => wp_create_nonce( '_breeze_purge_database' ),
135
+ 'breeze_purge_cache' => wp_create_nonce( '_breeze_purge_cache' ),
136
+ );
137
+
138
+ wp_localize_script( 'breeze-backend', 'breeze_token_name', $token_name );
139
+ }
140
+
141
+ /**
142
+ * Register menu
143
+ *
144
+ */
145
+ function register_menu_page() {
146
+ //add submenu for cloudsway
147
+ add_submenu_page( 'options-general.php', __( 'Breeze', 'breeze' ), __( 'Breeze', 'breeze' ), 'manage_options', 'breeze', array( $this, 'breeze_load_page' ) );
148
+ }
149
+
150
+ function register_network_menu_page() {
151
+ //add submenu for multisite network
152
+ add_submenu_page( 'settings.php', __( 'Breeze', 'breeze' ), __( 'Breeze', 'breeze' ), 'manage_options', 'breeze', array( $this, 'breeze_load_page' ) );
153
+ }
 
 
154
 
155
 
156
  /**
175
  );
176
  $wp_admin_bar->add_node( $args );
177
 
178
+ // Recreate the current URL in order to redirect to the same page on cache purge.
179
+ $current_protocol = is_ssl() ? 'https' : 'http';
180
+ $current_host = $_SERVER['HTTP_HOST'];
181
+ $current_script = $_SERVER['SCRIPT_NAME'];
182
+ $current_params = $_SERVER['QUERY_STRING'];
183
+ $current_screen_url = $current_protocol . '://' . $current_host . $current_script . '?' . $current_params;
184
+ $current_screen_url = remove_query_arg( array( 'breeze_purge', '_wpnonce' ), $current_screen_url );
185
+
186
  // add purge all item
187
  $args = array(
188
  'id' => 'breeze-purge-all',
189
  'title' => ( ! is_multisite() || $is_network ) ? esc_html__( 'Purge All Cache', 'breeze' ) : esc_html__( 'Purge Site Cache', 'breeze' ),
190
  'parent' => 'breeze-topbar',
191
+ 'href' => esc_url( wp_nonce_url( add_query_arg( 'breeze_purge', 1, $current_screen_url ), 'breeze_purge_cache' ) ),
192
  'meta' => array( 'class' => 'breeze-toolbar-group' ),
193
  );
194
  $wp_admin_bar->add_node( $args );
207
  );
208
  $wp_admin_bar->add_node( $args );
209
 
 
210
  // add child item (Purge Modules)
211
  $args = array(
212
  'id' => 'breeze-purge-varnish-group',
247
  $wp_admin_bar->add_node( $args );
248
  }
249
 
250
+ function breeze_load_page() {
251
+ if ( isset( $_GET['page'] ) && $_GET['page'] == 'breeze' ) {
252
+ require_once( BREEZE_PLUGIN_DIR . 'views/breeze-setting-views.php' );
253
+ }
254
+ }
255
+
256
+ public function breeze_show_error() {
257
+ echo '<div class="error"><p><strong>Breeze</strong> need at least PHP 5.3 version, please update php before installing the plugin.</p></div>';
258
+ }
259
+
260
+ //ajax admin
261
+ function ajaxHandle() {
262
+ add_action( 'wp_ajax_breeze_purge_varnish', array( 'Breeze_Configuration', 'purge_varnish_action' ) );
263
+ add_action( 'wp_ajax_breeze_purge_file', array( 'Breeze_Configuration', 'breeze_ajax_clean_cache' ) );
264
+ add_action( 'wp_ajax_breeze_purge_database', array( 'Breeze_Configuration', 'breeze_ajax_purge_database' ) );
265
+ }
266
+
267
+ /*
268
+ * Register active plugin hook
269
+ */
270
+ public static function plugin_active_hook() {
271
+ WP_Filesystem();
272
+ // Default basic
273
+ $basic = breeze_get_option( 'basic_settings' );
274
+ if ( empty( $basic ) ) {
275
+ $basic = array();
276
+ }
277
+ $default_basic = array(
278
+ 'breeze-active' => '1',
279
+ 'breeze-ttl' => '',
280
+ 'breeze-minify-html' => '0',
281
+ 'breeze-minify-css' => '0',
282
+ 'breeze-minify-js' => '0',
283
+ 'breeze-gzip-compression' => '1',
284
+ 'breeze-desktop-cache' => '1',
285
+ 'breeze-browser-cache' => '1',
286
+ 'breeze-mobile-cache' => '1',
287
+ 'breeze-disable-admin' => '1',
288
+ 'breeze-display-clean' => '1',
289
+ 'breeze-include-inline-js' => '0',
290
+ 'breeze-include-inline-css' => '0',
291
+ );
292
+ $basic = array_merge( $default_basic, $basic );
293
+
294
+ // Default Advanced
295
+ $advanced = breeze_get_option( 'advanced_settings' );
296
+ if ( empty( $advanced ) ) {
297
+ $advanced = array();
298
+ }
299
+ $default_advanced = array(
300
+ 'breeze-exclude-urls' => array(),
301
+ 'breeze-group-css' => '0',
302
+ 'breeze-group-js' => '0',
303
+ 'breeze-exclude-css' => array(),
304
+ 'breeze-exclude-js' => array(),
305
+ 'breeze-move-to-footer-js' => array(),
306
+ 'breeze-defer-js' => array(),
307
+ );
308
+ $advanced = array_merge( $default_advanced, $advanced );
309
+
310
+ //CDN default
311
+ $cdn = breeze_get_option( 'cdn_integration' );
312
+ if ( empty( $cdn ) ) {
313
+ $cdn = array();
314
+ }
315
+ $wp_content = substr( WP_CONTENT_DIR, strlen( ABSPATH ) );
316
+ $default_cdn = array(
317
+ 'cdn-active' => '0',
318
+ 'cdn-url' => '',
319
+ 'cdn-content' => array( 'wp-includes', $wp_content ),
320
+ 'cdn-exclude-content' => array( '.php' ),
321
+ 'cdn-relative-path' => '1',
322
+ );
323
+ $cdn = array_merge( $default_cdn, $cdn );
324
+
325
+ // Varnish default
326
+ $varnish = breeze_get_option( 'varnish_cache' );
327
+ if ( empty( $varnish ) ) {
328
+ $varnish = array();
329
+ }
330
+ $default_varnish = array(
331
+ 'auto-purge-varnish' => '1',
332
+ );
333
+ $varnish = array_merge( $default_varnish, $varnish );
334
+
335
+ if ( is_multisite() ) {
336
+ $blogs = get_sites();
337
+ foreach ( $blogs as $blog ) {
338
+ update_blog_option( (int) $blog->blog_id, 'breeze_basic_settings', $basic );
339
+ update_blog_option( (int) $blog->blog_id, 'breeze_advanced_settings', $advanced );
340
+ update_blog_option( (int) $blog->blog_id, 'breeze_cdn_integration', $cdn );
341
+ update_blog_option( (int) $blog->blog_id, 'breeze_varnish_cache', $varnish );
342
+ }
343
+ } else {
344
+ update_option( 'breeze_basic_settings', $basic );
345
+ update_option( 'breeze_advanced_settings', $advanced );
346
+ update_option( 'breeze_cdn_integration', $cdn );
347
+ update_option( 'breeze_varnish_cache', $varnish );
348
+ }
349
+
350
+ //add header to htaccess if setting is enabled or by default if first installed
351
  Breeze_Configuration::update_htaccess();
352
+ //automatic config start cache
353
+ Breeze_ConfigCache::factory()->write();
354
+ Breeze_ConfigCache::factory()->write_config_cache();
355
+
356
+ if ( ! empty( $basic ) && ! empty( $basic['breeze-active'] ) ) {
357
+ Breeze_ConfigCache::factory()->toggle_caching( true );
358
+ }
359
+ }
360
+
361
+ /*
362
+ * Register deactive plugin hook
363
+ */
364
+ public static function plugin_deactive_hook() {
365
+ WP_Filesystem();
366
+ Breeze_ConfigCache::factory()->clean_up();
367
+ Breeze_ConfigCache::factory()->clean_config();
368
+ Breeze_ConfigCache::factory()->toggle_caching( false );
369
+ Breeze_Configuration::update_htaccess( true );
370
+ }
371
+
372
+ /*
373
+ * Render tab
374
+ */
375
+ public static function render( $tab ) {
376
+ require_once( BREEZE_PLUGIN_DIR . 'views/tabs/' . $tab . '.php' );
377
+ }
378
+
379
+ // Check varnish cache exist
380
+ public static function check_varnish() {
381
+ if ( isset( $_SERVER['HTTP_X_VARNISH'] ) ) {
382
+ return true;
383
+ }
384
+
385
+ return false;
386
+ }
387
+
388
+ // Applied to the list of links to display on the plugins page
389
+ public function breeze_add_action_links( $links ) {
390
+ $mylinks = array(
391
+ '<a href="' . admin_url( 'options-general.php?page=breeze' ) . '">Settings</a>',
392
+ );
393
+
394
+ return array_merge( $mylinks, $links );
395
+ }
396
 
397
  // Applied to the list of links to display on the network plugins page
398
+ public function breeze_add_action_links_network( $links ) {
399
  $mylinks = array(
400
  '<a href="' . network_admin_url( 'settings.php?page=breeze' ) . '">Settings</a>',
401
  );
402
 
403
+ return array_merge( $mylinks, $links );
404
  }
405
 
406
  // Clear all cache action
417
  public function breeze_clear_varnish() {
418
  $main = new Breeze_PurgeVarnish();
419
 
420
+ $is_network = ( is_network_admin() || ( ! empty( $_POST['is_network'] ) && 'true' === $_POST['is_network'] ) );
421
 
422
  if ( is_multisite() && $is_network ) {
423
  $sites = get_sites();
424
+ foreach ( $sites as $site ) {
425
+ switch_to_blog( $site->blog_id );
426
+ $homepage = home_url() . '/?breeze';
427
+ $main->purge_cache( $homepage );
428
  restore_current_blog();
429
  }
430
  } else {
434
  }
435
  }
436
 
437
+ add_action(
438
+ 'init',
439
+ function () {
440
+ $admin = new Breeze_Admin();
441
+ },
442
+ 0
443
+ );
inc/breeze-configuration.php CHANGED
@@ -64,7 +64,7 @@ class Breeze_Configuration{
64
  'breeze-browser-cache' => (isset($_POST['browser-cache']) ? '1' : '0'),
65
  'breeze-desktop-cache' => (int)$_POST['desktop-cache'],
66
  'breeze-mobile-cache' => (int)$_POST['mobile-cache'],
67
- 'breeze-disable-admin' => '1',
68
  'breeze-display-clean' => '1',
69
  'breeze-include-inline-js' => (isset($_POST['include-inline-js']) ? '1' : '0'),
70
  'breeze-include-inline-css' => (isset($_POST['include-inline-css']) ? '1' : '0'),
@@ -93,6 +93,7 @@ class Breeze_Configuration{
93
 
94
  //delete cache after settings
95
  do_action('breeze_clear_all_cache');
 
96
  }
97
  }
98
  // Advanced options tab
@@ -145,6 +146,7 @@ class Breeze_Configuration{
145
 
146
  //delete cache after settings
147
  do_action('breeze_clear_all_cache');
 
148
  }
149
  }
150
 
@@ -192,6 +194,7 @@ class Breeze_Configuration{
192
 
193
  //delete cache after settings
194
  do_action('breeze_clear_all_cache');
 
195
  }
196
  }
197
 
64
  'breeze-browser-cache' => (isset($_POST['browser-cache']) ? '1' : '0'),
65
  'breeze-desktop-cache' => (int)$_POST['desktop-cache'],
66
  'breeze-mobile-cache' => (int)$_POST['mobile-cache'],
67
+ 'breeze-disable-admin' => (isset($_POST['breeze-admin-cache']) ? '0' : '1'), // 0 is enable, 1 is disable in this case.
68
  'breeze-display-clean' => '1',
69
  'breeze-include-inline-js' => (isset($_POST['include-inline-js']) ? '1' : '0'),
70
  'breeze-include-inline-css' => (isset($_POST['include-inline-css']) ? '1' : '0'),
93
 
94
  //delete cache after settings
95
  do_action('breeze_clear_all_cache');
96
+
97
  }
98
  }
99
  // Advanced options tab
146
 
147
  //delete cache after settings
148
  do_action('breeze_clear_all_cache');
149
+
150
  }
151
  }
152
 
194
 
195
  //delete cache after settings
196
  do_action('breeze_clear_all_cache');
197
+
198
  }
199
  }
200
 
inc/cache/execute-cache.php CHANGED
@@ -2,7 +2,7 @@
2
  /*
3
  * Based on some work of https://github.com/tlovett1/simple-cache/blob/master/inc/dropins/file-based-page-cache.php
4
  */
5
- defined('ABSPATH') || exit;
6
 
7
  // Load helper functions.
8
  require_once dirname( __DIR__ ) . '/functions.php';
@@ -12,22 +12,22 @@ require_once 'Mobile-Detect-2.8.25/Mobile_Detect.php';
12
  $detect = new \Cloudways\Breeze\Mobile_Detect\Mobile_Detect;
13
 
14
  // Don't cache robots.txt or htacesss
15
- if (strpos($_SERVER['REQUEST_URI'], 'robots.txt') !== false || strpos($_SERVER['REQUEST_URI'], '.htaccess') !== false) {
16
- return;
17
  }
18
 
19
  // Don't cache non-GET requests
20
- if (!isset($_SERVER['REQUEST_METHOD']) || $_SERVER['REQUEST_METHOD'] !== 'GET') {
21
- return;
22
  }
23
 
24
  $file_extension = $_SERVER['REQUEST_URI'];
25
- $file_extension = preg_replace('#^(.*?)\?.*$#', '$1', $file_extension);
26
- $file_extension = trim(preg_replace('#^.*\.(.*)$#', '$1', $file_extension));
27
 
28
  // Don't cache disallowed extensions. Prevents wp-cron.php, xmlrpc.php, etc.
29
- if (!preg_match('#index\.php$#i', $_SERVER['REQUEST_URI']) && in_array($file_extension, array('php', 'xml', 'xsl'))) {
30
- return;
31
  }
32
 
33
  // @TODO: Remove debugging code.
@@ -36,75 +36,75 @@ if ( isset( $_GET['debug_config'] ) ) {
36
  exit;
37
  }
38
 
39
- $url_path = breeze_get_url_path();
40
  $user_logged = false;
41
- $filename = $url_path . 'guest';
42
  // Don't cache
43
- if (!empty($_COOKIE)) {
44
- $wp_cookies = array('wordpressuser_', 'wordpresspass_', 'wordpress_sec_', 'wordpress_logged_in_');
45
 
46
- foreach ($_COOKIE as $key => $value) {
47
- // Logged in!
48
- if (strpos($key, 'wordpress_logged_in_') !== false) {
49
- $user_logged = true;
50
- }
51
 
52
- }
53
 
54
- if ($user_logged) {
55
- foreach ($_COOKIE as $k => $v) {
56
- if (strpos($k, 'wordpress_logged_in_') !== false) {
57
- $nameuser = substr($v, 0, strpos($v, '|'));
58
- $filename = $url_path . strtolower($nameuser);
59
- }
60
- }
61
- }
62
- if (!empty($_COOKIE['breeze_commented_posts'])) {
63
- foreach ($_COOKIE['breeze_commented_posts'] as $path) {
64
- if (rtrim($path, '/') === rtrim($_SERVER['REQUEST_URI'], '/')) {
65
- // User commented on this post
66
- return;
67
- }
68
- }
69
- }
70
  }
71
 
72
  //check disable cache for page
73
- $domain = (((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || $_SERVER['SERVER_PORT'] == 443) ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'];
74
  //decode url with russian language
75
- $current_url = $domain . rawurldecode($_SERVER['REQUEST_URI']);
76
- $opts_config = $GLOBALS['breeze_config'];
77
- $check_exclude = check_exclude_page($opts_config, $current_url);
78
 
79
  //load cache
80
- if (!$check_exclude) {
81
- $devices = $opts_config['cache_options'];
82
- $X1 = '';
83
- // Detect devices
84
- if ($detect->isMobile() && !$detect->isTablet()) {
85
- // The first X will be D for Desktop cache
86
- // M for Mobile cache
87
- // T for Tablet cache
88
- if ((int)$devices['breeze-mobile-cache'] == 1) {
89
- $X1 = 'D';
90
- $filename .= '_breeze_cache_desktop';
91
- }
92
- if ((int)$devices['breeze-mobile-cache'] == 2) {
93
- $X1 = 'M';
94
- $filename .= '_breeze_cache_mobile';
95
- }
96
 
97
- } else {
98
- if ((int)$devices['breeze-desktop-cache'] == 1) {
99
- $X1 = 'D';
100
- $filename .= '_breeze_cache_desktop';
101
- }
102
- }
103
 
104
- breeze_serve_cache($filename, $url_path, $X1, $devices);
105
- ob_start('breeze_cache');
106
  } else {
107
- header('Cache-Control: no-cache');
108
  }
109
 
110
  /**
@@ -112,39 +112,40 @@ if (!$check_exclude) {
112
  *
113
  * @param string $buffer
114
  * @param int $flags
 
115
  * @since 1.0
116
  * @return string
117
  */
118
- function breeze_cache($buffer, $flags)
119
- {
120
- // No cache for pages without 200 response status
121
- if (http_response_code() !== 200) {
122
- return $buffer;
123
- }
124
-
125
- require_once 'Mobile-Detect-2.8.25/Mobile_Detect.php';
126
- $detect = new \Cloudways\Breeze\Mobile_Detect\Mobile_Detect;
127
- //not cache per administrator if option disable optimization for admin users clicked
128
- if (!empty($GLOBALS['breeze_config']) && (int)$GLOBALS['breeze_config']['disable_per_adminuser']) {
129
  $current_user = wp_get_current_user();
130
  if (in_array('administrator', $current_user->roles)) {
131
  return $buffer;
132
  }
133
- }
134
-
135
- if (strlen($buffer) < 255) {
136
- return $buffer;
137
- }
138
-
139
- // Don't cache search, 404, or password protected
140
- if (is_404() || is_search() || post_password_required()) {
141
- return $buffer;
142
- }
143
- global $wp_filesystem;
144
- if (empty($wp_filesystem)) {
145
- require_once(ABSPATH . '/wp-admin/includes/file.php');
146
- WP_Filesystem();
147
- }
148
  $url_path = breeze_get_url_path();
149
 
150
  $cache_base_path = breeze_get_cache_base_path();
@@ -158,103 +159,104 @@ function breeze_cache($buffer, $flags)
158
  }
159
  $path .= '/';
160
 
161
- $modified_time = time(); // Make sure modified time is consistent
162
-
163
- if (preg_match('#</html>#i', $buffer)) {
164
- $buffer .= "\n<!-- Cache served by breeze CACHE - Last modified: " . gmdate('D, d M Y H:i:s', $modified_time) . " GMT -->\n";
165
- }
166
- $headers = array(
167
- array(
168
- 'name' => 'Content-Length',
169
- 'value' => strlen($buffer)
170
- ),
171
- array(
172
- 'name' => 'Content-Type',
173
- 'value' => 'text/html; charset=utf-8'
174
- ),
175
- array(
176
- 'name' => 'Last-Modified',
177
- 'value' => gmdate('D, d M Y H:i:s', $modified_time) . ' GMT'
178
- )
179
- );
180
-
181
- if(!isset($_SERVER['HTTP_X_VARNISH'])) {
182
- $headers = array_merge(array(
183
- array(
184
- 'name' => 'Expires',
185
- 'value' => 'Wed, 17 Aug 2005 00:00:00 GMT'
186
- ),
187
- array(
188
- 'name' => 'Cache-Control',
189
- 'value' => 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'
190
- ),
191
- array(
192
- 'name' => 'Pragma',
193
- 'value' => 'no-cache'
194
- )
195
- ));
196
- }
197
-
198
- $data = serialize(array('body' => $buffer, 'headers' => $headers));
199
- //cache per users
200
- if (is_user_logged_in()) {
201
- $current_user = wp_get_current_user();
202
- if ($current_user->user_login) {
203
- $url_path .= $current_user->user_login;
204
- }
205
- } else {
206
- $url_path .= 'guest';
207
- }
208
- $devices = $GLOBALS['breeze_config']['cache_options'];
209
- // Detect devices
210
- if ($detect->isMobile() && !$detect->isTablet()) {
211
- if ($devices['breeze-mobile-cache'] == 1) {
212
- $X1 = 'D';
213
- $url_path .= '_breeze_cache_desktop';
214
- }
215
- if ($devices['breeze-mobile-cache'] == 2) {
216
- $X1 = 'M';
217
- $url_path .= '_breeze_cache_mobile';
218
- }
219
- } else {
220
- if ($devices['breeze-desktop-cache'] == 1) {
221
- $X1 = 'D';
222
- $url_path .= '_breeze_cache_desktop';
223
- }
224
- }
225
-
226
- if (strpos($url_path, '_breeze_cache_') !== false) {
227
- if (!empty($GLOBALS['breeze_config']['cache_options']['breeze-gzip-compression']) && function_exists('gzencode')) {
228
- $wp_filesystem->put_contents($path . md5($url_path . '/index.gzip.html') . '.php', $data);
229
- $wp_filesystem->touch($path . md5($url_path . '/index.gzip.html') . '.php', $modified_time);
230
- } else {
231
- $wp_filesystem->put_contents($path . md5($url_path . '/index.html') . '.php', $data);
232
- $wp_filesystem->touch($path . md5($url_path . '/index.html') . '.php', $modified_time);
233
- }
234
- } else {
235
- return $buffer;
236
- }
237
- //set cache provider header if not exists cache file
238
- header('Cache-Provider:CLOUDWAYS-CACHE-' . $X1 . 'C');
239
-
240
- // Do not send this header in case we are behind a varnish proxy
241
- if(!isset($_SERVER['HTTP_X_VARNISH'])) {
242
- header('Cache-Control: no-cache'); // Check back every time to see if re-download is necessary
243
- }
244
-
245
- header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified_time) . ' GMT');
246
-
247
- if (function_exists('ob_gzhandler') && !empty($GLOBALS['breeze_config']['cache_options']['breeze-gzip-compression'])) {
248
- $ini_output_compression = ini_get('zlib.output_compression');
249
- $array_values = array('1', 'On', 'on');
250
- if (in_array($ini_output_compression, $array_values)) {
251
- return $buffer;
252
- } else {
253
- return ob_gzhandler($buffer, $flags);
254
- }
255
- } else {
256
- return $buffer;
257
- }
 
258
  }
259
 
260
  /**
@@ -263,13 +265,12 @@ function breeze_cache($buffer, $flags)
263
  * @since 1.0
264
  * @return string
265
  */
266
- function breeze_get_url_path()
267
- {
268
 
269
- $host = (isset($_SERVER['HTTP_HOST'])) ? $_SERVER['HTTP_HOST'] : '';
270
- $domain = (((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443)) ? 'https://' : 'http://');
271
 
272
- return $domain . rtrim($host, '/') . $_SERVER['REQUEST_URI'];
273
  }
274
 
275
  /**
@@ -277,95 +278,94 @@ function breeze_get_url_path()
277
  *
278
  * @since 1.0
279
  */
280
- function breeze_serve_cache($filename, $url_path, $X1,$opts)
281
- {
282
- if (strpos($filename, '_breeze_cache_') === false) {
283
- return;
284
- }
285
-
286
- if (function_exists('gzencode') && !empty($GLOBALS['breeze_config']['cache_options']['breeze-gzip-compression'])) {
287
- $file_name = md5($filename . '/index.gzip.html') . '.php';
288
- } else {
289
- $file_name = md5($filename . '/index.html') . '.php';
290
- }
291
-
292
-
293
- $path = breeze_get_cache_base_path() . md5($url_path) . '/' . $file_name;
294
-
295
- $modified_time = (int)@filemtime($path);
296
-
297
- if (!empty($opts['breeze-browser-cache']) &&!empty($modified_time) && !empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $modified_time) {
298
- header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified', true, 304);
299
- exit;
300
- }
301
-
302
- if (@file_exists($path)) {
303
-
304
- $cacheFile = file_get_contents($path);
305
-
306
-
307
- if ($cacheFile != false) {
308
- $datas = unserialize($cacheFile);
309
- foreach ($datas['headers'] as $data) {
310
- header($data['name'] . ': ' . $data['value']);
311
- }
312
- //set cache provider header
313
- header('Cache-Provider:CLOUDWAYS-CACHE-' . $X1 . 'E');
314
-
315
- $client_support_gzip = true;
316
-
317
- //check gzip request from client
318
- if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) && (strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') === false || strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate') === false)) {
319
- $client_support_gzip = false;
320
- }
321
-
322
- if ($client_support_gzip && function_exists('gzdecode') && !empty($GLOBALS['breeze_config']['cache_options']['breeze-gzip-compression'])) {
323
- //if file is zip
324
-
325
- $content = gzencode($datas['body'], 9);
326
- header('Content-Encoding: gzip');
327
- header("cache-control: must-revalidate");
328
- header('Content-Length: ' . strlen($content));
329
- header('Vary: Accept-Encoding');
330
- echo $content;
331
- } else {
332
- //render page cache
333
- echo $datas['body'];
334
- }
335
- exit;
336
- }
337
- }
338
  }
339
 
340
- function check_exclude_page($opts_config,$current_url){
341
  //check disable cache for page
342
- if (!empty($opts_config['exclude_url'])) {
343
- foreach ($opts_config['exclude_url'] as $v) {
344
  // Clear blank character
345
- $v = trim($v);
346
- if( preg_match( '/(\&?\/?\(\.?\*\)|\/\*|\*)$/', $v , $matches)){
347
  // End of rules is *, /*, [&][/](*) , [&][/](.*)
348
- $pattent = substr($v , 0, strpos($v,$matches[0]));
349
- if($v[0] == '/'){
350
  // A path of exclude url with regex
351
- if((@preg_match( '@'.$pattent.'@', $current_url, $matches ) > 0)){
352
  return true;
353
  }
354
- }else{
355
  // Full exclude url with regex
356
- if(strpos( $current_url,$pattent) !== false){
357
  return true;
358
  }
359
  }
360
 
361
- }else{
362
- if($v[0] == '/'){
363
  // A path of exclude
364
- if((@preg_match( '@'.$v.'@', $current_url, $matches ) > 0)){
365
  return true;
366
  }
367
  } else { // Whole path
368
- if($v == $current_url){
369
  return true;
370
  }
371
  }
2
  /*
3
  * Based on some work of https://github.com/tlovett1/simple-cache/blob/master/inc/dropins/file-based-page-cache.php
4
  */
5
+ defined( 'ABSPATH' ) || exit;
6
 
7
  // Load helper functions.
8
  require_once dirname( __DIR__ ) . '/functions.php';
12
  $detect = new \Cloudways\Breeze\Mobile_Detect\Mobile_Detect;
13
 
14
  // Don't cache robots.txt or htacesss
15
+ if ( strpos( $_SERVER['REQUEST_URI'], 'robots.txt' ) !== false || strpos( $_SERVER['REQUEST_URI'], '.htaccess' ) !== false ) {
16
+ return;
17
  }
18
 
19
  // Don't cache non-GET requests
20
+ if ( ! isset( $_SERVER['REQUEST_METHOD'] ) || $_SERVER['REQUEST_METHOD'] !== 'GET' ) {
21
+ return;
22
  }
23
 
24
  $file_extension = $_SERVER['REQUEST_URI'];
25
+ $file_extension = preg_replace( '#^(.*?)\?.*$#', '$1', $file_extension );
26
+ $file_extension = trim( preg_replace( '#^.*\.(.*)$#', '$1', $file_extension ) );
27
 
28
  // Don't cache disallowed extensions. Prevents wp-cron.php, xmlrpc.php, etc.
29
+ if ( ! preg_match( '#index\.php$#i', $_SERVER['REQUEST_URI'] ) && in_array( $file_extension, array( 'php', 'xml', 'xsl' ) ) ) {
30
+ return;
31
  }
32
 
33
  // @TODO: Remove debugging code.
36
  exit;
37
  }
38
 
39
+ $url_path = breeze_get_url_path();
40
  $user_logged = false;
41
+ $filename = $url_path . 'guest';
42
  // Don't cache
43
+ if ( ! empty( $_COOKIE ) ) {
44
+ $wp_cookies = array( 'wordpressuser_', 'wordpresspass_', 'wordpress_sec_', 'wordpress_logged_in_' );
45
 
46
+ foreach ( $_COOKIE as $key => $value ) {
47
+ // Logged in!
48
+ if ( strpos( $key, 'wordpress_logged_in_' ) !== false ) {
49
+ $user_logged = true;
50
+ }
51
 
52
+ }
53
 
54
+ if ( $user_logged ) {
55
+ foreach ( $_COOKIE as $k => $v ) {
56
+ if ( strpos( $k, 'wordpress_logged_in_' ) !== false ) {
57
+ $nameuser = substr( $v, 0, strpos( $v, '|' ) );
58
+ $filename = $url_path . strtolower( $nameuser );
59
+ }
60
+ }
61
+ }
62
+ if ( ! empty( $_COOKIE['breeze_commented_posts'] ) ) {
63
+ foreach ( $_COOKIE['breeze_commented_posts'] as $path ) {
64
+ if ( rtrim( $path, '/' ) === rtrim( $_SERVER['REQUEST_URI'], '/' ) ) {
65
+ // User commented on this post
66
+ return;
67
+ }
68
+ }
69
+ }
70
  }
71
 
72
  //check disable cache for page
73
+ $domain = ( ( ( ! empty( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] !== 'off' ) || $_SERVER['SERVER_PORT'] == 443 ) ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'];
74
  //decode url with russian language
75
+ $current_url = $domain . rawurldecode( $_SERVER['REQUEST_URI'] );
76
+ $opts_config = $GLOBALS['breeze_config'];
77
+ $check_exclude = check_exclude_page( $opts_config, $current_url );
78
 
79
  //load cache
80
+ if ( ! $check_exclude ) {
81
+ $devices = $opts_config['cache_options'];
82
+ $X1 = '';
83
+ // Detect devices
84
+ if ( $detect->isMobile() && ! $detect->isTablet() ) {
85
+ // The first X will be D for Desktop cache
86
+ // M for Mobile cache
87
+ // T for Tablet cache
88
+ if ( (int) $devices['breeze-mobile-cache'] == 1 ) {
89
+ $X1 = 'D';
90
+ $filename .= '_breeze_cache_desktop';
91
+ }
92
+ if ( (int) $devices['breeze-mobile-cache'] == 2 ) {
93
+ $X1 = 'M';
94
+ $filename .= '_breeze_cache_mobile';
95
+ }
96
 
97
+ } else {
98
+ if ( (int) $devices['breeze-desktop-cache'] == 1 ) {
99
+ $X1 = 'D';
100
+ $filename .= '_breeze_cache_desktop';
101
+ }
102
+ }
103
 
104
+ breeze_serve_cache( $filename, $url_path, $X1, $devices );
105
+ ob_start( 'breeze_cache' );
106
  } else {
107
+ header( 'Cache-Control: no-cache' );
108
  }
109
 
110
  /**
112
  *
113
  * @param string $buffer
114
  * @param int $flags
115
+ *
116
  * @since 1.0
117
  * @return string
118
  */
119
+ function breeze_cache( $buffer, $flags ) {
120
+ // No cache for pages without 200 response status
121
+ if ( http_response_code() !== 200 ) {
122
+ return $buffer;
123
+ }
124
+
125
+ require_once 'Mobile-Detect-2.8.25/Mobile_Detect.php';
126
+ $detect = new \Cloudways\Breeze\Mobile_Detect\Mobile_Detect;
127
+ //not cache per administrator if option disable optimization for admin users clicked
128
+ if ( ! empty( $GLOBALS['breeze_config'] ) && (int) $GLOBALS['breeze_config']['disable_per_adminuser'] ) {
129
+
130
  $current_user = wp_get_current_user();
131
  if (in_array('administrator', $current_user->roles)) {
132
  return $buffer;
133
  }
134
+ }
135
+
136
+ if ( strlen( $buffer ) < 255 ) {
137
+ return $buffer;
138
+ }
139
+
140
+ // Don't cache search, 404, or password protected
141
+ if ( is_404() || is_search() || post_password_required() ) {
142
+ return $buffer;
143
+ }
144
+ global $wp_filesystem;
145
+ if ( empty( $wp_filesystem ) ) {
146
+ require_once( ABSPATH . '/wp-admin/includes/file.php' );
147
+ WP_Filesystem();
148
+ }
149
  $url_path = breeze_get_url_path();
150
 
151
  $cache_base_path = breeze_get_cache_base_path();
159
  }
160
  $path .= '/';
161
 
162
+ $modified_time = time(); // Make sure modified time is consistent
163
+
164
+ if ( preg_match( '#</html>#i', $buffer ) ) {
165
+ $buffer .= "\n<!-- Cache served by breeze CACHE - Last modified: " . gmdate( 'D, d M Y H:i:s', $modified_time ) . " GMT -->\n";
166
+ }
167
+ $headers = array(
168
+ array(
169
+ 'name' => 'Content-Length',
170
+ 'value' => strlen( $buffer )
171
+ ),
172
+ array(
173
+ 'name' => 'Content-Type',
174
+ 'value' => 'text/html; charset=utf-8'
175
+ ),
176
+ array(
177
+ 'name' => 'Last-Modified',
178
+ 'value' => gmdate( 'D, d M Y H:i:s', $modified_time ) . ' GMT'
179
+ )
180
+ );
181
+
182
+ if ( ! isset( $_SERVER['HTTP_X_VARNISH'] ) ) {
183
+ $headers = array_merge( array(
184
+ array(
185
+ 'name' => 'Expires',
186
+ 'value' => 'Wed, 17 Aug 2005 00:00:00 GMT'
187
+ ),
188
+ array(
189
+ 'name' => 'Cache-Control',
190
+ 'value' => 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'
191
+ ),
192
+ array(
193
+ 'name' => 'Pragma',
194
+ 'value' => 'no-cache'
195
+ )
196
+ ) );
197
+ }
198
+
199
+ $data = serialize( array( 'body' => $buffer, 'headers' => $headers ) );
200
+ //cache per users
201
+ if ( is_user_logged_in() ) {
202
+ $current_user = wp_get_current_user();
203
+ if ( $current_user->user_login ) {
204
+ $url_path .= $current_user->user_login;
205
+ }
206
+ } else {
207
+ $url_path .= 'guest';
208
+ }
209
+ $devices = $GLOBALS['breeze_config']['cache_options'];
210
+ // Detect devices
211
+ if ( $detect->isMobile() && ! $detect->isTablet() ) {
212
+ if ( $devices['breeze-mobile-cache'] == 1 ) {
213
+ $X1 = 'D';
214
+ $url_path .= '_breeze_cache_desktop';
215
+ }
216
+ if ( $devices['breeze-mobile-cache'] == 2 ) {
217
+ $X1 = 'M';
218
+ $url_path .= '_breeze_cache_mobile';
219
+ }
220
+ } else {
221
+ if ( $devices['breeze-desktop-cache'] == 1 ) {
222
+ $X1 = 'D';
223
+ $url_path .= '_breeze_cache_desktop';
224
+ }
225
+ }
226
+
227
+ if ( strpos( $url_path, '_breeze_cache_' ) !== false ) {
228
+ if ( ! empty( $GLOBALS['breeze_config']['cache_options']['breeze-gzip-compression'] ) && function_exists( 'gzencode' ) ) {
229
+ $wp_filesystem->put_contents( $path . md5( $url_path . '/index.gzip.html' ) . '.php', $data );
230
+ $wp_filesystem->touch( $path . md5( $url_path . '/index.gzip.html' ) . '.php', $modified_time );
231
+ } else {
232
+ $wp_filesystem->put_contents( $path . md5( $url_path . '/index.html' ) . '.php', $data );
233
+ $wp_filesystem->touch( $path . md5( $url_path . '/index.html' ) . '.php', $modified_time );
234
+ }
235
+ } else {
236
+ return $buffer;
237
+ }
238
+
239
+ //set cache provider header if not exists cache file
240
+ header( 'Cache-Provider:CLOUDWAYS-CACHE-' . $X1 . 'C' );
241
+
242
+ // Do not send this header in case we are behind a varnish proxy
243
+ if ( ! isset( $_SERVER['HTTP_X_VARNISH'] ) ) {
244
+ header( 'Cache-Control: no-cache' ); // Check back every time to see if re-download is necessary
245
+ }
246
+
247
+ header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', $modified_time ) . ' GMT' );
248
+
249
+ if ( function_exists( 'ob_gzhandler' ) && ! empty( $GLOBALS['breeze_config']['cache_options']['breeze-gzip-compression'] ) ) {
250
+ $ini_output_compression = ini_get( 'zlib.output_compression' );
251
+ $array_values = array( '1', 'On', 'on' );
252
+ if ( in_array( $ini_output_compression, $array_values ) ) {
253
+ return $buffer;
254
+ } else {
255
+ return ob_gzhandler( $buffer, $flags );
256
+ }
257
+ } else {
258
+ return $buffer;
259
+ }
260
  }
261
 
262
  /**
265
  * @since 1.0
266
  * @return string
267
  */
268
+ function breeze_get_url_path() {
 
269
 
270
+ $host = ( isset( $_SERVER['HTTP_HOST'] ) ) ? $_SERVER['HTTP_HOST'] : '';
271
+ $domain = ( ( ( ! empty( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] !== 'off' ) || ( ! empty( $_SERVER['SERVER_PORT'] ) && $_SERVER['SERVER_PORT'] == 443 ) ) ? 'https://' : 'http://' );
272
 
273
+ return $domain . rtrim( $host, '/' ) . $_SERVER['REQUEST_URI'];
274
  }
275
 
276
  /**
278
  *
279
  * @since 1.0
280
  */
281
+ function breeze_serve_cache( $filename, $url_path, $X1, $opts ) {
282
+ if ( strpos( $filename, '_breeze_cache_' ) === false ) {
283
+ return;
284
+ }
285
+
286
+ if ( function_exists( 'gzencode' ) && ! empty( $GLOBALS['breeze_config']['cache_options']['breeze-gzip-compression'] ) ) {
287
+ $file_name = md5( $filename . '/index.gzip.html' ) . '.php';
288
+ } else {
289
+ $file_name = md5( $filename . '/index.html' ) . '.php';
290
+ }
291
+
292
+
293
+ $path = breeze_get_cache_base_path() . md5( $url_path ) . '/' . $file_name;
294
+
295
+ $modified_time = (int) @filemtime( $path );
296
+
297
+ if ( ! empty( $opts['breeze-browser-cache'] ) && ! empty( $modified_time ) && ! empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) && strtotime( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) === $modified_time ) {
298
+ header( $_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified', true, 304 );
299
+ exit;
300
+ }
301
+
302
+ if ( @file_exists( $path ) ) {
303
+
304
+ $cacheFile = file_get_contents( $path );
305
+
306
+
307
+ if ( $cacheFile != false ) {
308
+ $datas = unserialize( $cacheFile );
309
+ foreach ( $datas['headers'] as $data ) {
310
+ header( $data['name'] . ': ' . $data['value'] );
311
+ }
312
+ //set cache provider header
313
+ header( 'Cache-Provider:CLOUDWAYS-CACHE-' . $X1 . 'E' );
314
+
315
+ $client_support_gzip = true;
316
+
317
+ //check gzip request from client
318
+ if ( isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) && ( strpos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip' ) === false || strpos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate' ) === false ) ) {
319
+ $client_support_gzip = false;
320
+ }
321
+
322
+ if ( $client_support_gzip && function_exists( 'gzdecode' ) && ! empty( $GLOBALS['breeze_config']['cache_options']['breeze-gzip-compression'] ) ) {
323
+ //if file is zip
324
+
325
+ $content = gzencode( $datas['body'], 9 );
326
+ header( 'Content-Encoding: gzip' );
327
+ header( "cache-control: must-revalidate" );
328
+ header( 'Content-Length: ' . strlen( $content ) );
329
+ header( 'Vary: Accept-Encoding' );
330
+ echo $content;
331
+ } else {
332
+ //render page cache
333
+ echo $datas['body'];
334
+ }
335
+ exit;
336
+ }
337
+ }
 
338
  }
339
 
340
+ function check_exclude_page( $opts_config, $current_url ) {
341
  //check disable cache for page
342
+ if ( ! empty( $opts_config['exclude_url'] ) ) {
343
+ foreach ( $opts_config['exclude_url'] as $v ) {
344
  // Clear blank character
345
+ $v = trim( $v );
346
+ if ( preg_match( '/(\&?\/?\(\.?\*\)|\/\*|\*)$/', $v, $matches ) ) {
347
  // End of rules is *, /*, [&][/](*) , [&][/](.*)
348
+ $pattent = substr( $v, 0, strpos( $v, $matches[0] ) );
349
+ if ( $v[0] == '/' ) {
350
  // A path of exclude url with regex
351
+ if ( ( @preg_match( '@' . $pattent . '@', $current_url, $matches ) > 0 ) ) {
352
  return true;
353
  }
354
+ } else {
355
  // Full exclude url with regex
356
+ if ( strpos( $current_url, $pattent ) !== false ) {
357
  return true;
358
  }
359
  }
360
 
361
+ } else {
362
+ if ( $v[0] == '/' ) {
363
  // A path of exclude
364
+ if ( ( @preg_match( '@' . $v . '@', $current_url, $matches ) > 0 ) ) {
365
  return true;
366
  }
367
  } else { // Whole path
368
+ if ( $v == $current_url ) {
369
  return true;
370
  }
371
  }
inc/cache/purge-cache.php CHANGED
@@ -119,7 +119,7 @@ class Breeze_PurgeCache {
119
 
120
  WP_Filesystem();
121
 
122
- $cache_path = breeze_get_cache_base_path( is_network_admin() );
123
  $wp_filesystem->rmdir( untrailingslashit( $cache_path ), true );
124
 
125
  if ( function_exists( 'wp_cache_flush' ) ) {
119
 
120
  WP_Filesystem();
121
 
122
+ $cache_path = breeze_get_cache_base_path( is_network_admin(), true );
123
  $wp_filesystem->rmdir( untrailingslashit( $cache_path ), true );
124
 
125
  if ( function_exists( 'wp_cache_flush' ) ) {
inc/cache/purge-varnish.php CHANGED
@@ -22,9 +22,9 @@ defined( 'ABSPATH' ) || die( 'No direct script access allowed!' );
22
 
23
  class Breeze_PurgeVarnish {
24
  protected $blogId;
25
- protected $urlsPurge = array();
26
- protected $auto_purge = false;
27
- protected $actions = array(
28
  'switch_theme', // After a theme is changed
29
  'save_post', // Save a post
30
  'deleted_post', // Delete a post
@@ -39,12 +39,17 @@ class Breeze_PurgeVarnish {
39
  //storage config
40
  if ( ! empty( $settings['auto-purge-varnish'] ) ) {
41
  $this->auto_purge = (int) $settings['auto-purge-varnish'];
 
 
 
 
 
 
42
  }
43
  add_action( 'init', array( $this, 'init' ) );
44
  }
45
 
46
  public function init() {
47
- //Push urlsPurge
48
  if ( $this->auto_purge ) {
49
  if ( ! empty( $this->actions ) ) {
50
  //if enabled auto purge option , this action will start
@@ -74,12 +79,21 @@ class Breeze_PurgeVarnish {
74
  *
75
  */
76
  public function breeze_execute_purge() {
77
- $urlsPurge = array_unique( $this->urlsPurge );
78
 
79
- if ( ! empty( $urlsPurge ) ) {
80
- foreach ( $urlsPurge as $url ) {
81
- $this->purge_cache( $url );
 
 
 
 
 
 
 
 
 
82
  }
 
83
  } else {
84
  $homepage = home_url() . '/?breeze';
85
  if ( isset( $_REQUEST['breeze_action'] ) && $_REQUEST['breeze_action'] == 'breeze_settings' ) {
@@ -274,7 +288,7 @@ class Breeze_PurgeVarnish {
274
  $listofurls,
275
  get_post_type_archive_link( get_post_type( $postId ) ),
276
  get_post_type_archive_feed_link( get_post_type( $postId ) )
277
- // Need to add in JSON?
278
  );
279
  }
280
  // Feeds
22
 
23
  class Breeze_PurgeVarnish {
24
  protected $blogId;
25
+ protected $urlsPurge = array();
26
+ protected $auto_purge = false;
27
+ protected $actions = array(
28
  'switch_theme', // After a theme is changed
29
  'save_post', // Save a post
30
  'deleted_post', // Delete a post
39
  //storage config
40
  if ( ! empty( $settings['auto-purge-varnish'] ) ) {
41
  $this->auto_purge = (int) $settings['auto-purge-varnish'];
42
+ if ( $this->auto_purge && ! isset( $_GET['breeze_check_cache_available'] ) ) {
43
+ // before sending the requests, we need to make sure Varnish is actually enabled.
44
+ // If Varnish is disabled, the requests will take longer to finish and will affect
45
+ // the WordPress performance.
46
+ #$this->auto_purge = is_varnish_cache_started();
47
+ }
48
  }
49
  add_action( 'init', array( $this, 'init' ) );
50
  }
51
 
52
  public function init() {
 
53
  if ( $this->auto_purge ) {
54
  if ( ! empty( $this->actions ) ) {
55
  //if enabled auto purge option , this action will start
79
  *
80
  */
81
  public function breeze_execute_purge() {
 
82
 
83
+ if ( ! empty( $this->urlsPurge ) ) {
84
+ $urlsPurge = array_unique( $this->urlsPurge );
85
+
86
+ // before sending the requests, we need to make sure Varnish is actually enabled.
87
+ // If Varnish is disabled, the requests will take longer to finish and will affect
88
+ // the WordPress performance.
89
+ $do_purge = is_varnish_cache_started();
90
+
91
+ if ( true === $do_purge ) {
92
+ foreach ( $urlsPurge as $url ) {
93
+ $this->purge_cache( $url );
94
+ }
95
  }
96
+
97
  } else {
98
  $homepage = home_url() . '/?breeze';
99
  if ( isset( $_REQUEST['breeze_action'] ) && $_REQUEST['breeze_action'] == 'breeze_settings' ) {
288
  $listofurls,
289
  get_post_type_archive_link( get_post_type( $postId ) ),
290
  get_post_type_archive_feed_link( get_post_type( $postId ) )
291
+ // Need to add in JSON?
292
  );
293
  }
294
  // Feeds
inc/cdn-integration/breeze-cdn-rewrite.php CHANGED
@@ -34,7 +34,25 @@ class Breeze_CDN_Rewrite {
34
  $this->dirs = $option['cdn-content'];
35
  $this->excludes = $option['cdn-exclude-content'];
36
  $this->relative = $option['cdn-relative-path'];
 
 
37
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  /*
39
  * Replace cdn on html raw
40
  */
34
  $this->dirs = $option['cdn-content'];
35
  $this->excludes = $option['cdn-exclude-content'];
36
  $this->relative = $option['cdn-relative-path'];
37
+
38
+ $this->hardcoded_exceptions_to_ignore();
39
  }
40
+
41
+ /**
42
+ * Handles extra exceptions which need to be excluded
43
+ * and instead use local URL instead of CDN.
44
+ *
45
+ * @since 1.1.3
46
+ */
47
+ private function hardcoded_exceptions_to_ignore() {
48
+ if ( ! array( $this->excludes ) || empty( $this->excludes ) ) {
49
+ $this->excludes = array();
50
+ }
51
+ $this->excludes [] = 'download_file';
52
+ // Allow users to use filter and add exceptions from CDN url.
53
+ $this->excludes = apply_filters( 'breeze_cdn_exclude_paths', $this->excludes );
54
+ }
55
+
56
  /*
57
  * Replace cdn on html raw
58
  */
inc/functions.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * @copyright 2017 Cloudways https://www.cloudways.com
4
  *
5
  * This program is free software; you can redistribute it and/or modify
6
  * it under the terms of the GNU General Public License as published by
@@ -22,17 +22,20 @@ defined( 'ABSPATH' ) || die( 'No direct script access allowed!' );
22
  * Get base path for the page cache directory.
23
  *
24
  * @param bool $is_network Whether to include the blog ID in the path on multisite.
 
25
  * @return string
26
  */
27
  function breeze_get_cache_base_path( $is_network = false ) {
28
- $path = rtrim( WP_CONTENT_DIR, '/\\' ) . '/cache/breeze/';
29
 
30
  if ( ! $is_network && is_multisite() ) {
31
  global $blog_id;
 
32
 
33
  if ( ! empty( $blog_id ) ) {
34
  $path .= abs( intval( $blog_id ) ) . DIRECTORY_SEPARATOR;
35
  }
 
 
36
  }
37
 
38
  return $path;
@@ -42,7 +45,8 @@ function breeze_get_cache_base_path( $is_network = false ) {
42
  * Get the total size of a directory (including subdirectories).
43
  *
44
  * @param string $dir
45
- * @param array $exclude
 
46
  * @return int
47
  */
48
  function breeze_get_directory_size( $dir, $exclude = array() ) {
@@ -62,3 +66,30 @@ function breeze_get_directory_size( $dir, $exclude = array() ) {
62
 
63
  return $size;
64
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
  /**
3
+ * @copyright 2017 Cloudways https://www.cloudways.com
4
  *
5
  * This program is free software; you can redistribute it and/or modify
6
  * it under the terms of the GNU General Public License as published by
22
  * Get base path for the page cache directory.
23
  *
24
  * @param bool $is_network Whether to include the blog ID in the path on multisite.
25
+ *
26
  * @return string
27
  */
28
  function breeze_get_cache_base_path( $is_network = false ) {
 
29
 
30
  if ( ! $is_network && is_multisite() ) {
31
  global $blog_id;
32
+ $path = rtrim( WP_CONTENT_DIR, '/\\' ) . '/cache/breeze/';
33
 
34
  if ( ! empty( $blog_id ) ) {
35
  $path .= abs( intval( $blog_id ) ) . DIRECTORY_SEPARATOR;
36
  }
37
+ } else {
38
+ $path = rtrim( WP_CONTENT_DIR, '/\\' ) . '/cache/breeze/';
39
  }
40
 
41
  return $path;
45
  * Get the total size of a directory (including subdirectories).
46
  *
47
  * @param string $dir
48
+ * @param array $exclude
49
+ *
50
  * @return int
51
  */
52
  function breeze_get_directory_size( $dir, $exclude = array() ) {
66
 
67
  return $size;
68
  }
69
+
70
+ function breeze_current_user_type( $as_dir = true ) {
71
+
72
+ if ( function_exists( 'is_user_logged_in' ) && is_user_logged_in() ) {
73
+ if ( current_user_can( 'administrator' ) ) {
74
+ return 'administrator' . ( true === $as_dir ? '/' : '' );
75
+ } elseif ( current_user_can( 'editor' ) ) {
76
+ return 'editor' . ( true === $as_dir ? '/' : '' );
77
+ } elseif ( current_user_can( 'author' ) ) {
78
+ return 'author' . ( true === $as_dir ? '/' : '' );
79
+ } elseif ( current_user_can( 'contributor' ) ) {
80
+ return 'contributor' . ( true === $as_dir ? '/' : '' );
81
+ }
82
+ }
83
+
84
+ return '';
85
+ }
86
+
87
+ function breeze_all_user_folders() {
88
+ return array(
89
+ '',
90
+ 'administrator',
91
+ 'editor',
92
+ 'author',
93
+ 'contributor',
94
+ );
95
+ }
inc/helpers.php CHANGED
@@ -112,9 +112,9 @@ function breeze_is_supported( $check ) {
112
  * @param array $url_list
113
  * @param string $extension
114
  *
 
115
  * @since 1.1.0
116
  *
117
- * @return bool
118
  */
119
  function breeze_validate_urls( $url_list = array() ) {
120
  if ( ! is_array( $url_list ) ) {
@@ -205,12 +205,12 @@ function breeze_get_file_extension_from_url( $url_given = '' ) {
205
  * if found, will result in an array with all entries found
206
  * if not found, an empty array will be resulted.
207
  *
208
- * @since 1.1.0
209
- *
210
  * @param string $needle
211
  * @param array $haystack
212
  *
213
  * @return array
 
 
214
  */
215
  function breeze_is_string_in_array_values( $needle = '', $haystack = array() ) {
216
  if ( empty( $needle ) || empty( $haystack ) ) {
@@ -334,7 +334,6 @@ function breeze_file_match_pattern( $file_url, $pattern ) {
334
  return $result;
335
  }
336
 
337
-
338
  /**
339
  * Will return true/false if the cache headers exist and
340
  * have values HIT or MISS.
@@ -343,37 +342,65 @@ function breeze_file_match_pattern( $file_url, $pattern ) {
343
  * This method will request only the current url homepage headers
344
  * and if the first time is a MISS, it will try again.
345
  *
346
- * @param int $retry
 
 
347
  *
348
  * @return bool
349
  */
350
- function is_varnish_cache_started( $retry = 1 ) {
351
- // Making sure the request is only for HEADER info without getting the content from the page
352
- $context_options = array(
353
- 'http' => array(
354
- 'method' => 'HEAD',
355
- 'follow_location' => 1,
356
- ),
357
- 'ssl' => array(
358
- 'verify_peer' => false
359
- ),
360
- );
361
- $context = stream_context_create( $context_options );
362
 
363
- $url_ping = trim( home_url() . '?breeze_check_cache_available=' . time() );
364
- $headers = get_headers( $url_ping, 1, $context );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
 
366
  if ( empty( $headers ) ) {
367
  return false;
368
  }
369
 
370
- $headers = array_change_key_case( $headers, CASE_LOWER );
 
 
371
 
372
  if ( ! isset( $headers['x-cache'] ) ) {
373
  if ( 1 === $retry ) {
374
  $retry ++;
375
 
376
- return is_varnish_cache_started( $retry );
377
  }
378
 
379
  return false;
@@ -384,16 +411,16 @@ function is_varnish_cache_started( $retry = 1 ) {
384
  // After the first header requests, the cache headers are formed.
385
  // Checking the second time will give better results.
386
  if ( 1 === $retry ) {
387
- if ( 'hit' === $cache_header ) {
388
  return true;
389
  } else {
390
  $retry ++;
391
 
392
- return is_varnish_cache_started( $retry );
393
  }
394
  } else {
395
 
396
- if ( 'hit' === $cache_header ) {
397
  return true;
398
  }
399
 
@@ -401,3 +428,159 @@ function is_varnish_cache_started( $retry = 1 ) {
401
  }
402
  }
403
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  * @param array $url_list
113
  * @param string $extension
114
  *
115
+ * @return bool
116
  * @since 1.1.0
117
  *
 
118
  */
119
  function breeze_validate_urls( $url_list = array() ) {
120
  if ( ! is_array( $url_list ) ) {
205
  * if found, will result in an array with all entries found
206
  * if not found, an empty array will be resulted.
207
  *
 
 
208
  * @param string $needle
209
  * @param array $haystack
210
  *
211
  * @return array
212
+ * @since 1.1.0
213
+ *
214
  */
215
  function breeze_is_string_in_array_values( $needle = '', $haystack = array() ) {
216
  if ( empty( $needle ) || empty( $haystack ) ) {
334
  return $result;
335
  }
336
 
 
337
  /**
338
  * Will return true/false if the cache headers exist and
339
  * have values HIT or MISS.
342
  * This method will request only the current url homepage headers
343
  * and if the first time is a MISS, it will try again.
344
  *
345
+ * @param int $retry how many retries count.
346
+ * @param int $time_fresh current time to make a fresh connect.
347
+ * @param bool $use_headers To use get_headers or cURL.
348
  *
349
  * @return bool
350
  */
351
+ function is_varnish_cache_started( $retry = 1, $time_fresh = 0, $use_headers = false ) {
352
+ if ( empty( $time_fresh ) ) {
353
+ $time_fresh = time();
354
+ }
 
 
 
 
 
 
 
 
355
 
356
+ // Code specific for Cloudways Server.
357
+ if ( 1 === $retry ) {
358
+ $check_local_server = is_varnish_layer_started();
359
+ if ( true === $check_local_server ) {
360
+ return true;
361
+ }
362
+ }
363
+
364
+ $url_ping = trim( home_url() . '?breeze_check_cache_available=' . $time_fresh );
365
+
366
+ if ( true === $use_headers ) {
367
+ // Making sure the request is only for HEADER info without getting the content from the page
368
+ $context_options = array(
369
+ 'http' => array(
370
+ 'method' => 'HEAD',
371
+ 'follow_location' => 1,
372
+ ),
373
+ 'ssl' => array(
374
+ 'verify_peer' => false,
375
+ ),
376
+ );
377
+ $context = stream_context_create( $context_options );
378
+ $headers = get_headers( $url_ping, 1, $context );
379
+
380
+ if ( empty( $headers ) ) {
381
+ $use_headers = false;
382
+ } else {
383
+ $headers = array_change_key_case( $headers, CASE_LOWER );
384
+ }
385
+ }
386
+
387
+ if ( false === $use_headers ) {
388
+ $headers = breeze_get_headers_via_curl( $url_ping );
389
+ }
390
 
391
  if ( empty( $headers ) ) {
392
  return false;
393
  }
394
 
395
+ if ( true === $headers ) {
396
+ return true;
397
+ }
398
 
399
  if ( ! isset( $headers['x-cache'] ) ) {
400
  if ( 1 === $retry ) {
401
  $retry ++;
402
 
403
+ return is_varnish_cache_started( $retry, $time_fresh, $use_headers );
404
  }
405
 
406
  return false;
411
  // After the first header requests, the cache headers are formed.
412
  // Checking the second time will give better results.
413
  if ( 1 === $retry ) {
414
+ if ( substr_count( $cache_header, 'hit' ) > 0 ) {
415
  return true;
416
  } else {
417
  $retry ++;
418
 
419
+ return is_varnish_cache_started( $retry, $time_fresh, $use_headers );
420
  }
421
  } else {
422
 
423
+ if ( substr_count( $cache_header, 'hit' ) > 0 ) {
424
  return true;
425
  }
426
 
428
  }
429
  }
430
  }
431
+
432
+ /**
433
+ * Fallback function to fetch headers.
434
+ *
435
+ * @param string $url_ping URL from where to get the headers.
436
+ *
437
+ * @return array|bool
438
+ */
439
+ function breeze_get_headers_via_curl( $url_ping = '' ) {
440
+ $connection = curl_init();
441
+ $headers = array();
442
+ curl_setopt( $connection, CURLOPT_URL, $url_ping );
443
+ curl_setopt( $connection, CURLOPT_NOBODY, true );
444
+ curl_setopt( $connection, CURLOPT_RETURNTRANSFER, true );
445
+ curl_setopt( $connection, CURLOPT_FOLLOWLOCATION, true ); // follow redirects
446
+ curl_setopt( $connection, CURLOPT_SSL_VERIFYPEER, false ); // if the SSL is invalid, curl will have trouble giving the correct response.
447
+ curl_setopt( $connection, CURLOPT_HEADER, true );// return just headers
448
+ curl_setopt( $connection, CURLOPT_TIMEOUT, 1 );
449
+ // this function is called by curl for each header received
450
+ curl_setopt(
451
+ $connection,
452
+ CURLOPT_HEADERFUNCTION,
453
+ function ( $curl, $header ) use ( &$headers ) {
454
+ $len = strlen( $header );
455
+ $header = explode( ':', $header, 2 );
456
+ if ( count( $header ) < 2 ) { // ignore invalid headers
457
+ return $len;
458
+ }
459
+
460
+ $headers[ strtolower( trim( $header[0] ) ) ][] = trim( $header[1] );
461
+
462
+ return $len;
463
+ }
464
+ );
465
+
466
+ curl_exec( $connection );
467
+ curl_close( $connection );
468
+
469
+ // x-cacheable
470
+ if ( isset( $headers['x-cacheable'] ) ) {
471
+ $x_cacheable_value = array_pop( $headers['x-cacheable'] );
472
+ if ( 'yes' === strtolower( $x_cacheable_value ) || 'short' === strtolower( $x_cacheable_value ) ) {
473
+ return true;
474
+ }
475
+ }
476
+
477
+ if ( isset( $headers['x-cache'] ) ) {
478
+ $x_cache_value = array_pop( $headers['x-cache'] );
479
+
480
+ return array( 'x-cache' => $x_cache_value );
481
+ }
482
+
483
+ return false;
484
+
485
+ }
486
+
487
+ /**
488
+ * Determine if the Varnish server is up and running.
489
+ *
490
+ * CloudWays:
491
+ * At server root level Varnish being disabled.
492
+ * HTTP_X_VARNISH - does not exist or is NULL
493
+ * HTTP_X_APPLICATION - contains varnishpass
494
+ *
495
+ * At Application level ( WP install ) - Varnish ON
496
+ * At server level is ON
497
+ * HTTP_X_VARNISH - has random numerical value
498
+ * HTTP_X_APPLICATION - contains value different from varnishpass, usually application name.
499
+ *
500
+ * At Application level ( WP install ) - Varnish OFF
501
+ * At server level is ON
502
+ * HTTP_X_VARNISH - has random numerical value
503
+ * HTTP_X_APPLICATION - contains value varnishpass
504
+ *
505
+ * @since 1.1.3
506
+ */
507
+ function is_varnish_layer_started() {
508
+ $data = $_SERVER;
509
+
510
+ if ( ! isset( $data['HTTP_X_VARNISH'] ) ) {
511
+ return false;
512
+ }
513
+
514
+ if ( isset( $data['HTTP_X_VARNISH'] ) && isset( $data['HTTP_X_APPLICATION'] ) ) {
515
+
516
+ if ( 'varnishpass' === trim( $data['HTTP_X_APPLICATION'] ) ) {
517
+ return false;
518
+ } elseif ( 'bypass' === trim( $data['HTTP_X_APPLICATION'] ) ) {
519
+ return false;
520
+ } elseif ( is_null( $data['HTTP_X_APPLICATION'] ) ) {
521
+ return false;
522
+ }
523
+ }
524
+
525
+ if ( ! isset( $data['HTTP_X_APPLICATION'] ) ) {
526
+ return false;
527
+ }
528
+
529
+
530
+ return true;
531
+ }
532
+
533
+ /**
534
+ * Handles file writing.
535
+ * Using fopen() si a lot faster than file_put_contents().
536
+ *
537
+ * @param string $file_path
538
+ * @param string $content
539
+ *
540
+ * @return bool
541
+ * @since 1.1.3
542
+ */
543
+ function breeze_read_write_file( $file_path = '', $content = '' ) {
544
+ if ( empty( $file_path ) ) {
545
+ return false;
546
+ }
547
+
548
+ if ( ( $handler = @fopen( $file_path, 'w' ) ) !== false ) { // phpcs:ignore
549
+ if ( ( @fwrite( $handler, $content ) ) !== false ) { // phpcs:ignore
550
+ @fclose( $handler ); // phpcs:ignore
551
+ }
552
+ }
553
+
554
+ }
555
+
556
+
557
+ function breeze_lock_cache_process( $path = '' ) {
558
+ $filename = 'process.lock';
559
+ $create_lock = fopen( $path . $filename, 'w' );
560
+ if ( false === $create_lock ) {
561
+ return false;
562
+ }
563
+ fclose( $create_lock );
564
+
565
+ return true;
566
+ }
567
+
568
+ function breeze_is_process_locked( $path = '' ) {
569
+ $filename = 'process.lock';
570
+ if ( file_exists( $path . $filename ) ) {
571
+ return true;
572
+ }
573
+
574
+ return false;
575
+ }
576
+
577
+ function breeze_unlock_process( $path = '' ) {
578
+ $filename = 'process.lock';
579
+ if ( file_exists( $path . $filename ) ) {
580
+ @unlink( $path . $filename );
581
+
582
+ return true;
583
+ }
584
+
585
+ return false;
586
+ }
inc/minification/breeze-minification-base.php CHANGED
@@ -2,50 +2,52 @@
2
  /*
3
  * Based on some work of autoptimize plugin
4
  */
5
- if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
 
 
6
 
7
  abstract class Breeze_MinificationBase {
8
  protected $content = '';
9
  protected $tagWarning = false;
10
-
11
- public function __construct($content) {
12
  $this->content = $content;
13
  }
14
-
15
  //Reads the page and collects tags
16
- abstract public function read($justhead);
17
-
18
  //Joins and optimizes collected things
19
  abstract public function minify();
20
-
21
  //Caches the things
22
  abstract public function cache();
23
-
24
  //Returns the content
25
  abstract public function getcontent();
26
-
27
  //Converts an URL to a full path
28
- protected function getpath($url) {
29
- $url=apply_filters( 'breeze_filter_cssjs_alter_url', $url);
30
-
31
- if (strpos($url,'%')!==false) {
32
- $url=urldecode($url);
33
  }
34
 
35
  // normalize
36
- if (strpos($url,'//')===0) {
37
- if (is_ssl()) {
38
- $url = "https:".$url;
39
  } else {
40
- $url = "http:".$url;
41
  }
42
- } else if ((strpos($url,'//')===false) && (strpos($url,parse_url(breeze_WP_SITE_URL,PHP_URL_HOST))===false)) {
43
- $url = breeze_WP_SITE_URL.$url;
44
  }
45
 
46
  // first check; hostname wp site should be hostname of url
47
- $thisHost=@parse_url($url,PHP_URL_HOST);
48
- if ($thisHost!==parse_url(breeze_WP_SITE_URL,PHP_URL_HOST)) {
49
  /*
50
  * first try to get all domains from WPML (if available)
51
  * then explicitely declare $this->cdn_url as OK as well
@@ -53,21 +55,21 @@ abstract class Breeze_MinificationBase {
53
  * each item in that array will be considered part of the same WP multisite installation
54
  */
55
  $multidomains = array();
56
-
57
- $multidomainsWPML = apply_filters('wpml_setting', array(), 'language_domains');
58
- if (!empty($multidomainsWPML)) {
59
- $multidomains = array_map(array($this,"ao_getDomain"),$multidomainsWPML);
60
  }
61
-
62
- if (!empty($this->cdn_url)) {
63
- $multidomains[]=parse_url($this->cdn_url,PHP_URL_HOST);
64
  }
65
-
66
- $multidomains = apply_filters('breeze_filter_cssjs_multidomain', $multidomains);
67
-
68
- if (!empty($multidomains)) {
69
- if (in_array($thisHost,$multidomains)) {
70
- $url=str_replace($thisHost, parse_url(breeze_WP_SITE_URL,PHP_URL_HOST), $url);
71
  } else {
72
  return false;
73
  }
@@ -75,151 +77,160 @@ abstract class Breeze_MinificationBase {
75
  return false;
76
  }
77
  }
78
-
79
  // try to remove "wp root url" from url while not minding http<>https
80
- $tmp_ao_root = preg_replace('/https?/','',breeze_WP_ROOT_URL);
81
- $tmp_url = preg_replace('/https?/','',$url);
82
- $path = str_replace($tmp_ao_root,'',$tmp_url);
83
-
84
  // final check; if path starts with :// or //, this is not a URL in the WP context and we have to assume we can't aggregate
85
- if (preg_match('#^:?//#',$path)) {
86
- /** External script/css (adsense, etc) */
87
  return false;
88
- }
89
 
90
- $path = str_replace('//','/',BREEZE_ROOT_DIR.$path);
91
- return $path;
 
92
  }
93
 
94
  // needed for WPML-filter
95
- protected function ao_getDomain($in) {
96
- // make sure the url starts with something vaguely resembling a protocol
97
- if ((strpos($in,"http")!==0) && (strpos($in,"//")!==0)) {
98
- $in="http://".$in;
99
- }
100
-
101
- // do the actual parse_url
102
- $out = parse_url($in,PHP_URL_HOST);
103
-
104
- // fallback if parse_url does not understand the url is in fact a url
105
- if (empty($out)) $out=$in;
106
-
 
 
107
  return $out;
108
  }
109
 
110
 
111
  // logger
112
- protected function ao_logger($logmsg,$appendHTML=true) {
113
- if ($appendHTML) {
114
- $logmsg="<!--noptimize--><!-- ".$logmsg." --><!--/noptimize-->";
115
- $this->content.=$logmsg;
116
  } else {
117
- error_log("Error: ".$logmsg);
118
  }
119
  }
120
 
121
  // hide everything between noptimize-comment tags
122
- protected function hide_noptimize($noptimize_in) {
123
- if ( preg_match( '/<!--\s?noptimize\s?-->/', $noptimize_in ) ) {
124
  $noptimize_out = preg_replace_callback(
125
  '#<!--\s?noptimize\s?-->.*?<!--\s?/\s?noptimize\s?-->#is',
126
 
127
- function($matches){
128
- return "%%NOPTIMIZE".breeze_HASH."%%".base64_encode($matches[0])."%%NOPTIMIZE%%";
129
- },
130
  $noptimize_in
131
  );
132
  } else {
133
  $noptimize_out = $noptimize_in;
134
  }
 
135
  return $noptimize_out;
136
  }
137
-
138
  // unhide noptimize-tags
139
- protected function restore_noptimize($noptimize_in) {
140
- if ( strpos( $noptimize_in, '%%NOPTIMIZE%%' ) !== false ) {
141
  $noptimize_out = preg_replace_callback(
142
- '#%%NOPTIMIZE'.breeze_HASH.'%%(.*?)%%NOPTIMIZE%%#is',
143
 
144
- function($matches){
145
- return base64_decode($matches[1]);
146
- },
147
  $noptimize_in
148
  );
149
  } else {
150
  $noptimize_out = $noptimize_in;
151
  }
 
152
  return $noptimize_out;
153
  }
154
 
155
- protected function hide_iehacks($iehacks_in) {
156
- if ( strpos( $iehacks_in, '<!--[if' ) !== false ) {
157
  $iehacks_out = preg_replace_callback(
158
  '#<!--\[if.*?\[endif\]-->#is',
159
 
160
- function($matches){
161
- return "%%IEHACK".breeze_HASH."%%".base64_encode($matches[0])."%%IEHACK%%";
162
- },
163
 
164
  $iehacks_in
165
  );
166
  } else {
167
  $iehacks_out = $iehacks_in;
168
  }
 
169
  return $iehacks_out;
170
  }
171
 
172
- protected function restore_iehacks($iehacks_in) {
173
- if ( strpos( $iehacks_in, '%%IEHACK%%' ) !== false ) {
174
  $iehacks_out = preg_replace_callback(
175
- '#%%IEHACK'.breeze_HASH.'%%(.*?)%%IEHACK%%#is',
176
 
177
- function($matches){
178
- return base64_decode($matches[1]);
179
- },
180
  $iehacks_in
181
  );
182
  } else {
183
- $iehacks_out=$iehacks_in;
184
  }
 
185
  return $iehacks_out;
186
  }
187
 
188
- protected function hide_comments($comments_in) {
189
- if ( strpos( $comments_in, '<!--' ) !== false ) {
190
- $comments_out = preg_replace_callback(
191
- '#<!--.*?-->#is',
192
-
193
- function($matches){
194
- return "%%COMMENTS".breeze_HASH."%%".base64_encode($matches[0])."%%COMMENTS%%";
195
- },
196
- $comments_in
197
- );
198
- } else {
199
- $comments_out = $comments_in;
200
- }
201
- return $comments_out;
202
- }
203
-
204
- protected function restore_comments($comments_in) {
205
- if ( strpos( $comments_in, '%%COMMENTS%%' ) !== false ) {
206
- $comments_out = preg_replace_callback(
207
- '#%%COMMENTS'.breeze_HASH.'%%(.*?)%%COMMENTS%%#is',
208
-
209
- function($matches){
210
- return base64_decode($matches[1]);
211
- },
212
- $comments_in
213
- );
214
- } else {
215
- $comments_out=$comments_in;
216
- }
217
- return $comments_out;
 
 
218
  }
219
 
220
  protected function url_replace_cdn( $url ) {
221
  $cdn_url = apply_filters( 'breeze_filter_base_cdnurl', $this->cdn_url );
222
- if ( !empty($cdn_url) ) {
223
  // secondly prepend domain-less absolute URL's
224
  if ( ( substr( $url, 0, 1 ) === '/' ) && ( substr( $url, 1, 1 ) !== '/' ) ) {
225
  $url = rtrim( $cdn_url, '/' ) . $url;
@@ -243,79 +254,141 @@ abstract class Breeze_MinificationBase {
243
 
244
  // allow API filter to take alter after CDN replacement
245
  $url = apply_filters( 'breeze_filter_base_replace_cdn', $url );
 
246
  return $url;
247
  }
248
 
249
- protected function inject_in_html($payload,$replaceTag) {
250
- if (strpos($this->content,$replaceTag[0])!== false) {
251
- if ($replaceTag[1]==="after") {
252
- $replaceBlock=$replaceTag[0].$payload;
253
- } else if ($replaceTag[1]==="replace"){
254
- $replaceBlock=$payload;
255
  } else {
256
- $replaceBlock=$payload.$replaceTag[0];
257
  }
258
- $this->content = substr_replace($this->content,$replaceBlock,strpos($this->content,$replaceTag[0]),strlen($replaceTag[0]));
259
  } else {
260
  $this->content .= $payload;
261
- if (!$this->tagWarning) {
262
- $this->content .= "<!--noptimize--><!-- breeze found a problem with the HTML in your Theme, tag ".$replaceTag[0]." missing --><!--/noptimize-->";
263
- $this->tagWarning=true;
264
  }
265
  }
266
  }
267
-
268
- protected function isremovable($tag, $removables) {
269
- foreach ($removables as $match) {
270
- if (strpos($tag,$match)!==false) {
271
  return true;
272
  }
273
  }
 
274
  return false;
275
  }
276
-
277
- // inject already minified code in optimized JS/CSS
278
- protected function inject_minified($in) {
279
- if ( strpos( $in, '%%INJECTLATER%%' ) !== false ) {
280
- $out = preg_replace_callback(
281
- '#%%INJECTLATER'.breeze_HASH.'%%(.*?)%%INJECTLATER%%#is',
282
-
283
- function($matches){
284
- $filepath=base64_decode(strtok($matches[1],"|"));
285
- $filecontent=file_get_contents($filepath);
286
-
287
- // remove BOM
288
- $filecontent = preg_replace("#\x{EF}\x{BB}\x{BF}#","",$filecontent);
289
-
290
- // remove comments and blank lines
291
- if (substr($filepath,-3,3)===".js") {
292
- $filecontent=preg_replace("#^\s*\/\/.*$#Um","",$filecontent);
293
  }
294
 
295
- $filecontent=preg_replace("#^\s*\/\*[^!].*\*\/\s?#Us","",$filecontent);
296
- $filecontent=preg_replace("#(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+#", "\n", $filecontent);
297
 
298
- // specific stuff for JS-files
299
- if (substr($filepath,-3,3)===".js") {
300
- if ((substr($filecontent,-1,1)!==";")&&(substr($filecontent,-1,1)!=="}")) {
301
- $filecontent.=";";
302
- }
303
 
304
- if (get_option("breeze_js_trycatch")==="on") {
305
- $filecontent="try{".$filecontent."}catch(e){}";
306
- }
307
- } else if ((substr($filepath,-4,4)===".css")) {
308
- $filecontent=Breeze_MinificationStyles::fixurls($filepath,$filecontent);
309
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
 
311
- // return
312
- return "\n".$filecontent;
313
- },
314
- $in
315
- );
316
- } else {
317
- $out = $in;
318
- }
319
- return $out;
320
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
321
  }
2
  /*
3
  * Based on some work of autoptimize plugin
4
  */
5
+ if ( ! defined( 'ABSPATH' ) ) {
6
+ exit;
7
+ } // Exit if accessed directly
8
 
9
  abstract class Breeze_MinificationBase {
10
  protected $content = '';
11
  protected $tagWarning = false;
12
+
13
+ public function __construct( $content ) {
14
  $this->content = $content;
15
  }
16
+
17
  //Reads the page and collects tags
18
+ abstract public function read( $justhead );
19
+
20
  //Joins and optimizes collected things
21
  abstract public function minify();
22
+
23
  //Caches the things
24
  abstract public function cache();
25
+
26
  //Returns the content
27
  abstract public function getcontent();
28
+
29
  //Converts an URL to a full path
30
+ protected function getpath( $url ) {
31
+ $url = apply_filters( 'breeze_filter_cssjs_alter_url', $url );
32
+
33
+ if ( strpos( $url, '%' ) !== false ) {
34
+ $url = urldecode( $url );
35
  }
36
 
37
  // normalize
38
+ if ( strpos( $url, '//' ) === 0 ) {
39
+ if ( is_ssl() ) {
40
+ $url = "https:" . $url;
41
  } else {
42
+ $url = "http:" . $url;
43
  }
44
+ } else if ( ( strpos( $url, '//' ) === false ) && ( strpos( $url, parse_url( breeze_WP_SITE_URL, PHP_URL_HOST ) ) === false ) ) {
45
+ $url = breeze_WP_SITE_URL . $url;
46
  }
47
 
48
  // first check; hostname wp site should be hostname of url
49
+ $thisHost = @parse_url( $url, PHP_URL_HOST );
50
+ if ( $thisHost !== parse_url( breeze_WP_SITE_URL, PHP_URL_HOST ) ) {
51
  /*
52
  * first try to get all domains from WPML (if available)
53
  * then explicitely declare $this->cdn_url as OK as well
55
  * each item in that array will be considered part of the same WP multisite installation
56
  */
57
  $multidomains = array();
58
+
59
+ $multidomainsWPML = apply_filters( 'wpml_setting', array(), 'language_domains' );
60
+ if ( ! empty( $multidomainsWPML ) ) {
61
+ $multidomains = array_map( array( $this, "ao_getDomain" ), $multidomainsWPML );
62
  }
63
+
64
+ if ( ! empty( $this->cdn_url ) ) {
65
+ $multidomains[] = parse_url( $this->cdn_url, PHP_URL_HOST );
66
  }
67
+
68
+ $multidomains = apply_filters( 'breeze_filter_cssjs_multidomain', $multidomains );
69
+
70
+ if ( ! empty( $multidomains ) ) {
71
+ if ( in_array( $thisHost, $multidomains ) ) {
72
+ $url = str_replace( $thisHost, parse_url( breeze_WP_SITE_URL, PHP_URL_HOST ), $url );
73
  } else {
74
  return false;
75
  }
77
  return false;
78
  }
79
  }
80
+
81
  // try to remove "wp root url" from url while not minding http<>https
82
+ $tmp_ao_root = preg_replace( '/https?/', '', breeze_WP_ROOT_URL );
83
+ $tmp_url = preg_replace( '/https?/', '', $url );
84
+ $path = str_replace( $tmp_ao_root, '', $tmp_url );
85
+
86
  // final check; if path starts with :// or //, this is not a URL in the WP context and we have to assume we can't aggregate
87
+ if ( preg_match( '#^:?//#', $path ) ) {
88
+ /** External script/css (adsense, etc) */
89
  return false;
90
+ }
91
 
92
+ $path = str_replace( '//', '/', BREEZE_ROOT_DIR . $path );
93
+
94
+ return $path;
95
  }
96
 
97
  // needed for WPML-filter
98
+ protected function ao_getDomain( $in ) {
99
+ // make sure the url starts with something vaguely resembling a protocol
100
+ if ( ( strpos( $in, "http" ) !== 0 ) && ( strpos( $in, "//" ) !== 0 ) ) {
101
+ $in = "http://" . $in;
102
+ }
103
+
104
+ // do the actual parse_url
105
+ $out = parse_url( $in, PHP_URL_HOST );
106
+
107
+ // fallback if parse_url does not understand the url is in fact a url
108
+ if ( empty( $out ) ) {
109
+ $out = $in;
110
+ }
111
+
112
  return $out;
113
  }
114
 
115
 
116
  // logger
117
+ protected function ao_logger( $logmsg, $appendHTML = true ) {
118
+ if ( $appendHTML ) {
119
+ $logmsg = "<!--noptimize--><!-- " . $logmsg . " --><!--/noptimize-->";
120
+ $this->content .= $logmsg;
121
  } else {
122
+ error_log( "Error: " . $logmsg );
123
  }
124
  }
125
 
126
  // hide everything between noptimize-comment tags
127
+ protected function hide_noptimize( $noptimize_in ) {
128
+ if ( preg_match( '/<!--\s?noptimize\s?-->/', $noptimize_in ) ) {
129
  $noptimize_out = preg_replace_callback(
130
  '#<!--\s?noptimize\s?-->.*?<!--\s?/\s?noptimize\s?-->#is',
131
 
132
+ function ( $matches ) {
133
+ return "%%NOPTIMIZE" . breeze_HASH . "%%" . base64_encode( $matches[0] ) . "%%NOPTIMIZE%%";
134
+ },
135
  $noptimize_in
136
  );
137
  } else {
138
  $noptimize_out = $noptimize_in;
139
  }
140
+
141
  return $noptimize_out;
142
  }
143
+
144
  // unhide noptimize-tags
145
+ protected function restore_noptimize( $noptimize_in ) {
146
+ if ( strpos( $noptimize_in, '%%NOPTIMIZE%%' ) !== false ) {
147
  $noptimize_out = preg_replace_callback(
148
+ '#%%NOPTIMIZE' . breeze_HASH . '%%(.*?)%%NOPTIMIZE%%#is',
149
 
150
+ function ( $matches ) {
151
+ return base64_decode( $matches[1] );
152
+ },
153
  $noptimize_in
154
  );
155
  } else {
156
  $noptimize_out = $noptimize_in;
157
  }
158
+
159
  return $noptimize_out;
160
  }
161
 
162
+ protected function hide_iehacks( $iehacks_in ) {
163
+ if ( strpos( $iehacks_in, '<!--[if' ) !== false ) {
164
  $iehacks_out = preg_replace_callback(
165
  '#<!--\[if.*?\[endif\]-->#is',
166
 
167
+ function ( $matches ) {
168
+ return "%%IEHACK" . breeze_HASH . "%%" . base64_encode( $matches[0] ) . "%%IEHACK%%";
169
+ },
170
 
171
  $iehacks_in
172
  );
173
  } else {
174
  $iehacks_out = $iehacks_in;
175
  }
176
+
177
  return $iehacks_out;
178
  }
179
 
180
+ protected function restore_iehacks( $iehacks_in ) {
181
+ if ( strpos( $iehacks_in, '%%IEHACK%%' ) !== false ) {
182
  $iehacks_out = preg_replace_callback(
183
+ '#%%IEHACK' . breeze_HASH . '%%(.*?)%%IEHACK%%#is',
184
 
185
+ function ( $matches ) {
186
+ return base64_decode( $matches[1] );
187
+ },
188
  $iehacks_in
189
  );
190
  } else {
191
+ $iehacks_out = $iehacks_in;
192
  }
193
+
194
  return $iehacks_out;
195
  }
196
 
197
+ protected function hide_comments( $comments_in ) {
198
+ if ( strpos( $comments_in, '<!--' ) !== false ) {
199
+ $comments_out = preg_replace_callback(
200
+ '#<!--.*?-->#is',
201
+
202
+ function ( $matches ) {
203
+ return "%%COMMENTS" . breeze_HASH . "%%" . base64_encode( $matches[0] ) . "%%COMMENTS%%";
204
+ },
205
+ $comments_in
206
+ );
207
+ } else {
208
+ $comments_out = $comments_in;
209
+ }
210
+
211
+ return $comments_out;
212
+ }
213
+
214
+ protected function restore_comments( $comments_in ) {
215
+ if ( strpos( $comments_in, '%%COMMENTS%%' ) !== false ) {
216
+ $comments_out = preg_replace_callback(
217
+ '#%%COMMENTS' . breeze_HASH . '%%(.*?)%%COMMENTS%%#is',
218
+
219
+ function ( $matches ) {
220
+ return base64_decode( $matches[1] );
221
+ },
222
+ $comments_in
223
+ );
224
+ } else {
225
+ $comments_out = $comments_in;
226
+ }
227
+
228
+ return $comments_out;
229
  }
230
 
231
  protected function url_replace_cdn( $url ) {
232
  $cdn_url = apply_filters( 'breeze_filter_base_cdnurl', $this->cdn_url );
233
+ if ( ! empty( $cdn_url ) ) {
234
  // secondly prepend domain-less absolute URL's
235
  if ( ( substr( $url, 0, 1 ) === '/' ) && ( substr( $url, 1, 1 ) !== '/' ) ) {
236
  $url = rtrim( $cdn_url, '/' ) . $url;
254
 
255
  // allow API filter to take alter after CDN replacement
256
  $url = apply_filters( 'breeze_filter_base_replace_cdn', $url );
257
+
258
  return $url;
259
  }
260
 
261
+ protected function inject_in_html( $payload, $replaceTag ) {
262
+ if ( strpos( $this->content, $replaceTag[0] ) !== false ) {
263
+ if ( $replaceTag[1] === "after" ) {
264
+ $replaceBlock = $replaceTag[0] . $payload;
265
+ } else if ( $replaceTag[1] === "replace" ) {
266
+ $replaceBlock = $payload;
267
  } else {
268
+ $replaceBlock = $payload . $replaceTag[0];
269
  }
270
+ $this->content = substr_replace( $this->content, $replaceBlock, strpos( $this->content, $replaceTag[0] ), strlen( $replaceTag[0] ) );
271
  } else {
272
  $this->content .= $payload;
273
+ if ( ! $this->tagWarning ) {
274
+ $this->content .= "<!--noptimize--><!-- breeze found a problem with the HTML in your Theme, tag " . $replaceTag[0] . " missing --><!--/noptimize-->";
275
+ $this->tagWarning = true;
276
  }
277
  }
278
  }
279
+
280
+ protected function isremovable( $tag, $removables ) {
281
+ foreach ( $removables as $match ) {
282
+ if ( strpos( $tag, $match ) !== false ) {
283
  return true;
284
  }
285
  }
286
+
287
  return false;
288
  }
289
+
290
+ // inject already minified code in optimized JS/CSS
291
+ protected function inject_minified( $in ) {
292
+ if ( strpos( $in, '%%INJECTLATER%%' ) !== false ) {
293
+ $out = preg_replace_callback(
294
+ '#%%INJECTLATER' . breeze_HASH . '%%(.*?)%%INJECTLATER%%#is',
295
+
296
+ function ( $matches ) {
297
+ $filepath = base64_decode( strtok( $matches[1], "|" ) );
298
+ $filecontent = file_get_contents( $filepath );
299
+ if(empty(trim($filecontent))){
300
+ return '';
 
 
 
 
 
301
  }
302
 
303
+ // remove BOM
304
+ $filecontent = preg_replace( "#\x{EF}\x{BB}\x{BF}#", "", $filecontent );
305
 
306
+ // remove comments and blank lines
307
+ if ( substr( $filepath, - 3, 3 ) === ".js" ) {
308
+ $filecontent = preg_replace( "#^\s*\/\/.*$#Um", "", $filecontent );
309
+ }
 
310
 
311
+ $filecontent = preg_replace( "#^\s*\/\*[^!].*\*\/\s?#Us", "", $filecontent );
312
+ $filecontent = preg_replace( "#(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+#", "\n", $filecontent );
313
+
314
+ // specific stuff for JS-files
315
+ if ( substr( $filepath, - 3, 3 ) === ".js" ) {
316
+ if ( ( substr( $filecontent, - 1, 1 ) !== ";" ) && ( substr( $filecontent, - 1, 1 ) !== "}" ) ) {
317
+ $filecontent .= ";";
318
+ }
319
+
320
+ if ( get_option( "breeze_js_trycatch" ) === "on" ) {
321
+ $filecontent = "try{" . $filecontent . "}catch(e){}";
322
+ }
323
+ } else if ( ( substr( $filepath, - 4, 4 ) === ".css" ) ) {
324
+ $filecontent = Breeze_MinificationStyles::fixurls( $filepath, $filecontent );
325
+ }
326
+
327
+ // return
328
+ return "\n" . $filecontent;
329
+ },
330
+ $in
331
+ );
332
+ } else {
333
+ $out = $in;
334
+ }
335
+
336
+ return $out;
337
+ }
338
+
339
+ /**
340
+ * Handles clear cache for the situation where cache files do not exist.
341
+ * @since 1.1.3
342
+ */
343
+ protected function clear_cache_data() {
344
+ //delete minify
345
+ Breeze_MinificationCache::clear_minification();
346
+ //clear normal cache
347
+ Breeze_PurgeCache::breeze_cache_flush();
348
+
349
+ //Breeze_PurgeCache::factory();
350
+ //clear varnish cache
351
+ $varnish_cache = new Breeze_PurgeVarnish();
352
+
353
+ $is_network = ( is_network_admin() || ( ! empty( $_POST['is_network'] ) && 'true' === $_POST['is_network'] ) );
354
+
355
+ if ( is_multisite() && $is_network ) {
356
+ $sites = get_sites();
357
+ foreach ( $sites as $site ) {
358
+ switch_to_blog( $site->blog_id );
359
+ $homepage = home_url() . '/?breeze';
360
+ $varnish_cache->purge_cache( $homepage );
361
+ restore_current_blog();
362
+ }
363
+ } else {
364
+ $homepage = home_url() . '/?breeze';
365
+ $varnish_cache->purge_cache( $homepage );
366
+ }
367
+ }
368
 
369
+ /**
370
+ * Helps to check if the cache file actually exists.
371
+ *
372
+ * @param string $file_path Full file path.
373
+ *
374
+ * @return bool
375
+ * @since 1.1.3
376
+ */
377
+ protected function is_cache_file_present( $file_path = '' ) {
378
+ if ( file_exists( $file_path ) ) {
379
+ return true;
380
+ }
381
+
382
+ return false;
383
+ }
384
+
385
+ public function get_cache_file_url( $type = 'css' ) {
386
+ $cache_dir = BREEZE_MINIFICATION_CACHE . breeze_current_user_type() . ( ! empty( $type ) ? $type . '/' : '' );
387
+ if ( is_multisite() ) {
388
+ $blog_id = get_current_blog_id();
389
+ $cache_dir = BREEZE_MINIFICATION_CACHE . $blog_id . '/' . breeze_current_user_type() . ( ! empty( $type ) ? $type . '/' : '' );
390
+ }
391
+
392
+ return $cache_dir;
393
+ }
394
  }
inc/minification/breeze-minification-cache.php CHANGED
@@ -1,123 +1,155 @@
1
  <?php
2
- if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
 
 
3
  /*
4
  * Based on some work of autoptimize plugin
5
  */
 
6
  class Breeze_MinificationCache {
7
- private $filename;
8
  private $mime;
9
  private $cachedir;
10
  private $delayed;
11
 
12
- public function __construct($md5,$ext='php') {
13
- $this->cachedir = BREEZE_MINIFICATION_CACHE;
14
- if(is_multisite()){
15
- $blog_id = get_current_blog_id();
16
- $this->cachedir = BREEZE_MINIFICATION_CACHE.$blog_id . '/';
17
- }
 
18
  $this->delayed = BREEZE_CACHE_DELAY;
19
- $this->nogzip = BREEZE_CACHE_NOGZIP;
20
- if($this->nogzip == false) {
21
- $this->filename = BREEZE_CACHEFILE_PREFIX.$md5.'.php';
22
  } else {
23
- if (in_array($ext, array("js","css"))) {
24
- $this->filename = $ext.'/'.BREEZE_CACHEFILE_PREFIX.$md5.'.'.$ext;
25
  } else {
26
- $this->filename = '/'.BREEZE_CACHEFILE_PREFIX.$md5.'.'.$ext;
27
  }
28
  }
29
 
30
 
31
  }
32
 
33
- public function check() {
34
- if(!file_exists($this->cachedir.$this->filename)) {
 
 
 
 
 
 
 
 
 
35
  // No cached file, sorry
36
  return false;
37
  }
 
38
  // Cache exists!
39
  return true;
40
  }
41
- public function retrieve() {
42
- if($this->check()) {
43
- if($this->nogzip == false) {
44
- return file_get_contents($this->cachedir.$this->filename.'.none');
 
45
  } else {
46
- return file_get_contents($this->cachedir.$this->filename);
47
  }
48
  }
 
49
  return false;
50
  }
51
- public function cache($code,$mime) {
52
- if($this->nogzip == false) {
53
- $file = ($this->delayed ? 'delayed.php' : 'default.php');
54
- $phpcode = file_get_contents(BREEZE_PLUGIN_DIR.'/inc/minification/config/'.$file);
55
- $phpcode = str_replace(array('%%CONTENT%%','exit;'),array($mime,''),$phpcode);
56
- file_put_contents($this->cachedir.$this->filename,$phpcode, LOCK_EX);
57
- file_put_contents($this->cachedir.$this->filename.'.none',$code, LOCK_EX);
58
- if(!$this->delayed) {
 
 
 
 
 
 
 
59
  // Compress now!
60
- file_put_contents($this->cachedir.$this->filename.'.deflate',gzencode($code,9,FORCE_DEFLATE), LOCK_EX);
61
- file_put_contents($this->cachedir.$this->filename.'.gzip',gzencode($code,9,FORCE_GZIP), LOCK_EX);
 
 
 
62
  }
63
  } else {
64
  // Write code to cache without doing anything else
65
- file_put_contents($this->cachedir.$this->filename,$code, LOCK_EX);
 
66
  }
67
  }
68
- public function getname() {
69
- apply_filters('breeze_filter_cache_getname',breeze_CACHE_URL.$this->filename);
 
 
70
  return $this->filename;
71
  }
72
- //create folder cache
73
- public static function create_cache_minification_folder(){
74
- if(!defined('BREEZE_MINIFICATION_CACHE')) {
75
- // We didn't set a cache
76
- return false;
77
- }
78
- if(is_multisite()){
79
- $blog_id = get_current_blog_id();
80
- foreach (array("","js","css") as $checkDir) {
81
- if(!Breeze_MinificationCache::checkCacheDir(BREEZE_MINIFICATION_CACHE. $blog_id .'/'.$checkDir)) {
82
- return false;
83
- }
84
- }
85
-
86
- /** write index.html here to avoid prying eyes */
87
- $indexFile=BREEZE_MINIFICATION_CACHE . $blog_id .'/index.html';
88
- if(!is_file($indexFile)) {
89
- @file_put_contents($indexFile,'<html><head><meta name="robots" content="noindex, nofollow"></head><body></body></html>');
90
- }
91
-
92
- /** write .htaccess here to overrule wp_super_cache */
93
- $htAccess=BREEZE_MINIFICATION_CACHE. $blog_id .'/.htaccess';
94
- }else{
95
- foreach (array("","js","css") as $checkDir) {
96
- if(!Breeze_MinificationCache::checkCacheDir(BREEZE_MINIFICATION_CACHE.$checkDir)) {
97
- return false;
98
- }
99
- }
100
- /** write index.html here to avoid prying eyes */
101
- $indexFile=BREEZE_MINIFICATION_CACHE.'/index.html';
102
- if(!is_file($indexFile)) {
103
- @file_put_contents($indexFile,'<html><head><meta name="robots" content="noindex, nofollow"></head><body></body></html>');
104
- }
105
-
106
- /** write .htaccess here to overrule wp_super_cache */
107
- $htAccess=BREEZE_MINIFICATION_CACHE.'/.htaccess';
108
- }
109
-
110
- if(!is_file($htAccess)) {
 
 
 
111
  /**
112
  * create wp-content/AO_htaccess_tmpl with
113
  * whatever htaccess rules you might need
114
  * if you want to override default AO htaccess
115
  */
116
- $htaccess_tmpl=WP_CONTENT_DIR."/AO_htaccess_tmpl";
117
- if (is_file($htaccess_tmpl)) {
118
- $htAccessContent=file_get_contents($htaccess_tmpl);
119
- } else if (is_multisite()) {
120
- $htAccessContent='<IfModule mod_headers.c>
121
  Header set Vary "Accept-Encoding"
122
  Header set Cache-Control "max-age=10672000, must-revalidate"
123
  </IfModule>
@@ -144,7 +176,7 @@ class Breeze_MinificationCache {
144
  </Files>
145
  </IfModule>';
146
  } else {
147
- $htAccessContent='<IfModule mod_headers.c>
148
  Header set Vary "Accept-Encoding"
149
  Header set Cache-Control "max-age=10672000, must-revalidate"
150
  </IfModule>
@@ -172,31 +204,33 @@ class Breeze_MinificationCache {
172
  </IfModule>';
173
  }
174
 
175
- @file_put_contents($htAccess,$htAccessContent);
176
  }
177
- // All OK
178
- return true;
179
 
180
- }
 
 
 
 
181
  // check dir cache
182
- static function checkCacheDir($dir) {
183
  // Check and create if not exists
184
- if(!file_exists($dir)) {
185
- @mkdir($dir,0775,true);
186
- if(!file_exists($dir)) {
187
  return false;
188
  }
189
  }
190
 
191
  // check if we can now write
192
- if(!is_writable($dir)) {
193
  return false;
194
  }
195
 
196
  // and write index.html here to avoid prying eyes
197
- $indexFile=$dir.'/index.html';
198
- if(!is_file($indexFile)) {
199
- @file_put_contents($indexFile,'<html><head><meta name="robots" content="noindex, nofollow"></head><body></body></html>');
200
  }
201
 
202
  return true;
@@ -223,44 +257,103 @@ class Breeze_MinificationCache {
223
  if ( ! isset( $_GET['breeze_purge'] ) && ! Breeze_MinificationCache::create_cache_minification_folder() ) {
224
  return false;
225
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
 
227
- if(is_multisite()){
228
- $blog_id = get_current_blog_id();
229
- // scan the cachedirs
230
- foreach (array("","js","css") as $scandirName) {
231
- $scan[$scandirName] = scandir(BREEZE_MINIFICATION_CACHE.$blog_id.'/'.$scandirName);
232
- }
233
- // clear the cachedirs
234
- foreach ($scan as $scandirName=>$scanneddir) {
235
- $thisAoCacheDir=rtrim(BREEZE_MINIFICATION_CACHE.$blog_id.'/'.$scandirName,"/")."/";
236
- foreach($scanneddir as $file) {
237
- if(!in_array($file,array('.','..')) && strpos($file,BREEZE_CACHEFILE_PREFIX) !== false && is_file($thisAoCacheDir.$file)) {
238
- @unlink($thisAoCacheDir.$file);
239
- }
240
- }
241
- }
242
- @unlink(BREEZE_MINIFICATION_CACHE.$blog_id."/.htaccess");
243
- }else{
244
- // scan the cachedirs
245
- foreach (array("","js","css") as $scandirName) {
246
- $scan[$scandirName] = scandir(BREEZE_MINIFICATION_CACHE.$scandirName);
247
- }
248
- // clear the cachedirs
249
- foreach ($scan as $scandirName=>$scanneddir) {
250
- $thisAoCacheDir=rtrim(BREEZE_MINIFICATION_CACHE.$scandirName,"/")."/";
251
- foreach($scanneddir as $file) {
252
- if(!in_array($file,array('.','..')) && strpos($file,BREEZE_CACHEFILE_PREFIX) !== false && is_file($thisAoCacheDir.$file)) {
253
- @unlink($thisAoCacheDir.$file);
254
- }
255
- }
256
- }
257
-
258
- @unlink(BREEZE_MINIFICATION_CACHE."/.htaccess");
259
- }
260
  return true;
261
  }
262
 
263
- public static function factory() {
264
 
265
  static $instance;
266
 
1
  <?php
2
+ if ( ! defined( 'ABSPATH' ) ) {
3
+ exit;
4
+ } // Exit if accessed directly
5
  /*
6
  * Based on some work of autoptimize plugin
7
  */
8
+
9
  class Breeze_MinificationCache {
10
+ private $filename;
11
  private $mime;
12
  private $cachedir;
13
  private $delayed;
14
 
15
+ public function __construct( $md5, $ext = 'php' ) {
16
+ $this->cachedir = BREEZE_MINIFICATION_CACHE . breeze_current_user_type();
17
+ if ( is_multisite() ) {
18
+ $blog_id = get_current_blog_id();
19
+ $this->cachedir = BREEZE_MINIFICATION_CACHE . $blog_id . '/' . breeze_current_user_type();
20
+ }
21
+
22
  $this->delayed = BREEZE_CACHE_DELAY;
23
+ $this->nogzip = BREEZE_CACHE_NOGZIP;
24
+ if ( $this->nogzip == false ) {
25
+ $this->filename = BREEZE_CACHEFILE_PREFIX . $md5 . '.php';
26
  } else {
27
+ if ( in_array( $ext, array( "js", "css" ) ) ) {
28
+ $this->filename = $ext . '/' . BREEZE_CACHEFILE_PREFIX . $md5 . '.' . $ext;
29
  } else {
30
+ $this->filename = '/' . BREEZE_CACHEFILE_PREFIX . $md5 . '.' . $ext;
31
  }
32
  }
33
 
34
 
35
  }
36
 
37
+ public function get_cache_dir(){
38
+ return $this->cachedir;
39
+ }
40
+
41
+ public function get_file_name(){
42
+ return $this->filename;
43
+ }
44
+
45
+ public function check() {
46
+ if ( ! file_exists( $this->cachedir . $this->filename ) ) {
47
+
48
  // No cached file, sorry
49
  return false;
50
  }
51
+
52
  // Cache exists!
53
  return true;
54
  }
55
+
56
+ public function retrieve() {
57
+ if ( $this->check() ) {
58
+ if ( $this->nogzip == false ) {
59
+ return file_get_contents( $this->cachedir . $this->filename . '.none' );
60
  } else {
61
+ return file_get_contents( $this->cachedir . $this->filename );
62
  }
63
  }
64
+
65
  return false;
66
  }
67
+
68
+ public function cache( $code, $mime ) {
69
+ if ( $this->nogzip == false ) {
70
+ $file = ( $this->delayed ? 'delayed.php' : 'default.php' );
71
+ $phpcode = file_get_contents( BREEZE_PLUGIN_DIR . '/inc/minification/config/' . $file );
72
+ $phpcode = str_replace( array( '%%CONTENT%%', 'exit;' ), array( $mime, '' ), $phpcode );
73
+
74
+
75
+ //file_put_contents( $this->cachedir . $this->filename, $phpcode, LOCK_EX );
76
+ breeze_read_write_file( $this->cachedir . $this->filename, $phpcode );
77
+
78
+ // file_put_contents( $this->cachedir . $this->filename . '.none', $code, LOCK_EX );
79
+ breeze_read_write_file( $this->cachedir . $this->filename . '.none', $code );
80
+
81
+ if ( ! $this->delayed ) {
82
  // Compress now!
83
+ // file_put_contents( $this->cachedir . $this->filename . '.deflate', gzencode( $code, 9, FORCE_DEFLATE ), LOCK_EX );
84
+ breeze_read_write_file( $this->cachedir . $this->filename . '.deflate', gzencode( $code, 9, FORCE_DEFLATE ) );
85
+
86
+ // file_put_contents( $this->cachedir . $this->filename . '.gzip', gzencode( $code, 9, FORCE_GZIP ), LOCK_EX );
87
+ breeze_read_write_file( $this->cachedir . $this->filename . '.deflate', gzencode( $code, 9, FORCE_DEFLATE ) );
88
  }
89
  } else {
90
  // Write code to cache without doing anything else
91
+ // file_put_contents( $this->cachedir . $this->filename, $code, LOCK_EX );
92
+ breeze_read_write_file( $this->cachedir . $this->filename, $code );
93
  }
94
  }
95
+
96
+ public function getname() {
97
+ apply_filters( 'breeze_filter_cache_getname', breeze_CACHE_URL . breeze_current_user_type() . $this->filename );
98
+
99
  return $this->filename;
100
  }
101
+
102
+ //create folder cache
103
+ public static function create_cache_minification_folder() {
104
+ if ( ! defined( 'BREEZE_MINIFICATION_CACHE' ) ) {
105
+ // We didn't set a cache
106
+ return false;
107
+ }
108
+ if ( is_multisite() ) {
109
+ $blog_id = get_current_blog_id();
110
+ foreach ( array( "", "js", "css" ) as $checkDir ) {
111
+ if ( ! Breeze_MinificationCache::checkCacheDir( BREEZE_MINIFICATION_CACHE . $blog_id . '/' . breeze_current_user_type() . $checkDir ) ) {
112
+ return false;
113
+ }
114
+ }
115
+
116
+ /** write index.html here to avoid prying eyes */
117
+ $indexFile = BREEZE_MINIFICATION_CACHE . $blog_id . '/' . breeze_current_user_type() . '/index.html';
118
+ if ( ! is_file( $indexFile ) ) {
119
+ //@file_put_contents( $indexFile, '<html><head><meta name="robots" content="noindex, nofollow"></head><body></body></html>' );
120
+ breeze_read_write_file($indexFile, '<html><head><meta name="robots" content="noindex, nofollow"></head><body></body></html>');
121
+ }
122
+
123
+ /** write .htaccess here to overrule wp_super_cache */
124
+ $htAccess = BREEZE_MINIFICATION_CACHE . $blog_id . '/' . breeze_current_user_type() . '.htaccess';
125
+ } else {
126
+ foreach ( array( "", "js", "css" ) as $checkDir ) {
127
+ if ( ! Breeze_MinificationCache::checkCacheDir( BREEZE_MINIFICATION_CACHE . breeze_current_user_type() . $checkDir ) ) {
128
+ return false;
129
+ }
130
+ }
131
+ /** write index.html here to avoid prying eyes */
132
+ $indexFile = BREEZE_MINIFICATION_CACHE . breeze_current_user_type() . '/index.html';
133
+ if ( ! is_file( $indexFile ) ) {
134
+ //@file_put_contents( $indexFile, '<html><head><meta name="robots" content="noindex, nofollow"></head><body></body></html>' );
135
+ breeze_read_write_file($indexFile, '<html><head><meta name="robots" content="noindex, nofollow"></head><body></body></html>');
136
+ }
137
+
138
+ /** write .htaccess here to overrule wp_super_cache */
139
+ $htAccess = BREEZE_MINIFICATION_CACHE . breeze_current_user_type() . '/.htaccess';
140
+ }
141
+
142
+ if ( ! is_file( $htAccess ) ) {
143
  /**
144
  * create wp-content/AO_htaccess_tmpl with
145
  * whatever htaccess rules you might need
146
  * if you want to override default AO htaccess
147
  */
148
+ $htaccess_tmpl = WP_CONTENT_DIR . "/AO_htaccess_tmpl";
149
+ if ( is_file( $htaccess_tmpl ) ) {
150
+ $htAccessContent = file_get_contents( $htaccess_tmpl );
151
+ } else if ( is_multisite() ) {
152
+ $htAccessContent = '<IfModule mod_headers.c>
153
  Header set Vary "Accept-Encoding"
154
  Header set Cache-Control "max-age=10672000, must-revalidate"
155
  </IfModule>
176
  </Files>
177
  </IfModule>';
178
  } else {
179
+ $htAccessContent = '<IfModule mod_headers.c>
180
  Header set Vary "Accept-Encoding"
181
  Header set Cache-Control "max-age=10672000, must-revalidate"
182
  </IfModule>
204
  </IfModule>';
205
  }
206
 
207
+ @file_put_contents( $htAccess, $htAccessContent );
208
  }
 
 
209
 
210
+ // All OK
211
+ return true;
212
+
213
+ }
214
+
215
  // check dir cache
216
+ static function checkCacheDir( $dir ) {
217
  // Check and create if not exists
218
+ if ( ! file_exists( $dir ) ) {
219
+ @mkdir( $dir, 0775, true );
220
+ if ( ! file_exists( $dir ) ) {
221
  return false;
222
  }
223
  }
224
 
225
  // check if we can now write
226
+ if ( ! is_writable( $dir ) ) {
227
  return false;
228
  }
229
 
230
  // and write index.html here to avoid prying eyes
231
+ $indexFile = $dir . '/index.html';
232
+ if ( ! is_file( $indexFile ) ) {
233
+ @file_put_contents( $indexFile, '<html><head><meta name="robots" content="noindex, nofollow"></head><body></body></html>' );
234
  }
235
 
236
  return true;
257
  if ( ! isset( $_GET['breeze_purge'] ) && ! Breeze_MinificationCache::create_cache_minification_folder() ) {
258
  return false;
259
  }
260
+ if ( ! isset( $scan ) ) {
261
+ $scan = array();
262
+ }
263
+ $cache_folders = breeze_all_user_folders();
264
+
265
+ if ( is_multisite() ) {
266
+ $blog_id = get_current_blog_id();
267
+ // scan the cachedirs
268
+ foreach ( $cache_folders as $user_folder ) {
269
+ foreach ( array( "", "js", "css" ) as $scandirName ) {
270
+ $directory = BREEZE_MINIFICATION_CACHE . $blog_id . '/' . ( ! empty( $user_folder ) ? $user_folder . '/' : '' ) . $scandirName;
271
+
272
+ if ( is_dir( $directory ) ) {
273
+
274
+ $files_list = scandir( $directory );
275
+ if ( ! empty( $files_list ) ) {
276
+ if ( ! isset( $scan[ $scandirName ] ) ) {
277
+ $scan[ $scandirName ] = array();
278
+ }
279
+
280
+ foreach ( $files_list as $index => $filename ) {
281
+ if ( ! in_array( $filename, $scan[ $scandirName ] ) ) {
282
+ $scan[ $scandirName ][] = $filename;
283
+ }
284
+ }
285
+
286
+ }
287
+
288
+ }
289
+ }
290
+ }
291
+
292
+ // clear the cachedirs
293
+ foreach ( $cache_folders as $user_folder ) {
294
+ foreach ( $scan as $scandirName => $scanneddir ) {
295
+ $thisAoCacheDir = rtrim( BREEZE_MINIFICATION_CACHE . $blog_id . '/' . ( ! empty( $user_folder ) ? $user_folder . '/' : '' ) . $scandirName, "/" ) . "/";
296
+
297
+ foreach ( $scanneddir as $file ) {
298
+ if ( ! in_array( $file, array( '.', '..' ) ) && ( strpos( $file, 'lock' ) !== false || strpos( $file, BREEZE_CACHEFILE_PREFIX ) !== false) && is_file( $thisAoCacheDir . $file ) ) {
299
+ @unlink( $thisAoCacheDir . $file );
300
+ }
301
+ }
302
+
303
+ @unlink( BREEZE_MINIFICATION_CACHE . $blog_id . '/' . ( ! empty( $user_folder ) ? $user_folder . '/' : '' ) . ".htaccess" );
304
+ @unlink( BREEZE_MINIFICATION_CACHE . $blog_id . '/' . ( ! empty( $user_folder ) ? $user_folder . '/' : '' ) . "process.lock" );
305
+ }
306
+ }
307
+
308
+
309
+ } else {
310
+
311
+ // scan the cachedirs
312
+ foreach ( $cache_folders as $user_folder ) {
313
+ foreach ( array( "", "js", "css" ) as $scandirName ) {
314
+ $directory = BREEZE_MINIFICATION_CACHE . ( ! empty( $user_folder ) ? $user_folder . '/' : '' ) . $scandirName;
315
+
316
+ if ( is_dir( $directory ) ) {
317
+ $files_list = scandir( $directory );
318
+ if ( ! empty( $files_list ) ) {
319
+ if ( ! isset( $scan[ $scandirName ] ) ) {
320
+ $scan[ $scandirName ] = array();
321
+ }
322
+
323
+ foreach ( $files_list as $index => $filename ) {
324
+ if ( ! in_array( $filename, $scan[ $scandirName ] ) ) {
325
+ $scan[ $scandirName ][] = $filename;
326
+ }
327
+ }
328
+
329
+ }
330
+ }
331
+
332
+ }
333
+ }
334
+
335
+ // clear the cachedirs
336
+ foreach ( $cache_folders as $user_folder ) {
337
+ foreach ( $scan as $scandirName => $scanneddir ) {
338
+ $thisAoCacheDir = rtrim( BREEZE_MINIFICATION_CACHE . ( ! empty( $user_folder ) ? $user_folder . '/' : '' ) . $scandirName, "/" ) . "/";
339
+
340
+ foreach ( $scanneddir as $file ) {
341
+ if ( ! in_array( $file, array( '.', '..' ) ) && ( strpos( $file, 'lock' ) !== false || strpos( $file, BREEZE_CACHEFILE_PREFIX ) !== false) && is_file( $thisAoCacheDir . $file ) ) {
342
+ @unlink( $thisAoCacheDir . $file );
343
+ }
344
+ }
345
+ }
346
+ @unlink( BREEZE_MINIFICATION_CACHE . ( ! empty( $user_folder ) ? $user_folder . '/' : '' ) . ".htaccess" );
347
+ @unlink( BREEZE_MINIFICATION_CACHE . ( ! empty( $user_folder ) ? $user_folder . '/' : '' ) . "process.lock" );
348
+ }
349
+
350
+
351
+ }
352
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
353
  return true;
354
  }
355
 
356
+ public static function factory() {
357
 
358
  static $instance;
359
 
inc/minification/breeze-minification-html.php CHANGED
@@ -2,88 +2,119 @@
2
  /*
3
  * Based on some work of autoptimize plugin
4
  */
5
- if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
 
 
6
 
7
  class Breeze_MinificationHtml extends Breeze_MinificationBase {
8
  private $keepcomments = false;
9
- private $exclude = array('<!-- ngg_resource_manager_marker -->');
10
-
11
- public function read($options) {
 
 
 
 
 
 
 
 
 
 
 
 
12
  // Remove the HTML comments?
13
  $this->keepcomments = (bool) $options['keepcomments'];
14
-
15
  // filter to force xhtml
16
  $this->forcexhtml = (bool) apply_filters( 'breeze_filter_html_forcexhtml', false );
17
-
18
  // filter to add strings to be excluded from HTML minification
19
- $excludeHTML = apply_filters( 'breeze_filter_html_exclude','' );
20
- if ($excludeHTML !== "") {
21
- $exclHTMLArr = array_filter(array_map('trim',explode(",",$excludeHTML)));
22
- $this->exclude = array_merge($exclHTMLArr, $this->exclude);
23
- }
24
-
25
  // Nothing else for HTML
26
  return true;
27
  }
28
-
29
  //Joins and optimizes CSS
30
  public function minify() {
31
- $noptimizeHTML = apply_filters( 'breeze_filter_html_noptimize', false, $this->content );
32
- if ($noptimizeHTML)
33
- return false;
34
-
35
- if(class_exists('Minify_HTML')) {
 
 
 
 
 
36
  // wrap the to-be-excluded strings in noptimize tags
37
- foreach ($this->exclude as $exclString) {
38
- if (strpos($this->content, $exclString)!==false) {
39
- $replString = "<!--noptimize-->".$exclString."<!--/noptimize-->";
40
- $this->content = str_replace($exclString, $replString, $this->content);
41
- }
42
- }
43
 
44
  // noptimize me
45
- $this->content = $this->hide_noptimize($this->content);
46
 
47
  // Minify html
48
- $options = array('keepComments' => $this->keepcomments);
49
- if ($this->forcexhtml) {
50
  $options['xhtml'] = true;
51
  }
52
 
53
- if (method_exists('Minify_HTML', 'minify')) {
54
- $tmp_content = Minify_HTML::minify($this->content, $options);
55
- if (!empty($tmp_content)) {
56
  $this->content = $tmp_content;
57
- unset($tmp_content);
58
  }
59
  }
60
 
61
  // restore noptimize
62
- $this->content = $this->restore_noptimize($this->content);
63
-
64
  // remove the noptimize-wrapper from around the excluded strings
65
- foreach ($this->exclude as $exclString) {
66
- $replString = "<!--noptimize-->".$exclString."<!--/noptimize-->";
67
- if (strpos($this->content, $replString) !== false) {
68
- $this->content = str_replace($replString, $exclString, $this->content);
69
- }
70
- }
71
 
72
  return true;
73
  }
74
-
75
  // Didn't minify :(
76
  return false;
77
  }
78
-
79
  // Does nothing
80
  public function cache() {
81
  //No cache for HTML
82
  return true;
83
  }
84
-
85
  //Returns the content
86
  public function getcontent() {
87
- return $this->content;
 
 
 
 
 
 
 
 
 
 
 
 
88
  }
89
  }
2
  /*
3
  * Based on some work of autoptimize plugin
4
  */
5
+ if ( ! defined( 'ABSPATH' ) ) {
6
+ exit;
7
+ } // Exit if accessed directly
8
 
9
  class Breeze_MinificationHtml extends Breeze_MinificationBase {
10
  private $keepcomments = false;
11
+ private $exclude = array( '<!-- ngg_resource_manager_marker -->' );
12
+ private $original_content = '';
13
+ private $show_original_content = 0;
14
+ private $do_process = false;
15
+
16
+ public function read( $options ) {
17
+ $this_path_url = $this->get_cache_file_url( '' );
18
+ if ( false === breeze_is_process_locked( $this_path_url ) ) {
19
+ $this->do_process = breeze_lock_cache_process( $this_path_url );
20
+ } else {
21
+ $this->original_content = $this->content;
22
+
23
+ return true;
24
+ }
25
+
26
  // Remove the HTML comments?
27
  $this->keepcomments = (bool) $options['keepcomments'];
28
+
29
  // filter to force xhtml
30
  $this->forcexhtml = (bool) apply_filters( 'breeze_filter_html_forcexhtml', false );
31
+
32
  // filter to add strings to be excluded from HTML minification
33
+ $excludeHTML = apply_filters( 'breeze_filter_html_exclude', '' );
34
+ if ( $excludeHTML !== "" ) {
35
+ $exclHTMLArr = array_filter( array_map( 'trim', explode( ",", $excludeHTML ) ) );
36
+ $this->exclude = array_merge( $exclHTMLArr, $this->exclude );
37
+ }
38
+
39
  // Nothing else for HTML
40
  return true;
41
  }
42
+
43
  //Joins and optimizes CSS
44
  public function minify() {
45
+ if ( false === $this->do_process ) {
46
+ return true;
47
+ }
48
+
49
+ $noptimizeHTML = apply_filters( 'breeze_filter_html_noptimize', false, $this->content );
50
+ if ( $noptimizeHTML ) {
51
+ return false;
52
+ }
53
+
54
+ if ( class_exists( 'Minify_HTML' ) ) {
55
  // wrap the to-be-excluded strings in noptimize tags
56
+ foreach ( $this->exclude as $exclString ) {
57
+ if ( strpos( $this->content, $exclString ) !== false ) {
58
+ $replString = "<!--noptimize-->" . $exclString . "<!--/noptimize-->";
59
+ $this->content = str_replace( $exclString, $replString, $this->content );
60
+ }
61
+ }
62
 
63
  // noptimize me
64
+ $this->content = $this->hide_noptimize( $this->content );
65
 
66
  // Minify html
67
+ $options = array( 'keepComments' => $this->keepcomments );
68
+ if ( $this->forcexhtml ) {
69
  $options['xhtml'] = true;
70
  }
71
 
72
+ if ( method_exists( 'Minify_HTML', 'minify' ) ) {
73
+ $tmp_content = Minify_HTML::minify( $this->content, $options );
74
+ if ( ! empty( $tmp_content ) ) {
75
  $this->content = $tmp_content;
76
+ unset( $tmp_content );
77
  }
78
  }
79
 
80
  // restore noptimize
81
+ $this->content = $this->restore_noptimize( $this->content );
82
+
83
  // remove the noptimize-wrapper from around the excluded strings
84
+ foreach ( $this->exclude as $exclString ) {
85
+ $replString = "<!--noptimize-->" . $exclString . "<!--/noptimize-->";
86
+ if ( strpos( $this->content, $replString ) !== false ) {
87
+ $this->content = str_replace( $replString, $exclString, $this->content );
88
+ }
89
+ }
90
 
91
  return true;
92
  }
93
+
94
  // Didn't minify :(
95
  return false;
96
  }
97
+
98
  // Does nothing
99
  public function cache() {
100
  //No cache for HTML
101
  return true;
102
  }
103
+
104
  //Returns the content
105
  public function getcontent() {
106
+ if ( ! empty( $this->show_original_content ) ) {
107
+ return $this->original_content;
108
+ }
109
+
110
+ if ( true === $this->do_process ) {
111
+ $this_path_url = $this->get_cache_file_url( '' );
112
+ breeze_unlock_process( $this_path_url );
113
+ return $this->content;
114
+ } else {
115
+ return $this->original_content;
116
+ }
117
+
118
+ //return $this->content;
119
  }
120
  }
inc/minification/breeze-minification-scripts.php CHANGED
@@ -1,712 +1,893 @@
1
- <?php
2
- /*
3
- * Based on some work of autoptimize plugin
4
- */
5
- if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
6
-
7
- class Breeze_MinificationScripts extends Breeze_MinificationBase {
8
- private $head_scripts = array();
9
- private $footer_scripts = array();
10
- private $dontmove = array('document.write','html5.js','show_ads.js','google_ad','blogcatalog.com/w','tweetmeme.com/i','mybloglog.com/','histats.com/js','ads.smowtion.com/ad.js','statcounter.com/counter/counter.js','widgets.amung.us','ws.amazon.com/widgets','media.fastclick.net','/ads/','comment-form-quicktags/quicktags.php','edToolbar','intensedebate.com','scripts.chitika.net/','_gaq.push','jotform.com/','admin-bar.min.js','GoogleAnalyticsObject','plupload.full.min.js','syntaxhighlighter','adsbygoogle','gist.github.com','_stq','nonce','post_id','data-noptimize');
11
- private $domove = array('gaJsHost','load_cmc','jd.gallery.transitions.js','swfobject.embedSWF(','tiny_mce.js','tinyMCEPreInit.go');
12
- private $domovelast = array('addthis.com','/afsonline/show_afs_search.js','disqus.js','networkedblogs.com/getnetworkwidget','infolinks.com/js/','jd.gallery.js.php','jd.gallery.transitions.js','swfobject.embedSWF(','linkwithin.com/widget.js','tiny_mce.js','tinyMCEPreInit.go');
13
- private $trycatch = false;
14
- private $alreadyminified = false;
15
- private $forcehead = true;
16
- private $include_inline = false;
17
- private $jscode = '';
18
- private $url = '';
19
- private $move = array('first' => array(), 'last' => array());
20
- private $restofcontent = '';
21
- private $md5hash = '';
22
- private $whitelist = '';
23
- private $jsremovables = array();
24
- private $inject_min_late = '';
25
- private $group_js = false;
26
- private $custom_js_exclude = array();
27
- private $js_head_group = array();
28
- private $js_footer_group = array();
29
- private $js_min_head = array();
30
- private $js_min_footer = array();
31
- private $url_group_head = array();
32
- private $url_group_footer = array();
33
- private $jscode_inline_head = array();
34
- private $jscode_inline_footer = array();
35
- private $move_to_footer_js = array();
36
- private $move_to_footer = array();
37
- private $defer_js = array();
38
-
39
- //Reads the page and collects script tags
40
- public function read($options) {
41
- $noptimizeJS = apply_filters( 'breeze_filter_js_noptimize', false, $this->content );
42
- if ($noptimizeJS) return false;
43
-
44
- // only optimize known good JS?
45
- $whitelistJS = apply_filters( 'breeze_filter_js_whitelist', "" );
46
- if (!empty($whitelistJS)) {
47
- $this->whitelist = array_filter(array_map('trim',explode(",",$whitelistJS)));
48
- }
49
-
50
- // is there JS we should simply remove
51
- $removableJS = apply_filters( 'breeze_filter_js_removables', '');
52
- if (!empty($removableJS)) {
53
- $this->jsremovables = array_filter(array_map('trim',explode(",",$removableJS)));
54
- }
55
-
56
- // only header?
57
- if( apply_filters('breeze_filter_js_justhead',$options['justhead']) == true ) {
58
- $content = explode('</head>',$this->content,2);
59
- $this->content = $content[0].'</head>';
60
- $this->restofcontent = $content[1];
61
- }
62
-
63
- // include inline?
64
- if( apply_filters('breeze_js_include_inline',$options['include_inline']) == true ) {
65
- $this->include_inline = true;
66
- }
67
-
68
- // group js?
69
- if( apply_filters('breeze_js_group_js',$options['group_js']) == true ) {
70
- $this->group_js = true;
71
- }
72
-
73
- //custom js exclude
74
- if(!empty($options['custom_js_exclude'])){
75
- $this->custom_js_exclude = $options['custom_js_exclude'];
76
- }
77
-
78
- // JS files will move to footer
79
- if(!empty($options['move_to_footer_js'])){
80
- $this->move_to_footer_js = $options['move_to_footer_js'];
81
- }
82
-
83
- // JS files will move to footer
84
- if(!empty($options['defer_js'])){
85
- $this->defer_js = $options['defer_js'];
86
- }
87
-
88
- // filter to "late inject minified JS", default to true for now (it is faster)
89
- $this->inject_min_late = apply_filters('breeze_filter_js_inject_min_late',true);
90
-
91
- // filters to override hardcoded do(nt)move(last) array contents (array in, array out!)
92
- $this->dontmove = apply_filters( 'breeze_js_dontmove', $this->dontmove );
93
- $this->domovelast = apply_filters( 'breeze_filter_js_movelast', $this->domovelast );
94
- $this->domove = apply_filters( 'breeze_filter_js_domove', $this->domove );
95
-
96
- // get extra exclusions settings or filter
97
- $excludeJS = $options['js_exclude'];
98
- $excludeJS = apply_filters( 'breeze_filter_js_exclude', $excludeJS );
99
- if ($excludeJS!=="") {
100
- $exclJSArr = array_filter(array_map('trim',explode(",",$excludeJS)));
101
- $this->dontmove = array_merge($exclJSArr,$this->dontmove);
102
- }
103
-
104
- //Should we add try-catch?
105
- if($options['trycatch'] == true)
106
- $this->trycatch = true;
107
-
108
- // force js in head?
109
- if($options['forcehead'] == true) {
110
- $this->forcehead = true;
111
- } else {
112
- $this->forcehead = false;
113
- }
114
- $this->forcehead = apply_filters( 'breeze_filter_js_forcehead', $this->forcehead );
115
-
116
- // get cdn url
117
- $this->cdn_url = $options['cdn_url'];
118
-
119
- // noptimize me
120
- $this->content = $this->hide_noptimize($this->content);
121
-
122
- // Save IE hacks
123
- $this->content = $this->hide_iehacks($this->content);
124
-
125
- // comments
126
- $this->content = $this->hide_comments($this->content);
127
-
128
- //Get script files
129
- $exploded_content = explode('</head>', $this->content, 2);
130
- $this->getJS($exploded_content[0]);
131
- $this->getJS($exploded_content[1], false);
132
-
133
- if (!empty($this->head_scripts) || !empty($this->footer_scripts)) {
134
- // Re-order moving to footer JS files
135
- $ordered_moving_js = array_intersect_key($this->move_to_footer_js, $this->move_to_footer);
136
- $ordered_moving_js = array_map(array($this, 'getpath'), $ordered_moving_js);
137
- $this->footer_scripts = array_merge($ordered_moving_js, $this->footer_scripts);
138
- return true;
139
- }
140
-
141
- // No script files, great!
142
- return false;
143
- }
144
-
145
- //Get all JS in page
146
- private function getJS($content, $head = true) {
147
- if(preg_match_all('#<script.*</script>#Usmi',$content,$matches)) {
148
- foreach($matches[0] as $tag) {
149
- // only consider aggregation whitelisted in should_aggregate-function
150
- if( !$this->should_aggregate($tag) ) {
151
- $tag='';
152
- continue;
153
- }
154
-
155
- if(preg_match('/\ssrc=("|\')?(.*(\ |\>))("|\')?/Usmi',$tag,$source)) {
156
- $source[2] = substr($source[2], 0, -1);
157
- if ($this->isremovable($tag,$this->jsremovables)) {
158
- $content = str_replace($tag,'',$content);
159
- continue;
160
- }
161
-
162
- // External script
163
- $url = current(explode('?',$source[2],2));
164
- if ($url[0] == "'" || $url[0] == '"') {
165
- $url = substr($url, 1);
166
- }
167
- if ($url[strlen($url) - 1] == '"' || $url[strlen($url) - 1] == "'") {
168
- $url = substr($url, 0 , -1);
169
- }
170
-
171
- // Let's check if this file is in the excluded list.
172
- $is_excluded = breeze_is_string_in_array_values( $url, $this->custom_js_exclude );
173
- //exclude js
174
- if ( ! empty( $is_excluded ) ) {
175
- continue;
176
- }
177
-
178
- $path = $this->getpath($url);
179
- if($path !== false && preg_match('#\.js$#',$path)) {
180
- //Inline
181
- if($this->ismergeable($tag)) {
182
- //We can merge it
183
- if ($head) {
184
- // If this file will be move to footer
185
- if (in_array($url, $this->move_to_footer_js)) {
186
- $this->move_to_footer[$url] = $path;
187
- } else {
188
- $this->head_scripts[$url] = $path;
189
- }
190
- } else {
191
- $this->footer_scripts[$url] = $path;
192
- }
193
- } else {
194
- //No merge, but maybe we can move it
195
- if($this->ismovable($tag)) {
196
- //Yeah, move it
197
- if($this->movetolast($tag)) {
198
- $this->move['last'][] = $tag;
199
- } else {
200
- $this->move['first'][] = $tag;
201
- }
202
- } else {
203
- //We shouldn't touch this
204
- $tag = '';
205
- }
206
- }
207
- } else {
208
- //External script (example: google analytics)
209
- //OR Script is dynamic (.php etc)
210
- if($this->ismovable($tag)) {
211
- if($this->movetolast($tag)) {
212
- $this->move['last'][] = $tag;
213
- } else {
214
- $this->move['first'][] = $tag;
215
- }
216
- } else {
217
- //We shouldn't touch this
218
- $tag = '';
219
- }
220
- }
221
- } else {
222
- // Inline script
223
- if ($this->isremovable($tag,$this->jsremovables)) {
224
- $content = str_replace($tag,'',$content);
225
- continue;
226
- }
227
-
228
- // unhide comments, as javascript may be wrapped in comment-tags for old times' sake
229
- $tag = $this->restore_comments($tag);
230
- if($this->ismergeable($tag) && ( $this->include_inline )) {
231
- preg_match('#<script.*>(.*)</script>#Usmi',$tag,$code);
232
- $code = preg_replace('#.*<!\[CDATA\[(?:\s*\*/)?(.*)(?://|/\*)\s*?\]\]>.*#sm','$1',$code[1]);
233
- $code = preg_replace('/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/','',$code);
234
-
235
- if ($head) {
236
- $this->head_scripts[] = 'INLINE;'.$code;
237
- } else {
238
- $this->footer_scripts[] = 'INLINE;'.$code;
239
- }
240
- } else {
241
- // Can we move this?
242
- if($this->ismovable($tag)) {
243
- if($this->movetolast($tag)) {
244
- $this->move['last'][] = $tag;
245
- } else {
246
- $this->move['first'][] = $tag;
247
- }
248
- } else {
249
- //We shouldn't touch this
250
- $tag = '';
251
- }
252
- }
253
- // re-hide comments to be able to do the removal based on tag from $this->content
254
- $tag = $this->hide_comments($tag);
255
- }
256
- //Remove the original script tag
257
- $content = str_replace($tag,'',$content);
258
- }
259
- }
260
-
261
- if ($head) {
262
- $this->content = $content;
263
- } else {
264
- $this->content .= '</head>' . $content;
265
- }
266
-
267
- return true;
268
- }
269
-
270
- public function minify() {
271
- $this->runMinify($this->head_scripts);
272
- $this->runMinify($this->footer_scripts, false);
273
-
274
- return true;
275
- }
276
-
277
- //Joins and optimizes JS
278
- private function runMinify($scripts, $head = true) {
279
- foreach($scripts as $url => $script) {
280
- if(preg_match('#^INLINE;#',$script)) {
281
- //Inline script
282
- $script = preg_replace('#^INLINE;#','',$script);
283
- $script = rtrim( $script, ";\n\t\r" ) . ';';
284
- //Add try-catch?
285
- if($this->trycatch) {
286
- $script = 'try{'.$script.'}catch(e){}';
287
- }
288
- $tmpscript = apply_filters( 'breeze_js_individual_script', $script, "" );
289
- if ( has_filter('breeze_js_individual_script') && !empty($tmpscript) ) {
290
- $script=$tmpscript;
291
- $this->alreadyminified=true;
292
- }
293
-
294
- if ($head) {
295
- $this->js_head_group[] = $script;
296
- } else {
297
- $this->js_footer_group[] = $script;
298
- }
299
- } else {
300
- //External script
301
- if($script !== false && file_exists($script) && is_readable($script)) {
302
- $scriptsrc = file_get_contents($script);
303
- $scriptsrc = preg_replace('/\x{EF}\x{BB}\x{BF}/','',$scriptsrc);
304
- $scriptsrc = rtrim($scriptsrc,";\n\t\r").';';
305
- //Add try-catch?
306
- if($this->trycatch) {
307
- $scriptsrc = 'try{'.$scriptsrc.'}catch(e){}';
308
- }
309
- $tmpscriptsrc = apply_filters( 'breeze_js_individual_script', $scriptsrc, $script );
310
- if ( has_filter('breeze_js_individual_script') && !empty($tmpscriptsrc) ) {
311
- $scriptsrc=$tmpscriptsrc;
312
- $this->alreadyminified=true;
313
- } else if ((strpos($script,"min.js")!==false) && ($this->inject_min_late===true)) {
314
- $scriptsrc="%%INJECTLATER".breeze_HASH."%%".base64_encode($script)."|".md5($scriptsrc)."%%INJECTLATER%%";
315
- }
316
- if($this->group_js == true){
317
- $this->jscode .= "\n" . $scriptsrc;
318
- }else{
319
- if ($head) {
320
- $this->js_head_group[$url] = $scriptsrc;
321
- } else {
322
- $this->js_footer_group[$url] = $scriptsrc;
323
- }
324
- }
325
- }/*else{
326
- //Couldn't read JS. Maybe getpath isn't working?
327
- }*/
328
- }
329
- }
330
-
331
- // Minify JS
332
- // When using group JS
333
- if (!$head && !empty($this->jscode)) {
334
- //Check for already-minified code
335
- $this->md5hash = md5($this->jscode);
336
- $ccheck = new Breeze_MinificationCache($this->md5hash,'js');
337
- if($ccheck->check()) {
338
- $this->jscode = $ccheck->retrieve();
339
- $this->alreadyminified = true;
340
- }
341
- unset($ccheck);
342
-
343
- //$this->jscode has all the uncompressed code now.
344
-
345
- if ($this->alreadyminified !== true) {
346
- if (class_exists('JSMin') && apply_filters( 'breeze_js_do_minify' , true)) {
347
- if (@is_callable(array("JSMin","minify"))) {
348
- $tmp_jscode = trim(JSMin::minify($this->jscode));
349
- if (!empty($tmp_jscode)) {
350
- $this->jscode = $tmp_jscode;
351
- unset($tmp_jscode);
352
- }
353
- }
354
- }
355
-
356
- $this->jscode = $this->inject_minified($this->jscode);
357
- }
358
-
359
- // Get the inline JS and minify
360
- if (!empty($this->js_head_group) || !empty($this->js_footer_group)) {
361
- if (!empty($this->js_head_group)) {
362
- foreach ($this->js_head_group as $jscode) {
363
- //$this->jscode has all the uncompressed code now.
364
- if (class_exists('JSMin') && apply_filters('breeze_js_do_minify', true)) {
365
- if (@is_callable(array("JSMin", "minify"))) {
366
- $tmp_jscode = trim(JSMin::minify($jscode));
367
- if (!empty($tmp_jscode)) {
368
- $jscode = $tmp_jscode;
369
- unset($tmp_jscode);
370
- }
371
- }
372
- }
373
-
374
- $this->jscode_inline_head[] = $this->inject_minified($jscode);
375
- }
376
- }
377
-
378
- if (!empty($this->js_footer_group)) {
379
- foreach ($this->js_footer_group as $jscode) {
380
- //$this->jscode has all the uncompressed code now.
381
- if (class_exists('JSMin') && apply_filters('breeze_js_do_minify', true)) {
382
- if (@is_callable(array("JSMin", "minify"))) {
383
- $tmp_jscode = trim(JSMin::minify($jscode));
384
- if (!empty($tmp_jscode)) {
385
- $jscode = $tmp_jscode;
386
- unset($tmp_jscode);
387
- }
388
- }
389
- }
390
-
391
- $this->jscode_inline_footer[] = $this->inject_minified($jscode);
392
- }
393
- }
394
- }
395
-
396
- return true;
397
- }
398
-
399
- // Not using group JS
400
- if (!empty($this->js_head_group) || !empty($this->js_footer_group)) {
401
- if ($head && !empty($this->js_head_group)) {
402
- foreach ($this->js_head_group as $url => $jscode) {
403
- //Check for already-minified code
404
- $this->md5hash = md5($jscode);
405
- $ccheck = new Breeze_MinificationCache($this->md5hash, 'js');
406
-
407
- if ($ccheck->check()) {
408
- $js_exist = $ccheck->retrieve();
409
- $this->js_min_head[$url] = $this->md5hash . '_breezejsgroup_' . $js_exist;
410
- continue;
411
- }
412
- unset($ccheck);
413
-
414
- //$this->jscode has all the uncompressed code now.
415
-
416
- if (class_exists('JSMin') && apply_filters('breeze_js_do_minify', true)) {
417
- if (@is_callable(array("JSMin", "minify"))) {
418
- $tmp_jscode = trim(JSMin::minify($jscode));
419
- if (!empty($tmp_jscode)) {
420
- $jscode = $tmp_jscode;
421
- unset($tmp_jscode);
422
- }
423
- }
424
- }
425
-
426
- $jscode = $this->inject_minified($jscode);
427
- $this->js_min_head[$url] = $this->md5hash . '_breezejsgroup_' . $jscode;
428
- }
429
- }
430
-
431
- if (!$head && !empty($this->js_footer_group)) {
432
- foreach ($this->js_footer_group as $url => $jscode) {
433
- //Check for already-minified code
434
- $this->md5hash = md5($jscode);
435
- $ccheck = new Breeze_MinificationCache($this->md5hash, 'js');
436
- if ($ccheck->check()) {
437
- $js_exist = $ccheck->retrieve();
438
- $this->js_min_footer[$url] = $this->md5hash . '_breezejsgroup_' . $js_exist;
439
- continue;
440
- }
441
- unset($ccheck);
442
-
443
- //$this->jscode has all the uncompressed code now.
444
-
445
- if (class_exists('JSMin') && apply_filters('breeze_js_do_minify', true)) {
446
- if (@is_callable(array("JSMin", "minify"))) {
447
- $tmp_jscode = trim(JSMin::minify($jscode));
448
- if (!empty($tmp_jscode)) {
449
- $jscode = $tmp_jscode;
450
- unset($tmp_jscode);
451
- }
452
- }
453
- }
454
-
455
- $jscode = $this->inject_minified($jscode);
456
- $this->js_min_footer[$url] = $this->md5hash . '_breezejsgroup_' . $jscode;
457
- }
458
- }
459
- }
460
-
461
- return true;
462
- }
463
-
464
- //Caches the JS in uncompressed, deflated and gzipped form.
465
- public function cache() {
466
- if($this->group_js == true){
467
- $cache = new Breeze_MinificationCache($this->md5hash,'js');
468
- if(!$cache->check()) {
469
- //Cache our code
470
- $cache->cache($this->jscode,'text/javascript');
471
- }
472
- $this->url = breeze_CACHE_URL.$cache->getname();
473
- $this->url = $this->url_replace_cdn($this->url);
474
- }else{
475
- foreach ($this->js_min_head as $old_url => $js_min){
476
- $namehash = substr($js_min, 0 , strpos($js_min,'_breezejsgroup_'));
477
- $js_code = substr($js_min,strpos($js_min,'_breezejsgroup_')+strlen('_breezejsgroup_'));
478
- $cache = new Breeze_MinificationCache($namehash,'js');
479
- if(!$cache->check()) {
480
- //Cache our code
481
- $cache->cache($js_code,'text/javascript');
482
- }
483
- $url = breeze_CACHE_URL.$cache->getname();
484
- $this->url_group_head[$old_url]= $this->url_replace_cdn($url);
485
- }
486
-
487
- foreach ($this->js_min_footer as $old_url => $js_min){
488
- $namehash = substr($js_min, 0 , strpos($js_min,'_breezejsgroup_'));
489
- $js_code = substr($js_min,strpos($js_min,'_breezejsgroup_')+strlen('_breezejsgroup_'));
490
- $cache = new Breeze_MinificationCache($namehash,'js');
491
- if(!$cache->check()) {
492
- //Cache our code
493
- $cache->cache($js_code,'text/javascript');
494
- }
495
- $url = breeze_CACHE_URL.$cache->getname();
496
- $this->url_group_footer[$old_url]= $this->url_replace_cdn($url);
497
- }
498
- }
499
- }
500
-
501
- // Returns the content
502
- public function getcontent() {
503
- // Restore the full content
504
- if(!empty($this->restofcontent)) {
505
- $this->content .= $this->restofcontent;
506
- $this->restofcontent = '';
507
- }
508
-
509
- // Load inline JS to html
510
- if (!empty($this->jscode_inline_head)) {
511
- $replaceTag = array("</head>", "before");
512
-
513
- foreach ($this->jscode_inline_head as $js) {
514
- $jsHead[] = '<script type="text/javascript">'.$js.'</script>';
515
- }
516
- $jsReplacement = '';
517
- $jsReplacement .= implode('', $jsHead);
518
- $this->inject_in_html($jsReplacement, $replaceTag);
519
- }
520
-
521
- if (!empty($this->jscode_inline_footer)) {
522
- $replaceTag = array("</body>", "before");
523
-
524
- foreach ($this->jscode_inline_footer as $js) {
525
- $jsFooter[] = '<script type="text/javascript">'.$js.'</script>';
526
- }
527
- $jsReplacement = '';
528
- $jsReplacement .= implode('', $jsFooter);
529
- $this->inject_in_html($jsReplacement, $replaceTag);
530
- }
531
-
532
- //$defer = apply_filters('breeze_filter_js_defer', $defer);
533
-
534
- if ($this->group_js == true) {
535
- $replaceTag = array("</body>", "before");
536
-
537
- $bodyreplacementpayload = '<script type="text/javascript" defer src="'.$this->url.'"></script>';
538
- $bodyreplacementpayload = apply_filters('breeze_filter_js_bodyreplacementpayload', $bodyreplacementpayload);
539
-
540
- $bodyreplacement = implode('',$this->move['first']);
541
- $bodyreplacement .= $bodyreplacementpayload;
542
- $bodyreplacement .= implode('',$this->move['last']);
543
-
544
- $replaceTag = apply_filters( 'breeze_filter_js_replacetag', $replaceTag );
545
-
546
- if (strlen($this->jscode)>0) {
547
- $this->inject_in_html($bodyreplacement,$replaceTag);
548
- }
549
- } else {
550
- $headScript = array();
551
- $footerScript = array();
552
-
553
- if (!empty($this->url_group_head)) {
554
- $replaceTag = array("</head>", "before");
555
-
556
- foreach ($this->url_group_head as $old_url => $url) {
557
- $defer = '';
558
- if (gettype($old_url) == 'string' && in_array($old_url, $this->defer_js)) {
559
- $defer = 'defer ';
560
- }
561
-
562
- $headScript[] = '<script type="text/javascript" ' . $defer . 'src="' . $url . '"></script>';
563
- }
564
- $jsReplacementPayload = implode('', $headScript);
565
-
566
- $jsReplacement = implode('', $this->move['first']);
567
- $jsReplacement .= $jsReplacementPayload;
568
-
569
- $replaceTag = apply_filters('breeze_filter_js_replacetag', $replaceTag);
570
-
571
- if (!empty($this->js_min_head)) {
572
- $this->inject_in_html($jsReplacement, $replaceTag);
573
- }
574
- }
575
-
576
- if (!empty($this->url_group_footer)) {
577
- $replaceTag = array("</body>", "before");
578
-
579
- foreach ($this->url_group_footer as $old_url => $url) {
580
- $defer = '';
581
- if (gettype($old_url) == 'string' && in_array($old_url, $this->defer_js)) {
582
- $defer = 'defer ';
583
- }
584
-
585
- $footerScript[] = '<script type="text/javascript" ' . $defer . 'src="' . $url . '"></script>';
586
- }
587
- $jsReplacementPayload = implode('', $footerScript);
588
-
589
- $jsReplacement = $jsReplacementPayload;
590
- $jsReplacement .= implode('', $this->move['last']);
591
-
592
- $replaceTag = apply_filters('breeze_filter_js_replacetag', $replaceTag);
593
-
594
- if (!empty($this->js_min_footer)) {
595
- $this->inject_in_html($jsReplacement, $replaceTag);
596
- }
597
- }
598
- }
599
-
600
- // restore comments
601
- $this->content = $this->restore_comments($this->content);
602
-
603
- // Restore IE hacks
604
- $this->content = $this->restore_iehacks($this->content);
605
-
606
- // Restore noptimize
607
- $this->content = $this->restore_noptimize($this->content);
608
-
609
- // Return the modified HTML
610
- return $this->content;
611
- }
612
-
613
- // Checks against the white- and blacklists
614
- private function ismergeable($tag) {
615
- if (!empty($this->whitelist)) {
616
- foreach ($this->whitelist as $match) {
617
- if(strpos($tag,$match)!==false) {
618
- return true;
619
- }
620
- }
621
- // no match with whitelist
622
- return false;
623
- } else {
624
- foreach($this->domove as $match) {
625
- if(strpos($tag,$match)!==false) {
626
- //Matched something
627
- return false;
628
- }
629
- }
630
-
631
- if ($this->movetolast($tag)) {
632
- return false;
633
- }
634
-
635
- foreach($this->dontmove as $match) {
636
- if(strpos($tag,$match)!==false) {
637
- //Matched something
638
- return false;
639
- }
640
- }
641
-
642
- // If we're here it's safe to merge
643
- return true;
644
- }
645
- }
646
-
647
- //Checks agains the blacklist
648
- private function ismovable($tag) {
649
- if ($this->include_inline !== true || apply_filters('breeze_filter_js_unmovable',true)) {
650
- return false;
651
- }
652
-
653
- foreach($this->domove as $match) {
654
- if(strpos($tag,$match)!==false) {
655
- //Matched something
656
- return true;
657
- }
658
- }
659
-
660
- if ($this->movetolast($tag)) {
661
- return true;
662
- }
663
-
664
- foreach($this->dontmove as $match) {
665
- if(strpos($tag,$match)!==false) {
666
- //Matched something
667
- return false;
668
- }
669
- }
670
-
671
- //If we're here it's safe to move
672
- return true;
673
- }
674
-
675
- private function movetolast($tag) {
676
- foreach($this->domovelast as $match) {
677
- if(strpos($tag,$match)!==false) {
678
- //Matched, return true
679
- return true;
680
- }
681
- }
682
-
683
- //Should be in 'first'
684
- return false;
685
- }
686
-
687
- /**
688
- * Determines wheter a <script> $tag should be aggregated or not.
689
- *
690
- * We consider these as "aggregation-safe" currently:
691
- * - script tags without a `type` attribute
692
- * - script tags with an explicit `type` of `text/javascript`, 'text/ecmascript',
693
- * 'application/javascript' or 'application/ecmascript'
694
- *
695
- * Everything else should return false.
696
- *
697
- * @param string $tag
698
- * @return bool
699
- *
700
- * original function by https://github.com/zytzagoo/ on his AO fork, thanks Tomas!
701
- */
702
- public function should_aggregate($tag) {
703
- preg_match('#<(script[^>]*)>#i',$tag,$scripttag);
704
- if ( strpos($scripttag[1], 'type=')===false ) {
705
- return true;
706
- } else if ( preg_match('/type=["\']?(?:text|application)\/(?:javascript|ecmascript)["\']?/i', $scripttag[1]) ) {
707
- return true;
708
- } else {
709
- return false;
710
- }
711
- }
712
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Based on some work of autoptimize plugin
4
+ */
5
+ if ( ! defined( 'ABSPATH' ) ) {
6
+ exit;
7
+ } // Exit if accessed directly
8
+
9
+ class Breeze_MinificationScripts extends Breeze_MinificationBase {
10
+ private $head_scripts = array();
11
+ private $footer_scripts = array();
12
+ private $dontmove = array(
13
+ 'gtag',
14
+ 'document.write',
15
+ 'html5.js',
16
+ 'show_ads.js',
17
+ 'google_ad',
18
+ 'blogcatalog.com/w',
19
+ 'tweetmeme.com/i',
20
+ 'mybloglog.com/',
21
+ 'histats.com/js',
22
+ 'ads.smowtion.com/ad.js',
23
+ 'statcounter.com/counter/counter.js',
24
+ 'widgets.amung.us',
25
+ 'ws.amazon.com/widgets',
26
+ 'media.fastclick.net',
27
+ '/ads/',
28
+ 'comment-form-quicktags/quicktags.php',
29
+ 'edToolbar',
30
+ 'intensedebate.com',
31
+ 'scripts.chitika.net/',
32
+ '_gaq.push',
33
+ 'jotform.com/',
34
+ 'admin-bar.min.js',
35
+ 'GoogleAnalyticsObject',
36
+ 'plupload.full.min.js',
37
+ 'syntaxhighlighter',
38
+ 'adsbygoogle',
39
+ 'gist.github.com',
40
+ '_stq',
41
+ 'nonce',
42
+ 'post_id',
43
+ 'data-noptimize',
44
+ );
45
+ private $domove = array( 'gaJsHost', 'load_cmc', 'jd.gallery.transitions.js', 'swfobject.embedSWF(', 'tiny_mce.js', 'tinyMCEPreInit.go' );
46
+ private $domovelast = array(
47
+ 'addthis.com',
48
+ '/afsonline/show_afs_search.js',
49
+ 'disqus.js',
50
+ 'networkedblogs.com/getnetworkwidget',
51
+ 'infolinks.com/js/',
52
+ 'jd.gallery.js.php',
53
+ 'jd.gallery.transitions.js',
54
+ 'swfobject.embedSWF(',
55
+ 'linkwithin.com/widget.js',
56
+ 'tiny_mce.js',
57
+ 'tinyMCEPreInit.go',
58
+ );
59
+ private $trycatch = false;
60
+ private $alreadyminified = false;
61
+ private $forcehead = true;
62
+ private $include_inline = false;
63
+ private $jscode = '';
64
+ private $url = '';
65
+ private $move = array(
66
+ 'first' => array(),
67
+ 'last' => array(),
68
+ );
69
+ private $restofcontent = '';
70
+ private $md5hash = '';
71
+ private $whitelist = '';
72
+ private $jsremovables = array();
73
+ private $inject_min_late = '';
74
+ private $group_js = false;
75
+ private $custom_js_exclude = array();
76
+ private $js_head_group = array();
77
+ private $js_footer_group = array();
78
+ private $js_min_head = array();
79
+ private $js_min_footer = array();
80
+ private $url_group_head = array();
81
+ private $url_group_footer = array();
82
+ private $jscode_inline_head = array();
83
+ private $jscode_inline_footer = array();
84
+ private $move_to_footer_js = array();
85
+ private $move_to_footer = array();
86
+ private $defer_js = array();
87
+ private $full_script = '';
88
+ private $uncompressed_inline = array();
89
+ private $inline_increment = 1;
90
+ private $original_content = '';
91
+ private $show_original_content = 0;
92
+ private $do_process = false;
93
+
94
+ //Reads the page and collects script tags
95
+ public function read( $options ) {
96
+
97
+ $this_path_url = $this->get_cache_file_url( 'js' );
98
+ if ( false === breeze_is_process_locked( $this_path_url ) ) {
99
+ $this->do_process = breeze_lock_cache_process( $this_path_url );
100
+ } else {
101
+ $this->original_content = $this->content;
102
+
103
+ return true;
104
+ }
105
+
106
+ $noptimizeJS = apply_filters( 'breeze_filter_js_noptimize', false, $this->content );
107
+ if ( $noptimizeJS ) {
108
+ return false;
109
+ }
110
+
111
+ // only optimize known good JS?
112
+ $whitelistJS = apply_filters( 'breeze_filter_js_whitelist', '' );
113
+ if ( ! empty( $whitelistJS ) ) {
114
+ $this->whitelist = array_filter( array_map( 'trim', explode( ',', $whitelistJS ) ) );
115
+ }
116
+
117
+ // is there JS we should simply remove
118
+ $removableJS = apply_filters( 'breeze_filter_js_removables', '' );
119
+ if ( ! empty( $removableJS ) ) {
120
+ $this->jsremovables = array_filter( array_map( 'trim', explode( ',', $removableJS ) ) );
121
+ }
122
+
123
+ // only header?
124
+ if ( apply_filters( 'breeze_filter_js_justhead', $options['justhead'] ) == true ) {
125
+ $content = explode( '</head>', $this->content, 2 );
126
+ $this->content = $content[0] . '</head>';
127
+ $this->restofcontent = $content[1];
128
+ }
129
+
130
+ // include inline?
131
+ if ( apply_filters( 'breeze_js_include_inline', $options['include_inline'] ) == true ) {
132
+ $this->include_inline = true;
133
+ }
134
+
135
+ // group js?
136
+ if ( apply_filters( 'breeze_js_group_js', $options['group_js'] ) == true ) {
137
+ $this->group_js = true;
138
+ }
139
+
140
+ //custom js exclude
141
+ if ( ! empty( $options['custom_js_exclude'] ) ) {
142
+ $this->custom_js_exclude = $options['custom_js_exclude'];
143
+ }
144
+
145
+ // JS files will move to footer
146
+ if ( ! empty( $options['move_to_footer_js'] ) ) {
147
+ $this->move_to_footer_js = $options['move_to_footer_js'];
148
+ }
149
+
150
+ // JS files will move to footer
151
+ if ( ! empty( $options['defer_js'] ) ) {
152
+ $this->defer_js = $options['defer_js'];
153
+ }
154
+
155
+ // filter to "late inject minified JS", default to true for now (it is faster)
156
+ $this->inject_min_late = apply_filters( 'breeze_filter_js_inject_min_late', true );
157
+
158
+ // filters to override hardcoded do(nt)move(last) array contents (array in, array out!)
159
+ $this->dontmove = apply_filters( 'breeze_js_dontmove', $this->dontmove );
160
+ $this->domovelast = apply_filters( 'breeze_filter_js_movelast', $this->domovelast );
161
+ $this->domove = apply_filters( 'breeze_filter_js_domove', $this->domove );
162
+
163
+ // get extra exclusions settings or filter
164
+ $excludeJS = $options['js_exclude'];
165
+ $excludeJS = apply_filters( 'breeze_filter_js_exclude', $excludeJS );
166
+ if ( $excludeJS !== '' ) {
167
+ $exclJSArr = array_filter( array_map( 'trim', explode( ',', $excludeJS ) ) );
168
+ $this->dontmove = array_merge( $exclJSArr, $this->dontmove );
169
+ }
170
+
171
+ //Should we add try-catch?
172
+ if ( $options['trycatch'] == true ) {
173
+ $this->trycatch = true;
174
+ }
175
+
176
+ // force js in head?
177
+ if ( $options['forcehead'] == true ) {
178
+ $this->forcehead = true;
179
+ } else {
180
+ $this->forcehead = false;
181
+ }
182
+ $this->forcehead = apply_filters( 'breeze_filter_js_forcehead', $this->forcehead );
183
+
184
+ // get cdn url
185
+ $this->cdn_url = $options['cdn_url'];
186
+
187
+ // noptimize me
188
+ $this->content = $this->hide_noptimize( $this->content );
189
+
190
+ // Save IE hacks
191
+ $this->content = $this->hide_iehacks( $this->content );
192
+
193
+ // comments
194
+ $this->content = $this->hide_comments( $this->content );
195
+
196
+ //Get script files
197
+ $exploded_content = explode( '</head>', $this->content, 2 );
198
+ $this->getJS( $exploded_content[0] );
199
+ $this->getJS( $exploded_content[1], false );
200
+
201
+ if ( ! empty( $this->head_scripts ) || ! empty( $this->footer_scripts ) ) {
202
+ // Re-order moving to footer JS files
203
+ $ordered_moving_js = array_intersect_key( $this->move_to_footer_js, $this->move_to_footer );
204
+ $ordered_moving_js = array_map( array( $this, 'getpath' ), $ordered_moving_js );
205
+ $this->footer_scripts = array_merge( $ordered_moving_js, $this->footer_scripts );
206
+
207
+ return true;
208
+ }
209
+
210
+ // No script files, great!
211
+ return false;
212
+ }
213
+
214
+ //Get all JS in page
215
+ private function getJS( $content, $head = true ) {
216
+ if ( preg_match_all( '#<script.*</script>#Usmi', $content, $matches ) ) {
217
+ foreach ( $matches[0] as $tag ) {
218
+ // only consider aggregation whitelisted in should_aggregate-function
219
+ if ( ! $this->should_aggregate( $tag ) ) {
220
+ $tag = '';
221
+ continue;
222
+ }
223
+
224
+ if ( preg_match( '/\ssrc=("|\')?(.*(\ |\>))("|\')?/Usmi', $tag, $source ) ) {
225
+ $source[2] = substr( $source[2], 0, - 1 );
226
+ if ( $this->isremovable( $tag, $this->jsremovables ) ) {
227
+ $content = str_replace( $tag, '', $content );
228
+ continue;
229
+ }
230
+
231
+ // External script
232
+ $url = current( explode( '?', $source[2], 2 ) );
233
+ if ( $url[0] == "'" || $url[0] == '"' ) {
234
+ $url = substr( $url, 1 );
235
+ }
236
+ if ( $url[ strlen( $url ) - 1 ] == '"' || $url[ strlen( $url ) - 1 ] == "'" ) {
237
+ $url = substr( $url, 0, - 1 );
238
+ }
239
+
240
+ // Let's check if this file is in the excluded list.
241
+ $is_excluded = breeze_is_string_in_array_values( $url, $this->custom_js_exclude );
242
+ //exclude js
243
+ if ( ! empty( $is_excluded ) ) {
244
+ continue;
245
+ }
246
+
247
+ $path = $this->getpath( $url );
248
+ if ( $path !== false && preg_match( '#\.js$#', $path ) ) {
249
+ //Inline
250
+ if ( $this->ismergeable( $tag ) ) {
251
+ //We can merge it
252
+ if ( $head ) {
253
+ // If this file will be move to footer
254
+ if ( in_array( $url, $this->move_to_footer_js ) ) {
255
+ $this->move_to_footer[ $url ] = $path;
256
+ } else {
257
+ $this->head_scripts[ $url ] = $path;
258
+ }
259
+ } else {
260
+ $this->footer_scripts[ $url ] = $path;
261
+ }
262
+ } else {
263
+ //No merge, but maybe we can move it
264
+ if ( $this->ismovable( $tag ) ) {
265
+ //Yeah, move it
266
+ if ( $this->movetolast( $tag ) ) {
267
+ $this->move['last'][] = $tag;
268
+ } else {
269
+ $this->move['first'][] = $tag;
270
+ }
271
+ } else {
272
+ //We shouldn't touch this
273
+ $tag = '';
274
+ }
275
+ }
276
+ } else {
277
+ //External script (example: google analytics)
278
+ //OR Script is dynamic (.php etc)
279
+ if ( $this->ismovable( $tag ) ) {
280
+ if ( $this->movetolast( $tag ) ) {
281
+ $this->move['last'][] = $tag;
282
+ } else {
283
+ $this->move['first'][] = $tag;
284
+ }
285
+ } else {
286
+ //We shouldn't touch this
287
+ $tag = '';
288
+ }
289
+ }
290
+ } else {
291
+ // Inline script
292
+ if ( $this->isremovable( $tag, $this->jsremovables ) ) {
293
+ $content = str_replace( $tag, '', $content );
294
+ continue;
295
+ }
296
+
297
+ // unhide comments, as javascript may be wrapped in comment-tags for old times' sake
298
+ $tag = $this->restore_comments( $tag );
299
+ if ( $this->ismergeable( $tag ) && ( $this->include_inline || $this->group_js ) ) {
300
+
301
+ preg_match( '#<script.*>(.*)</script>#Usmi', $tag, $code );
302
+ $code = preg_replace( '#.*<!\[CDATA\[(?:\s*\*/)?(.*)(?://|/\*)\s*?\]\]>.*#sm', '$1', $code[1] );
303
+ $code = preg_replace( '/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/', '', $code );
304
+
305
+ if ( $head ) {
306
+ $this->head_scripts[] = 'INLINE;' . $code;
307
+ } else {
308
+ $this->footer_scripts[] = 'INLINE;' . $code;
309
+ }
310
+ } else {
311
+ // Can we move this?
312
+ if ( $this->ismovable( $tag ) ) {
313
+ if ( $this->movetolast( $tag ) ) {
314
+ $this->move['last'][] = $tag;
315
+ } else {
316
+ $this->move['first'][] = $tag;
317
+ }
318
+ } else {
319
+ //We shouldn't touch this
320
+ $tag = '';
321
+ }
322
+ }
323
+ // re-hide comments to be able to do the removal based on tag from $this->content
324
+ $tag = $this->hide_comments( $tag );
325
+ }
326
+ //Remove the original script tag
327
+ $content = str_replace( $tag, '', $content );
328
+ }
329
+ }
330
+
331
+ if ( $head ) {
332
+ $this->content = $content;
333
+ } else {
334
+ $this->content .= '</head>' . $content;
335
+ }
336
+
337
+ return true;
338
+ }
339
+
340
+ public function minify() {
341
+ $this->runMinify( $this->head_scripts );
342
+ $this->runMinify( $this->footer_scripts, false );
343
+
344
+ if ( ! empty( $this->group_js ) && empty( $this->include_inline ) && ! empty( $this->uncompressed_inline ) ) {
345
+ foreach ( $this->uncompressed_inline as $index_inline => $uncompressed_js ) {
346
+ // add the uncompressed inline
347
+ $this->full_script = str_replace( $index_inline, $uncompressed_js, $this->full_script );
348
+ }
349
+ }
350
+
351
+ return true;
352
+ }
353
+
354
+ //Joins and optimizes JS
355
+ private function runMinify( $scripts, $head = true ) {
356
+ if ( false === $this->do_process ) {
357
+ return true;
358
+ }
359
+
360
+ foreach ( $scripts as $url => $script ) {
361
+
362
+ if ( preg_match( '#^INLINE;#', $script ) ) {
363
+ //Inline script
364
+ $script = preg_replace( '#^INLINE;#', '', $script );
365
+ $script = rtrim( $script, ";\n\t\r" ) . ';';
366
+ //Add try-catch?
367
+ if ( $this->trycatch ) {
368
+ $script = 'try{' . $script . '}catch(e){}';
369
+ }
370
+ $tmpscript = apply_filters( 'breeze_js_individual_script', $script, '' );
371
+ if ( has_filter( 'breeze_js_individual_script' ) && ! empty( $tmpscript ) ) {
372
+ $script = $tmpscript;
373
+ $this->alreadyminified = true;
374
+ }
375
+
376
+ if ( empty( $this->group_js ) ) {
377
+
378
+ if ( $head ) {
379
+ $this->js_head_group[] = $script;
380
+ } else {
381
+ $this->js_footer_group[] = $script;
382
+ }
383
+ }
384
+
385
+ if ( empty( $this->include_inline ) ) {
386
+
387
+ $index_inline = "/*!IS_UNCOMPRESSED_INLINE_{$this->inline_increment}*/";
388
+ $this->full_script .= $index_inline;
389
+ $this->uncompressed_inline[ $index_inline ] = $script;
390
+ $this->inline_increment ++;
391
+
392
+ } else {
393
+
394
+ $this->full_script .= $script;
395
+ }
396
+ } else {
397
+
398
+ //External script
399
+ if ( $script !== false && file_exists( $script ) && is_readable( $script ) ) {
400
+
401
+ $scriptsrc = file_get_contents( $script );
402
+ $scriptsrc = preg_replace( '/\x{EF}\x{BB}\x{BF}/', '', $scriptsrc );
403
+ $scriptsrc = rtrim( $scriptsrc, ";\n\t\r" ) . ';';
404
+
405
+ //Add try-catch?
406
+ if ( $this->trycatch ) {
407
+ $scriptsrc = 'try{' . $scriptsrc . '}catch(e){}';
408
+ }
409
+ $tmpscriptsrc = apply_filters( 'breeze_js_individual_script', $scriptsrc, $script );
410
+ if ( has_filter( 'breeze_js_individual_script' ) && ! empty( $tmpscriptsrc ) ) {
411
+ $scriptsrc = $tmpscriptsrc;
412
+ $this->alreadyminified = true;
413
+
414
+ } elseif ( ( strpos( $script, 'min.js' ) !== false ) && ( $this->inject_min_late === true ) || $this->breeze_js_files_exceptions( $url ) ) {
415
+ $scriptsrc = '%%INJECTLATER' . breeze_HASH . '%%' . base64_encode( $script ) . '|' . md5( $scriptsrc ) . '%%INJECTLATER%%';
416
+
417
+ }
418
+
419
+
420
+ if ( $this->group_js == true ) {
421
+ $this->jscode .= "\n" . $scriptsrc;
422
+ $this->full_script .= "\n" . $scriptsrc;
423
+ } else {
424
+ if ( $head ) {
425
+ $this->js_head_group[ $url ] = $scriptsrc;
426
+ } else {
427
+ $this->js_footer_group[ $url ] = $scriptsrc;
428
+ }
429
+ }
430
+ }/*else{
431
+ //Couldn't read JS. Maybe getpath isn't working?
432
+ }*/
433
+ }
434
+ }
435
+
436
+ // Minify JS
437
+ // When using group JS
438
+ if ( ! $head && ! empty( $this->jscode ) ) {
439
+ //Check for already-minified code
440
+ $this->md5hash = md5( $this->full_script );
441
+ $ccheck = new Breeze_MinificationCache( $this->md5hash, 'js' );
442
+ if ( $ccheck->check() ) {
443
+ $this->full_script = $ccheck->retrieve();
444
+ $this->alreadyminified = true;
445
+ }
446
+ unset( $ccheck );
447
+
448
+ //$this->jscode has all the uncompressed code now.
449
+
450
+ if ( $this->alreadyminified !== true ) {
451
+
452
+ if ( class_exists( 'JSMin' ) && apply_filters( 'breeze_js_do_minify', true ) ) {
453
+ if ( @is_callable( array( 'JSMin', 'minify' ) ) ) {
454
+
455
+ $tmp_jscode = trim( JSMin::minify( $this->full_script ) );
456
+ if ( ! empty( $tmp_jscode ) ) {
457
+ $this->full_script = $tmp_jscode;
458
+ unset( $tmp_jscode );
459
+ }
460
+ }
461
+ }
462
+
463
+ $this->full_script = $this->inject_minified( $this->full_script );
464
+ }
465
+
466
+ // Get the inline JS and minify
467
+ if ( ! empty( $this->js_head_group ) || ! empty( $this->js_footer_group ) ) {
468
+ if ( ! empty( $this->js_head_group ) ) {
469
+ foreach ( $this->js_head_group as $jscode ) {
470
+ //$this->jscode has all the uncompressed code now.
471
+ if ( class_exists( 'JSMin' ) && apply_filters( 'breeze_js_do_minify', true ) ) {
472
+ if ( @is_callable( array( 'JSMin', 'minify' ) ) ) {
473
+ $tmp_jscode = trim( JSMin::minify( $jscode ) );
474
+ if ( ! empty( $tmp_jscode ) ) {
475
+ $jscode = $tmp_jscode;
476
+ unset( $tmp_jscode );
477
+ }
478
+ }
479
+ }
480
+
481
+ $this->jscode_inline_head[] = $this->inject_minified( $jscode );
482
+ }
483
+ }
484
+
485
+ if ( ! empty( $this->js_footer_group ) ) {
486
+ foreach ( $this->js_footer_group as $jscode ) {
487
+ //$this->jscode has all the uncompressed code now.
488
+ if ( class_exists( 'JSMin' ) && apply_filters( 'breeze_js_do_minify', true ) ) {
489
+ if ( @is_callable( array( 'JSMin', 'minify' ) ) ) {
490
+ $tmp_jscode = trim( JSMin::minify( $jscode ) );
491
+ if ( ! empty( $tmp_jscode ) ) {
492
+ $jscode = $tmp_jscode;
493
+ unset( $tmp_jscode );
494
+ }
495
+ }
496
+ }
497
+
498
+ $this->jscode_inline_footer[] = $this->inject_minified( $jscode );
499
+ }
500
+ }
501
+ }
502
+
503
+ return true;
504
+ }
505
+
506
+ // Not using group JS
507
+ if ( ! empty( $this->js_head_group ) || ! empty( $this->js_footer_group ) ) {
508
+ if ( $head && ! empty( $this->js_head_group ) ) {
509
+ foreach ( $this->js_head_group as $url => $jscode ) {
510
+ //Check for already-minified code
511
+ $this->md5hash = md5( $jscode );
512
+ $ccheck = new Breeze_MinificationCache( $this->md5hash, 'js' );
513
+
514
+ if ( $ccheck->check() ) {
515
+ $js_exist = $ccheck->retrieve();
516
+ $this->js_min_head[ $url ] = $this->md5hash . '_breezejsgroup_' . $js_exist;
517
+ continue;
518
+ }
519
+ unset( $ccheck );
520
+
521
+ //$this->jscode has all the uncompressed code now.
522
+
523
+ if ( class_exists( 'JSMin' ) && apply_filters( 'breeze_js_do_minify', true ) ) {
524
+ if ( @is_callable( array( 'JSMin', 'minify' ) ) ) {
525
+ $tmp_jscode = trim( JSMin::minify( $jscode ) );
526
+ if ( ! empty( $tmp_jscode ) ) {
527
+ $jscode = $tmp_jscode;
528
+ unset( $tmp_jscode );
529
+ }
530
+ }
531
+ }
532
+
533
+ $jscode = $this->inject_minified( $jscode );
534
+ $this->js_min_head[ $url ] = $this->md5hash . '_breezejsgroup_' . $jscode;
535
+ }
536
+ }
537
+
538
+ if ( ! $head && ! empty( $this->js_footer_group ) ) {
539
+ foreach ( $this->js_footer_group as $url => $jscode ) {
540
+ //Check for already-minified code
541
+ $this->md5hash = md5( $jscode );
542
+ $ccheck = new Breeze_MinificationCache( $this->md5hash, 'js' );
543
+ if ( $ccheck->check() ) {
544
+ $js_exist = $ccheck->retrieve();
545
+ $this->js_min_footer[ $url ] = $this->md5hash . '_breezejsgroup_' . $js_exist;
546
+ continue;
547
+ }
548
+ unset( $ccheck );
549
+
550
+ //$this->jscode has all the uncompressed code now.
551
+
552
+ if ( class_exists( 'JSMin' ) && apply_filters( 'breeze_js_do_minify', true ) ) {
553
+ if ( @is_callable( array( 'JSMin', 'minify' ) ) ) {
554
+ $tmp_jscode = trim( JSMin::minify( $jscode ) );
555
+ if ( ! empty( $tmp_jscode ) ) {
556
+ $jscode = $tmp_jscode;
557
+ unset( $tmp_jscode );
558
+ }
559
+ }
560
+ }
561
+
562
+ $jscode = $this->inject_minified( $jscode );
563
+ $this->js_min_footer[ $url ] = $this->md5hash . '_breezejsgroup_' . $jscode;
564
+ }
565
+ }
566
+ }
567
+
568
+ return true;
569
+ }
570
+
571
+ //Caches the JS in uncompressed, deflated and gzipped form.
572
+ public function cache() {
573
+ if ( false === $this->do_process ) {
574
+ return true;
575
+ }
576
+
577
+ if ( $this->group_js == true ) {
578
+ // If inline is also included
579
+ $cache = new Breeze_MinificationCache( $this->md5hash, 'js' );
580
+
581
+ if ( ! $cache->check() ) {
582
+ //Cache our code
583
+ $cache->cache( $this->full_script, 'text/javascript' );
584
+ }
585
+
586
+ $cache_directory = $cache->get_cache_dir();
587
+ if ( $this->is_cache_file_present( $cache_directory . $cache->get_file_name() ) ) {
588
+ $this->url = breeze_CACHE_URL . breeze_current_user_type() . $cache->getname();
589
+ $this->url = $this->url_replace_cdn( $this->url );
590
+ } else {
591
+ $this->show_original_content = 1;
592
+ $this->clear_cache_data();
593
+ }
594
+
595
+ } else {
596
+ $url_exists = true;
597
+
598
+ foreach ( $this->js_min_head as $old_url => $js_min ) {
599
+ $namehash = substr( $js_min, 0, strpos( $js_min, '_breezejsgroup_' ) );
600
+ $js_code = substr( $js_min, strpos( $js_min, '_breezejsgroup_' ) + strlen( '_breezejsgroup_' ) );
601
+ $cache = new Breeze_MinificationCache( $namehash, 'js' );
602
+ if ( ! $cache->check() ) {
603
+ //Cache our code
604
+ $cache->cache( $js_code, 'text/javascript' );
605
+ }
606
+
607
+ $cache_directory = $cache->get_cache_dir();
608
+ if ( ! file_exists( $cache_directory . $cache->get_file_name() ) ) {
609
+ $url_exists = false;
610
+ } else {
611
+ $url = breeze_CACHE_URL . breeze_current_user_type() . $cache->getname();
612
+ $this->url_group_head[ $old_url ] = $this->url_replace_cdn( $url );
613
+ }
614
+ }
615
+
616
+ foreach ( $this->js_min_footer as $old_url => $js_min ) {
617
+ $namehash = substr( $js_min, 0, strpos( $js_min, '_breezejsgroup_' ) );
618
+ $js_code = substr( $js_min, strpos( $js_min, '_breezejsgroup_' ) + strlen( '_breezejsgroup_' ) );
619
+ $cache = new Breeze_MinificationCache( $namehash, 'js' );
620
+ if ( ! $cache->check() ) {
621
+ //Cache our code
622
+ $cache->cache( $js_code, 'text/javascript' );
623
+ }
624
+
625
+ $cache_directory = $cache->get_cache_dir();
626
+ if ( ! file_exists( $cache_directory . $cache->get_file_name() ) ) {
627
+ $url_exists = false;
628
+ } else {
629
+ $url = breeze_CACHE_URL . breeze_current_user_type() . $cache->getname();
630
+ $this->url_group_footer[ $old_url ] = $this->url_replace_cdn( $url );
631
+ }
632
+ }
633
+
634
+ if ( false === $url_exists ) {
635
+ $this->show_original_content = 1;
636
+ $this->clear_cache_data();
637
+ }
638
+ }
639
+ }
640
+
641
+ // Returns the content
642
+ public function getcontent() {
643
+ if ( ! empty( $this->show_original_content ) ) {
644
+ return $this->original_content;
645
+ }
646
+
647
+ // Restore the full content
648
+ if ( ! empty( $this->restofcontent ) ) {
649
+ $this->content .= $this->restofcontent;
650
+ $this->restofcontent = '';
651
+ }
652
+
653
+ // Load inline JS to html
654
+ if ( ! empty( $this->jscode_inline_head ) && empty( $this->group_js ) ) {
655
+
656
+ $replaceTag = array( '</head>', 'before' );
657
+
658
+ foreach ( $this->jscode_inline_head as $js ) {
659
+ $jsHead[] = '<script type="text/javascript">' . $js . '</script>';
660
+ }
661
+ $jsReplacement = '';
662
+ $jsReplacement .= implode( '', $jsHead );
663
+ $this->inject_in_html( $jsReplacement, $replaceTag );
664
+ }
665
+
666
+ if ( ! empty( $this->jscode_inline_footer ) && empty( $this->group_js ) ) {
667
+ $replaceTag = array( '</body>', 'before' );
668
+
669
+ foreach ( $this->jscode_inline_footer as $js ) {
670
+ $jsFooter[] = '<script type="text/javascript">' . $js . '</script>';
671
+ }
672
+ $jsReplacement = '';
673
+ $jsReplacement .= implode( '', $jsFooter );
674
+ $this->inject_in_html( $jsReplacement, $replaceTag );
675
+ }
676
+
677
+ //$defer = apply_filters('breeze_filter_js_defer', $defer);
678
+
679
+ if ( $this->group_js == true ) {
680
+ $replaceTag = array( '</body>', 'before' );
681
+
682
+ $bodyreplacementpayload = '<script type="text/javascript" defer src="' . $this->url . '"></script>';
683
+ $bodyreplacementpayload = apply_filters( 'breeze_filter_js_bodyreplacementpayload', $bodyreplacementpayload );
684
+
685
+ $bodyreplacement = implode( '', $this->move['first'] );
686
+ $bodyreplacement .= $bodyreplacementpayload;
687
+ $bodyreplacement .= implode( '', $this->move['last'] );
688
+
689
+ $replaceTag = apply_filters( 'breeze_filter_js_replacetag', $replaceTag );
690
+
691
+ if ( strlen( $this->full_script ) > 0 ) {
692
+ $this->inject_in_html( $bodyreplacement, $replaceTag );
693
+ }
694
+ } else {
695
+ $headScript = array();
696
+ $footerScript = array();
697
+
698
+ if ( ! empty( $this->url_group_head ) ) {
699
+ $replaceTag = array( '</head>', 'before' );
700
+
701
+ foreach ( $this->url_group_head as $old_url => $url ) {
702
+ $defer = '';
703
+ if ( gettype( $old_url ) == 'string' && in_array( $old_url, $this->defer_js ) ) {
704
+ $defer = 'defer ';
705
+ }
706
+
707
+ $headScript[] = '<script type="text/javascript" ' . $defer . 'src="' . $url . '"></script>';
708
+ }
709
+ $jsReplacementPayload = implode( '', $headScript );
710
+
711
+ $jsReplacement = implode( '', $this->move['first'] );
712
+ $jsReplacement .= $jsReplacementPayload;
713
+
714
+ $replaceTag = apply_filters( 'breeze_filter_js_replacetag', $replaceTag );
715
+
716
+ if ( ! empty( $this->js_min_head ) ) {
717
+ $this->inject_in_html( $jsReplacement, $replaceTag );
718
+ }
719
+ }
720
+
721
+ if ( ! empty( $this->url_group_footer ) ) {
722
+ $replaceTag = array( '</body>', 'before' );
723
+
724
+ foreach ( $this->url_group_footer as $old_url => $url ) {
725
+ $defer = '';
726
+ if ( gettype( $old_url ) == 'string' && in_array( $old_url, $this->defer_js ) ) {
727
+ $defer = 'defer ';
728
+ }
729
+
730
+ $footerScript[] = '<script type="text/javascript" ' . $defer . 'src="' . $url . '"></script>';
731
+ }
732
+ $jsReplacementPayload = implode( '', $footerScript );
733
+
734
+ $jsReplacement = $jsReplacementPayload;
735
+ $jsReplacement .= implode( '', $this->move['last'] );
736
+
737
+ $replaceTag = apply_filters( 'breeze_filter_js_replacetag', $replaceTag );
738
+
739
+ if ( ! empty( $this->js_min_footer ) ) {
740
+ $this->inject_in_html( $jsReplacement, $replaceTag );
741
+ }
742
+ }
743
+ }
744
+
745
+ // restore comments
746
+ $this->content = $this->restore_comments( $this->content );
747
+
748
+ // Restore IE hacks
749
+ $this->content = $this->restore_iehacks( $this->content );
750
+
751
+ // Restore noptimize
752
+ $this->content = $this->restore_noptimize( $this->content );
753
+
754
+ if ( true === $this->do_process ) {
755
+ $this_path_url = $this->get_cache_file_url( 'js' );
756
+ breeze_unlock_process( $this_path_url );
757
+
758
+ return $this->content;
759
+ } else {
760
+ return $this->original_content;
761
+ }
762
+ // Return the modified HTML
763
+ //return $this->content;
764
+ }
765
+
766
+ // Checks against the white- and blacklists
767
+ private function ismergeable( $tag ) {
768
+ if ( ! empty( $this->whitelist ) ) {
769
+ foreach ( $this->whitelist as $match ) {
770
+ if ( strpos( $tag, $match ) !== false ) {
771
+ return true;
772
+ }
773
+ }
774
+
775
+ // no match with whitelist
776
+ return false;
777
+ } else {
778
+ foreach ( $this->domove as $match ) {
779
+ if ( strpos( $tag, $match ) !== false ) {
780
+ //Matched something
781
+ return false;
782
+ }
783
+ }
784
+
785
+ if ( $this->movetolast( $tag ) ) {
786
+ return false;
787
+ }
788
+
789
+ foreach ( $this->dontmove as $match ) {
790
+ if ( strpos( $tag, $match ) !== false ) {
791
+ //Matched something
792
+ return false;
793
+ }
794
+ }
795
+
796
+ // If we're here it's safe to merge
797
+ return true;
798
+ }
799
+ }
800
+
801
+ //Checks agains the blacklist
802
+ private function ismovable( $tag ) {
803
+ if ( $this->include_inline !== true || apply_filters( 'breeze_filter_js_unmovable', true ) ) {
804
+ return false;
805
+ }
806
+
807
+ foreach ( $this->domove as $match ) {
808
+ if ( strpos( $tag, $match ) !== false ) {
809
+ //Matched something
810
+ return true;
811
+ }
812
+ }
813
+
814
+ if ( $this->movetolast( $tag ) ) {
815
+ return true;
816
+ }
817
+
818
+ foreach ( $this->dontmove as $match ) {
819
+ if ( strpos( $tag, $match ) !== false ) {
820
+ //Matched something
821
+ return false;
822
+ }
823
+ }
824
+
825
+ //If we're here it's safe to move
826
+ return true;
827
+ }
828
+
829
+ private function movetolast( $tag ) {
830
+ foreach ( $this->domovelast as $match ) {
831
+ if ( strpos( $tag, $match ) !== false ) {
832
+ //Matched, return true
833
+ return true;
834
+ }
835
+ }
836
+
837
+ //Should be in 'first'
838
+ return false;
839
+ }
840
+
841
+ /**
842
+ * Determines wheter a <script> $tag should be aggregated or not.
843
+ *
844
+ * We consider these as "aggregation-safe" currently:
845
+ * - script tags without a `type` attribute
846
+ * - script tags with an explicit `type` of `text/javascript`, 'text/ecmascript',
847
+ * 'application/javascript' or 'application/ecmascript'
848
+ *
849
+ * Everything else should return false.
850
+ *
851
+ * @param string $tag
852
+ *
853
+ * @return bool
854
+ *
855
+ * original function by https://github.com/zytzagoo/ on his AO fork, thanks Tomas!
856
+ */
857
+ public function should_aggregate( $tag ) {
858
+ preg_match( '#<(script[^>]*)>#i', $tag, $scripttag );
859
+ if ( strpos( $scripttag[1], 'type=' ) === false ) {
860
+ return true;
861
+ } elseif ( preg_match( '/type=["\']?(?:text|application)\/(?:javascript|ecmascript)["\']?/i', $scripttag[1] ) ) {
862
+ return true;
863
+ } else {
864
+ return false;
865
+ }
866
+ }
867
+
868
+ /**
869
+ * Search for specific exceptions.
870
+ * Files that should not be minified twice or included in grouping..
871
+ *
872
+ * @param $needle
873
+ *
874
+ * @return bool
875
+ * @since 1.1.3
876
+ */
877
+ private function breeze_js_files_exceptions( $needle ) {
878
+ $search_patterns = array(
879
+ 'cs-vendor\.[a-zA-Z0-9]*\.js',
880
+ 'cs\.[a-zA-Z0-9]*\.js',
881
+ );
882
+
883
+ $needle = trim( $needle );
884
+ foreach ( $search_patterns as $pattern ) {
885
+ preg_match( '/(' . $pattern . ')/i', $needle, $output_array );
886
+ if ( ! empty( $output_array ) ) { // is found ?
887
+ return true;
888
+ }
889
+ }
890
+
891
+ return false;
892
+ }
893
+ }
inc/minification/breeze-minification-styles.php CHANGED
@@ -1,745 +1,865 @@
1
- <?php
2
- /*
3
- * Based on some work of autoptimize plugin
4
- */
5
- if ( ! defined( 'ABSPATH' ) ) {
6
- exit;
7
- } // Exit if accessed directly
8
- class Breeze_MinificationStyles extends Breeze_MinificationBase {
9
- private $css = array();
10
- private $csscode = array();
11
- private $url = array();
12
- private $restofcontent = '';
13
- private $mhtml = '';
14
- private $datauris = false;
15
- private $hashmap = array();
16
- private $alreadyminified = false;
17
- private $inline = false;
18
- private $defer = false;
19
- private $defer_inline = false;
20
- private $whitelist = '';
21
- private $cssinlinesize = '';
22
- private $cssremovables = array();
23
- private $include_inline = false;
24
- private $inject_min_late = '';
25
- private $group_css = false;
26
- private $custom_css_exclude = array();
27
- private $css_group_val = array();
28
- private $css_min_arr = array();
29
- private $issetminfile = false;
30
- private $url_group_arr = array();
31
-
32
- //Reads the page and collects style tags
33
- public function read( $options ) {
34
- $noptimizeCSS = apply_filters( 'breeze_filter_css_noptimize', false, $this->content );
35
- if ( $noptimizeCSS ) {
36
- return false;
37
- }
38
- $whitelistCSS = apply_filters( 'breeze_filter_css_whitelist', '' );
39
- if ( ! empty( $whitelistCSS ) ) {
40
- $this->whitelist = array_filter( array_map( 'trim', explode( ",", $whitelistCSS ) ) );
41
- }
42
- if ( $options['nogooglefont'] == true ) {
43
- $removableCSS = "fonts.googleapis.com";
44
- } else {
45
- $removableCSS = "";
46
- }
47
- $removableCSS = apply_filters( 'breeze_filter_css_removables', $removableCSS );
48
- if ( ! empty( $removableCSS ) ) {
49
- $this->cssremovables = array_filter( array_map( 'trim', explode( ",", $removableCSS ) ) );
50
- }
51
- $this->cssinlinesize = apply_filters( 'breeze_filter_css_inlinesize', 256 );
52
- // filter to "late inject minified CSS", default to true for now (it is faster)
53
- $this->inject_min_late = apply_filters( 'breeze_filter_css_inject_min_late', true );
54
- // Remove everything that's not the header
55
- if ( apply_filters( 'breeze_filter_css_justhead', $options['justhead'] ) == true ) {
56
- $content = explode( '</head>', $this->content, 2 );
57
- $this->content = $content[0] . '</head>';
58
- $this->restofcontent = $content[1];
59
- }
60
- // include inline?
61
- if ( apply_filters( 'breeze_css_include_inline', $options['include_inline'] ) == true ) {
62
- $this->include_inline = true;
63
- }
64
- // group css?
65
- if ( apply_filters( 'breeze_css_include_inline', $options['groupcss'] ) == true ) {
66
- $this->group_css = true;
67
- }
68
- //custom js exclude
69
- if ( ! empty( $options['custom_css_exclude'] ) ) {
70
- $this->custom_css_exclude = $options['custom_css_exclude'];
71
- }
72
- // what CSS shouldn't be autoptimized
73
- $excludeCSS = $options['css_exclude'];
74
- $excludeCSS = apply_filters( 'breeze_filter_css_exclude', $excludeCSS );
75
- if ( $excludeCSS !== "" ) {
76
- $this->dontmove = array_filter( array_map( 'trim', explode( ",", $excludeCSS ) ) );
77
- } else {
78
- $this->dontmove = "";
79
- }
80
- // should we defer css?
81
- // value: true/ false
82
- $this->defer = $options['defer'];
83
- $this->defer = apply_filters( 'breeze_filter_css_defer', $this->defer );
84
- // should we inline while deferring?
85
- // value: inlined CSS
86
- $this->defer_inline = $options['defer_inline'];
87
- // should we inline?
88
- // value: true/ false
89
- $this->inline = $options['inline'];
90
- $this->inline = apply_filters( 'breeze_filter_css_inline', $this->inline );
91
- // get cdn url
92
- $this->cdn_url = $options['cdn_url'];
93
- // Store data: URIs setting for later use
94
- $this->datauris = $options['datauris'];
95
- // noptimize me
96
- $this->content = $this->hide_noptimize( $this->content );
97
- // exclude (no)script, as those may contain CSS which should be left as is
98
- if ( strpos( $this->content, '<script' ) !== false ) {
99
- $this->content = preg_replace_callback(
100
- '#<(?:no)?script.*?<\/(?:no)?script>#is',
101
- function ( $matches ) {
102
- return "%%SCRIPT" . breeze_HASH . "%%" . base64_encode( $matches[0] ) . "%%SCRIPT%%";
103
- },
104
- $this->content
105
- );
106
- }
107
- // Save IE hacks
108
- $this->content = $this->hide_iehacks( $this->content );
109
- // hide comments
110
- $this->content = $this->hide_comments( $this->content );
111
- // Get <style> and <link>
112
- if ( preg_match_all( '#(<style[^>]*>.*</style>)|(<link[^>]*stylesheet[^>]*>)#Usmi', $this->content, $matches ) ) {
113
- foreach ( $matches[0] as $tag ) {
114
- if ( $this->isremovable( $tag, $this->cssremovables ) ) {
115
- $this->content = str_replace( $tag, '', $this->content );
116
- } else if ( $this->ismovable( $tag ) ) {
117
- // Get the media
118
- if ( strpos( $tag, 'media=' ) !== false ) {
119
- preg_match( '#media=(?:"|\')([^>]*)(?:"|\')#Ui', $tag, $medias );
120
- $medias = explode( ',', $medias[1] );
121
- $media = array();
122
- foreach ( $medias as $elem ) {
123
- if ( empty( $elem ) ) {
124
- $elem = "all";
125
- }
126
- $media[] = $elem;
127
- }
128
- } else {
129
- // No media specified - applies to all
130
- $media = array( 'all' );
131
- }
132
- $media = apply_filters( 'breeze_filter_css_tagmedia', $media, $tag );
133
- if ( preg_match( '#<link.*href=("|\')(.*)("|\')#Usmi', $tag, $source ) ) {
134
- // <link>
135
- $url = current( explode( '?', $source[2], 2 ) );
136
- // Let's check if this file is in the excluded list.
137
- $is_excluded = breeze_is_string_in_array_values( $url, $this->custom_css_exclude );
138
- //exclude css file
139
- if ( ! empty( $is_excluded ) ) {
140
- continue;
141
- }
142
- $path = $this->getpath( $url );
143
- if ( $path !== false && preg_match( '#\.css$#', $path ) ) {
144
- // Good link
145
- $this->css[] = array( $media, $path );
146
- } else {
147
- // Link is dynamic (.php etc)
148
- $tag = '';
149
- }
150
- } else {
151
- // inline css in style tags can be wrapped in comment tags, so restore comments
152
- $tag = $this->restore_comments( $tag );
153
- preg_match( '#<style.*>(.*)</style>#Usmi', $tag, $code );
154
- // and re-hide them to be able to to the removal based on tag
155
- $tag = $this->hide_comments( $tag );
156
- if ( $this->include_inline ) {
157
- $code = preg_replace( '#^.*<!\[CDATA\[(?:\s*\*/)?(.*)(?://|/\*)\s*?\]\]>.*$#sm', '$1', $code[1] );
158
- $this->css[] = array( $media, 'INLINE;' . $code );
159
- } else {
160
- $tag = '';
161
- }
162
- }
163
- // Remove the original style tag
164
- $this->content = str_replace( $tag, '', $this->content );
165
- }
166
- }
167
-
168
- return true;
169
- }
170
-
171
- // Really, no styles?
172
- return false;
173
- }
174
-
175
- // Joins and optimizes CSS
176
- public function minify() {
177
- foreach ( $this->css as $group ) {
178
- list( $media, $css ) = $group;
179
- if ( preg_match( '#^INLINE;#', $css ) ) {
180
- // <style>
181
- $css = preg_replace( '#^INLINE;#', '', $css );
182
- $css = $this->fixurls( ABSPATH . '/index.php', $css );
183
- $tmpstyle = apply_filters( 'breeze_css_individual_style', $css, "" );
184
- if ( has_filter( 'breeze_css_individual_style' ) && ! empty( $tmpstyle ) ) {
185
- $css = $tmpstyle;
186
- $this->alreadyminified = true;
187
- }
188
- } else {
189
- //<link>
190
- if ( $css !== false && file_exists( $css ) && is_readable( $css ) ) {
191
- $cssPath = $css;
192
- $css = $this->fixurls( $cssPath, file_get_contents( $cssPath ) );
193
- $css = preg_replace( '/\x{EF}\x{BB}\x{BF}/', '', $css );
194
- $tmpstyle = apply_filters( 'breeze_css_individual_style', $css, $cssPath );
195
- if ( has_filter( 'breeze_css_individual_style' ) && ! empty( $tmpstyle ) ) {
196
- $css = $tmpstyle;
197
- $this->alreadyminified = true;
198
- } else if ( $this->can_inject_late( $cssPath, $css ) ) {
199
- $css = "%%INJECTLATER" . breeze_HASH . "%%" . base64_encode( $cssPath ) . "|" . md5( $css ) . "%%INJECTLATER%%";
200
- }
201
- } else {
202
- // Couldn't read CSS. Maybe getpath isn't working?
203
- $css = '';
204
- }
205
- }
206
- if ( $this->group_css == true ) {
207
- foreach ( $media as $elem ) {
208
- if ( ! isset( $this->csscode[ $elem ] ) ) {
209
- $this->csscode[ $elem ] = '';
210
- }
211
- $this->csscode[ $elem ] .= "\n/*FILESTART*/" . $css;
212
- }
213
- } else {
214
- foreach ( $media as $elem ) {
215
- $this->css_group_val[] = $elem . "_breezecssgroup_" . $css;
216
- }
217
- }
218
- }
219
- if ( $this->group_css == true ) {
220
- // Check for duplicate code
221
- $md5list = array();
222
- $tmpcss = $this->csscode;
223
- foreach ( $tmpcss as $media => $code ) {
224
- $md5sum = md5( $code );
225
- $medianame = $media;
226
- foreach ( $md5list as $med => $sum ) {
227
- // If same code
228
- if ( $sum === $md5sum ) {
229
- //Add the merged code
230
- $medianame = $med . ', ' . $media;
231
- $this->csscode[ $medianame ] = $code;
232
- $md5list[ $medianame ] = $md5list[ $med ];
233
- unset( $this->csscode[ $med ], $this->csscode[ $media ] );
234
- unset( $md5list[ $med ] );
235
- }
236
- }
237
- $md5list[ $medianame ] = $md5sum;
238
- }
239
- unset( $tmpcss );
240
- // Manage @imports, while is for recursive import management
241
- foreach ( $this->csscode as &$thiscss ) {
242
- // Flag to trigger import reconstitution and var to hold external imports
243
- $fiximports = false;
244
- $external_imports = "";
245
- while ( preg_match_all( '#^(/*\s?)@import.*(?:;|$)#Um', $thiscss, $matches ) ) {
246
- foreach ( $matches[0] as $import ) {
247
- if ( $this->isremovable( $import, $this->cssremovables ) ) {
248
- $thiscss = str_replace( $import, '', $thiscss );
249
- $import_ok = true;
250
- } else {
251
- $url = trim( preg_replace( '#^.*((?:https?:|ftp:)?//.*\.css).*$#', '$1', trim( $import ) ), " \t\n\r\0\x0B\"'" );
252
- $path = $this->getpath( $url );
253
- $import_ok = false;
254
- if ( file_exists( $path ) && is_readable( $path ) ) {
255
- $code = addcslashes( $this->fixurls( $path, file_get_contents( $path ) ), "\\" );
256
- $code = preg_replace( '/\x{EF}\x{BB}\x{BF}/', '', $code );
257
- $tmpstyle = apply_filters( 'breeze_css_individual_style', $code, "" );
258
- if ( has_filter( 'breeze_css_individual_style' ) && ! empty( $tmpstyle ) ) {
259
- $code = $tmpstyle;
260
- $this->alreadyminified = true;
261
- } else if ( $this->can_inject_late( $path, $code ) ) {
262
- $code = "%%INJECTLATER" . breeze_HASH . "%%" . base64_encode( $path ) . "|" . md5( $code ) . "%%INJECTLATER%%";
263
- }
264
- if ( ! empty( $code ) ) {
265
- $tmp_thiscss = preg_replace( '#(/\*FILESTART\*/.*)' . preg_quote( $import, '#' ) . '#Us', '/*FILESTART2*/' . $code . '$1', $thiscss );
266
- if ( ! empty( $tmp_thiscss ) ) {
267
- $thiscss = $tmp_thiscss;
268
- $import_ok = true;
269
- unset( $tmp_thiscss );
270
- }
271
- unset( $code );
272
- }
273
- }
274
- }
275
- if ( ! $import_ok ) {
276
- // external imports and general fall-back
277
- $external_imports .= $import;
278
- $thiscss = str_replace( $import, '', $thiscss );
279
- $fiximports = true;
280
- }
281
- }
282
- $thiscss = preg_replace( '#/\*FILESTART\*/#', '', $thiscss );
283
- $thiscss = preg_replace( '#/\*FILESTART2\*/#', '/*FILESTART*/', $thiscss );
284
- }
285
- // add external imports to top of aggregated CSS
286
- if ( $fiximports ) {
287
- $thiscss = $external_imports . $thiscss;
288
- }
289
- }
290
- unset( $thiscss );
291
- // $this->csscode has all the uncompressed code now.
292
- $mhtmlcount = 0;
293
- foreach ( $this->csscode as &$code ) {
294
- // Check for already-minified code
295
- $hash = md5( $code );
296
- $ccheck = new Breeze_MinificationCache( $hash, 'css' );
297
- if ( $ccheck->check() ) {
298
- $code = $ccheck->retrieve();
299
- $this->hashmap[ md5( $code ) ] = $hash;
300
- continue;
301
- }
302
- unset( $ccheck );
303
- // Do the imaging!
304
- $imgreplace = array();
305
- preg_match_all( '#(background[^;}]*url\((?!\s?"?\s?data)(.*)\)[^;}]*)(?:;|$|})#Usm', $code, $matches );
306
- if ( ( $this->datauris == true ) && ( function_exists( 'base64_encode' ) ) && ( is_array( $matches ) ) ) {
307
- foreach ( $matches[2] as $count => $quotedurl ) {
308
- $iurl = trim( $quotedurl, " \t\n\r\0\x0B\"'" );
309
- // if querystring, remove it from url
310
- if ( strpos( $iurl, '?' ) !== false ) {
311
- $iurl = strtok( $iurl, '?' );
312
- }
313
- $ipath = $this->getpath( $iurl );
314
- $datauri_max_size = 4096;
315
- $datauri_max_size = (int) apply_filters( 'breeze_filter_css_datauri_maxsize', $datauri_max_size );
316
- $datauri_exclude = apply_filters( 'breeze_filter_css_datauri_exclude', "" );
317
- if ( ! empty( $datauri_exclude ) ) {
318
- $no_datauris = array_filter( array_map( 'trim', explode( ",", $datauri_exclude ) ) );
319
- foreach ( $no_datauris as $no_datauri ) {
320
- if ( strpos( $iurl, $no_datauri ) !== false ) {
321
- $ipath = false;
322
- break;
323
- }
324
- }
325
- }
326
- if ( $ipath != false && preg_match( '#\.(jpe?g|png|gif|bmp)$#i', $ipath ) && file_exists( $ipath ) && is_readable( $ipath ) && filesize( $ipath ) <= $datauri_max_size ) {
327
- $ihash = md5( $ipath );
328
- $icheck = new Breeze_MinificationCache( $ihash, 'img' );
329
- if ( $icheck->check() ) {
330
- // we have the base64 image in cache
331
- $headAndData = $icheck->retrieve();
332
- $_base64data = explode( ";base64,", $headAndData );
333
- $base64data = $_base64data[1];
334
- } else {
335
- // It's an image and we don't have it in cache, get the type
336
- $explA = explode( '.', $ipath );
337
- $type = end( $explA );
338
- switch ( $type ) {
339
- case 'jpeg':
340
- $dataurihead = 'data:image/jpeg;base64,';
341
- break;
342
- case 'jpg':
343
- $dataurihead = 'data:image/jpeg;base64,';
344
- break;
345
- case 'gif':
346
- $dataurihead = 'data:image/gif;base64,';
347
- break;
348
- case 'png':
349
- $dataurihead = 'data:image/png;base64,';
350
- break;
351
- case 'bmp':
352
- $dataurihead = 'data:image/bmp;base64,';
353
- break;
354
- default:
355
- $dataurihead = 'data:application/octet-stream;base64,';
356
- }
357
- // Encode the data
358
- $base64data = base64_encode( file_get_contents( $ipath ) );
359
- $headAndData = $dataurihead . $base64data;
360
- // Save in cache
361
- $icheck->cache( $headAndData, "text/plain" );
362
- }
363
- unset( $icheck );
364
- // Add it to the list for replacement
365
- $imgreplace[ $matches[1][ $count ] ] = str_replace( $quotedurl, $headAndData, $matches[1][ $count ] ) . ";\n*" . str_replace( $quotedurl, 'mhtml:%%MHTML%%!' . $mhtmlcount, $matches[1][ $count ] ) . ";\n_" . $matches[1][ $count ] . ';';
366
- // Store image on the mhtml document
367
- $this->mhtml .= "--_\r\nContent-Location:{$mhtmlcount}\r\nContent-Transfer-Encoding:base64\r\n\r\n{$base64data}\r\n";
368
- $mhtmlcount ++;
369
- } else {
370
- // just cdn the URL if applicable
371
- if ( ! empty( $this->cdn_url ) ) {
372
- $url = trim( $quotedurl, " \t\n\r\0\x0B\"'" );
373
- $cdn_url = $this->url_replace_cdn( $url );
374
- $imgreplace[ $matches[1][ $count ] ] = str_replace( $quotedurl, $cdn_url, $matches[1][ $count ] );
375
- }
376
- }
377
- }
378
- } else if ( ( is_array( $matches ) ) && ( ! empty( $this->cdn_url ) ) ) {
379
- // change background image urls to cdn-url
380
- foreach ( $matches[2] as $count => $quotedurl ) {
381
- $url = trim( $quotedurl, " \t\n\r\0\x0B\"'" );
382
- $cdn_url = $this->url_replace_cdn( $url );
383
- $imgreplace[ $matches[1][ $count ] ] = str_replace( $quotedurl, $cdn_url, $matches[1][ $count ] );
384
- }
385
- }
386
- if ( ! empty( $imgreplace ) ) {
387
- $code = str_replace( array_keys( $imgreplace ), array_values( $imgreplace ), $code );
388
- }
389
- // CDN the fonts!
390
- if ( ( ! empty( $this->cdn_url ) ) && ( apply_filters( 'breeze_filter_css_fonts_cdn', false ) ) && ( version_compare( PHP_VERSION, '5.3.0' ) >= 0 ) ) {
391
- $fontreplace = array();
392
- include_once( BREEZE_PLUGIN_DIR . 'inc/minification/config/minificationFontRegex.php' );
393
- preg_match_all( $fonturl_regex, $code, $matches );
394
- if ( is_array( $matches ) ) {
395
- foreach ( $matches[8] as $count => $quotedurl ) {
396
- $url = trim( $quotedurl, " \t\n\r\0\x0B\"'" );
397
- $cdn_url = $this->url_replace_cdn( $url );
398
- $fontreplace[ $matches[8][ $count ] ] = str_replace( $quotedurl, $cdn_url, $matches[8][ $count ] );
399
- }
400
- if ( ! empty( $fontreplace ) ) {
401
- $code = str_replace( array_keys( $fontreplace ), array_values( $fontreplace ), $code );
402
- }
403
- }
404
- }
405
- // Minify
406
- if ( ( $this->alreadyminified !== true ) && ( apply_filters( "breeze_css_do_minify", true ) ) ) {
407
- if ( class_exists( 'Minify_CSS_Compressor' ) ) {
408
- $tmp_code = trim( Minify_CSS_Compressor::process( $code ) );
409
- } else if ( class_exists( 'CSSmin' ) ) {
410
- $cssmin = new CSSmin();
411
- if ( method_exists( $cssmin, "run" ) ) {
412
- $tmp_code = trim( $cssmin->run( $code ) );
413
- } elseif ( @is_callable( array( $cssmin, "minify" ) ) ) {
414
- $tmp_code = trim( CssMin::minify( $code ) );
415
- }
416
- }
417
- if ( ! empty( $tmp_code ) ) {
418
- $code = $tmp_code;
419
- unset( $tmp_code );
420
- }
421
- }
422
- $code = $this->inject_minified( $code );
423
- $tmp_code = apply_filters( 'breeze_css_after_minify', $code );
424
- if ( ! empty( $tmp_code ) ) {
425
- $code = $tmp_code;
426
- unset( $tmp_code );
427
- }
428
- $this->hashmap[ md5( $code ) ] = $hash;
429
- }
430
- unset( $code );
431
- } else {
432
- foreach ( $this->css_group_val as $value ) {
433
- $media = substr( $value, 0, strpos( $value, '_breezecssgroup_' ) );
434
- $css = substr( $value, strpos( $value, '_breezecssgroup_' ) + strlen( '_breezecssgroup_' ) );
435
- $hash = md5( $css );
436
- $ccheck = new Breeze_MinificationCache( $hash, 'css' );
437
- if ( $ccheck->check() ) {
438
- $css_exist = $ccheck->retrieve();
439
- $this->css_min_arr[] = $media . "_breezemedia_" . $hash . "_breezekey_" . $css_exist;
440
- continue;
441
- }
442
- unset( $ccheck );
443
- // Minify
444
- if ( class_exists( 'Minify_CSS_Compressor' ) ) {
445
- $tmp_code = trim( Minify_CSS_Compressor::process( $css ) );
446
- } else if ( class_exists( 'CSSmin' ) ) {
447
- $cssmin = new CSSmin();
448
- if ( method_exists( $cssmin, "run" ) ) {
449
- $tmp_code = trim( $cssmin->run( $css ) );
450
- } elseif ( @is_callable( array( $cssmin, "minify" ) ) ) {
451
- $tmp_code = trim( CssMin::minify( $css ) );
452
- }
453
- }
454
- if ( ! empty( $tmp_code ) ) {
455
- $css = $tmp_code;
456
- unset( $tmp_code );
457
- }
458
- $css = $this->inject_minified( $css );
459
- $css = apply_filters( 'breeze_css_after_minify', $css );
460
- $this->css_min_arr[] = $media . "_breezemedia_" . $hash . "_breezekey_" . $css;
461
- }
462
- unset( $css );
463
- }
464
-
465
- return true;
466
- }
467
-
468
- //Caches the CSS in uncompressed, deflated and gzipped form.
469
- public function cache() {
470
- if ( $this->datauris ) {
471
- // MHTML Preparation
472
- $this->mhtml = "/*\r\nContent-Type: multipart/related; boundary=\"_\"\r\n\r\n" . $this->mhtml . "*/\r\n";
473
- $md5 = md5( $this->mhtml );
474
- $cache = new Breeze_MinificationCache( $md5, 'txt' );
475
- if ( ! $cache->check() ) {
476
- // Cache our images for IE
477
- $cache->cache( $this->mhtml, 'text/plain' );
478
- }
479
- $mhtml = breeze_CACHE_URL . $cache->getname();
480
- }
481
- if ( $this->group_css == true ) {
482
- // CSS cache
483
- foreach ( $this->csscode as $media => $code ) {
484
- $md5 = $this->hashmap[ md5( $code ) ];
485
- if ( $this->datauris ) {
486
- // Images for ie! Get the right url
487
- $code = str_replace( '%%MHTML%%', $mhtml, $code );
488
- }
489
- $cache = new Breeze_MinificationCache( $md5, 'css' );
490
- if ( ! $cache->check() ) {
491
- // Cache our code
492
- $cache->cache( $code, 'text/css' );
493
- }
494
- $this->url[ $media ] = breeze_CACHE_URL . $cache->getname();
495
- }
496
- } else {
497
- foreach ( $this->css_min_arr as $value ) {
498
- $media = substr( $value, 0, strpos( $value, '_breezemedia_' ) );
499
- $code = substr( $value, strpos( $value, '_breezemedia_' ) + strlen( '_breezemedia_' ) );
500
- $hash = substr( $code, 0, strpos( $code, '_breezekey_' ) );
501
- $css = substr( $code, strpos( $code, '_breezekey_' ) + strlen( '_breezekey_' ) );
502
- $cache = new Breeze_MinificationCache( $hash, 'css' );
503
- if ( ! $cache->check() ) {
504
- // Cache our code
505
- $cache->cache( $css, 'text/css' );
506
- }
507
- $this->url_group_arr[] = $media . "_breezemedia_" . $hash . "_breezekey_" . breeze_CACHE_URL . $cache->getname();
508
- }
509
- }
510
- }
511
-
512
- //Returns the content
513
- public function getcontent() {
514
- // restore IE hacks
515
- $this->content = $this->restore_iehacks( $this->content );
516
- // restore comments
517
- $this->content = $this->restore_comments( $this->content );
518
- // restore (no)script
519
- if ( strpos( $this->content, '%%SCRIPT%%' ) !== false ) {
520
- $this->content = preg_replace_callback(
521
- '#%%SCRIPT' . breeze_HASH . '%%(.*?)%%SCRIPT%%#is',
522
-
523
- function ( $matches ) {
524
- return base64_decode( $matches[1] );
525
- },
526
- $this->content
527
- );
528
- }
529
- // restore noptimize
530
- $this->content = $this->restore_noptimize( $this->content );
531
- //Restore the full content
532
- if ( ! empty( $this->restofcontent ) ) {
533
- $this->content .= $this->restofcontent;
534
- $this->restofcontent = '';
535
- }
536
- // Inject the new stylesheets
537
- $replaceTag = array( "<title", "before" );
538
- $replaceTag = apply_filters( 'breeze_filter_css_replacetag', $replaceTag );
539
- if ( $this->group_css == true ) {
540
- if ( $this->inline == true ) {
541
- foreach ( $this->csscode as $media => $code ) {
542
- $this->inject_in_html( '<style type="text/css" media="' . $media . '">' . $code . '</style>', $replaceTag );
543
- }
544
- } else {
545
- if ( $this->defer == true ) {
546
- $deferredCssBlock = "<script data-cfasync='false'>function lCss(url,media) {var d=document;var l=d.createElement('link');l.rel='stylesheet';l.type='text/css';l.href=url;l.media=media;aoin=d.getElementsByTagName('noscript')[0];aoin.parentNode.insertBefore(l,aoin.nextSibling);}function deferredCSS() {";
547
- $noScriptCssBlock = "<noscript>";
548
- $defer_inline_code = $this->defer_inline;
549
- $defer_inline_code = apply_filters( 'breeze_filter_css_defer_inline', $defer_inline_code );
550
- if ( ! empty( $defer_inline_code ) ) {
551
- $iCssHash = md5( $defer_inline_code );
552
- $iCssCache = new Breeze_MinificationCache( $iCssHash, 'css' );
553
- if ( $iCssCache->check() ) {
554
- // we have the optimized inline CSS in cache
555
- $defer_inline_code = $iCssCache->retrieve();
556
- } else {
557
- if ( class_exists( 'Minify_CSS_Compressor' ) ) {
558
- $tmp_code = trim( Minify_CSS_Compressor::process( $this->defer_inline ) );
559
- } else if ( class_exists( 'CSSmin' ) ) {
560
- $cssmin = new CSSmin();
561
- $tmp_code = trim( $cssmin->run( $defer_inline_code ) );
562
- }
563
- if ( ! empty( $tmp_code ) ) {
564
- $defer_inline_code = $tmp_code;
565
- $iCssCache->cache( $defer_inline_code, "text/css" );
566
- unset( $tmp_code );
567
- }
568
- }
569
- $code_out = '<style type="text/css" id="aoatfcss" media="all">' . $defer_inline_code . '</style>';
570
- $this->inject_in_html( $code_out, $replaceTag );
571
- }
572
- }
573
- foreach ( $this->url as $media => $url ) {
574
- $url = $this->url_replace_cdn( $url );
575
- //Add the stylesheet either deferred (import at bottom) or normal links in head
576
- if ( $this->defer == true ) {
577
- $deferredCssBlock .= "lCss('" . $url . "','" . $media . "');";
578
- $noScriptCssBlock .= '<link type="text/css" media="' . $media . '" href="' . $url . '" rel="stylesheet" />';
579
- } else {
580
- if ( strlen( $this->csscode[ $media ] ) > $this->cssinlinesize ) {
581
- $this->inject_in_html( '<link type="text/css" media="' . $media . '" href="' . $url . '" rel="stylesheet" />', $replaceTag );
582
- } else if ( strlen( $this->csscode[ $media ] ) > 0 ) {
583
- $this->inject_in_html( '<style type="text/css" media="' . $media . '">' . $this->csscode[ $media ] . '</style>', $replaceTag );
584
- }
585
- }
586
- }
587
- if ( $this->defer == true ) {
588
- $deferredCssBlock .= "}if(window.addEventListener){window.addEventListener('DOMContentLoaded',deferredCSS,false);}else{window.onload = deferredCSS;}</script>";
589
- $noScriptCssBlock .= "</noscript>";
590
- $this->inject_in_html( $noScriptCssBlock, $replaceTag );
591
- $this->inject_in_html( $deferredCssBlock, array( '</body>', 'before' ) );
592
- }
593
- }
594
- } else {
595
- if ( $this->inline == true ) {
596
- foreach ( $this->csscode as $media => $code ) {
597
- $this->inject_in_html( '<style type="text/css" media="' . $media . '">' . $code . '</style>', $replaceTag );
598
- }
599
- } else {
600
- if ( $this->defer == true ) {
601
- $deferredCssBlock = "<script data-cfasync='false'>function lCss(url,media) {var d=document;var l=d.createElement('link');l.rel='stylesheet';l.type='text/css';l.href=url;l.media=media;aoin=d.getElementsByTagName('noscript')[0];aoin.parentNode.insertBefore(l,aoin.nextSibling);}function deferredCSS() {";
602
- $noScriptCssBlock = "<noscript>";
603
- $defer_inline_code = $this->defer_inline;
604
- $defer_inline_code = apply_filters( 'breeze_filter_css_defer_inline', $defer_inline_code );
605
- if ( ! empty( $defer_inline_code ) ) {
606
- $iCssHash = md5( $defer_inline_code );
607
- $iCssCache = new Breeze_MinificationCache( $iCssHash, 'css' );
608
- if ( $iCssCache->check() ) {
609
- // we have the optimized inline CSS in cache
610
- $defer_inline_code = $iCssCache->retrieve();
611
- } else {
612
- if ( class_exists( 'Minify_CSS_Compressor' ) ) {
613
- $tmp_code = trim( Minify_CSS_Compressor::process( $this->defer_inline ) );
614
- } else if ( class_exists( 'CSSmin' ) ) {
615
- $cssmin = new CSSmin();
616
- $tmp_code = trim( $cssmin->run( $defer_inline_code ) );
617
- }
618
- if ( ! empty( $tmp_code ) ) {
619
- $defer_inline_code = $tmp_code;
620
- $iCssCache->cache( $defer_inline_code, "text/css" );
621
- unset( $tmp_code );
622
- }
623
- }
624
- $code_out = '<style type="text/css" id="aoatfcss" media="all">' . $defer_inline_code . '</style>';
625
- $this->inject_in_html( $code_out, $replaceTag );
626
- }
627
- }
628
- foreach ( $this->url_group_arr as $value ) {
629
- $media = substr( $value, 0, strpos( $value, '_breezemedia_' ) );
630
- $code = substr( $value, strpos( $value, '_breezemedia_' ) + strlen( '_breezemedia_' ) );
631
- $hash = substr( $code, 0, strpos( $code, '_breezekey_' ) );
632
- $url = substr( $code, strpos( $code, '_breezekey_' ) + strlen( '_breezekey_' ) );
633
- $cache = new Breeze_MinificationCache( $hash, 'css' );
634
- if ( $cache->check() ) {
635
- $csscode = $cache->retrieve();
636
- }
637
- //Add the stylesheet either deferred (import at bottom) or normal links in head
638
- if ( $this->defer == true ) {
639
- $deferredCssBlock .= "lCss('" . $url . "','" . $media . "');";
640
- $noScriptCssBlock .= '<link type="text/css" media="' . $media . '" href="' . $url . '" rel="stylesheet" />';
641
- } else {
642
- if ( strlen( $csscode ) > $this->cssinlinesize ) {
643
- $url = $this->url_replace_cdn( $url );
644
- $this->inject_in_html( '<link type="text/css" media="' . $media . '" href="' . $url . '" rel="stylesheet" />', $replaceTag );
645
- } else if ( strlen( $csscode ) > 0 ) {
646
- $this->inject_in_html( '<style type="text/css" media="' . $media . '">' . $csscode . '</style>', $replaceTag );
647
- }
648
- }
649
- }
650
- if ( $this->defer == true ) {
651
- $deferredCssBlock .= "}if(window.addEventListener){window.addEventListener('DOMContentLoaded',deferredCSS,false);}else{window.onload = deferredCSS;}</script>";
652
- $noScriptCssBlock .= "</noscript>";
653
- $this->inject_in_html( $noScriptCssBlock, $replaceTag );
654
- $this->inject_in_html( $deferredCssBlock, array( '</body>', 'before' ) );
655
- }
656
- }
657
- }
658
-
659
- //Return the modified stylesheet
660
- return $this->content;
661
- }
662
-
663
- static function fixurls( $file, $code ) {
664
- $file = str_replace( BREEZE_ROOT_DIR, '/', $file );
665
- $dir = dirname( $file ); //Like /wp-content
666
- // quick fix for import-troubles in e.g. arras theme
667
- $code = preg_replace( '#@import ("|\')(.+?)\.css("|\')#', '@import url("${2}.css")', $code );
668
- if ( preg_match_all( '#url\((?!data)(?!\#)(?!"\#)(.*)\)#Usi', $code, $matches ) ) {
669
- $replace = array();
670
- foreach ( $matches[1] as $k => $url ) {
671
- // Remove quotes
672
- $url = trim( $url, " \t\n\r\0\x0B\"'" );
673
- $noQurl = trim( $url, "\"'" );
674
- if ( $url !== $noQurl ) {
675
- $removedQuotes = true;
676
- } else {
677
- $removedQuotes = false;
678
- }
679
- $url = $noQurl;
680
- if ( substr( $url, 0, 1 ) == '/' || preg_match( '#^(https?://|ftp://|data:)#i', $url ) ) {
681
- //URL is absolute
682
- continue;
683
- } else {
684
- // relative URL
685
- $newurl = preg_replace( '/https?:/', '', str_replace( " ", "%20", breeze_WP_ROOT_URL . str_replace( '//', '/', $dir . '/' . $url ) ) );
686
- $hash = md5( $url );
687
- $code = str_replace( $matches[0][ $k ], $hash, $code );
688
- if ( ! empty( $removedQuotes ) ) {
689
- $replace[ $hash ] = 'url(\'' . $newurl . '\')';
690
- } else {
691
- $replace[ $hash ] = 'url(' . $newurl . ')';
692
- }
693
- }
694
- }
695
- //Do the replacing here to avoid breaking URLs
696
- $code = str_replace( array_keys( $replace ), array_values( $replace ), $code );
697
- }
698
-
699
- return $code;
700
- }
701
-
702
- private function ismovable( $tag ) {
703
- if ( ! empty( $this->whitelist ) ) {
704
- foreach ( $this->whitelist as $match ) {
705
- if ( strpos( $tag, $match ) !== false ) {
706
- return true;
707
- }
708
- }
709
-
710
- // no match with whitelist
711
- return false;
712
- } else {
713
- if ( is_array( $this->dontmove ) ) {
714
- foreach ( $this->dontmove as $match ) {
715
- if ( strpos( $tag, $match ) !== false ) {
716
- //Matched something
717
- return false;
718
- }
719
- }
720
- }
721
-
722
- //If we're here it's safe to move
723
- return true;
724
- }
725
- }
726
-
727
- private function can_inject_late( $cssPath, $css ) {
728
- if ( ( strpos( $cssPath, "min.css" ) === false ) || ( $this->inject_min_late !== true ) ) {
729
- // late-inject turned off or file not minified based on filename
730
- return false;
731
- } else if ( strpos( $css, "@import" ) !== false ) {
732
- // can't late-inject files with imports as those need to be aggregated
733
- return false;
734
- } else if ( ( strpos( $css, "@font-face" ) !== false ) && ( apply_filters( "breeze_filter_css_fonts_cdn", false ) === true ) && ( ! empty( $this->cdn_url ) ) ) {
735
- // don't late-inject CSS with font-src's if fonts are set to be CDN'ed
736
- return false;
737
- } else if ( ( ( $this->datauris == true ) || ( ! empty( $this->cdn_url ) ) ) && preg_match( "#background[^;}]*url\(#Ui", $css ) ) {
738
- // don't late-inject CSS with images if CDN is set OR is image inlining is on
739
- return false;
740
- } else {
741
- // phew, all is safe, we can late-inject
742
- return true;
743
- }
744
- }
745
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Based on some work of autoptimize plugin
4
+ */
5
+ if ( ! defined( 'ABSPATH' ) ) {
6
+ exit;
7
+ } // Exit if accessed directly
8
+ class Breeze_MinificationStyles extends Breeze_MinificationBase {
9
+ private $css = array();
10
+ private $csscode = array();
11
+ private $url = array();
12
+ private $restofcontent = '';
13
+ private $mhtml = '';
14
+ private $datauris = false;
15
+ private $hashmap = array();
16
+ private $alreadyminified = false;
17
+ private $inline = false;
18
+ private $defer = false;
19
+ private $defer_inline = false;
20
+ private $whitelist = '';
21
+ private $cssinlinesize = '';
22
+ private $cssremovables = array();
23
+ private $include_inline = false;
24
+ private $inject_min_late = '';
25
+ private $group_css = false;
26
+ private $custom_css_exclude = array();
27
+ private $css_group_val = array();
28
+ private $css_min_arr = array();
29
+ private $issetminfile = false;
30
+ private $url_group_arr = array();
31
+ private $include_imported_css = false;
32
+ private $original_content = '';
33
+ private $show_original_content = 0;
34
+ private $do_process = false;
35
+
36
+
37
+ //Reads the page and collects style tags
38
+ public function read( $options ) {
39
+ $this->include_imported_css = filter_var( $options['include_imported_css'], FILTER_VALIDATE_BOOLEAN );
40
+
41
+ $this_path_url = $this->get_cache_file_url( 'css' );
42
+ if ( false === breeze_is_process_locked( $this_path_url ) ) {
43
+ $this->do_process = breeze_lock_cache_process( $this_path_url );
44
+ } else {
45
+ $this->original_content = $this->content;
46
+
47
+ return true;
48
+ }
49
+
50
+ $noptimizeCSS = apply_filters( 'breeze_filter_css_noptimize', false, $this->content );
51
+ if ( $noptimizeCSS ) {
52
+ return false;
53
+ }
54
+ $whitelistCSS = apply_filters( 'breeze_filter_css_whitelist', '' );
55
+ if ( ! empty( $whitelistCSS ) ) {
56
+ $this->whitelist = array_filter( array_map( 'trim', explode( ',', $whitelistCSS ) ) );
57
+ }
58
+ if ( $options['nogooglefont'] == true ) {
59
+ $removableCSS = 'fonts.googleapis.com';
60
+ } else {
61
+ $removableCSS = '';
62
+ }
63
+ $removableCSS = apply_filters( 'breeze_filter_css_removables', $removableCSS );
64
+ if ( ! empty( $removableCSS ) ) {
65
+ $this->cssremovables = array_filter( array_map( 'trim', explode( ',', $removableCSS ) ) );
66
+ }
67
+ $this->cssinlinesize = apply_filters( 'breeze_filter_css_inlinesize', 256 );
68
+ // filter to "late inject minified CSS", default to true for now (it is faster)
69
+ $this->inject_min_late = apply_filters( 'breeze_filter_css_inject_min_late', true );
70
+ // Remove everything that's not the header
71
+ if ( apply_filters( 'breeze_filter_css_justhead', $options['justhead'] ) == true ) {
72
+ $content = explode( '</head>', $this->content, 2 );
73
+ $this->content = $content[0] . '</head>';
74
+ $this->restofcontent = $content[1];
75
+ }
76
+ // include inline?
77
+ if ( apply_filters( 'breeze_css_include_inline', $options['include_inline'] ) == true ) {
78
+ $this->include_inline = true;
79
+ }
80
+ // group css?
81
+ if ( apply_filters( 'breeze_css_include_inline', $options['groupcss'] ) == true ) {
82
+ $this->group_css = true;
83
+ }
84
+ //custom js exclude
85
+ if ( ! empty( $options['custom_css_exclude'] ) ) {
86
+ $this->custom_css_exclude = array_merge( $this->custom_css_exclude, $options['custom_css_exclude'] );
87
+ }
88
+ // what CSS shouldn't be autoptimized
89
+ $excludeCSS = $options['css_exclude'];
90
+ $excludeCSS = apply_filters( 'breeze_filter_css_exclude', $excludeCSS );
91
+ if ( $excludeCSS !== '' ) {
92
+ $this->dontmove = array_filter( array_map( 'trim', explode( ',', $excludeCSS ) ) );
93
+ } else {
94
+ $this->dontmove = '';
95
+ }
96
+ // should we defer css?
97
+ // value: true/ false
98
+ $this->defer = $options['defer'];
99
+ $this->defer = apply_filters( 'breeze_filter_css_defer', $this->defer );
100
+ // should we inline while deferring?
101
+ // value: inlined CSS
102
+ $this->defer_inline = $options['defer_inline'];
103
+ // should we inline?
104
+ // value: true/ false
105
+ $this->inline = $options['inline'];
106
+ $this->inline = apply_filters( 'breeze_filter_css_inline', $this->inline );
107
+ // get cdn url
108
+ $this->cdn_url = $options['cdn_url'];
109
+ // Store data: URIs setting for later use
110
+ $this->datauris = $options['datauris'];
111
+ // noptimize me
112
+ $this->content = $this->hide_noptimize( $this->content );
113
+ // exclude (no)script, as those may contain CSS which should be left as is
114
+ if ( strpos( $this->content, '<script' ) !== false ) {
115
+ $this->content = preg_replace_callback(
116
+ '#<(?:no)?script.*?<\/(?:no)?script>#is',
117
+ function ( $matches ) {
118
+ return '%%SCRIPT' . breeze_HASH . '%%' . base64_encode( $matches[0] ) . '%%SCRIPT%%';
119
+ },
120
+ $this->content
121
+ );
122
+ }
123
+ // Save IE hacks
124
+ $this->content = $this->hide_iehacks( $this->content );
125
+ // hide comments
126
+ $this->content = $this->hide_comments( $this->content );
127
+ // Get <style> and <link>
128
+ if ( preg_match_all( '#(<style[^>]*>.*</style>)|(<link[^>]*stylesheet[^>]*>)#Usmi', $this->content, $matches ) ) {
129
+ foreach ( $matches[0] as $tag ) {
130
+ if ( $this->isremovable( $tag, $this->cssremovables ) ) {
131
+ $this->content = str_replace( $tag, '', $this->content );
132
+ } elseif ( $this->ismovable( $tag ) ) {
133
+ // Get the media
134
+ if ( strpos( $tag, 'media=' ) !== false ) {
135
+ preg_match( '#media=(?:"|\')([^>]*)(?:"|\')#Ui', $tag, $medias );
136
+ $medias = explode( ',', $medias[1] );
137
+ $media = array();
138
+ foreach ( $medias as $elem ) {
139
+ if ( empty( $elem ) ) {
140
+ $elem = 'all';
141
+ }
142
+ $media[] = $elem;
143
+ }
144
+ } else {
145
+ // No media specified - applies to all
146
+ $media = array( 'all' );
147
+ }
148
+ $media = apply_filters( 'breeze_filter_css_tagmedia', $media, $tag );
149
+ if ( preg_match( '#<link.*href=("|\')(.*)("|\')#Usmi', $tag, $source ) ) {
150
+ // <link>
151
+ $url = current( explode( '?', $source[2], 2 ) );
152
+ // Let's check if this file is in the excluded list.
153
+ $is_excluded = breeze_is_string_in_array_values( $url, $this->custom_css_exclude );
154
+ //exclude css file
155
+ if ( ! empty( $is_excluded ) ) {
156
+ continue;
157
+ }
158
+
159
+ // Treat special exceptions that might break front-end for admin/editor/author/contributor.
160
+ $is_an_exception = $this->breeze_css_files_exceptions( $url );
161
+ if ( true === $is_an_exception ) {
162
+ continue;
163
+ }
164
+
165
+ $path = $this->getpath( $url );
166
+ if ( $path !== false && preg_match( '#\.css$#', $path ) ) {
167
+ // Good link
168
+ $this->css[] = array( $media, $path );
169
+ } else {
170
+ // Link is dynamic (.php etc)
171
+ $tag = '';
172
+ }
173
+ } else {
174
+ // inline css in style tags can be wrapped in comment tags, so restore comments
175
+ $tag = $this->restore_comments( $tag );
176
+ preg_match( '#<style.*>(.*)</style>#Usmi', $tag, $code );
177
+ // and re-hide them to be able to to the removal based on tag
178
+ $tag = $this->hide_comments( $tag );
179
+ if ( $this->include_inline ) {
180
+ $code = preg_replace( '#^.*<!\[CDATA\[(?:\s*\*/)?(.*)(?://|/\*)\s*?\]\]>.*$#sm', '$1', $code[1] );
181
+ if ( true == $this->group_css ) {
182
+ if ( isset( $media[0] ) && 'print' === trim( $media[0] ) ) {
183
+ if ( false === strpos( $code, '@media' ) ) {
184
+ $code = '@media print{' . $code . '}';
185
+ }
186
+ } elseif ( isset( $media[0] ) && 'speech' === trim( $media[0] ) ) {
187
+ if ( false === strpos( $code, '@media' ) ) {
188
+ $code = '@media speech{' . $code . '}';
189
+ }
190
+ } elseif ( isset( $media[0] ) && 'screen' === trim( $media[0] ) ) {
191
+ if ( false === strpos( $code, '@media' ) ) {
192
+ $code = '@media screen{' . $code . '}';
193
+ }
194
+ }
195
+ }
196
+ $this->css[] = array( $media, 'INLINE;' . $code );
197
+ } else {
198
+ $tag = '';
199
+ }
200
+ }
201
+ // Remove the original style tag
202
+ $this->content = str_replace( $tag, '', $this->content );
203
+ }
204
+ }
205
+
206
+ return true;
207
+ }
208
+
209
+ // Really, no styles?
210
+ return false;
211
+ }
212
+
213
+ // Joins and optimizes CSS
214
+ public function minify() {
215
+
216
+ if ( false === $this->do_process ) {
217
+ return true;
218
+ }
219
+
220
+ foreach ( $this->css as $group ) {
221
+ list( $media, $css ) = $group;
222
+ if ( preg_match( '#^INLINE;#', $css ) ) {
223
+ // <style>
224
+ $css = preg_replace( '#^INLINE;#', '', $css );
225
+ $css = $this->fixurls( ABSPATH . '/index.php', $css );
226
+ $tmpstyle = apply_filters( 'breeze_css_individual_style', $css, '' );
227
+ if ( has_filter( 'breeze_css_individual_style' ) && ! empty( $tmpstyle ) ) {
228
+ $css = $tmpstyle;
229
+ $this->alreadyminified = true;
230
+ }
231
+ } else {
232
+ //<link>
233
+ if ( $css !== false && file_exists( $css ) && is_readable( $css ) ) {
234
+ $cssPath = $css;
235
+ $css = $this->fixurls( $cssPath, file_get_contents( $cssPath ) );
236
+ $css = preg_replace( '/\x{EF}\x{BB}\x{BF}/', '', $css );
237
+ $tmpstyle = apply_filters( 'breeze_css_individual_style', $css, $cssPath );
238
+ if ( has_filter( 'breeze_css_individual_style' ) && ! empty( $tmpstyle ) ) {
239
+ $css = $tmpstyle;
240
+ $this->alreadyminified = true;
241
+ } elseif ( $this->can_inject_late( $cssPath, $css ) ) {
242
+ $css = '%%INJECTLATER' . breeze_HASH . '%%' . base64_encode( $cssPath ) . '|' . md5( $css ) . '%%INJECTLATER%%';
243
+ }
244
+ } else {
245
+ // Couldn't read CSS. Maybe getpath isn't working?
246
+ $css = '';
247
+ }
248
+ }
249
+ if ( $this->group_css == true ) {
250
+ foreach ( $media as $elem ) {
251
+ if ( ! isset( $this->csscode[ $elem ] ) ) {
252
+ $this->csscode[ $elem ] = '';
253
+ }
254
+ $this->csscode[ $elem ] .= "\n/*FILESTART*/" . $css;
255
+ }
256
+ } else {
257
+ foreach ( $media as $elem ) {
258
+ $this->css_group_val[] = $elem . '_breezecssgroup_' . $css;
259
+ }
260
+ }
261
+ }
262
+ if ( $this->group_css == true ) {
263
+ // Check for duplicate code
264
+ $md5list = array();
265
+ $tmpcss = $this->csscode;
266
+ foreach ( $tmpcss as $media => $code ) {
267
+ $md5sum = md5( $code );
268
+ $medianame = $media;
269
+ foreach ( $md5list as $med => $sum ) {
270
+ // If same code
271
+ if ( $sum === $md5sum ) {
272
+ //Add the merged code
273
+ $medianame = $med . ', ' . $media;
274
+ $this->csscode[ $medianame ] = $code;
275
+ $md5list[ $medianame ] = $md5list[ $med ];
276
+ unset( $this->csscode[ $med ], $this->csscode[ $media ] );
277
+ unset( $md5list[ $med ] );
278
+ }
279
+ }
280
+ $md5list[ $medianame ] = $md5sum;
281
+ }
282
+ unset( $tmpcss );
283
+ // Manage @imports, while is for recursive import management
284
+ foreach ( $this->csscode as &$thiscss ) {
285
+ // Flag to trigger import reconstitution and var to hold external imports
286
+ $fiximports = false;
287
+ $external_imports = '';
288
+ while ( preg_match_all( '#^(/*\s?)@import.*(?:;|$)#Um', $thiscss, $matches ) ) {
289
+ foreach ( $matches[0] as $import ) {
290
+
291
+ if ( $this->isremovable( $import, $this->cssremovables ) ) {
292
+
293
+ $thiscss = str_replace( $import, '', $thiscss );
294
+ $import_ok = true;
295
+ } else {
296
+ $url = trim( preg_replace( '#^.*((?:https?:|ftp:)?//.*\.css).*$#', '$1', trim( $import ) ), " \t\n\r\0\x0B\"'" );
297
+ $path = $this->getpath( $url );
298
+ $import_ok = false;
299
+
300
+ if ( true === $this->include_imported_css && file_exists( $path ) && is_readable( $path ) ) { // add settings for this
301
+
302
+ $code = addcslashes( $this->fixurls( $path, file_get_contents( $path ) ), '\\' );
303
+ $code = preg_replace( '/\x{EF}\x{BB}\x{BF}/', '', $code );
304
+ $tmpstyle = apply_filters( 'breeze_css_individual_style', $code, '' );
305
+ if ( has_filter( 'breeze_css_individual_style' ) && ! empty( $tmpstyle ) ) {
306
+ $code = $tmpstyle;
307
+ $this->alreadyminified = true;
308
+ } elseif ( $this->can_inject_late( $path, $code ) ) {
309
+ $code = '%%INJECTLATER' . breeze_HASH . '%%' . base64_encode( $path ) . '|' . md5( $code ) . '%%INJECTLATER%%';
310
+ }
311
+ if ( ! empty( $code ) ) {
312
+ $tmp_thiscss = preg_replace( '#(/\*FILESTART\*/.*)' . preg_quote( $import, '#' ) . '#Us', '/*FILESTART2*/' . $code . '$1', $thiscss );
313
+ if ( ! empty( $tmp_thiscss ) ) {
314
+ $thiscss = $tmp_thiscss;
315
+ $import_ok = true;
316
+ unset( $tmp_thiscss );
317
+ }
318
+ unset( $code );
319
+ }
320
+ }
321
+ }
322
+ if ( ! $import_ok ) {
323
+ // external imports and general fall-back
324
+ $external_imports .= $import;
325
+ $thiscss = str_replace( $import, '', $thiscss );
326
+ $fiximports = true;
327
+ }
328
+ }
329
+ $thiscss = preg_replace( '#/\*FILESTART\*/#', '', $thiscss );
330
+ $thiscss = preg_replace( '#/\*FILESTART2\*/#', '/*FILESTART*/', $thiscss );
331
+ }
332
+ // add external imports to top of aggregated CSS
333
+ if ( $fiximports ) {
334
+ $thiscss = $external_imports . $thiscss;
335
+ }
336
+ }
337
+ unset( $thiscss );
338
+ // $this->csscode has all the uncompressed code now.
339
+ $mhtmlcount = 0;
340
+ foreach ( $this->csscode as &$code ) {
341
+ // Check for already-minified code
342
+ $hash = md5( $code );
343
+ $ccheck = new Breeze_MinificationCache( $hash, 'css' );
344
+ if ( $ccheck->check() ) {
345
+ $code = $ccheck->retrieve();
346
+ $this->hashmap[ md5( $code ) ] = $hash;
347
+ continue;
348
+ }
349
+ unset( $ccheck );
350
+ // Do the imaging!
351
+ $imgreplace = array();
352
+ preg_match_all( '#(background[^;}]*url\((?!\s?"?\s?data)(.*)\)[^;}]*)(?:;|$|})#Usm', $code, $matches );
353
+ if ( ( $this->datauris == true ) && ( function_exists( 'base64_encode' ) ) && ( is_array( $matches ) ) ) {
354
+ foreach ( $matches[2] as $count => $quotedurl ) {
355
+ $iurl = trim( $quotedurl, " \t\n\r\0\x0B\"'" );
356
+ // if querystring, remove it from url
357
+ if ( strpos( $iurl, '?' ) !== false ) {
358
+ $iurl = strtok( $iurl, '?' );
359
+ }
360
+ $ipath = $this->getpath( $iurl );
361
+ $datauri_max_size = 4096;
362
+ $datauri_max_size = (int) apply_filters( 'breeze_filter_css_datauri_maxsize', $datauri_max_size );
363
+ $datauri_exclude = apply_filters( 'breeze_filter_css_datauri_exclude', '' );
364
+ if ( ! empty( $datauri_exclude ) ) {
365
+ $no_datauris = array_filter( array_map( 'trim', explode( ',', $datauri_exclude ) ) );
366
+ foreach ( $no_datauris as $no_datauri ) {
367
+ if ( strpos( $iurl, $no_datauri ) !== false ) {
368
+ $ipath = false;
369
+ break;
370
+ }
371
+ }
372
+ }
373
+ if ( $ipath != false && preg_match( '#\.(jpe?g|png|gif|bmp)$#i', $ipath ) && file_exists( $ipath ) && is_readable( $ipath ) && filesize( $ipath ) <= $datauri_max_size ) {
374
+ $ihash = md5( $ipath );
375
+ $icheck = new Breeze_MinificationCache( $ihash, 'img' );
376
+ if ( $icheck->check() ) {
377
+ // we have the base64 image in cache
378
+ $headAndData = $icheck->retrieve();
379
+ $_base64data = explode( ';base64,', $headAndData );
380
+ $base64data = $_base64data[1];
381
+ } else {
382
+ // It's an image and we don't have it in cache, get the type
383
+ $explA = explode( '.', $ipath );
384
+ $type = end( $explA );
385
+ switch ( $type ) {
386
+ case 'jpeg':
387
+ $dataurihead = 'data:image/jpeg;base64,';
388
+ break;
389
+ case 'jpg':
390
+ $dataurihead = 'data:image/jpeg;base64,';
391
+ break;
392
+ case 'gif':
393
+ $dataurihead = 'data:image/gif;base64,';
394
+ break;
395
+ case 'png':
396
+ $dataurihead = 'data:image/png;base64,';
397
+ break;
398
+ case 'bmp':
399
+ $dataurihead = 'data:image/bmp;base64,';
400
+ break;
401
+ default:
402
+ $dataurihead = 'data:application/octet-stream;base64,';
403
+ }
404
+ // Encode the data
405
+ $base64data = base64_encode( file_get_contents( $ipath ) );
406
+ $headAndData = $dataurihead . $base64data;
407
+ // Save in cache
408
+ $icheck->cache( $headAndData, 'text/plain' );
409
+ }
410
+ unset( $icheck );
411
+ // Add it to the list for replacement
412
+ $imgreplace[ $matches[1][ $count ] ] = str_replace( $quotedurl, $headAndData, $matches[1][ $count ] ) . ";\n*" . str_replace( $quotedurl, 'mhtml:%%MHTML%%!' . $mhtmlcount, $matches[1][ $count ] ) . ";\n_" . $matches[1][ $count ] . ';';
413
+ // Store image on the mhtml document
414
+ $this->mhtml .= "--_\r\nContent-Location:{$mhtmlcount}\r\nContent-Transfer-Encoding:base64\r\n\r\n{$base64data}\r\n";
415
+ $mhtmlcount ++;
416
+ } else {
417
+ // just cdn the URL if applicable
418
+ if ( ! empty( $this->cdn_url ) ) {
419
+ $url = trim( $quotedurl, " \t\n\r\0\x0B\"'" );
420
+ $cdn_url = $this->url_replace_cdn( $url );
421
+ $imgreplace[ $matches[1][ $count ] ] = str_replace( $quotedurl, $cdn_url, $matches[1][ $count ] );
422
+ }
423
+ }
424
+ }
425
+ } elseif ( ( is_array( $matches ) ) && ( ! empty( $this->cdn_url ) ) ) {
426
+ // change background image urls to cdn-url
427
+ foreach ( $matches[2] as $count => $quotedurl ) {
428
+ $url = trim( $quotedurl, " \t\n\r\0\x0B\"'" );
429
+ $cdn_url = $this->url_replace_cdn( $url );
430
+ $imgreplace[ $matches[1][ $count ] ] = str_replace( $quotedurl, $cdn_url, $matches[1][ $count ] );
431
+ }
432
+ }
433
+ if ( ! empty( $imgreplace ) ) {
434
+ $code = str_replace( array_keys( $imgreplace ), array_values( $imgreplace ), $code );
435
+ }
436
+ // CDN the fonts!
437
+ if ( ( ! empty( $this->cdn_url ) ) && ( apply_filters( 'breeze_filter_css_fonts_cdn', false ) ) && ( version_compare( PHP_VERSION, '5.3.0' ) >= 0 ) ) {
438
+ $fontreplace = array();
439
+ include_once( BREEZE_PLUGIN_DIR . 'inc/minification/config/minificationFontRegex.php' );
440
+ preg_match_all( $fonturl_regex, $code, $matches );
441
+ if ( is_array( $matches ) ) {
442
+ foreach ( $matches[8] as $count => $quotedurl ) {
443
+ $url = trim( $quotedurl, " \t\n\r\0\x0B\"'" );
444
+ $cdn_url = $this->url_replace_cdn( $url );
445
+ $fontreplace[ $matches[8][ $count ] ] = str_replace( $quotedurl, $cdn_url, $matches[8][ $count ] );
446
+ }
447
+ if ( ! empty( $fontreplace ) ) {
448
+ $code = str_replace( array_keys( $fontreplace ), array_values( $fontreplace ), $code );
449
+ }
450
+ }
451
+ }
452
+ // Minify
453
+ if ( ( $this->alreadyminified !== true ) && ( apply_filters( 'breeze_css_do_minify', true ) ) ) {
454
+ if ( class_exists( 'Minify_CSS_Compressor' ) ) {
455
+ $tmp_code = trim( Minify_CSS_Compressor::process( $code ) );
456
+ } elseif ( class_exists( 'CSSmin' ) ) {
457
+ $cssmin = new CSSmin();
458
+ if ( method_exists( $cssmin, 'run' ) ) {
459
+ $tmp_code = trim( $cssmin->run( $code ) );
460
+ } elseif ( @is_callable( array( $cssmin, 'minify' ) ) ) {
461
+ $tmp_code = trim( CssMin::minify( $code ) );
462
+ }
463
+ }
464
+ if ( ! empty( $tmp_code ) ) {
465
+ $code = $tmp_code;
466
+ unset( $tmp_code );
467
+ }
468
+ }
469
+ $code = $this->inject_minified( $code );
470
+ $tmp_code = apply_filters( 'breeze_css_after_minify', $code );
471
+ if ( ! empty( $tmp_code ) ) {
472
+ $code = $tmp_code;
473
+ unset( $tmp_code );
474
+ }
475
+ $this->hashmap[ md5( $code ) ] = $hash;
476
+ }
477
+ unset( $code );
478
+ } else {
479
+ foreach ( $this->css_group_val as $value ) {
480
+ $media = substr( $value, 0, strpos( $value, '_breezecssgroup_' ) );
481
+ $css = substr( $value, strpos( $value, '_breezecssgroup_' ) + strlen( '_breezecssgroup_' ) );
482
+ $hash = md5( $css );
483
+ $ccheck = new Breeze_MinificationCache( $hash, 'css' );
484
+ if ( $ccheck->check() ) {
485
+ $css_exist = $ccheck->retrieve();
486
+ $this->css_min_arr[] = $media . '_breezemedia_' . $hash . '_breezekey_' . $css_exist;
487
+ continue;
488
+ }
489
+ unset( $ccheck );
490
+ // Minify
491
+ if ( class_exists( 'Minify_CSS_Compressor' ) ) {
492
+ $tmp_code = trim( Minify_CSS_Compressor::process( $css ) );
493
+ } elseif ( class_exists( 'CSSmin' ) ) {
494
+ $cssmin = new CSSmin();
495
+ if ( method_exists( $cssmin, 'run' ) ) {
496
+ $tmp_code = trim( $cssmin->run( $css ) );
497
+ } elseif ( @is_callable( array( $cssmin, 'minify' ) ) ) {
498
+ $tmp_code = trim( CssMin::minify( $css ) );
499
+ }
500
+ }
501
+ if ( ! empty( $tmp_code ) ) {
502
+ $css = $tmp_code;
503
+ unset( $tmp_code );
504
+ }
505
+ $css = $this->inject_minified( $css );
506
+ $css = apply_filters( 'breeze_css_after_minify', $css );
507
+ $this->css_min_arr[] = $media . '_breezemedia_' . $hash . '_breezekey_' . $css;
508
+ }
509
+ unset( $css );
510
+ }
511
+
512
+ return true;
513
+ }
514
+
515
+ //Caches the CSS in uncompressed, deflated and gzipped form.
516
+ public function cache() {
517
+ if ( false === $this->do_process ) {
518
+ return true;
519
+ }
520
+
521
+ if ( $this->datauris ) {
522
+ // MHTML Preparation
523
+ $this->mhtml = "/*\r\nContent-Type: multipart/related; boundary=\"_\"\r\n\r\n" . $this->mhtml . "*/\r\n";
524
+ $md5 = md5( $this->mhtml );
525
+ $cache = new Breeze_MinificationCache( $md5, 'txt' );
526
+ if ( ! $cache->check() ) {
527
+ // Cache our images for IE
528
+ $cache->cache( $this->mhtml, 'text/plain' );
529
+ }
530
+ $mhtml = breeze_CACHE_URL . breeze_current_user_type() . $cache->getname();
531
+
532
+ }
533
+ if ( $this->group_css == true ) {
534
+ $whole_css_file = '';
535
+ // CSS cache
536
+ foreach ( $this->csscode as $media => $code ) {
537
+
538
+ if ( $this->datauris ) {
539
+ // Images for ie! Get the right url
540
+ $code = str_replace( '%%MHTML%%', $mhtml, $code );
541
+ }
542
+ // compile all the CSS together to create a single file.
543
+ $whole_css_file .= $code;
544
+ }
545
+
546
+ $md5 = md5( $whole_css_file );
547
+ $cache = new Breeze_MinificationCache( $md5, 'css' );
548
+ if ( ! $cache->check() ) {
549
+ // Cache our code
550
+ $cache->cache( $whole_css_file, 'text/css' );
551
+ }
552
+
553
+ $cache_file_url = breeze_CACHE_URL . breeze_current_user_type() . $cache->getname();
554
+ $cache_directory = $cache->get_cache_dir();
555
+
556
+ if ( $this->is_cache_file_present( $cache_directory . $cache->get_file_name() ) ) {
557
+ $this->url['all'] = $cache_file_url;
558
+ } else {
559
+ $this->show_original_content = 1;
560
+ $this->clear_cache_data();
561
+ }
562
+
563
+ } else {
564
+ $url_exists = true;
565
+ foreach ( $this->css_min_arr as $value ) {
566
+ $media = substr( $value, 0, strpos( $value, '_breezemedia_' ) );
567
+ $code = substr( $value, strpos( $value, '_breezemedia_' ) + strlen( '_breezemedia_' ) );
568
+ $hash = substr( $code, 0, strpos( $code, '_breezekey_' ) );
569
+ $css = substr( $code, strpos( $code, '_breezekey_' ) + strlen( '_breezekey_' ) );
570
+ $cache = new Breeze_MinificationCache( $hash, 'css' );
571
+ if ( ! $cache->check() ) {
572
+ // Cache our code
573
+ $cache->cache( $css, 'text/css' );
574
+ }
575
+
576
+ $cache_directory = $cache->get_cache_dir();
577
+
578
+ if ( ! file_exists( $cache_directory . $cache->get_file_name() ) ) {
579
+ $url_exists = false;
580
+ } else {
581
+ $this->url_group_arr[] = $media . "_breezemedia_" . $hash . "_breezekey_" . breeze_CACHE_URL . breeze_current_user_type() . $cache->getname();
582
+ }
583
+ }
584
+
585
+ if ( false === $url_exists ) {
586
+ $this->show_original_content = 1;
587
+ $this->clear_cache_data();
588
+ }
589
+ }
590
+ }
591
+
592
+ //Returns the content
593
+ public function getcontent() {
594
+
595
+ if ( ! empty( $this->show_original_content ) ) {
596
+ return $this->original_content;
597
+ }
598
+ // restore IE hacks
599
+ $this->content = $this->restore_iehacks( $this->content );
600
+ // restore comments
601
+ $this->content = $this->restore_comments( $this->content );
602
+ // restore (no)script
603
+ if ( strpos( $this->content, '%%SCRIPT%%' ) !== false ) {
604
+ $this->content = preg_replace_callback(
605
+ '#%%SCRIPT' . breeze_HASH . '%%(.*?)%%SCRIPT%%#is',
606
+
607
+ function ( $matches ) {
608
+ return base64_decode( $matches[1] );
609
+ },
610
+ $this->content
611
+ );
612
+ }
613
+ // restore noptimize
614
+ $this->content = $this->restore_noptimize( $this->content );
615
+ //Restore the full content
616
+ if ( ! empty( $this->restofcontent ) ) {
617
+ $this->content .= $this->restofcontent;
618
+ $this->restofcontent = '';
619
+ }
620
+ // Inject the new stylesheets
621
+ $replaceTag = array( '<title', 'before' );
622
+ $replaceTag = apply_filters( 'breeze_filter_css_replacetag', $replaceTag );
623
+ if ( $this->group_css == true ) {
624
+ if ( $this->inline == true ) {
625
+ foreach ( $this->csscode as $media => $code ) {
626
+ $this->inject_in_html( '<style type="text/css" media="' . $media . '">' . $code . '</style>', $replaceTag );
627
+ }
628
+ } else {
629
+ if ( $this->defer == true ) {
630
+ $deferredCssBlock = "<script data-cfasync='false'>function lCss(url,media) {var d=document;var l=d.createElement('link');l.rel='stylesheet';l.type='text/css';l.href=url;l.media=media;aoin=d.getElementsByTagName('noscript')[0];aoin.parentNode.insertBefore(l,aoin.nextSibling);}function deferredCSS() {";
631
+ $noScriptCssBlock = '<noscript>';
632
+ $defer_inline_code = $this->defer_inline;
633
+ $defer_inline_code = apply_filters( 'breeze_filter_css_defer_inline', $defer_inline_code );
634
+ if ( ! empty( $defer_inline_code ) ) {
635
+ $iCssHash = md5( $defer_inline_code );
636
+ $iCssCache = new Breeze_MinificationCache( $iCssHash, 'css' );
637
+ if ( $iCssCache->check() ) {
638
+ // we have the optimized inline CSS in cache
639
+ $defer_inline_code = $iCssCache->retrieve();
640
+ } else {
641
+ if ( class_exists( 'Minify_CSS_Compressor' ) ) {
642
+ $tmp_code = trim( Minify_CSS_Compressor::process( $this->defer_inline ) );
643
+ } elseif ( class_exists( 'CSSmin' ) ) {
644
+ $cssmin = new CSSmin();
645
+ $tmp_code = trim( $cssmin->run( $defer_inline_code ) );
646
+ }
647
+ if ( ! empty( $tmp_code ) ) {
648
+ $defer_inline_code = $tmp_code;
649
+ $iCssCache->cache( $defer_inline_code, 'text/css' );
650
+ unset( $tmp_code );
651
+ }
652
+ }
653
+ $code_out = '<style type="text/css" id="aoatfcss" media="all">' . $defer_inline_code . '</style>';
654
+ $this->inject_in_html( $code_out, $replaceTag );
655
+ }
656
+ }
657
+ foreach ( $this->url as $media => $url ) {
658
+ $url = $this->url_replace_cdn( $url );
659
+ //Add the stylesheet either deferred (import at bottom) or normal links in head
660
+ if ( $this->defer == true ) {
661
+ $deferredCssBlock .= "lCss('" . $url . "','" . $media . "');";
662
+ $noScriptCssBlock .= '<link type="text/css" media="' . $media . '" href="' . $url . '" rel="stylesheet" />';
663
+ } else {
664
+ if ( strlen( $this->csscode[ $media ] ) > $this->cssinlinesize ) {
665
+ $this->inject_in_html( '<link type="text/css" media="' . $media . '" href="' . $url . '" rel="stylesheet" />', $replaceTag );
666
+ } elseif ( strlen( $this->csscode[ $media ] ) > 0 ) {
667
+ $this->inject_in_html( '<style type="text/css" media="' . $media . '">' . $this->csscode[ $media ] . '</style>', $replaceTag );
668
+ }
669
+ }
670
+ }
671
+ if ( $this->defer == true ) {
672
+ $deferredCssBlock .= "}if(window.addEventListener){window.addEventListener('DOMContentLoaded',deferredCSS,false);}else{window.onload = deferredCSS;}</script>";
673
+ $noScriptCssBlock .= '</noscript>';
674
+ $this->inject_in_html( $noScriptCssBlock, $replaceTag );
675
+ $this->inject_in_html( $deferredCssBlock, array( '</body>', 'before' ) );
676
+ }
677
+ }
678
+ } else {
679
+ if ( $this->inline == true ) {
680
+ foreach ( $this->csscode as $media => $code ) {
681
+ $this->inject_in_html( '<style type="text/css" media="' . $media . '">' . $code . '</style>', $replaceTag );
682
+ }
683
+ } else {
684
+ if ( $this->defer == true ) {
685
+ $deferredCssBlock = "<script data-cfasync='false'>function lCss(url,media) {var d=document;var l=d.createElement('link');l.rel='stylesheet';l.type='text/css';l.href=url;l.media=media;aoin=d.getElementsByTagName('noscript')[0];aoin.parentNode.insertBefore(l,aoin.nextSibling);}function deferredCSS() {";
686
+ $noScriptCssBlock = '<noscript>';
687
+ $defer_inline_code = $this->defer_inline;
688
+ $defer_inline_code = apply_filters( 'breeze_filter_css_defer_inline', $defer_inline_code );
689
+ if ( ! empty( $defer_inline_code ) ) {
690
+ $iCssHash = md5( $defer_inline_code );
691
+ $iCssCache = new Breeze_MinificationCache( $iCssHash, 'css' );
692
+ if ( $iCssCache->check() ) {
693
+ // we have the optimized inline CSS in cache
694
+ $defer_inline_code = $iCssCache->retrieve();
695
+ } else {
696
+ if ( class_exists( 'Minify_CSS_Compressor' ) ) {
697
+ $tmp_code = trim( Minify_CSS_Compressor::process( $this->defer_inline ) );
698
+ } elseif ( class_exists( 'CSSmin' ) ) {
699
+ $cssmin = new CSSmin();
700
+ $tmp_code = trim( $cssmin->run( $defer_inline_code ) );
701
+ }
702
+ if ( ! empty( $tmp_code ) ) {
703
+ $defer_inline_code = $tmp_code;
704
+ $iCssCache->cache( $defer_inline_code, 'text/css' );
705
+ unset( $tmp_code );
706
+ }
707
+ }
708
+ $code_out = '<style type="text/css" id="aoatfcss" media="all">' . $defer_inline_code . '</style>';
709
+ $this->inject_in_html( $code_out, $replaceTag );
710
+ }
711
+ }
712
+ foreach ( $this->url_group_arr as $value ) {
713
+ $media = substr( $value, 0, strpos( $value, '_breezemedia_' ) );
714
+ $code = substr( $value, strpos( $value, '_breezemedia_' ) + strlen( '_breezemedia_' ) );
715
+ $hash = substr( $code, 0, strpos( $code, '_breezekey_' ) );
716
+ $url = substr( $code, strpos( $code, '_breezekey_' ) + strlen( '_breezekey_' ) );
717
+ $cache = new Breeze_MinificationCache( $hash, 'css' );
718
+ if ( $cache->check() ) {
719
+ $csscode = $cache->retrieve();
720
+ }
721
+ //Add the stylesheet either deferred (import at bottom) or normal links in head
722
+ if ( $this->defer == true ) {
723
+ $deferredCssBlock .= "lCss('" . $url . "','" . $media . "');";
724
+ $noScriptCssBlock .= '<link type="text/css" media="' . $media . '" href="' . $url . '" rel="stylesheet" />';
725
+ } else {
726
+ if ( strlen( $csscode ) > $this->cssinlinesize ) {
727
+ $url = $this->url_replace_cdn( $url );
728
+ $this->inject_in_html( '<link type="text/css" media="' . $media . '" href="' . $url . '" rel="stylesheet" />', $replaceTag );
729
+ } elseif ( strlen( $csscode ) > 0 ) {
730
+ $this->inject_in_html( '<style type="text/css" media="' . $media . '">' . $csscode . '</style>', $replaceTag );
731
+ }
732
+ }
733
+ }
734
+ if ( $this->defer == true ) {
735
+ $deferredCssBlock .= "}if(window.addEventListener){window.addEventListener('DOMContentLoaded',deferredCSS,false);}else{window.onload = deferredCSS;}</script>";
736
+ $noScriptCssBlock .= '</noscript>';
737
+ $this->inject_in_html( $noScriptCssBlock, $replaceTag );
738
+ $this->inject_in_html( $deferredCssBlock, array( '</body>', 'before' ) );
739
+ }
740
+ }
741
+ }
742
+
743
+ if ( true === $this->do_process ) {
744
+ $this_path_url = $this->get_cache_file_url( 'css' );
745
+ breeze_unlock_process( $this_path_url );
746
+
747
+ return $this->content;
748
+ } else {
749
+ return $this->original_content;
750
+ }
751
+ //Return the modified stylesheet
752
+ //return $this->content;
753
+ }
754
+
755
+ static function fixurls( $file, $code ) {
756
+ $file = str_replace( BREEZE_ROOT_DIR, '/', $file );
757
+ $dir = dirname( $file ); //Like /wp-content
758
+ // quick fix for import-troubles in e.g. arras theme
759
+ $code = preg_replace( '#@import ("|\')(.+?)\.css("|\')#', '@import url("${2}.css")', $code );
760
+ if ( preg_match_all( '#url\((?!data)(?!\#)(?!"\#)(.*)\)#Usi', $code, $matches ) ) {
761
+ $replace = array();
762
+ foreach ( $matches[1] as $k => $url ) {
763
+ // Remove quotes
764
+ $url = trim( $url, " \t\n\r\0\x0B\"'" );
765
+ $noQurl = trim( $url, "\"'" );
766
+ if ( $url !== $noQurl ) {
767
+ $removedQuotes = true;
768
+ } else {
769
+ $removedQuotes = false;
770
+ }
771
+ $url = $noQurl;
772
+ if ( substr( $url, 0, 1 ) == '/' || preg_match( '#^(https?://|ftp://|data:)#i', $url ) ) {
773
+ //URL is absolute
774
+ continue;
775
+ } else {
776
+ // relative URL
777
+ $newurl = preg_replace( '/https?:/', '', str_replace( ' ', '%20', breeze_WP_ROOT_URL . str_replace( '//', '/', $dir . '/' . $url ) ) );
778
+ $hash = md5( $url );
779
+ $code = str_replace( $matches[0][ $k ], $hash, $code );
780
+ if ( ! empty( $removedQuotes ) ) {
781
+ $replace[ $hash ] = 'url(\'' . $newurl . '\')';
782
+ } else {
783
+ $replace[ $hash ] = 'url(' . $newurl . ')';
784
+ }
785
+ }
786
+ }
787
+ //Do the replacing here to avoid breaking URLs
788
+ $code = str_replace( array_keys( $replace ), array_values( $replace ), $code );
789
+ }
790
+
791
+ return $code;
792
+ }
793
+
794
+ private function ismovable( $tag ) {
795
+ if ( ! empty( $this->whitelist ) ) {
796
+ foreach ( $this->whitelist as $match ) {
797
+ if ( strpos( $tag, $match ) !== false ) {
798
+ return true;
799
+ }
800
+ }
801
+
802
+ // no match with whitelist
803
+ return false;
804
+ } else {
805
+ if ( is_array( $this->dontmove ) ) {
806
+ foreach ( $this->dontmove as $match ) {
807
+ if ( strpos( $tag, $match ) !== false ) {
808
+ //Matched something
809
+ return false;
810
+ }
811
+ }
812
+ }
813
+
814
+ //If we're here it's safe to move
815
+ return true;
816
+ }
817
+ }
818
+
819
+ private function can_inject_late( $cssPath, $css ) {
820
+ if ( ( strpos( $cssPath, 'min.css' ) === false ) || ( $this->inject_min_late !== true ) ) {
821
+ // late-inject turned off or file not minified based on filename
822
+ return false;
823
+ } elseif ( strpos( $css, '@import' ) !== false ) {
824
+ // can't late-inject files with imports as those need to be aggregated
825
+ return false;
826
+ } elseif ( ( strpos( $css, '@font-face' ) !== false ) && ( apply_filters( 'breeze_filter_css_fonts_cdn', false ) === true ) && ( ! empty( $this->cdn_url ) ) ) {
827
+ // don't late-inject CSS with font-src's if fonts are set to be CDN'ed
828
+ return false;
829
+ } elseif ( ( ( $this->datauris == true ) || ( ! empty( $this->cdn_url ) ) ) && preg_match( '#background[^;}]*url\(#Ui', $css ) ) {
830
+ // don't late-inject CSS with images if CDN is set OR is image inlining is on
831
+ return false;
832
+ } else {
833
+ // phew, all is safe, we can late-inject
834
+ return true;
835
+ }
836
+ }
837
+
838
+
839
+ /**
840
+ * Search for specific exceptions.
841
+ * Files that should not be included in grouping.
842
+ *
843
+ * @param $needle
844
+ *
845
+ * @return bool
846
+ * @since 1.1.3
847
+ */
848
+ private function breeze_css_files_exceptions( $needle ) {
849
+ $search_patterns = array(
850
+ 'huebert\.[a-zA-Z0-9]*\.css',
851
+ 'app\.[a-zA-Z0-9]*\.css',
852
+ );
853
+
854
+ $needle = trim( $needle );
855
+ foreach ( $search_patterns as $pattern ) {
856
+ preg_match( '/(' . $pattern . ')/i', $needle, $output_array );
857
+ if ( ! empty( $output_array ) ) { // is found ?
858
+
859
+ return true;
860
+ }
861
+ }
862
+
863
+ return false;
864
+ }
865
+ }
inc/minification/breeze-minify-main.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * @copyright 2017 Cloudways https://www.cloudways.com
4
  *
5
  * Original development of this plugin by JoomUnited https://www.joomunited.com/
6
  *
@@ -18,33 +18,33 @@
18
  * along with this program; if not, write to the Free Software
19
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
  */
21
- defined('ABSPATH') || die('No direct script access allowed!');
22
 
23
  class Breeze_Minify {
24
 
25
- public function __construct()
26
- {
27
- //check disable cache for page
28
- $domain = (((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS']!=='off') || (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT']==443)) ? 'https://':'http://' ).$_SERVER['HTTP_HOST'];
29
- $current_url = $domain.$_SERVER['REQUEST_URI'];
30
 
31
- $check_url = $this->check_exclude_url($current_url);
32
 
33
- //load config file when redirect template
34
- if ( ! $check_url && self::should_cache() ) {
35
- //cache html
36
- //cache minification
37
- if (Breeze_MinificationCache::create_cache_minification_folder()) {
38
- $conf = breeze_get_option( 'basic_settings' );
39
- if ( !empty($conf['breeze-minify-html']) || !empty($conf['breeze-minify-css']) || !empty($conf['breeze-minify-js']) ) {
40
- if (defined('breeze_INIT_EARLIER')) {
41
- add_action('init', array($this,'breeze_start_buffering'), -1);
42
- } else {
43
- add_action('template_redirect', array($this,'breeze_start_buffering'), 2);
44
- }
45
- }
46
- }
47
- }
 
48
 
49
  }
50
 
@@ -60,207 +60,235 @@ class Breeze_Minify {
60
  return true;
61
  }
62
 
63
- /*
64
- * Start buffer
65
- */
66
- public function breeze_start_buffering(){
67
- $ao_noptimize = false;
 
 
 
 
 
 
 
 
 
 
 
68
 
69
- // check for DONOTMINIFY constant as used by e.g. WooCommerce POS
70
- if (defined('DONOTMINIFY') && (constant('DONOTMINIFY') === true || constant('DONOTMINIFY') === "true")) {
71
- $ao_noptimize = true;
72
- }
73
- // filter you can use to block autoptimization on your own terms
74
- $ao_noptimize = (bool) apply_filters('breeze_filter_noptimize', $ao_noptimize);
75
- if (!is_feed() && !$ao_noptimize && !is_admin()) {
76
- // Config element
77
- $conf = breeze_get_option( 'basic_settings' );
78
- // Load our base class
79
- include_once(BREEZE_PLUGIN_DIR . 'inc/minification/breeze-minification-base.php');
80
 
81
- // Load extra classes and set some vars
82
- if (!empty($conf['breeze-minify-html'])) {
83
- include_once(BREEZE_PLUGIN_DIR . 'inc/minification/breeze-minification-html.php');
84
- // BUG: new minify-html does not support keeping HTML comments, skipping for now
85
- if(!class_exists('Minify_HTML')){
86
- @include(BREEZE_PLUGIN_DIR . 'inc/minification/minify/minify-html.php');
87
- }
88
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
- if (!empty($conf['breeze-minify-js'])) {
91
- include_once(BREEZE_PLUGIN_DIR . 'inc/minification/breeze-minification-scripts.php');
92
- if (!class_exists('JSMin')) {
93
- if (defined('breeze_LEGACY_MINIFIERS')) {
94
- @include(BREEZE_PLUGIN_DIR . 'inc/minification/minify/jsmin-1.1.1.php');
95
- } else {
96
- @include(BREEZE_PLUGIN_DIR . 'inc/minification/minify/minify-2.1.7-jsmin.php');
97
- }
98
- }
99
- if (!defined('CONCATENATE_SCRIPTS')) {
100
- define('CONCATENATE_SCRIPTS', false);
101
- }
102
- if (!defined('COMPRESS_SCRIPTS')) {
103
- define('COMPRESS_SCRIPTS', false);
104
- }
105
- }
106
- if (!empty($conf['breeze-minify-css'])) {
107
- include_once(BREEZE_PLUGIN_DIR . 'inc/minification/breeze-minification-styles.php');
108
- if (defined('breeze_LEGACY_MINIFIERS')) {
109
- if (!class_exists('Minify_CSS_Compressor')) {
110
- @include(BREEZE_PLUGIN_DIR . 'inc/minification/minify/minify-css-compressor.php');
111
- }
112
- } else {
113
- if (!class_exists('CSSmin')) {
114
- @include(BREEZE_PLUGIN_DIR . 'inc/minification/minify/yui-php-cssmin-2.4.8-4_fgo.php');
115
- }
116
- }
117
- if (!defined('COMPRESS_CSS')) {
118
- define('COMPRESS_CSS', false);
119
- }
120
- }
121
- // Now, start the real thing!
122
- add_filter('breeze_minify_content_return',array($this,'breeze_end_buffering'));
123
- }
124
- }
125
 
126
- /*
127
- * Minify css , js and optimize html when start
128
- */
129
 
130
- public function breeze_end_buffering($content) {
131
- if (stripos($content, "<html") === false || stripos($content, "<html amp") !== false || stripos($content, "<html ⚡") !== false || stripos($content, "<xsl:stylesheet") !== false) {
132
- return $content;
133
- }
134
- // load URL constants as late as possible to allow domain mapper to kick in
135
- if (function_exists("domain_mapping_siteurl")) {
136
- define('breeze_WP_SITE_URL', domain_mapping_siteurl(get_current_blog_id()));
137
- define('breeze_WP_CONTENT_URL', str_replace(get_original_url(breeze_WP_SITE_URL), breeze_WP_SITE_URL, content_url()));
138
- } else {
139
- define('breeze_WP_SITE_URL', site_url());
140
- define('breeze_WP_CONTENT_URL', content_url());
141
- }
142
- if (is_multisite() && apply_filters('breeze_separate_blog_caches', true)) {
143
- $blog_id = get_current_blog_id();
144
- define('breeze_CACHE_URL', breeze_WP_CONTENT_URL . BREEZE_CACHE_CHILD_DIR . $blog_id . '/');
145
- } else {
146
- define('breeze_CACHE_URL', breeze_WP_CONTENT_URL . BREEZE_CACHE_CHILD_DIR);
147
- }
148
- define('breeze_WP_ROOT_URL', str_replace(BREEZE_WP_CONTENT_NAME, '', breeze_WP_CONTENT_URL));
149
 
150
- define('breeze_HASH',wp_hash(breeze_CACHE_URL));
151
- // Config element
152
- $conf = breeze_get_option( 'basic_settings' );
153
- $minify = breeze_get_option( 'advanced_settings' );
154
 
155
- // Choose the classes
156
- $classes = array();
157
- $js_include_inline = $css_include_inline = false;
158
- if (!empty($conf['breeze-minify-js']))
159
- $classes[] = 'Breeze_MinificationScripts';
160
- if (!empty($conf['breeze-minify-css']))
161
- $classes[] = 'Breeze_MinificationStyles';
162
- if (!empty($conf['breeze-minify-html']))
163
- $classes[] = 'Breeze_MinificationHtml';
164
- if (!empty($conf['breeze-include-inline-js']))
165
- $js_include_inline = true;
166
- if (!empty($conf['breeze-include-inline-css']))
167
- $css_include_inline = true;
168
- $groupcss = false;
169
- $groupjs = false;
170
- if (!empty($minify['breeze-group-css'])){
171
- $groupcss = true;
172
- }
173
- if (!empty($minify['breeze-group-js'])){
174
- $groupjs = true;
175
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
 
177
- // Set some options
178
- $classoptions = array(
179
- 'Breeze_MinificationScripts' => array(
180
- 'justhead' => false,
181
- 'forcehead' => false,
182
- 'trycatch' => false,
183
- 'js_exclude' => "s_sid, smowtion_size, sc_project, WAU_, wau_add, comment-form-quicktags, edToolbar, ch_client, seal.js",
184
- 'cdn_url' => "",
185
- 'include_inline' => $js_include_inline,
186
- 'group_js' => $groupjs,
187
- 'custom_js_exclude' => $minify['breeze-exclude-js'],
188
- 'move_to_footer_js' => $minify['breeze-move-to-footer-js'],
189
- 'defer_js' => $minify['breeze-defer-js']
190
- ),
191
- 'Breeze_MinificationStyles' => array(
192
- 'justhead' => false,
193
- 'datauris' => false,
194
- 'defer' => false,
195
- 'defer_inline' => false,
196
- 'inline' => false,
197
- 'css_exclude' => "admin-bar.min.css, dashicons.min.css",
198
- 'cdn_url' => "",
199
- 'include_inline' => $css_include_inline,
200
- 'nogooglefont' => false,
201
- 'groupcss' => $groupcss,
202
- 'custom_css_exclude' => $minify['breeze-exclude-css']
203
- ),
204
- 'Breeze_MinificationHtml' => array(
205
- 'keepcomments' => false
206
- )
207
- );
208
 
209
- $content = apply_filters('breeze_filter_html_before_minify', $content);
210
 
211
- if (!empty($conf) && $conf['breeze-disable-admin'] && current_user_can('manage_options')) {
212
- $content = apply_filters('breeze_html_after_minify', $content);
213
- }else{
214
- // Run the classes
215
- foreach ($classes as $name) {
216
- $instance = new $name($content);
 
217
 
218
- if ($instance->read($classoptions[$name])) {
219
- $instance->minify();
220
- $instance->cache();
221
- $content = $instance->getcontent();
222
- }
223
- unset($instance);
224
- }
225
- $content = apply_filters('breeze_html_after_minify', $content);
226
- }
227
- return $content;
228
- }
229
- /*
230
- * check url from Never cache the following pages area
231
- */
232
- public function check_exclude_url($current_url){
233
- $opts_config = breeze_get_option( 'advanced_settings' );
234
- //check disable cache for page
235
- if (!empty($opts_config['breeze-exclude-urls'])) {
236
- foreach ($opts_config['breeze-exclude-urls'] as $v) {
237
- // Clear blank character
238
- $v = trim($v);
239
- if( preg_match( '/(\&?\/?\(\.?\*\)|\/\*|\*)$/', $v , $matches)){
240
- // End of rules is *, /*, [&][/](*) , [&][/](.*)
241
- $pattent = substr($v , 0, strpos($v,$matches[0]));
242
- if($v[0] == '/'){
243
- // A path of exclude url with regex
244
- if((@preg_match( '@'.$pattent.'@', $current_url, $matches ) > 0)){
245
- return true;
246
- }
247
- }else{
248
- // Full exclude url with regex
249
- if(strpos( $current_url,$pattent) !== false){
250
- return true;
251
- }
252
- }
253
 
254
- }else{
255
- // Whole path
256
- if($v == $current_url){
257
- return true;
258
- }
259
- }
260
- }
261
- }
262
 
263
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
264
 
265
- }
 
 
 
 
 
 
 
 
 
 
 
266
  }
1
  <?php
2
  /**
3
+ * @copyright 2017 Cloudways https://www.cloudways.com
4
  *
5
  * Original development of this plugin by JoomUnited https://www.joomunited.com/
6
  *
18
  * along with this program; if not, write to the Free Software
19
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
  */
21
+ defined( 'ABSPATH' ) || die( 'No direct script access allowed!' );
22
 
23
  class Breeze_Minify {
24
 
25
+ public function __construct() {
26
+ //check disable cache for page
27
+ $domain = ( ( ( ! empty( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] !== 'off' ) || ( ! empty( $_SERVER['SERVER_PORT'] ) && $_SERVER['SERVER_PORT'] == 443 ) ) ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'];
28
+ $current_url = $domain . $_SERVER['REQUEST_URI'];
 
29
 
30
+ $check_url = $this->check_exclude_url( $current_url );
31
 
32
+ //load config file when redirect template
33
+ if ( ! $check_url && self::should_cache() ) {
34
+ //cache html
35
+ //cache minification
36
+ if ( Breeze_MinificationCache::create_cache_minification_folder() ) {
37
+ $conf = breeze_get_option( 'basic_settings' );
38
+ if ( ! empty( $conf['breeze-minify-html'] ) || ! empty( $conf['breeze-minify-css'] ) || ! empty( $conf['breeze-minify-js'] ) ) {
39
+
40
+ if ( defined( 'breeze_INIT_EARLIER' ) ) {
41
+ add_action( 'init', array( $this, 'breeze_start_buffering' ), - 1 );
42
+ } else {
43
+ add_action( 'wp_loaded', array( $this, 'breeze_start_buffering' ), 2 );
44
+ }
45
+ }
46
+ }
47
+ }
48
 
49
  }
50
 
60
  return true;
61
  }
62
 
63
+ /*
64
+ * Start buffer
65
+ */
66
+ public function breeze_start_buffering() {
67
+ $ao_noptimize = false;
68
+ // check for DONOTMINIFY constant as used by e.g. WooCommerce POS
69
+ if ( defined( 'DONOTMINIFY' ) && ( constant( 'DONOTMINIFY' ) === true || constant( 'DONOTMINIFY' ) === "true" ) ) {
70
+ $ao_noptimize = true;
71
+ }
72
+ // filter you can use to block autoptimization on your own terms
73
+ $ao_noptimize = (bool) apply_filters( 'breeze_filter_noptimize', $ao_noptimize );
74
+ if ( ! is_feed() && ! $ao_noptimize && ! is_admin() ) {
75
+ // Config element
76
+ $conf = breeze_get_option( 'basic_settings' );
77
+ // Load our base class
78
+ include_once( BREEZE_PLUGIN_DIR . 'inc/minification/breeze-minification-base.php' );
79
 
80
+ // Load extra classes and set some vars
81
+ if ( ! empty( $conf['breeze-minify-html'] ) ) {
82
+ include_once( BREEZE_PLUGIN_DIR . 'inc/minification/breeze-minification-html.php' );
83
+ // BUG: new minify-html does not support keeping HTML comments, skipping for now
84
+ if ( ! class_exists( 'Minify_HTML' ) ) {
85
+ @include( BREEZE_PLUGIN_DIR . 'inc/minification/minify/minify-html.php' );
86
+ }
87
+ }
 
 
 
88
 
89
+ if ( ! empty( $conf['breeze-minify-js'] ) ) {
90
+ include_once( BREEZE_PLUGIN_DIR . 'inc/minification/breeze-minification-scripts.php' );
91
+ if ( ! class_exists( 'JSMin' ) ) {
92
+ if ( defined( 'breeze_LEGACY_MINIFIERS' ) ) {
93
+ @include( BREEZE_PLUGIN_DIR . 'inc/minification/minify/jsmin-1.1.1.php' );
94
+ } else {
95
+ @include( BREEZE_PLUGIN_DIR . 'inc/minification/minify/minify-2.1.7-jsmin.php' );
96
+ }
97
+ }
98
+ if ( ! defined( 'CONCATENATE_SCRIPTS' ) ) {
99
+ define( 'CONCATENATE_SCRIPTS', false );
100
+ }
101
+ if ( ! defined( 'COMPRESS_SCRIPTS' ) ) {
102
+ define( 'COMPRESS_SCRIPTS', false );
103
+ }
104
+ }
105
+ if ( ! empty( $conf['breeze-minify-css'] ) ) {
106
+ include_once( BREEZE_PLUGIN_DIR . 'inc/minification/breeze-minification-styles.php' );
107
+ if ( defined( 'breeze_LEGACY_MINIFIERS' ) ) {
108
+ if ( ! class_exists( 'Minify_CSS_Compressor' ) ) {
109
+ @include( BREEZE_PLUGIN_DIR . 'inc/minification/minify/minify-css-compressor.php' );
110
+ }
111
+ } else {
112
+ if ( ! class_exists( 'CSSmin' ) ) {
113
+ @include( BREEZE_PLUGIN_DIR . 'inc/minification/minify/yui-php-cssmin-2.4.8-4_fgo.php' );
114
+ }
115
+ }
116
+ if ( ! defined( 'COMPRESS_CSS' ) ) {
117
+ define( 'COMPRESS_CSS', false );
118
+ }
119
+ }
120
 
121
+ // Now, start the real thing!
122
+ add_filter( 'breeze_minify_content_return', array( $this, 'breeze_end_buffering' ) );
123
+ }
124
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
+ /*
127
+ * Minify css , js and optimize html when start
128
+ */
129
 
130
+ public function breeze_end_buffering( $content ) {
131
+ if ( stripos( $content, "<html" ) === false || stripos( $content, "<html amp" ) !== false || stripos( $content, "<html ⚡" ) !== false || stripos( $content, "<xsl:stylesheet" ) !== false ) {
132
+ return $content;
133
+ }
134
+ // load URL constants as late as possible to allow domain mapper to kick in
135
+ if ( function_exists( "domain_mapping_siteurl" ) ) {
136
+ define( 'breeze_WP_SITE_URL', domain_mapping_siteurl( get_current_blog_id() ) );
137
+ define( 'breeze_WP_CONTENT_URL', str_replace( get_original_url( breeze_WP_SITE_URL ), breeze_WP_SITE_URL, content_url() ) );
138
+ } else {
139
+ define( 'breeze_WP_SITE_URL', site_url() );
140
+ define( 'breeze_WP_CONTENT_URL', content_url() );
141
+ }
142
+ if ( is_multisite() && apply_filters( 'breeze_separate_blog_caches', true ) ) {
143
+ $blog_id = get_current_blog_id();
144
+ define( 'breeze_CACHE_URL', breeze_WP_CONTENT_URL . BREEZE_CACHE_CHILD_DIR . $blog_id . '/' );
145
+ } else {
146
+ define( 'breeze_CACHE_URL', breeze_WP_CONTENT_URL . BREEZE_CACHE_CHILD_DIR );
147
+ }
148
+ define( 'breeze_WP_ROOT_URL', str_replace( BREEZE_WP_CONTENT_NAME, '', breeze_WP_CONTENT_URL ) );
149
 
150
+ define( 'breeze_HASH', wp_hash( breeze_CACHE_URL ) );
151
+ // Config element
152
+ $conf = breeze_get_option( 'basic_settings' );
153
+ $minify = breeze_get_option( 'advanced_settings' );
154
 
155
+ // Choose the classes
156
+ $classes = array();
157
+ $js_include_inline = $css_include_inline = false;
158
+ if ( ! empty( $conf['breeze-minify-js'] ) ) {
159
+ $classes[] = 'Breeze_MinificationScripts';
160
+ }
161
+ if ( ! empty( $conf['breeze-minify-css'] ) ) {
162
+ $classes[] = 'Breeze_MinificationStyles';
163
+ }
164
+ if ( ! empty( $conf['breeze-minify-html'] ) ) {
165
+ $classes[] = 'Breeze_MinificationHtml';
166
+ }
167
+ if ( ! empty( $conf['breeze-include-inline-js'] ) ) {
168
+ $js_include_inline = true;
169
+ }
170
+ if ( ! empty( $conf['breeze-include-inline-css'] ) ) {
171
+ $css_include_inline = true;
172
+ }
173
+ $groupcss = false;
174
+ $groupjs = false;
175
+ if ( ! empty( $minify['breeze-group-css'] ) ) {
176
+ $groupcss = true;
177
+ }
178
+ if ( ! empty( $minify['breeze-group-js'] ) ) {
179
+ $groupjs = true;
180
+ }
181
+
182
+ // Set some options
183
+ $classoptions = array(
184
+ 'Breeze_MinificationScripts' => array(
185
+ 'justhead' => false,
186
+ 'forcehead' => false,
187
+ 'trycatch' => false,
188
+ 'js_exclude' => "s_sid, smowtion_size, sc_project, WAU_, wau_add, comment-form-quicktags, edToolbar, ch_client, seal.js",
189
+ 'cdn_url' => "",
190
+ 'include_inline' => $js_include_inline,
191
+ 'group_js' => $groupjs,
192
+ 'custom_js_exclude' => $minify['breeze-exclude-js'],
193
+ 'move_to_footer_js' => $minify['breeze-move-to-footer-js'],
194
+ 'defer_js' => $minify['breeze-defer-js']
195
+ ),
196
+ 'Breeze_MinificationStyles' => array(
197
+ 'justhead' => false,
198
+ 'datauris' => false,
199
+ 'defer' => false,
200
+ 'defer_inline' => false,
201
+ 'inline' => false,
202
+ 'css_exclude' => "admin-bar.min.css, dashicons.min.css",
203
+ 'cdn_url' => "",
204
+ 'include_inline' => $css_include_inline,
205
+ 'nogooglefont' => false,
206
+ 'groupcss' => $groupcss,
207
+ 'custom_css_exclude' => $minify['breeze-exclude-css'],
208
+ 'include_imported_css' => false,
209
+ ),
210
+ 'Breeze_MinificationHtml' => array(
211
+ 'keepcomments' => false
212
+ )
213
+ );
214
+
215
+ $content = apply_filters( 'breeze_filter_html_before_minify', $content );
216
+
217
+ if ( ! empty( $conf ) && $conf['breeze-disable-admin'] && ( current_user_can( 'administrator' ) || current_user_can( 'editor' ) || current_user_can( 'author' ) || current_user_can( 'contributor' ) ) ) {
218
+ $content = apply_filters( 'breeze_html_after_minify', $content );
219
+
220
+ } else {
221
+ // Run the classes
222
+ foreach ( $classes as $name ) {
223
+ $do_process = false;
224
+ $instance = new $name( $content );
225
+ if ( 'Breeze_MinificationStyles' === $name ) {
226
+ $this_path_url = $instance->get_cache_file_url( 'css' );
227
+ $do_process = breeze_is_process_locked( $this_path_url );
228
+ }
229
+
230
+ if ( 'Breeze_MinificationScripts' === $name ) {
231
+ $this_path_url = $instance->get_cache_file_url( 'js' );
232
+ $do_process = breeze_is_process_locked( $this_path_url );
233
+ }
234
 
235
+ if ( 'Breeze_MinificationHtml' === $name ) {
236
+ $this_path_url = $instance->get_cache_file_url( '' );
237
+ $do_process = breeze_is_process_locked( $this_path_url );
238
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
 
240
+ if ( false === $do_process ) {
241
 
242
+ if ( $instance->read( $classoptions[ $name ] ) ) {
243
+ $instance->minify();
244
+ $instance->cache();
245
+ $content = $instance->getcontent();
246
+ }
247
+ unset( $instance );
248
+ }
249
 
250
+ }
251
+ $content = apply_filters( 'breeze_html_after_minify', $content );
252
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
 
254
+ return $content;
255
+ }
 
 
 
 
 
 
256
 
257
+ /*
258
+ * check url from Never cache the following pages area
259
+ */
260
+ public function check_exclude_url( $current_url ) {
261
+ $opts_config = breeze_get_option( 'advanced_settings' );
262
+ //check disable cache for page
263
+ if ( ! empty( $opts_config['breeze-exclude-urls'] ) ) {
264
+ foreach ( $opts_config['breeze-exclude-urls'] as $v ) {
265
+ // Clear blank character
266
+ $v = trim( $v );
267
+ if ( preg_match( '/(\&?\/?\(\.?\*\)|\/\*|\*)$/', $v, $matches ) ) {
268
+ // End of rules is *, /*, [&][/](*) , [&][/](.*)
269
+ $pattent = substr( $v, 0, strpos( $v, $matches[0] ) );
270
+ if ( $v[0] == '/' ) {
271
+ // A path of exclude url with regex
272
+ if ( ( @preg_match( '@' . $pattent . '@', $current_url, $matches ) > 0 ) ) {
273
+ return true;
274
+ }
275
+ } else {
276
+ // Full exclude url with regex
277
+ if ( strpos( $current_url, $pattent ) !== false ) {
278
+ return true;
279
+ }
280
+ }
281
 
282
+ } else {
283
+ // Whole path
284
+ if ( $v == $current_url ) {
285
+ return true;
286
+ }
287
+ }
288
+ }
289
+ }
290
+
291
+ return false;
292
+
293
+ }
294
  }
inc/minification/minify/yui-php-cssmin-2.4.8-4_fgo.php CHANGED
@@ -1,789 +1,807 @@
1
- <?php
2
-
3
- /*!
4
- * cssmin.php v2.4.8-4
5
- * Author: Tubal Martin - http://tubalmartin.me/
6
- * Repo: https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port
7
- *
8
- * This is a PHP port of the CSS minification tool distributed with YUICompressor,
9
- * itself a port of the cssmin utility by Isaac Schlueter - http://foohack.com/
10
- * Permission is hereby granted to use the PHP version under the same
11
- * conditions as the YUICompressor.
12
- */
13
-
14
- /*!
15
- * YUI Compressor
16
- * http://developer.yahoo.com/yui/compressor/
17
- * Author: Julien Lecomte - http://www.julienlecomte.net/
18
- * Copyright (c) 2013 Yahoo! Inc. All rights reserved.
19
- * The copyrights embodied in the content of this file are licensed
20
- * by Yahoo! Inc. under the BSD (revised) open source license.
21
- */
22
-
23
- class CSSmin
24
- {
25
- const NL = '___YUICSSMIN_PRESERVED_NL___';
26
- const TOKEN = '___YUICSSMIN_PRESERVED_TOKEN_';
27
- const COMMENT = '___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_';
28
- const CLASSCOLON = '___YUICSSMIN_PSEUDOCLASSCOLON___';
29
- const QUERY_FRACTION = '___YUICSSMIN_QUERY_FRACTION___';
30
-
31
- private $comments;
32
- private $preserved_tokens;
33
- private $memory_limit;
34
- private $max_execution_time;
35
- private $pcre_backtrack_limit;
36
- private $pcre_recursion_limit;
37
- private $raise_php_limits;
38
-
39
- /**
40
- * @param bool|int $raise_php_limits
41
- * If true, PHP settings will be raised if needed
42
- */
43
- public function __construct($raise_php_limits = TRUE)
44
- {
45
- // Set suggested PHP limits
46
- $this->memory_limit = 128 * 1048576; // 128MB in bytes
47
- $this->max_execution_time = 60; // 1 min
48
- $this->pcre_backtrack_limit = 1000 * 1000;
49
- $this->pcre_recursion_limit = 500 * 1000;
50
-
51
- $this->raise_php_limits = (bool) $raise_php_limits;
52
- }
53
-
54
- /**
55
- * Minify a string of CSS
56
- * @param string $css
57
- * @param int|bool $linebreak_pos
58
- * @return string
59
- */
60
- public function run($css = '', $linebreak_pos = FALSE)
61
- {
62
- if (empty($css)) {
63
- return '';
64
- }
65
-
66
- if ($this->raise_php_limits) {
67
- $this->do_raise_php_limits();
68
- }
69
-
70
- $this->comments = array();
71
- $this->preserved_tokens = array();
72
-
73
- $start_index = 0;
74
- $length = strlen($css);
75
-
76
- $css = $this->extract_data_urls($css);
77
-
78
- // collect all comment blocks...
79
- while (($start_index = $this->index_of($css, '/*', $start_index)) >= 0) {
80
- $end_index = $this->index_of($css, '*/', $start_index + 2);
81
- if ($end_index < 0) {
82
- $end_index = $length;
83
- }
84
- $comment_found = $this->str_slice($css, $start_index + 2, $end_index);
85
- $this->comments[] = $comment_found;
86
- $comment_preserve_string = self::COMMENT . (count($this->comments) - 1) . '___';
87
- $css = $this->str_slice($css, 0, $start_index + 2) . $comment_preserve_string . $this->str_slice($css, $end_index);
88
- // Set correct start_index: Fixes issue #2528130
89
- $start_index = $end_index + 2 + strlen($comment_preserve_string) - strlen($comment_found);
90
- }
91
-
92
- // preserve strings so their content doesn't get accidentally minified
93
- $css = preg_replace_callback('/(?:"(?:[^\\\\"]|\\\\.|\\\\)*")|'."(?:'(?:[^\\\\']|\\\\.|\\\\)*')/S", array($this, 'replace_string'), $css);
94
-
95
- // Let's divide css code in chunks of 5.000 chars aprox.
96
- // Reason: PHP's PCRE functions like preg_replace have a "backtrack limit"
97
- // of 100.000 chars by default (php < 5.3.7) so if we're dealing with really
98
- // long strings and a (sub)pattern matches a number of chars greater than
99
- // the backtrack limit number (i.e. /(.*)/s) PCRE functions may fail silently
100
- // returning NULL and $css would be empty.
101
- $charset = '';
102
- $charset_regexp = '/(@charset)( [^;]+;)/i';
103
- $css_chunks = array();
104
- $css_chunk_length = 5000; // aprox size, not exact
105
- $start_index = 0;
106
- $i = $css_chunk_length; // save initial iterations
107
- $l = strlen($css);
108
-
109
-
110
- // if the number of characters is 5000 or less, do not chunk
111
- if ($l <= $css_chunk_length) {
112
- $css_chunks[] = $css;
113
- } else {
114
- // chunk css code securely
115
- while ($i < $l) {
116
- $i += 50; // save iterations
117
- if ($l - $start_index <= $css_chunk_length || $i >= $l) {
118
- $css_chunks[] = $this->str_slice($css, $start_index);
119
- break;
120
- }
121
- if ($css[$i - 1] === '}' && $i - $start_index > $css_chunk_length) {
122
- // If there are two ending curly braces }} separated or not by spaces,
123
- // join them in the same chunk (i.e. @media blocks)
124
- $next_chunk = substr($css, $i);
125
- if (preg_match('/^\s*\}/', $next_chunk)) {
126
- $i = $i + $this->index_of($next_chunk, '}') + 1;
127
- }
128
-
129
- $css_chunks[] = $this->str_slice($css, $start_index, $i);
130
- $start_index = $i;
131
- }
132
- }
133
- }
134
-
135
- // Minify each chunk
136
- for ($i = 0, $n = count($css_chunks); $i < $n; $i++) {
137
- $css_chunks[$i] = $this->minify($css_chunks[$i], $linebreak_pos);
138
- // Keep the first @charset at-rule found
139
- if (empty($charset) && preg_match($charset_regexp, $css_chunks[$i], $matches)) {
140
- $charset = strtolower($matches[1]) . $matches[2];
141
- }
142
- // Delete all @charset at-rules
143
- $css_chunks[$i] = preg_replace($charset_regexp, '', $css_chunks[$i]);
144
- }
145
-
146
- // Update the first chunk and push the charset to the top of the file.
147
- $css_chunks[0] = $charset . $css_chunks[0];
148
-
149
- return implode('', $css_chunks);
150
- }
151
-
152
- /**
153
- * Sets the memory limit for this script
154
- * @param int|string $limit
155
- */
156
- public function set_memory_limit($limit)
157
- {
158
- $this->memory_limit = $this->normalize_int($limit);
159
- }
160
-
161
- /**
162
- * Sets the maximum execution time for this script
163
- * @param int|string $seconds
164
- */
165
- public function set_max_execution_time($seconds)
166
- {
167
- $this->max_execution_time = (int) $seconds;
168
- }
169
-
170
- /**
171
- * Sets the PCRE backtrack limit for this script
172
- * @param int $limit
173
- */
174
- public function set_pcre_backtrack_limit($limit)
175
- {
176
- $this->pcre_backtrack_limit = (int) $limit;
177
- }
178
-
179
- /**
180
- * Sets the PCRE recursion limit for this script
181
- * @param int $limit
182
- */
183
- public function set_pcre_recursion_limit($limit)
184
- {
185
- $this->pcre_recursion_limit = (int) $limit;
186
- }
187
-
188
- /**
189
- * Try to configure PHP to use at least the suggested minimum settings
190
- */
191
- private function do_raise_php_limits()
192
- {
193
- $php_limits = array(
194
- 'memory_limit' => $this->memory_limit,
195
- 'max_execution_time' => $this->max_execution_time,
196
- 'pcre.backtrack_limit' => $this->pcre_backtrack_limit,
197
- 'pcre.recursion_limit' => $this->pcre_recursion_limit
198
- );
199
-
200
- // If current settings are higher respect them.
201
- foreach ($php_limits as $name => $suggested) {
202
- $current = $this->normalize_int(ini_get($name));
203
- // memory_limit exception: allow -1 for "no memory limit".
204
- if ($current > -1 && ($suggested == -1 || $current < $suggested)) {
205
- ini_set($name, $suggested);
206
- }
207
- }
208
- }
209
-
210
- /**
211
- * Does bulk of the minification
212
- * @param string $css
213
- * @param int|bool $linebreak_pos
214
- * @return string
215
- */
216
- private function minify($css, $linebreak_pos)
217
- {
218
- // strings are safe, now wrestle the comments
219
- for ($i = 0, $max = count($this->comments); $i < $max; $i++) {
220
-
221
- $token = $this->comments[$i];
222
- $placeholder = '/' . self::COMMENT . $i . '___/';
223
-
224
- // ! in the first position of the comment means preserve
225
- // so push to the preserved tokens keeping the !
226
- if (substr($token, 0, 1) === '!') {
227
- $this->preserved_tokens[] = $token;
228
- $token_tring = self::TOKEN . (count($this->preserved_tokens) - 1) . '___';
229
- $css = preg_replace($placeholder, $token_tring, $css, 1);
230
- // Preserve new lines for /*! important comments
231
- $css = preg_replace('/\s*[\n\r\f]+\s*(\/\*'. $token_tring .')/S', self::NL.'$1', $css);
232
- $css = preg_replace('/('. $token_tring .'\*\/)\s*[\n\r\f]+\s*/', '$1'.self::NL, $css);
233
- continue;
234
- }
235
-
236
- // \ in the last position looks like hack for Mac/IE5
237
- // shorten that to /*\*/ and the next one to /**/
238
- if (substr($token, (strlen($token) - 1), 1) === '\\') {
239
- $this->preserved_tokens[] = '\\';
240
- $css = preg_replace($placeholder, self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1);
241
- $i = $i + 1; // attn: advancing the loop
242
- $this->preserved_tokens[] = '';
243
- $css = preg_replace('/' . self::COMMENT . $i . '___/', self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1);
244
- continue;
245
- }
246
-
247
- // keep empty comments after child selectors (IE7 hack)
248
- // e.g. html >/**/ body
249
- if (strlen($token) === 0) {
250
- $start_index = $this->index_of($css, $this->str_slice($placeholder, 1, -1));
251
- if ($start_index > 2) {
252
- if (substr($css, $start_index - 3, 1) === '>') {
253
- $this->preserved_tokens[] = '';
254
- $css = preg_replace($placeholder, self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1);
255
- }
256
- }
257
- }
258
-
259
- // in all other cases kill the comment
260
- $css = preg_replace('/\/\*' . $this->str_slice($placeholder, 1, -1) . '\*\//', '', $css, 1);
261
- }
262
-
263
-
264
- // Normalize all whitespace strings to single spaces. Easier to work with that way.
265
- $css = preg_replace('/\s+/', ' ', $css);
266
-
267
- // preserve flex, keeping percentage even if 0
268
- $css = preg_replace_callback('/flex\s?:\s?((?:[0-9 ]*)\s?(?:px|em|auto|%)?(?:calc\(.*\))?)/i',array($this, 'replace_flex'),$css);
269
-
270
- // Fix IE7 issue on matrix filters which browser accept whitespaces between Matrix parameters
271
- $css = preg_replace_callback('/\s*filter\:\s*progid:DXImageTransform\.Microsoft\.Matrix\(([^\)]+)\)/', array($this, 'preserve_old_IE_specific_matrix_definition'), $css);
272
-
273
- // Shorten & preserve calculations calc(...) since spaces are important
274
- $css = preg_replace_callback('/calc(\(((?:[^\(\)]+|(?1))*)\))/i', array($this, 'replace_calc'), $css);
275
-
276
- // Replace positive sign from numbers preceded by : or a white-space before the leading space is removed
277
- // +1.2em to 1.2em, +.8px to .8px, +2% to 2%
278
- $css = preg_replace('/((?<!\\\\)\:|\s)\+(\.?\d+)/S', '$1$2', $css);
279
-
280
- // Remove leading zeros from integer and float numbers preceded by : or a white-space
281
- // 000.6 to .6, -0.8 to -.8, 0050 to 50, -01.05 to -1.05
282
- $css = preg_replace('/((?<!\\\\)\:|\s)(\-?)0+(\.?\d+)/S', '$1$2$3', $css);
283
-
284
- // Remove trailing zeros from float numbers preceded by : or a white-space
285
- // -6.0100em to -6.01em, .0100 to .01, 1.200px to 1.2px
286
- $css = preg_replace('/((?<!\\\\)\:|\s)(\-?)(\d?\.\d+?)0+([^\d])/S', '$1$2$3$4', $css);
287
-
288
- // Remove trailing .0 -> -9.0 to -9
289
- $css = preg_replace('/((?<!\\\\)\:|\s)(\-?\d+)\.0([^\d])/S', '$1$2$3', $css);
290
-
291
- // Replace 0 length numbers with 0
292
- $css = preg_replace('/((?<!\\\\)\:|\s)\-?\.?0+([^\d])/S', '${1}0$2', $css);
293
-
294
- // Remove the spaces before the things that should not have spaces before them.
295
- // But, be careful not to turn "p :link {...}" into "p:link{...}"
296
- // Swap out any pseudo-class colons with the token, and then swap back.
297
- $css = preg_replace_callback('/(?:^|\})[^\{]*\s+\:/', array($this, 'replace_colon'), $css);
298
-
299
- // Remove spaces before the things that should not have spaces before them.
300
- $css = preg_replace('/\s+([\!\{\}\;\:\>\+\(\)\]\~\=,])/', '$1', $css);
301
-
302
- // Restore spaces for !important
303
- $css = preg_replace('/\!important/i', ' !important', $css);
304
-
305
- // bring back the colon
306
- $css = preg_replace('/' . self::CLASSCOLON . '/', ':', $css);
307
-
308
- // retain space for special IE6 cases
309
- $css = preg_replace_callback('/\:first\-(line|letter)(\{|,)/i', array($this, 'lowercase_pseudo_first'), $css);
310
-
311
- // no space after the end of a preserved comment
312
- $css = preg_replace('/\*\/ /', '*/', $css);
313
-
314
- // lowercase some popular @directives
315
- $css = preg_replace_callback('/@(font-face|import|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?keyframe|media|page|namespace)/i', array($this, 'lowercase_directives'), $css);
316
-
317
- // lowercase some more common pseudo-elements
318
- $css = preg_replace_callback('/:(active|after|before|checked|disabled|empty|enabled|first-(?:child|of-type)|focus|hover|last-(?:child|of-type)|link|only-(?:child|of-type)|root|:selection|target|visited)/i', array($this, 'lowercase_pseudo_elements'), $css);
319
-
320
- // lowercase some more common functions
321
- $css = preg_replace_callback('/:(lang|not|nth-child|nth-last-child|nth-last-of-type|nth-of-type|(?:-(?:moz|webkit)-)?any)\(/i', array($this, 'lowercase_common_functions'), $css);
322
-
323
- // lower case some common function that can be values
324
- // NOTE: rgb() isn't useful as we replace with #hex later, as well as and() is already done for us
325
- $css = preg_replace_callback('/([:,\( ]\s*)(attr|color-stop|from|rgba|to|url|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?(?:calc|max|min|(?:repeating-)?(?:linear|radial)-gradient)|-webkit-gradient)/iS', array($this, 'lowercase_common_functions_values'), $css);
326
-
327
- // Put the space back in some cases, to support stuff like
328
- // @media screen and (-webkit-min-device-pixel-ratio:0){
329
- $css = preg_replace('/\band\(/i', 'and (', $css);
330
-
331
- // Remove the spaces after the things that should not have spaces after them.
332
- $css = preg_replace('/([\!\{\}\:;\>\+\(\[\~\=,])\s+/S', '$1', $css);
333
-
334
- // remove unnecessary semicolons
335
- $css = preg_replace('/;+\}/', '}', $css);
336
-
337
- // Fix for issue: #2528146
338
- // Restore semicolon if the last property is prefixed with a `*` (lte IE7 hack)
339
- // to avoid issues on Symbian S60 3.x browsers.
340
- $css = preg_replace('/(\*[a-z0-9\-]+\s*\:[^;\}]+)(\})/', '$1;$2', $css);
341
-
342
- // Replace 0 <length> and 0 <percentage> values with 0.
343
- // <length> data type: https://developer.mozilla.org/en-US/docs/Web/CSS/length
344
- // <percentage> data type: https://developer.mozilla.org/en-US/docs/Web/CSS/percentage
345
- $css = preg_replace('/([^\\\\]\:|\s)0(?:em|ex|ch|rem|vw|vh|vm|vmin|cm|mm|in|px|pt|pc|%)/iS', '${1}0', $css);
346
-
347
- // 0% step in a keyframe? restore the % unit
348
- $css = preg_replace_callback('/(@[a-z\-]*?keyframes[^\{]+\{)(.*?)(\}\})/iS', array($this, 'replace_keyframe_zero'), $css);
349
-
350
- // Replace 0 0; or 0 0 0; or 0 0 0 0; with 0.
351
- $css = preg_replace('/\:0(?: 0){1,3}(;|\}| \!)/', ':0$1', $css);
352
-
353
- // Fix for issue: #2528142
354
- // Replace text-shadow:0; with text-shadow:0 0 0;
355
- $css = preg_replace('/(text-shadow\:0)(;|\}| \!)/i', '$1 0 0$2', $css);
356
-
357
- // Replace background-position:0; with background-position:0 0;
358
- // same for transform-origin
359
- // Changing -webkit-mask-position: 0 0 to just a single 0 will result in the second parameter defaulting to 50% (center)
360
- $css = preg_replace('/(background|background\-position|webkit-mask-position|(?:webkit|moz|o|ms|)\-?transform\-origin)\:0(;|\}| \!)/iS', '$1:0 0$2', $css);
361
-
362
- // Shorten colors from rgb(51,102,153) to #336699, rgb(100%,0%,0%) to #ff0000 (sRGB color space)
363
- // Shorten colors from hsl(0, 100%, 50%) to #ff0000 (sRGB color space)
364
- // This makes it more likely that it'll get further compressed in the next step.
365
- $css = preg_replace_callback('/rgb\s*\(\s*([0-9,\s\-\.\%]+)\s*\)(.{1})/i', array($this, 'rgb_to_hex'), $css);
366
- $css = preg_replace_callback('/hsl\s*\(\s*([0-9,\s\-\.\%]+)\s*\)(.{1})/i', array($this, 'hsl_to_hex'), $css);
367
-
368
- // Shorten colors from #AABBCC to #ABC or short color name.
369
- $css = $this->compress_hex_colors($css);
370
-
371
- // border: none to border:0, outline: none to outline:0
372
- $css = preg_replace('/(border\-?(?:top|right|bottom|left|)|outline)\:none(;|\}| \!)/iS', '$1:0$2', $css);
373
-
374
- // shorter opacity IE filter
375
- $css = preg_replace('/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $css);
376
-
377
- // Find a fraction that is used for Opera's -o-device-pixel-ratio query
378
- // Add token to add the "\" back in later
379
- $css = preg_replace('/\(([a-z\-]+):([0-9]+)\/([0-9]+)\)/i', '($1:$2'. self::QUERY_FRACTION .'$3)', $css);
380
-
381
- // Remove empty rules.
382
- $css = preg_replace('/[^\};\{\/]+\{\}/S', '', $css);
383
-
384
- // Add "/" back to fix Opera -o-device-pixel-ratio query
385
- $css = preg_replace('/'. self::QUERY_FRACTION .'/', '/', $css);
386
-
387
- // Replace multiple semi-colons in a row by a single one
388
- // See SF bug #1980989
389
- $css = preg_replace('/;;+/', ';', $css);
390
-
391
- // Restore new lines for /*! important comments
392
- $css = preg_replace('/'. self::NL .'/', "\n", $css);
393
-
394
- // Lowercase all uppercase properties
395
- $css = preg_replace_callback('/(\{|\;)([A-Z\-]+)(\:)/', array($this, 'lowercase_properties'), $css);
396
-
397
- // Some source control tools don't like it when files containing lines longer
398
- // than, say 8000 characters, are checked in. The linebreak option is used in
399
- // that case to split long lines after a specific column.
400
- if ($linebreak_pos !== FALSE && (int) $linebreak_pos >= 0) {
401
- $linebreak_pos = (int) $linebreak_pos;
402
- $start_index = $i = 0;
403
- while ($i < strlen($css)) {
404
- $i++;
405
- if ($css[$i - 1] === '}' && $i - $start_index > $linebreak_pos) {
406
- $css = $this->str_slice($css, 0, $i) . "\n" . $this->str_slice($css, $i);
407
- $start_index = $i;
408
- }
409
- }
410
- }
411
-
412
- // restore preserved comments and strings in reverse order
413
- for ($i = count($this->preserved_tokens) - 1; $i >= 0; $i--) {
414
- $css = preg_replace('/' . self::TOKEN . $i . '___/', $this->preserved_tokens[$i], $css, 1);
415
- // $css.=$this->preserved_tokens[$i];
416
- }
417
-
418
- // Trim the final string (for any leading or trailing white spaces)
419
- return trim($css);
420
- }
421
-
422
- /**
423
- * Utility method to replace all data urls with tokens before we start
424
- * compressing, to avoid performance issues running some of the subsequent
425
- * regexes against large strings chunks.
426
- *
427
- * @param string $css
428
- * @return string
429
- */
430
- private function extract_data_urls($css)
431
- {
432
- // Leave data urls alone to increase parse performance.
433
- $max_index = strlen($css) - 1;
434
- $append_index = $index = $last_index = $offset = 0;
435
- $sb = array();
436
- $pattern = '/url\(\s*(["\']?)data\:/i';
437
-
438
- // Since we need to account for non-base64 data urls, we need to handle
439
- // ' and ) being part of the data string. Hence switching to indexOf,
440
- // to determine whether or not we have matching string terminators and
441
- // handling sb appends directly, instead of using matcher.append* methods.
442
-
443
- while (preg_match($pattern, $css, $m, 0, $offset)) {
444
- $index = $this->index_of($css, $m[0], $offset);
445
- $last_index = $index + strlen($m[0]);
446
- $start_index = $index + 4; // "url(".length()
447
- $end_index = $last_index - 1;
448
- $terminator = $m[1]; // ', " or empty (not quoted)
449
- $found_terminator = FALSE;
450
-
451
- if (strlen($terminator) === 0) {
452
- $terminator = ')';
453
- }
454
-
455
- while ($found_terminator === FALSE && $end_index+1 <= $max_index) {
456
- $end_index = $this->index_of($css, $terminator, $end_index + 1);
457
-
458
- // endIndex == 0 doesn't really apply here
459
- if ($end_index > 0 && substr($css, $end_index - 1, 1) !== '\\') {
460
- $found_terminator = TRUE;
461
- if (')' != $terminator) {
462
- $end_index = $this->index_of($css, ')', $end_index);
463
- }
464
- }
465
- }
466
-
467
- // Enough searching, start moving stuff over to the buffer
468
- $sb[] = $this->str_slice($css, $append_index, $index);
469
-
470
- if ($found_terminator) {
471
- $token = $this->str_slice($css, $start_index, $end_index);
472
- if (strpos($token,"<svg")===false && strpos($token,'svg+xml')===false) {
473
- $token = preg_replace('/\s+/', '', $token);
474
- }
475
- $this->preserved_tokens[] = $token;
476
-
477
- $preserver = 'url(' . self::TOKEN . (count($this->preserved_tokens) - 1) . '___)';
478
- $sb[] = $preserver;
479
-
480
- $append_index = $end_index + 1;
481
- } else {
482
- // No end terminator found, re-add the whole match. Should we throw/warn here?
483
- $sb[] = $this->str_slice($css, $index, $last_index);
484
- $append_index = $last_index;
485
- }
486
-
487
- $offset = $last_index;
488
- }
489
-
490
- $sb[] = $this->str_slice($css, $append_index);
491
-
492
- return implode('', $sb);
493
- }
494
-
495
- /**
496
- * Utility method to compress hex color values of the form #AABBCC to #ABC or short color name.
497
- *
498
- * DOES NOT compress CSS ID selectors which match the above pattern (which would break things).
499
- * e.g. #AddressForm { ... }
500
- *
501
- * DOES NOT compress IE filters, which have hex color values (which would break things).
502
- * e.g. filter: chroma(color="#FFFFFF");
503
- *
504
- * DOES NOT compress invalid hex values.
505
- * e.g. background-color: #aabbccdd
506
- *
507
- * @param string $css
508
- * @return string
509
- */
510
- private function compress_hex_colors($css)
511
- {
512
- // Look for hex colors inside { ... } (to avoid IDs) and which don't have a =, or a " in front of them (to avoid filters)
513
- $pattern = '/(\=\s*?["\']?)?#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])(\}|[^0-9a-f{][^{]*?\})/iS';
514
- $_index = $index = $last_index = $offset = 0;
515
- $sb = array();
516
- // See: http://ajaxmin.codeplex.com/wikipage?title=CSS%20Colors
517
- $short_safe = array(
518
- '#808080' => 'gray',
519
- '#008000' => 'green',
520
- '#800000' => 'maroon',
521
- '#000080' => 'navy',
522
- '#808000' => 'olive',
523
- '#ffa500' => 'orange',
524
- '#800080' => 'purple',
525
- '#c0c0c0' => 'silver',
526
- '#008080' => 'teal',
527
- '#f00' => 'red'
528
- );
529
-
530
- while (preg_match($pattern, $css, $m, 0, $offset)) {
531
- $index = $this->index_of($css, $m[0], $offset);
532
- $last_index = $index + strlen($m[0]);
533
- $is_filter = $m[1] !== null && $m[1] !== '';
534
-
535
- $sb[] = $this->str_slice($css, $_index, $index);
536
-
537
- if ($is_filter) {
538
- // Restore, maintain case, otherwise filter will break
539
- $sb[] = $m[1] . '#' . $m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7];
540
- } else {
541
- if (strtolower($m[2]) == strtolower($m[3]) &&
542
- strtolower($m[4]) == strtolower($m[5]) &&
543
- strtolower($m[6]) == strtolower($m[7])) {
544
- // Compress.
545
- $hex = '#' . strtolower($m[3] . $m[5] . $m[7]);
546
- } else {
547
- // Non compressible color, restore but lower case.
548
- $hex = '#' . strtolower($m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7]);
549
- }
550
- // replace Hex colors to short safe color names
551
- $sb[] = array_key_exists($hex, $short_safe) ? $short_safe[$hex] : $hex;
552
- }
553
-
554
- $_index = $offset = $last_index - strlen($m[8]);
555
- }
556
-
557
- $sb[] = $this->str_slice($css, $_index);
558
-
559
- return implode('', $sb);
560
- }
561
-
562
- /* CALLBACKS
563
- * ---------------------------------------------------------------------------------------------
564
- */
565
-
566
- private function replace_string($matches)
567
- {
568
- $match = $matches[0];
569
- $quote = substr($match, 0, 1);
570
- // Must use addcslashes in PHP to avoid parsing of backslashes
571
- $match = addcslashes($this->str_slice($match, 1, -1), '\\');
572
-
573
- // maybe the string contains a comment-like substring?
574
- // one, maybe more? put'em back then
575
- if (($pos = $this->index_of($match, self::COMMENT)) >= 0) {
576
- for ($i = 0, $max = count($this->comments); $i < $max; $i++) {
577
- $match = preg_replace('/' . self::COMMENT . $i . '___/', $this->comments[$i], $match, 1);
578
- }
579
- }
580
-
581
- // minify alpha opacity in filter strings
582
- $match = preg_replace('/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $match);
583
-
584
- $this->preserved_tokens[] = $match;
585
- return $quote . self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . $quote;
586
- }
587
-
588
- private function replace_colon($matches)
589
- {
590
- return preg_replace('/\:/', self::CLASSCOLON, $matches[0]);
591
- }
592
-
593
- private function replace_calc($matches)
594
- {
595
- $this->preserved_tokens[] = preg_replace('/([\+\-]{1})\(/','$1 (',trim(preg_replace('/\s*([\*\/\(\),])\s*/', '$1', $matches[2])));
596
- return 'calc('. self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')';
597
- }
598
-
599
- private function replace_flex($matches)
600
- {
601
- $this->preserved_tokens[] = trim($matches[1]);
602
- return 'flex:'.self::TOKEN . (count($this->preserved_tokens) - 1) . '___';
603
- }
604
-
605
- private function preserve_old_IE_specific_matrix_definition($matches)
606
- {
607
- $this->preserved_tokens[] = $matches[1];
608
- return 'filter:progid:DXImageTransform.Microsoft.Matrix(' . self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')';
609
- }
610
-
611
- private function replace_keyframe_zero($matches)
612
- {
613
- return $matches[1] . preg_replace('/0(\{|,[^\)\{]+\{)/', '0%$1', $matches[2]) . $matches[3];
614
- }
615
-
616
- private function rgb_to_hex($matches)
617
- {
618
- // Support for percentage values rgb(100%, 0%, 45%);
619
- if ($this->index_of($matches[1], '%') >= 0){
620
- $rgbcolors = explode(',', str_replace('%', '', $matches[1]));
621
- for ($i = 0; $i < count($rgbcolors); $i++) {
622
- $rgbcolors[$i] = $this->round_number(floatval($rgbcolors[$i]) * 2.55);
623
- }
624
- } else {
625
- $rgbcolors = explode(',', $matches[1]);
626
- }
627
-
628
- // Values outside the sRGB color space should be clipped (0-255)
629
- for ($i = 0; $i < count($rgbcolors); $i++) {
630
- $rgbcolors[$i] = $this->clamp_number(intval($rgbcolors[$i], 10), 0, 255);
631
- $rgbcolors[$i] = sprintf("%02x", $rgbcolors[$i]);
632
- }
633
-
634
- // Fix for issue #2528093
635
- if (!preg_match('/[\s\,\);\}]/', $matches[2])){
636
- $matches[2] = ' ' . $matches[2];
637
- }
638
-
639
- return '#' . implode('', $rgbcolors) . $matches[2];
640
- }
641
-
642
- private function hsl_to_hex($matches)
643
- {
644
- $values = explode(',', str_replace('%', '', $matches[1]));
645
- $h = floatval($values[0]);
646
- $s = floatval($values[1]);
647
- $l = floatval($values[2]);
648
-
649
- // Wrap and clamp, then fraction!
650
- $h = ((($h % 360) + 360) % 360) / 360;
651
- $s = $this->clamp_number($s, 0, 100) / 100;
652
- $l = $this->clamp_number($l, 0, 100) / 100;
653
-
654
- if ($s == 0) {
655
- $r = $g = $b = $this->round_number(255 * $l);
656
- } else {
657
- $v2 = $l < 0.5 ? $l * (1 + $s) : ($l + $s) - ($s * $l);
658
- $v1 = (2 * $l) - $v2;
659
- $r = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h + (1/3)));
660
- $g = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h));
661
- $b = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h - (1/3)));
662
- }
663
-
664
- return $this->rgb_to_hex(array('', $r.','.$g.','.$b, $matches[2]));
665
- }
666
-
667
- private function lowercase_pseudo_first($matches)
668
- {
669
- return ':first-'. strtolower($matches[1]) .' '. $matches[2];
670
- }
671
-
672
- private function lowercase_directives($matches)
673
- {
674
- return '@'. strtolower($matches[1]);
675
- }
676
-
677
- private function lowercase_pseudo_elements($matches)
678
- {
679
- return ':'. strtolower($matches[1]);
680
- }
681
-
682
- private function lowercase_common_functions($matches)
683
- {
684
- return ':'. strtolower($matches[1]) .'(';
685
- }
686
-
687
- private function lowercase_common_functions_values($matches)
688
- {
689
- return $matches[1] . strtolower($matches[2]);
690
- }
691
-
692
- private function lowercase_properties($matches)
693
- {
694
- return $matches[1].strtolower($matches[2]).$matches[3];
695
- }
696
-
697
- /* HELPERS
698
- * ---------------------------------------------------------------------------------------------
699
- */
700
-
701
- private function hue_to_rgb($v1, $v2, $vh)
702
- {
703
- $vh = $vh < 0 ? $vh + 1 : ($vh > 1 ? $vh - 1 : $vh);
704
- if ($vh * 6 < 1) return $v1 + ($v2 - $v1) * 6 * $vh;
705
- if ($vh * 2 < 1) return $v2;
706
- if ($vh * 3 < 2) return $v1 + ($v2 - $v1) * ((2/3) - $vh) * 6;
707
- return $v1;
708
- }
709
-
710
- private function round_number($n)
711
- {
712
- return intval(floor(floatval($n) + 0.5), 10);
713
- }
714
-
715
- private function clamp_number($n, $min, $max)
716
- {
717
- return min(max($n, $min), $max);
718
- }
719
-
720
- /**
721
- * PHP port of Javascript's "indexOf" function for strings only
722
- * Author: Tubal Martin http://blog.margenn.com
723
- *
724
- * @param string $haystack
725
- * @param string $needle
726
- * @param int $offset index (optional)
727
- * @return int
728
- */
729
- private function index_of($haystack, $needle, $offset = 0)
730
- {
731
- $index = strpos($haystack, $needle, $offset);
732
-
733
- return ($index !== FALSE) ? $index : -1;
734
- }
735
-
736
- /**
737
- * PHP port of Javascript's "slice" function for strings only
738
- * Author: Tubal Martin http://blog.margenn.com
739
- * Tests: http://margenn.com/tubal/str_slice/
740
- *
741
- * @param string $str
742
- * @param int $start index
743
- * @param int|bool $end index (optional)
744
- * @return string
745
- */
746
- private function str_slice($str, $start = 0, $end = FALSE)
747
- {
748
- if ($end !== FALSE && ($start < 0 || $end <= 0)) {
749
- $max = strlen($str);
750
-
751
- if ($start < 0) {
752
- if (($start = $max + $start) < 0) {
753
- return '';
754
- }
755
- }
756
-
757
- if ($end < 0) {
758
- if (($end = $max + $end) < 0) {
759
- return '';
760
- }
761
- }
762
-
763
- if ($end <= $start) {
764
- return '';
765
- }
766
- }
767
-
768
- $slice = ($end === FALSE) ? substr($str, $start) : substr($str, $start, $end - $start);
769
- return ($slice === FALSE) ? '' : $slice;
770
- }
771
-
772
- /**
773
- * Convert strings like "64M" or "30" to int values
774
- * @param mixed $size
775
- * @return int
776
- */
777
- private function normalize_int($size)
778
- {
779
- if (is_string($size)) {
780
- switch (substr($size, -1)) {
781
- case 'M': case 'm': return $size * 1048576;
782
- case 'K': case 'k': return $size * 1024;
783
- case 'G': case 'g': return $size * 1073741824;
784
- }
785
- }
786
-
787
- return (int) $size;
788
- }
789
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*!
4
+ * cssmin.php v2.4.8-4
5
+ * Author: Tubal Martin - http://tubalmartin.me/
6
+ * Repo: https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port
7
+ *
8
+ * This is a PHP port of the CSS minification tool distributed with YUICompressor,
9
+ * itself a port of the cssmin utility by Isaac Schlueter - http://foohack.com/
10
+ * Permission is hereby granted to use the PHP version under the same
11
+ * conditions as the YUICompressor.
12
+ */
13
+
14
+ /*!
15
+ * YUI Compressor
16
+ * http://developer.yahoo.com/yui/compressor/
17
+ * Author: Julien Lecomte - http://www.julienlecomte.net/
18
+ * Copyright (c) 2013 Yahoo! Inc. All rights reserved.
19
+ * The copyrights embodied in the content of this file are licensed
20
+ * by Yahoo! Inc. under the BSD (revised) open source license.
21
+ */
22
+
23
+ class CSSmin {
24
+ const NL = '___YUICSSMIN_PRESERVED_NL___';
25
+ const TOKEN = '___YUICSSMIN_PRESERVED_TOKEN_';
26
+ const COMMENT = '___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_';
27
+ const CLASSCOLON = '___YUICSSMIN_PSEUDOCLASSCOLON___';
28
+ const QUERY_FRACTION = '___YUICSSMIN_QUERY_FRACTION___';
29
+
30
+ private $comments;
31
+ private $preserved_tokens;
32
+ private $memory_limit;
33
+ private $max_execution_time;
34
+ private $pcre_backtrack_limit;
35
+ private $pcre_recursion_limit;
36
+ private $raise_php_limits;
37
+
38
+ /**
39
+ * @param bool|int $raise_php_limits
40
+ * If true, PHP settings will be raised if needed
41
+ */
42
+ public function __construct( $raise_php_limits = true ) {
43
+ // Set suggested PHP limits
44
+ $this->memory_limit = 128 * 1048576; // 128MB in bytes
45
+ $this->max_execution_time = 60; // 1 min
46
+ $this->pcre_backtrack_limit = 1000 * 1000;
47
+ $this->pcre_recursion_limit = 500 * 1000;
48
+
49
+ $this->raise_php_limits = (bool) $raise_php_limits;
50
+ }
51
+
52
+ /**
53
+ * Minify a string of CSS
54
+ *
55
+ * @param string $css
56
+ * @param int|bool $linebreak_pos
57
+ *
58
+ * @return string
59
+ */
60
+ public function run( $css = '', $linebreak_pos = false ) {
61
+ if ( empty( $css ) ) {
62
+ return '';
63
+ }
64
+
65
+ if ( $this->raise_php_limits ) {
66
+ $this->do_raise_php_limits();
67
+ }
68
+
69
+ $this->comments = array();
70
+ $this->preserved_tokens = array();
71
+
72
+ $start_index = 0;
73
+ $length = strlen( $css );
74
+
75
+ $css = $this->extract_data_urls( $css );
76
+
77
+ // collect all comment blocks...
78
+ while ( ( $start_index = $this->index_of( $css, '/*', $start_index ) ) >= 0 ) {
79
+ $end_index = $this->index_of( $css, '*/', $start_index + 2 );
80
+ if ( $end_index < 0 ) {
81
+ $end_index = $length;
82
+ }
83
+ $comment_found = $this->str_slice( $css, $start_index + 2, $end_index );
84
+ $this->comments[] = $comment_found;
85
+ $comment_preserve_string = self::COMMENT . ( count( $this->comments ) - 1 ) . '___';
86
+ $css = $this->str_slice( $css, 0, $start_index + 2 ) . $comment_preserve_string . $this->str_slice( $css, $end_index );
87
+ // Set correct start_index: Fixes issue #2528130
88
+ $start_index = $end_index + 2 + strlen( $comment_preserve_string ) - strlen( $comment_found );
89
+ }
90
+
91
+ // preserve strings so their content doesn't get accidentally minified
92
+ $css = preg_replace_callback( '/(?:"(?:[^\\\\"]|\\\\.|\\\\)*")|' . "(?:'(?:[^\\\\']|\\\\.|\\\\)*')/S", array( $this, 'replace_string' ), $css );
93
+
94
+ // Let's divide css code in chunks of 5.000 chars aprox.
95
+ // Reason: PHP's PCRE functions like preg_replace have a "backtrack limit"
96
+ // of 100.000 chars by default (php < 5.3.7) so if we're dealing with really
97
+ // long strings and a (sub)pattern matches a number of chars greater than
98
+ // the backtrack limit number (i.e. /(.*)/s) PCRE functions may fail silently
99
+ // returning NULL and $css would be empty.
100
+ $charset = '';
101
+ $charset_regexp = '/(@charset)( [^;]+;)/i';
102
+ $css_chunks = array();
103
+ $css_chunk_length = 5000; // aprox size, not exact
104
+ $start_index = 0;
105
+ $i = $css_chunk_length; // save initial iterations
106
+ $l = strlen( $css );
107
+
108
+ // if the number of characters is 5000 or less, do not chunk
109
+ if ( $l <= $css_chunk_length ) {
110
+ $css_chunks[] = $css;
111
+ } else {
112
+ // chunk css code securely
113
+ while ( $i < $l ) {
114
+ $i += 50; // save iterations
115
+ if ( $l - $start_index <= $css_chunk_length || $i >= $l ) {
116
+ $css_chunks[] = $this->str_slice( $css, $start_index );
117
+ break;
118
+ }
119
+ if ( $css[ $i - 1 ] === '}' && $i - $start_index > $css_chunk_length ) {
120
+ // If there are two ending curly braces }} separated or not by spaces,
121
+ // join them in the same chunk (i.e. @media blocks)
122
+ $next_chunk = substr( $css, $i );
123
+ if ( preg_match( '/^\s*\}/', $next_chunk ) ) {
124
+ $i = $i + $this->index_of( $next_chunk, '}' ) + 1;
125
+ }
126
+
127
+ $css_chunks[] = $this->str_slice( $css, $start_index, $i );
128
+ $start_index = $i;
129
+ }
130
+ }
131
+ }
132
+
133
+ // Minify each chunk
134
+ for ( $i = 0, $n = count( $css_chunks ); $i < $n; $i ++ ) {
135
+ $css_chunks[ $i ] = $this->minify( $css_chunks[ $i ], $linebreak_pos );
136
+ // Keep the first @charset at-rule found
137
+ if ( empty( $charset ) && preg_match( $charset_regexp, $css_chunks[ $i ], $matches ) ) {
138
+ $charset = strtolower( $matches[1] ) . $matches[2];
139
+ }
140
+ // Delete all @charset at-rules
141
+ $css_chunks[ $i ] = preg_replace( $charset_regexp, '', $css_chunks[ $i ] );
142
+ }
143
+
144
+ // Update the first chunk and push the charset to the top of the file.
145
+ $css_chunks[0] = $charset . $css_chunks[0];
146
+
147
+ return implode( '', $css_chunks );
148
+ }
149
+
150
+ /**
151
+ * Sets the memory limit for this script
152
+ *
153
+ * @param int|string $limit
154
+ */
155
+ public function set_memory_limit( $limit ) {
156
+ $this->memory_limit = $this->normalize_int( $limit );
157
+ }
158
+
159
+ /**
160
+ * Sets the maximum execution time for this script
161
+ *
162
+ * @param int|string $seconds
163
+ */
164
+ public function set_max_execution_time( $seconds ) {
165
+ $this->max_execution_time = (int) $seconds;
166
+ }
167
+
168
+ /**
169
+ * Sets the PCRE backtrack limit for this script
170
+ *
171
+ * @param int $limit
172
+ */
173
+ public function set_pcre_backtrack_limit( $limit ) {
174
+ $this->pcre_backtrack_limit = (int) $limit;
175
+ }
176
+
177
+ /**
178
+ * Sets the PCRE recursion limit for this script
179
+ *
180
+ * @param int $limit
181
+ */
182
+ public function set_pcre_recursion_limit( $limit ) {
183
+ $this->pcre_recursion_limit = (int) $limit;
184
+ }
185
+
186
+ /**
187
+ * Try to configure PHP to use at least the suggested minimum settings
188
+ */
189
+ private function do_raise_php_limits() {
190
+ $php_limits = array(
191
+ 'memory_limit' => $this->memory_limit,
192
+ 'max_execution_time' => $this->max_execution_time,
193
+ 'pcre.backtrack_limit' => $this->pcre_backtrack_limit,
194
+ 'pcre.recursion_limit' => $this->pcre_recursion_limit,
195
+ );
196
+
197
+ // If current settings are higher respect them.
198
+ foreach ( $php_limits as $name => $suggested ) {
199
+ $current = $this->normalize_int( ini_get( $name ) );
200
+ // memory_limit exception: allow -1 for "no memory limit".
201
+ if ( $current > - 1 && ( $suggested == - 1 || $current < $suggested ) ) {
202
+ ini_set( $name, $suggested );
203
+ }
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Does bulk of the minification
209
+ *
210
+ * @param string $css
211
+ * @param int|bool $linebreak_pos
212
+ *
213
+ * @return string
214
+ */
215
+ private function minify( $css, $linebreak_pos ) {
216
+ // strings are safe, now wrestle the comments
217
+ for ( $i = 0, $max = count( $this->comments ); $i < $max; $i ++ ) {
218
+
219
+ $token = $this->comments[ $i ];
220
+ $placeholder = '/' . self::COMMENT . $i . '___/';
221
+
222
+ // ! in the first position of the comment means preserve
223
+ // so push to the preserved tokens keeping the !
224
+ if ( substr( $token, 0, 1 ) === '!' ) {
225
+ $this->preserved_tokens[] = $token;
226
+ $token_tring = self::TOKEN . ( count( $this->preserved_tokens ) - 1 ) . '___';
227
+ $css = preg_replace( $placeholder, $token_tring, $css, 1 );
228
+ // Preserve new lines for /*! important comments
229
+ $css = preg_replace( '/\s*[\n\r\f]+\s*(\/\*' . $token_tring . ')/S', self::NL . '$1', $css );
230
+ $css = preg_replace( '/(' . $token_tring . '\*\/)\s*[\n\r\f]+\s*/', '$1' . self::NL, $css );
231
+ continue;
232
+ }
233
+
234
+ // \ in the last position looks like hack for Mac/IE5
235
+ // shorten that to /*\*/ and the next one to /**/
236
+ if ( substr( $token, ( strlen( $token ) - 1 ), 1 ) === '\\' ) {
237
+ $this->preserved_tokens[] = '\\';
238
+ $css = preg_replace( $placeholder, self::TOKEN . ( count( $this->preserved_tokens ) - 1 ) . '___', $css, 1 );
239
+ $i = $i + 1; // attn: advancing the loop
240
+ $this->preserved_tokens[] = '';
241
+ $css = preg_replace( '/' . self::COMMENT . $i . '___/', self::TOKEN . ( count( $this->preserved_tokens ) - 1 ) . '___', $css, 1 );
242
+ continue;
243
+ }
244
+
245
+ // keep empty comments after child selectors (IE7 hack)
246
+ // e.g. html >/**/ body
247
+ if ( strlen( $token ) === 0 ) {
248
+ $start_index = $this->index_of( $css, $this->str_slice( $placeholder, 1, - 1 ) );
249
+ if ( $start_index > 2 ) {
250
+ if ( substr( $css, $start_index - 3, 1 ) === '>' ) {
251
+ $this->preserved_tokens[] = '';
252
+ $css = preg_replace( $placeholder, self::TOKEN . ( count( $this->preserved_tokens ) - 1 ) . '___', $css, 1 );
253
+ }
254
+ }
255
+ }
256
+
257
+ // in all other cases kill the comment
258
+ $css = preg_replace( '/\/\*' . $this->str_slice( $placeholder, 1, - 1 ) . '\*\//', '', $css, 1 );
259
+ }
260
+
261
+ // Normalize all whitespace strings to single spaces. Easier to work with that way.
262
+ $css = preg_replace( '/\s+/', ' ', $css );
263
+
264
+ // preserve flex, keeping percentage even if 0
265
+ $css = preg_replace_callback( '/flex\s?:\s?((?:[0-9 ]*)\s?(?:px|em|auto|%)?(?:calc\(.*\))?)/i', array( $this, 'replace_flex' ), $css );
266
+
267
+ // Fix IE7 issue on matrix filters which browser accept whitespaces between Matrix parameters
268
+ $css = preg_replace_callback( '/\s*filter\:\s*progid:DXImageTransform\.Microsoft\.Matrix\(([^\)]+)\)/', array( $this, 'preserve_old_IE_specific_matrix_definition' ), $css );
269
+
270
+ // Shorten & preserve calculations calc(...) since spaces are important
271
+ $css = preg_replace_callback( '/calc(\(((?:[^\(\)]+|(?1))*)\))/i', array( $this, 'replace_calc' ), $css );
272
+
273
+ // Replace positive sign from numbers preceded by : or a white-space before the leading space is removed
274
+ // +1.2em to 1.2em, +.8px to .8px, +2% to 2%
275
+ $css = preg_replace( '/((?<!\\\\)\:|\s)\+(\.?\d+)/S', '$1$2', $css );
276
+
277
+ // Remove leading zeros from integer and float numbers preceded by : or a white-space
278
+ // 000.6 to .6, -0.8 to -.8, 0050 to 50, -01.05 to -1.05
279
+ $css = preg_replace( '/((?<!\\\\)\:|\s)(\-?)0+(\.?\d+)/S', '$1$2$3', $css );
280
+
281
+ // Remove trailing zeros from float numbers preceded by : or a white-space
282
+ // -6.0100em to -6.01em, .0100 to .01, 1.200px to 1.2px
283
+ $css = preg_replace( '/((?<!\\\\)\:|\s)(\-?)(\d?\.\d+?)0+([^\d])/S', '$1$2$3$4', $css );
284
+
285
+ // Remove trailing .0 -> -9.0 to -9
286
+ $css = preg_replace( '/((?<!\\\\)\:|\s)(\-?\d+)\.0([^\d])/S', '$1$2$3', $css );
287
+
288
+ // Replace 0 length numbers with 0
289
+ $css = preg_replace( '/((?<!\\\\)\:|\s)\-?\.?0+([^\d])/S', '${1}0$2', $css );
290
+
291
+ // Remove the spaces before the things that should not have spaces before them.
292
+ // But, be careful not to turn "p :link {...}" into "p:link{...}"
293
+ // Swap out any pseudo-class colons with the token, and then swap back.
294
+ $css = preg_replace_callback( '/(?:^|\})[^\{]*\s+\:/', array( $this, 'replace_colon' ), $css );
295
+
296
+ // Remove spaces before the things that should not have spaces before them.
297
+ $css = preg_replace( '/\s+([\!\{\}\;\:\>\+\(\)\]\~\=,])/', '$1', $css );
298
+
299
+ // Restore spaces for !important
300
+ $css = preg_replace( '/\!important/i', ' !important', $css );
301
+
302
+ // bring back the colon
303
+ $css = preg_replace( '/' . self::CLASSCOLON . '/', ':', $css );
304
+
305
+ // retain space for special IE6 cases
306
+ $css = preg_replace_callback( '/\:first\-(line|letter)(\{|,)/i', array( $this, 'lowercase_pseudo_first' ), $css );
307
+
308
+ // no space after the end of a preserved comment
309
+ $css = preg_replace( '/\*\/ /', '*/', $css );
310
+
311
+ // lowercase some popular @directives
312
+ $css = preg_replace_callback( '/@(font-face|import|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?keyframe|media|page|namespace)/i', array( $this, 'lowercase_directives' ), $css );
313
+
314
+ // lowercase some more common pseudo-elements
315
+ $css = preg_replace_callback(
316
+ '/:(active|after|before|checked|disabled|empty|enabled|first-(?:child|of-type)|focus|hover|last-(?:child|of-type)|link|only-(?:child|of-type)|root|:selection|target|visited)/i',
317
+ array(
318
+ $this,
319
+ 'lowercase_pseudo_elements',
320
+ ),
321
+ $css
322
+ );
323
+
324
+ // lowercase some more common functions
325
+ $css = preg_replace_callback( '/:(lang|not|nth-child|nth-last-child|nth-last-of-type|nth-of-type|(?:-(?:moz|webkit)-)?any)\(/i', array( $this, 'lowercase_common_functions' ), $css );
326
+
327
+ // lower case some common function that can be values
328
+ // NOTE: rgb() isn't useful as we replace with #hex later, as well as and() is already done for us
329
+ $css = preg_replace_callback(
330
+ '/([:,\( ]\s*)(attr|color-stop|from|rgba|to|url|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?(?:calc|max|min|(?:repeating-)?(?:linear|radial)-gradient)|-webkit-gradient)/iS',
331
+ array(
332
+ $this,
333
+ 'lowercase_common_functions_values',
334
+ ),
335
+ $css
336
+ );
337
+
338
+ // Put the space back in some cases, to support stuff like
339
+ // @media screen and (-webkit-min-device-pixel-ratio:0){
340
+ $css = preg_replace( '/\band\(/i', 'and (', $css );
341
+
342
+ // Remove the spaces after the things that should not have spaces after them.
343
+ $css = preg_replace( '/([\!\{\}\:;\>\+\(\[\~\=,])\s+/S', '$1', $css );
344
+
345
+ // remove unnecessary semicolons
346
+ $css = preg_replace( '/;+\}/', '}', $css );
347
+
348
+ // Fix for issue: #2528146
349
+ // Restore semicolon if the last property is prefixed with a `*` (lte IE7 hack)
350
+ // to avoid issues on Symbian S60 3.x browsers.
351
+ $css = preg_replace( '/(\*[a-z0-9\-]+\s*\:[^;\}]+)(\})/', '$1;$2', $css );
352
+
353
+ // Replace 0 <length> and 0 <percentage> values with 0.
354
+ // <length> data type: https://developer.mozilla.org/en-US/docs/Web/CSS/length
355
+ // <percentage> data type: https://developer.mozilla.org/en-US/docs/Web/CSS/percentage
356
+ $css = preg_replace( '/([^\\\\]\:|\s)0(?:em|ex|ch|rem|vw|vh|vm|vmin|cm|mm|in|px|pt|pc|%)/iS', '${1}0', $css );
357
+
358
+ // 0% step in a keyframe? restore the % unit
359
+ $css = preg_replace_callback( '/(@[a-z\-]*?keyframes[^\{]+\{)(.*?)(\}\})/iS', array( $this, 'replace_keyframe_zero' ), $css );
360
+
361
+ // Replace 0 0; or 0 0 0; or 0 0 0 0; with 0.
362
+ $css = preg_replace( '/\:0(?: 0){1,3}(;|\}| \!)/', ':0$1', $css );
363
+
364
+ // Fix for issue: #2528142
365
+ // Replace text-shadow:0; with text-shadow:0 0 0;
366
+ $css = preg_replace( '/(text-shadow\:0)(;|\}| \!)/i', '$1 0 0$2', $css );
367
+
368
+ // Replace background-position:0; with background-position:0 0;
369
+ // same for transform-origin
370
+ // Changing -webkit-mask-position: 0 0 to just a single 0 will result in the second parameter defaulting to 50% (center)
371
+ $css = preg_replace( '/(background|background\-position|webkit-mask-position|(?:webkit|moz|o|ms|)\-?transform\-origin)\:0(;|\}| \!)/iS', '$1:0 0$2', $css );
372
+
373
+ // Shorten colors from rgb(51,102,153) to #336699, rgb(100%,0%,0%) to #ff0000 (sRGB color space)
374
+ // Shorten colors from hsl(0, 100%, 50%) to #ff0000 (sRGB color space)
375
+ // This makes it more likely that it'll get further compressed in the next step.
376
+ $css = preg_replace_callback( '/rgb\s*\(\s*([0-9,\s\-\.\%]+)\s*\)(.{1})/i', array( $this, 'rgb_to_hex' ), $css );
377
+ $css = preg_replace_callback( '/hsl\s*\(\s*([0-9,\s\-\.\%]+)\s*\)(.{1})/i', array( $this, 'hsl_to_hex' ), $css );
378
+
379
+ // Shorten colors from #AABBCC to #ABC or short color name.
380
+ $css = $this->compress_hex_colors( $css );
381
+
382
+ // border: none to border:0, outline: none to outline:0
383
+ $css = preg_replace( '/(border\-?(?:top|right|bottom|left|)|outline)\:none(;|\}| \!)/iS', '$1:0$2', $css );
384
+
385
+ // shorter opacity IE filter
386
+ $css = preg_replace( '/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $css );
387
+
388
+ // Find a fraction that is used for Opera's -o-device-pixel-ratio query
389
+ // Add token to add the "\" back in later
390
+ $css = preg_replace( '/\(([a-z\-]+):([0-9]+)\/([0-9]+)\)/i', '($1:$2' . self::QUERY_FRACTION . '$3)', $css );
391
+
392
+ // Remove empty rules.
393
+ $css = preg_replace( '/[^\};\{\/]+\{\}/S', '', $css );
394
+
395
+ // Add "/" back to fix Opera -o-device-pixel-ratio query
396
+ $css = preg_replace( '/' . self::QUERY_FRACTION . '/', '/', $css );
397
+
398
+ // Replace multiple semi-colons in a row by a single one
399
+ // See SF bug #1980989
400
+ $css = preg_replace( '/;;+/', ';', $css );
401
+
402
+ // Restore new lines for /*! important comments
403
+ $css = preg_replace( '/' . self::NL . '/', "\n", $css );
404
+
405
+ // Lowercase all uppercase properties
406
+ $css = preg_replace_callback( '/(\{|\;)([A-Z\-]+)(\:)/', array( $this, 'lowercase_properties' ), $css );
407
+
408
+ // Some source control tools don't like it when files containing lines longer
409
+ // than, say 8000 characters, are checked in. The linebreak option is used in
410
+ // that case to split long lines after a specific column.
411
+ if ( $linebreak_pos !== false && (int) $linebreak_pos >= 0 ) {
412
+ $linebreak_pos = (int) $linebreak_pos;
413
+ $start_index = $i = 0;
414
+ while ( $i < strlen( $css ) ) {
415
+ $i ++;
416
+ if ( $css[ $i - 1 ] === '}' && $i - $start_index > $linebreak_pos ) {
417
+ $css = $this->str_slice( $css, 0, $i ) . "\n" . $this->str_slice( $css, $i );
418
+ $start_index = $i;
419
+ }
420
+ }
421
+ }
422
+
423
+ // restore preserved comments and strings in reverse order
424
+ for ( $i = count( $this->preserved_tokens ) - 1; $i >= 0; $i -- ) {
425
+ $css = preg_replace( '/' . self::TOKEN . $i . '___/', $this->preserved_tokens[ $i ], $css, 1 );
426
+ // $css.=$this->preserved_tokens[$i];
427
+ }
428
+
429
+ // Trim the final string (for any leading or trailing white spaces)
430
+ return trim( $css );
431
+ }
432
+
433
+ /**
434
+ * Utility method to replace all data urls with tokens before we start
435
+ * compressing, to avoid performance issues running some of the subsequent
436
+ * regexes against large strings chunks.
437
+ *
438
+ * @param string $css
439
+ *
440
+ * @return string
441
+ */
442
+ private function extract_data_urls( $css ) {
443
+ // Leave data urls alone to increase parse performance.
444
+ $max_index = strlen( $css ) - 1;
445
+ $append_index = $index = $last_index = $offset = 0;
446
+ $sb = array();
447
+ $pattern = '/url\(\s*(["\']?)data\:/i';
448
+
449
+ // Since we need to account for non-base64 data urls, we need to handle
450
+ // ' and ) being part of the data string. Hence switching to indexOf,
451
+ // to determine whether or not we have matching string terminators and
452
+ // handling sb appends directly, instead of using matcher.append* methods.
453
+
454
+ while ( preg_match( $pattern, $css, $m, 0, $offset ) ) {
455
+ $index = $this->index_of( $css, $m[0], $offset );
456
+ $last_index = $index + strlen( $m[0] );
457
+ $start_index = $index + 4; // "url(".length()
458
+ $end_index = $last_index - 1;
459
+ $terminator = $m[1]; // ', " or empty (not quoted)
460
+ $found_terminator = false;
461
+
462
+ if ( strlen( $terminator ) === 0 ) {
463
+ $terminator = ')';
464
+ }
465
+
466
+ while ( $found_terminator === false && $end_index + 1 <= $max_index ) {
467
+ $end_index = $this->index_of( $css, $terminator, $end_index + 1 );
468
+
469
+ // endIndex == 0 doesn't really apply here
470
+ if ( $end_index > 0 && substr( $css, $end_index - 1, 1 ) !== '\\' ) {
471
+ $found_terminator = true;
472
+ if ( ')' != $terminator ) {
473
+ $end_index = $this->index_of( $css, ')', $end_index );
474
+ }
475
+ }
476
+ }
477
+
478
+ // Enough searching, start moving stuff over to the buffer
479
+ $sb[] = $this->str_slice( $css, $append_index, $index );
480
+
481
+ if ( $found_terminator ) {
482
+ $token = $this->str_slice( $css, $start_index, $end_index );
483
+ if ( strpos( $token, '<svg' ) === false && strpos( $token, 'svg+xml' ) === false ) {
484
+ $token = preg_replace( '/\s+/', '', $token );
485
+ }
486
+ $this->preserved_tokens[] = $token;
487
+
488
+ $preserver = 'url(' . self::TOKEN . ( count( $this->preserved_tokens ) - 1 ) . '___)';
489
+ $sb[] = $preserver;
490
+
491
+ $append_index = $end_index + 1;
492
+ } else {
493
+ // No end terminator found, re-add the whole match. Should we throw/warn here?
494
+ $sb[] = $this->str_slice( $css, $index, $last_index );
495
+ $append_index = $last_index;
496
+ }
497
+
498
+ $offset = $last_index;
499
+ }
500
+
501
+ $sb[] = $this->str_slice( $css, $append_index );
502
+
503
+ return implode( '', $sb );
504
+ }
505
+
506
+ /**
507
+ * Utility method to compress hex color values of the form #AABBCC to #ABC or short color name.
508
+ *
509
+ * DOES NOT compress CSS ID selectors which match the above pattern (which would break things).
510
+ * e.g. #AddressForm { ... }
511
+ *
512
+ * DOES NOT compress IE filters, which have hex color values (which would break things).
513
+ * e.g. filter: chroma(color="#FFFFFF");
514
+ *
515
+ * DOES NOT compress invalid hex values.
516
+ * e.g. background-color: #aabbccdd
517
+ *
518
+ * @param string $css
519
+ *
520
+ * @return string
521
+ */
522
+ private function compress_hex_colors( $css ) {
523
+ // Look for hex colors inside { ... } (to avoid IDs) and which don't have a =, or a " in front of them (to avoid filters)
524
+ $pattern = '/(\=\s*?["\']?)?#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])(\}|[^0-9a-f{][^{]*?\})/iS';
525
+ $_index = $index = $last_index = $offset = 0;
526
+ $sb = array();
527
+ // See: http://ajaxmin.codeplex.com/wikipage?title=CSS%20Colors
528
+ $short_safe = array(
529
+ '#808080' => 'gray',
530
+ '#008000' => 'green',
531
+ '#800000' => 'maroon',
532
+ '#000080' => 'navy',
533
+ '#808000' => 'olive',
534
+ '#ffa500' => 'orange',
535
+ '#800080' => 'purple',
536
+ '#c0c0c0' => 'silver',
537
+ '#008080' => 'teal',
538
+ '#f00' => 'red',
539
+ );
540
+
541
+ while ( preg_match( $pattern, $css, $m, 0, $offset ) ) {
542
+ $index = $this->index_of( $css, $m[0], $offset );
543
+ $last_index = $index + strlen( $m[0] );
544
+ $is_filter = $m[1] !== null && $m[1] !== '';
545
+
546
+ $sb[] = $this->str_slice( $css, $_index, $index );
547
+
548
+ if ( $is_filter ) {
549
+ // Restore, maintain case, otherwise filter will break
550
+ $sb[] = $m[1] . '#' . $m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7];
551
+ } else {
552
+ if ( strtolower( $m[2] ) == strtolower( $m[3] ) &&
553
+ strtolower( $m[4] ) == strtolower( $m[5] ) &&
554
+ strtolower( $m[6] ) == strtolower( $m[7] ) ) {
555
+ // Compress.
556
+ $hex = '#' . strtolower( $m[3] . $m[5] . $m[7] );
557
+ } else {
558
+ // Non compressible color, restore but lower case.
559
+ $hex = '#' . strtolower( $m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7] );
560
+ }
561
+ // replace Hex colors to short safe color names
562
+ $sb[] = array_key_exists( $hex, $short_safe ) ? $short_safe[ $hex ] : $hex;
563
+ }
564
+
565
+ $_index = $offset = $last_index - strlen( $m[8] );
566
+ }
567
+
568
+ $sb[] = $this->str_slice( $css, $_index );
569
+
570
+ return implode( '', $sb );
571
+ }
572
+
573
+ /* CALLBACKS
574
+ * ---------------------------------------------------------------------------------------------
575
+ */
576
+
577
+ private function replace_string( $matches ) {
578
+ $match = $matches[0];
579
+ $quote = substr( $match, 0, 1 );
580
+ // Must use addcslashes in PHP to avoid parsing of backslashes
581
+ $match = addcslashes( $this->str_slice( $match, 1, - 1 ), '\\' );
582
+
583
+ // maybe the string contains a comment-like substring?
584
+ // one, maybe more? put'em back then
585
+ if ( ( $pos = $this->index_of( $match, self::COMMENT ) ) >= 0 ) {
586
+ for ( $i = 0, $max = count( $this->comments ); $i < $max; $i ++ ) {
587
+ $match = preg_replace( '/' . self::COMMENT . $i . '___/', $this->comments[ $i ], $match, 1 );
588
+ }
589
+ }
590
+
591
+ // minify alpha opacity in filter strings
592
+ $match = preg_replace( '/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $match );
593
+
594
+ $this->preserved_tokens[] = $match;
595
+
596
+ return $quote . self::TOKEN . ( count( $this->preserved_tokens ) - 1 ) . '___' . $quote;
597
+ }
598
+
599
+ private function replace_colon( $matches ) {
600
+ return preg_replace( '/\:/', self::CLASSCOLON, $matches[0] );
601
+ }
602
+
603
+ private function replace_calc( $matches ) {
604
+ $this->preserved_tokens[] = preg_replace( '/([\+\-]{1})\(/', '$1 (', trim( preg_replace( '/\s*([\*\/\(\),])\s*/', '$1', $matches[2] ) ) );
605
+
606
+ return 'calc(' . self::TOKEN . ( count( $this->preserved_tokens ) - 1 ) . '___' . ')';
607
+ }
608
+
609
+ private function replace_flex( $matches ) {
610
+ $this->preserved_tokens[] = trim( $matches[1] );
611
+
612
+ return 'flex:' . self::TOKEN . ( count( $this->preserved_tokens ) - 1 ) . '___';
613
+ }
614
+
615
+ private function preserve_old_IE_specific_matrix_definition( $matches ) {
616
+ $this->preserved_tokens[] = $matches[1];
617
+
618
+ return 'filter:progid:DXImageTransform.Microsoft.Matrix(' . self::TOKEN . ( count( $this->preserved_tokens ) - 1 ) . '___' . ')';
619
+ }
620
+
621
+ private function replace_keyframe_zero( $matches ) {
622
+ return $matches[1] . preg_replace( '/0(\{|,[^\)\{]+\{)/', '0%$1', $matches[2] ) . $matches[3];
623
+ }
624
+
625
+ private function rgb_to_hex( $matches ) {
626
+ // Support for percentage values rgb(100%, 0%, 45%);
627
+ if ( $this->index_of( $matches[1], '%' ) >= 0 ) {
628
+ $rgbcolors = explode( ',', str_replace( '%', '', $matches[1] ) );
629
+ for ( $i = 0; $i < count( $rgbcolors ); $i ++ ) {
630
+ $rgbcolors[ $i ] = $this->round_number( floatval( $rgbcolors[ $i ] ) * 2.55 );
631
+ }
632
+ } else {
633
+ $rgbcolors = explode( ',', $matches[1] );
634
+ }
635
+
636
+ // Values outside the sRGB color space should be clipped (0-255)
637
+ for ( $i = 0; $i < count( $rgbcolors ); $i ++ ) {
638
+ $rgbcolors[ $i ] = $this->clamp_number( intval( $rgbcolors[ $i ], 10 ), 0, 255 );
639
+ $rgbcolors[ $i ] = sprintf( '%02x', $rgbcolors[ $i ] );
640
+ }
641
+
642
+ // Fix for issue #2528093
643
+ if ( ! preg_match( '/[\s\,\);\}]/', $matches[2] ) ) {
644
+ $matches[2] = ' ' . $matches[2];
645
+ }
646
+
647
+ return '#' . implode( '', $rgbcolors ) . $matches[2];
648
+ }
649
+
650
+ private function hsl_to_hex( $matches ) {
651
+ $values = explode( ',', str_replace( '%', '', $matches[1] ) );
652
+ $h = floatval( $values[0] );
653
+ $s = floatval( $values[1] );
654
+ $l = floatval( $values[2] );
655
+
656
+ // Wrap and clamp, then fraction!
657
+ $h = ( ( ( $h % 360 ) + 360 ) % 360 ) / 360;
658
+ $s = $this->clamp_number( $s, 0, 100 ) / 100;
659
+ $l = $this->clamp_number( $l, 0, 100 ) / 100;
660
+
661
+ if ( $s == 0 ) {
662
+ $r = $g = $b = $this->round_number( 255 * $l );
663
+ } else {
664
+ $v2 = $l < 0.5 ? $l * ( 1 + $s ) : ( $l + $s ) - ( $s * $l );
665
+ $v1 = ( 2 * $l ) - $v2;
666
+ $r = $this->round_number( 255 * $this->hue_to_rgb( $v1, $v2, $h + ( 1 / 3 ) ) );
667
+ $g = $this->round_number( 255 * $this->hue_to_rgb( $v1, $v2, $h ) );
668
+ $b = $this->round_number( 255 * $this->hue_to_rgb( $v1, $v2, $h - ( 1 / 3 ) ) );
669
+ }
670
+
671
+ return $this->rgb_to_hex( array( '', $r . ',' . $g . ',' . $b, $matches[2] ) );
672
+ }
673
+
674
+ private function lowercase_pseudo_first( $matches ) {
675
+ return ':first-' . strtolower( $matches[1] ) . ' ' . $matches[2];
676
+ }
677
+
678
+ private function lowercase_directives( $matches ) {
679
+ return '@' . strtolower( $matches[1] );
680
+ }
681
+
682
+ private function lowercase_pseudo_elements( $matches ) {
683
+ return ':' . strtolower( $matches[1] );
684
+ }
685
+
686
+ private function lowercase_common_functions( $matches ) {
687
+ return ':' . strtolower( $matches[1] ) . '(';
688
+ }
689
+
690
+ private function lowercase_common_functions_values( $matches ) {
691
+ return $matches[1] . strtolower( $matches[2] );
692
+ }
693
+
694
+ private function lowercase_properties( $matches ) {
695
+ return $matches[1] . strtolower( $matches[2] ) . $matches[3];
696
+ }
697
+
698
+ /* HELPERS
699
+ * ---------------------------------------------------------------------------------------------
700
+ */
701
+
702
+ private function hue_to_rgb( $v1, $v2, $vh ) {
703
+ $vh = $vh < 0 ? $vh + 1 : ( $vh > 1 ? $vh - 1 : $vh );
704
+ if ( $vh * 6 < 1 ) {
705
+ return $v1 + ( $v2 - $v1 ) * 6 * $vh;
706
+ }
707
+ if ( $vh * 2 < 1 ) {
708
+ return $v2;
709
+ }
710
+ if ( $vh * 3 < 2 ) {
711
+ return $v1 + ( $v2 - $v1 ) * ( ( 2 / 3 ) - $vh ) * 6;
712
+ }
713
+
714
+ return $v1;
715
+ }
716
+
717
+ private function round_number( $n ) {
718
+ return intval( floor( floatval( $n ) + 0.5 ), 10 );
719
+ }
720
+
721
+ private function clamp_number( $n, $min, $max ) {
722
+ return min( max( $n, $min ), $max );
723
+ }
724
+
725
+ /**
726
+ * PHP port of Javascript's "indexOf" function for strings only
727
+ * Author: Tubal Martin http://blog.margenn.com
728
+ *
729
+ * @param string $haystack
730
+ * @param string $needle
731
+ * @param int $offset index (optional)
732
+ *
733
+ * @return int
734
+ */
735
+ private function index_of( $haystack, $needle, $offset = 0 ) {
736
+ $index = strpos( $haystack, $needle, $offset );
737
+
738
+ return ( $index !== false ) ? $index : - 1;
739
+ }
740
+
741
+ /**
742
+ * PHP port of Javascript's "slice" function for strings only
743
+ * Author: Tubal Martin http://blog.margenn.com
744
+ * Tests: http://margenn.com/tubal/str_slice/
745
+ *
746
+ * @param string $str
747
+ * @param int $start index
748
+ * @param int|bool $end index (optional)
749
+ *
750
+ * @return string
751
+ */
752
+ private function str_slice( $str, $start = 0, $end = false ) {
753
+ if ( $end !== false && ( $start < 0 || $end <= 0 ) ) {
754
+ $max = strlen( $str );
755
+
756
+ if ( $start < 0 ) {
757
+ if ( ( $start = $max + $start ) < 0 ) {
758
+ return '';
759
+ }
760
+ }
761
+
762
+ if ( $end < 0 ) {
763
+ if ( ( $end = $max + $end ) < 0 ) {
764
+ return '';
765
+ }
766
+ }
767
+
768
+ if ( $end <= $start ) {
769
+ return '';
770
+ }
771
+ }
772
+
773
+ $slice = ( $end === false ) ? substr( $str, $start ) : substr( $str, $start, $end - $start );
774
+
775
+ return ( $slice === false ) ? '' : $slice;
776
+ }
777
+
778
+ /**
779
+ * Convert strings like "64M" or "30" to int values
780
+ *
781
+ * @param mixed $size
782
+ *
783
+ * @return int
784
+ */
785
+ private function normalize_int( $size ) {
786
+
787
+ $size_type = substr( $size, - 1 ); // M/K/G
788
+ $size_numeric = substr( $size, 0, ( strlen( $size ) - 1 ) ); // numeric value
789
+
790
+ if ( is_string( $size_type ) ) {
791
+
792
+ switch ( $size_type ) {
793
+ case 'M':
794
+ case 'm':
795
+ return $size_numeric * 1048576;
796
+ case 'K':
797
+ case 'k':
798
+ return $size_numeric * 1024;
799
+ case 'G':
800
+ case 'g':
801
+ return $size_numeric * 1073741824;
802
+ }
803
+ }
804
+
805
+ return (int) $size;
806
+ }
807
+ }
inc/plugin-incompatibility/class-breeze-incompatibility-plugins.php ADDED
@@ -0,0 +1,368 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) ) {
3
+ header( 'Status: 403 Forbidden' );
4
+ header( 'HTTP/1.1 403 Forbidden' );
5
+ exit;
6
+ }
7
+ /**
8
+ * Class used to check if user has any other cache plugins active.
9
+ * If here are any then we need to display a message informing the user of possible issues.
10
+ *
11
+ * @since 1.1.1
12
+ *
13
+ * Class Breeze_Incompatibility_Plugins
14
+ */
15
+ if ( ! class_exists( 'Breeze_Incompatibility_Plugins' ) ) {
16
+ class Breeze_Incompatibility_Plugins {
17
+ /**
18
+ * Used to hold the data needed to display in the notice.
19
+ * @var string HTML notification content.
20
+ */
21
+ protected $notification_message = '';
22
+
23
+ /**
24
+ * Contains the plugins list
25
+ *
26
+ * @var array current install plugins list.
27
+ */
28
+ protected $plugins_list = array();
29
+
30
+ /**
31
+ * Breeze_Incompatibility_Plugins constructor.
32
+ */
33
+ function __construct() {
34
+ /**
35
+ * Init the notification.
36
+ *
37
+ * @see https://developer.wordpress.org/reference/hooks/after_plugin_row_plugin_file/
38
+ */
39
+ #add_action( 'after_plugin_row_' . BREEZE_BASENAME, array( &$this, 'prepare_and_display_notification_content' ), 15, 2 );
40
+ add_action( 'admin_notices', array( &$this, 'prepare_and_display_notification_content' ), 15 );
41
+ add_action( 'network_admin_notices', array( &$this, 'prepare_and_display_notification_content' ), 15 );
42
+
43
+ add_action( 'wp_ajax_compatibility_warning_close', array( &$this, 'compatibility_warning_close' ) );
44
+ }
45
+
46
+ public function compatibility_warning_close() {
47
+ $response = array();
48
+ $response['success'] = true;
49
+ update_option( 'breeze_hide_notice', 'yes', 'no' );
50
+
51
+ wp_send_json( $response );
52
+ }
53
+
54
+ /**
55
+ * Display plugin conflicts list in plugins page.
56
+ *
57
+ * @param string $file Plugin basename.
58
+ * @param array $plugin_data Plugin information.
59
+ */
60
+ public function prepare_and_display_notification_content( $file = '', $plugin_data = array() ) {
61
+ $current_screen = get_current_screen(); // get the current WP screen
62
+
63
+ // If we are on Network plugins or single site plugins screen, run the script.
64
+ if ( ( ! empty( $current_screen ) && ( 'plugins-network' === $current_screen->base || 'plugins' === $current_screen->base ) ) ) {
65
+ // Gather messages for incompatibility notice.
66
+ $this->notification_message = $this->notification_for_incompatibility();
67
+ // Future notices can be added and captured here.
68
+
69
+ // Start the notice row.
70
+ if ( ! empty( $this->notification_message ) ) {
71
+ // Display catched notifications.
72
+ echo $this->notification_message;
73
+ }
74
+ // End the notice row.
75
+
76
+ }
77
+ }
78
+
79
+ /**
80
+ *
81
+ *
82
+ * @return false|string
83
+ */
84
+ protected function notification_for_incompatibility() {
85
+ // Fetch the list of processed incompatible/conflicting plugins.
86
+ $incompatibility_list = $this->incompatibility_list();
87
+ $notice_message = '';
88
+ $show_message = true;
89
+
90
+ $get_notice_rule = get_option( 'breeze_hide_notice', '' );
91
+
92
+ $comparing_value = md5( wp_json_encode( $incompatibility_list ) );
93
+ if ( 'yes' === $get_notice_rule ) {
94
+ $get_old_values = get_option( 'breeze_show_incompatibility', '' );
95
+ if ( $get_old_values !== $comparing_value ) {
96
+ delete_option( 'breeze_hide_notice' );
97
+ update_option( 'breeze_show_incompatibility', $comparing_value, 'no' );
98
+ } else {
99
+ $show_message = false;
100
+ }
101
+ } else {
102
+ update_option( 'breeze_show_incompatibility', $comparing_value, 'no' );
103
+ }
104
+
105
+ if ( $show_message && ! empty( $incompatibility_list ) ) {
106
+ // Build the HTML for the error notice.
107
+ ob_start();
108
+ require BREEZE_PLUGIN_DIR . 'views/html-notice-plugin-screen-incompatibilities.php';
109
+ $notice_message = ob_get_contents();
110
+ ob_get_clean();
111
+ }
112
+
113
+ return $notice_message;
114
+ }
115
+
116
+ protected function incompatibility_list() {
117
+ global $status, $page, $s;
118
+
119
+ // Current installed plugins
120
+ $installed_plugins = $this->plugins_list();
121
+ // Fetch the list of incompatible/conflicting plugins data
122
+ $incompatible_plugins = $this->list_of_incompatible_plugins();
123
+ $final_list = array();
124
+ $context = $status;
125
+
126
+ if ( ! empty( $incompatible_plugins ) && ! empty( $installed_plugins ) ) {
127
+ foreach ( $incompatible_plugins as $plugin => $details ) {
128
+
129
+ if ( isset( $installed_plugins[ $plugin ] ) ) {
130
+
131
+ // Only do the operations if the given plugin is active.
132
+ if ( is_plugin_active( $plugin ) ) {
133
+
134
+ // Version that not compatible
135
+ $warning_version = $details['warning_version'];
136
+ // Need to see if the values is -1
137
+ $warning_version_int = (int) $warning_version;
138
+ $active_item = $installed_plugins[ $plugin ];
139
+ $is_warning = false;
140
+
141
+ // This means it's a specific version we need to be aware of.
142
+ if ( - 1 !== $warning_version_int ) {
143
+ $current_version = $active_item['Version']; // Current installed plugin version.
144
+ $operator = $details['compare_sign']; // Compare Operator
145
+ $is_warning = version_compare( $current_version, $warning_version, $operator );
146
+ } elseif ( - 1 === $warning_version_int ) { // incompatible no matter the the version
147
+ $is_warning = true;
148
+ }
149
+
150
+ $network_only_text = '';
151
+ // If the plugin is marked as a warning
152
+ if ( true === $is_warning ) {
153
+ // Build the default message for incompatibility.
154
+ $message = $active_item['Title'] . ' ' . esc_html__( 'Plugin', 'breeze' ) . ' ' . $active_item['Version'] . ' ' . esc_html__( 'is not compatible', 'breeze' ) . ' ';
155
+ if ( ! empty( trim( $details['warning_message'] ) ) ) {
156
+ // If a custom message exists, overwrite the default message.
157
+ $message = trim( $details['warning_message'] );
158
+ }
159
+ $current_screen = get_current_screen();
160
+ $show_deactivate = false;
161
+ if ( 'plugins-network' === $current_screen->base ) {
162
+ if ( current_user_can( 'manage_network_plugins' ) ) {
163
+ $show_deactivate = true;
164
+ }
165
+ } elseif ( 'plugins' === $current_screen->base ) {
166
+ if ( current_user_can( 'deactivate_plugin', $plugin ) ) {
167
+ $is_active = is_plugin_active( $plugin );
168
+ $restrict_network_active = ( is_multisite() && is_plugin_active_for_network( $plugin ) );
169
+ $restrict_network_only = ( is_multisite() && is_network_only_plugin( $plugin ) && ! $is_active );
170
+
171
+ if ( ! $restrict_network_active && ! $restrict_network_only ) {
172
+ $show_deactivate = true;
173
+ }
174
+
175
+ // Some plugins can only be disabled from Network if Multi-site
176
+ if ( $restrict_network_active ) {
177
+ $network_only_text = __( 'Network Active - deactivate from Network' );
178
+ } elseif ( $restrict_network_only ) {
179
+ $network_only_text = __( 'Network Only - deactivate from Network' );
180
+ }
181
+ }
182
+ }
183
+ // Build data for the notice HTML
184
+ $final_list[] = array(
185
+ 'warning_message' => $message,
186
+ 'safe_version_message' => ( ! empty( trim( $details['safe_version_message'] ) ) ? $details['safe_version_message'] : '' ),
187
+ 'display_deactivate_button' => $show_deactivate,
188
+ 'deactivate_url' => wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . urlencode( $plugin ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'deactivate-plugin_' . $plugin ),
189
+ 'is_network_only' => $network_only_text,
190
+ );
191
+
192
+ }
193
+ }
194
+ }
195
+ }
196
+ }
197
+
198
+ return $final_list;
199
+ }
200
+
201
+ /**
202
+ * Cache the plugins list.
203
+ *
204
+ * @return array Plugins of current WP install
205
+ */
206
+ protected function plugins_list() {
207
+ // If $plugins_list is empty, request the list again
208
+ if ( empty( $this->plugins_list ) || ! is_array( $this->plugins_list ) ) {
209
+ $this->plugins_list = get_plugins();
210
+ }
211
+
212
+ /* Example of an element from get_plugins()
213
+ array(
214
+ 'breeze/breeze.php' => array(
215
+ 'WC requires at least' => '',
216
+ 'WC tested up to' => '',
217
+ 'Woo' => '',
218
+ 'Name' => 'Breeze',
219
+ 'PluginURI' => '',
220
+ 'Version' => '1.1.1',
221
+ 'Description' => 'Breeze is a WordPress cache plugin with extensive options to speed up your website. All the options including Varnish Cache are compatible with Cloudways hosting.',
222
+ 'Author' => 'Cloudways',
223
+ 'AuthorURI' => 'https://www.cloudways.com',
224
+ 'TextDomain' => 'breeze',
225
+ 'DomainPath' => '/languages',
226
+ 'Network' => true,
227
+ 'Title' => 'Breeze',
228
+ 'AuthorName' => 'Cloudways',
229
+ ),
230
+ );
231
+ */
232
+
233
+ return $this->plugins_list;
234
+ }
235
+
236
+ /**
237
+ * Add/Remove from this list incompatible plugins.
238
+ * Follow the instructions in the comment below and template copy an existent teplate
239
+ * to modify for any new item.
240
+ *
241
+ * @return array
242
+ */
243
+ protected function list_of_incompatible_plugins() {
244
+ return array(
245
+ /**
246
+ * The format:
247
+ * <plugin-folder>/<plugin-main-file>.php
248
+ * This is how WordPress recognizes the plugins
249
+ *
250
+ * Parameter explanation:
251
+ * ! warning_message !
252
+ * If left empty it will automatically use "<Plugin name> Plugin (<version_no>)".
253
+ * If you fill this field, it will overwrite the default message and display the custom message instead.
254
+ *
255
+ * ! safe_version_message !
256
+ * This message is just text to inform the user about a compatible version that is working with Breeze.
257
+ * If left empty, it does not display anything.
258
+ * Will display as Note: safe_version_message
259
+ *
260
+ * ! warning_version !
261
+ * Type the version from which the plugin is no longer compatible.
262
+ * Type -1 so that all versions of this plugin are not compatible.
263
+ *
264
+ * ! compare_sign !
265
+ * It will use current plugin version to compare with warning_version using the given sign.
266
+ * Accepted compare operators <,<=,>,>=, ==, =, !=, <>.
267
+ * If warning_version has the value -1, the compare_sign will be ignored.
268
+ * Current version of installed plugin compared to warning_version
269
+ */
270
+ 'w3-total-cache/w3-total-cache.php' => array(
271
+ 'warning_message' => '',
272
+ 'warning_version' => - 1,
273
+ 'compare_sign' => '>',
274
+ 'safe_version_message' => '',
275
+ ),
276
+ 'wp-super-cache/wp-cache.php' => array(
277
+ 'warning_message' => '',
278
+ 'warning_version' => - 1,
279
+ 'compare_sign' => '>',
280
+ 'safe_version_message' => '',
281
+ ),
282
+ 'litespeed-cache/litespeed-cache.php' => array(
283
+ 'warning_message' => '',
284
+ 'warning_version' => '2.0',
285
+ 'compare_sign' => '>=', // Current version of installed plugin compared to warning_version
286
+ 'safe_version_message' => 'Version (1.0 - 1.9) are compatible.',
287
+ ),
288
+ 'quick-cache/quick-cache.php' => array(
289
+ 'warning_message' => '',
290
+ 'warning_version' => - 1,
291
+ 'compare_sign' => '>',
292
+ 'safe_version_message' => '',
293
+ ),
294
+ 'hyper-cache/plugin.php' => array(
295
+ 'warning_message' => '',
296
+ 'warning_version' => - 1,
297
+ 'compare_sign' => '>',
298
+ 'safe_version_message' => '',
299
+ ),
300
+ 'hyper-cache-extended/plugin.php' => array(
301
+ 'warning_message' => '',
302
+ 'warning_version' => - 1,
303
+ 'compare_sign' => '>',
304
+ 'safe_version_message' => '',
305
+ ),
306
+ 'wp-fast-cache/wp-fast-cache.php' => array(
307
+ 'warning_message' => '',
308
+ 'warning_version' => - 1,
309
+ 'compare_sign' => '>',
310
+ 'safe_version_message' => '',
311
+ ),
312
+ 'flexicache/wp-plugin.php' => array(
313
+ 'warning_message' => '',
314
+ 'warning_version' => - 1,
315
+ 'compare_sign' => '>',
316
+ 'safe_version_message' => '',
317
+ ),
318
+ 'wp-fastest-cache/wpFastestCache.php' => array(
319
+ 'warning_message' => '',
320
+ 'warning_version' => - 1,
321
+ 'compare_sign' => '>',
322
+ 'safe_version_message' => '',
323
+ ),
324
+ 'lite-cache/plugin.php' => array(
325
+ 'warning_message' => '',
326
+ 'warning_version' => - 1,
327
+ 'compare_sign' => '>',
328
+ 'safe_version_message' => '',
329
+ ),
330
+ 'gator-cache/gator-cache.php' => array(
331
+ 'warning_message' => '',
332
+ 'warning_version' => - 1,
333
+ 'compare_sign' => '>',
334
+ 'safe_version_message' => '',
335
+ ),
336
+ 'wp-http-compression/wp-http-compression.php' => array(
337
+ 'warning_message' => '',
338
+ 'warning_version' => - 1,
339
+ 'compare_sign' => '>',
340
+ 'safe_version_message' => '',
341
+ ),
342
+ 'wordpress-gzip-compression/ezgz.php' => array(
343
+ 'warning_message' => '',
344
+ 'warning_version' => - 1,
345
+ 'compare_sign' => '>',
346
+ 'safe_version_message' => '',
347
+ ),
348
+ 'gzip-ninja-speed-compression/gzip-ninja-speed.php' => array(
349
+ 'warning_message' => '',
350
+ 'warning_version' => - 1,
351
+ 'compare_sign' => '>',
352
+ 'safe_version_message' => '',
353
+ ),
354
+ 'speed-booster-pack/speed-booster-pack.php' => array(
355
+ 'warning_message' => '',
356
+ 'warning_version' => - 1,
357
+ 'compare_sign' => '>',
358
+ 'safe_version_message' => '',
359
+ ),
360
+
361
+ );
362
+ }
363
+
364
+
365
+ }
366
+
367
+ new Breeze_Incompatibility_Plugins();
368
+ }
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: Cloudways
3
  Tags: cache,caching, performance, wp-cache, cdn, combine, compress, speed plugin, database cache,gzip, http compression, js cache, minify, optimize, page cache, performance, speed, expire headers
4
  Requires at least: 4.5
5
  Tested up to: 5.3
6
- Stable tag: 1.1.2
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -145,6 +145,18 @@ Using Gzip, Breeze compresses the request files, further reducing the size of th
145
 
146
  == Changelog ==
147
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  = 1.1.2 =
149
  * Fix: Improved handling of exclusion of CSS and JS while Minification and Group Files options are enabled.
150
  * Fix: Allow wildcard (.*) based exclusion of pattern files/URIs in exclude JS and exclude CSS fields.
3
  Tags: cache,caching, performance, wp-cache, cdn, combine, compress, speed plugin, database cache,gzip, http compression, js cache, minify, optimize, page cache, performance, speed, expire headers
4
  Requires at least: 4.5
5
  Tested up to: 5.3
6
+ Stable tag: 1.1.3
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
145
 
146
  == Changelog ==
147
 
148
+ = 1.1.3 =
149
+ * Fix: Undefine error for inline JS when JS Group file is enabled.
150
+ * Fix: Several files displayed when Group Files was enabled.
151
+ * Fix: Varnish auto purge slowed down admin area while varnish is not running.
152
+ * Fix: PDF files are not downloadable with CDN enabled.
153
+ * Fix: miscellaneous UI issues.
154
+ * Add: The Google Analytics script/tag is now excluded form Minification.
155
+ * Add: Option to enable cache for admin user.
156
+ * Add: Handling of 404 error of JS/CSS/HTML when cache files are not writeable.
157
+ * Add: Exclude @import directive from CSS Minification.
158
+
159
+
160
  = 1.1.2 =
161
  * Fix: Improved handling of exclusion of CSS and JS while Minification and Group Files options are enabled.
162
  * Fix: Allow wildcard (.*) based exclusion of pattern files/URIs in exclude JS and exclude CSS fields.
views/breeze-setting-views.php CHANGED
@@ -100,7 +100,7 @@ $global_tabs = array(
100
  echo '<p class="multisite-inherit-disclaimer">' . __( '* Any change here will also be applied to all the sub-sites that are using Network level settings.', 'wpr' ) . '</p>';
101
  }
102
  echo '<p class="submit">' . PHP_EOL .
103
- '<input type="submit" class="button button-primary" value="'. __('Save Changes', 'breeze') .'"/>' . PHP_EOL .
104
  '</p>';
105
  }
106
  if ( ! in_array( $key, $global_tabs ) ) {
100
  echo '<p class="multisite-inherit-disclaimer">' . __( '* Any change here will also be applied to all the sub-sites that are using Network level settings.', 'wpr' ) . '</p>';
101
  }
102
  echo '<p class="submit">' . PHP_EOL .
103
+ '<input type="submit" class="button button-primary breeze-submit-btn" value="'. __('Save Changes', 'breeze') .'"/>' . PHP_EOL .
104
  '</p>';
105
  }
106
  if ( ! in_array( $key, $global_tabs ) ) {
views/html-notice-plugin-screen-incompatibilities.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Admin View Notice.
4
+ * Notice to display possible incompatibility issues.
5
+ *
6
+ * @since 1.1.1
7
+ */
8
+
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ header( 'Status: 403 Forbidden' );
11
+ header( 'HTTP/1.1 403 Forbidden' );
12
+ exit;
13
+ }
14
+
15
+ if ( ! isset( $incompatibility_list ) ) {
16
+ $incompatibility_list = array();
17
+ }
18
+
19
+ /**
20
+ * For variable $incompatibility_list
21
+ * @see Breeze_Incompatibility_Plugins::notification_for_incompatibility()
22
+ */
23
+ ?>
24
+ <div class="notice notice-error is-dismissible" id="breeze-plugins-notice">
25
+ <br/>
26
+ <span><strong><?php esc_html_e( 'Breeze Incompatible Plugins', 'breeze' ); ?></strong></span>
27
+ <br/>
28
+ <span class="text-error">
29
+ <?php esc_html_e( 'The following plugin(s) is not compatible with Breeze and could conflict with plugin options.', 'breeze' ); ?>
30
+ <?php esc_html_e( 'We recommend deactivating these plugin(s) and installing a compatible version.', 'breeze' ); ?>
31
+ </span>
32
+ <ul>
33
+ <?php
34
+ foreach ( $incompatibility_list as $plugin ) {
35
+ $note_message = $plugin['safe_version_message'];
36
+ ?>
37
+
38
+ <li><?php echo esc_html( $plugin['warning_message'] ); ?>
39
+ <?php if ( $plugin['display_deactivate_button'] ) { ?>
40
+ ( <a class="" href="<?php echo esc_url( $plugin['deactivate_url'] ); ?>">
41
+ <?php esc_html_e( 'Deactivate', 'breeze' ); ?>
42
+ </a> )
43
+ <?php
44
+ } elseif ( ! empty( trim( $plugin['is_network_only'] ) ) ) {
45
+ echo '[ ' . esc_html( $plugin['is_network_only'] ) . ' ]';
46
+ }
47
+ ?>
48
+
49
+ <?php
50
+ if ( ! empty( $note_message ) ) {
51
+ echo '. ' . esc_html( $note_message );
52
+ }
53
+ ?>
54
+ </li>
55
+
56
+ <?php } ?>
57
+ </ul>
58
+ </div>
views/tabs/basic.php CHANGED
@@ -148,4 +148,26 @@ $basic = breeze_get_option( 'basic_settings', true );
148
  </select>
149
  </td>
150
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  </table>
148
  </select>
149
  </td>
150
  </tr>
151
+ <tr>
152
+ <td>
153
+ <label class="breeze_tool_tip"><?php _e('Enable cache for loggedin users', 'breeze'); ?></label>
154
+ </td>
155
+ <td>
156
+ <ul>
157
+ <li>
158
+ <input type="checkbox" name="breeze-admin-cache" id="breeze-admin-cache"
159
+ value="0" <?php checked($basic['breeze-disable-admin'], '0') ?>/>
160
+ <label class="breeze_tool_tip" for="breeze-admin-cache">
161
+ <?php _e('Enable cache for WP standard user roles: Administrator, Editor, Author, Contributor.', 'breeze') ?>
162
+
163
+ </label>
164
+ <br/>
165
+ <span>
166
+ <b><?php esc_html_e( 'Note', 'breeze' ); ?>:&nbsp;</b>
167
+ <span style="color: #ff0000"><?php echo esc_html__( 'This option might not work properly with some page builders.', 'breeze' ) ?></span>
168
+ </span>
169
+ </li>
170
+ </ul>
171
+ </td>
172
+ </tr>
173
  </table>
views/tabs/varnish.php CHANGED
@@ -2,7 +2,7 @@
2
  defined('ABSPATH') or die;
3
 
4
  $varnish = breeze_get_option( 'varnish_cache', true );
5
- $check_varnish = Breeze_Admin::check_varnish();
6
  ?>
7
  <div class="breeze-top-notice">
8
  <p class="breeze_tool_tip"><?php _e('By default Varnish is enabled on all WordPress websites hosted on Cloudways.','breeze')?></p>
2
  defined('ABSPATH') or die;
3
 
4
  $varnish = breeze_get_option( 'varnish_cache', true );
5
+ $check_varnish = is_varnish_cache_started();
6
  ?>
7
  <div class="breeze-top-notice">
8
  <p class="breeze_tool_tip"><?php _e('By default Varnish is enabled on all WordPress websites hosted on Cloudways.','breeze')?></p>