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.

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.

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?

share|improve this question

2 Answers 2

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.

share|improve this answer
    
It appears as though the get_header() call is including a file which calls wp_head() (at the very least). Wouldn't this advance the chain to the point where modifying the query would no longer impact scripts that use wp_head? –  agent86 Nov 27 '12 at 18:39
    
Why would that be a problem? By default, is_singular() is TRUE on a static-page-as-front-page. –  Chip Bennett Nov 27 '12 at 18:42
    
I tried this approach and it's still not loading the javascript, so I'm looking for what could potentially be the issue. The plugin is also looking at the value of post - is that set (properly, to the latest post) by the time I've called get_header()? –  agent86 Nov 27 '12 at 18:53
    
Can you add the Plugin callbacks to your question? This is getting to the point that it will be impossible to answer precisely without seeing what the Plugins are actually trying to do. –  Chip Bennett Nov 27 '12 at 18:56
    
I've linked the plugin's sourcecode (their SVN repo) and called out the specific function I'm trying to get working. I called out the $post issue early in the question, but it looks like I left it off my summary at the end. –  agent86 Nov 27 '12 at 19:33
up vote 0 down vote accepted

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.

share|improve this answer
1  
Overwriting $wp_query bothers the software engineer in me who wants compartmentalization and low coupling. I don't know if this violates any particular WP coding guidelines as well. I may revisit this solution if I can come up with a more elegant way of implementing it. –  agent86 Nov 28 '12 at 21:23
    
Given your answer, see my alteration of it. Might not bother you as much. –  Johannes Pille Nov 28 '12 at 21:45
    
This is the only thing thus far I've found that works, so I suppose it's the best that can be done. Sigh. –  agent86 Dec 8 '12 at 14:51

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.