Autoptimize - Version 1.8.2

Version Description

  • Improvement: more graceful failure when minifier classes exist but method does not, based on bug-report by Franck160
  • Improvement: deferred CSS is also outputted in noscript-tags
  • Improvement: differentiate between Apache version in .htaccess file as suggested by iMadalin
  • Improvement: also aggregate protocol-less CSS/JS URI's (as suggested by Ross
  • Improvement: disable autoptimization based on parameter in querystring (for debugging)
  • Bugfix: some CSS-imports were not being aggregated/ minified
  • Bugfix: add CSS before to avoid breakage when title includes other attributes (e.g. itemscope)
  • Bugfix: make sure javascript or css between comments is not aggregated as reported by Milap Gajjar
  • Tested with WordPress 3.9 (beta 1)
  • Updates in FAQ
Download this release

Release Info

Developer futtta
Plugin Icon 128x128 Autoptimize
Version 1.8.2
Comparing to
See all releases

Code changes from version 1.8.1 to 1.8.2

autoptimize.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Autoptimize
4
  Plugin URI: http://blog.futtta.be/autoptimize
5
  Description: Optimizes your website, concatenating the CSS and JavaScript code, and compressing it.
6
- Version: 1.8.1
7
  Author: Frank Goossens (futtta)
8
  Author URI: http://blog.futtta.be/
9
  Domain Path: localization/
@@ -34,7 +34,7 @@ $conf = autoptimizeConfig::instance();
34
  /* Check if we're updating, in which case we might need to do stuff and flush the cache
35
  to avoid old versions of aggregated files lingering around */
36
 
37
- $autoptimize_version="1.8.1";
38
  $autoptimize_db_version=get_option('autoptimize_version','none');
39
 
