4

If I want to create a link that will always show the latest post how can i do that?

Lets say I have three post types and there are three links with posts names (like a nav list) to those post types. How do I make it dynamic? I can't make it like this: blah.com/post, because it always will be always changing.

2 Answers 2

4

If I understand well you want to show the last post (one post) from one of the 3 post types you have, using a dynamic url like http://example.com/latest.

First of all lets add a filter to 'do_parse_request' filter:

add_filter( 'do_parse_request', function( $bool, WP $wp ) {
  $home_path = trim( parse_url( home_url(), PHP_URL_PATH ), '/' );
  $path = substr( trim( add_query_arg( array() ), '/' ), strlen( $home_path ) );
  if ( $path === 'latest' ) { // change 'latest' to anything else to change the url
     $wp->query_vars = array(
       'posts_per_page' => 1, // if you want more than one post change this
       'post_type' => array(
          'post',
          'another_cpy', // this should be your CPT name
          'yet_another_cpt' // this should be your CPT name
        )
     );
     $wp->is_latests = true;
     return false; // stop WordPress parsing request
  }
  $wp->is_latests = false;
  return $bool;
}, 0, 2);

Using previous code when you visit a page like http://example.com/latest WordPress will pick the last post from one of the 3 CPT, however you have no control on the template (index.php will be used).

However a simple filter to 'template_include' allows to choose the template:

add_filter( 'template_include', function( $template ) {
  global $wp;
  if ( $wp->is_latests ) {
    // change the name of the templates you want to use.
    // If none of the files is found in your theme folder, than index.php will be used
    $locate_template = locate_template( array( 'latest.php', 'single.php' ) );
    if ( ! empty( $locate_template ) ) {
       $template = $locate_template;
    }
  }
  return $template;
} );

That's all. Note that:

  • to view the page only one db query is required
  • you do not need to create a page, nor a page template for the scope
  • no rewrite rule is involved

Edit

If you want more than one post, let's say 3, and you want the last post for each CPT (like the answer by @DrewAPicture does) you can do it without running 3 separate queries.

First of all change 'posts_per_page' => 1 to 'posts_per_page' => 3 in the code above, after that add a filter to 'posts_groupby_request':

add_filter( 'posts_groupby_request', function( $groupby, $query ) {
  global $wp;
  if ( ! is_admin() && $query->is_main_query() && $wp->is_latests ) {
    $groupby = "{$GLOBALS['wpdb']->posts}.post_type";
  }
  return $groupby;
}, PHP_INT_MAX, 2);
2
  • 1
    This seems to be closer to what the OP is asking for, in terms of the rewrite slug, however it seems like from his description that he wants the latest from each of the post types, separately, rather than the latest post of any of the three post types. Having to run three queries sucks, but I can't think of a better way other than limiting the query footprints as much as possible. I could be wrong :) Sep 9, 2014 at 1:24
  • @DrewAPicture title of OP states "show the latest post", where "post" is singular. So I guessed OP wants to show 1 post. And even if he want one post for every cpt (so 3 posts in total) it is possible without running 3 queries, just by grouping posts by post_type using posts_groupby_request filter. I'll post an update to answer.
    – gmazzap
    Sep 9, 2014 at 1:39
3

You could run three get_posts() calls to snag the latest post from each post type, and build the links from there. Something like this would output the most recent post from each of the three post types in an unordered list:

/**
 * Grab the latest post from three different post types.
 *
 * @return array Array of post objects.
 */
function wpdocs_get_single_recent_posts() {
    $posts = array();

    foreach ( array( 'ptype_one', 'ptype_two', 'ptype_three' ) as $type ) {
        $post = get_posts( array(
            'posts_per_page' => 1,
            'post_type'      => $type,
        ) );

        if ( ! empty( $post[0] ) ) {
            $posts[] = $post[0];
        }
    }
    return $posts;
}

// In the theme ...
if ( ! empty( $posts = wpdocs_get_single_recent_posts() ) ) {
    echo '<ul>';
    foreach ( $posts as $obj ) {
        printf( '<li><a href="%1$s">%2$s</a></li>',
            apply_filters( 'the_permalink', get_permalink( $obj ) ),
            apply_filters( 'the_title', get_the_title( $obj ) )
        );
    }
    echo '</ul>'
} 
3
  • I think I confused you sorry. I need a link thats dynamic, so <a href="site.com/lastestpost"></a> So the lastestpost part will change whenever I create a new post Sep 8, 2014 at 13:47
  • In fact this answer is fully valid and a good one (+1). The only rework it might receive it that the query could get attached to pre_get_posts and the loop could be a template. Then simply add a page with a slug of latestposts.
    – kaiser
    Sep 8, 2014 at 23:29
  • It works, but require 3 db queries (and if a page template is involved queries becomes four). Also you are forced to create a page and assign a page template... there is a simpler and most efficent way /cc @kaiser
    – gmazzap
    Sep 9, 2014 at 1:15

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.