Warning: Declaration of Thesis_Comment::start_lvl(&$output, $depth, $args) should be compatible with Walker::start_lvl(&$output, $depth = 0, $args = Array) in /nfs/c04/h02/mnt/66302/domains/gettheeye.com/html/wp-content/themes/thesis_16/lib/functions/comments.php on line 0

Warning: Declaration of Thesis_Comment::end_lvl(&$output, $depth, $args) should be compatible with Walker::end_lvl(&$output, $depth = 0, $args = Array) in /nfs/c04/h02/mnt/66302/domains/gettheeye.com/html/wp-content/themes/thesis_16/lib/functions/comments.php on line 0

Warning: Declaration of Thesis_Comment::start_el(&$output, $comment, $depth, $args) should be compatible with Walker::start_el(&$output, $object, $depth = 0, $args = Array, $current_object_id = 0) in /nfs/c04/h02/mnt/66302/domains/gettheeye.com/html/wp-content/themes/thesis_16/lib/functions/comments.php on line 0

Warning: Declaration of Thesis_Comment::end_el(&$output, $comment, $depth, $args) should be compatible with Walker::end_el(&$output, $object, $depth = 0, $args = Array) in /nfs/c04/h02/mnt/66302/domains/gettheeye.com/html/wp-content/themes/thesis_16/lib/functions/comments.php on line 0


by Zack on August 29, 2009


On the Internet speed is fundamental for usability. Even the best web pages turn awful during the few minutes you wait for them to load. Performance isn’t the exclusive purview of server administrators counting the number of processors assigned to each database. It is the responsibility of everyone working on a project. You can make your blog run faster, here’s how I did it to mine.

Get The Eye runs on WordPress. Even though WordPress does a lot to make my blog run faster, there is more for me to do. Making a blog run fast takes a little planning.


Most people enter Get The Eye through the front page. For the majority of blogs the front page is the most complex one and this blog is no exception. I focused my efforts on improving performance of that page.

Focusing performance where it really matters is part of the 80 percent strategy of performance. In performance tuning you’ll never solve 100 percent of the problem and you don’t need to try. Picking the right 80 percent is almost always enough.


I wanted each page to load in less than 2 seconds.

Performance tuning is like getting rich, you never know when you’re done. That’s why it is important to set goals. Performance goals look like, support X users per hour or make each page load in less than X seconds.

Setting goals is important, but I wanted to make them reasonable. I’m not Google. I’m a long way away from getting even 1,000 requests per hour —forget about 1,000 per minute— so I focused on making the page load faster for each user. My goal is making the front page load in under two seconds.

CSS Sprites

Many website use CSS sprites to improve performance while loading small images. Sprites combine many small image files into one big file. The size of the combined image can be smaller than the combined size of the original icons. Sprites also reduce the number of HTTP requests. I’ll talk a little more about that later in this article.

Sprites work well for smaller images, but Get The Eye uses a larger image to represent each article on the front page. When I had nine articles this was fine, but with 40 articles the combined image is over 350 kilobytes. That is way too big to load fast.

Making one image for everything was too big, but luckily I didn’t need to. Right now this site has either five or seven pages depending on the size of your browser window. You really only need the first page to load quickly so I split the sprites into three image bundles:

As the site gets larger I’ll add even more.

Fast image loading

Splitting the image up made the top page display faster, but you still had to wait for all of them to load. I took three steps to make the images load faster.

1 Deferred image loading

Smaller image bundles is a step in the right direction, but I still needed to keep users from loading all the images before they needed them. The solution was deferred image loading with JavaScript. This took a little bit of code.

var mainImage1 = new Image();
mainImage1.src = "http://images.gettheeye.com/images/main_images1.png";
    backgroundImage: "url('http://images.gettheeye.com/images/main_images1.png')",
    backgroundRepeat: "no-repeat"

With this mechanism instead of specifying the image location in the CSS I do it in JavaScript. This code gets called after the page loads. The result is that you load the images from the first page first and don’t have to wait for the others before you start using the blog.

2 Puny PNG

I still wanted to make my images smaller so I ran all my images through Puny PNG. It compressed the images without losing quality. It main my main image bundle 25 percent smaller. Final image size: 70 kilobytes

3 images.gettheyeye.com

The last change was creating images.gettheeye.com. Web browsers creates a group of workers to load the many files that make up a single web page. Normally this group has four workers in it. That means if your web page has more than four files you’ll have to wait until some of the workers are free.

However, there is a little bit of a hack here. The browser has a different group of workers for each website. By host my images on the subdomain images.gettheeye.com I can increase my group of workers from four to eight.

All of this makes the images load faster, now let’s work on the JavaScript and CSS.

YUI Compressor

When I write JavaScript and CSS I like to use generous comments. They help me remember what I was doing and help other people read my code. At run time these comments, and extra formatting, become a problem. They make the files larger for no real benefit.

