Modify WP_Query to use custom fields with custom post types

Most if not all of the WordPress sites that I build these days use Custom Post Types with Custom Fields.

I use the excellent CPT UI and Advanced Custom Fields plugins for these. I highly recommend them.

I’ll often want to change the way that WordPress displays these posts, which can be problematic. An easy way would be to add a new query to the page template, and discard the page’s main query object.

Not much of an issue, but it’s an extra and un-needed hit on the database.

A better way is to hook into that main query, and make your adjustments there.

Of course WordPress provides a hook for this, pre_get_posts, which is trivial to implement.

Ordering a custom post by a custom field

Let’s say we want to create an Event custom post. We’ve looked at Event Manager, an excellent plugin but overkill for our situation.

We use CPT UI to create the new Event CPT, and ensure that Has Archive is TRUE to enable the list of events to display.

Next, we use ACF to create a custom field called Event Date which uses a datepicker field type, and set it to display only on posts of type Event. And from ACF’s documentation: “If you intend to use this field to order your posts by, please leave the format as yymmdd.” This is exactly our situation so we leave the defaults.

So far, so good. We can create new events, set the date and view them on the site (after visiting the Permalinks page, of course).

However, WordPress displays the post in the order of publication, where we want them to display in the order of the Event’s date. Step in pre_get_posts.

Before we write the function, we also remember that this should only work on the site’s front end (i.e. not on the admin screen), and for the page’s main query only.

We then want to order the posts by the event_date from earliest to latest, i.e. Ascending.

Therefore:

function theme_event_cpt_orderby_event_date_custom_field($query)
{
    if(!is_admin()                                       // don't run on admin pages
       && $query->is_main_query()                        // target the main query only
       && $query->query_vars['post_type'] == 'event'     // run only for the Event post type
    )
    {
        $query->set('meta_key','event_date');            // choose this custom field
        $query->set('orderby', 'meta_value_num');        // order by the custom field specified
        $query->set('order', 'ASC');                     // order Ascending (low to high)
    }
}
add_action( 'pre_get_posts', 'theme_event_cpt_orderby_event_date_custom_field' );

Voila, our Event archive page now sorts events by the event date, making much more sense for our users.

WordPress provides more methods for even finer grained control. Thes methods and their arguments are detailed on the WP_Query documentation page.