Celebrating 300000 Autoptimize downloads with new release

300k-1, that isSo just now Autoptimize passed the 300000 downloads mark (6 months after reaching 200k), which feels huge to me. To celebrate I just pushed out version 1.9.3, which features -as becomes a minor release- small improvements and bugfixes. From the changelog;

  • improvement: more intelligent CDN-replacement logic, thanks Squazz for reporting and testing
  • improvement: allow strings (comments) to be excluded from HTML-optimization when comment removal is active (via API)
  • improvement: changed priority with which AO gets triggered by WordPress, solving JS not being aggregated when NextGen Galleries is active, with great help from msebald
  • improvement: extra JS exclude-strings: gist.github.com, text/html, text/template, wp-slimstat.min.js, _stq, nonce, post_id (the latter two were removed from the default “manual” exclude list on the settings-page and can be removed there if you want)
  • new in API: autoptimize_filter_html_exclude, autoptimize_filter_css_defer, autoptimize_filter_css_inline, autoptimize_filter_base_replace_cdn, autoptimize_filter_js_noptimize, autoptimize_filter_css_noptimize, autoptimize_filter_html_noptimize
  • bugfix: remove some PHP notices, as reported by dimitrov.adrian
  • bugfix: make sure HTML-optimalization does not gobble a space before a cite as proposed by ecdltf
  • bugfix: cleaning the cache did not work on non-default directories as encountered by NoahJ Champion
  • upgraded to yui compressor php port 2.4.8-4
  • added arabic translation, thanks to the ekleel team
  • tested with WordPress 4.2 beta 3 (yep, it works)

So there you have your present, no go unwrap it! Have fun! 🙂

wordpress.org plugin repo: ratings changed

autoptimize ratings on feb 26th 2015Yesterday the average rating of all plugins on the wordpress.org repository changed; ratings that were not linked to a review, were removed. That means that ratings dating from before approximately November 2012, when reviews were introduced, are not being taken into account any more.
This had a positive impact on the average rating of my own plugins, but especially so for Autoptimize. That plugin was largely unsupported before I took over in January 2013 and got some low ratings as a consequence (the average was 4.2 at the time, if I’m not mistaking). With those old numbers now out of the way, the average went from 4.6 to 4.8 overnight. Yay!
[Update: a couple of days later there were even more changes on the WordPress Plugin pages.]

Bye 2014, it was nice knowing ya!

this used to be an animated gif, click to see itWith 2014 finally behind us, we can start dwelling on that past as of yesterday. These are some of my 2014 facts & figures:
About my blog:

My WordPress plugins:

  • Autoptimize
    • 2 major and 7 minor releases
    • 141324 downloads, bringing the total to 241650
    • answered lots of questions and feedback on the support-forum, allowing me to improve both the code and the FAQ.
    • 2015 will bring Autoptimize 2.0 (fixing the occasional WSOD & the cache-size problem) and Autoptimize Power-Ups (extensions for professional & power-users)
  • WP YouTube Lyte:
    • 2 major and 2 minor releases
    • 36507 downloads, now totalling 210285
    • 2015 will see continued improvements and WP YouTube Lyte Power-Ups (you guessed it, extensions for professional & power-users)
  • WP DoNotTrack:
    • 2 minor releases
    • 4312 downloads, now 12009 total
    • 2015 really should see a 1.0 release, which will finally include CSP-enforced protection.

Bye 2014, it was nice knowing ya, but I’m off enjoying 2015 now!

Autoptimize minor update and beyond

I just released an update to Autoptimize, bumping the version to 1.9.2. Main new features;

  • New: support for alternative cache-directory and file-prefix as requested by a.o. Jassi Bacha, Cluster666 and Baris Unver.
  • Improvement: hard-exclude all linked-data json objects (script type=application/ld+json)
  • Improvement: several filters added to the API, e.g. to alter optimized HTML, CSS or JS
  • Some bugfixes
  • Swedish translations updated & Ukrainian added, courtesy of Zanatoly of SebWeo.com

