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'm running into circles trying to set up a simple rewrite rule, and thought I'd run the question by some of the rewrite experts here.

I have a custom post type, "mealplan", and I'm trying to implement a basic url rewrite where visitng site.com/mealplan/current will take the visitor to the most recent post of type "mealplan".

I've tried using several variants on this rule:

global $wp_rewrite;
$wp_rewrite->add_rule('mealplan/current', 
  'index.php?post_type=mealplan&numberposts=1&orderby=date&order=DESC', 
  'top' ); 

... but I can't seem to get either the 'numberposts' or the 'posts_per_page' parameters to do anything in the query string like that. It just goes straight to the archive page with the default number of posts per page.

This does what I want:

global $wp_rewrite;
$current_mealplan = get_posts( array(
  'post_type'=>'mealplan',
  'numberposts'=>1,
  'orderby'=>'date',
  'order'=>'DESC' ) );
$wp_rewrite->add_rule('mealplan/current', 
  'index.php?post_type=mealplan&post_id='.$current_mealplan[0]->ID, 
  'top');

...but at the cost of an additional query and a potential flush rules on every page load. Even if I optimize this by saving the current post ID in an option that's updated on update_post (so rules only have to be flushed when they change), this feels like unnecessary work that could be avoided if I could only get the url parameters above to work correctly.

share|improve this question

1 Answer 1

up vote 4 down vote accepted

Well, numberposts is not actually a query variable. It's just turned into posts_per_page in get_posts() before the query is run. posts_per_page is a private query var, which means you can't run it in the query string. A possible solution would be to register a custom query variable (let's say 'latest_mealplan' and add that variable to the rewrite rule (e.g. index.php?post_type=mealplan&orderby=date&order=DESC&latest_mealplan=1).

Then, hook into 'parse_request', which passes the $wp object to the callback. From there, it's just a matter of setting the parameter:

if( !empty( $wp->query_vars['latest_mealplan'] ) ){
  $wp->query_vars['posts_per_page'] = 1;
  add_filter( 'template_include', create_function( '$a', 'return locate_template(array("single-mealplan.php"));' ) );
}

Hope this helps!

share|improve this answer
    
Thanks, that helps a lot... I was almost there, but I was thrown by the syntax of that hook... I wasn't familiar with the context of the do_action_ref_array call. So now my url rewrite shows only one post, but its still using the archive template, not the "single-mealplan.php" template. I've tried adding $wp->is_singular = $wp->is_single = true;, but I think its too late. Is there an earlier hook I can use, before the template is set? –  goldenapples Jan 3 '11 at 21:51
    
$wp doesn't have the value for is_single(), that'd be $wp_query->is_single. But you don't even need to touch that. Just add code to filter the template directly. I'll edit the code above to reflect that. –  John P Bloch Jan 3 '11 at 23:39
    
That's great. Thank you! –  goldenapples Jan 3 '11 at 23:47
1  
Actually they are both query variables, they're just not public query variables, unlike cat, tag, page, etc.. (meta_key would be an example of another private query variable). –  t31os Jan 4 '11 at 15:31

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.