Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I have posts with a custom field called year. The year ranges from 1900 to 2011. I want to create an individual page for each year which will displays the posts with that year. So I will be creating a page with a template and a custom query to find all posts with that specific year.

However, instead of creating 100+ individual year pages I want to just create 1 page which will extract the parameter from the URL and into a variable and then find the posts with that variable.

So instead of creating individual pages like base.com/year/1990 , base.com/year/1991, base.com/year/1992 I just want to create one page and extract the year. So for example I want to extract 2008 out of this page URL:

http://www.base.com/year/2008

I already know I can extract year by using this code:

$post->post_name;

but how to I get additional parameters?

Thanks

share|improve this question

3 Answers 3

This problem can be solved with the WordPress Rewrite API

The simplest way

I assume that you've created a page called year and the request is most probably matched to this rule (.+?)(/[0-9]+)?/?$, with the query rewritten to pagename=year.

However, you will notice from the regular expression that an additional / can be matched to with numbers following it.

Requesting /year/1999 will transform the query to pagename=year&page=%2F1999. Thus page is what will contain 1999. And you can get to it using get_query_var('page'); and feed it to your custom query by using use the simple get_posts() and feed it the extra meta_key and meta_value to retrieve your posts like so:

$args['meta_key'] = 'year';
$args['meta_value'] = get_query_var('page');
// ... other arguments
$posts_array = get_posts( $args );

But isn't this wrong?

If using this unexpected result and behavior of taking page and feeding it in as year this feels wrong, you can go about achieving the same result in a different way by adding your own rewrite rule.

By adding a rule that will match ^year/([^/]\d+)/?' and rewrite to pagename=year&custom_year=$matches[1] you will be able to access custom_year via $wp global object.

// this has to be done only once!
add_rewrite_rule('^year/([^/]\d+)/?',
    'index.php?pagename=year&custom_year=$matches[1],
    'top');
flush_rewrite_rules();

The code above should be wrapped to be hooked into the init action. The query itself can be accessed retrieved from the $wp->matched_query property and has to be parsed:

global $wp; // may be required to bring into scope

$q_args = array();
parse_str($wp->matched_query, $q_args);
$custom_year = $q_args['custom_year'];

$args['meta_key'] = 'year';
$args['meta_value'] = get_query_var('custom_year');
// ... other arguments
$posts_array = get_posts( $args );

Note how you pick the name of your custom query field and make sure it's not in danger of collision with any of the reserved terms.

Another way of looking at it

You may be better off looking at the whole situation from an archive's perspective rather than a page. If you register your own custom taxonomy for your posts instead of a custom field, you'll be able to query for posts based on that taxonomy without the manually adding additional rewrite rules.

The register_taxonomy() function will allow you to add your custom_year taxonomy and query for it getting archive pages back, without additional parsing, queries, etc.

You may have to flush_rewrite_rules() once after registering the taxonomies in order to flush some new rules WordPress automatically generates when registering taxonomies.

Take note of the rewrite argument you supply to register_taxonomy(), set it to custom_year and you should be able to query for posts in the taxonomy without further modifications.

share|improve this answer
global $post;
// This is how you get the year of a post, not from the URL
$post_year = idate('Y', strtotime("{$post->post_created_gmt} GMT"));

And to get them from the DB you do this:

global $wpdb;
$archive = array();
foreach(($rows = $wpdb->get_results(
    "SELECT `ID`, YEAR(`post_date_gmt`) AS `Year` FROM {$wpdb->posts}
        WHERE `post_type`='post' ORDER BY `post_date_gmt` DESC;"
)) as $row){
    if(!isset($archive[$row->Year])){
        $archive[$row->Year] = array();
    }
    $archive[$row->Year][] = $row->ID;
}
foreach($archive as $year => $posts){
    foreach($posts as $post){
        $permalink = get_permalink($post);
        $post = get_post($post);
        // Do stuff with $year and $post here
    }
}

Now you can add you own code instead of // Do stuff with $year... and do what you wish with the posts. If you have tens of thousands of posts, you need to optimize this a bit by grouping by year.

It's a starting point.

Regards.

share|improve this answer
    
Thanks, sorry if you missed it but I think I said that year is a custom field. I'm not trying to get the year the post was published but the year I added to a custom field. I'm advertising some books and some of them were released between 1900 - 2011. –  Jonathan Oct 21 '11 at 20:50
    
@Jonny What's the name of the field that holds the YEAR? I'll rewrite the queries for that exact custom field value. –  EarnestoDev Oct 21 '11 at 20:52
    
Hi, thanks. It is called "year". –  Jonathan Oct 21 '11 at 20:53

REMIX:

global $wpdb;
$archive = array();
foreach(($rows = $wpdb->get_results(
    "SELECT t1.`ID`, t2.`meta_value` AS `Year` FROM
        {$wpdb->posts} AS t1, {$wpdb->postmeta} AS t2
    WHERE t2.`meta_key`='year' AND
        t1.`ID` = t2.`post_id` AND
        t1.`post_type`='post'
    ORDER BY `Year` DESC, `post_date_gmt` DESC;"
)) as $row){
    if(!isset($archive[$row->Year])){
        $archive[$row->Year] = array();
    }
    $archive[$row->Year][] = $row->ID;
}
foreach($archive as $year => $posts){
    foreach($posts as $post){
        $permalink = get_permalink($post);
        $post = get_post($post);
        // Do stuff with $year and $post here
    }
}

Hope this helps as a foundation :)

Regards.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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