I’m already thinking about version 2.0 (which should fix the 2 big issues some people face; exploding cache size due to page-specific inline code & the rare but nasty white screen of death due to CSS minification issues) and about some powerful new features that could extend Autoptimize for professionals and power-users in need of something more. 2015 is going to be great, hope you guys & girls will be part of that!
Anyway, enjoy the end-of-year festivities and above all, have fun & share some of the happiness!
 

Amazed by Autoptimize take-up

autoptimize at +200K downloads, wow!Less then a year after reaching 100000 downloads, Autoptimize broke the 200000 barrier just last week.
It’s also exiting to see how people are blogging (or tweeting) about it as well;

So yeah, I’m pretty amazed by how well Autoptimize is doing. Thanks for the confidence!

WP SEO vs Autoptimize; who broke your WordPress?

Autoptimize 1.9 was released yesterday but unfortunately some reports were coming in about JS optimization being broken.  At first I suspected the problem being related to small changes that added semi-colons to individual blocks of script (before being aggregated), but tests with some impacted users showed this was not the case.
The breakthrough came in this thread in Autoptimize’s support forum, where user “grief-of-these-days” confirmed the problem started with the update of WP SEO and specifically the “sitelinks search box“-functionality that was added in WP SEO 1.6. Sitelinks Search Box comes as an inline script of type “application/ld+json”, that contains a name-less JSON-object with “linked data”. Autoptimize detected, aggregated and minimized this name-less object, but that not only defies the sitelinks search box mechanism, but potentially also broke the optimized JS itself. So I updated & enabled WP SEO, confirmed the problem, identified “potentialAction” as unique string to base exclusion on and pushed out 1.9.1 which will now no longer Autoptimize Sitelinks Search Box-code.
So who broke your WordPress today, WP SEO or Autoptmize? Well, WP SEO’s update may have made the bug appear, but based on the fact that json-ld is standardized and as such will probably be also present in other guises, Autoptimize should really just exclude any script of the “application/ld+json”-type from being aggregated & minimized (and not just that of the Sitelinks Search Box). Adding to the to-do-list now!

(When) should you Try/Catch Javascript?

Autoptimize comes with a “Add try-catch wrapping?”-option, which wraps every aggregated script in a try-catch-block, to avoid an error in one script to block the others.
I considered enabling this option by default, as it would prevent JS optimization occasionally breaking sites badly. I discussed this with a number of smart people and searched the web, eventually stumbling on this blogpost which offers an alternative for try-catch because;

Some JavaScript engines, such as V8 (Chrome) do not optimize functions that make use of a try/catch block as the optimizing compiler will skip it when encountered. No matter what context you use a try/catch block in, there will always be an inherent performance hit, quite possibly a substantial one. [Testcases] confirm [that] not only is there up to a 90% loss in performance when no error even occurs, but the declination is significantly greater when an error is raised and control enters the catch block.

So given this damning evidence of severe performance degradation, “try/catch wrapping” will not be enabled by default and although Ryan’s alternative approach has its merits, I’m weary of the caveats so I won’t include that (for now anyway). If your site breaks when enabling JS optimization in Autoptimize, you can enable try/catch wrapping as a quick workaround, but finding the offending script and excluding it from being optimized is clearly the better solution.

Next Autoptimize eliminates render-blocking CSS in above-the-fold content

Although current versions of Autoptimize can already tackle Google PageSpeed Insights’ “Eliminate render-blocking CSS in above-the-fold content” tip, the next release will allow you to do so in an even better way. As from version 1.9 you’ll be able to combine the best of both “inline CSS” and “defer CSS” worlds. “Defer” effectively becomes “Inline and defer“, allowing you to specify the “above the fold CSS” which is then inlined in the head of your HTML, while your normal autoptimized CSS is deferred until the page has finished loading.
Other improvements in the upcoming Autoptimize 1.9.0 include:

  • Inlined Base64-encoded background Images will now be cached as well and the threshold for inlining these images has been bumped up to 4096 bytes (from 2560).
  • Separate cache-directories for CSS and JS in /wp-content/cache/autoptimize, which should result in faster cache pruning (and in some cases possibly faster serving of individual aggregated files).
  • CSS is now added before the <title>-tag, JS before </body> (and after </title> when forced in head). This can be overridden in the API.
  • Some usability Improvements of the administration-page
  • Multiple hooks added to the API a.o. filters to not aggregate inline CSS or JS and filters to aggregate but not minify CSS or JS.
  • Multiple bugfixes & improvements