The solution is YUI Compressor. This is a free tool from Yahoo that compresses JavaScript and CSS files by stripping out spaces, tabs, and comments. YUI Compressor took the 20 kilobyte source file for gettheeye.js and squished it down to a 7.5 kilobyte gettheeye.min.js. Over 50 percent smaller!

The only downside to JavaScript compression tools is the undecipherable nature of the code they output. YUI Compressor took 626 lines of JavaScript and compressed it down to one line. Great for computers, but just about impossible to read.

As an added perk YUI Compressor also find potential problems with my JavaScript before I deploy it. I integrated YUI Compressor into a simple build process with one line in a shell script:

java -jar bin/yuicompressor-2.4.2/build/yuicompressor-2.4.2.jar 
gettheeye.js -o wp-content/themes/thesis-15/custom/gettheeye.min.js

This helps make my JavaScript and CSS smaller, now let’s look at changing how those files are loaded.

Fewer HTTP requests

Your browser gets data from a web server using a protocol called HTTP. This is why website URLs start with http://. HTTP is a very stable protocol, but it is also an expensive one. Each time the browser makes a request it spends a lot of time setting up each request. CSS sprites work so well because they cut down the number of requests.

I wanted to apply this same improvement to my CSS files. There are three places you can put the CSS for your page:

  1. In an attribute like <div style=“color: red;”>
  2. In a separate CSS file like mystyles.css
  3. At the top of the page in a <style> tag

Putting the CSS in a separate file makes it easy to maintain. I can edit it using a CSS aware editor and reuse it in other pages. However, that means making separate HTTP requests for each file. Embedding the CSS in a style tag makes it load faster, but is very difficult to work with.

My solution is separate CSS files when I write the page and embedded ones when I run the page. There are some existing tools to do this like Sprockets for Ruby, but I didn’t need anything that complex. This is easy to do with a little PHP.

function echoFile($myFile) {
    $fh = fopen($myFile, 'r');
    $theData = fread($fh, filesize($myFile));
    echo $theData;

This code will load a specified file and push the contents of that file back to the browser. I can call it like this for a CSS file:

echo '<style type="text/css">';
echo '</style>';

A small change makes it work for JavaScript:

echo '<script type="text/javascript">';
echo '</script>';

Embedding the files requires fewer HTTP requests for new users. However, repeat users never have the chance to cache the data in their browsers. However, given the size of the files and the nature of my traffic it feels like the right solution.

Faster server-side

All of these improvements focus on making the client load the page faster. To make the server serve the page faster I added WP Super Cache. This is a WordPress plugin that caches the results of a page and serves them again from the cache. This means the page doesn’t get rebuilt for every request. It works so well that there isn’t much more to say about it. If you run WordPress go download it.

Performance tools

For most of these performance improvements I relied on Yahoo’s YSlow and Google’s Page Speed. These are both free Firefox plugins that tell you what your page is doing and suggest ways to make it faster. These two tools found most of the issues I fixed.

The results

Most of the time my top page loads in just over three seconds and makes 16 HTTP requests. Compare that with the results from some other big blogs: 32 for Smashing Magazine, 57 for CopyBlogger, and 81 for ChrisBrogan.com.

I didn’t hit my two second goal for the main page, but many of the individual articles load that fast. I’m still working on the main page. Performance tuning isn’t something you’re ever done with. There are always little tweaks you can add, but I’m feeling good about where I am now. Get The Eye is very maintainable and fast enough that it feel good to use. Now if I could just get the traffic of some of those other blogs I’ll be all set.

Fatal error: Uncaught Error: Class 'thesis_comments' not found in /nfs/c04/h02/mnt/66302/domains/gettheeye.com/html/wp-content/themes/thesis_16/comments.php:24 Stack trace: #0 /nfs/c04/h02/mnt/66302/domains/gettheeye.com/html/wp-includes/comment-template.php(1513): require() #1 /nfs/c04/h02/mnt/66302/domains/gettheeye.com/html/wp-content/themes/thesis_16/lib/functions/loop.php(92): comments_template() #2 /nfs/c04/h02/mnt/66302/domains/gettheeye.com/html/wp-content/themes/thesis_16/lib/functions/loop.php(8): thesis_single_loop() #3 /nfs/c04/h02/mnt/66302/domains/gettheeye.com/html/wp-content/themes/thesis_16/lib/html/content_box.php(66): thesis_loop_posts() #4 /nfs/c04/h02/mnt/66302/domains/gettheeye.com/html/wp-content/themes/thesis_16/lib/html/content_box.php(42): thesis_content_column() #5 /nfs/c04/h02/mnt/66302/domains/gettheeye.com/html/wp-content/themes/thesis_16/lib/html/content_box.php(25): thesis_columns() #6 /nfs/c04/h02/mnt/66302/domains/gettheeye.com/html/wp-content/themes/thesis_16/lib/html/frameworks.php(27): in /nfs/c04/h02/mnt/66302/domains/gettheeye.com/html/wp-content/themes/thesis_16/comments.php on line 24