Time To First Byte – part 2

I often do performance optimisation on WordPress sites for clients, and have recently completed such a project.  One really critical metric I explored is Time To First Byte (TTFB).  But it can be hard to really drill down into it.

In my last post I spoke specifically about how to use the Server-Timing response header to return exactly how much time is spent on the server.  And you can return multiple values, for different parts of the process as well.  I promised a follow up post to dive into how to implement this header, so here it is.

In PHP this can prove rather difficult, as all headers need to be set before you output any HTML, including whitespace.  You can’t do that with the timing header, as it needs to be pretty much the last thing that you do, in order to include all of the time spent on the server.  The solution for this is to use an output buffer, something like this…

echo "etc."; //all of your application code
@header("Server-Timing: Total;dur=" . $seconds);
ob_end_flush(); //now the headers are sent

By using the output buffer, the headers all need to be set before the output buffer is flushed, allowing you to send HTML to the buffer beforehand.  This works a treat.

Luckily in WordPress, they use exactly this technique, so we can use that to our advantage.  They also create a global variable pretty early on in the loading of WordPress called $timestart, making it even easier.  In a plugin file, or the “functions.php” file of your theme, add the following PHP snippet…

function riklewis_shutdown() {
  global $timestart;
  $timediff = microtime(true) - $timestart;
  @header("Server-Timing: Total;dur=" . $timediff*1000);
add_action('shutdown', 'riklewis_shutdown', 0);

As you can see, the shutdown hook is used to trigger a function which calculates the time (in milliseconds) between now and the $timestart global variable, which is converted to seconds and added to the Server-Timing header.

This hook is one of the last things that runs before PHP shuts down execution, so it’s the perfect place to put our code.  However, it’s very important to set the priority (that third parameter) to 0 – this is because the output buffer is flushed using the same hook with a priority of 1, and we need to sneak in before that.

So there you have it, a way to easily return the time actually spent on the server with each request, perfect for performance optimisation, and breaking down that Time To First Byte (TTFB) value.