On the todo-list; testing, some translation updates (I’ll contact you translators in the coming week) and updating the readme.txt.
The first test-version of what will become 1.9.0 (still tagged 1.8.5 for now though) has been committed to wordpress.org’s plugin SVN and can be downloaded here. Anyone wanting to help out testing this new release, go and grab your copy and provide me with feedback.

PHP HTML parsing performance shootout; regex vs DOM

As I wrote earlier an Autoptimize user proposed to switch from regular expression based script & style extraction to using native PHP DOM functions (optionally with xpath). I created a small test-script to compare performance and the DOM methods are on average 500% slower than the preg_match based solution. Here are some details;

  • There are 3 tests; regular expression-based (preg_match), DOM + getElementsByTagName and DOM + XPath. You can see the source here and see it in action here.
  • The code in all 3 testcases does what Autoptimize does to start with when optimizing JavaScript:
    1. extract all javascript (code if inline, url if external) and add it to an array
    2. remove the javascript from the HTML
  • With each load of the test-script, the 3 tests get executed 100 times and total time per method is displayed.
  • That test-script was run 5 times on 3 different HTML-files; one small mobile page with some JavaScript and two bigger desktop ones with lots of JS.

The detailed results;

total time regextotal time domtotal time dom+xpath
arturo’s HP0.6114.83664.977
deredactie HP2.33225.6155.879
m deredactie HP0.06960.46040.4558

So while parsing HTML with regular expressions might be frowned upon in developer communities (and rightly so, as a lot can go wrong with PCRE in PHP) it is vastly superior with regards to performance. In the very limited scope of Autoptimize, where the regex-based approach is tried & tested on thousands of blogs, using DOM would simply create too much overhead.

Some HTML DOM parsing gotchas in PHP’s DOMDocument

Although I had used Simple HTML DOM parser for WP DoNotTrack, I’ve been looking into native PHP HTML DOM parsing as a possible replacement for regular expressions for Autoptimize as proposed by Arturo. I won’t go into the performance comparison results just yet, but here’s some of the things I learned while experimenting with DOMDocument which in turn might help innocent passers-by of this blogpost.

  • loadHTML doesn’t always play nice with different character encodings, you might need something like mb_convert_encoding to work around that.
  • loadHTML will try to “repair” your HTML to make sure an XML-parser can work with it. So what goes in will not come out the same way.
  • loadHTML will spit out tons of warnings or notices about the HTML not being XML; you might want to suppress error-reporting by prepending the command with an @ (e.g. @$dom->loadHTML($htmlstring);)
  • If you use e.g. getELementsByTagName to extract nodes into a seperate DomNodeList and you want to use that to change the DomDocument can result in … unexpected behavior as the DomNodeList gets updated when changes are made to the DomDocument. Copy the DomNodes from the DomNodeList into a new array (which will not get altered) and iterate over that to update the DomDocument as seen in the example below.
  • removeChild is a method of DomNode, not of DomDocument. This means $dom->removeChild(DomNode) will not work. Instead invoke removeChild on the parent of the node you want to remove as seen in the example below
// loadHTML from string, suppressing errors
$dom = new DOMDocument();
@$dom->loadHTML($html);
// get all script-nodes
$_scripts=$dom->getElementsByTagName("script");
// move the result form a DomNodeList to an array
$scripts = array();
foreach ($_scripts as $script) {
   $scripts[]=$script;
}
// iterate over array and remove script-tags from DOM
foreach ($scripts as $script) {
   $script->parentNode->removeChild($script);
}
// write DOM back to the HTML-string
$html = $dom->saveHTML();

Now chop chop, back to my code to finish that performance comparison. Who know what else we’ll learn 😉