1

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?

3 Answers 3

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.

5
  • 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, 2012 at 18:39
  • Why would that be a problem? By default, is_singular() is TRUE on a static-page-as-front-page. Nov 27, 2012 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, 2012 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. Nov 27, 2012 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, 2012 at 19:33
0

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
  • 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, 2012 at 21:23
  • Given your answer, see my alteration of it. Might not bother you as much. Nov 28, 2012 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, 2012 at 14:51
0

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.)

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.