How do I display only the latest post on my home page, while maintaining proper plugin hooks?

What I’m trying to do is display the most recent post (a la my theme’s “single.php”) on my “home” page.

This is complicated by the fact that I have certain plugins (specifically, Scripts n Styles) that are hooking wp_head and wp_enqueue_scripts. In these hooks, they are checking is_singular() to see if my per-post javascript should be injected into the page or not. They then check attributes of the global $post variable to determine which scripts to inject. I want the per-post javascript to be properly injected on the home page if needed.

Read More

For reference, the plugin in question’s source code is here and the specific function I’m concerned with running properly is called scripts_in_head():

static function scripts_in_head() {
    // Global
    $options = get_option( 'SnS_options' );
    if ( ! empty( $options ) && ! empty( $options[ 'scripts_in_head' ] ) ) {
        ?><script type="text/javascript" id="sns_global_scripts_in_head"><?php
        echo $options[ 'scripts_in_head' ];
        ?></script><?php
    }

    if ( ! is_singular() ) return;
    // Individual
    global $post;
    $SnS = get_post_meta( $post->ID, '_SnS', true );
    $scripts = isset( $SnS['scripts'] ) ? $SnS[ 'scripts' ]: array();
    if ( ! empty( $scripts ) && ! empty( $scripts[ 'scripts_in_head' ] ) ) {
        ?><script type="text/javascript" id="sns_scripts_in_head"><?php
        echo $scripts[ 'scripts_in_head' ];
        ?></script><?php
    }
}

I’m pretty new to WordPress development, so I’ve probably made a boneheaded mistake here that is making my life overly difficult. Here are the various and sundry ways I’ve beaten my head against the wall:

From what I understand, I can’t just change my home.php template, since the template isn’t even executed until after all these hooks would have already run. Therefore, modifying the query at this point or creating a new one would be pointless.

I could use a HTTP header redirect, although I’m not sure that would work without manually updating the redirect every time the latest post changes.

I could change home.php to have a javascript redirect, but that seems like it would be a lot of time/effort wasted loading the “dead” home page just to get redirected to another page. If this is the only way, so be it, but it seems like I should be able to do better.

I’ve tried creating a plugin that hooks earlier than Scripts n Styles, and modifies $wp_query, but this doesn’t seem to work properly. Likely, I’m doing it wrong:

function make_single_from_home()
    global $wp_query;
    if ( $wp_query->is_home() ) {
        $last = wp_get_recent_posts( '1');
        $last_id = $last['0']['ID'];
        $wp_query->set( 'p', $last_id )
        $wp_query->set( 'post_count', 1);
        $wp_query->set( 'is_home', false);
        $wp_query->set( 'is_single', true);
    }
}

I’ve tried attaching this to several events prior to Scripts n Styles’ hook, (send_header, template_redirect, etc), and it doesn’t seem to help. I don’t see the javascript blocks being added to my <head> tag. (It’s possible that this is a valid solution and I or the plugin are just Doing It Wrong)

It’s also possible that there’s a really easy way to make my homepage a singular page displaying my latest post, and I’m just too new to figure it out.

Is there some way to create a home page that displays just the latest post, while making the $post variable valid, and is_singular() == true early enough for my plugin dependencies?

Related posts

Leave a Reply

3 comments

  1. I’m not sure how plugin hooks would impact in any way the solution to your problem. The home.php template file gets included at the template_redirect action, which fires well-before wp_head.

    That said, what it sounds like you want to do is:

    1. Have 'posts_per_page' = 1 on the first page of the blog posts index
    2. Have 'posts_per_page' = 10 on subsequent pages of the blog posts index

    The simplest method is probably to use a static page as the site front page, and then use a custom query in front-page.php to retrieve the latest post.

    front-page.php:

    get_header();
    
    $latest_post_args = array(
        'post_per_page' = 1;
    );
    
    $latest_post = new WP_Query( $latest_post_args );
    
    if ( $latest_post->have_posts() ) : while ( $latest_post->have-posts() ) : $latest_post->the_post();
    
        // Loop markup goes here
    
    endwhile; endif;
    
    wp_reset_postdata();
    
    get_footer();
    

    Since is_singular() returns true for static pages as the site front page, your plugin script enqueues should be unaffected.

  2. Chip’s answer helped me fix the error, but it took a bit more tweaking to get it fully solved.

    With a static front page, the front-page.php template will be called (as per the hierarchy) with $wp_query populated with page ID that corresponds to the page you’ve chosen to show as the “static page” in the reading options.

    Chip suggested creating a new query after the get_header() call, which can help change the posts that are displayed. He’s also correct that, owing to the settings parsed into $wp_query to the front-page.php template, the is_singular() call will return TRUE.

    However, this won’t solve the issue of the value of $post. As soon as get_header() is called, most themes will advance the action chain from template_redirect past wp_enqueue_scripts. Any hooks in between there will be called, and it will be too late to effect the value of $wp_query or $post for plugins that hook one of the events in that region.

    Therefore, the wp_head action was getting called with the $post information from the “static page” entry. Since I don’t want that to happen, I have to modify these values somehow prior to the call to get_header().

    There are probably multiple ways of doing this, but the one that worked for me was to add:

    global $wp_query;
    
    $last = wp_get_recent_posts(array('numberposts'=>'1','post_status'=>'publish' ));
    $last_id = $last['0']['ID'];
    
    $wp_query = new WP_Query('p='.$last_id);
    

    to my front-page.php prior to the call to get_header(). This overwrites the query value generated from the static page, and replaces it with one that returns just the most recent post.

    It’s probably possible to do this with a plugin as well, so long as you hook early enough.

  3. You are trying to display a snippet of JavaScript on the homepage, which features a single post.

    The simplest way is to include the snippet of JS everywhere (Global Settings), then check in the JavaScipt whether you are on the homepage: if ( $('body').hasClass('home') ) { /* do_stuff() */ }

    This will simplify your maintenance of code.

    (Sorry I didn’t ever see this until now.)