W3 Total Cache - Version 2.1.0

Version Description

  • Feature: Added a Feature Showcase to highlight new and existing features
  • Update: Consolidated cache groups settings pages
  • Update: Replaced deprecated jQuery method for WordPress 5.6
  • Fix: PHP warnings for sprintf placeholders in PHP 8
  • Fix: PHP deprecated warnings in PHP 8
  • Fix: Browser Cache Quick Reference Chart link
  • Fix: Bad nonce in help
  • Fix: Google Drive CDN JavaScript
Download this release

Release Info

Developer joemoto
Plugin Icon 128x128 W3 Total Cache
Version 2.1.0
Comparing to
See all releases

Code changes from version 2.0.1 to 2.1.0

Files changed (50) hide show
  1. BrowserCache_Page.php +2 -9
  2. CacheGroups_Plugin_Admin.php +274 -0
  3. CacheGroups_Plugin_Admin_View.js +324 -0
  4. CacheGroups_Plugin_Admin_View.php +345 -0
  5. Cache_Redis.php +6 -1
  6. Cdn_GoogleDrive_Page.php +11 -8
  7. Cdn_GoogleDrive_Page_View.js +2 -2
  8. Cdnfsd_Plugin_Admin.php +0 -3
  9. DbCache_WpdbInjection_QueryCaching.php +16 -10
  10. FeatureShowcase_Plugin_Admin.php +398 -0
  11. FeatureShowcase_Plugin_Admin_View.php +102 -0
  12. Generic_AdminActions_Default.php +0 -152
  13. Generic_AdminNotes.php +10 -3
  14. Generic_Plugin.php +7 -0
  15. Generic_Plugin_Admin.php +35 -9
  16. Mobile_Page_ReferrerGroups.php +0 -28
  17. Mobile_Page_UserAgentGroups.php +0 -45
  18. ObjectCache_WpObjectCache_Regular.php +7 -4
  19. PageSpeed_Plugin_Widget.php +1 -1
  20. PgCache_ContentGrabber.php +4 -2
  21. PgCache_Page_CookieGroups.php +0 -78
  22. PgCache_Page_CookieGroups_View.js +0 -96
  23. PgCache_Page_CookieGroups_View.php +0 -112
  24. PgCache_Plugin_Admin.php +10 -29
  25. Root_AdminMenu.php +218 -176
  26. Root_Loader.php +1 -0
  27. SetupGuide_Plugin_Admin.php +21 -4
  28. Util_PageUrls.php +8 -5
  29. inc/options/common/header.php +4 -13
  30. inc/options/install.php +1 -1
  31. inc/options/mobile.php +0 -130
  32. inc/options/referrer.php +0 -92
  33. inc/wizard/template.php +33 -10
  34. lib/CSSTidy/class.csstidy.php +209 -142
  35. lib/CSSTidy/class.csstidy_optimise.php +390 -46
  36. lib/CSSTidy/class.csstidy_print.php +45 -11
  37. lib/CSSTidy/data.inc.php +20 -17
  38. lib/Minify/Minify/ImportProcessor.php +1 -1
  39. pub/css/feature-showcase.css +167 -0
  40. pub/css/options.css +9 -4
  41. pub/css/setup-guide.css +0 -1
  42. pub/css/wizard.css +3 -3
  43. pub/js/feature-counter.js +46 -0
  44. pub/js/jquery.masonry.min.js +1 -1
  45. pub/js/options.js +2 -222
  46. pub/js/setup-guide.js +14 -5
  47. pub/js/wizard.js +6 -0
  48. readme.txt +12 -2
  49. w3-total-cache-api.php +1 -1
  50. w3-total-cache.php +2 -2
BrowserCache_Page.php CHANGED
@@ -1,27 +1,20 @@
1
  <?php
2
  namespace W3TC;
3
 
