3

I want to give the users the ability to sort the posts in the archive by some custom fields that I pre-define.

The end result would be en a tabbed container, and the user will click on the relevant filter-link that he/her want to see.

As an example: http://www.metacritic.com/browse/games/genre/date/action/all

I want to:
- Filter by date
- Filter by title
- Filter by meta_key

Is this possible to do?

Thanks for all help.. :)

2 Answers 2

2

NOTES: Regarding Jan Fabry's answer... Be sure to sanitize that incoming data first, else you're opening yourself to all sorts of nasty query strings..

You should also probably return the incoming data on that filter, return $query, in place of return;

I also think it would be preferable to have an array of possible values or do a query for possible meta values, that way you can build a switch that can check the incoming value matches against one of those possible values (easier way to sanitize the data coming in).

Not a regular user here, else i'd post an example (no idea how posting code works here - couldn't find it in the FAQ).

EDIT: Thanks for the poster pointing me to info for posting code.

Example follows, hopefully it works out ok... :)

// Only add the needed meta orders
$possible_orders = array( 'some_meta_key', 'some_other_meta_key' );

add_filter( 'pre_get_posts', 'archive_meta_sorting' );
function archive_meta_sorting( $query_object ) {
    if( !is_archive() || is_admin() )
        return $query_object;

    if( !isset( $_GET['orderby'] ) )
        return $query_object;

    global $possible_orders;

    $orderby = trim( $_GET['orderby'] );    

    switch( $orderby ) {
        case( in_array( $orderby, $possible_orders ) ):
            $query_object->set( 'orderby', 'meta_value' );
            $query_object->set( 'meta_key', $orderby );
            break;
        // You don't actually need these two cases below, it will work without them
        // The switch could actually just be a simple if in_array condition..
        case 'title':
            $query_object->set( 'orderby', 'title' );
            break;
        case 'date':
            $query_object->set( 'orderby', 'date' );
            break;
    }
    return $query_object;
}

You only need to pass in values for the meta sorting, the title and date will work just fine using the native support for ordering by those values, same can be said for order(desc or asc).

I hope that helps...

6
  • See here for how to post code: wordpress.stackexchange.com/editing-help
    – sorich87
    Nov 4, 2010 at 13:48
  • Yes, It's the idea that I can control the meta values that the user can filter posts by. I have a lot of custom fields/meta values, and it is not necessary/possible to filter with all of them. It's just a few values that I want the user to be able to filter by.
    – Martin-Al
    Nov 4, 2010 at 14:20
  • Thank you, @t31os. I will definitely try out this.. :) I'll get back to ya'll when I have tested it.
    – Martin-Al
    Nov 4, 2010 at 14:22
  • Happy to help.. :)
    – t31os
    Nov 4, 2010 at 14:40
  • @t31os: I believe get_posts() prepares meta_key and white-lists orderby, so SQL injection is prevented. But your idea of a restricted safe list is of course much cleaner. Since pre_get_posts is an action and not a filter, the returned value of your function is ignored, so I don't think you have to return anything.
    – Jan Fabry
    Nov 4, 2010 at 15:43
1

This is certainly possible, but how easy it will be depends on how clean you want the URL to be. If you don't mind appending ?orderby=[fieldname]&order=[asc or desc], you can just try it out. Adding ?orderby=title&order=asc to an archive page will, indeed, order by title with the 'A' before the 'Z' (default order is descending, since that is logical when ordering by date).

If you want to order by a meta key, say rating, you cannot just add orderby=rating, but you also have to tell the WP_Query::get_posts() function that you want to include this meta key in the query. The best way to do this is probably hooking into the pre_get_posts action, where you can check for the presence of this order field and add it to the query_vars of the object if needed. Something like this (but untested):

add_action('pre_get_posts', 'check_meta_sort');
function check_meta_sort(&$query)
{
    if (!isset($_GET['orderbymeta'])) {
        return;
    }
    $query->query_vars['meta_key'] = $_GET['orderbymeta'];
    $query->query_vars['orderby'] = $_GET['orderbymeta'];
}

If you want "nice" URLs, ending in /title, /date, /[meta-key], you will need to look into the Rewrite engine, but I can't help you there (yet).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.