Single Post as Home Page in WordPress

Over the past few months, I’ve been working on a new premium theme for WordPress that would feature a single post on the home page. The one issue I needed to overcome was that I wanted that post to appear the same as it would on the single post page, which meant also displaying the comments.

This wasn’t as straightforward as you might think, though I did find a few different ways to make it happen.

Change the WordPress query

The easiest is to just insert two lines of code into the theme’s index.php file right before the WordPress loop:

<?php
global $wp_query;
$wp_query->is_single = true;
?>

Now you can set the Blog pages show at most number to “1” in Settings → Reading and it’ll work.

Not too complicated, right?

The major issue with this is that you’re tricking WordPress into thinking that the home page is actually a single post page. It’s not the most efficient way to code and you will end up having two pages that display the same content with different URLs, which is a no-no for search engines.

A better way to do the same thing (which I still think is a no-no), is to hook into pre_get_post and change the query a little:

<?php
add_action( 'pre_get_posts', 'bavotasan_custom_pre_get_posts' );
function bavotasan_custom_pre_get_posts( $query ) {
   if ( ! $query->is_home() || ! $query->is_main_query() )
      return;

   global $withcomments;
   $withcomments = true;
   $query->set( 'posts_per_page', '1' );
   $query->set( 'ignore_sticky_posts', '1' );
}
?>

This is more efficient, though still presents us with the issue of double content.

Check out the WordPress Codex for more info on pre_get_post().

Redirect the template

The only other solution I could think of that would make a single post the home page and not cause double content is to redirect to the latest post automatically.

There are a few different ways to accomplish this.

Open up index.php and replace the code with this:

<?php
if ( have_posts() ) :
   while (have_posts()) : the_post();
      wp_redirect( get_permalink() );
   endwhile;
endif;
?>

Or if you prefer to hook it all in functions.php, here the code your need:

add_action( 'template_redirect', 'bavotasan_custom_template_redirect' );
function bavotasan_custom_template_redirect() {
   if ( is_home() ) {
      $latest_post_ID = get_posts( 'posts_per_page=1&fields=ids' );
      wp_redirect( get_permalink( $latest_post_ID[0] ) );
      exit();
  }
}

You can even add in a little ternary operator to check for sticky posts:

add_action( 'template_redirect', 'bavotasan_custom_template_redirect' );
function bavotasan_custom_template_redirect() {
   if ( is_home() ) {
      $latest_post_ID = ( $sticky = get_option( 'sticky_posts' ) ) ? $sticky : get_posts( 'posts_per_page=1&fields=ids&ignore_sticky_posts=0' );
      wp_redirect( get_permalink( $latest_post_ID[0] ) );
      exit();
  }
}

Check out the WordPress Codex for more info on template_redirect().

Update

After @Kaspars made some valid points in the comments below, I thought about the redirect and found another approach that might be better. This requires both the pre_get_post() hook and the template redirect, but it eliminated the double content and keeps your home page URL constant.

add_action( 'pre_get_posts', 'bavotasan_custom_pre_get_posts' );
function bavotasan_custom_pre_get_posts( $query ) {
	if ( ! $query->is_home() || ! $query->is_main_query() )
		return;

	global $withcomments;
	$withcomments = true;
	$query->set( 'posts_per_page', '1' );
	$query->set( 'ignore_sticky_posts', '1' );
}

add_action( 'template_redirect', 'bavotasan_custom_template_redirect' );
function bavotasan_custom_template_redirect() {
   $latest_post_ID = get_posts( 'posts_per_page=1&fields=ids&ignore_sticky_posts=0' );
   if ( is_single( $latest_post_ID ) ) {
      wp_redirect( home_url() );
      exit();
  }
}

You lose the ability to feature a sticky post, though there is probably a workaround that could even make that work. For now, I suggest using this technique.

I’d like to hear what others have to say so feel free to add your thought in the comment section below.

Featured image provided by Gratisography.