40
  if ($autoptimize_db_version !== $autoptimize_version) {
@@ -133,6 +133,13 @@ function autoptimize_start_buffering() {
133
  // filter you can use to block autoptimization on your own terms
134
  $ao_noptimize = (bool) apply_filters( 'autoptimize_filter_noptimize', $ao_noptimize );
135
 
 
 
 
 
 
 
 
136
  if (!is_feed() && !$ao_noptimize ) {
137
 
138
  // Config element
@@ -184,7 +191,7 @@ function autoptimize_start_buffering() {
184
  }
185
  }
186
 
187
- //Action on end -
188
  function autoptimize_end_buffering($content) {
189
  if ( stripos($content,"<html") === false || stripos($content,"<xsl:stylesheet") !== false ) { return $content;}
190
 
3
  Plugin Name: Autoptimize
4
  Plugin URI: http://blog.futtta.be/autoptimize
5
  Description: Optimizes your website, concatenating the CSS and JavaScript code, and compressing it.
6
+ Version: 1.8.2
7
  Author: Frank Goossens (futtta)
8
  Author URI: http://blog.futtta.be/
9
  Domain Path: localization/
34
  /* Check if we're updating, in which case we might need to do stuff and flush the cache
35
  to avoid old versions of aggregated files lingering around */
36
 
37
+ $autoptimize_version="1.8.2";
38
  $autoptimize_db_version=get_option('autoptimize_version','none');
39
 
40
  if ($autoptimize_db_version !== $autoptimize_version) {
133
  // filter you can use to block autoptimization on your own terms
134
  $ao_noptimize = (bool) apply_filters( 'autoptimize_filter_noptimize', $ao_noptimize );
135
 
136
+ // noptimize in qs to get non-optimized page for debugging
137
+ if (array_key_exists("ao_noptimize",$_GET)) {
138
+ if ($_GET["ao_noptimize"]==="1") {
139
+ $ao_noptimize = true;
140
+ }
141
+ }
142
+
143
  if (!is_feed() && !$ao_noptimize ) {
144
 
145
  // Config element
191
  }
192
  }
193
 
194
+ // Action on end, this is where the magic happens
195
  function autoptimize_end_buffering($content) {
196
  if ( stripos($content,"<html") === false || stripos($content,"<xsl:stylesheet") !== false ) { return $content;}
197
 
classes/autoptimizeBase.php CHANGED
@@ -25,7 +25,9 @@ abstract class autoptimizeBase
25
 
26
  //Converts an URL to a full path
27
  protected function getpath($url) {
28
- if ((strpos($url,'//')===false) && (strpos($url,parse_url(AUTOPTIMIZE_WP_SITE_URL,PHP_URL_HOST))===false)) {
 
 
29
  $url = AUTOPTIMIZE_WP_SITE_URL.$url;
30
  }
31
  $path = str_replace(AUTOPTIMIZE_WP_ROOT_URL,'',$url);
@@ -109,6 +111,38 @@ abstract class autoptimizeBase
109
  }
110
  return $iehacks_out;
111
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
  protected function url_replace_cdn($url) {
114
  if (!empty($this->cdn_url)) {
25
 
26
  //Converts an URL to a full path
27
  protected function getpath($url) {
28
+ if (strpos($url,'//')===0) {
29
+ $url = "http:".$url;
30
+ } else if ((strpos($url,'//')===false) && (strpos($url,parse_url(AUTOPTIMIZE_WP_SITE_URL,PHP_URL_HOST))===false)) {
31
  $url = AUTOPTIMIZE_WP_SITE_URL.$url;
32
  }
33
  $path = str_replace(AUTOPTIMIZE_WP_ROOT_URL,'',$url);
111
  }
112
  return $iehacks_out;
113
  }
114
+
115
+ protected function hide_comments($comments_in) {
116
+ if ( strpos( $comments_in, '<!--' ) !== false ) {
117
+ $comments_out = preg_replace_callback(
118
+ '#<!--.*?-->#is',
119
+ create_function(
120
+ '$matches',
121
+ 'return "%%COMMENTS%%".base64_encode($matches[0])."%%COMMENTS%%";'
122
+ ),
123
+ $comments_in
124
+ );
125
+ } else {
126
+ $comments_out = $comments_in;
127
+ }
128
+ return $comments_out;
129
+ }
130
+
131
+ protected function restore_comments($comments_in) {
132
+ if ( strpos( $comments_in, '%%COMMENTS%%' ) !== false ) {
133
+ $comments_out = preg_replace_callback(
134
+ '#%%COMMENTS%%(.*?)%%COMMENTS%%#is',
135
+ create_function(
136
+ '$matches',
137
+ 'return stripslashes(base64_decode($matches[1]));'
138
+ ),
139
+ $comments_in
140
+ );
141
+ } else {
142
+ $comments_out=$comments_in;
143
+ }
144
+ return $comments_out;
145
+ }
146
 
147
  protected function url_replace_cdn($url) {
148
  if (!empty($this->cdn_url)) {
classes/autoptimizeHTML.php CHANGED
@@ -25,10 +25,13 @@ class autoptimizeHTML extends autoptimizeBase {
25
 
26
  // Minify html
27
  $options = array('keepComments' => $this->keepcomments);
28
- $tmp_content = Minify_HTML::minify($this->content,$options);
29
- if (!empty($tmp_content)) {
30
- $this->content = $tmp_content;
31
- unset($tmp_content);
 
 
 
32
  }
33
 
34
  // restore noptimize
25
 
26
  // Minify html
27
  $options = array('keepComments' => $this->keepcomments);
28
+
29
+ if (is_callable(array(new Minify_HTML,"minify"))) {
30
+ $tmp_content = Minify_HTML::minify($this->content,$options);
31
+ if (!empty($tmp_content)) {
32
+ $this->content = $tmp_content;
33
+ unset($tmp_content);
34
+ }
35
  }
36
 
37
  // restore noptimize
classes/autoptimizeScripts.php CHANGED
@@ -50,9 +50,12 @@ class autoptimizeScripts extends autoptimizeBase
50
  // noptimize me
51
  $this->content = $this->hide_noptimize($this->content);
52
 
53
- //Save IE hacks
54
  $this->content = $this->hide_iehacks($this->content);
55
 
 
 
 
56
  //Get script files
57
  if(preg_match_all('#<script.*</script>#Usmi',$this->content,$matches)) {
58
  foreach($matches[0] as $tag) {
@@ -164,12 +167,16 @@ class autoptimizeScripts extends autoptimizeBase
164
 
165
  //$this->jscode has all the uncompressed code now.
166
  if(class_exists('JSMin')) {
167
- $tmp_jscode = trim(JSMin::minify($this->jscode));
168
- if (!empty($tmp_jscode)) {
169
- $this->jscode = $tmp_jscode;
170
- unset($tmp_jscode);
 
171
  }
172
- return true;
 
 
 
173
  } else {
174
  return false;
175
  }
@@ -217,6 +224,9 @@ class autoptimizeScripts extends autoptimizeBase
217
  $this->warn_html();
218
  }
219
 
 
 
 
220
  // Restore IE hacks
221
  $this->content = $this->restore_iehacks($this->content);
222
 
50
  // noptimize me
51
  $this->content = $this->hide_noptimize($this->content);
52
 
53
+ // Save IE hacks
54
  $this->content = $this->hide_iehacks($this->content);
55
 
56
+ // comments
57
+ $this->content = $this->hide_comments($this->content);
58
+
59
  //Get script files
60
  if(preg_match_all('#<script.*</script>#Usmi',$this->content,$matches)) {
61
  foreach($matches[0] as $tag) {
167
 
168
  //$this->jscode has all the uncompressed code now.
169
  if(class_exists('JSMin')) {
170
+ if (is_callable(array(new JSMin,"minify"))) {
171
+ $tmp_jscode = trim(JSMin::minify($this->jscode));
172
+ if (!empty($tmp_jscode)) {
173
+ $this->jscode = $tmp_jscode;
174
+ unset($tmp_jscode);
175
  }
176
+ return true;
177
+ } else {
178
+ return false;
179
+ }
180
  } else {
181
  return false;
182
  }
224
  $this->warn_html();
225
  }
226
 
227
+ // restore comments
228
+ $this->content = $this->restore_comments($this->content);
229
+
230
  // Restore IE hacks
231
  $this->content = $this->restore_iehacks($this->content);
232
 
classes/autoptimizeStyles.php CHANGED
@@ -35,7 +35,7 @@ class autoptimizeStyles extends autoptimizeBase {
35
  // get cdn url
36
  $this->cdn_url = $options['cdn_url'];
37
 
38
- //Store data: URIs setting for later use
39
  $this->datauris = $options['datauris'];
40
 
41
  // noptimize me
@@ -55,6 +55,9 @@ class autoptimizeStyles extends autoptimizeBase {
55
 
56
  // Save IE hacks
57
  $this->content = $this->hide_iehacks($this->content);
 
 
 
58
 
59
  // Get <style> and <link>
60
  if(preg_match_all('#(<style[^>]*>.*</style>)|(<link[^>]*stylesheet[^>]*>)#Usmi',$this->content,$matches)) {
@@ -158,7 +161,7 @@ class autoptimizeStyles extends autoptimizeBase {
158
 
159
  while(preg_match_all('#^(/*\s?)@import.*(?:;|$)#Um',$thiscss,$matches)) {
160
  foreach($matches[0] as $import) {
161
- $url = trim(preg_replace('#^.*((?:https?|ftp)://.*\.css).*$#','$1',$import)," \t\n\r\0\x0B\"'");
162
  $path = $this->getpath($url);
163
  $import_ok = false;
164
  if (file_exists($path) && is_readable($path)) {
@@ -270,11 +273,14 @@ class autoptimizeStyles extends autoptimizeBase {
270
 
271
  //Minify
272
  if (class_exists('Minify_CSS_Compressor')) {
273
- // legacy
274
  $tmp_code = trim(Minify_CSS_Compressor::process($code));
275
  } else if(class_exists('CSSmin')) {
276
  $cssmin = new CSSmin();
277
- $tmp_code = trim($cssmin->run($code));
 
 
 
 
278
  }
279
 
280
  if (!empty($tmp_code)) {
@@ -322,8 +328,11 @@ class autoptimizeStyles extends autoptimizeBase {
322
 
323
  //Returns the content
324
  public function getcontent() {
325
- //Restore IE hacks
326
  $this->content = $this->restore_iehacks($this->content);
 
 
 
327
 
328
  // restore noscript
329
  if ( strpos( $this->content, '%%NOSCRIPT%%' ) !== false ) {
@@ -351,8 +360,8 @@ class autoptimizeStyles extends autoptimizeBase {
351
  //Add the new stylesheets
352
  if ($this->inline == true) {
353
  foreach($this->csscode as $media => $code) {
354
- if (strpos($this->content,"<title>")!==false) {
355
- $this->content = str_replace('<title>','<style type="text/css" media="'.$media.'">'.$code.'</style><title>',$this->content);
356
  } else {
357
  $warn_html_template=true;
358
  $this->content .= '<style type="text/css" media="'.$media.'">'.$code.'</style>';
@@ -361,6 +370,7 @@ class autoptimizeStyles extends autoptimizeBase {
361
  } else {
362
  if($this->defer == true) {
363
  $deferredCssBlock = "<script>function lCss(url,media) {var d=document;var l=d.createElement('link');l.rel='stylesheet';l.type='text/css';l.href=url;l.media=media; d.getElementsByTagName('head')[0].appendChild(l);}function deferredCSS() {";
 
364
  }
365
 
366
  foreach($this->url as $media => $url) {
@@ -369,9 +379,10 @@ class autoptimizeStyles extends autoptimizeBase {
369
  //Add the stylesheet either deferred (import at bottom) or normal links in head
370
  if($this->defer == true) {
371
  $deferredCssBlock .= "lCss('".$url."','".$media."');";
 
372
  } else {
373
- if (strpos($this->content,"<title>")!==false) {
374
- $this->content = str_replace('<title>','<link type="text/css" media="'.$media.'" href="'.$url.'" rel="stylesheet" /><title>',$this->content);
375
  } else {
376
  $warn_html_template=true;
377
  $this->content .= '<link type="text/css" media="'.$media.'" href="'.$url.'" rel="stylesheet" />';
@@ -381,6 +392,13 @@ class autoptimizeStyles extends autoptimizeBase {
381
 
382
  if($this->defer == true) {
383
  $deferredCssBlock .= "}if(window.addEventListener){window.addEventListener('DOMContentLoaded',deferredCSS,false);}else{window.onload = deferredCSS;}</script>";
 
 
 
 
 
 
 
384
  if (strpos($this->content,"</body>")!==false) {
385
  $this->content = str_replace('</body>',$deferredCssBlock.'</body>',$this->content);
386
  } else {
35
  // get cdn url
36
  $this->cdn_url = $options['cdn_url'];
37
 
38
+ // Store data: URIs setting for later use
39
  $this->datauris = $options['datauris'];
40
 
41
  // noptimize me
55
 
56
  // Save IE hacks
57
  $this->content = $this->hide_iehacks($this->content);
58
+
59
+ // hide comments
60
+ $this->content = $this->hide_comments($this->content);
61
 
62
  // Get <style> and <link>
63
  if(preg_match_all('#(<style[^>]*>.*</style>)|(<link[^>]*stylesheet[^>]*>)#Usmi',$this->content,$matches)) {
161
 
162
  while(preg_match_all('#^(/*\s?)@import.*(?:;|$)#Um',$thiscss,$matches)) {
163
  foreach($matches[0] as $import) {
164
+ $url = trim(preg_replace('#^.*((?:https?|ftp)://.*\.css).*$#','$1',trim($import))," \t\n\r\0\x0B\"'");
165
  $path = $this->getpath($url);
166
  $import_ok = false;
167
  if (file_exists($path) && is_readable($path)) {
273
 
274
  //Minify
275
  if (class_exists('Minify_CSS_Compressor')) {
 
276
  $tmp_code = trim(Minify_CSS_Compressor::process($code));
277
  } else if(class_exists('CSSmin')) {
278
  $cssmin = new CSSmin();
279
+ if (method_exists($cssmin,"run")) {
280
+ $tmp_code = trim($cssmin->run($code));
281
+ } elseif (is_callable(array($cssmin,"minify"))) {
282
+ $tmp_code = trim(CssMin::minify($code));
283
+ }
284
  }
285
 
286
  if (!empty($tmp_code)) {
328
 
329
  //Returns the content
330
  public function getcontent() {
331
+ // restore IE hacks
332
  $this->content = $this->restore_iehacks($this->content);
333
+
334
+ // restore comments
335
+ $this->content = $this->restore_comments($this->content);
336
 
337
  // restore noscript
338
  if ( strpos( $this->content, '%%NOSCRIPT%%' ) !== false ) {
360
  //Add the new stylesheets
361
  if ($this->inline == true) {
362
  foreach($this->csscode as $media => $code) {
363
+ if (strpos($this->content,"<title")!==false) {
364
+ $this->content = str_replace('<title','<style type="text/css" media="'.$media.'">'.$code.'</style><title',$this->content);
365
  } else {
366
  $warn_html_template=true;
367
  $this->content .= '<style type="text/css" media="'.$media.'">'.$code.'</style>';
370
  } else {
371
  if($this->defer == true) {
372
  $deferredCssBlock = "<script>function lCss(url,media) {var d=document;var l=d.createElement('link');l.rel='stylesheet';l.type='text/css';l.href=url;l.media=media; d.getElementsByTagName('head')[0].appendChild(l);}function deferredCSS() {";
373
+ $noScriptCssBlock = "<noscript>";
374
  }
375
 
376
  foreach($this->url as $media => $url) {
379
  //Add the stylesheet either deferred (import at bottom) or normal links in head
380
  if($this->defer == true) {
381
  $deferredCssBlock .= "lCss('".$url."','".$media."');";
382
+ $noScriptCssBlock .= '<link type="text/css" media="'.$media.'" href="'.$url.'" rel="stylesheet" />';
383
  } else {
384
+ if (strpos($this->content,"<title")!==false) {
385
+ $this->content = str_replace('<title','<link type="text/css" media="'.$media.'" href="'.$url.'" rel="stylesheet" /><title',$this->content);
386
  } else {
387
  $warn_html_template=true;
388
  $this->content .= '<link type="text/css" media="'.$media.'" href="'.$url.'" rel="stylesheet" />';
392
 
393
  if($this->defer == true) {
394
  $deferredCssBlock .= "}if(window.addEventListener){window.addEventListener('DOMContentLoaded',deferredCSS,false);}else{window.onload = deferredCSS;}</script>";
395
+ $noScriptCssBlock .= "</noscript>";
396
+ if (strpos($this->content,"<title")!==false) {
397
+ $this->content = str_replace('<title',$noScriptCssBlock.'<title',$this->content);
398
+ } else {
399
+ $warn_html_template=true;
400
+ $this->content .= $noScriptCssBlock;
401
+ }
402
  if (strpos($this->content,"</body>")!==false) {
403
  $this->content = str_replace('</body>',$deferredCssBlock.'</body>',$this->content);
404
  } else {
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: futtta, turl
3
  Tags: css, html, javascript, js, optimize, speed, cache, data-uri, aggregate, minimize, minification, performance, pagespeed, booster, multisite
4
  Donate link: http://blog.futtta.be/2013/10/21/do-not-donate-to-me/
5
  Requires at least: 2.7
6
- Tested up to: 3.8
7
- Stable tag: 1.8.1
8
 
9
  Autoptimize speeds up your website and helps you save bandwidth by aggregating and minimizing JS, CSS and HTML.
10
 
@@ -54,6 +54,14 @@ Inlining all CSS has one clear advantage (better PageSpeed score) and one big di
54
 
55
  So the choice should be based on your answer to some site-specific questions; what is your site's bounce rate? How many pages per visit do your visitors request? If you have a high bounce rate and a low number of average pages per visit, inlining CSS looks like a good idea. But with a high number of pages/ visit, it's probably not a good idea. Except if all you care about is a stellar PageSpeed-score, off course.
56
 
 
 
 
 
 
 
 
 
57
  = What can I do with the API? =
58
 
59
  A whole lot; there are filters you can use to conditionally disable Autoptimize per request, to change the CSS- and JS-excludes, to change the limit for CSS background-images to be inlined in the CSS, to define what JS-files are moved behing the aggregated on, to change the defer-attribute on the aggregated JS script-tag, There are examples for all filters in autoptimize_helper.php_example.
@@ -70,11 +78,7 @@ If you want your uploaded images to be on the CDN as well, you can change the up
70
 
71
  = How can I force the aggregated files to be static CSS or JS instead of PHP? =
72
 
73
- If your webserver is properly configured to handle compression (gzip or deflate) and cache expiry (expires and cache-control with sufficient cacheability), you don't need Autoptimize to handle that for you. In that case you can check the "Save aggregated script/css as static files?"-option, which will force Autoptimize to save the aggregated files as .css and .js-files (meaning no PHP is needed to serve these files).
74
-
75
- = Does Autoptimize work with BuddyPress? =
76
-
77
- Based on earlier feedback received from BuddyPress users, CSS and JS-Autoptimization do not seem to work correctly, leaving you with only HTML optimizations. This might be due to problems in Autoptimize which have already been fixed, so feel free to give it a shot anyhow.
78
 
79
  = Compatibility with WP SlimSat =
80
 
@@ -121,6 +125,18 @@ You can report problems on the [wordpress.org support forum](http://wordpress.or
121
 
122
  == Changelog ==
123
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  = 1.8.1 =
125
  * bugfix: CSS in conditional comments was not excluded from aggregation as reported by [Rolf](http://www.finkbeiner-holz.de/) and [bottapress](http://www.wordpress-hebergement.fr/)
126
 
3
  Tags: css, html, javascript, js, optimize, speed, cache, data-uri, aggregate, minimize, minification, performance, pagespeed, booster, multisite
4
  Donate link: http://blog.futtta.be/2013/10/21/do-not-donate-to-me/
5
  Requires at least: 2.7
6
+ Tested up to: 3.9
7
+ Stable tag: 1.8.2
8
 
9
  Autoptimize speeds up your website and helps you save bandwidth by aggregating and minimizing JS, CSS and HTML.
10
 
54
 
55
  So the choice should be based on your answer to some site-specific questions; what is your site's bounce rate? How many pages per visit do your visitors request? If you have a high bounce rate and a low number of average pages per visit, inlining CSS looks like a good idea. But with a high number of pages/ visit, it's probably not a good idea. Except if all you care about is a stellar PageSpeed-score, off course.
56
 
57
+ You can find more information on this topic [in this blog post](http://blog.futtta.be/2014/02/13/should-you-inline-or-defer-blocking-css/).
58
+
59
+ = My cache is getting huge, doesn't Autoptimize purge the cache? =
60
+
61
+ Autoptimize does not have its proper cache purging mechanism, as this could remove optimized CSS/JS which is still referred to in other caches which would break your site.
62
+
63
+ You can however keep the cache size at an acceptable level by excludinng JS-variables (or sometimes CSS-selectors) that change on a per page (or per pageload) basis. You can read how you can do that [in this blogpost](http://blog.futtta.be/2014/03/19/how-to-keep-autoptimizes-cache-size-under-control-and-improve-visitor-experience/).
64
+
65
  = What can I do with the API? =
66
 
67
  A whole lot; there are filters you can use to conditionally disable Autoptimize per request, to change the CSS- and JS-excludes, to change the limit for CSS background-images to be inlined in the CSS, to define what JS-files are moved behing the aggregated on, to change the defer-attribute on the aggregated JS script-tag, There are examples for all filters in autoptimize_helper.php_example.
78
 
79
  = How can I force the aggregated files to be static CSS or JS instead of PHP? =
80
 
81
+ If your webserver is properly configured to handle compression (gzip or deflate) and cache expiry (expires and cache-control with sufficient cacheability), you don't need Autoptimize to handle that for you. In that case you can check the "Save aggregated script/css as static files?"-option, which will force Autoptimize to save the aggregated files as .css and .js-files (meaning no PHP is needed to serve these files). This setting is default as of Autoptimize 1.8.
 
 
 
 
82
 
83
  = Compatibility with WP SlimSat =
84
 
125
 
126
  == Changelog ==
127
 
128
+ = 1.8.2 =
129
+ * Improvement: more graceful failure when minifier classes exist but method does not, based on [bug-report by Franck160](http://wordpress.org/support/topic/confict-with-dynamic-to-top)
130
+ * Improvement: deferred CSS is also outputted in noscript-tags
131
+ * Improvement: differentiate between Apache version in .htaccess file as suggested by [iMadalin](http://www.imadalin.ro/)
132
+ * Improvement: also aggregate protocol-less CSS/JS URI's (as [suggested by Ross](http://wordpress.org/support/topic/protocol-less-url-support)
133
+ * Improvement: disable autoptimization based on parameter in querystring (for debugging)
134
+ * Bugfix: some CSS-imports were not being aggregated/ minified
135
+ * Bugfix: add CSS before <title instead of <title> to avoid breakage when title includes other attributes (e.g. itemscope)
136
+ * Bugfix: make sure javascript or css between comments is not aggregated as reported by [Milap Gajjar](http://wordpress.org/support/topic/the-optimized-css-contains-duplicate-classes)
137
+ * Tested with WordPress 3.9 (beta 1)
138
+ * Updates in FAQ
139
+
140
  = 1.8.1 =
141
  * bugfix: CSS in conditional comments was not excluded from aggregation as reported by [Rolf](http://www.finkbeiner-holz.de/) and [bottapress](http://www.wordpress-hebergement.fr/)
142