Author: topher

Storing complex queries in transients

I’ve recently discovered the joy of transients in WordPress.  You can read about them here: http://codex.wordpress.org/Transients_API.  It’s a method of caching bits of information.  If you have an object cache on your server like memcache, it’ll store it there, otherwise it stores it in the database.

You may wonder why I’d want to store the results of a database query in the database, since I’m still making a call.  The difference is that the original query takes much longer to run than the transient retrieval.

Here’s the code I have for creating the transient:

But what happens if someone makes a change?  We want to clear that transient, so that the next time it’s asked for it’ll recreate itself.

Now we have the results of of a complex query stored in a place that takes less time to retrieve, while making it so that it self clears when needed.

pre_get_posts instead of query_posts

The other day I had a custom content type of things for sale.  There’s a meta field for marking it Sold.  On my archive page I didn’t want to include Sold items, so I went hunting for the proper query_posts() bit to put in the top of my archive template.

What I found was several posts that said to never ever use query_posts().  The reason is that it doesn’t actually change the query like I thought it did, it simply runs another one.  However successful that may be at getting your content, it’s a second database query you don’t want.

The answer is to use a filter called pre_get_posts, and just like it sounds, it allows you to do stuff before you get posts.

So here’s what I did:

function filter_sold_coaches( $query ) {

    // check to see if we're editing the main query on the page.
    if( $query->is_main_query() ){

        // Check to make sure I'm on the Coaches archive page OR the Make page AND I'm not in the admin area
        if ( ($query->is_post_type_archive('coaches') OR $query->is_tax('make')) AND !is_admin() ) {

            // set a meta query to get only Coaches where the ecpt_sold element does not exist.
            $query->set('meta_query',array( array( 'key' => 'ecpt_sold', 'value' => 'on', 'compare' => 'NOT EXISTS')));

            // now I want to order by the year field, so I do that
            $query->set('meta_key', 'ecpt_coachyear');
            $query->set('orderby', 'meta_value_num');
        }

    }
    return $query;

}
// now I apply my function to pre_get_posts and Bob's your uncle
add_filter( 'pre_get_posts', 'filter_sold_coaches' );

The !is_admin bit is important, because this will affect your admin area if you don’t and you’ll find that you’re missing some posts.

Using the set() method you can set anything that you migth set with WP_Query, so if you’re good with that then this should be quite easy for you.

Many thanks to @pippinsplugins for wisdom in putting this together.

Rendering Jetpack Stats

jetpack-logo-smallJetpack is a plugin offered by WordPress.com, and it contains a variety of services, each of which can be activated or deactivated within Jetpack, depending on what you want to use.

One of the features is web site statistics.  You create a WordPress.com account and then associate it with your Jetpack plugin.  Then Jetpack keeps track of statistics for your site on WordPress.com.  You can log in there and view what’s going on, or right in your own site you can view some charts and graphs.

On the sites we build at work we have a Social bar, with the usual colleciton of social traffic indicators.  You can see it here: http://www.salinehornets.com/.  One of the things we wanted there was an indication of how many times the specific articles had been viewed.

Through a long voyage of discovery about why various plugins that claimed to do this were failing, AND some wonderful support from Andy at Automattic, I figured out a good way.

Jetpack provides a function called stats_get_csv that queries WordPress.com, and here’s how I’m using it:

$args = array(
    'days'=>-1,
    'limit'=>-1,
    'post_id'=>$post_id
);

$result = stats_get_csv('postviews', $args);

The -1 indicates infinity, so I’m asking for all days, unlimited, and I’m giving it the post_id I’m looking for.

Then in the function call I’m telling it I want postviews.  That gets me an array that looks like this:

Array
(
    [0] => Array
        (
            [views] => 2
        )

)

So I then do something like this:

$views = $result[0]['views'];
return number_format_i18n($views);

This is all in a function, hence the return.

The stats_get_csv function caches for 300 seconds, so you won’t necessarily see instant changes as you reload your page.  You probably also should be caching on your own end, so that you’re not even hitting it that often.  We’re doing whole page caching, so that my archive page doesn’t make 10 calls at once on that page.

There’s precious little documentation about this process, which is one of the reasons I did this post.

The plugin we tried using before this wasn’t passing the post_id, it was trying to get stats for ALL posts, and then loop through them and grab the one we wanted.  The problem is that the function doesn’t return ALL posts, it returns the top 30 or so.  It’s much more efficient to simply ask for the one you want.

Post Sorting Reloaded

I recently had a client tell me they wanted an archive page that listed every single item in the database on one page.  Since it was for a custon content type and not an infinite blog I went with it. It just uses the default archive template

They they said they wanted them sorted by title alphabetically, rather than by date.  This made me sad because I didn’t want to have to hack together a custom archive page just to change the sorting.  Plugin hunting I went.

Post sorting reloaded screenshot
Admin Screenshot

What I ended up with is Post Sorting Reloaded.  It offers a simple interface to sort ANY content type archive page in any way you want.  Click on the screenshot on the right for a nice large version.

The thing I love most is that it doesn’t try to be clever, and help you figure out how to sort.  It’s simply a wrapper for the posts_orderby filter, and then you can enter any logic code you want for the condition and the sort parameters.

It’s simple, updated recently, and worked magnificently.

WordPress first settings

There’s a short list of things of things I do immediately to every WordPress install.  I’m not talking about plugins or themes, just simple settings changes. Some of them I strongly recommend to everyone, some are optional, but I’d recommend you at least look through them.

 1. Turn off Comments

Even if I know I’m going to want them later, if left on it’ll take about 20 minutes for spammers to find your site and start leaving garbage.  (Settings -> Discussion)

2. Turn off Gravatars

This is optional, but I hate gravatars.  It’s Automattic’s home built spyware and slows your page loads.  (Settings -> Discussion)

3. Set Permalink structure

The default structure is not SEO friendly, nor humanly understandable.  I like “day and name”, but anything beside post id’s is good. (Settings -> Permalinks)

4. Set the Time Zone

The default timezone is UTC, and it’s unlikely that your site is based in that timezone. (Settings -> General)

5. Set the day the week starts on

The default is Monday.  Every client I’ve ever had wanted Sunday.  (Settings -> General)

6. Set Tagline

The default tagline is “Just another WordPress site”.  Occasionally this will remain in the html on the site, but get hidden by CSS or something.  This looks bad to google and other nerds looking at your code. (Settings -> General)

7. Delete the default page and post

WordPress comes with one Page and one Post in there.  It can be ok to re-use the page, but the post needs to go, or you’ll look a little silly when people go to the first post in your blog.  If you don’t rename the first page, or delete it, it also looks bad.

What are some of your initial settings?