Archives For WordPress error handling

Making Sure Things Don’t fail Silently in your WordPress Code

Exceptions and errors happen, there is nothing you can do about it if your building sites. Since they are going to happen let’s make sure that we handle them.

For more robust error handling this is not really going to handle it. Your going to need to look at something like Airbrake for really robust application error handling. You could also use Test Driven Development (TDD) to make sure that code changes in one place do not affect the rest of the application. The things we will be dealing with are not getting the expected information in a widget.

If you prefer a video version jump to the end of the post.

Our Content

So let’s start by building a basic function so we can handle the exceptions that might come from it. We will assume that we are working with WooCommerce and that we are expecting the slug of a product category or ‘sale’ to denote an item that is on sale.

$tab = get_option( 'theme_t_wp_tabs' );

if( $tab != 'sale' ){
	// must be a product category so we do product category stuff
} else {
	// it's a sale item so do sale item stuff
}

That’s how I find most code. Since we built it and we know that we will be getting either a product category or a ‘sale’ for a sale item, but what if later another developer changes some code and we don’t get what we expect in our function. With it laid out as above it would just fail silently. Sure there would be no content on the page but no one may notice for a few hours, days, or weeks and the farther we get away from the change the harder it is to track down the change that broke things. Now lets look at how we should lay out the function to handle data we don’t expect.

$tab = get_option( 'theme_t_wp_tabs' );
$prod_cats = get_terms( 'product_cat' );
$prod_slugs = array();

// we expect to match against product slugs so lets get them out of our terms
foreach( $prod_cats as $cat ){
  $prod_slugs = $cat->slug;
}

if( $tab != 'sale' && !in_array( $tab, $prod_slugs ){
    // must be a product category so we do product category stuff
} elseif( $tab == 'sale' ){
    // it's a sale item so do sale item stuff
} elseif( $tab == 'blank'){
  // we have no content and that is fine
} else {
    // who knows what this is so we should let someone know that something is wrong
  theme_t_wp_error_message(
    'front page tabs',
    'We got through the tab navigation for featured items on the homepage and it was not a product category or a sale/featured item'
  );
}

In the second version we not only check to see if it’s a sale item but we also build an array of Product Categories and make sure that our value is in it as well. Then we make sure it’s a sale item. If it’s not sale is it a ‘blank’ value (meaning the client does not want any information in the tab) and if so we just do nothing because it should be blank. Finally we get to our error function with takes two arguments. The first is the message name (will be a subject line in an email) and the second is a message (will be the message in our email).

Our Error Function

Now we can look at our error function.

/**
 * The place where error notices go to die
 *
 * @param     string  $function   opt  The function we had an error on
 * @param     string  $message    opt  The error message
 *
 * @uses      set_transient
 * @uses      get_transient
 * @uses      wp_mail
 *
 * @author    WP Theme Tutorial, Curtis McHale
 * @since     Theme Name X.Y
 *
 */
function theme_t_wp_error_message( $function = null, $message = null ){

  $did_this_run = get_transient( $function );

  // lets stop here if this has run in the last 12 hours
  if( !empty( $did_this_run ) ) return;

  if( empty( $function ) && empty( $message ) ){
    // so we don't know about this but there is no message
    wp_mail(
      get_bloginfo( 'admin_email' ),
      'There was no error message at '.time(),
      'Looks like there was an error but someone did not fill in any part of the message'
    );
  }

  // setting a transient for 1/2 day so we don't get flooded with emails
  set_transient( $function, 'true', 60 * 60 * 12 );

  wp_mail(
    get_bloginfo( 'admin_email' ),
    $function,
    $message
  );

}

The first thing we do with our error function is get a transient with get_transient. We do this because the next thing we do is to check to see if the transient has anything in it. If there is something in the transient we are not going to do anything because the transient only gets set if the error has already been emailed at some point in the last 12 hours.

After we have made sure not to flood the inbox of anyone lets make sure that we have a message and subject for our email. Yes we should always have both but we may not for some reason so let’s just handle it now instead of later if it becomes a problem. If there are no values in $message or $function we will send an email to the site admin and at least give theme the time the error happened. Then at least they have some idea that something did not work as expected and can start the process of tracking the issue down.

So we know that we have not sent an email about this issue in the last 12 hours, and we have values in $message and $function, so lets keep going and set our transient with set_transient. This is the value we checked for at the beginning of our function to make sure that we don’t flood the inbox of anyone with error messages.

With our transient set we can now send our email with wp_mail. If your not familiar with wp_mail then read my tutorial on wp_mail. The subject and message were defined when we called theme_t_wp_error_message() in our first function.

Yes you could simply use wp_mail() directly in the first function but then we would not get the transient set to make sure that email inboxes are not flooded. If we no longer wanted to send the emails to the admin email on the site we’d also have to go hunt down all the instances of wp_mail and change the email. By abstracting the function we can just change the email in one spot.

Video