4
-
5
-
6
  class BrowserCache_Page extends Base_Page_Settings {
7
  protected $_page = 'w3tc_browsercache';
8
 
9
-
10
- static public function w3tc_ajax() {
11
  add_action( 'w3tc_ajax_browsercache_quick_reference', array(
12
  '\W3TC\BrowserCache_Page',
13
  'w3tc_ajax_browsercache_quick_reference' ) );
14
  }
15
 
16
-
17
-
18
- public function w3tc_ajax_browsercache_quick_reference() {
19
  include W3TC_DIR . '/BrowserCache_Page_View_QuickReference.php';
20
  exit();
21
  }
22
 
23
-
24
-
25
  function view() {
26
  $browsercache_enabled = $this->_config->get_boolean( 'browsercache.enabled' );
27
  $browsercache_last_modified = ( $this->_config->get_boolean( 'browsercache.cssjs.last_modified' ) && $this->_config->get_boolean( 'browsercache.html.last_modified' ) && $this->_config->get_boolean( 'browsercache.other.last_modified' ) );
1
  <?php
2
  namespace W3TC;
3
 
 
 
4
  class BrowserCache_Page extends Base_Page_Settings {
5
  protected $_page = 'w3tc_browsercache';
6
 
7
+ public static function w3tc_ajax() {
 
8
  add_action( 'w3tc_ajax_browsercache_quick_reference', array(
9
  '\W3TC\BrowserCache_Page',
10
  'w3tc_ajax_browsercache_quick_reference' ) );
11
  }
12
 
13
+ public static function w3tc_ajax_browsercache_quick_reference() {
 
 
14
  include W3TC_DIR . '/BrowserCache_Page_View_QuickReference.php';
15
  exit();
16
  }
17
 
 
 
18
  function view() {
19
  $browsercache_enabled = $this->_config->get_boolean( 'browsercache.enabled' );
20
  $browsercache_last_modified = ( $this->_config->get_boolean( 'browsercache.cssjs.last_modified' ) && $this->_config->get_boolean( 'browsercache.html.last_modified' ) && $this->_config->get_boolean( 'browsercache.other.last_modified' ) );
CacheGroups_Plugin_Admin.php ADDED
@@ -0,0 +1,274 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * File: CacheGroups_Plugin_Admin.php
4
+ *
5
+ * @since 2.1.0
6
+ *
7
+ * @package W3TC
8
+ */
9
+
10
+ namespace W3TC;
11
+
12
+ /**
13
+ * Class: CacheGroups_Plugin_Admin
14
+ *
15
+ * @since 2.1.0
16
+ */
17
+ class CacheGroups_Plugin_Admin extends Base_Page_Settings {
18
+ /**
19
+ * Current page.
20
+ *
21
+ * @var string
22
+ */
23
+ protected $_page = 'w3tc_cachegroups'; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
24
+
25
+ /**
26
+ * Cache groups settings view.
27
+ *
28
+ * @since 2.1.0
29
+ */
30
+ public function view() {
31
+ $c = Dispatcher::config();
32
+
33
+ // Header.
34
+ require W3TC_INC_DIR . '/options/common/header.php';
35
+
36
+ // User agent groups.
37
+ $useragent_groups = array(
38
+ 'value' => $c->get_array( 'mobile.rgroups' ),
39
+ 'disabled' => $c->is_sealed( 'mobile.rgroups' ),
40
+ 'description' =>
41
+ '<li>' .
42
+ __(
43
+ 'Enabling even a single user agent group will set a cookie called "w3tc_referrer." It is used to ensure a consistent user experience across page views. Make sure any reverse proxy servers etc respect this cookie for proper operation.',
44
+ 'w3-total-cache'
45
+ ) .
46
+ '</li>' .
47
+ '<li>' .
48
+ __(
49
+ 'Per the above, make sure that visitors are notified about the cookie as per any regulations in your market.',
50
+ 'w3-total-cache'
51
+ ) .
52
+ '</li>',
53
+ );
54
+
55
+ $useragent_groups = apply_filters( 'w3tc_ui_config_item_mobile.rgroups', $useragent_groups ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
56
+ $w3_mobile = Dispatcher::component( 'Mobile_UserAgent' );
57
+ $useragent_themes = $w3_mobile->get_themes();
58
+
59
+ // Referrer groups.
60
+ $referrer_groups = $this->_config->get_array( 'referrer.rgroups' );
61
+ $w3_referrer = Dispatcher::component( 'Mobile_Referrer' );
62
+ $referrer_themes = $w3_referrer->get_themes();
63
+
64
+ // Cookie groups.
65
+ $cookie_groups = array(
66
+ 'value' => $c->get_array( 'pgcache.cookiegroups.groups' ),
67
+ 'disabled' => $c->is_sealed( 'pgcache.cookiegroups.groups' ),
68
+ );
69
+ $cookie_groups = apply_filters( 'w3tc_ui_config_item_pgcache.cookiegroups.groups', $cookie_groups ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
70
+
71
+ // Load view.
72
+ require W3TC_DIR . '/CacheGroups_Plugin_Admin_View.php';
73
+
74
+ // Footer.
75
+ require W3TC_INC_DIR . '/options/common/footer.php';
76
+ }
77
+
78
+ /**
79
+ * Save settings.
80
+ *
81
+ * @since 2.1.0
82
+ *
83
+ * @static
84
+ *
85
+ * @param array $config Config.
86
+ */
87
+ public static function w3tc_config_ui_save_w3tc_cachegroups( $config ) {
88
+ // * User agent groups.
89
+ $useragent_groups = Util_Request::get_array( 'mobile_groups' );
90
+ $mobile_groups = array();
91
+ $cached_mobile_groups = array();
92
+
93
+ foreach ( $useragent_groups as $group => $group_config ) {
94
+ $group = strtolower( $group );
95
+ $group = preg_replace( '~[^0-9a-z_]+~', '_', $group );
96
+ $group = trim( $group, '_' );
97
+
98
+ if ( $group ) {
99
+ $theme = isset( $group_config['theme'] ) ? trim( $group_config['theme'] ) : 'default';
100
+ $enabled = isset( $group_config['enabled'] ) ? (bool) $group_config['enabled'] : true;
101
+ $redirect = isset( $group_config['redirect'] ) ? trim( $group_config['redirect'] ) : '';
102
+ $agents = isset( $group_config['agents'] ) ? explode( "\r\n", trim( $group_config['agents'] ) ) : array();
103
+
104
+ $mobile_groups[ $group ] = array(
105
+ 'theme' => $theme,
106
+ 'enabled' => $enabled,
107
+ 'redirect' => $redirect,
108
+ 'agents' => $agents,
109
+ );
110
+
111
+ $cached_mobile_groups[ $group ] = $agents;
112
+ }
113
+ }
114
+
115
+ // Allow plugins modify WPSC mobile groups.
116
+ $cached_mobile_groups = apply_filters( 'cached_mobile_groups', $cached_mobile_groups );
117
+
118
+ // Merge existent and delete removed groups.
119
+ foreach ( $mobile_groups as $group => $group_config ) {
120
+ if ( isset( $cached_mobile_groups[ $group ] ) ) {
121
+ $mobile_groups[ $group ]['agents'] = (array) $cached_mobile_groups[ $group ];
122
+ } else {
123
+ unset( $mobile_groups[ $group ] );
124
+ }
125
+ }
126
+
127
+ // Add new groups.
128
+ foreach ( $cached_mobile_groups as $group => $agents ) {
129
+ if ( ! isset( $mobile_groups[ $group ] ) ) {
130
+ $mobile_groups[ $group ] = array(
131
+ 'theme' => '',
132
+ 'enabled' => true,
133
+ 'redirect' => '',
134
+ 'agents' => $agents,
135
+ );
136
+ }
137
+ }
138
+
139
+ // Allow plugins modify W3TC mobile groups.
140
+ $mobile_groups = apply_filters( 'w3tc_mobile_groups', $mobile_groups );
141
+
142
+ // Sanitize mobile groups.
143
+ foreach ( $mobile_groups as $group => $group_config ) {
144
+ $mobile_groups[ $group ] = array_merge(
145
+ array(
146
+ 'theme' => '',
147
+ 'enabled' => true,
148
+ 'redirect' => '',
149
+ 'agents' => array(),
150
+ ),
151
+ $group_config
152
+ );
153
+
154
+ $mobile_groups[ $group ]['agents'] = array_unique( $mobile_groups[ $group ]['agents'] );
155
+ $mobile_groups[ $group ]['agents'] = array_map( 'strtolower', $mobile_groups[ $group ]['agents'] );
156
+
157
+ sort( $mobile_groups[ $group ]['agents'] );
158
+ }
159
+
160
+ $enable_mobile = false;
161
+
162
+ foreach ( $mobile_groups as $group_config ) {
163
+ if ( $group_config['enabled'] ) {
164
+ $enable_mobile = true;
165
+ break;
166
+ }
167
+ }
168
+
169
+ $config->set( 'mobile.enabled', $enable_mobile );
170
+ $config->set( 'mobile.rgroups', $mobile_groups );
171
+
172
+ // * Referrer groups.
173
+ $ref_groups = Util_Request::get_array( 'referrer_groups' );
174
+
175
+ $referrer_groups = array();
176
+
177
+ foreach ( $ref_groups as $group => $group_config ) {
178
+ $group = strtolower( $group );
179
+ $group = preg_replace( '~[^0-9a-z_]+~', '_', $group );
180
+ $group = trim( $group, '_' );
181
+
182
+ if ( $group ) {
183
+ $theme = isset( $group_config['theme'] ) ? trim( $group_config['theme'] ) : 'default';
184
+ $enabled = isset( $group_config['enabled'] ) ? (bool) $group_config['enabled'] : true;
185
+ $redirect = isset( $group_config['redirect'] ) ? trim( $group_config['redirect'] ) : '';
186
+ $referrers = isset( $group_config['referrers'] ) ? explode( "\r\n", trim( $group_config['referrers'] ) ) : array();
187
+
188
+ $referrer_groups[ $group ] = array(
189
+ 'theme' => $theme,
190
+ 'enabled' => $enabled,
191
+ 'redirect' => $redirect,
192
+ 'referrers' => $referrers,
193
+ );
194
+ }
195
+ }
196
+
197
+ // Allow plugins modify W3TC referrer groups.
198
+ $referrer_groups = apply_filters( 'w3tc_referrer_groups', $referrer_groups );
199
+
200
+ // Sanitize mobile groups.
201
+ foreach ( $referrer_groups as $group => $group_config ) {
202
+ $referrer_groups[ $group ] = array_merge(
203
+ array(
204
+ 'theme' => '',
205
+ 'enabled' => true,
206
+ 'redirect' => '',
207
+ 'referrers' => array(),
208
+ ),
209
+ $group_config
210
+ );
211
+
212
+ $referrer_groups[ $group ]['referrers'] = array_unique( $referrer_groups[ $group ]['referrers'] );
213
+ $referrer_groups[ $group ]['referrers'] = array_map( 'strtolower', $referrer_groups[ $group ]['referrers'] );
214
+
215
+ sort( $referrer_groups[ $group ]['referrers'] );
216
+ }
217
+
218
+ $enable_referrer = false;
219
+
220
+ foreach ( $referrer_groups as $group_config ) {
221
+ if ( $group_config['enabled'] ) {
222
+ $enable_referrer = true;
223
+ break;
224
+ }
225
+ }
226
+
227
+ $config->set( 'referrer.enabled', $enable_referrer );
228
+ $config->set( 'referrer.rgroups', $referrer_groups );
229
+
230
+ // * Cookie groups.
231
+ $mobile_groups = array();
232
+ $cached_mobile_groups = array();
233
+ $cookie_groups = Util_Request::get_array( 'cookiegroups' );
234
+
235
+ foreach ( $cookie_groups as $group => $group_config ) {
236
+ $group = strtolower( $group );
237
+ $group = preg_replace( '~[^0-9a-z_]+~', '_', $group );
238
+ $group = trim( $group, '_' );
239
+
240
+ if ( $group ) {
241
+ $enabled = isset( $group_config['enabled'] ) ?
242
+ (bool) $group_config['enabled'] : false;
243
+ $cache = isset( $group_config['cache'] ) ?
244
+ (bool) $group_config['cache'] : false;
245
+ $cookies = isset( $group_config['cookies'] ) ?
246
+ explode( "\r\n", trim( $group_config['cookies'] ) ) : array();
247
+ $cookies = array_unique( $cookies );
248
+
249
+ sort( $cookies );
250
+
251
+ $cookiegroups[ $group ] = array(
252
+ 'enabled' => $enabled,
253
+ 'cache' => $cache,
254
+ 'cookies' => $cookies,
255
+ );
256
+ }
257
+ }
258
+
259
+ // Allow plugins modify W3TC cookie groups.
260
+ $cookiegroups = apply_filters( 'w3tc_pgcache_cookiegroups', $cookiegroups );
261
+
262
+ $enabled = false;
263
+
264
+ foreach ( $cookiegroups as $group_config ) {
265
+ if ( $group_config['enabled'] ) {
266
+ $enabled = true;
267
+ break;
268
+ }
269
+ }
270
+
271
+ $config->set( 'pgcache.cookiegroups.enabled', $enabled );
272
+ $config->set( 'pgcache.cookiegroups.groups', $cookiegroups );
273
+ }
274
+ }
CacheGroups_Plugin_Admin_View.js ADDED
@@ -0,0 +1,324 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * File: CacheGroups_Plugin_Admin_View.js
3
+ *
4
+ * @since 2.1.0
5
+ *
6
+ * @package W3TC
7
+ */
8
+
9
+ jQuery(function() {
10
+
11
+ // User agent groups.
12
+
13
+ jQuery('#mobile_form').on( 'submit', function() {
14
+ var error = false;
15
+
16
+ jQuery('#mobile_groups li').each(function() {
17
+ if (jQuery(this).find(':checked').length) {
18
+ var group = jQuery(this).find('.mobile_group').text();
19
+ var theme = jQuery(this).find(':selected').val();
20
+ var redirect = jQuery(this).find('input[type=text]').val();
21
+ var agents = jQuery.trim(jQuery(this).find('textarea').val()).split("\n");
22
+
23
+ jQuery('#mobile_groups li').each(function() {
24
+ if (jQuery(this).find(':checked').length) {
25
+ var compare_group = jQuery(this).find('.mobile_group').text();
26
+ if (compare_group != group) {
27
+ var compare_theme = jQuery(this).find(':selected').val();
28
+ var compare_redirect = jQuery(this).find('input[type=text]').val();
29
+ var compare_agents = jQuery.trim(jQuery(this).find('textarea').val()).split("\n");
30
+
31
+ if (compare_redirect == '' && redirect == '' && compare_theme != '' && compare_theme == theme) {
32
+ alert('Duplicate theme "' + compare_theme + '" found in the group "' + group + '".');
33
+ error = true;
34
+ return false;
35
+ }
36
+
37
+ if (compare_redirect != '' && compare_redirect == redirect) {
38
+ alert('Duplicate redirect "' + compare_redirect + '" found in the group "' + group + '".');
39
+ error = true;
40
+ return false;
41
+ }
42
+
43
+ jQuery.each(compare_agents, function(index, value) {
44
+ if (jQuery.inArray(value, agents) != -1) {
45
+ alert('Duplicate stem "' + value + '" found in the group "' + compare_group + '".');
46
+ error = true;
47
+ return false;
48
+ }
49
+ });
50
+ }
51
+ }
52
+ });
53
+
54
+ if (error) {
55
+ return false;
56
+ }
57
+ }
58
+ });
59
+
60
+ if (error) {
61
+ return false;
62
+ }
63
+ });
64
+
65
+ jQuery('#mobile_add').on( 'click', function() {
66
+ var group = prompt('Enter group name (only "0-9", "a-z", "_" symbols are allowed).');
67
+
68
+ if (group !== null) {
69
+ group = group.toLowerCase();
70
+ group = group.replace(/[^0-9a-z_]+/g, '_');
71
+ group = group.replace(/^_+/, '');
72
+ group = group.replace(/_+$/, '');
73
+
74
+ if (group) {
75
+ var exists = false;
76
+
77
+ jQuery('.mobile_group').each(function() {
78
+ if (jQuery(this).html() == group) {
79
+ alert('Group already exists!');
80
+ exists = true;
81
+ return false;
82
+ }
83
+ });
84
+
85
+ if (!exists) {
86
+ var li = jQuery('<li id="mobile_group_' + group + '"><table class="form-table"><tr><th>Group name:</th><td><span class="mobile_group_number">' + (jQuery('#mobile_groups li').length + 1) + '.</span> <span class="mobile_group">' + group + '</span> <input type="button" class="button mobile_delete" value="Delete group" /></td></tr><tr><th><label for="mobile_groups_' + group + '_enabled">Enabled:</label></th><td><input type="hidden" name="mobile_groups[' + group + '][enabled]" value="0" /><input id="mobile_groups_' + group + '_enabled" type="checkbox" name="mobile_groups[' + group + '][enabled]" value="1" checked="checked" /></td></tr><tr><th><label for="mobile_groups_' + group + '_theme">Theme:</label></th><td><select id="mobile_groups_' + group + '_theme" name="mobile_groups[' + group + '][theme]"><option value="">-- Pass-through --</option></select><p class="description">Assign this group of user agents to a specific them. Leaving this option "Active Theme" allows any plugins you have (e.g. mobile plugins) to properly handle requests for these user agents. If the "redirect users to" field is not empty, this setting is ignored.</p></td></tr><tr><th><label for="mobile_groups_' + group + '_redirect">Redirect users to:</label></th><td><input id="mobile_groups_' + group + '_redirect" type="text" name="mobile_groups[' + group + '][redirect]" value="" size="60" /><p class="description">A 302 redirect is used to send this group of users to another hostname (domain); recommended if a 3rd party service provides a mobile version of your site.</p></td></tr><tr><th><label for="mobile_groups_' + group + '_agents">User agents:</label></th><td><textarea id="mobile_groups_' + group + '_agents" name="mobile_groups[' + group + '][agents]" rows="10" cols="50"></textarea><p class="description">Specify the user agents for this group.</p></td></tr></table></li>');
87
+ var select = li.find('select');
88
+
89
+ jQuery.each(mobile_themes, function(index, value) {
90
+ select.append(jQuery('<option />').val(index).html(value));
91
+ });
92
+
93
+ jQuery('#mobile_groups').append(li);
94
+ w3tc_mobile_groups_clear();
95
+ window.location.hash = '#mobile_group_' + group;
96
+ li.find('textarea').focus();
97
+ }
98
+ } else {
99
+ alert('Empty group name!');
100
+ }
101
+ }
102
+ });
103
+
104
+ jQuery('.mobile_delete').on('click', function () {
105
+ if (confirm('Are you sure want to delete this group?')) {
106
+ jQuery(this).parents('#mobile_groups li').remove();
107
+ w3tc_mobile_groups_clear();
108
+ w3tc_beforeupload_bind();
109
+ }
110
+ });
111
+
112
+ w3tc_mobile_groups_clear();
113
+
114
+ // Referrer groups.
115
+
116
+ jQuery('#referrer_form').on( 'submit', function() {
117
+ var error = false;
118
+
119
+ jQuery('#referrer_groups li').each(function() {
120
+ if (jQuery(this).find(':checked').length) {
121
+ var group = jQuery(this).find('.referrer_group').text();
122
+ var theme = jQuery(this).find(':selected').val();
123
+ var redirect = jQuery(this).find('input[type=text]').val();
124
+ var agents = jQuery.trim(jQuery(this).find('textarea').val()).split("\n");
125
+
126
+ jQuery('#referrer_groups li').each(function() {
127
+ if (jQuery(this).find(':checked').length) {
128
+ var compare_group = jQuery(this).find('.referrer_group').text();
129
+ if (compare_group != group) {
130
+ var compare_theme = jQuery(this).find(':selected').val();
131
+ var compare_redirect = jQuery(this).find('input[type=text]').val();
132
+ var compare_agents = jQuery.trim(jQuery(this).find('textarea').val()).split("\n");
133
+
134
+ if (compare_redirect == '' && redirect == '' && compare_theme != '' && compare_theme == theme) {
135
+ alert('Duplicate theme "' + compare_theme + '" found in the group "' + group + '".');
136
+ error = true;
137
+ return false;
138
+ }
139
+
140
+ if (compare_redirect != '' && compare_redirect == redirect) {
141
+ alert('Duplicate redirect "' + compare_redirect + '" found in the group "' + group + '".');
142
+ error = true;
143
+ return false;
144
+ }
145
+
146
+ jQuery.each(compare_agents, function(index, value) {
147
+ if (jQuery.inArray(value, agents) != -1) {
148
+ alert('Duplicate stem "' + value + '" found in the group "' + compare_group + '".');
149
+ error = true;
150
+ return false;
151
+ }
152
+ });
153
+ }
154
+ }
155
+ });
156
+
157
+ if (error) {
158
+ return false;
159
+ }
160
+ }
161
+ });
162
+
163
+ if (error) {
164
+ return false;
165
+ }
166
+ });
167
+
168
+ jQuery('#referrer_add').on( 'click', function() {
169
+ var group = prompt('Enter group name (only "0-9", "a-z", "_" symbols are allowed).');
170
+
171
+ if (group !== null) {
172
+ group = group.toLowerCase();
173
+ group = group.replace(/[^0-9a-z_]+/g, '_');
174
+ group = group.replace(/^_+/, '');
175
+ group = group.replace(/_+$/, '');
176
+
177
+ if (group) {
178
+ var exists = false;
179
+
180
+ jQuery('.referrer_group').each(function() {
181
+ if (jQuery(this).html() == group) {
182
+ alert('Group already exists!');
183
+ exists = true;
184
+ return false;
185
+ }
186
+ });
187
+
188
+ if (!exists) {
189
+ var li = jQuery('<li id="referrer_group_' + group + '"><table class="form-table"><tr><th>Group name:</th><td><span class="referrer_group_number">' + (jQuery('#referrer_groups li').length + 1) + '.</span> <span class="referrer_group">' + group + '</span> <input type="button" class="button referrer_delete" value="Delete group" /></td></tr><tr><th><label for="referrer_groups_' + group + '_enabled">Enabled:</label></th><td><input type="hidden" name="referrer_groups[' + group + '][enabled]" value="0" /><input id="referrer_groups_' + group + '_enabled" type="checkbox" name="referrer_groups[' + group + '][enabled]" value="1" checked="checked" /></td></tr><tr><th><label for="referrer_groups_' + group + '_theme">Theme:</label></th><td><select id="referrer_groups_' + group + '_theme" name="referrer_groups[' + group + '][theme]"><option value="">-- Pass-through --</option></select><p class="description">Assign this group of referrers to a specific them. Leaving this option "Active Theme" allows any plugins you have (e.g. referrer plugins) to properly handle requests for these referrers. If the "redirect users to" field is not empty, this setting is ignored.</p></td></tr><tr><th><label for="referrer_groups_' + group + '_redirect">Redirect users to:</label></th><td><input id="referrer_groups_' + group + '_redirect" type="text" name="referrer_groups[' + group + '][redirect]" value="" size="60" /><p class="description">A 302 redirect is used to send this group of users to another hostname (domain); recommended if a 3rd party service provides a referrer version of your site.</p></td></tr><tr><th><label for="referrer_groups_' + group + '_referrers">Referrers:</label></th><td><textarea id="referrer_groups_' + group + '_referrers" name="referrer_groups[' + group + '][referrers]" rows="10" cols="50"></textarea><p class="description">Specify the referrers for this group.</p></td></tr></table></li>');
190
+ var select = li.find('select');
191
+
192
+ jQuery.each(referrer_themes, function(index, value) {
193
+ select.append(jQuery('<option />').val(index).html(value));
194
+ });
195
+
196
+ jQuery('#referrer_groups').append(li);
197
+ w3tc_referrer_groups_clear();
198
+ window.location.hash = '#referrer_group_' + group;
199
+ li.find('textarea').focus();
200
+ }
201
+ } else {
202
+ alert('Empty group name!');
203
+ }
204
+ }
205
+ });
206
+
207
+ jQuery('.referrer_delete').on('click', function () {
208
+ if (confirm('Are you sure want to delete this group?')) {
209
+ jQuery(this).parents('#referrer_groups li').remove();
210
+ w3tc_referrer_groups_clear();
211
+ w3tc_beforeupload_bind();
212
+ }
213
+ });
214
+
215
+ w3tc_referrer_groups_clear();
216
+
217
+ // Cookie groups.
218
+
219
+ jQuery( '#w3tc_cookiegroup_add' ).on( 'click', function() {
220
+ var group = prompt('Enter group name (only "0-9", "a-z", "_" symbols are allowed).');
221
+
222
+ if (group !== null) {
223
+ group = group.toLowerCase();
224
+ group = group.replace(/[^0-9a-z_]+/g, '_');
225
+ group = group.replace(/^_+/, '');
226
+ group = group.replace(/_+$/, '');
227
+
228
+ if (group) {
229
+ var exists = false;
230
+
231
+ jQuery('.cookiegroup_name').each(function() {
232
+ if (jQuery(this).html() == group) {
233
+ alert('Group already exists!');
234
+ exists = true;
235
+ return false;
236
+ }
237
+ });
238
+
239
+ if (!exists) {
240
+ var li = jQuery('<li id="cookiegroup_' + group + '">' +
241
+ '<table class="form-table">' +
242
+ '<tr>' +
243
+ '<th>Group name:</th>' +
244
+ '<td><span class="cookiegroup_number">' + (jQuery('#cookiegroups li').length + 1) + '.</span> ' +
245
+ '<span class="cookiegroup_name">' + group + '</span> ' +
246
+ '<input type="button" class="button cookiegroup_delete" value="Delete group" /></td>' +
247
+ '</tr>' +
248
+ '<tr>' +
249
+ '<th><label for="cookiegroup_' + group + '_enabled">Enabled:</label></th>' +
250
+ '<td>' +
251
+ '<input id="cookiegroup_' + group + '_enabled" type="checkbox" name="cookiegroups[' +
252
+ group + '][enabled]" value="1" checked="checked" /></td>' +
253
+ '</tr>' +
254
+ '<tr>' +
255
+ '<th><label for="cookiegroup_' + group + '_cache">Cache:</label></th>' +
256
+ '<td>' +
257
+ '<input id="cookiegroup_' + group + '_cache" type="checkbox" name="cookiegroups[' +
258
+ group + '][cache]" value="1" checked="checked" /></td></tr>' +
259
+ '<tr>' +
260
+ '<th><label for="cookiegroups_' + group + '_cookies">Cookies:</label></th>' +
261
+ '<td><textarea id="cookiegroups_' + group + '_cookies" name="cookiegroups[' +
262
+ group + '][cookies]" rows="10" cols="50"></textarea>' +
263
+ '<p class="description">Specify the cookies for this group. Values like \'cookie\', \'cookie=value\', and cookie[a-z]+=value[a-z]+are supported. Remember to escape special characters like spaces, dots or dashes with a backslash. Regular expressions are also supported.</p></td></tr>' +
264
+ '</table></li>');
265
+ var select = li.find('select');
266
+
267
+ jQuery('#cookiegroups').append(li);
268
+ w3tc_cookiegroups_clear();
269
+ window.location.hash = '#cookiegroup_' + group;
270
+ li.find('textarea').focus();
271
+ }
272
+ } else {
273
+ alert('Empty group name!');
274
+ }
275
+ }
276
+ });
277
+
278
+ jQuery('.w3tc_cookiegroup_delete').on( 'click', function () {
279
+ if (confirm('Are you sure want to delete this group?')) {
280
+ jQuery(this).parents('#cookiegroups li').remove();
281
+ w3tc_cookiegroups_clear();
282
+ w3tc_beforeupload_bind();
283
+ }
284
+ });
285
+
286
+ w3tc_cookiegroups_clear();
287
+
288
+ // Add sortable.
289
+ if (jQuery.ui && jQuery.ui.sortable) {
290
+ jQuery('#cookiegroups').sortable({
291
+ axis: 'y',
292
+ stop: function() {
293
+ jQuery('#cookiegroups').find('.cookiegroup_number').each(function(index) {
294
+ jQuery(this).html((index + 1) + '.');
295
+ });
296
+ }
297
+ });
298
+ }
299
+
300
+ });
301
+
302
+ function w3tc_mobile_groups_clear() {
303
+ if (!jQuery('#mobile_groups li').length) {
304
+ jQuery('#mobile_groups_empty').show();
305
+ } else {
306
+ jQuery('#mobile_groups_empty').hide();
307
+ }
308
+ }
309
+
310
+ function w3tc_referrer_groups_clear() {
311
+ if (!jQuery('#referrer_groups li').length) {
312
+ jQuery('#referrer_groups_empty').show();
313
+ } else {
314
+ jQuery('#referrer_groups_empty').hide();
315
+ }
316
+ }
317
+
318
+ function w3tc_cookiegroups_clear() {
319
+ if (!jQuery('#cookiegroups li').length) {
320
+ jQuery('#cookiegroups_empty').show();
321
+ } else {
322
+ jQuery('#cookiegroups_empty').hide();
323
+ }
324
+ }
CacheGroups_Plugin_Admin_View.php ADDED
@@ -0,0 +1,345 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * File: CacheGroups_Plugin_Admin_View.php
4
+ *
5
+ * @since 2.1.0
6
+ *
7
+ * @package W3TC
8
+ *
9
+ * @uses $useragent_groups
10
+ * @uses $useragent_themes
11
+ * @uses $referrer_groups
12
+ * @uses $referrer_themes
13
+ * @uses $cookie_groups
14
+ */
15
+
16
+ namespace W3TC;
17
+
18
+ if ( ! defined( 'W3TC' ) ) {
19
+ die();
20
+ }
21
+ ?>
22
+
23
+ <form id="cachegroups_form" action="admin.php?page=<?php echo esc_attr( $this->_page ); ?>" method="post">
24
+
25
+ <!-- User Agenet Groups -->
26
+
27
+ <script type="text/javascript">/*<![CDATA[*/
28
+ var mobile_themes = {};
29
+ <?php foreach ( $useragent_themes as $theme_key => $theme_name ) : ?>
30
+ mobile_themes['<?php echo esc_attr( addslashes( $theme_key ) ); ?>'] = '<?php echo esc_html( addslashes( $theme_name ) ); ?>';
31
+ <?php endforeach; ?>
32
+ /*]]>*/</script>
33
+
34
+ <div class="metabox-holder">
35
+ <?php Util_Ui::postbox_header( __( 'Manage User Agent Groups', 'w3-total-cache' ), '', 'manage-uag' ); ?>
36
+ <p>
37
+ <input id="mobile_add" type="button" class="button"
38
+ <?php disabled( $useragent_groups['disabled'] ); ?>
39
+ value="<?php esc_html_e( 'Create a group', 'w3-total-cache' ); ?>" />
40
+ <?php esc_html_e( 'of user agents by specifying names in the user agents field. Assign a set of user agents to use a specific theme, redirect them to another domain or if an existing mobile plugin is active, create user agent groups to ensure that a unique cache is created for each user agent group. Drag and drop groups into order (if needed) to determine their priority (top -&gt; down).', 'w3-total-cache' ); ?>
41
+ </p>
42
+
43
+ <ul id="mobile_groups">
44
+ <?php
45
+ $index = 0;
46
+
47
+ foreach ( $useragent_groups['value'] as $group => $group_config ) :
48
+ $index++;
49
+ ?>
50
+ <li id="mobile_group_<?php echo esc_attr( $group ); ?>">
51
+ <table class="form-table">
52
+ <tr>
53
+ <th>
54
+ <?php esc_html_e( 'Group name:', 'w3-total-cache' ); ?>
55
+ </th>
56
+ <td>
57
+ <span class="mobile_group_number"><?php echo esc_attr( $index ); ?>.</span> <span class="mobile_group"><?php echo esc_html( $group ); // phpcs:ignore ?></span>
58
+ <input type="button" class="button mobile_delete"
59
+ value="Delete group"
60
+ <?php disabled( $useragent_groups['disabled'] ); ?> />
61
+ </td>
62
+ </tr>
63
+ <tr>
64
+ <th>
65
+ <label for="mobile_groups_<?php echo esc_attr( $group ); ?>_enabled"><?php esc_html_e( 'Enabled:', 'w3-total-cache' ); ?></label>
66
+ </th>
67
+ <td>
68
+ <input type="hidden" name="mobile_groups[<?php echo esc_attr( $group ); ?>][enabled]" value="0" />
69
+ <input id="mobile_groups_<?php echo esc_attr( $group ); ?>_enabled"
70
+ type="checkbox"
71
+ name="mobile_groups[<?php echo esc_attr( $group ); ?>][enabled]"
72
+ <?php disabled( $useragent_groups['disabled'] ); ?> value="1"
73
+ <?php checked( $group_config['enabled'], true ); ?> />
74
+ </td>
75
+ </tr>
76
+ <tr>
77
+ <th>
78
+ <label for="mobile_groups_<?php echo esc_attr( $group ); ?>_theme"><?php esc_html_e( 'Theme:', 'w3-total-cache' ); ?></label>
79
+ </th>
80
+ <td>
81
+ <select id="mobile_groups_<?php echo esc_attr( $group ); ?>_theme"
82
+ name="mobile_groups[<?php echo esc_attr( $group ); ?>][theme]"
83
+ <?php disabled( $useragent_groups['disabled'] ); ?> >
84
+ <option value="">-- Pass-through --</option>
85
+ <?php foreach ( $useragent_themes as $theme_key => $theme_name ) : ?>
86
+ <option value="<?php echo esc_attr( $theme_key ); ?>"<?php selected( $theme_key, $group_config['theme'] ); ?>><?php echo esc_html( $theme_name ); ?></option>
87
+ <?php endforeach; ?>
88
+ </select>
89
+ <p class="description">
90
+ <?php esc_html_e( 'Assign this group of user agents to a specific theme. Selecting "Pass-through" allows any plugin(s) (e.g. mobile plugins) to properly handle requests for these user agents. If the "redirect users to" field is not empty, this setting is ignored.', 'w3-total-cache' ); ?>
91
+ </p>
92
+ </td>
93
+ </tr>
94
+ <tr>
95
+ <th>
96
+ <label for="mobile_groups_<?php echo esc_attr( $group ); ?>_redirect"><?php esc_html_e( 'Redirect users to:', 'w3-total-cache' ); ?></label>
97
+ </th>
98
+ <td>
99
+ <input id="mobile_groups_<?php echo esc_attr( $group ); ?>_redirect"
100
+ type="text" name="mobile_groups[<?php echo esc_attr( $group ); ?>][redirect]"
101
+ value="<?php echo esc_attr( $group_config['redirect'] ); ?>"
102
+ <?php disabled( $useragent_groups['disabled'] ); ?>
103
+ size="60" />
104
+ <p class="description"><?php esc_html_e( 'A 302 redirect is used to send this group of users to another hostname (domain); recommended if a 3rd party service provides a mobile version of your site.', 'w3-total-cache' ); ?></p>
105
+ </td>
106
+ </tr>
107
+ <tr>
108
+ <th>
109
+ <label for="mobile_groups_<?php echo esc_attr( $group ); ?>_agents"><?php esc_html_e( 'User agents:', 'w3-total-cache' ); ?></label>
110
+ </th>
111
+ <td>
112
+ <textarea id="mobile_groups_<?php echo esc_attr( $group ); ?>_agents"
113
+ name="mobile_groups[<?php echo esc_attr( $group ); ?>][agents]"
114
+ rows="10" cols="50" <?php disabled( $useragent_groups['disabled'] ); ?>><?php echo esc_textarea( implode( "\r\n", (array) $group_config['agents'] ) ); ?></textarea>
115
+ <p class="description">
116
+ <?php esc_html_e( 'Specify the user agents for this group. Remember to escape special characters like spaces, dots or dashes with a backslash. Regular expressions are also supported.', 'w3-total-cache' ); ?>
117
+ </p>
118
+ </td>
119
+ </tr>
120
+ </table>
121
+ </li>
122
+ <?php endforeach; ?>
123
+ </ul>
124
+ <div id="mobile_groups_empty" style="display: none;"><?php esc_html_e( 'No groups added. All user agents recieve the same page and minify cache results.', 'w3-total-cache' ); ?></div>
125
+
126
+ <?php
127
+ if ( ! $useragent_groups['disabled'] ) {
128
+ Util_Ui::button_config_save( 'mobile' );
129
+ }
130
+
131
+ Util_Ui::postbox_footer();
132
+
133
+ Util_Ui::postbox_header(
134
+ __( 'Note(s):', 'w3-total-cache' ),
135
+ '',
136
+ 'notes'
137
+ );
138
+ ?>
139
+
140
+ <table class="form-table">
141
+ <tr>
142
+ <th colspan="2">
143
+ <ul>
144
+ <?php echo $useragent_groups['description']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
145
+ </ul>
146
+ </th>
147
+ </tr>
148
+ </table>
149
+ <?php Util_Ui::postbox_footer(); ?>
150
+ </div>
151
+
152
+ <!-- Referrer Groups -->
153
+
154
+ <script type="text/javascript">/*<![CDATA[*/
155
+ var referrer_themes = {};
156
+ <?php foreach ( $referrer_themes as $theme_key => $theme_name ) : ?>
157
+ referrer_themes['<?php echo esc_attr( $theme_key ); ?>'] = '<?php echo esc_html( $theme_name ); ?>';
158
+ <?php endforeach; ?>
159
+ /*]]>*/</script>
160
+
161
+ <div class="metabox-holder">
162
+ <?php Util_Ui::postbox_header( __( 'Manage Referrer Groups', 'w3-total-cache' ), '', 'manage-rg' ); ?>
163
+ <p>
164
+ <input id="referrer_add" type="button" class="button" value="<?php esc_html_e( 'Create a group', 'w3-total-cache' ); ?>" /> <?php esc_html_e( 'of referrers by specifying names in the referrers field. Assign a set of referrers to use a specific theme, redirect them to another domain, create referrer groups to ensure that a unique cache is created for each referrer group. Drag and drop groups into order (if needed) to determine their priority (top -&gt; down).', 'w3-total-cache' ); ?>
165
+ </p>
166
+
167
+ <ul id="referrer_groups">
168
+ <?php
169
+ $index = 0;
170
+
171
+ foreach ( $referrer_groups as $group => $group_config ) :
172
+ $index++;
173
+ ?>
174
+ <li id="referrer_group_<?php echo esc_attr( $group ); ?>">
175
+ <table class="form-table">
176
+ <tr>
177
+ <th>
178
+ <?php esc_html_e( 'Group name:', 'w3-total-cache' ); ?>
179
+ </th>
180
+ <td>
181
+ <span class="referrer_group_number"><?php echo esc_attr( $index ); ?>.</span> <span class="referrer_group"><?php echo esc_html( $group ); ?></span> <input type="button" class="button referrer_delete" value="<?php esc_html_e( 'Delete group', 'w3-total-cache' ); ?>" />
182
+ </td>
183
+ </tr>
184
+ <tr>
185
+ <th>
186
+ <label for="referrer_groups_<?php echo esc_attr( $group ); ?>_enabled"><?php esc_html_e( 'Enabled:', 'w3-total-cache' ); ?></label>
187
+ </th>
188
+ <td>
189
+ <input type="hidden" name="referrer_groups[<?php echo esc_attr( $group ); ?>][enabled]" value="0" />
190
+ <input id="referrer_groups_<?php echo esc_attr( $group ); ?>_enabled" type="checkbox" name="referrer_groups[<?php echo esc_attr( $group ); ?>][enabled]" value="1"<?php checked( $group_config['enabled'], true ); ?> />
191
+ </td>
192
+ </tr>
193
+ <tr>
194
+ <th>
195
+ <label for="referrer_groups_<?php echo esc_attr( $group ); ?>_theme"><?php esc_html_e( 'Theme:', 'w3-total-cache' ); ?></label>
196
+ </th>
197
+ <td>
198
+ <select id="referrer_groups_<?php echo esc_attr( $group ); ?>_theme" name="referrer_groups[<?php echo esc_attr( $group ); ?>][theme]">
199
+ <option value=""><?php esc_html_e( '-- Pass-through --', 'w3-total-cache' ); ?></option>
200
+ <?php foreach ( $referrer_themes as $theme_key => $theme_name ) : ?>
201
+ <option value="<?php echo esc_attr( $theme_key ); ?>"<?php selected( $theme_key, $group_config['theme'] ); ?>><?php echo esc_html( $theme_name ); ?></option>
202
+ <?php endforeach; ?>
203
+ </select>
204
+ <p class="description"><?php esc_html_e( 'Assign this group of referrers to a specific theme. Selecting "Pass-through" allows any plugin(s) (e.g. referrer plugins) to properly handle requests for these referrers. If the "redirect users to" field is not empty, this setting is ignored.', 'w3-total-cache' ); ?></p>
205
+ </td>
206
+ </tr>
207
+ <tr>
208
+ <th>
209
+ <label for="referrer_groups_<?php echo esc_attr( $group ); ?>_redirect"><?php esc_html_e( 'Redirect users to:', 'w3-total-cache' ); ?></label>
210
+ </th>
211
+ <td>
212
+ <input id="referrer_groups_<?php echo esc_attr( $group ); ?>_redirect" type="text" name="referrer_groups[<?php echo esc_attr( $group ); ?>][redirect]" value="<?php echo esc_attr( $group_config['redirect'] ); ?>" size="60" />
213
+ <p class="description"><?php esc_html_e( 'A 302 redirect is used to send this group of referrers to another hostname (domain).', 'w3-total-cache' ); ?></p>
214
+ </td>
215
+ </tr>
216
+ <tr>
217
+ <th>
218
+ <label for="referrer_groups_<?php echo esc_attr( $group ); ?>_referrers"><?php esc_html_e( 'Referrers:', 'w3-total-cache' ); ?></label>
219
+ </th>
220
+ <td>
221
+ <textarea id="referrer_groups_<?php echo esc_attr( $group ); ?>_referrers" name="referrer_groups[<?php echo esc_attr( $group ); ?>][referrers]" rows="10" cols="50"><?php echo esc_textarea( implode( "\r\n", (array) $group_config['referrers'] ) ); ?></textarea>
222
+ <p class="description"><?php esc_html_e( 'Specify the referrers for this group. Remember to escape special characters like spaces, dots or dashes with a backslash. Regular expressions are also supported.', 'w3-total-cache' ); ?></p>
223
+ </td>
224
+ </tr>
225
+ </table>
226
+ </li>
227
+ <?php endforeach; ?>
228
+ </ul>
229
+ <div id="referrer_groups_empty" style="display: none;"><?php esc_html_e( 'No groups added. All referrers recieve the same page and minify cache results.', 'w3-total-cache' ); ?></div>
230
+
231
+ <?php Util_Ui::button_config_save( 'referrers' ); ?>
232
+ <?php Util_Ui::postbox_footer(); ?>
233
+ </div>
234
+
235
+ <!-- Cookie Groups -->
236
+
237
+ <div class="metabox-holder">
238
+ <?php Util_Ui::postbox_header( __( 'Manage Cookie Groups', 'w3-total-cache' ), '', 'manage-cg' ); ?>
239
+ <p>
240
+ <input id="w3tc_cookiegroup_add" type="button" class="button"
241
+ <?php disabled( $cookie_groups['disabled'] ); ?>
242
+ value="<?php esc_html_e( 'Create a group', 'w3-total-cache' ); ?>" />
243
+ <?php esc_html_e( 'of Cookies by specifying names in the Cookies field. Assign a set of Cookies to ensure that a unique cache is created for each Cookie group. Drag and drop groups into order (if needed) to determine their priority (top -&gt; down).', 'w3-total-cache' ); ?>
244
+ </p>
245
+
246
+ <ul id="cookiegroups" class="w3tc_cachegroups">
247
+ <?php
248
+ $index = 0;
249
+ foreach ( $cookie_groups['value'] as $group => $group_config ) :
250
+ $index++;
251
+ ?>
252
+ <li id="cookiegroup_<?php echo esc_attr( $group ); ?>">
253
+ <table class="form-table">
254
+ <tr>
255
+ <th>
256
+ <?php esc_html_e( 'Group name:', 'w3-total-cache' ); ?>
257
+ </th>
258
+ <td>
259
+ <span class="cookiegroup_number"><?php echo esc_attr( $index ); ?>.</span>
260
+ <span class="cookiegroup_name"><?php echo htmlspecialchars( $group ); // phpcs:ignore ?></span>
261
+ <input type="button" class="button w3tc_cookiegroup_delete"
262
+ value="Delete group"
263
+ <?php disabled( $cookie_groups['disabled'] ); ?> />
264
+ </td>
265
+ </tr>
266
+ <tr>
267
+ <th>
268
+ <label for="cookiegroup_<?php echo esc_attr( $group ); ?>_enabled">
269
+ <?php esc_html_e( 'Enabled:', 'w3-total-cache' ); ?>
270
+ </label>
271
+ </th>
272
+ <td>
273
+ <input id="cookiegroup_<?php echo esc_attr( $group ); ?>_enabled"
274
+ type="checkbox"
275
+ name="cookiegroups[<?php echo esc_attr( $group ); ?>][enabled]"
276
+ <?php disabled( $cookie_groups['disabled'] ); ?> value="1"
277
+ <?php checked( $group_config['enabled'], true ); ?> />
278
+ </td>
279
+ </tr>
280
+ <tr>
281
+ <th>
282
+ <label for="cookiegroup_<?php echo esc_attr( $group ); ?>_cache">
283
+ <?php esc_html_e( 'Cache:', 'w3-total-cache' ); ?>
284
+ </label>
285
+ </th>
286
+ <td>
287
+ <input id="cookiegroup_<?php echo esc_attr( $group ); ?>_cache"
288
+ type="checkbox"
289
+ name="cookiegroups[<?php echo esc_attr( $group ); ?>][cache]"
290
+ <?php disabled( $cookie_groups['disabled'] ); ?> value="1"
291
+ <?php checked( $group_config['cache'], true ); ?> />
292
+ </td>
293
+ </tr>
294
+ <tr>
295
+ <th>
296
+ <label for="cookiegroup_<?php echo esc_attr( $group ); ?>_cookies">
297
+ <?php esc_html_e( 'Cookies:', 'w3-total-cache' ); ?>
298
+ </label>
299
+ </th>
300
+ <td>
301
+ <textarea id="cookiegroup_<?php echo esc_attr( $group ); ?>_cookies"
302
+ name="cookiegroups[<?php echo esc_attr( $group ); ?>][cookies]"
303
+ rows="10" cols="50" <?php disabled( $cookie_groups['disabled'] ); ?>><?php echo esc_textarea( implode( "\r\n", (array) $group_config['cookies'] ) ); ?></textarea>
304
+ <p class="description">
305
+ <?php esc_html_e( 'Specify the cookies for this group. Values like \'cookie\', \'cookie=value\', and cookie[a-z]+=value[a-z]+ are supported. Remember to escape special characters like spaces, dots or dashes with a backslash. Regular expressions are also supported.', 'w3-total-cache' ); ?>
306
+ </p>
307
+ </td>
308
+ </tr>
309
+ </table>
310
+ </li>
311
+ <?php endforeach; ?>
312
+ </ul>
313
+ <div id="cookiegroups_empty" style="display: none;"><?php esc_html_e( 'No groups added. All Cookies recieve the same page and minify cache results.', 'w3-total-cache' ); ?></div>
314
+
315
+ <?php
316
+ if ( ! $cookie_groups['disabled'] ) {
317
+ Util_Ui::button_config_save( 'pgcache_cookiegroups' );
318
+ }
319
+
320
+ Util_Ui::postbox_footer();
321
+
322
+ Util_Ui::postbox_header(
323
+ __( 'Note(s):', 'w3-total-cache' ),
324
+ '',
325
+ 'notes'
326
+ );
327
+ ?>
328
+ <table class="form-table">
329
+ <tr>
330
+ <th colspan="2">
331
+ <ul>
332
+ <li>
333
+ <?php esc_html_e( 'Content is cached for each group separately.', 'w3-total-cache' ); ?>
334
+ </li>
335
+ <li>
336
+ <?php esc_html_e( 'Per the above, make sure that visitors are notified about the cookie as per any regulations in your market.', 'w3-total-cache' ); ?>
337
+ </li>
338
+ </ul>
339
+ </th>
340
+ </tr>
341
+ </table>
342
+ <?php Util_Ui::postbox_footer(); ?>
343
+ </div>
344
+
345
+ </form>
Cache_Redis.php CHANGED
@@ -62,8 +62,13 @@ class Cache_Redis extends Cache_Base {
62
 
63
  $storage_key = $this->get_item_key( $key );
64
  $accessor = $this->_get_accessor( $storage_key );
65
- if ( is_null( $accessor ) )
66
  return false;
 
 
 
 
 
67
 
68
  return $accessor->setex( $storage_key, $expire, serialize( $value ) );
69
  }
62
 
63
  $storage_key = $this->get_item_key( $key );
64
  $accessor = $this->_get_accessor( $storage_key );
65
+ if ( is_null( $accessor ) ) {
66
  return false;
67
+ }
68
+
69
+ if ( ! $expire ) {
70
+ return $accessor->set( $storage_key, serialize( $value ) );
71
+ }
72
 
73
  return $accessor->setex( $storage_key, $expire, serialize( $value ) );
74
  }
Cdn_GoogleDrive_Page.php CHANGED
@@ -2,7 +2,7 @@
2
  namespace W3TC;
3
 
4
  class Cdn_GoogleDrive_Page {
5
- // called from plugin-admin
6
  static public function admin_print_scripts_w3tc_cdn() {
7
  wp_enqueue_script( 'w3tc_cdn_google_drive',
8
  plugins_url( 'Cdn_GoogleDrive_Page_View.js', W3TC_FILE ),
@@ -11,9 +11,11 @@ class Cdn_GoogleDrive_Page {
11
  $path = 'admin.php?page=w3tc_cdn';
12
  $return_url = self_admin_url( $path );
13
 
14
- wp_localize_script( 'w3tc_cdn_google_drive',
 
15
  'w3tc_cdn_google_drive_url',
16
- W3TC_GOOGLE_DRIVE_AUTHORIZE_URL . '?return_url=' . urlencode( $return_url ) );
 
17
 
18
  // it's return from google oauth
19
  if ( isset( $_GET['oa_client_id'] ) ) {
@@ -26,15 +28,16 @@ class Cdn_GoogleDrive_Page {
26
 
27
  $popup_url = self_admin_url( $path );
28
 
29
- wp_localize_script( 'w3tc_cdn_google_drive',
30
- 'w3tc_cdn_google_drive_popup_url', $popup_url );
 
 
 
31
 
32
  }
33
  }
34
 
35
-
36
-
37
- static public function w3tc_settings_cdn_boxarea_configuration() {
38
  $config = Dispatcher::config();
39
  include W3TC_DIR . '/Cdn_GoogleDrive_Page_View.php';
40
  }
2
  namespace W3TC;
3
 
4
  class Cdn_GoogleDrive_Page {
5
+ // called from plugin-admin.
6
  static public function admin_print_scripts_w3tc_cdn() {
7
  wp_enqueue_script( 'w3tc_cdn_google_drive',
8
  plugins_url( 'Cdn_GoogleDrive_Page_View.js', W3TC_FILE ),
11
  $path = 'admin.php?page=w3tc_cdn';
12
  $return_url = self_admin_url( $path );
13
 
14
+ wp_localize_script(
15
+ 'w3tc_cdn_google_drive',
16
  'w3tc_cdn_google_drive_url',
17
+ array( W3TC_GOOGLE_DRIVE_AUTHORIZE_URL . '?return_url=' . urlencode( $return_url ) )
18
+ );
19
 
20
  // it's return from google oauth
21
  if ( isset( $_GET['oa_client_id'] ) ) {
28
 
29
  $popup_url = self_admin_url( $path );
30
 
31
+ wp_localize_script(
32
+ 'w3tc_cdn_google_drive',
33
+ 'w3tc_cdn_google_drive_popup_url',
34
+ array( $popup_url )
35
+ );
36
 
37
  }
38
  }
39
 
40
+ public static function w3tc_settings_cdn_boxarea_configuration() {
 
 
41
  $config = Dispatcher::config();
42
  include W3TC_DIR . '/Cdn_GoogleDrive_Page_View.php';
43
  }
Cdn_GoogleDrive_Page_View.js CHANGED
@@ -1,6 +1,6 @@
1
  jQuery(function($) {
2
  $('.w3tc_cdn_google_drive_authorize').click(function() {
3
- window.location = w3tc_cdn_google_drive_url;
4
  });
5
 
6
  if (window.w3tc_cdn_google_drive_popup_url) {
@@ -9,7 +9,7 @@ jQuery(function($) {
9
  close: '',
10
  width: 800,
11
  height: 500,
12
- url: w3tc_cdn_google_drive_popup_url,
13
  onClose: function() {
14
  }
15
  });
1
  jQuery(function($) {
2
  $('.w3tc_cdn_google_drive_authorize').click(function() {
3
+ window.location = w3tc_cdn_google_drive_url[0];
4
  });
5
 
6
  if (window.w3tc_cdn_google_drive_popup_url) {
9
  close: '',
10
  width: 800,
11
  height: 500,
12
+ url: w3tc_cdn_google_drive_popup_url[0],
13
  onClose: function() {
14
  }
15
  });
Cdnfsd_Plugin_Admin.php CHANGED
@@ -61,9 +61,6 @@ class Cdnfsd_Plugin_Admin {
61
  add_action( 'init', array(
62
  '\W3TC\Cdnfsd_TransparentCDN_Page',
63
  'admin_test_api_parameters_transparentcdn' ) );
64
- add_action( 'w3tc_ajax', array(
65
- '\W3TC\Cdnfsd_TransparentCDN_Popup',
66
- 'w3tc_ajax' ) );
67
  add_action( 'w3tc_settings_box_cdnfsd', array(
68
  '\W3TC\Cdnfsd_TransparentCDN_Page',
69
  'w3tc_settings_box_cdnfsd' ) );
61
  add_action( 'init', array(
62
  '\W3TC\Cdnfsd_TransparentCDN_Page',
63
  'admin_test_api_parameters_transparentcdn' ) );
 
 
 
64
  add_action( 'w3tc_settings_box_cdnfsd', array(
65
  '\W3TC\Cdnfsd_TransparentCDN_Page',
66
  'w3tc_settings_box_cdnfsd' ) );
DbCache_WpdbInjection_QueryCaching.php CHANGED
@@ -721,27 +721,33 @@ class DbCache_WpdbInjection_QueryCaching extends DbCache_WpdbInjection {
721
 
722
  public function w3tc_footer_comment( $strings ) {
723
  $reject_reason = $this->get_reject_reason();
724
- $append = ( $reject_reason ? sprintf( ' (%s)', $reject_reason ) : '' );
725
 
726
  if ( $this->query_hits ) {
727
  $strings[] = sprintf(
728
- __( 'Database Caching %d/%d queries in %.3f seconds using %s%s', 'w3-total-cache' ),
729
- $this->query_hits, $this->query_total, $this->time_total,
 
 
 
730
  Cache::engine_name( $this->_config->get_string( 'dbcache.engine' ) ),
731
- $append );
 
732
  } else {
733
  $strings[] = sprintf(
734
- __( 'Database Caching using %s%s', 'w3-total-cache' ),
 
735
  Cache::engine_name( $this->_config->get_string( 'dbcache.engine' ) ),
736
- $append );
 
737
  }
738
 
739
  if ( $this->debug ) {
740
  $strings[] = '';
741
- $strings[] = "Db cache debug info:";
742
- $strings[] = sprintf( "%s%d", str_pad( 'Total queries: ', 20 ), $this->query_total );
743
- $strings[] = sprintf( "%s%d", str_pad( 'Cached queries: ', 20 ), $this->query_hits );
744
- $strings[] = sprintf( "%s%.4f", str_pad( 'Total query time: ', 20 ), $this->time_total );
745
  }
746
 
747
  if ( $this->log_filehandle ) {
721
 
722
  public function w3tc_footer_comment( $strings ) {
723
  $reject_reason = $this->get_reject_reason();
724
+ $append = empty( $reject_reason ) ? '' : sprintf( ' (%1$s)', $reject_reason );
725
 
726
  if ( $this->query_hits ) {
727
  $strings[] = sprintf(
728
+ // translators: 1: Query hits, 2: Total queries, 3: Total time, 4: Engine name, 5: Reject reason.
729
+ __( 'Database Caching %1$d/%2$d queries in %3$.3f seconds using %4$s%5$s', 'w3-total-cache' ),
730
+ $this->query_hits,
731
+ $this->query_total,
732
+ $this->time_total,
733
  Cache::engine_name( $this->_config->get_string( 'dbcache.engine' ) ),
734
+ $append
735
+ );
736
  } else {
737
  $strings[] = sprintf(
738
+ // translators: 1: Engine name, 2: Reject reason.
739
+ __( 'Database Caching using %1$s%2$s', 'w3-total-cache' ),
740
  Cache::engine_name( $this->_config->get_string( 'dbcache.engine' ) ),
741
+ $append
742
+ );
743
  }
744
 
745
  if ( $this->debug ) {
746
  $strings[] = '';
747
+ $strings[] = 'Db cache debug info:';
748
+ $strings[] = sprintf( "%1$s%2$d", str_pad( 'Total queries: ', 20 ), $this->query_total );
749
+ $strings[] = sprintf( "%1$s%2$d", str_pad( 'Cached queries: ', 20 ), $this->query_hits );
750
+ $strings[] = sprintf( "%1$s%2$.4f", str_pad( 'Total query time: ', 20 ), $this->time_total );
751
  }
752
 
753
  if ( $this->log_filehandle ) {
FeatureShowcase_Plugin_Admin.php ADDED
@@ -0,0 +1,398 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * File: FeatureShowcase_Plugin_Admin.php
4
+ *
5
+ * @since 2.1.0
6
+ *
7
+ * @package W3TC
8
+ */
9
+
10
+ namespace W3TC;
11
+
12
+ /**
13
+ * Class: FeatureShowcase_Plugin_Admin
14
+ *
15
+ * @since 2.1.0
16
+ */
17
+ class FeatureShowcase_Plugin_Admin {
18
+ /**
19
+ * Current page.
20
+ *
21
+ * @since 2.1.0
22
+ * @access private
23
+ *
24
+ * @var string
25
+ */
26
+ private $_page = 'w3tc_feature_showcase'; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
27
+
28
+ /**
29
+ * Constructor.
30
+ *
31
+ * @since 2.1.0
32
+ *
33
+ * @see Util_Request::get_string()
34
+ * @see self::enqueue_styles()
35
+ * @see self::set_config()
36
+ */
37
+ public function __construct() {
38
+ $page = Util_Request::get_string( 'page' );
39
+
40
+ if ( 'w3tc_feature_showcase' === $page ) {
41
+ add_action(
42
+ 'admin_enqueue_scripts',
43
+ array(
44
+ $this,
45
+ 'enqueue_styles',
46
+ )
47
+ );
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Run.
53
+ *
54
+ * Run by Root_Loader.
55
+ *
56
+ * @since 2.1.0
57
+ */
58
+ public function run() {
59
+ }
60
+
61
+ /**
62
+ * Render the page.
63
+ *
64
+ * @since 2.1.0
65
+ *
66
+ * @see Dispatcher::config()
67
+ * @see self::get_cards()
68
+ */
69
+ public function load() {
70
+ $config = Dispatcher::config();
71
+ $cards = self::get_cards();
72
+
73
+ require W3TC_DIR . '/FeatureShowcase_Plugin_Admin_View.php';
74
+
75
+ // Mark unseen new features as seen.
76
+ $this->mark_seen();
77
+ }
78
+
79
+ /**
80
+ * Enqueue styles.
81
+ *
82
+ * @since 2.1.0
83
+ */
84
+ public function enqueue_styles() {
85
+ wp_enqueue_style(
86
+ 'w3tc_feature_showcase',
87
+ esc_url( plugin_dir_url( __FILE__ ) . 'pub/css/feature-showcase.css' ),
88
+ array(),
89
+ W3TC_VERSION
90
+ );
91
+ }
92
+
93
+ /**
94
+ * Mark all new features as seen.
95
+ *
96
+ * @since 2.1.0
97
+ *
98
+ * @global $current_user WordPress current user.
99
+ *
100
+ * @see self::get_cards()
101
+ */
102
+ public function mark_seen() {
103
+ global $current_user;
104
+
105
+ $features_seen = (array) get_user_meta( $current_user->ID, 'w3tc_features_seen', true );
106
+ $cards = self::get_cards();
107
+ $updated = false;
108
+
109
+ foreach ( $cards as $id => $card ) {
110
+ if ( ! empty( $card['is_new'] ) && ! in_array( $id, $features_seen, true ) ) {
111
+ $features_seen[] = $id;
112
+ $updated = true;
113
+ }
114
+ }
115
+
116
+ if ( $updated ) {
117
+ sort( $features_seen );
118
+
119
+ $features_seen = array_unique( array_filter( $features_seen ) );
120
+
121
+ update_user_meta( $current_user->ID, 'w3tc_features_seen', $features_seen );
122
+ }
123
+ }
124
+
125
+
126
+ /**
127
+ * Get the new feature unseen count.
128
+ *
129
+ * @since 2.1.0
130
+ *
131
+ * @static
132
+ *
133
+ * @global $current_user WordPress current user.
134
+ *
135
+ * @see self::get_cards()
136
+ *
137
+ * @return int
138
+ */
139
+ public static function get_unseen_count() {
140
+ global $current_user;
141
+
142
+ $unseen_count = 0;
143
+ $features_seen = (array) get_user_meta( $current_user->ID, 'w3tc_features_seen', true );
144
+ $cards = self::get_cards();
145
+
146
+ // Iterate through the new features and check if already seen.
147
+ foreach ( $cards as $id => $card ) {
148
+ if ( ! empty( $card['is_new'] ) && ! in_array( $id, $features_seen, true ) ) {
149
+ $unseen_count++;
150
+ }
151
+ }
152
+
153
+ return $unseen_count;
154
+ }
155
+
156
+ /**
157
+ * Get the feature cards.
158
+ *
159
+ * @since 2.1.0
160
+ *
161
+ * @access private
162
+ * @static
163
+ *
164
+ * @return array
165
+ */
166
+ private static function get_cards() {
167
+ return array(
168
+ 'setup_guide' => array(
169
+ 'title' => esc_html__( 'Setup Guide Wizard', 'w3-total-cache' ),
170
+ 'icon' => 'dashicons-superhero',
171
+ 'text' => esc_html__( 'The Setup Guide wizard quickly walks you through configuring W3 Total Cache.', 'w3-total-cache' ),
172
+ 'button' => '<button class="button" onclick="window.location=\'' .
173
+ esc_url( admin_url( 'admin.php?page=w3tc_setup_guide' ) ) . '\'">' .
174
+ __( 'Launch', 'w3-total-cache' ) . '</button>',
175
+ 'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/setup-guide-wizard/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=setup_guide' ) .
176
+ '">' . __( 'More info', 'w3-total-cache' ) . '</a>',
177
+ 'is_premium' => false,
178
+ 'is_new' => true,
179
+ ),
180
+ 'lazyload_gmaps' => array(
181
+ 'title' => esc_html__( 'Lazy Load Google Maps', 'w3-total-cache' ),
182
+ 'icon' => 'dashicons-admin-site',
183
+ 'text' => esc_html__( 'Defer loading offscreen Google Maps, making pages load faster.', 'w3-total-cache' ),
184
+ 'button' => '<button class="button" onclick="window.location=\'' .
185
+ esc_url( admin_url( 'admin.php?page=w3tc_userexperience' ) ) . '\'">' .
186
+ __( 'Settings', 'w3-total-cache' ) . '</button>',
187
+ 'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/lazy-load-google-maps/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=pro_lazyload_googlemaps' ) .
188
+ '">' . __( 'More info', 'w3-total-cache' ) . '</a>',
189
+ 'is_premium' => true,
190
+ 'is_new' => true,
191
+ ),
192
+ 'cdn_fsd' => array(
193
+ 'title' => esc_html__( 'Full Site Delivery via CDN', 'w3-total-cache' ),
194
+ 'icon' => 'dashicons-networking',
195
+ 'text' => esc_html__( 'Provide the best user experience possible by enhancing by hosting HTML pages and RSS feeds with (supported) CDN\'s high speed global networks.', 'w3-total-cache' ),
196
+ 'button' => '<button class="button" onclick="window.location=\'' .
197
+ esc_url( admin_url( 'admin.php?page=w3tc_general#cdn' ) ) . '\'">' .
198
+ __( 'Settings', 'w3-total-cache' ) . '</button>',
199
+ 'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/cdn-full-site-delivery/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=pro_cdn_fsd' ) .
200
+ '">' . __( 'More info', 'w3-total-cache' ) . '</a>',
201
+ 'is_premium' => true,
202
+ 'is_new' => false,
203
+ ),
204
+ 'render_blocking_css' => array(
205
+ 'title' => esc_html__( 'Eliminate Render Blocking CSS', 'w3-total-cache' ),
206
+ 'icon' => 'dashicons-table-row-delete',
207
+ 'text' => esc_html__( 'Render blocking CSS delays a webpage from being visible in a timely manner. Eliminate this easily with the click of a button in W3 Total Cache Pro.', 'w3-total-cache' ),
208
+ 'button' => '<button class="button" onclick="window.location=\'' .
209
+ esc_url( admin_url( 'admin.php?page=w3tc_minify#css' ) ) . '\'">' .
210
+ __( 'Settings', 'w3-total-cache' ) . '</button>',
211
+ 'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/how-to-use-manual-minify-for-css-and-js/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=pro_minify_CSS' ) .
212
+ '">' . __( 'More info', 'w3-total-cache' ) . '</a>',
213
+ 'is_premium' => true,
214
+ 'is_new' => false,
215
+ ),
216
+ 'extension_framework' => array(
217
+ 'title' => esc_html__( 'Extension Framework', 'w3-total-cache' ),
218
+ 'icon' => 'dashicons-insert',
219
+ 'text' => esc_html__( 'Improve the performance of your Genesis, WPML powered site, and much more. StudioPress\' Genesis Framework is up to 60% faster with W3TC Pro.', 'w3-total-cache' ),
220
+ 'button' => '<button class="button" onclick="window.location=\'' .
221
+ esc_url( admin_url( 'admin.php?page=w3tc_extensions' ) ) . '\'">' .
222
+ __( 'Settings', 'w3-total-cache' ) . '</button>',
223
+ 'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/extension-framework-pro/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=pro_extensions' ) .
224
+ '">' . __( 'More info', 'w3-total-cache' ) . '</a>',
225
+ 'is_premium' => true,
226
+ 'is_new' => false,
227
+ ),
228
+ 'fragment_cache' => array(
229
+ 'title' => esc_html__( 'Fragment Cache', 'w3-total-cache' ),
230
+ 'icon' => 'dashicons-chart-pie',
231
+ 'text' => esc_html__( 'Unlocking the fragment caching module delivers enhanced performance for plugins and themes that use the WordPress Transient API.', 'w3-total-cache' ),
232
+ 'button' => '<button class="button" onclick="window.location=\'' .
233
+ esc_url( admin_url( 'admin.php?page=w3tc_general#fragmentcache' ) ) . '\'">' .
234
+ __( 'Settings', 'w3-total-cache' ) . '</button>',
235
+ 'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/choosing-a-fragment-caching-method-for-w3-total-cache/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=pro_fragment_cache' ) .
236
+ '">' . __( 'More info', 'w3-total-cache' ) . '</a>',
237
+ 'is_premium' => true,
238
+ 'is_new' => false,
239
+ ),
240
+ 'rest_api_cache' => array(
241
+ 'title' => esc_html__( 'Rest API Caching', 'w3-total-cache' ),
242
+ 'icon' => 'dashicons-embed-generic',
243
+ 'text' => esc_html__( 'Save server resources or add scale and performance by caching the WordPress Rest API with W3TC Pro.', 'w3-total-cache' ),
244
+ 'button' => '<button class="button" onclick="window.location=\'' .
245
+ esc_url( admin_url( 'admin.php?page=w3tc_pgcache#rest' ) ) . '\'">' .
246
+ __( 'Settings', 'w3-total-cache' ) . '</button>',
247
+ 'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/achieve-ultimate-wordpress-performance-with-w3-total-cache-pro/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=pro_rest_api_caching' ) .
248
+ '">' . __( 'More info', 'w3-total-cache' ) . '</a>',
249
+ 'is_premium' => true,
250
+ 'is_new' => false,
251
+ ),
252
+ 'caching_stats' => array(
253
+ 'title' => esc_html__( 'Caching Statistics', 'w3-total-cache' ),
254
+ 'icon' => 'dashicons-chart-line',
255
+ 'text' => esc_html__( 'Analytics for your WordPress and Server cache that allow you to track the size, time and hit/miss ratio of each type of cache, giving you the information needed to gain maximum performance.', 'w3-total-cache' ),
256
+ 'button' => '<button class="button" onclick="window.location=\'' .
257
+ esc_url( admin_url( 'admin.php?page=w3tc_stats' ) ) . '\'">' .
258
+ __( 'Settings', 'w3-total-cache' ) . '</button>',
259
+ 'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/configuring-w3-total-cache-statistics-to-give-detailed-information-about-your-cache/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=pro_stats' ) .
260
+ '">' . __( 'More info', 'w3-total-cache' ) . '</a>',
261
+ 'is_premium' => true,
262
+ 'is_new' => false,
263
+ ),
264
+ 'purge_logs' => array(
265
+ 'title' => esc_html__( 'Purge Logs', 'w3-total-cache' ),
266
+ 'icon' => 'dashicons-search',
267
+ 'text' => esc_html__( 'Purge Logs provide information on when your cache has been purged and what triggered it. If you are troubleshooting an issue with your cache being cleared, Purge Logs can tell you why.', 'w3-total-cache' ),
268
+ 'button' => '<button class="button" onclick="window.location=\'' .
269
+ esc_url( admin_url( 'admin.php?page=w3tc_general#debug' ) ) . '\'">' .
270
+ __( 'Settings', 'w3-total-cache' ) . '</button>',
271
+ 'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/purge-cache-log/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=pro_purge_logs' ) .
272
+ '">' . __( 'More info', 'w3-total-cache' ) . '</a>',
273
+ 'is_premium' => true,
274
+ 'is_new' => false,
275
+ ),
276
+ 'page_cache' => array(
277
+ 'title' => esc_html__( 'Page Cache', 'w3-total-cache' ),
278
+ 'icon' => 'dashicons-format-aside',
279
+ 'text' => esc_html__( 'Page caching decreases the website response time, making pages load faster.', 'w3-total-cache' ),
280
+ 'button' => '<button class="button" onclick="window.location=\'' .
281
+ esc_url( admin_url( 'admin.php?page=w3tc_general#page_cache' ) ) . '\'">' .
282
+ __( 'Settings', 'w3-total-cache' ) . '</button>',
283
+ 'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/configuring-page-caching-in-w3-total-cache-for-shared-hosting/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=page_cache' ) .
284
+ '">' . __( 'More info', 'w3-total-cache' ) . '</a>',
285
+ 'is_premium' => false,
286
+ 'is_new' => false,
287
+ ),
288
+ 'minify' => array(
289
+ 'title' => esc_html__( 'Minify', 'w3-total-cache' ),
290
+ 'icon' => 'dashicons-media-text',
291
+ 'text' => esc_html__( 'Reduce load time by decreasing the size and number of CSS and JS files.', 'w3-total-cache' ),
292
+ 'button' => '<button class="button" onclick="window.location=\'' .
293
+ esc_url( admin_url( 'admin.php?page=w3tc_general#minify' ) ) . '\'">' .
294
+ __( 'Settings', 'w3-total-cache' ) . '</button>',
295
+ 'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/choosing-a-minification-method-for-w3-total-cache/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=minify' ) .
296
+ '">' . __( 'More info', 'w3-total-cache' ) . '</a>',
297
+ 'is_premium' => false,
298
+ 'is_new' => false,
299
+ ),
300
+ 'lazyload' => array(
301
+ 'title' => esc_html__( 'Lazy Load Images', 'w3-total-cache' ),
302
+ 'icon' => 'dashicons-format-image',
303
+ 'text' => esc_html__( 'Defer loading offscreen images, making pages load faster.', 'w3-total-cache' ),
304
+ 'button' => '<button class="button" onclick="window.location=\'' .
305
+ esc_url( admin_url( 'admin.php?page=w3tc_general#userexperience' ) ) . '\'">' .
306
+ __( 'Settings', 'w3-total-cache' ) . '</button>',
307
+ 'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/configuring-lazy-loading-for-your-wordpress-website-with-w3-total-cache/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=lazyload' ) .
308
+ '">' . __( 'More info', 'w3-total-cache' ) . '</a>',
309
+ 'is_premium' => false,
310
+ 'is_new' => false,
311
+ ),
312
+ 'cdn' => array(
313
+ 'title' => esc_html__( 'Content Delivery Network (CDN)', 'w3-total-cache' ),
314
+ 'icon' => 'dashicons-format-gallery',
315
+ 'text' => esc_html__( 'Host static files with a CDN to reduce page load time.', 'w3-total-cache' ),
316
+ 'button' => '<button class="button" onclick="window.location=\'' .
317
+ esc_url( admin_url( 'admin.php?page=w3tc_general#cdn' ) ) . '\'">' .
318
+ __( 'Settings', 'w3-total-cache' ) . '</button>',
319
+ 'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/configuring-w3-total-cache-with-stackpath-for-cdn-objects/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=cdn' ) .
320
+ '">' . __( 'More info', 'w3-total-cache' ) . '</a>',
321
+ 'is_premium' => false,
322
+ 'is_new' => false,
323
+ ),
324
+ 'opcode_cache' => array(
325
+ 'title' => esc_html__( 'Opcode Cache', 'w3-total-cache' ),
326
+ 'icon' => 'dashicons-performance',
327
+ 'text' => esc_html__( 'Improves PHP performance by storing precompiled script bytecode in shared memory.', 'w3-total-cache' ),
328
+ 'button' => '<button class="button" onclick="window.location=\'' .
329
+ esc_url( admin_url( 'admin.php?page=w3tc_general#system_opcache' ) ) . '\'">' .
330
+ __( 'Settings', 'w3-total-cache' ) . '</button>',
331
+ 'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/choosing-an-opcode-caching-method-with-w3-total-cache/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=opcode_cache' ) .
332
+ '">' . __( 'More info', 'w3-total-cache' ) . '</a>',
333
+ 'is_premium' => false,
334
+ 'is_new' => false,
335
+ ),
336
+ 'db_cache' => array(
337
+ 'title' => esc_html__( 'Database Cache', 'w3-total-cache' ),
338
+ 'icon' => 'dashicons-database-view',
339
+ 'text' => esc_html__( 'Persistently store data to reduce post, page and feed creation time.', 'w3-total-cache' ),
340
+ 'button' => '<button class="button" onclick="window.location=\'' .
341
+ esc_url( admin_url( 'admin.php?page=w3tc_general#database_cache' ) ) . '\'">' .
342
+ __( 'Settings', 'w3-total-cache' ) . '</button>',
343
+ 'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/choosing-a-database-caching-method-in-w3-total-cache/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=database_cache' ) .
344
+ '">' . __( 'More info', 'w3-total-cache' ) . '</a>',
345
+ 'is_premium' => false,
346
+ 'is_new' => false,
347
+ ),
348
+ 'object_cache' => array(
349
+ 'title' => esc_html__( 'Object Cache', 'w3-total-cache' ),
350
+ 'icon' => 'dashicons-archive',
351
+ 'text' => esc_html__( 'Persistently store objects to reduce execution time for common operations.', 'w3-total-cache' ),
352
+ 'button' => '<button class="button" onclick="window.location=\'' .
353
+ esc_url( admin_url( 'admin.php?page=w3tc_general#object_cache' ) ) . '\'">' .
354
+ __( 'Settings', 'w3-total-cache' ) . '</button>',
355
+ 'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/configuring-object-caching-methods-in-w3-total-cache/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=object_cache' ) .
356
+ '">' . __( 'More info', 'w3-total-cache' ) . '</a>',
357
+ 'is_premium' => false,
358
+ 'is_new' => false,
359
+ ),
360
+ 'browser_cache' => array(
361
+ 'title' => esc_html__( 'Browser Cache', 'w3-total-cache' ),
362
+ 'icon' => 'dashicons-welcome-widgets-menus',
363
+ 'text' => esc_html__( 'Reduce server load and decrease response time by using the cache available in site visitor\'s web browser.', 'w3-total-cache' ),
364
+ 'button' => '<button class="button" onclick="window.location=\'' .
365
+ esc_url( admin_url( 'admin.php?page=w3tc_general#browser_cache' ) ) . '\'">' .
366
+ __( 'Settings', 'w3-total-cache' ) . '</button>',
367
+ 'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/configuring-browser-caching-in-w3-total-cache/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=browser_cache' ) .
368
+ '">' . __( 'More info', 'w3-total-cache' ) . '</a>',
369
+ 'is_premium' => false,
370
+ 'is_new' => false,
371
+ ),
372
+ 'extensions' => array(
373
+ 'title' => esc_html__( 'Extensions', 'w3-total-cache' ),
374
+ 'icon' => 'dashicons-editor-kitchensink',
375
+ 'text' => esc_html__( 'Additional features to extend the functionality of W3 Total Cache, such as Accelerated Mobile Pages (AMP) for Minify and support for New Relic.', 'w3-total-cache' ),
376
+ 'button' => '<button class="button" onclick="window.location=\'' .
377
+ esc_url( admin_url( 'admin.php?page=w3tc_extensions' ) ) . '\'">' .
378
+ __( 'Settings', 'w3-total-cache' ) . '</button>',
379
+ 'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/extension-framework/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=extensions' ) .
380
+ '">' . __( 'More info', 'w3-total-cache' ) . '</a>',
381
+ 'is_premium' => false,
382
+ 'is_new' => false,
383
+ ),
384
+ 'cache_groups' => array(
385
+ 'title' => esc_html__( 'Cache Groups', 'w3-total-cache' ),
386
+ 'icon' => 'dashicons-image-filter',
387
+ 'text' => esc_html__( 'Manage cache groups for user agents, referrers, and cookies.', 'w3-total-cache' ),
388
+ 'button' => '<button class="button" onclick="window.location=\'' .
389
+ esc_url( admin_url( 'admin.php?page=w3tc_cachegroups' ) ) . '\'">' .
390
+ __( 'Settings', 'w3-total-cache' ) . '</button>',
391
+ 'link' => '<a target="_blank" href="' . esc_url( 'https://www.boldgrid.com/support/w3-total-cache/cache-groups/?utm_source=w3tc&utm_medium=feature_showcase&utm_campaign=cache_groups' ) .
392
+ '">' . __( 'More info', 'w3-total-cache' ) . '</a>',
393
+ 'is_premium' => false,
394
+ 'is_new' => false,
395
+ ),
396
+ );
397
+ }
398
+ }
FeatureShowcase_Plugin_Admin_View.php ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * File: FeatureShowcase_Plugin_Admin_View.php
4
+ *
5
+ * @since 2.1.0
6
+ *
7
+ * @package W3TC
8
+ *
9
+ * @uses array $config W3TC configuration.
10
+ * @uses array $cards {
11
+ * Feature configuration.
12
+ *
13
+ * @type string $title Title.
14
+ * @type string $icon Dashicon icon class.
15
+ * @type string $text Description.
16
+ * @type string $button Button markup.
17
+ * @type string $link Link URL address.
18
+ * @type bool $is_premium Is it a premium feature.
19
+ * }
20
+ *
21
+ * @see Util_Environment::is_w3tc_pro()
22
+ * @see Util_Ui::pro_wrap_maybe_end2()
23
+ *
24
+ * phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
25
+ */
26
+
27
+ namespace W3TC;
28
+
29
+ $is_pro = Util_Environment::is_w3tc_pro( $config );
30
+
31
+ if ( $is_pro ) {
32
+ require W3TC_INC_DIR . '/options/common/header.php';
33
+ } else {
34
+ require W3TC_INC_DIR . '/options/parts/dashboard_banner.php';
35
+ }
36
+
37
+ ?>
38
+
39
+ <div class="w3tc-page-container">
40
+ <div class="w3tc-card-container">
41
+ <?php
42
+
43
+ foreach ( $cards as $feature_id => $card ) {
44
+ $card_classes = 'w3tc-card';
45
+ $title_classes = 'w3tc-card-title';
46
+ $is_premium = ! empty( $card['is_premium'] );
47
+ $is_new = ! empty( $card['is_new'] );
48
+
49
+ if ( $is_premium ) {
50
+ $card_classes .= ' w3tc-card-premium';
51
+ $title_classes .= ' w3tc-card-premium';
52
+ }
53
+
54
+ if ( $is_premium && ! $is_pro ) {
55
+ $card_classes .= ' w3tc-card-upgrade';
56
+ }
57
+
58
+ ?>
59
+ <div class="<?php echo $card_classes; ?>" id="w3tc-feature-<?php echo esc_attr( $feature_id ); ?>">
60
+ <?php
61
+
62
+ if ( $is_new ) {
63
+ ?>
64
+ <div class="w3tc-card-ribbon-new"><span>NEW</span></div>
65
+ <?php
66
+ }
67
+
68
+ ?>
69
+ <div class="<?php echo $title_classes; ?>">
70
+ <p><?php echo $card['title']; ?></p>
71
+ <?php
72
+ if ( $is_premium ) {
73
+ ?>
74
+ <p class="w3tc-card-pro"><?php echo __( 'PRO FEATURE', 'w3-total-cache' ); ?></p>
75
+ <?php
76
+ }
77
+ ?>
78
+ </div>
79
+ <div class="w3tc-card-icon"><span class="dashicons <?php echo $card['icon']; ?>"></span></div>
80
+ <div class="w3tc-card-body"><p><?php echo $card['text']; ?></p></div>
81
+ <div class="w3tc-card-footer">
82
+ <div class="w3tc-card-button">
83
+ <?php
84
+
85
+ if ( $is_premium && ! $is_pro ) {
86
+ ?>
87
+ <button class="button w3tc-gopro-button button-buy-plugin" data-src="feature_showcase">Unlock Feature</button>
88
+ <?php
89
+ } elseif ( ! empty( $card['button'] ) ) {
90
+ echo $card['button'];
91
+ }
92
+
93
+ ?>
94
+ </div><div class="w3tc-card-links"><?php echo $card['link']; ?></div>
95
+ </div>
96
+ </div>
97
+ <?php
98
+ }
99
+
100
+ ?>
101
+ </div>
102
+ </div>
Generic_AdminActions_Default.php CHANGED
@@ -359,158 +359,6 @@ class Generic_AdminActions_Default {
359
  }
360
  }
361
 
362
- /**
363
- * Mobile tab
364
- */
365
- if ( $this->_page == 'w3tc_mobile' ) {
366
- $groups = Util_Request::get_array( 'mobile_groups' );
367
-
368
- $mobile_groups = array();
369
- $cached_mobile_groups = array();
370
-
371
- foreach ( $groups as $group => $group_config ) {
372
- $group = strtolower( $group );
373
- $group = preg_replace( '~[^0-9a-z_]+~', '_', $group );
374
- $group = trim( $group, '_' );
375
-
376
- if ( $group ) {
377
- $theme = ( isset( $group_config['theme'] ) ? trim( $group_config['theme'] ) : 'default' );
378
- $enabled = ( isset( $group_config['enabled'] ) ? (boolean) $group_config['enabled'] : true );
379
- $redirect = ( isset( $group_config['redirect'] ) ? trim( $group_config['redirect'] ) : '' );
380
- $agents = ( isset( $group_config['agents'] ) ? explode( "\r\n", trim( $group_config['agents'] ) ) : array() );
381
-
382
- $mobile_groups[$group] = array(
383
- 'theme' => $theme,
384
- 'enabled' => $enabled,
385
- 'redirect' => $redirect,
386
- 'agents' => $agents
387
- );
388
-
389
- $cached_mobile_groups[$group] = $agents;
390
- }
391
- }
392
-
393
- /**
394
- * Allow plugins modify WPSC mobile groups
395
- */
396
- $cached_mobile_groups = apply_filters( 'cached_mobile_groups', $cached_mobile_groups );
397
-
398
- /**
399
- * Merge existent and delete removed groups
400
- */
401
- foreach ( $mobile_groups as $group => $group_config ) {
402
- if ( isset( $cached_mobile_groups[$group] ) ) {
403
- $mobile_groups[$group]['agents'] = (array) $cached_mobile_groups[$group];
404
- } else {
405
- unset( $mobile_groups[$group] );
406
- }
407
- }
408
-
409
- /**
410
- * Add new groups
411
- */
412
- foreach ( $cached_mobile_groups as $group => $agents ) {
413
- if ( !isset( $mobile_groups[$group] ) ) {
414
- $mobile_groups[$group] = array(
415
- 'theme' => '',
416
- 'enabled' => true,
417
- 'redirect' => '',
418
- 'agents' => $agents
419
- );
420
- }
421
- }
422
-
423
- /**
424
- * Allow plugins modify W3TC mobile groups
425
- */
426
- $mobile_groups = apply_filters( 'w3tc_mobile_groups', $mobile_groups );
427
-
428
- /**
429
- * Sanitize mobile groups
430
- */
431
- foreach ( $mobile_groups as $group => $group_config ) {
432
- $mobile_groups[$group] = array_merge( array(
433
- 'theme' => '',
434
- 'enabled' => true,
435
- 'redirect' => '',
436
- 'agents' => array()
437
- ), $group_config );
438
-
439
- $mobile_groups[$group]['agents'] = array_unique( $mobile_groups[$group]['agents'] );
440
- $mobile_groups[$group]['agents'] = array_map( 'strtolower', $mobile_groups[$group]['agents'] );
441
- sort( $mobile_groups[$group]['agents'] );
442
- }
443
- $enable_mobile = false;
444
- foreach ( $mobile_groups as $group_config ) {
445
- if ( $group_config['enabled'] ) {
446
- $enable_mobile = true;
447
- break;
448
- }
449
- }
450
- $config->set( 'mobile.enabled', $enable_mobile );
451
- $config->set( 'mobile.rgroups', $mobile_groups );
452
- }
453
-
454
- /**
455
- * Referrer tab
456
- */
457
- if ( $this->_page == 'w3tc_referrer' ) {
458
- $groups = Util_Request::get_array( 'referrer_groups' );
459
-
460
- $referrer_groups = array();
461
-
462
- foreach ( $groups as $group => $group_config ) {
463
- $group = strtolower( $group );
464
- $group = preg_replace( '~[^0-9a-z_]+~', '_', $group );
465
- $group = trim( $group, '_' );
466
-
467
- if ( $group ) {
468
- $theme = ( isset( $group_config['theme'] ) ? trim( $group_config['theme'] ) : 'default' );
469
- $enabled = ( isset( $group_config['enabled'] ) ? (boolean) $group_config['enabled'] : true );
470
- $redirect = ( isset( $group_config['redirect'] ) ? trim( $group_config['redirect'] ) : '' );
471
- $referrers = ( isset( $group_config['referrers'] ) ? explode( "\r\n", trim( $group_config['referrers'] ) ) : array() );
472
-
473
- $referrer_groups[$group] = array(
474
- 'theme' => $theme,
475
- 'enabled' => $enabled,
476
- 'redirect' => $redirect,
477
- 'referrers' => $referrers
478
- );
479
- }
480
- }
481
-
482
- /**
483
- * Allow plugins modify W3TC referrer groups
484
- */
485
- $referrer_groups = apply_filters( 'w3tc_referrer_groups', $referrer_groups );
486
-
487
- /**
488
- * Sanitize mobile groups
489
- */
490
- foreach ( $referrer_groups as $group => $group_config ) {
491
- $referrer_groups[$group] = array_merge( array(
492
- 'theme' => '',
493
- 'enabled' => true,
494
- 'redirect' => '',
495
- 'referrers' => array()
496
- ), $group_config );
497
-
498
- $referrer_groups[$group]['referrers'] = array_unique( $referrer_groups[$group]['referrers'] );
499
- $referrer_groups[$group]['referrers'] = array_map( 'strtolower', $referrer_groups[$group]['referrers'] );
500
- sort( $referrer_groups[$group]['referrers'] );
501
- }
502
-
503
- $enable_referrer = false;
504
- foreach ( $referrer_groups as $group_config ) {
505
- if ( $group_config['enabled'] ) {
506
- $enable_referrer = true;
507
- break;
508
- }
509
- }
510
- $config->set( 'referrer.enabled', $enable_referrer );
511
- $config->set( 'referrer.rgroups', $referrer_groups );
512
- }
513
-
514
  /**
515
  * CDN tab
516
  */
359
  }
360
  }
361
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
362
  /**
363
  * CDN tab
364
  */
Generic_AdminNotes.php CHANGED
@@ -112,10 +112,17 @@ class Generic_AdminNotes {
112
  'w3-total-cache' ),
113
  Util_Ui::button_link(
114
  __( 'minify settings', 'w3-total-cache' ),
115
- Util_Ui::url( array(
 
116
  'w3tc_default_config_state_note' => 'y',
117
- 'key' => 'common.show_note.plugins_updated',
118
- 'value' => 'false' ) ) ) );
 
 
 
 
 
 
119
  }
