How do I create a link that will always show the latest post?

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 ), "https://wordpress.stackexchange.com/" );
  $path = substr( trim( add_query_arg( array() ), "https://wordpress.stackexchange.com/" ), 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);

Leave a Comment