120
 
121
  if ( count( $texts ) ) {
112
  'w3-total-cache' ),
113
  Util_Ui::button_link(
114
  __( 'minify settings', 'w3-total-cache' ),
115
+ Util_Ui::url(
116
+ array(
117
  'w3tc_default_config_state_note' => 'y',
118
+ 'key' => 'common.show_note.plugins_updated',
119
+ 'value' => 'false',
120
+ 'page' => 'w3tc_minify',
121
+ 'redirect' => esc_url( admin_url( 'admin.php?page=w3tc_minify' ) ),
122
+ )
123
+ )
124
+ )
125
+ );
126
  }
127
 
128
  if ( count( $texts ) ) {
Generic_Plugin.php CHANGED
@@ -301,6 +301,13 @@ class Generic_Plugin {
301
  );
302
  }
303
 
 
 
 
 
 
 
 
304
  $menu_items['40010.generic'] = array(
305
  'id' => 'w3tc_settings_general',
306
  'parent' => 'w3tc',
301
  );
302
  }
303
 
304
+ $menu_items['30000.generic'] = array(
305
+ 'id' => 'w3tc_feature_showcase',
306
+ 'parent' => 'w3tc',
307
+ 'title' => __( 'Feature Showcase', 'w3-total-cache' ),
308
+ 'href' => wp_nonce_url( network_admin_url( 'admin.php?page=w3tc_feature_showcase' ), 'w3tc' ),
309
+ );
310
+
311
  $menu_items['40010.generic'] = array(
312
  'id' => 'w3tc_settings_general',
313
  'parent' => 'w3tc',
Generic_Plugin_Admin.php CHANGED
@@ -224,7 +224,10 @@ class Generic_Plugin_Admin {
224
  do_action( 'admin_init_' . $_REQUEST['page'] );
225
  }
226
 
227
- function admin_enqueue_scripts() {
 
 
 
228
  wp_register_style( 'w3tc-options', plugins_url( 'pub/css/options.css', W3TC_FILE ), array(), W3TC_VERSION );
229
  wp_register_style( 'w3tc-lightbox', plugins_url( 'pub/css/lightbox.css', W3TC_FILE ), array(), W3TC_VERSION );
230
  wp_register_style( 'w3tc-widget', plugins_url( 'pub/css/widget.css', W3TC_FILE ), array(), W3TC_VERSION );
@@ -235,6 +238,20 @@ class Generic_Plugin_Admin {
235
  wp_register_script( 'w3tc-widget', plugins_url( 'pub/js/widget.js', W3TC_FILE ), array(), W3TC_VERSION );
236
  wp_register_script( 'w3tc-jquery-masonry', plugins_url( 'pub/js/jquery.masonry.min.js', W3TC_FILE ), array( 'jquery' ), W3TC_VERSION );
237
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
  if ( !is_null( $this->w3tc_message ) &&
239
  isset( $this->w3tc_message['actions'] ) &&
240
  is_array( $this->w3tc_message['actions'] ) ) {
@@ -409,9 +426,7 @@ class Generic_Plugin_Admin {
409
  }
410
 
411
  /**
412
- * Print scripts
413
- *
414
- * @return void
415
  */
416
  function admin_print_scripts() {
417
  wp_enqueue_script( 'w3tc-metadata' );
@@ -419,15 +434,26 @@ class Generic_Plugin_Admin {
419
  wp_enqueue_script( 'w3tc-lightbox' );
420
 
421
  if ( $this->is_w3tc_page ) {
422
- wp_localize_script( 'w3tc-options', 'w3tc_nonce',
423
- array( wp_create_nonce( 'w3tc' ) ) );
 
 
 
424
  }
425
 
426
-
427
  switch ( $this->_page ) {
428
  case 'w3tc_minify':
429
- case 'w3tc_mobile':
430
- case 'w3tc_referrer':
 
 
 
 
 
 
 
 
 
431
  case 'w3tc_cdn':
432
  wp_enqueue_script( 'jquery-ui-sortable' );
433
  break;
224
  do_action( 'admin_init_' . $_REQUEST['page'] );
225
  }
226
 
227
+ /**
228
+ * Enqueue admin scripts.
229
+ */
230
+ public function admin_enqueue_scripts() {
231
  wp_register_style( 'w3tc-options', plugins_url( 'pub/css/options.css', W3TC_FILE ), array(), W3TC_VERSION );
232
  wp_register_style( 'w3tc-lightbox', plugins_url( 'pub/css/lightbox.css', W3TC_FILE ), array(), W3TC_VERSION );
233
  wp_register_style( 'w3tc-widget', plugins_url( 'pub/css/widget.css', W3TC_FILE ), array(), W3TC_VERSION );
238
  wp_register_script( 'w3tc-widget', plugins_url( 'pub/js/widget.js', W3TC_FILE ), array(), W3TC_VERSION );
239
  wp_register_script( 'w3tc-jquery-masonry', plugins_url( 'pub/js/jquery.masonry.min.js', W3TC_FILE ), array( 'jquery' ), W3TC_VERSION );
240
 
241
+ // New feature count for the Feature Showcase.
242
+ wp_register_script( 'w3tc-feature-counter', plugins_url( 'pub/js/feature-counter.js', W3TC_FILE ), array(), W3TC_VERSION, true );
243
+
244
+ wp_localize_script(
245
+ 'w3tc-feature-counter',
246
+ 'W3TCFeatureShowcaseData',
247
+ array(
248
+ 'unseenCount' => FeatureShowcase_Plugin_Admin::get_unseen_count(),
249
+ )
250
+ );
251
+
252
+ wp_enqueue_script( 'w3tc-feature-counter' );
253
+
254
+ // Messages.
255
  if ( !is_null( $this->w3tc_message ) &&
256
  isset( $this->w3tc_message['actions'] ) &&
257
  is_array( $this->w3tc_message['actions'] ) ) {
426
  }
427
 
428
  /**
429
+ * Print scripts.
 
 
430
  */
431
  function admin_print_scripts() {
432
  wp_enqueue_script( 'w3tc-metadata' );
434
  wp_enqueue_script( 'w3tc-lightbox' );
435
 
436
  if ( $this->is_w3tc_page ) {
437
+ wp_localize_script(
438
+ 'w3tc-options',
439
+ 'w3tc_nonce',
440
+ array( wp_create_nonce( 'w3tc' ) )
441
+ );
442
  }
443
 
 
444
  switch ( $this->_page ) {
445
  case 'w3tc_minify':
446
+ case 'w3tc_cachegroups':
447
+ wp_enqueue_script(
448
+ 'w3tc_cachegroups',
449
+ plugins_url( 'CacheGroups_Plugin_Admin_View.js', W3TC_FILE ),
450
+ array(
451
+ 'jquery',
452
+ 'jquery-ui-sortable',
453
+ ),
454
+ W3TC_VERSION,
455
+ true
456
+ );
457
  case 'w3tc_cdn':
458
  wp_enqueue_script( 'jquery-ui-sortable' );
459
  break;
Mobile_Page_ReferrerGroups.php DELETED
@@ -1,28 +0,0 @@
1
- <?php
2
- namespace W3TC;
3
-
4
-
5
-
6
- class Mobile_Page_ReferrerGroups extends Base_Page_Settings {
7
- /**
8
- * Current page
9
- *
10
- * @var string
11
- */
12
- protected $_page = 'w3tc_referrer';
13
-
14
- /**
15
- * Referrer tab
16
- *
17
- * @return void
18
- */
19
- function view() {
20
- $groups = $this->_config->get_array( 'referrer.rgroups' );
21
-
22
- $w3_referrer = Dispatcher::component( 'Mobile_Referrer' );
23
-
24
- $themes = $w3_referrer->get_themes();
25
-
26
- include W3TC_INC_DIR . '/options/referrer.php';
27
- }
28
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Mobile_Page_UserAgentGroups.php DELETED
@@ -1,45 +0,0 @@
1
- <?php
2
- namespace W3TC;
3
-
4
-
5
-
6
- class Mobile_Page_UserAgentGroups extends Base_Page_Settings {
7
- /**
8
- * Current page
9
- *
10
- * @var string
11
- */
12
- protected $_page = 'w3tc_mobile';
13
-
14
-
15
- /**
16
- * Mobile tab
17
- *
18
- * @return void
19
- */
20
- function view() {
21
- $c = Dispatcher::config();
22
-
23
- $groups = array(
24
- 'value' => $c->get_array( 'mobile.rgroups' ),
25
- 'disabled' => $c->is_sealed( 'mobile.rgroups' ),
26
- 'description' =>
27
- '<li>' .
28
- __( 'Enabling even a single user agent group will set a cookie called "w3tc_referrer." It is used to ensure a consistent user experience across page views. Make sure any reverse proxy servers etc respect this cookie for proper operation.',
29
- 'w3-total-cache' ) .
30
- '</li>' .
31
- '<li>' .
32
- __( 'Per the above, make sure that visitors are notified about the cookie as per any regulations in your market.',
33
- 'w3-total-cache' ) .
34
- '</li>'
35
- );
36
-
37
- $groups = apply_filters( 'w3tc_ui_config_item_mobile.rgroups', $groups );
38
-
39
- $w3_mobile = Dispatcher::component( 'Mobile_UserAgent' );
40
- $themes = $w3_mobile->get_themes();
41
-
42
- include W3TC_INC_DIR . '/options/mobile.php';
43
- }
44
-
45
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ObjectCache_WpObjectCache_Regular.php CHANGED
@@ -845,13 +845,16 @@ class ObjectCache_WpObjectCache_Regular {
845
 
846
  public function w3tc_footer_comment( $strings ) {
847
  $reason = $this->get_reject_reason();
848
- $append = ( $reason != '' ? sprintf( ' (%s)', $reason ) : '' );
849
 
850
  $strings[] = sprintf(
851
- __( 'Object Caching %d/%d objects using %s%s', 'w3-total-cache' ),
852
- $this->cache_hits, $this->cache_total,
 
 
853
  Cache::engine_name( $this->_config->get_string( 'objectcache.engine' ) ),
854
- $append );
 
855
 
856
  if ( $this->_config->get_boolean( 'objectcache.debug' ) ) {
857
  $strings[] = '';
845
 
846
  public function w3tc_footer_comment( $strings ) {
847
  $reason = $this->get_reject_reason();
848
+ $append = empty( $reason ) ? '' : sprintf( ' (%1$s)', $reason );
849
 
850
  $strings[] = sprintf(
851
+ // translators: 1: Cache hits, 2: Cache total cache objects, 3: Engine anme, 4: Reason.
852
+ __( 'Object Caching %1$d/%2$d objects using %3$s%4$s', 'w3-total-cache' ),
853
+ $this->cache_hits,
854
+ $this->cache_total,
855
  Cache::engine_name( $this->_config->get_string( 'objectcache.engine' ) ),
856
+ $append
857
+ );
858
 
859
  if ( $this->_config->get_boolean( 'objectcache.debug' ) ) {
860
  $strings[] = '';
PageSpeed_Plugin_Widget.php CHANGED
@@ -107,7 +107,7 @@ class PageSpeed_Plugin_Widget {
107
  }
108
 
109
  ob_start();
110
- include W3TC_DIR . '/PageSpeed_Widget_View_FromApi.php';
111
  $content = ob_get_contents();
112
  ob_end_clean();
113
 
107
  }
108
 
109
  ob_start();
110
+ include __DIR__ . '/PageSpeed_Widget_View_FromApi.php';
111
  $content = ob_get_contents();
112
  ob_end_clean();
113
 
PgCache_ContentGrabber.php CHANGED
@@ -1566,10 +1566,12 @@ class PgCache_ContentGrabber {
1566
  */
1567
  public function w3tc_footer_comment( $strings ) {
1568
  $strings[] = sprintf(
1569
- __( 'Page Caching using %s%s%s', 'w3-total-cache' ),
 
1570
  Cache::engine_name( $this->_config->get_string( 'pgcache.engine' ) ),
1571
  '{w3tc_pagecache_reject_reason}',
1572
- isset($this->_page_key_extension['cookie']) ? ' ' . $this->_page_key_extension['cookie'] : '' );
 
1573
 
1574
 
1575
  if ( $this->_debug ) {
1566
  */
1567
  public function w3tc_footer_comment( $strings ) {
1568
  $strings[] = sprintf(
1569
+ // translators: 1: Engine name, 2: Reject reason placeholder, 3: Page key extension.
1570
+ __( 'Page Caching using %1$s%2$s%3$s', 'w3-total-cache' ),
1571
  Cache::engine_name( $this->_config->get_string( 'pgcache.engine' ) ),
1572
  '{w3tc_pagecache_reject_reason}',
1573
+ isset( $this->_page_key_extension['cookie'] ) ? ' ' . $this->_page_key_extension['cookie'] : ''
1574
+ );
1575
 
1576
 
1577
  if ( $this->_debug ) {
PgCache_Page_CookieGroups.php DELETED
@@ -1,78 +0,0 @@
1
- <?php
2
- namespace W3TC;
3
-
4
-
5
-
6
- class PgCache_Page_CookieGroups {
7
- static public function admin_init_w3tc_pgcache_cookiegroups() {
8
- wp_enqueue_script( 'jquery-ui-sortable' );
9
- wp_enqueue_script( 'w3tc_pgcache_page_cookiegroups',
10
- plugins_url( 'PgCache_Page_CookieGroups_View.js', W3TC_FILE ),
11
- array( 'jquery', 'jquery-ui-sortable' ), '1.0' );
12
- }
13
-
14
-
15
-
16
- static public function w3tc_settings_page_w3tc_pgcache_cookiegroups() {
17
- $c = Dispatcher::config();
18
-
19
- $groups = array(
20
- 'value' => $c->get_array( 'pgcache.cookiegroups.groups' ),
21
- 'disabled' => $c->is_sealed( 'pgcache.cookiegroups.groups' )
22
- );
23
-
24
- $groups = apply_filters( 'w3tc_ui_config_item_pgcache.cookiegroups.groups', $groups );
25
- $config = Dispatcher::config();
26
-
27
- include W3TC_DIR . '/PgCache_Page_CookieGroups_View.php';
28
- }
29
-
30
-
31
-
32
- static public function w3tc_config_ui_save_w3tc_pgcache_cookiegroups( $config ) {
33
- $groups = Util_Request::get_array( 'cookiegroups' );
34
-
35
- $mobile_groups = array();
36
- $cached_mobile_groups = array();
37
-
38
- foreach ( $groups as $group => $group_config ) {
39
- $group = strtolower( $group );
40
- $group = preg_replace( '~[^0-9a-z_]+~', '_', $group );
41
- $group = trim( $group, '_' );
42
-
43
- if ( $group ) {
44
- $enabled = ( isset( $group_config['enabled'] ) ?
45
- (boolean) $group_config['enabled'] : false );
46
- $cache = ( isset( $group_config['cache'] ) ?
47
- (boolean) $group_config['cache'] : false );
48
- $cookies = ( isset( $group_config['cookies'] ) ?
49
- explode( "\r\n", trim( $group_config['cookies'] ) ) :
50
- array() );
51
-
52
- $cookies = array_unique( $cookies );
53
- sort( $cookies );
54
-
55
- $cookiegroups[$group] = array(
56
- 'enabled' => $enabled,
57
- 'cache' => $cache,
58
- 'cookies' => $cookies
59
- );
60
- }
61
- }
62
-
63
- /**
64
- * Allow plugins modify W3TC mobile groups
65
- */
66
- $cookiegroups = apply_filters( 'w3tc_pgcache_cookiegroups', $cookiegroups );
67
-
68
- $enabled = false;
69
- foreach ( $cookiegroups as $group_config ) {
70
- if ( $group_config['enabled'] ) {
71
- $enabled = true;
72
- break;
73
- }
74
- }
75
- $config->set( 'pgcache.cookiegroups.enabled', $enabled );
76
- $config->set( 'pgcache.cookiegroups.groups', $cookiegroups );
77
- }
78
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
PgCache_Page_CookieGroups_View.js DELETED
@@ -1,96 +0,0 @@
1
- jQuery(function() {
2
-
3
-
4
- function w3tc_cookiegroups_clear() {
5
- if (!jQuery('#cookiegroups li').length) {
6
- jQuery('#cookiegroups_empty').show();
7
- } else {
8
- jQuery('#cookiegroups_empty').hide();
9
- }
10
- }
11
-
12
-
13
-
14
- jQuery('#w3tc_cookiegroup_add').click(function() {
15
- var group = prompt('Enter group name (only "0-9", "a-z", "_" symbols are allowed).');
16
-
17
- if (group !== null) {
18
- group = group.toLowerCase();
19
- group = group.replace(/[^0-9a-z_]+/g, '_');
20
- group = group.replace(/^_+/, '');
21
- group = group.replace(/_+$/, '');
22
-
23
- if (group) {
24
- var exists = false;
25
-
26
- jQuery('.cookiegroup_name').each(function() {
27
- if (jQuery(this).html() == group) {
28
- alert('Group already exists!');
29
- exists = true;
30
- return false;
31
- }
32
- });
33
-
34
- if (!exists) {
35
- var li = jQuery('<li id="cookiegroup_' + group + '">' +
36
- '<table class="form-table">' +
37
- '<tr>' +
38
- '<th>Group name:</th>' +
39
- '<td><span class="cookiegroup_number">' + (jQuery('#cookiegroups li').length + 1) + '.</span> ' +
40
- '<span class="cookiegroup_name">' + group + '</span> ' +
41
- '<input type="button" class="button cookiegroup_delete" value="Delete group" /></td>' +
42
- '</tr>' +
43
- '<tr>' +
44
- '<th><label for="cookiegroup_' + group + '_enabled">Enabled:</label></th>' +
45
- '<td>' +
46
- '<input id="cookiegroup_' + group + '_enabled" type="checkbox" name="cookiegroups[' +
47
- group + '][enabled]" value="1" checked="checked" /></td>' +
48
- '</tr>' +
49
- '<tr>' +
50
- '<th><label for="cookiegroup_' + group + '_cache">Cache:</label></th>' +
51
- '<td>' +
52
- '<input id="cookiegroup_' + group + '_cache" type="checkbox" name="cookiegroups[' +
53
- group + '][cache]" value="1" checked="checked" /></td></tr>' +
54
- '<tr>' +
55
- '<th><label for="cookiegroups_' + group + '_cookies">Cookies:</label></th>' +
56
- '<td><textarea id="cookiegroups_' + group + '_cookies" name="cookiegroups[' +
57
- group + '][cookies]" rows="10" cols="50"></textarea>' +
58
- '<p class="description">Specify the cookies for this group. Values like \'cookie\', \'cookie=value\', and cookie[a-z]+=value[a-z]+are supported. Remember to escape special characters like spaces, dots or dashes with a backslash. Regular expressions are also supported.</p></td></tr>' +
59
- '</table></li>');
60
- var select = li.find('select');
61
-
62
- jQuery('#cookiegroups').append(li);
63
- w3tc_cookiegroups_clear();
64
- window.location.hash = '#cookiegroup_' + group;
65
- li.find('textarea').focus();
66
- }
67
- } else {
68
- alert('Empty group name!');
69
- }
70
- }
71
- });
72
-
73
- jQuery('.w3tc_cookiegroup_delete').on('click', function () {
74
- if (confirm('Are you sure want to delete this group?')) {
75
- jQuery(this).parents('#cookiegroups li').remove();
76
- w3tc_cookiegroups_clear();
77
- w3tc_beforeupload_bind();
78
- }
79
- });
80
-
81
- w3tc_cookiegroups_clear();
82
-
83
- // add sortable
84
- if (jQuery.ui && jQuery.ui.sortable) {
85
- jQuery('#cookiegroups').sortable({
86
- axis: 'y',
87
- stop: function() {
88
- jQuery('#cookiegroups').find('.cookiegroup_number').each(function(index) {
89
- jQuery(this).html((index + 1) + '.');
90
- });
91
- }
92
- });
93
- }
94
-
95
-
96
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
PgCache_Page_CookieGroups_View.php DELETED
@@ -1,112 +0,0 @@
1
- <?php
2
- namespace W3TC;
3
-
4
- if ( !defined( 'W3TC' ) )
5
- die();
6
-
7
- ?>
8
-
9
- <p>
10
- <?php _e( 'Cookie group support is always <span class="w3tc-enabled">enabled</span>.', 'w3-total-cache' ); ?>
11
- </p>
12
-
13
- <form action="admin.php?page=w3tc_pgcache_cookiegroups" method="post">
14
- <div class="metabox-holder">
15
- <?php Util_Ui::postbox_header( __( 'Manage Cookie Groups', 'w3-total-cache' ), '', 'manage' ); ?>
16
- <p>
17
- <input id="w3tc_cookiegroup_add" type="button" class="button"
18
- <?php disabled( $groups['disabled'] ) ?>
19
- value="<?php _e( 'Create a group', 'w3-total-cache' ); ?>" />
20
- <?php _e( 'of Cookies by specifying names in the Cookies field. Assign a set of Cookies to ensure that a unique cache is created for each Cookie group. Drag and drop groups into order (if needed) to determine their priority (top -&gt; down).', 'w3-total-cache' ); ?>
21
- </p>
22
-
23
- <ul id="cookiegroups" class="w3tc_cachegroups">
24
- <?php $index = 0; foreach ( $groups['value'] as $group => $group_config ): $index++; ?>
25
- <li id="cookiegroup_<?php echo esc_attr( $group ); ?>">
26
- <table class="form-table">
27
- <tr>
28
- <th>
29
- <?php _e( 'Group name:', 'w3-total-cache' ); ?>
30
- </th>
31
- <td>
32
- <span class="cookiegroup_number"><?php echo $index; ?>.</span>
33
- <span class="cookiegroup_name"><?php echo htmlspecialchars( $group ); ?></span>
34
- <input type="button" class="button w3tc_cookiegroup_delete"
35
- value="Delete group"
36
- <?php disabled( $groups['disabled'] ) ?> />
37
- </td>
38
- </tr>
39
- <tr>
40
- <th>
41
- <label for="cookiegroup_<?php echo esc_attr( $group ); ?>_enabled">
42
- <?php _e( 'Enabled:', 'w3-total-cache' ); ?>
43
- </label>
44
- </th>
45
- <td>
46
- <input id="cookiegroup_<?php echo esc_attr( $group ); ?>_enabled"
47
- type="checkbox"
48
- name="cookiegroups[<?php echo esc_attr( $group ); ?>][enabled]"
49
- <?php disabled( $groups['disabled'] ) ?> value="1"
50
- <?php checked( $group_config['enabled'], true ); ?> />
51
- </td>
52
- </tr>
53
- <tr>
54
- <th>
55
- <label for="cookiegroup_<?php echo esc_attr( $group ); ?>_cache">
56
- <?php _e( 'Cache:', 'w3-total-cache' ); ?>
57
- </label>
58
- </th>
59
- <td>
60
- <input id="cookiegroup_<?php echo esc_attr( $group ); ?>_cache"
61
- type="checkbox"
62
- name="cookiegroups[<?php echo esc_attr( $group ); ?>][cache]"
63
- <?php disabled( $groups['disabled'] ) ?> value="1"
64
- <?php checked( $group_config['cache'], true ); ?> />
65
- </td>
66
- </tr>
67
- <tr>
68
- <th>
69
- <label for="cookiegroup_<?php echo esc_attr( $group ); ?>_cookies">
70
- <?php _e( 'Cookies:', 'w3-total-cache' ); ?>
71
- </label>
72
- </th>
73
- <td>
74
- <textarea id="cookiegroup_<?php echo esc_attr( $group ); ?>_cookies"
75
- name="cookiegroups[<?php echo esc_attr( $group ); ?>][cookies]"
76
- rows="10" cols="50" <?php disabled( $groups['disabled'] ) ?>><?php echo esc_textarea( implode( "\r\n", (array) $group_config['cookies'] ) ); ?></textarea>
77
- <p class="description">
78
- <?php _e( 'Specify the cookies for this group. Values like \'cookie\', \'cookie=value\', and cookie[a-z]+=value[a-z]+ are supported. Remember to escape special characters like spaces, dots or dashes with a backslash. Regular expressions are also supported.', 'w3-total-cache' ); ?>
79
- </p>
80
- </td>
81
- </tr>
82
- </table>
83
- </li>
84
- <?php endforeach; ?>
85
- </ul>
86
- <div id="cookiegroups_empty" style="display: none;"><?php _e( 'No groups added. All Cookies recieve the same page and minify cache results.', 'w3-total-cache' ) ?></div>
87
-
88
- <?php
89
- if ( !$groups['disabled'] )
90
- Util_Ui::button_config_save( 'pgcache_cookiegroups' );
91
- Util_Ui::postbox_footer();
92
-
93
- Util_Ui::postbox_header( __( 'Note(s):', 'w3-total-cache' ), '',
94
- 'notes' );
95
- ?>
96
- <table class="form-table">
97
- <tr>
98
- <th colspan="2">
99
- <ul>
100
- <li>
101
- <?php _e( 'Content is cached for each group separately.', 'w3-total-cache' ) ?>
102
- </li>
103
- <li>
104
- <?php _e( 'Per the above, make sure that visitors are notified about the cookie as per any regulations in your market.', 'w3-total-cache' ) ?>
105
- </li>
106
- </ul>
107
- </th>
108
- </tr>
109
- </table>
110
- <?php Util_Ui::postbox_footer(); ?>
111
- </div>
112
- </form>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
PgCache_Plugin_Admin.php CHANGED
@@ -36,29 +36,21 @@ class PgCache_Plugin_Admin {
36
  $this, 'w3tc_usage_statistics_summary_from_history' ), 10, 2 );
37
  }
38
 
39
- add_filter( 'w3tc_admin_menu', array( $this, 'w3tc_admin_menu' ) );
40
-
41
  add_action( 'admin_print_scripts-performance_page_w3tc_pgcache', array(
42
  '\W3TC\PgCache_Page',
43
  'admin_print_scripts_w3tc_pgcache'
44
  ) );
45
 
46
- // cookie groups
47
- add_action( 'admin_init_w3tc_pgcache_cookiegroups', array(
48
- '\W3TC\PgCache_Page_CookieGroups',
49
- 'admin_init_w3tc_pgcache_cookiegroups'
50
- ) );
51
-
52
- add_action( 'w3tc_settings_page-w3tc_pgcache_cookiegroups', array(
53
- '\W3TC\PgCache_Page_CookieGroups',
54
- 'w3tc_settings_page_w3tc_pgcache_cookiegroups'
55
- ) );
56
-
57
- add_action( 'w3tc_config_ui_save-w3tc_pgcache_cookiegroups', array(
58
- '\W3TC\PgCache_Page_CookieGroups',
59
- 'w3tc_config_ui_save_w3tc_pgcache_cookiegroups'
60
- ), 10, 1 );
61
-
62
  }
63
 
64
  function cleanup() {
@@ -308,17 +300,6 @@ class PgCache_Plugin_Admin {
308
  return $errors;
309
  }
310
 
311
- public function w3tc_admin_menu( $menu ) {
312
- $menu['w3tc_pgcache_cookiegroups'] = array(
313
- 'page_title' => __( 'Cookie Groups', 'w3-total-cache' ),
314
- 'menu_text' => __( 'Cookie Groups', 'w3-total-cache' ),
315
- 'visible_always' => false,
316
- 'order' => 950
317
- );
318
-
319
- return $menu;
320
- }
321
-
322
  public function w3tc_usage_statistics_summary_from_history( $summary, $history ) {
323
  // total size
324
  $g = Dispatcher::component( 'PgCache_ContentGrabber' );
36
  $this, 'w3tc_usage_statistics_summary_from_history' ), 10, 2 );
37
  }
38
 
 
 
39
  add_action( 'admin_print_scripts-performance_page_w3tc_pgcache', array(
40
  '\W3TC\PgCache_Page',
41
  'admin_print_scripts_w3tc_pgcache'
42
  ) );
43
 
44
+ // Cache groups.
45
+ add_action(
46
+ 'w3tc_config_ui_save-w3tc_cachegroups',
47
+ array(
48
+ '\W3TC\CacheGroups_Plugin_Admin',
49
+ 'w3tc_config_ui_save_w3tc_cachegroups',
50
+ ),
51
+ 10,
52
+ 1
53
+ );
 
 
 
 
 
 
54
  }
55
 
56
  function cleanup() {
300
  return $errors;
301
  }
302
 
 
 
 
 
 
 
 
 
 
 
 
303
  public function w3tc_usage_statistics_summary_from_history( $summary, $history ) {
304
  // total size
305
  $g = Dispatcher::component( 'PgCache_ContentGrabber' );
Root_AdminMenu.php CHANGED
@@ -1,265 +1,307 @@
1
  <?php
 
 
 
 
 
 
2
  namespace W3TC;
3
 
4
  /**
5
- * W3 Total Cache Root_AdminMenu
6
  */
7
-
8
  class Root_AdminMenu {
9
-
10
  /**
11
  * Current page
12
  *
13
  * @var string
14
  */
15
- protected $_page = 'w3tc_dashboard';
16
 
17
- private $_config;
 
 
 
 
 
18
 
19
- function __construct() {
 
 
 
20
  $this->_config = Dispatcher::config();
21
  }
22
 
23
- function generate_menu_array() {
 
 
 
 
 
24
  $pages = array(
25
- 'w3tc_dashboard' => array(
26
- 'page_title' => __( 'Dashboard', 'w3-total-cache' ),
27
- 'menu_text' => __( 'Dashboard', 'w3-total-cache' ),
28
  'visible_always' => true,
29
- 'order' => 100
30
  ),
31
- 'w3tc_general' => array(
32
- 'page_title' => __( 'General Settings', 'w3-total-cache' ),
33
- 'menu_text' => __( 'General Settings', 'w3-total-cache' ),
34
  'visible_always' => false,
35
- 'order' => 200
36
  ),
37
- 'w3tc_pgcache' => array(
38
- 'page_title' => __( 'Page Cache', 'w3-total-cache' ),
39
- 'menu_text' => __( 'Page Cache', 'w3-total-cache' ),
40
  'visible_always' => false,
41
- 'order' => 300
42
  ),
43
- 'w3tc_minify' => array(
44
- 'page_title' => __( 'Minify', 'w3-total-cache' ),
45
- 'menu_text' => __( 'Minify', 'w3-total-cache' ),
46
  'visible_always' => false,
47
- 'order' => 400
48
  ),
49
- 'w3tc_dbcache' => array(
50
- 'page_title' => __( 'Database Cache', 'w3-total-cache' ),
51
- 'menu_text' => __( 'Database Cache', 'w3-total-cache' ),
52
  'visible_always' => false,
53
- 'order' => 500
54
  ),
55
- 'w3tc_objectcache' => array(
56
- 'page_title' => __( 'Object Cache', 'w3-total-cache' ),
57
- 'menu_text' => __( 'Object Cache', 'w3-total-cache' ),
58
  'visible_always' => false,
59
- 'order' => 600
60
  ),
61
- 'w3tc_browsercache' => array(
62
- 'page_title' => __( 'Browser Cache', 'w3-total-cache' ),
63
- 'menu_text' => __( 'Browser Cache', 'w3-total-cache' ),
64
  'visible_always' => false,
65
- 'order' => 700
66
  ),
67
- 'w3tc_mobile' => array(
68
- 'page_title' => __( 'User Agent Groups', 'w3-total-cache' ),
69
- 'menu_text' => __( 'User Agent Groups', 'w3-total-cache' ),
70
  'visible_always' => false,
71
- 'order' => 800
72
  ),
73
- 'w3tc_referrer' => array(
74
- 'page_title' => __( 'Referrer Groups', 'w3-total-cache' ),
75
- 'menu_text' => __( 'Referrer Groups', 'w3-total-cache' ),
76
  'visible_always' => false,
77
- 'order' => 900
78
  ),
79
- 'w3tc_cdn' => array(
80
- 'page_title' => __( 'Content Delivery Network', 'w3-total-cache' ),
81
- 'menu_text' => __( '<acronym title="Content Delivery Network">CDN</acronym>', 'w3-total-cache' ),
 
 
 
82
  'visible_always' => false,
83
- 'order' => 1000
84
  ),
85
- 'w3tc_faq' => array(
86
- 'page_title' => __( 'FAQ', 'w3-total-cache' ),
87
- 'menu_text' => __( 'FAQ', 'w3-total-cache' ),
88
  'visible_always' => true,
89
- 'order' => 2000,
90
- 'redirect_faq' => '*'
91
  ),
92
- 'w3tc_support' => array(
93
- 'page_title' => __( 'Support', 'w3-total-cache' ),
94
- 'menu_text' => __( '<span style="color: red;">Support</span>', 'w3-total-cache' ),
95
  'visible_always' => true,
96
- 'order' => 2100
97
  ),
98
- 'w3tc_install' => array(
99
- 'page_title' => __( 'Install', 'w3-total-cache' ),
100
- 'menu_text' => __( 'Install', 'w3-total-cache' ),
101
  'visible_always' => false,
102
- 'order' => 2200
103
  ),
104
- 'w3tc_setup_guide' => array(
105
- 'page_title' => __( 'Setup Guide', 'w3-total-cache' ),
106
- 'menu_text' => __( 'Setup Guide', 'w3-total-cache' ),
107
  'visible_always' => false,
108
- 'order' => 2300
109
  ),
110
- 'w3tc_about' => array(
111
- 'page_title' => __( 'About', 'w3-total-cache' ),
112
- 'menu_text' => __( 'About', 'w3-total-cache' ),
113
  'visible_always' => true,
114
- 'order' => 2400
115
- )
116
  );
 
117
  $pages = apply_filters( 'w3tc_admin_menu', $pages, $this->_config );
118
 
119
  return $pages;
120
  }
121
 
122
- function generate( $base_capability ) {
 
 
 
 
 
 
123
  $pages = $this->generate_menu_array();
124
 
125
- uasort( $pages, function($a, $b) {
126
- return ($a['order'] - $b['order']);
 
 
127
  }
128
  );
129
 
130
- add_menu_page( __( 'Performance', 'w3-total-cache' ),
131
  __( 'Performance', 'w3-total-cache' ),
132
- apply_filters( 'w3tc_capability_menu_w3tc_dashboard',
133
- $base_capability ),
134
- 'w3tc_dashboard', '', 'none' );
 
 
 
 
 
 
135
 
136
- $submenu_pages = array();
137
- $is_master = ( is_network_admin() || !Util_Environment::is_wpmu() );
138
- $remaining_visible = !$this->_config->get_boolean( 'common.force_master' );
139
 
140
  foreach ( $pages as $slug => $titles ) {
141
  if ( $is_master || $titles['visible_always'] || $remaining_visible ) {
142
- $hook = add_submenu_page( 'w3tc_dashboard',
 
143
  $titles['page_title'] . ' | W3 Total Cache',
144
  $titles['menu_text'],
145
- apply_filters( 'w3tc_capability_menu_' . $slug,
146
- $base_capability ),
 
 
147
  $slug,
148
- array( $this, 'options' )
 
 
 
149
  );
 
150
  $submenu_pages[] = $hook;
151
  }
152
  }
 
153
  return $submenu_pages;
154
  }
155
 
156
  /**
157
- * Options page
158
- *
159
- * @return void
160
  */
161
- function options() {
162
  $this->_page = Util_Request::get_string( 'page' );
163
- if ( !Util_Admin::is_w3tc_admin_page() )
 
164
  $this->_page = 'w3tc_dashboard';
 
165
 
166
  /*
167
- * Hidden pages
168
  */
169
- if ( isset( $_REQUEST['w3tc_dbcluster_config'] ) ) {
170
  $options_dbcache = new DbCache_Page();
171
  $options_dbcache->dbcluster_config();
172
  }
173
 
174
  /**
175
- * Show tab
176
  */
177
  switch ( $this->_page ) {
178
- case 'w3tc_dashboard':
179
- $options_dashboard = new Generic_Page_Dashboard();
180
- $options_dashboard->options();
181
- break;
182
-
183
- case 'w3tc_general':
184
- $options_general = new Generic_Page_General();
185
- $options_general->options();
186
- break;
187
-
188
- case 'w3tc_pgcache':
189
- $options_pgcache = new PgCache_Page();
190
- $options_pgcache->options();
191
- break;
192
-
193
- case 'w3tc_minify':
194
- $options_minify = new Minify_Page();
195
- $options_minify->options();
196
- break;
197
-
198
- case 'w3tc_dbcache':
199
- $options_dbcache = new DbCache_Page();
200
- $options_dbcache->options();
201
- break;
202
-
203
- case 'w3tc_objectcache':
204
- $options_objectcache = new ObjectCache_Page();
205
- $options_objectcache->options();
206
- break;
207
-
208
- case 'w3tc_browsercache':
209
- $options_browsercache = new BrowserCache_Page();
210
- $options_browsercache->options();
211
- break;
212
-
213
- case 'w3tc_mobile':
214
- $options_mobile = new Mobile_Page_UserAgentGroups();
215
- $options_mobile->options();
216
- break;
217
-
218
- case 'w3tc_referrer':
219
- $options_referrer = new Mobile_Page_ReferrerGroups();
220
- $options_referrer->options();
221
- break;
222
-
223
- case 'w3tc_cdn':
224
- $options_cdn = new Cdn_Page();
225
- $options_cdn->options();
226
- break;
227
-
228
- case 'w3tc_stats':
229
- $p = new UsageStatistics_Page();
230
- $p->render();
231
- break;
232
-
233
- case 'w3tc_support':
234
- $options_support = new Support_Page();
235
- $options_support->options();
236
- break;
237
-
238
- case 'w3tc_install':
239
- $options_install = new Generic_Page_Install();
240
- $options_install->options();
241
- break;
242
-
243
- case 'w3tc_setup_guide':
244
- $setup_guide = new SetupGuide_Plugin_Admin();
245
- $setup_guide->load();
246
- break;
247
-
248
- case 'w3tc_about':
249
- $options_about = new Generic_Page_About();
250
- $options_about->options();
251
- break;
252
- default:
253
- // placeholder to make it the only way to show pages
254
- // with the time
255
- $view = new Base_Page_Settings();
256
- $view->options();
257
-
258
- do_action( "w3tc_settings_page-{$this->_page}" );
259
-
260
- $view->render_footer();
261
-
262
- break;
263
  }
264
  }
265
  }
1
  <?php
2
+ /**
3
+ * File: Root_AdminMenu.php
4
+ *
5
+ * @package W3TC
6
+ */
7
+
8
  namespace W3TC;
9
 
10
  /**
11
+ * Class: Root_AdminMenu
12
  */
 
13
  class Root_AdminMenu {
 
14
  /**
15
  * Current page
16
  *
17
  * @var string
18
  */
19
+ protected $_page = 'w3tc_dashboard'; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
20
 
21
+ /**
22
+ * Config.
23
+ *
24
+ * @var array
25
+ */
26
+ private $_config; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
27
 
28
+ /**
29
+ * Constructor.
30
+ */
31
+ public function __construct() {
32
  $this->_config = Dispatcher::config();
33
  }
34
 
35
+ /**
36
+ * Generate menu array.
37
+ *
38
+ * @return array
39
+ */
40
+ public function generate_menu_array() {
41
  $pages = array(
42
+ 'w3tc_dashboard' => array(
43
+ 'page_title' => __( 'Dashboard', 'w3-total-cache' ),
44
+ 'menu_text' => __( 'Dashboard', 'w3-total-cache' ),
45
  'visible_always' => true,
46
+ 'order' => 100,
47
  ),
48
+ 'w3tc_feature_showcase' => array(
49
+ 'page_title' => __( 'Feature Showcase', 'w3-total-cache' ),
50
+ 'menu_text' => __( 'Feature Showcase', 'w3-total-cache' ),
51
  'visible_always' => false,
52
+ 'order' => 200,
53
  ),
54
+ 'w3tc_general' => array(
55
+ 'page_title' => __( 'General Settings', 'w3-total-cache' ),
56
+ 'menu_text' => __( 'General Settings', 'w3-total-cache' ),
57
  'visible_always' => false,
58
+ 'order' => 300,
59
  ),
60
+ 'w3tc_pgcache' => array(
61
+ 'page_title' => __( 'Page Cache', 'w3-total-cache' ),
62
+ 'menu_text' => __( 'Page Cache', 'w3-total-cache' ),
63
  'visible_always' => false,
64
+ 'order' => 400,
65
  ),
66
+ 'w3tc_minify' => array(
67
+ 'page_title' => __( 'Minify', 'w3-total-cache' ),
68
+ 'menu_text' => __( 'Minify', 'w3-total-cache' ),
69
  'visible_always' => false,
70
+ 'order' => 500,
71
  ),
72
+ 'w3tc_dbcache' => array(
73
+ 'page_title' => __( 'Database Cache', 'w3-total-cache' ),
74
+ 'menu_text' => __( 'Database Cache', 'w3-total-cache' ),
75
  'visible_always' => false,
76
+ 'order' => 600,
77
  ),
78
+ 'w3tc_objectcache' => array(
79
+ 'page_title' => __( 'Object Cache', 'w3-total-cache' ),
80
+ 'menu_text' => __( 'Object Cache', 'w3-total-cache' ),
81
  'visible_always' => false,
82
+ 'order' => 700,
83
  ),
84
+ 'w3tc_browsercache' => array(
85
+ 'page_title' => __( 'Browser Cache', 'w3-total-cache' ),
86
+ 'menu_text' => __( 'Browser Cache', 'w3-total-cache' ),
87
  'visible_always' => false,
88
+ 'order' => 800,
89
  ),
90
+ 'w3tc_cachegroups' => array(
91
+ 'page_title' => __( 'Cache Groups', 'w3-total-cache' ),
92
+ 'menu_text' => __( 'Cache Groups', 'w3-total-cache' ),
93
  'visible_always' => false,
94
+ 'order' => 900,
95
  ),
96
+ 'w3tc_cdn' => array(
97
+ 'page_title' => __( 'Content Delivery Network', 'w3-total-cache' ),
98
+ 'menu_text' => sprintf(
99
+ '<acronym title="%1$s">CDN</acronym>',
100
+ __( 'Content Delivery Network', 'w3-total-cache' )
101
+ ),
102
  'visible_always' => false,
103
+ 'order' => 1000,
104
  ),
105
+ 'w3tc_faq' => array(
106
+ 'page_title' => __( 'FAQ', 'w3-total-cache' ),
107
+ 'menu_text' => __( 'FAQ', 'w3-total-cache' ),
108
  'visible_always' => true,
109
+ 'order' => 1100,
110
+ 'redirect_faq' => '*',
111
  ),
112
+ 'w3tc_support' => array(
113
+ 'page_title' => __( 'Support', 'w3-total-cache' ),
114
+ 'menu_text' => __( 'Support', 'w3-total-cache' ),
115
  'visible_always' => true,
116
+ 'order' => 1200,
117
  ),
118
+ 'w3tc_install' => array(
119
+ 'page_title' => __( 'Install', 'w3-total-cache' ),
120
+ 'menu_text' => __( 'Install', 'w3-total-cache' ),
121
  'visible_always' => false,
122
+ 'order' => 1300,
123
  ),
124
+ 'w3tc_setup_guide' => array(
125
+ 'page_title' => __( 'Setup Guide', 'w3-total-cache' ),
126
+ 'menu_text' => __( 'Setup Guide', 'w3-total-cache' ),
127
  'visible_always' => false,
128
+ 'order' => 1400,
129
  ),
130
+ 'w3tc_about' => array(
131
+ 'page_title' => __( 'About', 'w3-total-cache' ),
132
+ 'menu_text' => __( 'About', 'w3-total-cache' ),
133
  'visible_always' => true,
134
+ 'order' => 1500,
135
+ ),
136
  );
137
+
138
  $pages = apply_filters( 'w3tc_admin_menu', $pages, $this->_config );
139
 
140
  return $pages;
141
  }
142
 
143
+ /**
144
+ * Generate menu.
145
+ *
146
+ * @param string $base_capability Base compatibility.
147
+ * @return array
148
+ */
149
+ public function generate( $base_capability ) {
150
  $pages = $this->generate_menu_array();
151
 
152
+ uasort(
153
+ $pages,
154
+ function( $a, $b ) {
155
+ return ( $a['order'] - $b['order'] );
156
  }
157
  );
158
 
159
+ add_menu_page(
160
  __( 'Performance', 'w3-total-cache' ),
161
+ __( 'Performance', 'w3-total-cache' ),
162
+ apply_filters(
163
+ 'w3tc_capability_menu_w3tc_dashboard',
164
+ $base_capability
165
+ ),
166
+ 'w3tc_dashboard',
167
+ '',
168
+ 'none'
169
+ );
170
 
171
+ $submenu_pages = array();
172
+ $is_master = ( is_network_admin() || ! Util_Environment::is_wpmu() );
173
+ $remaining_visible = ! $this->_config->get_boolean( 'common.force_master' );
174
 
175
  foreach ( $pages as $slug => $titles ) {
176
  if ( $is_master || $titles['visible_always'] || $remaining_visible ) {
177
+ $hook = add_submenu_page(
178
+ 'w3tc_dashboard',
179
  $titles['page_title'] . ' | W3 Total Cache',
180
  $titles['menu_text'],
181
+ apply_filters(
182
+ 'w3tc_capability_menu_' . $slug,
183
+ $base_capability
184
+ ),
185
  $slug,
186
+ array(
187
+ $this,
188
+ 'options',
189
+ )
190
  );
191
+
192
  $submenu_pages[] = $hook;
193
  }
194
  }
195
+
196
  return $submenu_pages;
197
  }
198
 
199
  /**
200
+ * Options page.
 
 
201
  */
202
+ public function options() {
203
  $this->_page = Util_Request::get_string( 'page' );
204
+
205
+ if ( ! Util_Admin::is_w3tc_admin_page() ) {
206
  $this->_page = 'w3tc_dashboard';
207
+ }
208
 
209
  /*
210
+ * Hidden pages.
211
  */
212
+ if ( isset( $_REQUEST['w3tc_dbcluster_config'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
213
  $options_dbcache = new DbCache_Page();
214
  $options_dbcache->dbcluster_config();
215
  }
216
 
217
  /**
218
+ * Show tab.
219
  */
220
  switch ( $this->_page ) {
221
+ case 'w3tc_dashboard':
222
+ $options_dashboard = new Generic_Page_Dashboard();
223
+ $options_dashboard->options();
224
+ break;
225
+
226
+ case 'w3tc_general':
227
+ $options_general = new Generic_Page_General();
228
+ $options_general->options();
229
+ break;
230
+
231
+ case 'w3tc_pgcache':
232
+ $options_pgcache = new PgCache_Page();
233
+ $options_pgcache->options();
234
+ break;
235
+
236
+ case 'w3tc_minify':
237
+ $options_minify = new Minify_Page();
238
+ $options_minify->options();
239
+ break;
240
+
241
+ case 'w3tc_dbcache':
242
+ $options_dbcache = new DbCache_Page();
243
+ $options_dbcache->options();
244
+ break;
245
+
246
+ case 'w3tc_objectcache':
247
+ $options_objectcache = new ObjectCache_Page();
248
+ $options_objectcache->options();
249
+ break;
250
+
251
+ case 'w3tc_browsercache':
252
+ $options_browsercache = new BrowserCache_Page();
253
+ $options_browsercache->options();
254
+ break;
255
+
256
+ case 'w3tc_cachegroups':
257
+ $options_cachegroups = new CacheGroups_Plugin_Admin();
258
+ $options_cachegroups->options();
259
+ break;
260
+
261
+ case 'w3tc_cdn':
262
+ $options_cdn = new Cdn_Page();
263
+ $options_cdn->options();
264
+ break;
265
+
266
+ case 'w3tc_stats':
267
+ $p = new UsageStatistics_Page();
268
+ $p->render();
269
+ break;
270
+
271
+ case 'w3tc_support':
272
+ $options_support = new Support_Page();
273
+ $options_support->options();
274
+ break;
275
+
276
+ case 'w3tc_install':
277
+ $options_install = new Generic_Page_Install();
278
+ $options_install->options();
279
+ break;
280
+
281
+ case 'w3tc_setup_guide':
282
+ $setup_guide = new SetupGuide_Plugin_Admin();
283
+ $setup_guide->load();
284
+ break;
285
+
286
+ case 'w3tc_feature_showcase':
287
+ $feature_showcase = new FeatureShowcase_Plugin_Admin();
288
+ $feature_showcase->load();
289
+ break;
290
+
291
+ case 'w3tc_about':
292
+ $options_about = new Generic_Page_About();
293
+ $options_about->options();
294
+ break;
295
+ default:
296
+ // Placeholder to make it the only way to show pages with the time.
297
+ $view = new Base_Page_Settings();
298
+ $view->options();
299
+
300
+ do_action( 'w3tc_settings_page-' . $this->_page ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
301
+
302
+ $view->render_footer();
303
+
304
+ break;
 
305
  }
306
  }
307
  }
Root_Loader.php CHANGED
@@ -76,6 +76,7 @@ class Root_Loader {
76
  $plugins[] = new Generic_Plugin_AdminNotifications();
77
  $plugins[] = new UsageStatistics_Plugin_Admin();
78
  $plugins[] = new SetupGuide_Plugin_Admin();
 
79
  } else {
80
  if ( $c->get_boolean( 'jquerymigrate.disabled' ) ) {
81
  $plugins[] = new UserExperience_Plugin_Jquery();
76
  $plugins[] = new Generic_Plugin_AdminNotifications();
77
  $plugins[] = new UsageStatistics_Plugin_Admin();
78
  $plugins[] = new SetupGuide_Plugin_Admin();
79
+ $plugins[] = new FeatureShowcase_Plugin_Admin();
80
  } else {
81
  if ( $c->get_boolean( 'jquerymigrate.disabled' ) ) {
82
  $plugins[] = new UserExperience_Plugin_Jquery();
SetupGuide_Plugin_Admin.php CHANGED
@@ -38,10 +38,16 @@ class SetupGuide_Plugin_Admin {
38
  * @since 2.0.0
39
  */
40
  public function __construct() {
41
- require_once W3TC_INC_DIR . '/wizard/template.php';
 
 
42
 
43
- if ( is_null( self::$template ) ) {
44
- self::$template = new Wizard\Template( $this->get_config() );
 
 
 
 
45
  }
46
  }
47
 
@@ -1298,10 +1304,21 @@ class SetupGuide_Plugin_Admin {
1298
  'headline' => __( 'Setup Complete!', 'w3-total-cache' ),
1299
  'id' => 'complete',
1300
  'markup' => '<p>' .
 
 
 
 
 
 
 
 
 
 
 
1301
  sprintf(
1302
  // translators: 1: HTML strong open tag, 2: HTML strong close tag.
1303
  esc_html__(
1304
- '%1$sTime to First Byte%2$s has change by %3$s!',
1305
  'w3-total-cache'
1306
  ),
1307
  '<strong>',
38
  * @since 2.0.0
39
  */
40
  public function __construct() {
41
+ $page = Util_Request::get_string( 'page' );
42
+ $is_w3tc_ajax = defined( 'DOING_AJAX' ) && DOING_AJAX &&
43
+ isset( $_POST['action'] ) && 0 === strpos( $_POST['action'], 'w3tc_' );
44
 
45
+ if ( 'w3tc_setup_guide' === $page || $is_w3tc_ajax ) {
46
+ require_once W3TC_INC_DIR . '/wizard/template.php';
47
+
48
+ if ( is_null( self::$template ) ) {
49
+ self::$template = new Wizard\Template( $this->get_config() );
50
+ }
51
  }
52
  }
53
 
1304
  'headline' => __( 'Setup Complete!', 'w3-total-cache' ),
1305
  'id' => 'complete',
1306
  'markup' => '<p>' .
1307
+ sprintf(
1308
+ // translators: 1: HTML strong open tag, 2: HTML strong close tag, 3: Label.
1309
+ esc_html__(
1310
+ '%1$sPage Cache%2$s engine set to %1$s%3$s%2$s',
1311
+ 'w3-total-cache'
1312
+ ),
1313
+ '<strong>',
1314
+ '</strong>',
1315
+ '<span id="w3tc-pgcache-engine">' . esc_html__( 'UNKNOWN', 'w3-total-cache' ) . '</span>'
1316
+ ) . '</p>
1317
+ <p>' .
1318
  sprintf(
1319
  // translators: 1: HTML strong open tag, 2: HTML strong close tag.
1320
  esc_html__(
1321
+ '%1$sTime to First Byte%2$s has changed by %1$s%3$s%2$s',
1322
  'w3-total-cache'
1323
  ),
1324
  '<strong>',
Util_PageUrls.php CHANGED
@@ -543,14 +543,17 @@ class Util_PageUrls {
543
  }
544
 
545
  /**
546
- * Returns number of posts in the archive
547
  *
548
- * @param int $year
549
- * @param int $month
550
- * @param int $day
 
 
 
551
  * @return int
552
  */
553
- static public function get_archive_posts_count( $year = 0, $month = 0, $day = 0, $post_type/* = 'post'*/ ) {
554
  global $wpdb;
555
 
556
  $filters = array(
543
  }
544
 
545
  /**
546
+ * Returns number of posts in the archive.
547
  *
548
+ * @global $wpdb
549
+ *
550
+ * @param int $year Year.
551
+ * @param int $month Month.
552
+ * @param int $day Day number.
553
+ * @param string $post_type Post type.
554
  * @return int
555
  */
556
+ public static function get_archive_posts_count( $year = 0, $month = 0, $day = 0, $post_type = 'post' ) {
557
  global $wpdb;
558
 
559
  $filters = array(
inc/options/common/header.php CHANGED
@@ -134,23 +134,14 @@ $licensing_visible = ( ( !Util_Environment::is_wpmu() || is_network_admin() ) &&
134
  break;
135
  ?>
136
  <?php
137
- case 'w3tc_mobile':
138
  ?>
139
  <p id="w3tc-options-menu">
140
  <?php _e( 'Jump to: ', 'w3-total-cache' ); ?>
141
  <a href="#toplevel_page_w3tc_general"><?php _e( 'Main Menu', 'w3-total-cache' ); ?></a> |
142
- <a href="#manage"><?php _e( 'Manage User Agent Groups', 'w3-total-cache' ); ?></a>
143
- </p>
144
- <?php
145
- break;
146
- ?>
147
- <?php
148
- case 'w3tc_referrer':
149
- ?>
150
- <p id="w3tc-options-menu">
151
- <?php _e( 'Jump to: ', 'w3-total-cache' ); ?>
152
- <a href="#toplevel_page_w3tc_general"><?php _e( 'Main Menu', 'w3-total-cache' ); ?></a> |
153
- <a href="#manage"><?php _e( 'Manage Referrer Groups', 'w3-total-cache' ); ?></a>
154
  </p>
155
  <?php
156
  break;
134
  break;
135
  ?>
136
  <?php
137
+ case 'w3tc_cachegroups':
138
  ?>
139
  <p id="w3tc-options-menu">
140
  <?php _e( 'Jump to: ', 'w3-total-cache' ); ?>
141
  <a href="#toplevel_page_w3tc_general"><?php _e( 'Main Menu', 'w3-total-cache' ); ?></a> |
142
+ <a href="#manage-uag"><?php _e( 'Manage User Agent Groups', 'w3-total-cache' ); ?></a> |
143
+ <a href="#manage-rg"><?php _e( 'Manage Referrer Groups', 'w3-total-cache' ); ?></a> |
144
+ <a href="#manage-cg"><?php _e( 'Manage Cookie Groups', 'w3-total-cache' ); ?></a>
 
 
 
 
 
 
 
 
 
145
  </p>
146
  <?php
147
  break;
inc/options/install.php CHANGED
@@ -21,7 +21,7 @@ if ( !defined( 'W3TC' ) )
21
  <li><?php _e( '<em>Recommended:</em> If you already have a content delivery network (<acronym title="Content Delivery Network">CDN</acronym>) provider, proceed to the "<a href="admin.php?page=w3tc_cdn">Content Delivery Network</a>" tab and populate the fields and set your preferences. If you do not use the Media Library, you will need to import your images etc into the default locations. Use the Media Library Import Tool on the "Content Delivery Network" tab to perform this task. If you do not have a <acronym title="Content Delivery Network">CDN</acronym> provider, you can still improve your site\'s performance using the "Self-hosted" method. On your own server, create a subdomain and matching <acronym title="Domain Name System">DNS</acronym> Zone record; e.g. static.domain.com and configure <acronym title="File Transfer Protocol">FTP</acronym> options on the "Content Delivery Network" tab accordingly. Be sure to <acronym title="File Transfer Protocol">FTP</acronym> upload the appropriate files, using the available upload buttons.', 'w3-total-cache' ); ?></li>
22
  <li><?php _e( '<em>Optional:</em> On the "<a href="admin.php?page=w3tc_dbcache">Database Cache</a>" tab the recommended settings are preset. If using a shared hosting account use the "disk" method with caution; in either of these cases the response time of the disk may not be fast enough, so this option is disabled by default.', 'w3-total-cache' ); ?></li>
23
  <li><?php _e( '<em>Optional:</em> On the "<a href="admin.php?page=w3tc_objectcache">Object Cache</a>" tab the recommended settings are preset. If using a shared hosting account use the "disk" method with caution, the response time of the disk may not be fast enough, so this option is disabled by default. Test this option with and without database cache to ensure that it provides a performance increase.', 'w3-total-cache' ); ?></li>
24
- <li><?php _e( '<em>Optional:</em> On the "<a href="admin.php?page=w3tc_mobile">User Agent Groups</a>" tab, specify any user agents, like mobile phones if a mobile theme is used.', 'w3-total-cache' ); ?></li>
25
  </ol>
26
 
27
  <p>
21
  <li><?php _e( '<em>Recommended:</em> If you already have a content delivery network (<acronym title="Content Delivery Network">CDN</acronym>) provider, proceed to the "<a href="admin.php?page=w3tc_cdn">Content Delivery Network</a>" tab and populate the fields and set your preferences. If you do not use the Media Library, you will need to import your images etc into the default locations. Use the Media Library Import Tool on the "Content Delivery Network" tab to perform this task. If you do not have a <acronym title="Content Delivery Network">CDN</acronym> provider, you can still improve your site\'s performance using the "Self-hosted" method. On your own server, create a subdomain and matching <acronym title="Domain Name System">DNS</acronym> Zone record; e.g. static.domain.com and configure <acronym title="File Transfer Protocol">FTP</acronym> options on the "Content Delivery Network" tab accordingly. Be sure to <acronym title="File Transfer Protocol">FTP</acronym> upload the appropriate files, using the available upload buttons.', 'w3-total-cache' ); ?></li>
22
  <li><?php _e( '<em>Optional:</em> On the "<a href="admin.php?page=w3tc_dbcache">Database Cache</a>" tab the recommended settings are preset. If using a shared hosting account use the "disk" method with caution; in either of these cases the response time of the disk may not be fast enough, so this option is disabled by default.', 'w3-total-cache' ); ?></li>
23
  <li><?php _e( '<em>Optional:</em> On the "<a href="admin.php?page=w3tc_objectcache">Object Cache</a>" tab the recommended settings are preset. If using a shared hosting account use the "disk" method with caution, the response time of the disk may not be fast enough, so this option is disabled by default. Test this option with and without database cache to ensure that it provides a performance increase.', 'w3-total-cache' ); ?></li>
24
+ <li><?php _e( '<em>Optional:</em> On the "<a href="admin.php?page=w3tc_cachegroups">User Agent Groups</a>" tab, specify any user agents, like mobile phones if a mobile theme is used.', 'w3-total-cache' ); ?></li>
25
  </ol>
26
 
27
  <p>
inc/options/mobile.php DELETED
@@ -1,130 +0,0 @@
1
- <?php
2
- namespace W3TC;
3
-
4
- if ( !defined( 'W3TC' ) )
5
- die();
6
-
7
- ?>
8
- <?php include W3TC_INC_DIR . '/options/common/header.php'; ?>
9
-
10
- <script type="text/javascript">/*<![CDATA[*/
11
- var mobile_themes = {};
12
- <?php foreach ( $themes as $theme_key => $theme_name ): ?>
13
- mobile_themes['<?php echo addslashes( $theme_key ); ?>'] = '<?php echo addslashes( $theme_name ); ?>';
14
- <?php endforeach; ?>
15
- /*]]>*/</script>
16
-
17
- <p>
18
- <?php _e( 'User agent group support is always <span class="w3tc-enabled">enabled</span>.', 'w3-total-cache' ); ?>
19
- </p>
20
-
21
- <form id="mobile_form" action="admin.php?page=<?php echo $this->_page; ?>" method="post">
22
- <div class="metabox-holder">
23
- <?php Util_Ui::postbox_header( __( 'Manage User Agent Groups', 'w3-total-cache' ), '', 'manage' ); ?>
24
- <p>
25
- <input id="mobile_add" type="button" class="button"
26
- <?php disabled( $groups['disabled'] ) ?>
27
- value="<?php _e( 'Create a group', 'w3-total-cache' ); ?>" />
28
- <?php _e( 'of user agents by specifying names in the user agents field. Assign a set of user agents to use a specific theme, redirect them to another domain or if an existing mobile plugin is active, create user agent groups to ensure that a unique cache is created for each user agent group. Drag and drop groups into order (if needed) to determine their priority (top -&gt; down).', 'w3-total-cache' ); ?>
29
- </p>
30
-
31
- <ul id="mobile_groups">
32
- <?php $index = 0; foreach ( $groups['value'] as $group => $group_config ): $index++; ?>
33
- <li id="mobile_group_<?php echo esc_attr( $group ); ?>">
34
- <table class="form-table">
35
- <tr>
36
- <th>
37
- <?php _e( 'Group name:', 'w3-total-cache' ); ?>
38
- </th>
39
- <td>
40
- <span class="mobile_group_number"><?php echo $index; ?>.</span> <span class="mobile_group"><?php echo htmlspecialchars( $group ); ?></span>
41
- <input type="button" class="button mobile_delete"
42
- value="Delete group"
43
- <?php disabled( $groups['disabled'] ) ?> />
44
- </td>
45
- </tr>
46
- <tr>
47
- <th>
48
- <label for="mobile_groups_<?php echo esc_attr( $group ); ?>_enabled"><?php _e( 'Enabled:', 'w3-total-cache' ); ?></label>
49
- </th>
50
- <td>
51
- <input type="hidden" name="mobile_groups[<?php echo esc_attr( $group ); ?>][enabled]" value="0" />
52
- <input id="mobile_groups_<?php echo esc_attr( $group ); ?>_enabled"
53
- type="checkbox"
54
- name="mobile_groups[<?php echo esc_attr( $group ); ?>][enabled]"
55
- <?php disabled( $groups['disabled'] ) ?> value="1"
56
- <?php checked( $group_config['enabled'], true ); ?> />
57
- </td>
58
- </tr>
59
- <tr>
60
- <th>
61
- <label for="mobile_groups_<?php echo esc_attr( $group ); ?>_theme"><?php _e( 'Theme:', 'w3-total-cache' ); ?></label>
62
- </th>
63
- <td>
64
- <select id="mobile_groups_<?php echo esc_attr( $group ); ?>_theme"
65
- name="mobile_groups[<?php echo esc_attr( $group ); ?>][theme]"
66
- <?php disabled( $groups['disabled'] ) ?> >
67
- <option value="">-- Pass-through --</option>
68
- <?php foreach ( $themes as $theme_key => $theme_name ): ?>
69
- <option value="<?php echo esc_attr( $theme_key ); ?>"<?php selected( $theme_key, $group_config['theme'] ); ?>><?php echo htmlspecialchars( $theme_name ); ?></option>
70
- <?php endforeach; ?>
71
- </select>
72
- <p class="description">
73
- <?php _e( 'Assign this group of user agents to a specific theme. Selecting "Pass-through" allows any plugin(s) (e.g. mobile plugins) to properly handle requests for these user agents. If the "redirect users to" field is not empty, this setting is ignored.', 'w3-total-cache' ); ?>
74
- </p>
75
- </td>
76
- </tr>
77
- <tr>
78
- <th>
79
- <label for="mobile_groups_<?php echo esc_attr( $group ); ?>_redirect"><?php _e( 'Redirect users to:', 'w3-total-cache' ) ?></label>
80
- </th>
81
- <td>
82
- <input id="mobile_groups_<?php echo esc_attr( $group ); ?>_redirect"
83
- type="text" name="mobile_groups[<?php echo esc_attr( $group ); ?>][redirect]"
84
- value="<?php echo esc_attr( $group_config['redirect'] ); ?>"
85
- <?php disabled( $groups['disabled'] ) ?>
86
- size="60" />
87
- <p class="description"><?php _e( 'A 302 redirect is used to send this group of users to another hostname (domain); recommended if a 3rd party service provides a mobile version of your site.', 'w3-total-cache' ); ?></p>
88
- </td>
89
- </tr>
90
- <tr>
91
- <th>
92
- <label for="mobile_groups_<?php echo esc_attr( $group ); ?>_agents"><?php _e( 'User agents:', 'w3-total-cache' ); ?></label>
93
- </th>
94
- <td>
95
- <textarea id="mobile_groups_<?php echo esc_attr( $group ); ?>_agents"
96
- name="mobile_groups[<?php echo esc_attr( $group ); ?>][agents]"
97
- rows="10" cols="50" <?php disabled( $groups['disabled'] ) ?>><?php echo esc_textarea( implode( "\r\n", (array) $group_config['agents'] ) ); ?></textarea>
98
- <p class="description">
99
- <?php _e( 'Specify the user agents for this group. Remember to escape special characters like spaces, dots or dashes with a backslash. Regular expressions are also supported.', 'w3-total-cache' ); ?>
100
- </p>
101
- </td>
102
- </tr>
103
- </table>
104
- </li>
105
- <?php endforeach; ?>
106
- </ul>
107
- <div id="mobile_groups_empty" style="display: none;"><?php _e( 'No groups added. All user agents recieve the same page and minify cache results.', 'w3-total-cache' ) ?></div>
108
-
109
- <?php
110
- if ( !$groups['disabled'] )
111
- Util_Ui::button_config_save( 'mobile' );
112
- Util_Ui::postbox_footer();
113
-
114
- Util_Ui::postbox_header( __( 'Note(s):', 'w3-total-cache' ), '',
115
- 'notes' );
116
- ?>
117
- <table class="form-table">
118
- <tr>
119
- <th colspan="2">
120
- <ul>
121
- <?php echo $groups['description'] ?>
122
- </ul>
123
- </th>
124
- </tr>
125
- </table>
126
- <?php Util_Ui::postbox_footer(); ?>
127
- </div>
128
- </form>
129
-
130
- <?php include W3TC_INC_DIR . '/options/common/footer.php'; ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inc/options/referrer.php DELETED
@@ -1,92 +0,0 @@
1
- <?php
2
- namespace W3TC;
3
-
4
- if ( !defined( 'W3TC' ) )
5
- die();
6
-
7
- ?>
8
- <?php include W3TC_INC_DIR . '/options/common/header.php'; ?>
9
-
10
- <script type="text/javascript">/*<![CDATA[*/
11
- var referrer_themes = {};
12
- <?php foreach ( $themes as $theme_key => $theme_name ): ?>
13
- referrer_themes['<?php echo addslashes( $theme_key ); ?>'] = '<?php echo addslashes( $theme_name ); ?>';
14
- <?php endforeach; ?>
15
- /*]]>*/</script>
16
-
17
- <p>
18
- <?php _e( 'Referrer group support is always <span class="w3tc-enabled">enabled', 'w3-total-cache' ); ?></span>.
19
- </p>
20
-
21
- <form id="referrer_form" action="admin.php?page=<?php echo $this->_page; ?>" method="post">
22
- <div class="metabox-holder">
23
- <?php Util_Ui::postbox_header( __( 'Manage Referrer Groups', 'w3-total-cache' ), '', 'manage' ); ?>
24
- <p>
25
- <input id="referrer_add" type="button" class="button" value="<?php _e( 'Create a group', 'w3-total-cache' ); ?>" /> <?php _e( 'of referrers by specifying names in the referrers field. Assign a set of referrers to use a specific theme, redirect them to another domain, create referrer groups to ensure that a unique cache is created for each referrer group. Drag and drop groups into order (if needed) to determine their priority (top -&gt; down).', 'w3-total-cache' ); ?>
26
- </p>
27
-
28
- <ul id="referrer_groups">
29
- <?php $index = 0; foreach ( $groups as $group => $group_config ): $index++; ?>
30
- <li id="referrer_group_<?php echo esc_attr( $group ); ?>">
31
- <table class="form-table">
32
- <tr>
33
- <th>
34
- <?php _e( 'Group name:', 'w3-total-cache' ); ?>
35
- </th>
36
- <td>
37
- <span class="referrer_group_number"><?php echo $index; ?>.</span> <span class="referrer_group"><?php echo htmlspecialchars( $group ); ?></span> <input type="button" class="button referrer_delete" value="<?php _e( 'Delete group', 'w3-total-cache' ); ?>" />
38
- </td>
39
- </tr>
40
- <tr>
41
- <th>
42
- <label for="referrer_groups_<?php echo esc_attr( $group ); ?>_enabled"><?php _e( 'Enabled:', 'w3-total-cache' ); ?></label>
43
- </th>
44
- <td>
45
- <input type="hidden" name="referrer_groups[<?php echo esc_attr( $group ); ?>][enabled]" value="0" />
46
- <input id="referrer_groups_<?php echo esc_attr( $group ); ?>_enabled" type="checkbox" name="referrer_groups[<?php echo esc_attr( $group ); ?>][enabled]" value="1"<?php checked( $group_config['enabled'], true ); ?> />
47
- </td>
48
- </tr>
49
- <tr>
50
- <th>
51
- <label for="referrer_groups_<?php echo esc_attr( $group ); ?>_theme"><?php _e( 'Theme:', 'w3-total-cache' ); ?></label>
52
- </th>
53
- <td>
54
- <select id="referrer_groups_<?php echo esc_attr( $group ); ?>_theme" name="referrer_groups[<?php echo esc_attr( $group ); ?>][theme]">
55
- <option value=""><?php _e( '-- Pass-through --', 'w3-total-cache' ); ?></option>
56
- <?php foreach ( $themes as $theme_key => $theme_name ): ?>
57
- <option value="<?php echo esc_attr( $theme_key ); ?>"<?php selected( $theme_key, $group_config['theme'] ); ?>><?php echo htmlspecialchars( $theme_name ); ?></option>
58
- <?php endforeach; ?>
59
- </select>
60
- <p class="description"><?php _e( 'Assign this group of referrers to a specific theme. Selecting "Pass-through" allows any plugin(s) (e.g. referrer plugins) to properly handle requests for these referrers. If the "redirect users to" field is not empty, this setting is ignored.', 'w3-total-cache' ); ?></p>
61
- </td>
62
- </tr>
63
- <tr>
64
- <th>
65
- <label for="referrer_groups_<?php echo esc_attr( $group ); ?>_redirect"><?php _e( 'Redirect users to:', 'w3-total-cache' ); ?></label>
66
- </th>
67
- <td>
68
- <input id="referrer_groups_<?php echo esc_attr( $group ); ?>_redirect" type="text" name="referrer_groups[<?php echo esc_attr( $group ); ?>][redirect]" value="<?php echo esc_attr( $group_config['redirect'] ); ?>" size="60" />
69
- <p class="description"><?php _e( 'A 302 redirect is used to send this group of referrers to another hostname (domain).', 'w3-total-cache' ); ?></p>
70
- </td>
71
- </tr>
72
- <tr>
73
- <th>
74
- <label for="referrer_groups_<?php echo esc_attr( $group ); ?>_referrers"><?php _e( 'Referrers:', 'w3-total-cache' ); ?></label>
75
- </th>
76
- <td>
77
- <textarea id="referrer_groups_<?php echo esc_attr( $group ); ?>_referrers" name="referrer_groups[<?php echo esc_attr( $group ); ?>][referrers]" rows="10" cols="50"><?php echo esc_textarea( implode( "\r\n", (array) $group_config['referrers'] ) ); ?></textarea>
78
- <p class="description"><?php _e( 'Specify the referrers for this group. Remember to escape special characters like spaces, dots or dashes with a backslash. Regular expressions are also supported.', 'w3-total-cache' ); ?></p>
79
- </td>
80
- </tr>
81
- </table>
82
- </li>
83
- <?php endforeach; ?>
84
- </ul>
85
- <div id="referrer_groups_empty" style="display: none;"><?php _e( 'No groups added. All referrers recieve the same page and minify cache results.', 'w3-total-cache' ); ?></div>
86
-
87
- <?php Util_Ui::button_config_save( 'referrers' ); ?>
88
- <?php Util_Ui::postbox_footer(); ?>
89
- </div>
90
- </form>
91
-
92
- <?php include W3TC_INC_DIR . '/options/common/footer.php'; ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inc/wizard/template.php CHANGED
@@ -51,14 +51,8 @@ class Template {
51
  * Render the wizard.
52
  *
53
  * @since 2.0.0
54
- *
55
- * @see self::enqueue_scripts()
56
- * @see self::enqueue_styles()
57
  */
58
  public function render() {
59
- $this->enqueue_scripts();
60
- $this->enqueue_styles();
61
-
62
  $allowed_html = array(
63
  'a' => array(
64
  'href' => array(),
@@ -189,8 +183,27 @@ class Template {
189
  * Add hooks.
190
  *
191
  * @since 2.0.0
 
 
 
192
  */
193
- private function add_hooks() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  if ( isset( $this->config['actions'] ) && is_array( $this->config['actions'] ) ) {
195
  foreach ( $this->config['actions'] as $action ) {
196
  add_action(
@@ -219,7 +232,7 @@ class Template {
219
  *
220
  * @since 2.0.0
221
  */
222
- private function enqueue_scripts() {
223
  wp_enqueue_script(
224
  'w3tc_wizard',
225
  esc_url( plugin_dir_url( dirname( dirname( __FILE__ ) ) ) . 'pub/js/wizard.js' ),
@@ -228,6 +241,16 @@ class Template {
228
  false
229
  );
230
 
 
 
 
 
 
 
 
 
 
 
231
  if ( isset( $this->config['scripts'] ) && is_array( $this->config['scripts'] ) ) {
232
  foreach ( $this->config['scripts'] as $script ) {
233
  wp_register_script(
@@ -256,12 +279,12 @@ class Template {
256
  *
257
  * @since 2.0.0
258
  */
259
- private function enqueue_styles() {
260
  wp_enqueue_style(
261
  'w3tc_wizard',
262
  esc_url( plugin_dir_url( dirname( dirname( __FILE__ ) ) ) . 'pub/css/wizard.css' ),
263
  array(),
264
- 'all'
265
  );
266
 
267
  if ( isset( $this->config['styles'] ) && is_array( $this->config['styles'] ) ) {
51
  * Render the wizard.
52
  *
53
  * @since 2.0.0
 
 
 
54
  */
55
  public function render() {
 
 
 
56
  $allowed_html = array(
57
  'a' => array(
58
  'href' => array(),
183
  * Add hooks.
184
  *
185
  * @since 2.0.0
186
+ *
187
+ * @see self::enqueue_scripts()
188
+ * @see self::enqueue_styles()
189
  */
190
+ public function add_hooks() {
191
+ add_action(
192
+ 'admin_enqueue_scripts',
193
+ array(
194
+ $this,
195
+ 'enqueue_scripts',
196
+ )
197
+ );
198
+
199
+ add_action(
200
+ 'admin_enqueue_scripts',
201
+ array(
202
+ $this,
203
+ 'enqueue_styles',
204
+ )
205
+ );
206
+
207
  if ( isset( $this->config['actions'] ) && is_array( $this->config['actions'] ) ) {
208
  foreach ( $this->config['actions'] as $action ) {
209
  add_action(
232
  *
233
  * @since 2.0.0
234
  */
235
+ public function enqueue_scripts() {
236
  wp_enqueue_script(
237
  'w3tc_wizard',
238
  esc_url( plugin_dir_url( dirname( dirname( __FILE__ ) ) ) . 'pub/js/wizard.js' ),
241
  false
242
  );
243
 
244
+ wp_localize_script(
245
+ 'w3tc_wizard',
246
+ 'W3TC_Wizard',
247
+ array(
248
+ 'beforeunloadText' => __( 'Are you sure that you want to leve this page?', 'w3-total-cache' ),
249
+ )
250
+ );
251
+
252
+ wp_enqueue_script( 'w3tc_wizard' );
253
+
254
  if ( isset( $this->config['scripts'] ) && is_array( $this->config['scripts'] ) ) {
255
  foreach ( $this->config['scripts'] as $script ) {
256
  wp_register_script(
279
  *
280
  * @since 2.0.0
281
  */
282
+ public function enqueue_styles() {
283
  wp_enqueue_style(
284
  'w3tc_wizard',
285
  esc_url( plugin_dir_url( dirname( dirname( __FILE__ ) ) ) . 'pub/css/wizard.css' ),
286
  array(),
287
+ W3TC_VERSION
288
  );
289
 
290
  if ( isset( $this->config['styles'] ) && is_array( $this->config['styles'] ) ) {
lib/CSSTidy/class.csstidy.php CHANGED
@@ -32,48 +32,24 @@
32
  * @author Mark Scherer (remove $GLOBALS once and for all + PHP5.4 comp) 2012
33
  */
34
 
35
- /**
36
- * Defines ctype functions if required.
37
- *
38
- * @TODO: Make these methods of CSSTidy.
39
- * @since 1.0.0
40
- */
41
- if (!function_exists('ctype_space')){
42
- /* ctype_space Check for whitespace character(s) */
43
- function ctype_space($text){
44
- return (1===preg_match("/^[ \r\n\t\f]+$/", $text));
45
- }
46
- }
47
- if (!function_exists('ctype_alpha')){
48
- /* ctype_alpha Check for alphabetic character(s) */
49
- function ctype_alpha($text){
50
- return (1===preg_match('/^[a-zA-Z]+$/', $text));
51
- }
52
- }
53
- if (!function_exists('ctype_xdigit')){
54
- /* ctype_xdigit Check for HEX character(s) */
55
- function ctype_xdigit($text){
56
- return (1===preg_match('/^[a-fA-F0-9]+$/', $text));
57
- }
58
- }
59
-
60
  /**
61
  * Defines constants
62
  * @todo //TODO: make them class constants of csstidy
63
  */
64
- define('AT_START', 1);
65
- define('AT_END', 2);
66
- define('SEL_START', 3);
67
- define('SEL_END', 4);
68
- define('PROPERTY', 5);
69
- define('VALUE', 6);
70
- define('COMMENT', 7);
71
- define('DEFAULT_AT', 41);
 
72
 
73
  /**
74
  * Contains a class for printing CSS code
75
  *
76
- * @version 1.0
77
  */
78
  require('class.csstidy_print.php');
79
 
@@ -94,7 +70,7 @@ require('class.csstidy_optimise.php');
94
  * An online version should be available here: http://cdburnerxp.se/cssparse/css_optimiser.php
95
  * @package csstidy
96
  * @author Florian Schmitz (floele at gmail dot com) 2005-2006
97
- * @version 1.5.5
98
  */
99
  class csstidy {
100
 
@@ -147,7 +123,7 @@ class csstidy {
147
  * @var string
148
  * @access private
149
  */
150
- public $version = '1.5.5';
151
  /**
152
  * Stores the settings
153
  * @var array
@@ -314,10 +290,14 @@ class csstidy {
314
  2, 5, 8, etc -- enable sorting selectors inside one CSS declaration: a,b,c{}
315
  preserve order by default cause it can break functionnality
316
  */
317
- $this->settings['sort_selectors'] = false;
318
  /* is dangeroues to be used: CSS is broken sometimes */
319
  $this->settings['merge_selectors'] = 0;
320
  /* preserve or not browser hacks */
 
 
 
 
321
  $this->settings['discard_invalid_selectors'] = false;
322
  $this->settings['discard_invalid_properties'] = false;
323
  $this->settings['css_level'] = 'CSS3.0';
@@ -411,7 +391,17 @@ class csstidy {
411
  */
412
  public function _add_token($type, $data, $do = false) {
413
  if ($this->get_cfg('preserve_css') || $do) {
414
- $this->tokens[] = array($type, ($type == COMMENT) ? $data : trim($data));
 
 
 
 
 
 
 
 
 
 
415
  }
416
  }
417
 
@@ -447,10 +437,10 @@ class csstidy {
447
  $add = '';
448
  $replaced = false;
449
 
450
- while ($i < strlen($string) && (ctype_xdigit($string{$i}) || ctype_space($string{$i})) && strlen($add) < 6) {
451
- $add .= $string{$i};
452
 
453
- if (ctype_space($string{$i})) {
454
  break;
455
  }
456
  $i++;
@@ -464,12 +454,12 @@ class csstidy {
464
  $add = trim('\\' . $add);
465
  }
466
 
467
- if (@ctype_xdigit($string{$i + 1}) && ctype_space($string{$i})
468
- && !$replaced || !ctype_space($string{$i})) {
469
  $i--;
470
  }
471
 
472
- if ($add !== '\\' || !$this->get_cfg('remove_bslash') || strpos($this->tokens_list, $string{$i + 1}) !== false) {
473
  return $add;
474
  }
475
 
@@ -571,7 +561,7 @@ class csstidy {
571
  * @version 1.11
572
  */
573
  public function is_token(&$string, $i) {
574
- return (strpos($this->tokens_list, $string{$i}) !== false && !$this->escaped($string, $i));
575
  }
576
 
577
  /**
@@ -598,9 +588,10 @@ class csstidy {
598
  $this->print->input_css = $string;
599
  $string = str_replace("\r\n", "\n", $string) . ' ';
600
  $cur_comment = '';
 
601
 
602
  for ($i = 0, $size = strlen($string); $i < $size; $i++) {
603
- if ($string{$i} === "\n" || $string{$i} === "\r") {
604
  ++$this->line;
605
  }
606
 
@@ -608,27 +599,27 @@ class csstidy {
608
  /* Case in at-block */
609
  case 'at':
610
  if ($this->is_token($string, $i)) {
611
- if ($string{$i} === '/' && @$string{$i + 1} === '*') {
612
  $this->status = 'ic';
613
  ++$i;
614
  $this->from[] = 'at';
615
- } elseif ($string{$i} === '{') {
616
  $this->status = 'is';
617
- $this->at = $this->css_new_media_section($this->at);
618
  $this->_add_token(AT_START, $this->at);
619
- } elseif ($string{$i} === ',') {
620
- $this->at = trim($this->at) . ',';
621
- } elseif ($string{$i} === '\\') {
622
- $this->at .= $this->_unicode($string, $i);
623
  }
624
  // fix for complicated media, i.e @media screen and (-webkit-min-device-pixel-ratio:1.5)
625
- elseif (in_array($string{$i}, array('(', ')', ':', '.', '/'))) {
626
- $this->at .= $string{$i};
627
  }
628
  } else {
629
- $lastpos = strlen($this->at) - 1;
630
- if (!( (ctype_space($this->at{$lastpos}) || $this->is_token($this->at, $lastpos) && $this->at{$lastpos} === ',') && ctype_space($string{$i}))) {
631
- $this->at .= $string{$i};
632
  }
633
  }
634
  break;
@@ -636,24 +627,25 @@ class csstidy {
636
  /* Case in-selector */
637
  case 'is':
638
  if ($this->is_token($string, $i)) {
639
- if ($string{$i} === '/' && @$string{$i + 1} === '*' && trim($this->selector) == '') {
640
  $this->status = 'ic';
641
  ++$i;
642
  $this->from[] = 'is';
643
- } elseif ($string{$i} === '@' && trim($this->selector) == '') {
644
  // Check for at-rule
645
  $this->invalid_at = true;
646
  foreach ($at_rules as $name => $type) {
647
  if (!strcasecmp(substr($string, $i + 1, strlen($name)), $name)) {
648
- ($type === 'at') ? $this->at = '@' . $name : $this->selector = '@' . $name;
649
  if ($type === 'atis') {
650
  $this->next_selector_at = ($this->next_selector_at?$this->next_selector_at:($this->at?$this->at:DEFAULT_AT));
651
- $this->at = $this->css_new_media_section(' ');
652
  $type = 'is';
653
  }
654
  $this->status = $type;
655
  $i += strlen($name);
656
  $this->invalid_at = false;
 
657
  }
658
  }
659
 
@@ -661,54 +653,55 @@ class csstidy {
661
  $this->selector = '@';
662
  $invalid_at_name = '';
663
  for ($j = $i + 1; $j < $size; ++$j) {
664
- if (!ctype_alpha($string{$j})) {
665
  break;
666
  }
667
- $invalid_at_name .= $string{$j};
668
  }
669
  $this->log('Invalid @-rule: ' . $invalid_at_name . ' (removed)', 'Warning');
670
  }
671
- } elseif (($string{$i} === '"' || $string{$i} === "'")) {
672
- $this->cur_string[] = $string{$i};
673
  $this->status = 'instr';
674
- $this->str_char[] = $string{$i};
675
  $this->from[] = 'is';
676
  /* fixing CSS3 attribute selectors, i.e. a[href$=".mp3" */
677
- $this->quoted_string[] = ($string{$i - 1} === '=' );
678
- } elseif ($this->invalid_at && $string{$i} === ';') {
679
  $this->invalid_at = false;
680
  $this->status = 'is';
681
  if ($this->next_selector_at) {
682
- $this->at = $this->css_new_media_section($this->next_selector_at);
 
683
  $this->next_selector_at = '';
684
  }
685
- } elseif ($string{$i} === '{') {
686
  $this->status = 'ip';
687
  if ($this->at == '') {
688
- $this->at = $this->css_new_media_section(DEFAULT_AT);
689
  }
690
  $this->selector = $this->css_new_selector($this->at,$this->selector);
691
  $this->_add_token(SEL_START, $this->selector);
692
  $this->added = false;
693
- } elseif ($string{$i} === '}') {
694
  $this->_add_token(AT_END, $this->at);
695
- $this->at = '';
696
  $this->selector = '';
697
  $this->sel_separate = array();
698
- } elseif ($string{$i} === ',') {
699
  $this->selector = trim($this->selector) . ',';
700
  $this->sel_separate[] = strlen($this->selector);
701
- } elseif ($string{$i} === '\\') {
702
  $this->selector .= $this->_unicode($string, $i);
703
- } elseif ($string{$i} === '*' && @in_array($string{$i + 1}, array('.', '#', '[', ':')) && ($i==0 OR $string{$i - 1}!=='/')) {
704
  // remove unnecessary universal selector, FS#147, but not comment in selector
705
  } else {
706
- $this->selector .= $string{$i};
707
  }
708
  } else {
709
  $lastpos = strlen($this->selector) - 1;
710
- if ($lastpos == -1 || !( (ctype_space($this->selector{$lastpos}) || $this->is_token($this->selector, $lastpos) && $this->selector{$lastpos} === ',') && ctype_space($string{$i}))) {
711
- $this->selector .= $string{$i};
712
  }
713
  }
714
  break;
@@ -716,17 +709,17 @@ class csstidy {
716
  /* Case in-property */
717
  case 'ip':
718
  if ($this->is_token($string, $i)) {
719
- if (($string{$i} === ':' || $string{$i} === '=') && $this->property != '') {
720
  $this->status = 'iv';
721
  if (!$this->get_cfg('discard_invalid_properties') || $this->property_is_valid($this->property)) {
722
  $this->property = $this->css_new_property($this->at,$this->selector,$this->property);
723
  $this->_add_token(PROPERTY, $this->property);
724
  }
725
- } elseif ($string{$i} === '/' && @$string{$i + 1} === '*' && $this->property == '') {
726
  $this->status = 'ic';
727
  ++$i;
728
  $this->from[] = 'ip';
729
- } elseif ($string{$i} === '}') {
730
  $this->explode_selectors();
731
  $this->status = 'is';
732
  $this->invalid_at = false;
@@ -734,45 +727,46 @@ class csstidy {
734
  $this->selector = '';
735
  $this->property = '';
736
  if ($this->next_selector_at) {
737
- $this->at = $this->css_new_media_section($this->next_selector_at);
 
738
  $this->next_selector_at = '';
739
  }
740
- } elseif ($string{$i} === ';') {
741
  $this->property = '';
742
- } elseif ($string{$i} === '\\') {
743
  $this->property .= $this->_unicode($string, $i);
744
  }
745
  // else this is dumb IE a hack, keep it
746
  // including //
747
- elseif (($this->property === '' && !ctype_space($string{$i}))
748
- || ($this->property === '/' || $string{$i} === '/')) {
749
- $this->property .= $string{$i};
750
  }
751
- } elseif (!ctype_space($string{$i})) {
752
- $this->property .= $string{$i};
753
  }
754
  break;
755
 
756
  /* Case in-value */
757
  case 'iv':
758
- $pn = (($string{$i} === "\n" || $string{$i} === "\r") && $this->property_is_next($string, $i + 1) || $i == strlen($string) - 1);
759
  if ($this->is_token($string, $i) || $pn) {
760
- if ($string{$i} === '/' && @$string{$i + 1} === '*') {
761
  $this->status = 'ic';
762
  ++$i;
763
  $this->from[] = 'iv';
764
- } elseif (($string{$i} === '"' || $string{$i} === "'" || $string{$i} === '(')) {
765
- $this->cur_string[] = $string{$i};
766
- $this->str_char[] = ($string{$i} === '(') ? ')' : $string{$i};
767
  $this->status = 'instr';
768
  $this->from[] = 'iv';
769
  $this->quoted_string[] = in_array(strtolower($this->property), $quoted_string_properties);
770
- } elseif ($string{$i} === ',') {
771
  $this->sub_value = trim($this->sub_value) . ',';
772
- } elseif ($string{$i} === '\\') {
773
  $this->sub_value .= $this->_unicode($string, $i);
774
- } elseif ($string{$i} === ';' || $pn) {
775
- if ($this->selector{0} === '@' && isset($at_rules[substr($this->selector, 1)]) && $at_rules[substr($this->selector, 1)] === 'iv') {
776
  /* Add quotes to charset, import, namespace */
777
  $this->sub_value_arr[] = trim($this->sub_value);
778
 
@@ -794,12 +788,12 @@ class csstidy {
794
  } else {
795
  $this->status = 'ip';
796
  }
797
- } elseif ($string{$i} !== '}') {
798
- $this->sub_value .= $string{$i};
799
  }
800
- if (($string{$i} === '}' || $string{$i} === ';' || $pn) && !empty($this->selector)) {
801
  if ($this->at == '') {
802
- $this->at = $this->css_new_media_section(DEFAULT_AT);
803
  }
804
 
805
  // case settings
@@ -845,21 +839,22 @@ class csstidy {
845
  $this->sub_value_arr = array();
846
  $this->value = '';
847
  }
848
- if ($string{$i} === '}') {
849
  $this->explode_selectors();
850
  $this->_add_token(SEL_END, $this->selector);
851
  $this->status = 'is';
852
  $this->invalid_at = false;
853
  $this->selector = '';
854
  if ($this->next_selector_at) {
855
- $this->at = $this->css_new_media_section($this->next_selector_at);
 
856
  $this->next_selector_at = '';
857
  }
858
  }
859
  } elseif (!$pn) {
860
- $this->sub_value .= $string{$i};
861
 
862
- if (ctype_space($string{$i})) {
863
  $this->optimise->subvalue();
864
  if ($this->sub_value != '') {
865
  $this->sub_value_arr[] = $this->sub_value;
@@ -874,26 +869,26 @@ class csstidy {
874
  $_str_char = $this->str_char[count($this->str_char)-1];
875
  $_cur_string = $this->cur_string[count($this->cur_string)-1];
876
  $_quoted_string = $this->quoted_string[count($this->quoted_string)-1];
877
- $temp_add = $string{$i};
878
 
879
  // Add another string to the stack. Strings can't be nested inside of quotes, only parentheses, but
880
  // parentheticals can be nested more than once.
881
- if ($_str_char === ")" && ($string{$i} === "(" || $string{$i} === '"' || $string{$i} === '\'') && !$this->escaped($string, $i)) {
882
- $this->cur_string[] = $string{$i};
883
- $this->str_char[] = $string{$i} === '(' ? ')' : $string{$i};
884
  $this->from[] = 'instr';
885
- $this->quoted_string[] = ($_str_char === ')' && $string{$i} !== '(' && trim($_cur_string)==='(')?$_quoted_string:!($string{$i} === '(');
886
- continue;
887
  }
888
 
889
- if ($_str_char !== ")" && ($string{$i} === "\n" || $string{$i} === "\r") && !($string{$i - 1} === '\\' && !$this->escaped($string, $i - 1))) {
890
  $temp_add = "\\A";
891
  $this->log('Fixed incorrect newline in string', 'Warning');
892
  }
893
 
894
  $_cur_string .= $temp_add;
895
 
896
- if ($string{$i} === $_str_char && !$this->escaped($string, $i)) {
897
  $this->status = array_pop($this->from);
898
 
899
  if (!preg_match('|[' . implode('', $this->data['csstidy']['whitespace']) . ']|uis', $_cur_string) && $this->property !== 'content') {
@@ -944,13 +939,19 @@ class csstidy {
944
 
945
  /* Case in-comment */
946
  case 'ic':
947
- if ($string{$i} === '*' && $string{$i + 1} === '/') {
948
  $this->status = array_pop($this->from);
949
  $i++;
950
- $this->_add_token(COMMENT, $cur_comment);
 
 
 
 
 
 
951
  $cur_comment = '';
952
  } else {
953
- $cur_comment .= $string{$i};
954
  }
955
  break;
956
  }
@@ -1033,7 +1034,26 @@ class csstidy {
1033
  * @version 1.02
1034
  */
1035
  static function escaped(&$string, $pos) {
1036
- return!(@($string{$pos - 1} !== '\\') || csstidy::escaped($string, $pos - 1));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1037
  }
1038
 
1039
  /**
@@ -1061,29 +1081,27 @@ class csstidy {
1061
  }
1062
 
1063
  /**
1064
- * Start a new media section.
1065
- * Check if the media is not already known,
1066
- * else rename it with extra spaces
1067
- * to avoid merging
1068
  *
1069
- * @param string $media
1070
- * @return string
1071
  */
1072
- public function css_new_media_section($media) {
1073
- if ($this->get_cfg('preserve_css')) {
 
1074
  return $media;
1075
  }
1076
 
1077
  // if the last @media is the same as this
1078
  // keep it
1079
- if (!$this->css || !is_array($this->css) || empty($this->css)) {
1080
- return $media;
1081
- }
1082
  end($this->css);
1083
- list($at,) = each($this->css);
1084
  if ($at == $media) {
1085
  return $media;
1086
  }
 
 
1087
  while (isset($this->css[$media]))
1088
  if (is_numeric($media))
1089
  $media++;
@@ -1092,6 +1110,56 @@ class csstidy {
1092
  return $media;
1093
  }
1094
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1095
  /**
1096
  * Start a new selector.
1097
  * If already referenced in this media section,
@@ -1119,7 +1187,7 @@ class csstidy {
1119
 
1120
  // if last is the same, keep it
1121
  end($this->css[$media]);
1122
- list($sel,) = each($this->css[$media]);
1123
  if ($sel == $selector) {
1124
  return $selector;
1125
  }
@@ -1225,7 +1293,7 @@ class csstidy {
1225
  /**
1226
  * Checks if a property is valid
1227
  * @param string $property
1228
- * @return bool;
1229
  * @access public
1230
  * @version 1.0
1231
  */
@@ -1249,7 +1317,6 @@ class csstidy {
1249
  * @param string
1250
  * @return array
1251
  */
1252
-
1253
  public function parse_string_list($value) {
1254
  $value = trim($value);
1255
 
@@ -1262,26 +1329,26 @@ class csstidy {
1262
  $current_string = '';
1263
 
1264
  for ($i = 0, $_len = strlen($value); $i < $_len; $i++) {
1265
- if (($value{$i} === ',' || $value{$i} === ' ') && $in_str === true) {
1266
  $in_str = false;
1267
  $strings[] = $current_string;
1268
  $current_string = '';
1269
- } elseif ($value{$i} === '"' || $value{$i} === "'") {
1270
- if ($in_str === $value{$i}) {
1271
  $strings[] = $current_string;
1272
  $in_str = false;
1273
  $current_string = '';
1274
  continue;
1275
  } elseif (!$in_str) {
1276
- $in_str = $value{$i};
1277
  }
1278
  } else {
1279
  if ($in_str) {
1280
- $current_string .= $value{$i};
1281
  } else {
1282
- if (!preg_match("/[\s,]/", $value{$i})) {
1283
  $in_str = true;
1284
- $current_string = $value{$i};
1285
  }
1286
  }
1287
  }
32
  * @author Mark Scherer (remove $GLOBALS once and for all + PHP5.4 comp) 2012
33
  */
34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  /**
36
  * Defines constants
37
  * @todo //TODO: make them class constants of csstidy
38
  */
39
+ define('AT_START', 1);
40
+ define('AT_END', 2);
41
+ define('SEL_START', 3);
42
+ define('SEL_END', 4);
43
+ define('PROPERTY', 5);
44
+ define('VALUE', 6);
45
+ define('COMMENT', 7);
46
+ define('IMPORTANT_COMMENT',8);
47
+ define('DEFAULT_AT', 41);
48
 
49
  /**
50
  * Contains a class for printing CSS code
51
  *
52
+ * @version 1.1.0
53
  */
54
  require('class.csstidy_print.php');
55
 
70
  * An online version should be available here: http://cdburnerxp.se/cssparse/css_optimiser.php
71
  * @package csstidy
72
  * @author Florian Schmitz (floele at gmail dot com) 2005-2006
73
+ * @version 1.7.3
74
  */
75
  class csstidy {
76
 
123
  * @var string
124
  * @access private
125
  */
126
+ public $version = '1.7.3';
127
  /**
128
  * Stores the settings
129
  * @var array
290
  2, 5, 8, etc -- enable sorting selectors inside one CSS declaration: a,b,c{}
291
  preserve order by default cause it can break functionnality
292
  */
293
+ $this->settings['sort_selectors'] = 0;
294
  /* is dangeroues to be used: CSS is broken sometimes */
295
  $this->settings['merge_selectors'] = 0;
296
  /* preserve or not browser hacks */
297
+
298
+ /* Useful to produce a rtl css from a ltr one (or the opposite) */
299
+ $this->settings['reverse_left_and_right'] = 0;
300
+
301
  $this->settings['discard_invalid_selectors'] = false;
302
  $this->settings['discard_invalid_properties'] = false;
303
  $this->settings['css_level'] = 'CSS3.0';
391
  */
392
  public function _add_token($type, $data, $do = false) {
393
  if ($this->get_cfg('preserve_css') || $do) {
394
+ // nested @... : if opening a new part we just closed, remove the previous closing instead of adding opening
395
+ if ($type === AT_START
396
+ and count($this->tokens)
397
+ and $last = end($this->tokens)
398
+ and $last[0] === AT_END
399
+ and $last[1] === trim($data)) {
400
+ array_pop($this->tokens);
401
+ }
402
+ else {
403
+ $this->tokens[] = array($type, ($type == COMMENT or $type == IMPORTANT_COMMENT) ? $data : trim($data));
404
+ }
405
  }
406
  }
407
 
437
  $add = '';
438
  $replaced = false;
439
 
440
+ while ($i < strlen($string) && (ctype_xdigit($string[$i]) || ctype_space($string[$i])) && strlen($add) < 6) {
441
+ $add .= $string[$i];
442
 
443
+ if (ctype_space($string[$i])) {
444
  break;
445
  }
446
  $i++;
454
  $add = trim('\\' . $add);
455
  }
456
 
457
+ if (@ctype_xdigit($string[$i + 1]) && ctype_space($string[$i])
458
+ && !$replaced || !ctype_space($string[$i])) {
459
  $i--;
460
  }
461
 
462
+ if ($add !== '\\' || !$this->get_cfg('remove_bslash') || strpos($this->tokens_list, $string[$i + 1]) !== false) {
463
  return $add;
464
  }
465
 
561
  * @version 1.11
562
  */
563
  public function is_token(&$string, $i) {
564
+ return (strpos($this->tokens_list, $string[$i]) !== false && !$this->escaped($string, $i));
565
  }
566
 
567
  /**
588
  $this->print->input_css = $string;
589
  $string = str_replace("\r\n", "\n", $string) . ' ';
590
  $cur_comment = '';
591
+ $cur_at = '';
592
 
593
  for ($i = 0, $size = strlen($string); $i < $size; $i++) {
594
+ if ($string[$i] === "\n" || $string[$i] === "\r") {
595
  ++$this->line;
596
  }
597
 
599
  /* Case in at-block */
600
  case 'at':
601
  if ($this->is_token($string, $i)) {
602
+ if ($string[$i] === '/' && @$string[$i + 1] === '*') {
603
  $this->status = 'ic';
604
  ++$i;
605
  $this->from[] = 'at';
606
+ } elseif ($string[$i] === '{') {
607
  $this->status = 'is';
608
+ $this->at = $this->css_new_media_section($this->at, $cur_at);
609
  $this->_add_token(AT_START, $this->at);
610
+ } elseif ($string[$i] === ',') {
611
+ $cur_at = trim($cur_at) . ',';
612
+ } elseif ($string[$i] === '\\') {
613
+ $cur_at .= $this->_unicode($string, $i);
614
  }
615
  // fix for complicated media, i.e @media screen and (-webkit-min-device-pixel-ratio:1.5)
616
+ elseif (in_array($string[$i], array('(', ')', ':', '.', '/'))) {
617
+ $cur_at .= $string[$i];
618
  }
619
  } else {
620
+ $lastpos = strlen($cur_at) - 1;
621
+ if (!( (ctype_space($cur_at[$lastpos]) || $this->is_token($cur_at, $lastpos) && $cur_at[$lastpos] === ',') && ctype_space($string[$i]))) {
622
+ $cur_at .= $string[$i];
623
  }
624
  }
625
  break;
627
  /* Case in-selector */
628
  case 'is':
629
  if ($this->is_token($string, $i)) {
630
+ if ($string[$i] === '/' && @$string[$i + 1] === '*' && trim($this->selector) == '') {
631
  $this->status = 'ic';
632
  ++$i;
633
  $this->from[] = 'is';
634
+ } elseif ($string[$i] === '@' && trim($this->selector) == '') {
635
  // Check for at-rule
636
  $this->invalid_at = true;
637
  foreach ($at_rules as $name => $type) {
638
  if (!strcasecmp(substr($string, $i + 1, strlen($name)), $name)) {
639
+ ($type === 'at') ? $cur_at = '@' . $name : $this->selector = '@' . $name;
640
  if ($type === 'atis') {
641
  $this->next_selector_at = ($this->next_selector_at?$this->next_selector_at:($this->at?$this->at:DEFAULT_AT));
642
+ $this->at = $this->css_new_media_section($this->at, ' ', true);
643
  $type = 'is';
644
  }
645
  $this->status = $type;
646
  $i += strlen($name);
647
  $this->invalid_at = false;
648
+ break;
649
  }
650
  }
651
 
653
  $this->selector = '@';
654
  $invalid_at_name = '';
655
  for ($j = $i + 1; $j < $size; ++$j) {
656
+ if (!ctype_alpha($string[$j])) {
657
  break;
658
  }
659
+ $invalid_at_name .= $string[$j];
660
  }
661
  $this->log('Invalid @-rule: ' . $invalid_at_name . ' (removed)', 'Warning');
662
  }
663
+ } elseif (($string[$i] === '"' || $string[$i] === "'")) {
664
+ $this->cur_string[] = $string[$i];
665
  $this->status = 'instr';
666
+ $this->str_char[] = $string[$i];
667
  $this->from[] = 'is';
668
  /* fixing CSS3 attribute selectors, i.e. a[href$=".mp3" */
669
+ $this->quoted_string[] = ($string[$i - 1] === '=' );
670
+ } elseif ($this->invalid_at && $string[$i] === ';') {
671
  $this->invalid_at = false;
672
  $this->status = 'is';
673
  if ($this->next_selector_at) {
674
+ $this->at = $this->css_close_media_section($this->at);
675
+ $this->at = $this->css_new_media_section($this->at, $this->next_selector_at);
676
  $this->next_selector_at = '';
677
  }
678
+ } elseif ($string[$i] === '{') {
679
  $this->status = 'ip';
680
  if ($this->at == '') {
681
+ $this->at = $this->css_new_media_section($this->at, DEFAULT_AT);
682
  }
683
  $this->selector = $this->css_new_selector($this->at,$this->selector);
684
  $this->_add_token(SEL_START, $this->selector);
685
  $this->added = false;
686
+ } elseif ($string[$i] === '}') {
687
  $this->_add_token(AT_END, $this->at);
688
+ $this->at = $this->css_close_media_section($this->at);
689
  $this->selector = '';
690
  $this->sel_separate = array();
691
+ } elseif ($string[$i] === ',') {
692
  $this->selector = trim($this->selector) . ',';
693
  $this->sel_separate[] = strlen($this->selector);
694
+ } elseif ($string[$i] === '\\') {
695
  $this->selector .= $this->_unicode($string, $i);
696
+ } elseif ($string[$i] === '*' && @in_array($string[$i + 1], array('.', '#', '[', ':')) && ($i==0 OR $string[$i - 1]!=='/')) {
697
  // remove unnecessary universal selector, FS#147, but not comment in selector
698
  } else {
699
+ $this->selector .= $string[$i];
700
  }
701
  } else {
702
  $lastpos = strlen($this->selector) - 1;
703
+ if ($lastpos == -1 || !( (ctype_space($this->selector[$lastpos]) || $this->is_token($this->selector, $lastpos) && $this->selector[$lastpos] === ',') && ctype_space($string[$i]))) {
704
+ $this->selector .= $string[$i];
705
  }
706
  }
707
  break;
709
  /* Case in-property */
710
  case 'ip':
711
  if ($this->is_token($string, $i)) {
712
+ if (($string[$i] === ':' || $string[$i] === '=') && $this->property != '') {
713
  $this->status = 'iv';
714
  if (!$this->get_cfg('discard_invalid_properties') || $this->property_is_valid($this->property)) {
715
  $this->property = $this->css_new_property($this->at,$this->selector,$this->property);
716
  $this->_add_token(PROPERTY, $this->property);
717
  }
718
+ } elseif ($string[$i] === '/' && @$string[$i + 1] === '*' && $this->property == '') {
719
  $this->status = 'ic';
720
  ++$i;
721
  $this->from[] = 'ip';
722
+ } elseif ($string[$i] === '}') {
723
  $this->explode_selectors();
724
  $this->status = 'is';
725
  $this->invalid_at = false;
727
  $this->selector = '';
728
  $this->property = '';
729
  if ($this->next_selector_at) {
730
+ $this->at = $this->css_close_media_section($this->at);
731
+ $this->at = $this->css_new_media_section($this->at, $this->next_selector_at);
732
  $this->next_selector_at = '';
733
  }
734
+ } elseif ($string[$i] === ';') {
735
  $this->property = '';
736
+ } elseif ($string[$i] === '\\') {
737
  $this->property .= $this->_unicode($string, $i);
738
  }
739
  // else this is dumb IE a hack, keep it
740
  // including //
741
+ elseif (($this->property === '' && !ctype_space($string[$i]))
742
+ || ($this->property === '/' || $string[$i] === '/')) {
743
+ $this->property .= $string[$i];
744
  }
745
+ } elseif (!ctype_space($string[$i])) {
746
+ $this->property .= $string[$i];
747
  }
748
  break;
749
 
750
  /* Case in-value */
751
  case 'iv':
752
+ $pn = (($string[$i] === "\n" || $string[$i] === "\r") && $this->property_is_next($string, $i + 1) || $i == strlen($string) - 1);
753
  if ($this->is_token($string, $i) || $pn) {
754
+ if ($string[$i] === '/' && @$string[$i + 1] === '*') {
755
  $this->status = 'ic';
756
  ++$i;
757
  $this->from[] = 'iv';
758
+ } elseif (($string[$i] === '"' || $string[$i] === "'" || $string[$i] === '(')) {
759
+ $this->cur_string[] = $string[$i];
760
+ $this->str_char[] = ($string[$i] === '(') ? ')' : $string[$i];
761
  $this->status = 'instr';
762
  $this->from[] = 'iv';
763
  $this->quoted_string[] = in_array(strtolower($this->property), $quoted_string_properties);
764
+ } elseif ($string[$i] === ',') {
765
  $this->sub_value = trim($this->sub_value) . ',';
766
+ } elseif ($string[$i] === '\\') {
767
  $this->sub_value .= $this->_unicode($string, $i);
768
+ } elseif ($string[$i] === ';' || $pn) {
769
+ if ($this->selector[0] === '@' && isset($at_rules[substr($this->selector, 1)]) && $at_rules[substr($this->selector, 1)] === 'iv') {
770
  /* Add quotes to charset, import, namespace */
771
  $this->sub_value_arr[] = trim($this->sub_value);
772
 
788
  } else {
789
  $this->status = 'ip';
790
  }
791
+ } elseif ($string[$i] !== '}') {
792
+ $this->sub_value .= $string[$i];
793
  }
794
+ if (($string[$i] === '}' || $string[$i] === ';' || $pn) && !empty($this->selector)) {
795
  if ($this->at == '') {
796
+ $this->at = $this->css_new_media_section($this->at,DEFAULT_AT);
797
  }
798
 
799
  // case settings
839
  $this->sub_value_arr = array();
840
  $this->value = '';
841
  }
842
+ if ($string[$i] === '}') {
843
  $this->explode_selectors();
844
  $this->_add_token(SEL_END, $this->selector);
845
  $this->status = 'is';
846
  $this->invalid_at = false;
847
  $this->selector = '';
848
  if ($this->next_selector_at) {
849
+ $this->at = $this->css_close_media_section($this->at);
850
+ $this->at = $this->css_new_media_section($this->at, $this->next_selector_at);
851
  $this->next_selector_at = '';
852
  }
853
  }
854
  } elseif (!$pn) {
855
+ $this->sub_value .= $string[$i];
856
 
857
+ if (ctype_space($string[$i])) {
858
  $this->optimise->subvalue();
859
  if ($this->sub_value != '') {
860
  $this->sub_value_arr[] = $this->sub_value;
869
  $_str_char = $this->str_char[count($this->str_char)-1];
870
  $_cur_string = $this->cur_string[count($this->cur_string)-1];
871
  $_quoted_string = $this->quoted_string[count($this->quoted_string)-1];
872
+ $temp_add = $string[$i];
873
 
874
  // Add another string to the stack. Strings can't be nested inside of quotes, only parentheses, but
875
  // parentheticals can be nested more than once.
876
+ if ($_str_char === ")" && ($string[$i] === "(" || $string[$i] === '"' || $string[$i] === '\'') && !$this->escaped($string, $i)) {
877
+ $this->cur_string[] = $string[$i];
878
+ $this->str_char[] = $string[$i] === '(' ? ')' : $string[$i];
879
  $this->from[] = 'instr';
880
+ $this->quoted_string[] = ($_str_char === ')' && $string[$i] !== '(' && trim($_cur_string)==='(')?$_quoted_string:!($string[$i] === '(');
881
+ continue 2;
882
  }
883
 
884
+ if ($_str_char !== ")" && ($string[$i] === "\n" || $string[$i] === "\r") && !($string[$i - 1] === '\\' && !$this->escaped($string, $i - 1))) {
885
  $temp_add = "\\A";
886
  $this->log('Fixed incorrect newline in string', 'Warning');
887
  }
888
 
889
  $_cur_string .= $temp_add;
890
 
891
+ if ($string[$i] === $_str_char && !$this->escaped($string, $i)) {
892
  $this->status = array_pop($this->from);
893
 
894
  if (!preg_match('|[' . implode('', $this->data['csstidy']['whitespace']) . ']|uis', $_cur_string) && $this->property !== 'content') {
939
 
940
  /* Case in-comment */
941
  case 'ic':
942
+ if ($string[$i] === '*' && $string[$i + 1] === '/') {
943
  $this->status = array_pop($this->from);
944
  $i++;
945
+ if (strlen($cur_comment) > 1 and strncmp($cur_comment, '!', 1) === 0) {
946
+ $this->_add_token(IMPORTANT_COMMENT, $cur_comment);
947
+ $this->css_add_important_comment($cur_comment);
948
+ }
949
+ else {
950
+ $this->_add_token(COMMENT, $cur_comment);
951
+ }
952
  $cur_comment = '';
953
  } else {
954
+ $cur_comment .= $string[$i];
955
  }
956
  break;
957
  }
1034
  * @version 1.02
1035
  */
1036
  static function escaped(&$string, $pos) {
1037
+ return!(@($string[$pos - 1] !== '\\') || csstidy::escaped($string, $pos - 1));
1038
+ }
1039
+
1040
+
1041
+ /**
1042
+ * Add an important comment to the css code
1043
+ * (one we want to keep)
1044
+ * @param $comment
1045
+ */
1046
+ public function css_add_important_comment($comment) {
1047
+ if ($this->get_cfg('preserve_css') || trim($comment) == '') {
1048
+ return;
1049
+ }
1050
+ if (!isset($this->css['!'])) {
1051
+ $this->css['!'] = '';
1052
+ }
1053
+ else {
1054
+ $this->css['!'] .= "\n";
1055
+ }
1056
+ $this->css['!'] .= $comment;
1057
  }
1058
 
1059
  /**
1081
  }
1082
 
1083
  /**
1084
+ * Check if a current media section is the continuation of the last one
1085
+ * if not inc the name of the media section to avoid a merging
 
 
1086
  *
1087
+ * @param int|string $media
1088
+ * @return int|string
1089
  */
1090
+ public function css_check_last_media_section_or_inc($media) {
1091
+ // are we starting?
1092
+ if (!$this->css || !is_array($this->css) || empty($this->css)) {
1093
  return $media;
1094
  }
1095
 
1096
  // if the last @media is the same as this
1097
  // keep it
 
 
 
1098
  end($this->css);
1099
+ $at = key($this->css);
1100
  if ($at == $media) {
1101
  return $media;
1102
  }
1103
+
1104
+ // else inc the section in the array
1105
  while (isset($this->css[$media]))
1106
  if (is_numeric($media))
1107
  $media++;
1110
  return $media;
1111
  }
1112
 
1113
+ /**
1114
+ * Start a new media section.
1115
+ * Check if the media is not already known,
1116
+ * else rename it with extra spaces
1117
+ * to avoid merging
1118
+ *
1119
+ * @param string $current_media
1120
+ * @param string $media
1121
+ * @param bool $at_root
1122
+ * @return string
1123
+ */
1124
+ public function css_new_media_section($current_media, $new_media, $at_root = false) {
1125
+ if ($this->get_cfg('preserve_css')) {
1126
+ return $new_media;
1127
+ }
1128
+
1129
+ // if we already are in a media and CSS level is 3, manage nested medias
1130
+ if ($current_media
1131
+ && !$at_root
1132
+ // numeric $current_media means DEFAULT_AT or inc
1133
+ && !is_numeric($current_media)
1134
+ && strncmp($this->get_cfg('css_level'), 'CSS3', 4) == 0) {
1135
+
1136
+ $new_media = rtrim($current_media) . "{" . rtrim($new_media);
1137
+ }
1138
+
1139
+ return $this->css_check_last_media_section_or_inc($new_media);
1140
+ }
1141
+
1142
+ /**
1143
+ * Close a media section
1144
+ * Find the parent media we were in before or the root
1145
+ * @param $current_media
1146
+ * @return string
1147
+ */
1148
+ public function css_close_media_section($current_media) {
1149
+ if ($this->get_cfg('preserve_css')) {
1150
+ return '';
1151
+ }
1152
+
1153
+ if (strpos($current_media, '{') !== false) {
1154
+ $current_media = explode('{', $current_media);
1155
+ array_pop($current_media);
1156
+ $current_media = implode('{', $current_media);
1157
+ return $current_media;
1158
+ }
1159
+
1160
+ return '';
1161
+ }
1162
+
1163
  /**
1164
  * Start a new selector.
1165
  * If already referenced in this media section,
1187
 
1188
  // if last is the same, keep it
1189
  end($this->css[$media]);
1190
+ $sel = key($this->css[$media]);
1191
  if ($sel == $selector) {
1192
  return $selector;
1193
  }
1293
  /**
1294
  * Checks if a property is valid
1295
  * @param string $property
1296
+ * @return bool
1297
  * @access public
1298
  * @version 1.0
1299
  */
1317
  * @param string
1318
  * @return array
1319
  */
 
1320
  public function parse_string_list($value) {
1321
  $value = trim($value);
1322
 
1329
  $current_string = '';
1330
 
1331
  for ($i = 0, $_len = strlen($value); $i < $_len; $i++) {
1332
+ if (($value[$i] === ',' || $value[$i] === ' ') && $in_str === true) {
1333
  $in_str = false;
1334
  $strings[] = $current_string;
1335
  $current_string = '';
1336
+ } elseif ($value[$i] === '"' || $value[$i] === "'") {
1337
+ if ($in_str === $value[$i]) {
1338
  $strings[] = $current_string;
1339
  $in_str = false;
1340
  $current_string = '';
1341
  continue;
1342
  } elseif (!$in_str) {
1343
+ $in_str = $value[$i];
1344
  }
1345
  } else {
1346
  if ($in_str) {
1347
+ $current_string .= $value[$i];
1348
  } else {
1349
+ if (!preg_match("/[\s,]/", $value[$i])) {
1350
  $in_str = true;
1351
+ $current_string = $value[$i];
1352
  }
1353
  }
1354
  }
lib/CSSTidy/class.csstidy_optimise.php CHANGED
@@ -70,40 +70,60 @@ class csstidy_optimise {
70
  * @version 1.0
71
  */
72
  public function postparse() {
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  if ($this->parser->get_cfg('preserve_css')) {
74
  return;
75
  }
76
 
77
  if ((int)$this->parser->get_cfg('merge_selectors') === 2) {
78
  foreach ($this->css as $medium => $value) {
79
- $this->merge_selectors($this->css[$medium]);
 
 
80
  }
81
  }
82
 
83
  if ($this->parser->get_cfg('discard_invalid_selectors')) {
84
  foreach ($this->css as $medium => $value) {
85
- $this->discard_invalid_selectors($this->css[$medium]);
 
 
86
  }
87
  }
88
 
89
  if ($this->parser->get_cfg('optimise_shorthands') > 0) {
90
  foreach ($this->css as $medium => $value) {
91
- foreach ($value as $selector => $value1) {
92
- $this->css[$medium][$selector] = $this->merge_4value_shorthands($this->css[$medium][$selector]);
 
 
93
 
94
- if ($this->parser->get_cfg('optimise_shorthands') < 2) {
95
- continue;
96
- }
97
 
98
- $this->css[$medium][$selector] = $this->merge_font($this->css[$medium][$selector]);
99
 
100
- if ($this->parser->get_cfg('optimise_shorthands') < 3) {
101
- continue;
102
- }
103
 
104
- $this->css[$medium][$selector] = $this->merge_bg($this->css[$medium][$selector]);
105
- if (empty($this->css[$medium][$selector])) {
106
- unset($this->css[$medium][$selector]);
 
107
  }
108
  }
109
  }
@@ -338,8 +358,8 @@ class csstidy_optimise {
338
  // #aabbcc -> #abc
339
  if (strlen($color) == 7) {
340
  $color_temp = strtolower($color);
341
- if ($color_temp{0} === '#' && $color_temp{1} == $color_temp{2} && $color_temp{3} == $color_temp{4} && $color_temp{5} == $color_temp{6}) {
342
- $color = '#' . $color{1} . $color{3} . $color{5};
343
  }
344
  }
345
 
@@ -400,9 +420,9 @@ class csstidy_optimise {
400
  if ($number[1] == '' && in_array($this->property, $unit_values, true)) {
401
  $number[1] = 'px';
402
  }
403
- } elseif ($number[1] != 's' && $number[1] != 'ms') {
404
- $number[1] = '';
405
- }
406
 
407
  $temp[$l] = $number[0] . $number[1];
408
  }
@@ -418,7 +438,7 @@ class csstidy_optimise {
418
  */
419
  public function AnalyseCssNumber($string) {
420
  // most simple checks first
421
- if (strlen($string) == 0 || ctype_alpha($string{0})) {
422
  return false;
423
  }
424
 
@@ -525,12 +545,15 @@ class csstidy_optimise {
525
  * Dissolves properties like padding:10px 10px 10px to padding-top:10px;padding-bottom:10px;...
526
  * @param string $property
527
  * @param string $value
 
528
  * @return array
529
  * @version 1.0
530
  * @see merge_4value_shorthands()
531
  */
532
- public function dissolve_4value_shorthands($property, $value) {
533
- $shorthands = & $this->parser->data['csstidy']['shorthands'];
 
 
534
  if (!is_array($shorthands[$property])) {
535
  $return[$property] = $value;
536
  return $return;
@@ -567,63 +590,103 @@ class csstidy_optimise {
567
  return $return;
568
  }
569
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
570
  /**
571
  * Explodes a string as explode() does, however, not if $sep is escaped or within a string.
572
  * @param string $sep seperator
573
  * @param string $string
 
574
  * @return array
575
  * @version 1.0
576
  */
577
- public function explode_ws($sep, $string) {
578
  $status = 'st';
579
  $to = '';
580
 
581
- $output = array();
 
 
582
  $num = 0;
583
  for ($i = 0, $len = strlen($string); $i < $len; $i++) {
584
  switch ($status) {
585
  case 'st':
586
- if ($string{$i} == $sep && !$this->parser->escaped($string, $i)) {
587
  ++$num;
588
- } elseif ($string{$i} === '"' || $string{$i} === '\'' || $string{$i} === '(' && !$this->parser->escaped($string, $i)) {
589
  $status = 'str';
590
- $to = ($string{$i} === '(') ? ')' : $string{$i};
591
- (isset($output[$num])) ? $output[$num] .= $string{$i} : $output[$num] = $string{$i};
592
  } else {
593
- (isset($output[$num])) ? $output[$num] .= $string{$i} : $output[$num] = $string{$i};
594
  }
595
  break;
596
 
597
  case 'str':
598
- if ($string{$i} == $to && !$this->parser->escaped($string, $i)) {
599
  $status = 'st';
600
  }
601
- (isset($output[$num])) ? $output[$num] .= $string{$i} : $output[$num] = $string{$i};
602
  break;
603
  }
604
  }
605
 
606
- if (isset($output[0])) {
607
- return $output;
608
- } else {
609
- return array($output);
610
- }
611
  }
612
 
613
  /**
614
  * Merges Shorthand properties again, the opposite of dissolve_4value_shorthands()
615
  * @param array $array
 
616
  * @return array
617
  * @version 1.2
618
  * @see dissolve_4value_shorthands()
619
  */
620
- public function merge_4value_shorthands($array) {
621
  $return = $array;
622
- $shorthands = & $this->parser->data['csstidy']['shorthands'];
 
 
623
 
624
  foreach ($shorthands as $key => $value) {
625
- if (isset($array[$value[0]]) && isset($array[$value[1]])
626
- && isset($array[$value[2]]) && isset($array[$value[3]]) && $value !== 0) {
627
  $return[$key] = '';
628
 
629
  $important = '';
@@ -643,6 +706,45 @@ class csstidy_optimise {
643
  return $return;
644
  }
645
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
646
  /**
647
  * Dissolve background property
648
  * @param string $str_value
@@ -695,9 +797,9 @@ class csstidy_optimise {
695
  $have['clip'] = true;
696
  } elseif (in_array($str_value[$i][$j], $origin, true)) {
697
  $return['background-origin'] .= $str_value[$i][$j] . ',';
698
- } elseif ($str_value[$i][$j]{0} === '(') {
699
  $return['background-size'] .= substr($str_value[$i][$j], 1, -1) . ',';
700
- } elseif (in_array($str_value[$i][$j], $pos, true) || is_numeric($str_value[$i][$j]{0}) || $str_value[$i][$j]{0} === null || $str_value[$i][$j]{0} === '-' || $str_value[$i][$j]{0} === '.') {
701
  $return['background-position'] .= $str_value[$i][$j];
702
  if (!$have['pos'])
703
  $return['background-position'] .= ' '; else
@@ -843,7 +945,7 @@ class csstidy_optimise {
843
  } elseif ($have['style'] === false && in_array($str_value[0][$j], $font_style)) {
844
  $return['font-style'] = $str_value[0][$j];
845
  $have['style'] = true;
846
- } elseif ($have['size'] === false && (is_numeric($str_value[0][$j]{0}) || $str_value[0][$j]{0} === null || $str_value[0][$j]{0} === '.')) {
847
  $size = $this->explode_ws('/', trim($str_value[0][$j]));
848
  $return['font-size'] = $size[0];
849
  if (isset($size[1])) {
@@ -873,7 +975,7 @@ class csstidy_optimise {
873
 
874
  // Fix for 100 and more font-size
875
  if ($have['size'] === false && isset($return['font-weight']) &&
876
- is_numeric($return['font-weight']{0})) {
877
  $return['font-size'] = $return['font-weight'];
878
  unset($return['font-weight']);
879
  }
@@ -909,8 +1011,8 @@ class csstidy_optimise {
909
  $family = trim($family);
910
  $len = strlen($family);
911
  if (strpos($family, ' ') &&
912
- !(($family{0} === '"' && $family{$len - 1} === '"') ||
913
- ($family{0} === "'" && $family{$len - 1} === "'"))) {
914
  $family = '"' . $family . '"';
915
  }
916
  $result_families[] = $family;
@@ -960,4 +1062,246 @@ class csstidy_optimise {
960
  return $input_css;
961
  }
962
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
963
  }
70
  * @version 1.0
71
  */
72
  public function postparse() {
73
+
74
+ if ($this->parser->get_cfg('reverse_left_and_right') > 0) {
75
+
76
+ foreach ($this->css as $medium => $selectors) {
77
+ if (is_array($selectors)) {
78
+ foreach ($selectors as $selector => $properties) {
79
+ $this->css[$medium][$selector] = $this->reverse_left_and_right($this->css[$medium][$selector]);
80
+ }
81
+ }
82
+ }
83
+
84
+ }
85
+
86
  if ($this->parser->get_cfg('preserve_css')) {
87
  return;
88
  }
89
 
90
  if ((int)$this->parser->get_cfg('merge_selectors') === 2) {
91
  foreach ($this->css as $medium => $value) {
92
+ if (is_array($value)) {
93
+ $this->merge_selectors($this->css[$medium]);
94
+ }
95
  }
96
  }
97
 
98
  if ($this->parser->get_cfg('discard_invalid_selectors')) {
99
  foreach ($this->css as $medium => $value) {
100
+ if (is_array($value)) {
101
+ $this->discard_invalid_selectors($this->css[$medium]);
102
+ }
103
  }
104
  }
105
 
106
  if ($this->parser->get_cfg('optimise_shorthands') > 0) {
107
  foreach ($this->css as $medium => $value) {
108
+ if (is_array($value)) {
109
+ foreach ($value as $selector => $value1) {
110
+ $this->css[$medium][$selector] = $this->merge_4value_shorthands($this->css[$medium][$selector]);
111
+ $this->css[$medium][$selector] = $this->merge_4value_radius_shorthands($this->css[$medium][$selector]);
112
 
113
+ if ($this->parser->get_cfg('optimise_shorthands') < 2) {
114
+ continue;
115
+ }
116
 
117
+ $this->css[$medium][$selector] = $this->merge_font($this->css[$medium][$selector]);
118
 
119
+ if ($this->parser->get_cfg('optimise_shorthands') < 3) {
120
+ continue;
121
+ }
122
 
123
+ $this->css[$medium][$selector] = $this->merge_bg($this->css[$medium][$selector]);
124
+ if (empty($this->css[$medium][$selector])) {
125
+ unset($this->css[$medium][$selector]);
126
+ }
127
  }
128
  }
129
  }
358
  // #aabbcc -> #abc
359
  if (strlen($color) == 7) {
360
  $color_temp = strtolower($color);
361
+ if ($color_temp[0] === '#' && $color_temp[1] == $color_temp[2] && $color_temp[3] == $color_temp[4] && $color_temp[5] == $color_temp[6]) {
362
+ $color = '#' . $color[1] . $color[3] . $color[5];
363
  }
364
  }
365
 
420
  if ($number[1] == '' && in_array($this->property, $unit_values, true)) {
421
  $number[1] = 'px';
422
  }
423
+ } elseif ($number[1] != 's' && $number[1] != 'ms') {
424
+ $number[1] = '';
425
+ }
426
 
427
  $temp[$l] = $number[0] . $number[1];
428
  }
438
  */
439
  public function AnalyseCssNumber($string) {
440
  // most simple checks first
441
+ if (strlen($string) == 0 || ctype_alpha($string[0])) {
442
  return false;
443
  }
444
 
545
  * Dissolves properties like padding:10px 10px 10px to padding-top:10px;padding-bottom:10px;...
546
  * @param string $property
547
  * @param string $value
548
+ * @param array|null $shorthands
549
  * @return array
550
  * @version 1.0
551
  * @see merge_4value_shorthands()
552
  */
553
+ public function dissolve_4value_shorthands($property, $value, $shorthands = null) {
554
+ if (is_null($shorthands)) {
555
+ $shorthands = & $this->parser->data['csstidy']['shorthands'];
556
+ }
557
  if (!is_array($shorthands[$property])) {
558
  $return[$property] = $value;
559
  return $return;
590
  return $return;
591
  }
592
 
593
+ /**
594
+ * Dissolves radius properties like
595
+ * border-radius:10px 10px 10px / 1px 2px
596
+ * to border-top-left:10px 1px;border-top-right:10px 2x;...
597
+ * @param string $property
598
+ * @param string $value
599
+ * @return array
600
+ * @version 1.0
601
+ * @use dissolve_4value_shorthands()
602
+ * @see merge_4value_radius_shorthands()
603
+ */
604
+ public function dissolve_4value_radius_shorthands($property, $value) {
605
+ $shorthands = & $this->parser->data['csstidy']['radius_shorthands'];
606
+ if (!is_array($shorthands[$property])) {
607
+ $return[$property] = $value;
608
+ return $return;
609
+ }
610
+
611
+ if (strpos($value, '/') !== false) {
612
+ $values = $this->explode_ws('/', $value);
613
+ if (count($values) == 2) {
614
+ $r[0] = $this->dissolve_4value_shorthands($property, trim($values[0]), $shorthands);
615
+ $r[1] = $this->dissolve_4value_shorthands($property, trim($values[1]), $shorthands);
616
+ $return = array();
617
+ foreach ($r[0] as $p=>$v) {
618
+ $return[$p] = $v;
619
+ if ($r[1][$p] !== $v) {
620
+ $return[$p] .= ' ' . $r[1][$p];
621
+ }
622
+ }
623
+ return $return;
624
+ }
625
+ }
626
+
627
+ $return = $this->dissolve_4value_shorthands($property, $value, $shorthands);
628
+ return $return;
629
+ }
630
+
631
  /**
632
  * Explodes a string as explode() does, however, not if $sep is escaped or within a string.
633
  * @param string $sep seperator
634
  * @param string $string
635
+ * @param bool $explode_in_parenthesis
636
  * @return array
637
  * @version 1.0
638
  */
639
+ public function explode_ws($sep, $string, $explode_in_parenthesis = false) {
640
  $status = 'st';
641
  $to = '';
642
 
643
+ $output = array(
644
+ 0 => '',
645
+ );
646
  $num = 0;
647
  for ($i = 0, $len = strlen($string); $i < $len; $i++) {
648
  switch ($status) {
649
  case 'st':
650
+ if ($string[$i] == $sep && !$this->parser->escaped($string, $i)) {
651
  ++$num;
652
+ } elseif ($string[$i] === '"' || $string[$i] === '\'' || (!$explode_in_parenthesis && $string[$i] === '(') && !$this->parser->escaped($string, $i)) {
653
  $status = 'str';
654
+ $to = ($string[$i] === '(') ? ')' : $string[$i];
655
+ (isset($output[$num])) ? $output[$num] .= $string[$i] : $output[$num] = $string[$i];
656
  } else {
657
+ (isset($output[$num])) ? $output[$num] .= $string[$i] : $output[$num] = $string[$i];
658
  }
659
  break;
660
 
661
  case 'str':
662
+ if ($string[$i] == $to && !$this->parser->escaped($string, $i)) {
663
  $status = 'st';
664
  }
665
+ (isset($output[$num])) ? $output[$num] .= $string[$i] : $output[$num] = $string[$i];
666
  break;
667
  }
668
  }
669
 
670
+ return $output;
 
 
 
 
671
  }
672
 
673
  /**
674
  * Merges Shorthand properties again, the opposite of dissolve_4value_shorthands()
675
  * @param array $array
676
+ * @param array|null $shorthands
677
  * @return array
678
  * @version 1.2
679
  * @see dissolve_4value_shorthands()
680
  */
681
+ public function merge_4value_shorthands($array, $shorthands = null) {
682
  $return = $array;
683
+ if (is_null($shorthands)) {
684
+ $shorthands = & $this->parser->data['csstidy']['shorthands'];
685
+ }
686
 
687
  foreach ($shorthands as $key => $value) {
688
+ if ($value !== 0 && isset($array[$value[0]]) && isset($array[$value[1]])
689
+ && isset($array[$value[2]]) && isset($array[$value[3]])) {
690
  $return[$key] = '';
691
 
692
  $important = '';
706
  return $return;
707
  }
708
 
709
+ /**
710
+ * Merges Shorthand properties again, the opposite of dissolve_4value_shorthands()
711
+ * @param array $array
712
+ * @return array
713
+ * @version 1.2
714
+ * @use merge_4value_shorthands()
715
+ * @see dissolve_4value_radius_shorthands()
716
+ */
717
+ public function merge_4value_radius_shorthands($array) {
718
+ $return = $array;
719
+ $shorthands = & $this->parser->data['csstidy']['radius_shorthands'];
720
+
721
+ foreach ($shorthands as $key => $value) {
722
+ if (isset($array[$value[0]]) && isset($array[$value[1]])
723
+ && isset($array[$value[2]]) && isset($array[$value[3]]) && $value !== 0) {
724
+ $return[$key] = '';
725
+ $a = array();
726
+ for ($i = 0; $i < 4; $i++) {
727
+ $v = $this->explode_ws(' ', trim($array[$value[$i]]));
728
+ $a[0][$value[$i]] = reset($v);
729
+ $a[1][$value[$i]] = end($v);
730
+ }
731
+ $r = array();
732
+ $r[0] = $this->merge_4value_shorthands($a[0], $shorthands);
733
+ $r[1] = $this->merge_4value_shorthands($a[1], $shorthands);
734
+
735
+ if (isset($r[0][$key]) and isset($r[1][$key])) {
736
+ $return[$key] = $r[0][$key];
737
+ if ($r[1][$key] !== $r[0][$key]) {
738
+ $return[$key] .= ' / ' . $r[1][$key];
739
+ }
740
+ for ($i = 0; $i < 4; $i++) {
741
+ unset($return[$value[$i]]);
742
+ }
743
+ }
744
+ }
745
+ }
746
+ return $return;
747
+ }
748
  /**
749
  * Dissolve background property
750
  * @param string $str_value
797
  $have['clip'] = true;
798
  } elseif (in_array($str_value[$i][$j], $origin, true)) {
799
  $return['background-origin'] .= $str_value[$i][$j] . ',';
800
+ } elseif ($str_value[$i][$j][0] === '(') {
801
  $return['background-size'] .= substr($str_value[$i][$j], 1, -1) . ',';
802
+ } elseif (in_array($str_value[$i][$j], $pos, true) || is_numeric($str_value[$i][$j][0]) || $str_value[$i][$j][0] === null || $str_value[$i][$j][0] === '-' || $str_value[$i][$j][0] === '.') {
803
  $return['background-position'] .= $str_value[$i][$j];
804
  if (!$have['pos'])
805
  $return['background-position'] .= ' '; else
945
  } elseif ($have['style'] === false && in_array($str_value[0][$j], $font_style)) {
946
  $return['font-style'] = $str_value[0][$j];
947
  $have['style'] = true;
948
+ } elseif ($have['size'] === false && (is_numeric($str_value[0][$j][0]) || $str_value[0][$j][0] === null || $str_value[0][$j][0] === '.')) {
949
  $size = $this->explode_ws('/', trim($str_value[0][$j]));
950
  $return['font-size'] = $size[0];
951
  if (isset($size[1])) {
975
 
976
  // Fix for 100 and more font-size
977
  if ($have['size'] === false && isset($return['font-weight']) &&
978
+ is_numeric($return['font-weight'][0])) {
979
  $return['font-size'] = $return['font-weight'];
980
  unset($return['font-weight']);
981
  }
1011
  $family = trim($family);
1012
  $len = strlen($family);
1013
  if (strpos($family, ' ') &&
1014
+ !(($family[0] === '"' && $family[$len - 1] === '"') ||
1015
+ ($family[0] === "'" && $family[$len - 1] === "'"))) {
1016
  $family = '"' . $family . '"';
1017
  }
1018
  $result_families[] = $family;
1062
  return $input_css;
1063
  }
1064
 
1065
+ /**
1066
+ * Reverse left vs right in a list of properties/values
1067
+ * @param array $array
1068
+ * @return array
1069
+ */
1070
+ public function reverse_left_and_right($array) {
1071
+ $return = array();
1072
+
1073
+ // change left <-> right in properties name and values
1074
+ foreach ($array as $propertie => $value) {
1075
+
1076
+ if (method_exists($this, $m = 'reverse_left_and_right_' . str_replace('-','_',trim($propertie)))) {
1077
+ $value = $this->$m($value);
1078
+ }
1079
+
1080
+ // simple replacement for properties
1081
+ $propertie = str_ireplace(array('left', 'right' ,"\x1"), array("\x1", 'left', 'right') , $propertie);
1082
+ // be careful for values, not modifying protected or quoted valued
1083
+ foreach (array('left' => "\x1", 'right' => 'left', "\x1" => 'right') as $v => $r) {
1084
+ if (strpos($value, $v) !== false) {
1085
+ // attraper les left et right separes du reste (pas au milieu d'un mot)
1086
+ if (in_array($v, array('left', 'right') )) {
1087
+ $value = preg_replace(",\\b$v\\b,", "\x0" , $value);
1088
+ }
1089
+ else {
1090
+ $value = str_replace($v, "\x0" , $value);
1091
+ }
1092
+ $value = $this->explode_ws("\x0", $value . ' ', true);
1093
+ $value = rtrim(implode($r, $value));
1094
+ $value = str_replace("\x0" , $v, $value);
1095
+ }
1096
+ }
1097
+ $return[$propertie] = $value;
1098
+ }
1099
+
1100
+ return $return;
1101
+ }
1102
+
1103
+ /**
1104
+ * Reversing 4 values shorthands properties
1105
+ * @param string $value
1106
+ * @return string
1107
+ */
1108
+ public function reverse_left_and_right_4value_shorthands($property, $value) {
1109
+ $shorthands = & $this->parser->data['csstidy']['shorthands'];
1110
+ if (isset($shorthands[$property])) {
1111
+ $property_right = $shorthands[$property][1];
1112
+ $property_left = $shorthands[$property][3];
1113
+ $v = $this->dissolve_4value_shorthands($property, $value);
1114
+ if ($v[$property_left] !== $v[$property_right]) {
1115
+ $r = $v[$property_right];
1116
+ $v[$property_right] = $v[$property_left];
1117
+ $v[$property_left] = $r;
1118
+ $v = $this->merge_4value_shorthands($v);
1119
+ if (isset($v[$property])) {
1120
+ return $v[$property];
1121
+ }
1122
+ }
1123
+ }
1124
+ return $value;
1125
+ }
1126
+
1127
+ /**
1128
+ * Reversing 4 values radius shorthands properties
1129
+ * @param string $value
1130
+ * @return string
1131
+ */
1132
+ public function reverse_left_and_right_4value_radius_shorthands($property, $value) {
1133
+ $shorthands = & $this->parser->data['csstidy']['radius_shorthands'];
1134
+ if (isset($shorthands[$property])) {
1135
+ $v = $this->dissolve_4value_radius_shorthands($property, $value);
1136
+ if ($v[$shorthands[$property][0]] !== $v[$shorthands[$property][1]]
1137
+ or $v[$shorthands[$property][2]] !== $v[$shorthands[$property][3]]) {
1138
+ $r = array(
1139
+ $shorthands[$property][0] => $v[$shorthands[$property][1]],
1140
+ $shorthands[$property][1] => $v[$shorthands[$property][0]],
1141
+ $shorthands[$property][2] => $v[$shorthands[$property][3]],
1142
+ $shorthands[$property][3] => $v[$shorthands[$property][2]],
1143
+ );
1144
+ $v = $this->merge_4value_radius_shorthands($r);
1145
+ if (isset($v[$property])) {
1146
+ return $v[$property];
1147
+ }
1148
+ }
1149
+ }
1150
+ return $value;
1151
+ }
1152
+
1153
+ /**
1154
+ * Reversing margin shorthands
1155
+ * @param string $value
1156
+ * @return string
1157
+ */
1158
+ public function reverse_left_and_right_margin($value) {
1159
+ return $this->reverse_left_and_right_4value_shorthands('margin', $value);
1160
+ }
1161
+
1162
+ /**
1163
+ * Reversing padding shorthands
1164
+ * @param string $value
1165
+ * @return string
1166
+ */
1167
+ public function reverse_left_and_right_padding($value) {
1168
+ return $this->reverse_left_and_right_4value_shorthands('padding', $value);
1169
+ }
1170
+
1171
+ /**
1172
+ * Reversing border-color shorthands
1173
+ * @param string $value
1174
+ * @return string
1175
+ */
1176
+ public function reverse_left_and_right_border_color($value) {
1177
+ return $this->reverse_left_and_right_4value_shorthands('border-color', $value);
1178
+ }
1179
+
1180
+ /**
1181
+ * Reversing border-style shorthands
1182
+ * @param string $value
1183
+ * @return string
1184
+ */
1185
+ public function reverse_left_and_right_border_style($value) {
1186
+ return $this->reverse_left_and_right_4value_shorthands('border-style', $value);
1187
+ }
1188
+
1189
+ /**
1190
+ * Reversing border-width shorthands
1191
+ * @param string $value
1192
+ * @return string
1193
+ */
1194
+ public function reverse_left_and_right_border_width($value) {
1195
+ return $this->reverse_left_and_right_4value_shorthands('border-width', $value);
1196
+ }
1197
+
1198
+ /**
1199
+ * Reversing border-radius shorthands
1200
+ * @param string $value
1201
+ * @return string
1202
+ */
1203
+ public function reverse_left_and_right_border_radius($value) {
1204
+ return $this->reverse_left_and_right_4value_radius_shorthands('border-radius', $value);
1205
+ }
1206
+
1207
+ /**
1208
+ * Reversing border-radius shorthands
1209
+ * @param string $value
1210
+ * @return string
1211
+ */
1212
+ public function reverse_left_and_right__moz_border_radius($value) {
1213
+ return $this->reverse_left_and_right_4value_radius_shorthands('border-radius', $value);
1214
+ }
1215
+
1216
+ /**
1217
+ * Reversing border-radius shorthands
1218
+ * @param string $value
1219
+ * @return string
1220
+ */
1221
+ public function reverse_left_and_right__webkit_border_radius($value) {
1222
+ return $this->reverse_left_and_right_4value_radius_shorthands('border-radius', $value);
1223
+ }
1224
+
1225
+
1226
+ /**
1227
+ * Reversing background shorthands
1228
+ * @param string $value
1229
+ * @return string
1230
+ */
1231
+ public function reverse_left_and_right_background($value) {
1232
+ $values = $this->dissolve_short_bg($value);
1233
+ if (isset($values['background-position']) and $values['background-position']) {
1234
+ $v = $this->reverse_left_and_right_background_position($values['background-position']);
1235
+ if ($v !== $values['background-position']) {
1236
+ if ($value == $values['background-position']) {
1237
+ return $v;
1238
+ }
1239
+ else {
1240
+ $values['background-position'] = $v;
1241
+ $x = $this->merge_bg($values);
1242
+ if (isset($x['background'])) {
1243
+ return $x['background'];
1244
+ }
1245
+ }
1246
+ }
1247
+ }
1248
+ return $value;
1249
+ }
1250
+
1251
+ /**
1252
+ * Reversing background position shorthands
1253
+ * @param string $value
1254
+ * @return string
1255
+ */
1256
+ public function reverse_left_and_right_background_position_x($value) {
1257
+ return $this->reverse_left_and_right_background_position($value);
1258
+ }
1259
+
1260
+ /**
1261
+ * Reversing background position shorthands
1262
+ * @param string $value
1263
+ * @return string
1264
+ */
1265
+ public function reverse_left_and_right_background_position($value) {
1266
+ // multiple background case
1267
+ if (strpos($value, ',') !== false) {
1268
+ $values = $this->explode_ws(',', $value);
1269
+ if (count($values) > 1) {
1270
+ foreach ($values as $k=>$v) {
1271
+ $values[$k] = $this->reverse_left_and_right_background_position($v);
1272
+ }
1273
+ return implode(',', $values);
1274
+ }
1275
+ }
1276
+
1277
+ // if no explicit left or right value
1278
+ if (stripos($value, 'left') === false and stripos($value, 'right') === false) {
1279
+ $values = $this->explode_ws(' ', trim($value));
1280
+ $values = array_map('trim', $values);
1281
+ $values = array_filter($values, function ($v) { return strlen($v);});
1282
+ $values = array_values($values);
1283
+ if (count($values) == 1) {
1284
+ if (in_array($value, array('center', 'top', 'bottom', 'inherit', 'initial', 'unset'))) {
1285
+ return $value;
1286
+ }
1287
+ return "left $value";
1288
+ }
1289
+ if ($values[1] == 'top' or $values[1] == 'bottom') {
1290
+ if ($values[0] === 'center') {
1291
+ return $value;
1292
+ }
1293
+ return 'left ' . implode(' ', $values);
1294
+ }
1295
+ else {
1296
+ $last = array_pop($values);
1297
+ if ($last === 'center') {
1298
+ return $value;
1299
+ }
1300
+ return implode(' ', $values) . ' left ' . $last;
1301
+ }
1302
+ }
1303
+
1304
+ return $value;
1305
+ }
1306
+
1307
  }
lib/CSSTidy/class.csstidy_print.php CHANGED
@@ -219,20 +219,25 @@ class csstidy_print {
219
  $output .= $template[0] . '@namespace ' . $template[5] . $this->namespace . $template[6] . $template[13];
220
  }
221
 
222
- $in_at_out = '';
223
  $out = & $output;
 
224
 
225
  foreach ($this->tokens as $key => $token) {
226
  switch ($token[0]) {
227
  case AT_START:
228
  $out .= $template[0] . $this->_htmlsp($token[1], $plain) . $template[1];
229
- $out = & $in_at_out;
 
 
 
 
230
  break;
231
 
232
  case SEL_START:
233
  if ($this->parser->get_cfg('lowercase_s'))
234
  $token[1] = strtolower($token[1]);
235
- $out .= ( $token[1]{0} !== '@') ? $template[2] . $this->_htmlsp($token[1], $plain) : $template[0] . $this->_htmlsp($token[1], $plain);
236
  $out .= $template[3];
237
  break;
238
 
@@ -261,14 +266,31 @@ class csstidy_print {
261
  break;
262
 
263
  case AT_END:
264
- $out = & $output;
265
- $in_at_out = str_replace("\n\n", "\r\n", $in_at_out); // don't fill empty lines
266
- $in_at_out = str_replace("\n", "\n" . $template[10], $in_at_out);
267
- $in_at_out = str_replace("\r\n", "\n\n", $in_at_out);
268
- $out .= $template[10] . $in_at_out . $template[9];
269
- $in_at_out = '';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270
  break;
271
 
 
272
  case COMMENT:
273
  $out .= $template[11] . '/*' . $this->_htmlsp($token[1], $plain) . '*/' . $template[12];
274
  break;
@@ -319,13 +341,22 @@ class csstidy_print {
319
  $sort_selectors = $this->parser->get_cfg('sort_selectors');
320
  $sort_properties = $this->parser->get_cfg('sort_properties');
321
 
 
 
 
 
 
 
322
  foreach ($this->css as $medium => $val) {
323
  if ($sort_selectors)
324
  ksort($val);
325
  if (intval($medium) < DEFAULT_AT) {
326
  // un medium vide (contenant @font-face ou autre @) ne produit aucun conteneur
327
  if (strlen(trim($medium))) {
328
- $this->parser->_add_token(AT_START, $medium, true);
 
 
 
329
  }
330
  } elseif ($default_media) {
331
  $this->parser->_add_token(AT_START, $default_media, true);
@@ -365,7 +396,10 @@ class csstidy_print {
365
  if (intval($medium) < DEFAULT_AT) {
366
  // un medium vide (contenant @font-face ou autre @) ne produit aucun conteneur
367
  if (strlen(trim($medium))) {
368
- $this->parser->_add_token(AT_END, $medium, true);
 
 
 
369
  }
370
  } elseif ($default_media) {
371
  $this->parser->_add_token(AT_END, $default_media, true);
219
  $output .= $template[0] . '@namespace ' . $template[5] . $this->namespace . $template[6] . $template[13];
220
  }
221
 
222
+ $in_at_out = [];
223
  $out = & $output;
224
+ $indent_level = 0;
225
 
226
  foreach ($this->tokens as $key => $token) {
227
  switch ($token[0]) {
228
  case AT_START:
229
  $out .= $template[0] . $this->_htmlsp($token[1], $plain) . $template[1];
230
+ $indent_level++;
231
+ if (!isset($in_at_out[$indent_level])) {
232
+ $in_at_out[$indent_level] = '';
233
+ }
234
+ $out = & $in_at_out[$indent_level];
235
  break;
236
 
237
  case SEL_START:
238
  if ($this->parser->get_cfg('lowercase_s'))
239
  $token[1] = strtolower($token[1]);
240
+ $out .= ( $token[1][0] !== '@') ? $template[2] . $this->_htmlsp($token[1], $plain) : $template[0] . $this->_htmlsp($token[1], $plain);
241
  $out .= $template[3];
242
  break;
243
 
266
  break;
267
 
268
  case AT_END:
269
+ if (strlen($template[10])) {
270
+ // indent the bloc we are closing
271
+ $out = str_replace("\n\n", "\r\n", $out); // don't fill empty lines
272
+ $out = str_replace("\n", "\n" . $template[10], $out);
273
+ $out = str_replace("\r\n", "\n\n", $out);
274
+ }
275
+ if ($indent_level > 1) {
276
+ $out = & $in_at_out[$indent_level-1];
277
+ }
278
+ else {
279
+ $out = & $output;
280
+ }
281
+ $out .= $template[10] . $in_at_out[$indent_level];
282
+ if ($this->_seeknocomment($key, 1) != AT_END) {
283
+ $out .= $template[9];
284
+ }
285
+ else {
286
+ $out .= rtrim($template[9]);
287
+ }
288
+
289
+ unset($in_at_out[$indent_level]);
290
+ $indent_level--;
291
  break;
292
 
293
+ case IMPORTANT_COMMENT:
294
  case COMMENT:
295
  $out .= $template[11] . '/*' . $this->_htmlsp($token[1], $plain) . '*/' . $template[12];
296
  break;
341
  $sort_selectors = $this->parser->get_cfg('sort_selectors');
342
  $sort_properties = $this->parser->get_cfg('sort_properties');
343
 
344
+ // important comment section ?
345
+ if (isset($this->css['!'])) {
346
+ $this->parser->_add_token(IMPORTANT_COMMENT, rtrim($this->css['!']), true);
347
+ unset($this->css['!']);
348
+ }
349
+
350
  foreach ($this->css as $medium => $val) {
351
  if ($sort_selectors)
352
  ksort($val);
353
  if (intval($medium) < DEFAULT_AT) {
354
  // un medium vide (contenant @font-face ou autre @) ne produit aucun conteneur
355
  if (strlen(trim($medium))) {
356
+ $parts_to_open = explode('{', $medium);
357
+ foreach ($parts_to_open as $part) {
358
+ $this->parser->_add_token(AT_START, $part, true);
359
+ }
360
  }
361
  } elseif ($default_media) {
362
  $this->parser->_add_token(AT_START, $default_media, true);
396
  if (intval($medium) < DEFAULT_AT) {
397
  // un medium vide (contenant @font-face ou autre @) ne produit aucun conteneur
398
  if (strlen(trim($medium))) {
399
+ $parts_to_close = explode('{', $medium);
400
+ foreach (array_reverse($parts_to_close) as $part) {
401
+ $this->parser->_add_token(AT_END, $part, true);
402
+ }
403
  }
404
  } elseif ($default_media) {
405
  $this->parser->_add_token(AT_END, $default_media, true);
lib/CSSTidy/data.inc.php CHANGED
@@ -55,7 +55,7 @@ $data['csstidy']['units'] = array('in','cm','mm','pt','pc','px','rem','em','%','
55
  * @global array $data['csstidy']['at_rules']
56
  * @version 1.1
57
  */
58
- $data['csstidy']['at_rules'] = array('page' => 'is','font-face' => 'atis','charset' => 'iv', 'import' => 'iv','namespace' => 'iv','media' => 'at','keyframes' => 'at','-moz-keyframes' => 'at','-o-keyframes' => 'at','-webkit-keyframes' => 'at','-ms-keyframes' => 'at');
59
 
60
  /**
61
  * Properties that need a value with unit
@@ -274,7 +274,10 @@ $data['csstidy']['shorthands']['border-style'] = array('border-top-style','borde
274
  $data['csstidy']['shorthands']['border-width'] = array('border-top-width','border-right-width','border-bottom-width','border-left-width');
275
  $data['csstidy']['shorthands']['margin'] = array('margin-top','margin-right','margin-bottom','margin-left');
276
  $data['csstidy']['shorthands']['padding'] = array('padding-top','padding-right','padding-bottom','padding-left');
277
- $data['csstidy']['shorthands']['-moz-border-radius'] = 0;
 
 
 
278
 
279
  /**
280
  * All CSS Properties. Needed for csstidy::property_is_next()
@@ -585,20 +588,20 @@ $data['csstidy']['multiple_properties'] = array('background', 'background-image'
585
  * @version 1.0
586
  * @see csstidy::load_template()
587
  */
588
- $data['csstidy']['predefined_templates']['default'][] = '<span class="at">'; //string before @rule
589
- $data['csstidy']['predefined_templates']['default'][] = '</span> <span class="format">{</span>'."\n"; //bracket after @-rule
590
- $data['csstidy']['predefined_templates']['default'][] = '<span class="selector">'; //string before selector
591
- $data['csstidy']['predefined_templates']['default'][] = '</span> <span class="format">{</span>'."\n"; //bracket after selector
592
- $data['csstidy']['predefined_templates']['default'][] = '<span class="property">'; //string before property
593
- $data['csstidy']['predefined_templates']['default'][] = '</span><span class="value">'; //string after property+before value
594
- $data['csstidy']['predefined_templates']['default'][] = '</span><span class="format">;</span>'."\n"; //string after value
595
- $data['csstidy']['predefined_templates']['default'][] = '<span class="format">}</span>'; //closing bracket - selector
596
- $data['csstidy']['predefined_templates']['default'][] = "\n\n"; //space between blocks {...}
597
- $data['csstidy']['predefined_templates']['default'][] = "\n".'<span class="format">}</span>'. "\n\n"; //closing bracket @-rule
598
- $data['csstidy']['predefined_templates']['default'][] = ''; //indent in @-rule
599
- $data['csstidy']['predefined_templates']['default'][] = '<span class="comment">'; // before comment
600
- $data['csstidy']['predefined_templates']['default'][] = '</span>'."\n"; // after comment
601
- $data['csstidy']['predefined_templates']['default'][] = "\n"; // after each line @-rule
602
 
603
  $data['csstidy']['predefined_templates']['high_compression'][] = '<span class="at">';
604
  $data['csstidy']['predefined_templates']['high_compression'][] = '</span> <span class="format">{</span>'."\n";
@@ -612,7 +615,7 @@ $data['csstidy']['predefined_templates']['high_compression'][] = "\n";
612
  $data['csstidy']['predefined_templates']['high_compression'][] = "\n". '<span class="format">}'."\n".'</span>';
613
  $data['csstidy']['predefined_templates']['high_compression'][] = '';
614
  $data['csstidy']['predefined_templates']['high_compression'][] = '<span class="comment">'; // before comment
615
- $data['csstidy']['predefined_templates']['high_compression'][] = '</span>'; // after comment
616
  $data['csstidy']['predefined_templates']['high_compression'][] = "\n";
617
 
618
  $data['csstidy']['predefined_templates']['highest_compression'][] = '<span class="at">';
55
  * @global array $data['csstidy']['at_rules']
56
  * @version 1.1
57
  */
58
+ $data['csstidy']['at_rules'] = array('page' => 'is','font-face' => 'atis','charset' => 'iv', 'import' => 'iv','namespace' => 'iv','media' => 'at', 'supports' => 'at', 'keyframes' => 'at','-moz-keyframes' => 'at','-o-keyframes' => 'at','-webkit-keyframes' => 'at','-ms-keyframes' => 'at');
59
 
60
  /**
61
  * Properties that need a value with unit
274
  $data['csstidy']['shorthands']['border-width'] = array('border-top-width','border-right-width','border-bottom-width','border-left-width');
275
  $data['csstidy']['shorthands']['margin'] = array('margin-top','margin-right','margin-bottom','margin-left');
276
  $data['csstidy']['shorthands']['padding'] = array('padding-top','padding-right','padding-bottom','padding-left');
277
+
278
+ $data['csstidy']['radius_shorthands']['border-radius'] = array('border-top-left-radius','border-top-right-radius','border-bottom-right-radius','border-bottom-left-radius');
279
+ $data['csstidy']['radius_shorthands']['-webkit-border-radius'] = array('-webkit-border-top-left-radius','-webkit-border-top-right-radius','-webkit-border-bottom-right-radius','-webkit-border-bottom-left-radius');
280
+ $data['csstidy']['radius_shorthands']['-moz-border-radius'] = array('-moz-border-radius-topleft','-moz-border-radius-topright','-moz-border-radius-bottomright','-moz-border-radius-bottomleft');
281
 
282
  /**
283
  * All CSS Properties. Needed for csstidy::property_is_next()
588
  * @version 1.0
589
  * @see csstidy::load_template()
590
  */
591
+ $data['csstidy']['predefined_templates']['default'][0] = '<span class="at">'; //string before @rule
592
+ $data['csstidy']['predefined_templates']['default'][1] = '</span> <span class="format">{</span>'."\n"; //bracket after @-rule
593
+ $data['csstidy']['predefined_templates']['default'][2] = '<span class="selector">'; //string before selector
594
+ $data['csstidy']['predefined_templates']['default'][3] = '</span> <span class="format">{</span>'."\n"; //bracket after selector
595
+ $data['csstidy']['predefined_templates']['default'][4] = '<span class="property">'; //string before property
596
+ $data['csstidy']['predefined_templates']['default'][5] = '</span><span class="value">'; //string after property+before value
597
+ $data['csstidy']['predefined_templates']['default'][6] = '</span><span class="format">;</span>'."\n"; //string after value
598
+ $data['csstidy']['predefined_templates']['default'][7] = '<span class="format">}</span>'; //closing bracket - selector
599
+ $data['csstidy']['predefined_templates']['default'][8] = "\n\n"; //space between blocks {...}
600
+ $data['csstidy']['predefined_templates']['default'][9] = "\n".'<span class="format">}</span>'. "\n\n"; //closing bracket @-rule
601
+ $data['csstidy']['predefined_templates']['default'][10] = ''; //indent in @-rule
602
+ $data['csstidy']['predefined_templates']['default'][11] = '<span class="comment">'; // before comment
603
+ $data['csstidy']['predefined_templates']['default'][12] = '</span>'."\n"; // after comment
604
+ $data['csstidy']['predefined_templates']['default'][13] = "\n"; // after each line @-rule
605
 
606
  $data['csstidy']['predefined_templates']['high_compression'][] = '<span class="at">';
607
  $data['csstidy']['predefined_templates']['high_compression'][] = '</span> <span class="format">{</span>'."\n";
615
  $data['csstidy']['predefined_templates']['high_compression'][] = "\n". '<span class="format">}'."\n".'</span>';
616
  $data['csstidy']['predefined_templates']['high_compression'][] = '';
617
  $data['csstidy']['predefined_templates']['high_compression'][] = '<span class="comment">'; // before comment
618
+ $data['csstidy']['predefined_templates']['high_compression'][] = '</span>'."\n"; // after comment
619
  $data['csstidy']['predefined_templates']['high_compression'][] = "\n";
620
 
621
  $data['csstidy']['predefined_templates']['highest_compression'][] = '<span class="at">';
lib/Minify/Minify/ImportProcessor.php CHANGED
@@ -188,7 +188,7 @@ class Minify_ImportProcessor {
188
  function truepath($path)
189
  {
190
  // whether $path is unix or not
191
- $unipath = strlen($path) == 0 || $path{0} != '/';
192
  // attempts to detect if path is relative in which case, add cwd
193
  if (strpos($path, ':') === false && $unipath)
194
  $path = $this->_currentDir . DIRECTORY_SEPARATOR . $path;
188
  function truepath($path)
189
  {
190
  // whether $path is unix or not
191
+ $unipath = strlen($path) == 0 || substr($path, 0, 1) != '/';
192
  // attempts to detect if path is relative in which case, add cwd
193
  if (strpos($path, ':') === false && $unipath)
194
  $path = $this->_currentDir . DIRECTORY_SEPARATOR . $path;
pub/css/feature-showcase.css ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @media screen and (max-width: 320px) {
2
+ .w3tc-card-container {
3
+ grid-template-columns: 1fr;
4
+ }
5
+ }
6
+
7
+ @media screen and (max-width: 900px) {
8
+ .w3tc-card-container {
9
+ grid-template-columns: 1fr 1fr;
10
+ }
11
+ }
12
+
13
+ @media screen and (min-width: 900px) {
14
+ .w3tc-card-container {
15
+ grid-template-columns: 1fr 1fr 1fr;
16
+ }
17
+ }
18
+
19
+ @media screen and (min-width: 1400px) {
20
+ .w3tc-card-container {
21
+ grid-template-columns: 1fr 1fr 1fr 1fr;
22
+ }
23
+ }
24
+
25
+ .w3tc-page-container {
26
+ max-width: 1234px;
27
+ padding: 0;
28
+ }
29
+
30
+ #w3tc_dashboard_banner {
31
+ max-width: 1234px;
32
+ width: 100%;
33
+ }
34
+
35
+ .w3tc-card-container {
36
+ display: grid;
37
+ grid-gap: 2em;
38
+ }
39
+
40
+ .w3tc-card {
41
+ background: #fff;
42
+ border: 1px solid #ddd;
43
+ display: flex;
44
+ flex-direction: column;
45
+ position: relative;
46
+ }
47
+
48
+ .w3tc-card-title {
49
+ height: 2.5em;
50
+ }
51
+
52
+ .w3tc-card-title.w3tc-card-premium {
53
+ background-color: #2d4149;
54
+ }
55
+
56
+ .w3tc-card-title.w3tc-card-premium > p {
57
+ color: #fff;
58
+ }
59
+
60
+ .w3tc-card-title.w3tc-card-premium > p.w3tc-card-pro {
61
+ color: #30bec3;
62
+ margin: 0;
63
+ }
64
+
65
+ .w3tc-card-title > p:first-child {
66
+ font-size: 1.3em;
67
+ margin: 0;
68
+ white-space: nowrap;
69
+ }
70
+
71
+ .w3tc-card-body {
72
+ flex-grow: 10;
73
+ }
74
+
75
+ .w3tc-card-title,
76
+ .w3tc-card-body {
77
+ padding: 10px 10px 15px 10px;
78
+ }
79
+
80
+ .w3tc-card-icon {
81
+ border-top: 3px solid #000;
82
+ border-bottom: 1px solid #ddd;
83
+ height: 60px;
84
+ padding: 20px 0;
85
+ text-align: center;
86
+ }
87
+
88
+ .w3tc-card-icon .dashicons {
89
+ font-size: 60px;
90
+ height: 60px;
91
+ width: 60px;
92
+ }
93
+
94
+ .w3tc-card-icon-inactive {
95
+ border-top-color: #aaa;
96
+ }
97
+
98
+ .w3tc-card-icon img {
99
+ max-height: 60px;
100
+ }
101
+
102
+ .w3tc-card-upgrade {
103
+ background: #e7e7e7;
104
+ }
105
+
106
+ .w3tc-card-ribbon-new {
107
+ height: 75px;
108
+ overflow: hidden;
109
+ position: absolute;
110
+ right: -5px; top: -5px;
111
+ text-align: right;
112
+ width: 75px;
113
+ z-index: 1;
114
+ }
115
+
116
+ .w3tc-card-ribbon-new span {
117
+ background: #30bec3;
118
+ box-shadow: 0 3px 10px -5px rgba(0, 0, 0, 0.5);
119
+ color: #fff;
120
+ display: block;
121
+ font-size: 12px;
122
+ font-weight: bold;
123
+ line-height: 20px;
124
+ position: absolute;
125
+ right: -21px;
126
+ text-transform: uppercase;
127
+ text-align: center;
128
+ top: 19px;
129
+ transform: rotate(45deg);
130
+ -webkit-transform: rotate(45deg); /* Needed for Safari */
131
+ width: 100px;
132
+ }
133
+
134
+ .w3tc-card-ribbon-new span::before {
135
+ border-left: 3px solid #30bec3;
136
+ border-right: 3px solid transparent;
137
+ border-bottom: 3px solid transparent;
138
+ border-top: 3px solid #30bec3;
139
+ content: '';
140
+ left: 0px;
141
+ position: absolute;
142
+ top: 100%;
143
+ z-index: -1;
144
+ }
145
+
146
+ .w3tc-card-ribbon-new span::after {
147
+ border-right: 3px solid #30bec3;
148
+ border-left: 3px solid transparent;
149
+ border-bottom: 3px solid transparent;
150
+ border-top: 3px solid #30bec3;
151
+ content: '';
152
+ position: absolute;
153
+ right: 0%;
154
+ top: 100%;
155
+ z-index: -1;
156
+ }
157
+
158
+ .w3tc-card-footer {
159
+ margin: 0 0 10px 10px;
160
+ }
161
+
162
+ .w3tc-card-footer > div {
163
+ display: inline-block;
164
+ text-align: center;
165
+ vertical-align: middle;
166
+ width: 50%;
167
+ }
pub/css/options.css CHANGED
@@ -145,7 +145,8 @@ input.w3tc-error, textarea.w3tc-error {
145
  -moz-border-radius: 11px;
146
  }
147
 
148
- #w3tc fieldset .submit {
 
149
  margin: 1em 0 0 0;
150
  padding: 0;
151
  }
@@ -202,7 +203,7 @@ input.w3tc-error, textarea.w3tc-error {
202
  #mobile_groups td,
203
  #referrer_groups td,
204
  .w3tc_cachegroups td,
205
- {
206
  padding: 10px 10px 10px 15px;
207
  }
208
 
@@ -441,6 +442,10 @@ td.w3tc_config_value_text {
441
  color: #ddd;
442
  }
443
 
 
 
 
 
444
  .w3tc_popup_form {
445
  padding: 20px;
446
  }
@@ -636,7 +641,7 @@ table:not(.w3tc-pro-feature) .w3tc-gopro:after {
636
 
637
  #w3tc_dashboard_banner .inside > p:first-of-type {
638
  margin-top: 0;
639
- padding-top: 1em;
640
  }
641
 
642
  #w3tc_dashboard_banner .postbox .hndle {
@@ -687,4 +692,4 @@ table:not(.w3tc-pro-feature) .w3tc-gopro:after {
687
  .w3tc-label-danger {
688
  /* Same color as "update plugin count" in WP Dashboard left nav. */
689
  background: #ca4a1f;;
690
- }
145
  -moz-border-radius: 11px;
146
  }
147
 
148
+ #w3tc fieldset .submit,
149
+ #cachegroups_form .submit {
150
  margin: 1em 0 0 0;
151
  padding: 0;
152
  }
203
  #mobile_groups td,
204
  #referrer_groups td,
205
  .w3tc_cachegroups td,
206
+ #cachegroups_form .form-table th {
207
  padding: 10px 10px 10px 15px;
208
  }
209
 
442
  color: #ddd;
443
  }
444
 
445
+ #toplevel_page_w3tc_dashboard li a[href="admin.php?page=w3tc_support"] {
446
+ color: red;
447
+ }
448
+
449
  .w3tc_popup_form {
450
  padding: 20px;
451
  }
641
 
642
  #w3tc_dashboard_banner .inside > p:first-of-type {
643
  margin-top: 0;
644
+ padding-top: 1em;
645
  }
646
 
647
  #w3tc_dashboard_banner .postbox .hndle {
692
  .w3tc-label-danger {
693
  /* Same color as "update plugin count" in WP Dashboard left nav. */
694
  background: #ca4a1f;;
695
+ }
pub/css/setup-guide.css CHANGED
@@ -1,4 +1,3 @@
1
-
2
  .w3tc-setupguide-table th,
3
  .w3tc-setupguide-table td {
4
  text-align: left;
 
1
  .w3tc-setupguide-table th,
2
  .w3tc-setupguide-table td {
3
  text-align: left;
pub/css/wizard.css CHANGED
@@ -18,7 +18,7 @@
18
  #w3tc_wizard_title {
19
  color: #fff;
20
  position: absolute;
21
- bottom: 0;
22
  }
23
 
24
  /* Title text: "TOTAL CACHE:" */
@@ -42,8 +42,8 @@
42
  /* Wizard icon (w3 cube with shadow) */
43
  #w3tc_wizard_icon {
44
  position: absolute;
45
- top: 10px;
46
- left: -2px;
47
  }
48
 
49
  /**
18
  #w3tc_wizard_title {
19
  color: #fff;
20
  position: absolute;
21
+ bottom: 0;
22
  }
23
 
24
  /* Title text: "TOTAL CACHE:" */
42
  /* Wizard icon (w3 cube with shadow) */
43
  #w3tc_wizard_icon {
44
  position: absolute;
45
+ top: 10px;
46
+ left: -2px;
47
  }
48
 
49
  /**
pub/js/feature-counter.js ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * File: feature-counter.js
3
+ *
4
+ * JavaScript for feature counters.
5
+ *
6
+ * @since 2.1.0
7
+ *
8
+ * @global W3TCFeatureShowcaseData
9
+ */
10
+
11
+ jQuery(function() {
12
+ var $adminmenuItem = jQuery ( '#wp-admin-bar-w3tc_feature_showcase a' ),
13
+ $menuItem = jQuery( '#toplevel_page_w3tc_dashboard.wp-not-current-submenu a[href="admin.php?page=w3tc_dashboard"] .wp-menu-name' ),
14
+ $submenuItem = jQuery( '#toplevel_page_w3tc_dashboard a[href="admin.php?page=w3tc_feature_showcase"]' ),
15
+ markup = ' <span class="awaiting-mod count-' +
16
+ W3TCFeatureShowcaseData.unseenCount +
17
+ '"><span class="feature-count">' +
18
+ W3TCFeatureShowcaseData.unseenCount +
19
+ '</span></span>';
20
+
21
+ if ( W3TCFeatureShowcaseData.unseenCount > 0 ) {
22
+ if ( $adminmenuItem.length ) {
23
+ $adminmenuItem.append( markup );
24
+
25
+ $adminmenuItem.find( '.awaiting-mod' ).css(
26
+ {
27
+ padding: "0 5px",
28
+ "min-width": "18px",
29
+ height: "18px",
30
+ "border-radius": "9px",
31
+ "background-color": "#ca4a1f",
32
+ color: "#fff",
33
+ "font-size": "11px"
34
+ }
35
+ );
36
+ }
37
+
38
+ if ( $menuItem.length ) {
39
+ $menuItem.append( markup );
40
+ }
41
+
42
+ if ( $submenuItem.length ) {
43
+ $submenuItem.append( markup );
44
+ }
45
+ }
46
+ });
pub/js/jquery.masonry.min.js CHANGED
@@ -7,4 +7,4 @@
7
  * Licensed under the MIT license.
8
  * Copyright 2012 David DeSandro
9
  */
10
- (function(e,t,n){"use strict";var r=t.event,i;r.special.smartresize={setup:function(){t(this).bind("resize",r.special.smartresize.handler)},teardown:function(){t(this).unbind("resize",r.special.smartresize.handler)},handler:function(e,t){var n=this,s=arguments;e.type="smartresize",i&&clearTimeout(i),i=setTimeout(function(){r.dispatch.apply(n,s)},t==="execAsap"?0:100)}},t.fn.smartresize=function(e){return e?this.bind("smartresize",e):this.trigger("smartresize",["execAsap"])},t.Mason=function(e,n){this.element=t(n),this._create(e),this._init()},t.Mason.settings={isResizable:!0,isAnimated:!1,animationOptions:{queue:!1,duration:500},gutterWidth:0,isRTL:!1,isFitWidth:!1,containerStyle:{position:"relative"}},t.Mason.prototype={_filterFindBricks:function(e){var t=this.options.itemSelector;return t?e.filter(t).add(e.find(t)):e},_getBricks:function(e){var t=this._filterFindBricks(e).css({position:"absolute"}).addClass("masonry-brick");return t},_create:function(n){this.options=t.extend(!0,{},t.Mason.settings,n),this.styleQueue=[];var r=this.element[0].style;this.originalStyle={height:r.height||""};var i=this.options.containerStyle;for(var s in i)this.originalStyle[s]=r[s]||"";this.element.css(i),this.horizontalDirection=this.options.isRTL?"right":"left";var o=this.element.css("padding-"+this.horizontalDirection),u=this.element.css("padding-top");this.offset={x:o?parseInt(o,10):0,y:u?parseInt(u,10):0},this.isFluid=this.options.columnWidth&&typeof this.options.columnWidth=="function";var a=this;setTimeout(function(){a.element.addClass("masonry")},0),this.options.isResizable&&t(e).bind("smartresize.masonry",function(){a.resize()}),this.reloadItems()},_init:function(e){this._getColumns(),this._reLayout(e)},option:function(e,n){t.isPlainObject(e)&&(this.options=t.extend(!0,this.options,e))},layout:function(e,t){for(var n=0,r=e.length;n<r;n++)this._placeBrick(e[n]);var i={};i.height=Math.max.apply(Math,this.colYs);if(this.options.isFitWidth){var s=0;n=this.cols;while(--n){if(this.colYs[n]!==0)break;s++}i.width=(this.cols-s)*this.columnWidth-this.options.gutterWidth}this.styleQueue.push({$el:this.element,style:i});var o=this.isLaidOut?this.options.isAnimated?"animate":"css":"css",u=this.options.animationOptions,a;for(n=0,r=this.styleQueue.length;n<r;n++)a=this.styleQueue[n],a.$el[o](a.style,u);this.styleQueue=[],t&&t.call(e),this.isLaidOut=!0},_getColumns:function(){var e=this.options.isFitWidth?this.element.parent():this.element,t=e.width();this.columnWidth=this.isFluid?this.options.columnWidth(t):this.options.columnWidth||this.$bricks.outerWidth(!0)||t,this.columnWidth+=this.options.gutterWidth,this.cols=Math.floor((t+this.options.gutterWidth)/this.columnWidth),this.cols=Math.max(this.cols,1)},_placeBrick:function(e){var n=t(e),r,i,s,o,u;r=Math.ceil(n.outerWidth(!0)/this.columnWidth),r=Math.min(r,this.cols);if(r===1)s=this.colYs;else{i=this.cols+1-r,s=[];for(u=0;u<i;u++)o=this.colYs.slice(u,u+r),s[u]=Math.max.apply(Math,o)}var a=Math.min.apply(Math,s),f=0;for(var l=0,c=s.length;l<c;l++)if(s[l]===a){f=l;break}var h={top:a+this.offset.y};h[this.horizontalDirection]=this.columnWidth*f+this.offset.x,this.styleQueue.push({$el:n,style:h});var p=a+n.outerHeight(!0),d=this.cols+1-c;for(l=0;l<d;l++)this.colYs[f+l]=p},resize:function(){var e=this.cols;this._getColumns(),(this.isFluid||this.cols!==e)&&this._reLayout()},_reLayout:function(e){var t=this.cols;this.colYs=[];while(t--)this.colYs.push(0);this.layout(this.$bricks,e)},reloadItems:function(){this.$bricks=this._getBricks(this.element.children())},reload:function(e){this.reloadItems(),this._init(e)},appended:function(e,t,n){if(t){this._filterFindBricks(e).css({top:this.element.height()});var r=this;setTimeout(function(){r._appended(e,n)},1)}else this._appended(e,n)},_appended:function(e,t){var n=this._getBricks(e);this.$bricks=this.$bricks.add(n),this.layout(n,t)},remove:function(e){this.$bricks=this.$bricks.not(e),e.remove()},destroy:function(){this.$bricks.removeClass("masonry-brick").each(function(){this.style.position="",this.style.top="",this.style.left=""});var n=this.element[0].style;for(var r in this.originalStyle)n[r]=this.originalStyle[r];this.element.unbind(".masonry").removeClass("masonry").removeData("masonry"),t(e).unbind(".masonry")}},t.fn.imagesLoaded=function(e){function u(){e.call(n,r)}function a(e){var n=e.target;n.src!==s&&t.inArray(n,o)===-1&&(o.push(n),--i<=0&&(setTimeout(u),r.unbind(".imagesLoaded",a)))}var n=this,r=n.find("img").add(n.filter("img")),i=r.length,s="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==",o=[];return i||u(),r.bind("load.imagesLoaded error.imagesLoaded",a).each(function(){var e=this.src;this.src=s,this.src=e}),n};var s=function(t){e.console&&e.console.error(t)};t.fn.masonry=function(e){if(typeof e=="string"){var n=Array.prototype.slice.call(arguments,1);this.each(function(){var r=t.data(this,"masonry");if(!r){s("cannot call methods on masonry prior to initialization; attempted to call method '"+e+"'");return}if(!t.isFunction(r[e])||e.charAt(0)==="_"){s("no such method '"+e+"' for masonry instance");return}r[e].apply(r,n)})}else this.each(function(){var n=t.data(this,"masonry");n?(n.option(e||{}),n._init()):t.data(this,"masonry",new t.Mason(e,this))});return this}})(window,jQuery);
7
  * Licensed under the MIT license.
8
  * Copyright 2012 David DeSandro
9
  */
10
+ (function(e,t,n){"use strict";var r=t.event,i;r.special.smartresize={setup:function(){t(this).bind("resize",r.special.smartresize.handler)},teardown:function(){t(this).off("resize",r.special.smartresize.handler)},handler:function(e,t){var n=this,s=arguments;e.type="smartresize",i&&clearTimeout(i),i=setTimeout(function(){r.dispatch.apply(n,s)},t==="execAsap"?0:100)}},t.fn.smartresize=function(e){return e?this.bind("smartresize",e):this.trigger("smartresize",["execAsap"])},t.Mason=function(e,n){this.element=t(n),this._create(e),this._init()},t.Mason.settings={isResizable:!0,isAnimated:!1,animationOptions:{queue:!1,duration:500},gutterWidth:0,isRTL:!1,isFitWidth:!1,containerStyle:{position:"relative"}},t.Mason.prototype={_filterFindBricks:function(e){var t=this.options.itemSelector;return t?e.filter(t).add(e.find(t)):e},_getBricks:function(e){var t=this._filterFindBricks(e).css({position:"absolute"}).addClass("masonry-brick");return t},_create:function(n){this.options=t.extend(!0,{},t.Mason.settings,n),this.styleQueue=[];var r=this.element[0].style;this.originalStyle={height:r.height||""};var i=this.options.containerStyle;for(var s in i)this.originalStyle[s]=r[s]||"";this.element.css(i),this.horizontalDirection=this.options.isRTL?"right":"left";var o=this.element.css("padding-"+this.horizontalDirection),u=this.element.css("padding-top");this.offset={x:o?parseInt(o,10):0,y:u?parseInt(u,10):0},this.isFluid=this.options.columnWidth&&typeof this.options.columnWidth=="function";var a=this;setTimeout(function(){a.element.addClass("masonry")},0),this.options.isResizable&&t(e).bind("smartresize.masonry",function(){a.resize()}),this.reloadItems()},_init:function(e){this._getColumns(),this._reLayout(e)},option:function(e,n){t.isPlainObject(e)&&(this.options=t.extend(!0,this.options,e))},layout:function(e,t){for(var n=0,r=e.length;n<r;n++)this._placeBrick(e[n]);var i={};i.height=Math.max.apply(Math,this.colYs);if(this.options.isFitWidth){var s=0;n=this.cols;while(--n){if(this.colYs[n]!==0)break;s++}i.width=(this.cols-s)*this.columnWidth-this.options.gutterWidth}this.styleQueue.push({$el:this.element,style:i});var o=this.isLaidOut?this.options.isAnimated?"animate":"css":"css",u=this.options.animationOptions,a;for(n=0,r=this.styleQueue.length;n<r;n++)a=this.styleQueue[n],a.$el[o](a.style,u);this.styleQueue=[],t&&t.call(e),this.isLaidOut=!0},_getColumns:function(){var e=this.options.isFitWidth?this.element.parent():this.element,t=e.width();this.columnWidth=this.isFluid?this.options.columnWidth(t):this.options.columnWidth||this.$bricks.outerWidth(!0)||t,this.columnWidth+=this.options.gutterWidth,this.cols=Math.floor((t+this.options.gutterWidth)/this.columnWidth),this.cols=Math.max(this.cols,1)},_placeBrick:function(e){var n=t(e),r,i,s,o,u;r=Math.ceil(n.outerWidth(!0)/this.columnWidth),r=Math.min(r,this.cols);if(r===1)s=this.colYs;else{i=this.cols+1-r,s=[];for(u=0;u<i;u++)o=this.colYs.slice(u,u+r),s[u]=Math.max.apply(Math,o)}var a=Math.min.apply(Math,s),f=0;for(var l=0,c=s.length;l<c;l++)if(s[l]===a){f=l;break}var h={top:a+this.offset.y};h[this.horizontalDirection]=this.columnWidth*f+this.offset.x,this.styleQueue.push({$el:n,style:h});var p=a+n.outerHeight(!0),d=this.cols+1-c;for(l=0;l<d;l++)this.colYs[f+l]=p},resize:function(){var e=this.cols;this._getColumns(),(this.isFluid||this.cols!==e)&&this._reLayout()},_reLayout:function(e){var t=this.cols;this.colYs=[];while(t--)this.colYs.push(0);this.layout(this.$bricks,e)},reloadItems:function(){this.$bricks=this._getBricks(this.element.children())},reload:function(e){this.reloadItems(),this._init(e)},appended:function(e,t,n){if(t){this._filterFindBricks(e).css({top:this.element.height()});var r=this;setTimeout(function(){r._appended(e,n)},1)}else this._appended(e,n)},_appended:function(e,t){var n=this._getBricks(e);this.$bricks=this.$bricks.add(n),this.layout(n,t)},remove:function(e){this.$bricks=this.$bricks.not(e),e.remove()},destroy:function(){this.$bricks.removeClass("masonry-brick").each(function(){this.style.position="",this.style.top="",this.style.left=""});var n=this.element[0].style;for(var r in this.originalStyle)n[r]=this.originalStyle[r];this.element.off(".masonry").removeClass("masonry").removeData("masonry"),t(e).off(".masonry")}},t.fn.imagesLoaded=function(e){function u(){e.call(n,r)}function a(e){var n=e.target;n.src!==s&&t.inArray(n,o)===-1&&(o.push(n),--i<=0&&(setTimeout(u),r.off(".imagesLoaded",a)))}var n=this,r=n.find("img").add(n.filter("img")),i=r.length,s="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==",o=[];return i||u(),r.bind("load.imagesLoaded error.imagesLoaded",a).each(function(){var e=this.src;this.src=s,this.src=e}),n};var s=function(t){e.console&&e.console.error(t)};t.fn.masonry=function(e){if(typeof e=="string"){var n=Array.prototype.slice.call(arguments,1);this.each(function(){var r=t.data(this,"masonry");if(!r){s("cannot call methods on masonry prior to initialization; attempted to call method '"+e+"'");return}if(!t.isFunction(r[e])||e.charAt(0)==="_"){s("no such method '"+e+"' for masonry instance");return}r[e].apply(r,n)})}else this.each(function(){var n=t.data(this,"masonry");n?(n.option(e||{}),n._init()):t.data(this,"masonry",new t.Mason(e,this))});return this}})(window,jQuery);
pub/js/options.js CHANGED
@@ -48,22 +48,6 @@ function w3tc_minify_css_file_clear() {
48
  }
49
  }
50
 
51
- function w3tc_mobile_groups_clear() {
52
- if (!jQuery('#mobile_groups li').length) {
53
- jQuery('#mobile_groups_empty').show();
54
- } else {
55
- jQuery('#mobile_groups_empty').hide();
56
- }
57
- }
58
-
59
- function w3tc_referrer_groups_clear() {
60
- if (!jQuery('#referrer_groups li').length) {
61
- jQuery('#referrer_groups_empty').show();
62
- } else {
63
- jQuery('#referrer_groups_empty').hide();
64
- }
65
- }
66
-
67
  function w3tc_minify_js_file_add(theme, template, location, file) {
68
  var append = jQuery('<li><table><tr><th>&nbsp;</th><th>File URI:</th><th>Template:</th><th colspan="3">Embed Location:</th></tr><tr><td>' + (jQuery('#js_files li').length + 1) + '.</td><td><input class="js_enabled" type="text" name="js_files[' + theme + '][' + template + '][' + location + '][]" value="" size="70" \/></td><td><select class="js_file_template js_enabled"></select></td><td><select class="js_file_location js_enabled"><option value="include">Embed in &lt;head&gt;</option><option value="include-body">Embed after &lt;body&gt;</option><option value="include-footer">Embed before &lt;/body&gt;</option></select></td><td><input class="js_file_delete js_enabled button" type="button" value="Delete" /> <input class="js_file_verify js_enabled button" type="button" value="Verify URI" /></td></tr></table><\/li>');
69
  append.find('input:text').val(file);
@@ -253,7 +237,7 @@ function w3tc_beforeupload_bind() {
253
  }
254
 
255
  function w3tc_beforeupload_unbind() {
256
- jQuery(window).unbind('beforeunload', w3tc_beforeunload);
257
  }
258
 
259
  function w3tc_beforeunload() {
@@ -1086,210 +1070,6 @@ jQuery(function() {
1086
  return ret;
1087
  });
1088
 
1089
- // mobile tab
1090
- jQuery('#mobile_form').on( 'submit', function() {
1091
- var error = false;
1092
-
1093
- jQuery('#mobile_groups li').each(function() {
1094
- if (jQuery(this).find(':checked').length) {
1095
- var group = jQuery(this).find('.mobile_group').text();
1096
- var theme = jQuery(this).find(':selected').val();
1097
- var redirect = jQuery(this).find('input[type=text]').val();
1098
- var agents = jQuery.trim(jQuery(this).find('textarea').val()).split("\n");
1099
-
1100
- jQuery('#mobile_groups li').each(function() {
1101
- if (jQuery(this).find(':checked').length) {
1102
- var compare_group = jQuery(this).find('.mobile_group').text();
1103
- if (compare_group != group) {
1104
- var compare_theme = jQuery(this).find(':selected').val();
1105
- var compare_redirect = jQuery(this).find('input[type=text]').val();
1106
- var compare_agents = jQuery.trim(jQuery(this).find('textarea').val()).split("\n");
1107
-
1108
- if (compare_redirect == '' && redirect == '' && compare_theme != '' && compare_theme == theme) {
1109
- alert('Duplicate theme "' + compare_theme + '" found in the group "' + group + '".');
1110
- error = true;
1111
- return false;
1112
- }
1113
-
1114
- if (compare_redirect != '' && compare_redirect == redirect) {
1115
- alert('Duplicate redirect "' + compare_redirect + '" found in the group "' + group + '".');
1116
- error = true;
1117
- return false;
1118
- }
1119
-
1120
- jQuery.each(compare_agents, function(index, value) {
1121
- if (jQuery.inArray(value, agents) != -1) {
1122
- alert('Duplicate stem "' + value + '" found in the group "' + compare_group + '".');
1123
- error = true;
1124
- return false;
1125
- }
1126
- });
1127
- }
1128
- }
1129
- });
1130
-
1131
- if (error) {
1132
- return false;
1133
- }
1134
- }
1135
- });
1136
-
1137
- if (error) {
1138
- return false;
1139
- }
1140
- });
1141
-
1142
- jQuery('#mobile_add').on( 'click', function() {
1143
- var group = prompt('Enter group name (only "0-9", "a-z", "_" symbols are allowed).');
1144
-
1145
- if (group !== null) {
1146
- group = group.toLowerCase();
1147
- group = group.replace(/[^0-9a-z_]+/g, '_');
1148
- group = group.replace(/^_+/, '');
1149
- group = group.replace(/_+$/, '');
1150
-
1151
- if (group) {
1152
- var exists = false;
1153
-
1154
- jQuery('.mobile_group').each(function() {
1155
- if (jQuery(this).html() == group) {
1156
- alert('Group already exists!');
1157
- exists = true;
1158
- return false;
1159
- }
1160
- });
1161
-
1162
- if (!exists) {
1163
- var li = jQuery('<li id="mobile_group_' + group + '"><table class="form-table"><tr><th>Group name:</th><td><span class="mobile_group_number">' + (jQuery('#mobile_groups li').length + 1) + '.</span> <span class="mobile_group">' + group + '</span> <input type="button" class="button mobile_delete" value="Delete group" /></td></tr><tr><th><label for="mobile_groups_' + group + '_enabled">Enabled:</label></th><td><input type="hidden" name="mobile_groups[' + group + '][enabled]" value="0" /><input id="mobile_groups_' + group + '_enabled" type="checkbox" name="mobile_groups[' + group + '][enabled]" value="1" checked="checked" /></td></tr><tr><th><label for="mobile_groups_' + group + '_theme">Theme:</label></th><td><select id="mobile_groups_' + group + '_theme" name="mobile_groups[' + group + '][theme]"><option value="">-- Pass-through --</option></select><p class="description">Assign this group of user agents to a specific them. Leaving this option "Active Theme" allows any plugins you have (e.g. mobile plugins) to properly handle requests for these user agents. If the "redirect users to" field is not empty, this setting is ignored.</p></td></tr><tr><th><label for="mobile_groups_' + group + '_redirect">Redirect users to:</label></th><td><input id="mobile_groups_' + group + '_redirect" type="text" name="mobile_groups[' + group + '][redirect]" value="" size="60" /><p class="description">A 302 redirect is used to send this group of users to another hostname (domain); recommended if a 3rd party service provides a mobile version of your site.</p></td></tr><tr><th><label for="mobile_groups_' + group + '_agents">User agents:</label></th><td><textarea id="mobile_groups_' + group + '_agents" name="mobile_groups[' + group + '][agents]" rows="10" cols="50"></textarea><p class="description">Specify the user agents for this group.</p></td></tr></table></li>');
1164
- var select = li.find('select');
1165
-
1166
- jQuery.each(mobile_themes, function(index, value) {
1167
- select.append(jQuery('<option />').val(index).html(value));
1168
- });
1169
-
1170
- jQuery('#mobile_groups').append(li);
1171
- w3tc_mobile_groups_clear();
1172
- window.location.hash = '#mobile_group_' + group;
1173
- li.find('textarea').focus();
1174
- }
1175
- } else {
1176
- alert('Empty group name!');
1177
- }
1178
- }
1179
- });
1180
-
1181
- jQuery('.mobile_delete').on('click', function () {
1182
- if (confirm('Are you sure want to delete this group?')) {
1183
- jQuery(this).parents('#mobile_groups li').remove();
1184
- w3tc_mobile_groups_clear();
1185
- w3tc_beforeupload_bind();
1186
- }
1187
- });
1188
-
1189
- w3tc_mobile_groups_clear();
1190
-
1191
- // referrer tab
1192
- jQuery('#referrer_form').on( 'submit', function() {
1193
- var error = false;
1194
-
1195
- jQuery('#referrer_groups li').each(function() {
1196
- if (jQuery(this).find(':checked').length) {
1197
- var group = jQuery(this).find('.referrer_group').text();
1198
- var theme = jQuery(this).find(':selected').val();
1199
- var redirect = jQuery(this).find('input[type=text]').val();
1200
- var agents = jQuery.trim(jQuery(this).find('textarea').val()).split("\n");
1201
-
1202
- jQuery('#referrer_groups li').each(function() {
1203
- if (jQuery(this).find(':checked').length) {
1204
- var compare_group = jQuery(this).find('.referrer_group').text();
1205
- if (compare_group != group) {
1206
- var compare_theme = jQuery(this).find(':selected').val();
1207
- var compare_redirect = jQuery(this).find('input[type=text]').val();
1208
- var compare_agents = jQuery.trim(jQuery(this).find('textarea').val()).split("\n");
1209
-
1210
- if (compare_redirect == '' && redirect == '' && compare_theme != '' && compare_theme == theme) {
1211
- alert('Duplicate theme "' + compare_theme + '" found in the group "' + group + '".');
1212
- error = true;
1213
- return false;
1214
- }
1215
-
1216
- if (compare_redirect != '' && compare_redirect == redirect) {
1217
- alert('Duplicate redirect "' + compare_redirect + '" found in the group "' + group + '".');
1218
- error = true;
1219
- return false;
1220
- }
1221
-
1222
- jQuery.each(compare_agents, function(index, value) {
1223
- if (jQuery.inArray(value, agents) != -1) {
1224
- alert('Duplicate stem "' + value + '" found in the group "' + compare_group + '".');
1225
- error = true;
1226
- return false;
1227
- }
1228
- });
1229
- }
1230
- }
1231
- });
1232
-
1233
- if (error) {
1234
- return false;
1235
- }
1236
- }
1237
- });
1238
-
1239
- if (error) {
1240
- return false;
1241
- }
1242
- });
1243
-
1244
- jQuery('#referrer_add').on( 'click', function() {
1245
- var group = prompt('Enter group name (only "0-9", "a-z", "_" symbols are allowed).');
1246
-
1247
- if (group !== null) {
1248
- group = group.toLowerCase();
1249
- group = group.replace(/[^0-9a-z_]+/g, '_');
1250
- group = group.replace(/^_+/, '');
1251
- group = group.replace(/_+$/, '');
1252
-
1253
- if (group) {
1254
- var exists = false;
1255
-
1256
- jQuery('.referrer_group').each(function() {
1257
- if (jQuery(this).html() == group) {
1258
- alert('Group already exists!');
1259
- exists = true;
1260
- return false;
1261
- }
1262
- });
1263
-
1264
- if (!exists) {
1265
- var li = jQuery('<li id="referrer_group_' + group + '"><table class="form-table"><tr><th>Group name:</th><td><span class="referrer_group_number">' + (jQuery('#referrer_groups li').length + 1) + '.</span> <span class="referrer_group">' + group + '</span> <input type="button" class="button referrer_delete" value="Delete group" /></td></tr><tr><th><label for="referrer_groups_' + group + '_enabled">Enabled:</label></th><td><input type="hidden" name="referrer_groups[' + group + '][enabled]" value="0" /><input id="referrer_groups_' + group + '_enabled" type="checkbox" name="referrer_groups[' + group + '][enabled]" value="1" checked="checked" /></td></tr><tr><th><label for="referrer_groups_' + group + '_theme">Theme:</label></th><td><select id="referrer_groups_' + group + '_theme" name="referrer_groups[' + group + '][theme]"><option value="">-- Pass-through --</option></select><p class="description">Assign this group of referrers to a specific them. Leaving this option "Active Theme" allows any plugins you have (e.g. referrer plugins) to properly handle requests for these referrers. If the "redirect users to" field is not empty, this setting is ignored.</p></td></tr><tr><th><label for="referrer_groups_' + group + '_redirect">Redirect users to:</label></th><td><input id="referrer_groups_' + group + '_redirect" type="text" name="referrer_groups[' + group + '][redirect]" value="" size="60" /><p class="description">A 302 redirect is used to send this group of users to another hostname (domain); recommended if a 3rd party service provides a referrer version of your site.</p></td></tr><tr><th><label for="referrer_groups_' + group + '_referrers">Referrers:</label></th><td><textarea id="referrer_groups_' + group + '_referrers" name="referrer_groups[' + group + '][referrers]" rows="10" cols="50"></textarea><p class="description">Specify the referrers for this group.</p></td></tr></table></li>');
1266
- var select = li.find('select');
1267
-
1268
- jQuery.each(referrer_themes, function(index, value) {
1269
- select.append(jQuery('<option />').val(index).html(value));
1270
- });
1271
-
1272
- jQuery('#referrer_groups').append(li);
1273
- w3tc_referrer_groups_clear();
1274
- window.location.hash = '#referrer_group_' + group;
1275
- li.find('textarea').focus();
1276
- }
1277
- } else {
1278
- alert('Empty group name!');
1279
- }
1280
- }
1281
- });
1282
-
1283
- jQuery('.referrer_delete').on('click', function () {
1284
- if (confirm('Are you sure want to delete this group?')) {
1285
- jQuery(this).parents('#referrer_groups li').remove();
1286
- w3tc_referrer_groups_clear();
1287
- w3tc_beforeupload_bind();
1288
- }
1289
- });
1290
-
1291
- w3tc_referrer_groups_clear();
1292
-
1293
  // add sortable
1294
  if (jQuery.ui && jQuery.ui.sortable) {
1295
  jQuery('#js_files,#css_files').sortable({
@@ -1432,7 +1212,7 @@ jQuery(function() {
1432
 
1433
  jQuery.getJSON(ajaxurl, {
1434
  action: 'w3tc_ajax',
1435
- _wpnonce: w3tc_nonce,
1436
  w3tc_action: 'faq',
1437
  section: section
1438
  }, function(data) {
48
  }
49
  }
50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  function w3tc_minify_js_file_add(theme, template, location, file) {
52
  var append = jQuery('<li><table><tr><th>&nbsp;</th><th>File URI:</th><th>Template:</th><th colspan="3">Embed Location:</th></tr><tr><td>' + (jQuery('#js_files li').length + 1) + '.</td><td><input class="js_enabled" type="text" name="js_files[' + theme + '][' + template + '][' + location + '][]" value="" size="70" \/></td><td><select class="js_file_template js_enabled"></select></td><td><select class="js_file_location js_enabled"><option value="include">Embed in &lt;head&gt;</option><option value="include-body">Embed after &lt;body&gt;</option><option value="include-footer">Embed before &lt;/body&gt;</option></select></td><td><input class="js_file_delete js_enabled button" type="button" value="Delete" /> <input class="js_file_verify js_enabled button" type="button" value="Verify URI" /></td></tr></table><\/li>');
53
  append.find('input:text').val(file);
237
  }
238
 
239
  function w3tc_beforeupload_unbind() {
240
+ jQuery(window).off('beforeunload', w3tc_beforeunload);
241
  }
242
 
243
  function w3tc_beforeunload() {
1070
  return ret;
1071
  });
1072
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1073
  // add sortable
1074
  if (jQuery.ui && jQuery.ui.sortable) {
1075
  jQuery('#js_files,#css_files').sortable({
1212
 
1213
  jQuery.getJSON(ajaxurl, {
1214
  action: 'w3tc_ajax',
1215
+ _wpnonce: w3tc_nonce[0],
1216
  w3tc_action: 'faq',
1217
  section: section
1218
  }, function(data) {
pub/js/setup-guide.js CHANGED
@@ -1216,8 +1216,11 @@ function w3tc_wizard_actions( $slide ) {
1216
 
1217
  case 'w3tc-wizard-slide-complete':
1218
  var html,
1219
- pgcacheEngine = $container.find( 'input:checked[name="pgcache_engine"]' ).val();
1220
- pgcacheDiffPercent = $container.find( '#test-results' ).data( 'pgcacheDiffPercent-' + pgcacheEngine ),
 
 
 
1221
  dbcacheEngine = $container.find( 'input:checked[name="dbcache_engine"]' ).val(),
1222
  dbcacheEngineLabel = $container.find( 'input:checked[name="dbcache_engine"]' )
1223
  .closest('td').next('td').text(),
@@ -1241,16 +1244,22 @@ function w3tc_wizard_actions( $slide ) {
1241
  jQuery( '#w3tc-wizard-step-lazyload' ).append( '<span class="dashicons dashicons-yes"></span>' );
1242
  }
1243
 
 
 
 
1244
  // Present the Setup Complete slide.
1245
  $container.find( '#w3tc-options-menu li' ).removeClass( 'is-active' );
1246
  $container.find( '#w3tc-options-menu li' ).last().addClass( 'is-active' );
1247
 
1248
- html = ( pgcacheDiffPercent > 0 ? '+' : '' ) +
1249
- pgcacheDiffPercent +
1250
- '%';
 
1251
 
1252
  $container.find( '#w3tc-ttfb-diff' ).html( html );
1253
 
 
 
1254
  $container.find( '#w3tc-dbcache-engine' ).html( dbcacheEngineLabel );
1255
 
1256
  $container.find( '#w3tc-objcache-engine' ).html( objcacheEngineLabel );
1216
 
1217
  case 'w3tc-wizard-slide-complete':
1218
  var html,
1219
+ pgcacheEngine = $container.find( 'input:checked[name="pgcache_engine"]' ).val(),
1220
+ pgcacheEngineLabel = $container.find( 'input:checked[name="pgcache_engine"]' )
1221
+ .closest('td').next('td').text(),
1222
+ pgcacheDiffPercent = $container.find( '#test-results' )
1223
+ .data( 'pgcacheDiffPercent-' + pgcacheEngine ),
1224
  dbcacheEngine = $container.find( 'input:checked[name="dbcache_engine"]' ).val(),
1225
  dbcacheEngineLabel = $container.find( 'input:checked[name="dbcache_engine"]' )
1226
  .closest('td').next('td').text(),
1244
  jQuery( '#w3tc-wizard-step-lazyload' ).append( '<span class="dashicons dashicons-yes"></span>' );
1245
  }
1246
 
1247
+ // Prevent leave page alert.
1248
+ jQuery( window ).off( 'beforeunload' );
1249
+
1250
  // Present the Setup Complete slide.
1251
  $container.find( '#w3tc-options-menu li' ).removeClass( 'is-active' );
1252
  $container.find( '#w3tc-options-menu li' ).last().addClass( 'is-active' );
1253
 
1254
+ html = pgcacheDiffPercent !== undefined ?
1255
+ ( pgcacheDiffPercent > 0 ? '+' : '' ) +
1256
+ parseFloat( pgcacheDiffPercent ).toFixed( 2 ) +
1257
+ '%' : '0.00%';
1258
 
1259
  $container.find( '#w3tc-ttfb-diff' ).html( html );
1260
 
1261
+ $container.find( '#w3tc-pgcache-engine' ).html( pgcacheEngineLabel );
1262
+
1263
  $container.find( '#w3tc-dbcache-engine' ).html( dbcacheEngineLabel );
1264
 
1265
  $container.find( '#w3tc-objcache-engine' ).html( objcacheEngineLabel );
pub/js/wizard.js CHANGED
@@ -18,6 +18,10 @@
18
  $skipLink.on( 'click', skipFunction );
19
  $skipButton.on( 'click', skipFunction );
20
 
 
 
 
 
21
  // Listen for clicks to go to the W3TC Dashboard.
22
  $container.find( '#w3tc-wizard-dashboard' ).on( 'click', function () {
23
  jQuery( window ).off( 'beforeunload' );
@@ -36,6 +40,8 @@
36
  nodeName = $this.prop('nodeName'),
37
  page = location.href.replace(/^.+page=/, '' );
38
 
 
 
39
  if ( 'BUTTON' === nodeName ) {
40
  $this
41
  .prop( 'disabled', true )
18
  $skipLink.on( 'click', skipFunction );
19
  $skipButton.on( 'click', skipFunction );
20
 
21
+ jQuery( window ).on( 'beforeunload', function() {
22
+ return W3TC_Wizard.beforeunloadText;
23
+ });
24
+
25
  // Listen for clicks to go to the W3TC Dashboard.
26
  $container.find( '#w3tc-wizard-dashboard' ).on( 'click', function () {
27
  jQuery( window ).off( 'beforeunload' );
40
  nodeName = $this.prop('nodeName'),
41
  page = location.href.replace(/^.+page=/, '' );
42
 
43
+ jQuery( window ).off( 'beforeunload' );
44
+
45
  if ( 'BUTTON' === nodeName ) {
46
  $this
47
  .prop( 'disabled', true )
readme.txt CHANGED
@@ -1,9 +1,9 @@
1
  === Plugin Name ===
2
  Contributors: boldgrid, fredericktownes, maxicusc, gidomanders, bwmarkle, harryjackson1221, joemoto
3
  Tags: seo, cache, optimize, pagespeed, performance, caching, compression, maxcdn, nginx, varnish, redis, new relic, aws, amazon web services, s3, cloudfront, rackspace, cloudflare, azure, apache
4
- Requires at least: 3.2
5
  Tested up to: 5.6
6
- Stable tag: 2.0.1
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -275,6 +275,16 @@ Please reach out to all of these people and support their projects if you're so
275
 
276
  == Changelog ==
277
 
 
 
 
 
 
 
 
 
 
 
278
  = 2.0.1 =
279
  * Fix: Corrected redirection logic for the new Setup Guide
280
  * Fix: Fixed JavaScript w3tc_ga error
1
  === Plugin Name ===
2
  Contributors: boldgrid, fredericktownes, maxicusc, gidomanders, bwmarkle, harryjackson1221, joemoto
3
  Tags: seo, cache, optimize, pagespeed, performance, caching, compression, maxcdn, nginx, varnish, redis, new relic, aws, amazon web services, s3, cloudfront, rackspace, cloudflare, azure, apache
4
+ Requires at least: 3.8
5
  Tested up to: 5.6
6
+ Stable tag: 2.1.0
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
275
 
276
  == Changelog ==
277
 
278
+ = 2.1.0 =
279
+ * Feature: Added a Feature Showcase to highlight new and existing features
280
+ * Update: Consolidated cache groups settings pages
281
+ * Update: Replaced deprecated jQuery method for WordPress 5.6
282
+ * Fix: PHP warnings for sprintf placeholders in PHP 8
283
+ * Fix: PHP deprecated warnings in PHP 8
284
+ * Fix: Browser Cache Quick Reference Chart link
285
+ * Fix: Bad nonce in help
286
+ * Fix: Google Drive CDN JavaScript
287
+
288
  = 2.0.1 =
289
  * Fix: Corrected redirection logic for the new Setup Guide
290
  * Fix: Fixed JavaScript w3tc_ga error
w3-total-cache-api.php CHANGED
@@ -5,7 +5,7 @@ if ( !defined( 'ABSPATH' ) ) {
5
  }
6
 
7
  define( 'W3TC', true );
8
- define( 'W3TC_VERSION', '2.0.1' );
9
  define( 'W3TC_POWERED_BY', 'W3 Total Cache' );
10
  define( 'W3TC_EMAIL', 'w3tc@w3-edge.com' );
11
  define( 'W3TC_TEXT_DOMAIN', 'w3-total-cache' );
5
  }
6
 
7
  define( 'W3TC', true );
8
+ define( 'W3TC_VERSION', '2.1.0' );
9
  define( 'W3TC_POWERED_BY', 'W3 Total Cache' );
10
  define( 'W3TC_EMAIL', 'w3tc@w3-edge.com' );
11
  define( 'W3TC_TEXT_DOMAIN', 'w3-total-cache' );
w3-total-cache.php CHANGED
@@ -3,8 +3,8 @@
3
  * Plugin Name: W3 Total Cache
4
  * Plugin URI: https://www.boldgrid.com/totalcache/
5
  * Description: The highest rated and most complete WordPress performance plugin. Dramatically improve the speed and user experience of your site. Add browser, page, object and database caching as well as minify and content delivery network (CDN) to WordPress.
6
- * Version: 2.0.1
7
- * Requires at least: 3.2
8
  * Requires PHP: 5.3
9
  * Author: BoldGrid
10
  * Author URI: https://www.boldgrid.com/
3
  * Plugin Name: W3 Total Cache
4
  * Plugin URI: https://www.boldgrid.com/totalcache/
5
  * Description: The highest rated and most complete WordPress performance plugin. Dramatically improve the speed and user experience of your site. Add browser, page, object and database caching as well as minify and content delivery network (CDN) to WordPress.
6
+ * Version: 2.1.0
7
+ * Requires at least: 3.8
8
  * Requires PHP: 5.3
9
  * Author: BoldGrid
10
  * Author URI: https://www.boldgrid.com/