0

Yesterday i asked how it would be best to load all existing pages and their content on front page - to create single page layout. (Single page theme)

From the info on that page i created my own pre_get_posts hook in functions.php:

function show_all_pages_on_index( $query ) {
    if ( (is_front_page() || is_home()) && $query->is_main_query() ) {
        $query->set('post_type', 'page');
        $query->set('parent', '0');
        $query->set('post_status', 'publish');
        $query->set('orderby', 'menu_order');
        $query->set('order', 'ASC');
    }
}
add_action( 'pre_get_posts', 'show_all_pages_on_index' );

If i put echo in the condition there it gets printed out, so i guess the hook works.

but this snippet in index.php still only prints out the initial blogpost that gets created with wordpress install: index.php:

$myposts = get_posts();
foreach( $myposts as $post ) :  setup_postdata($post);

    echo "<li><a href='". the_permalink() ."'>". the_title()."</a></li>";

endforeach; 
wp_reset_postdata();

HTML:

http://localhost/hello-world/Hello world!<li><a href=''></a></li>

Edit - to show what worked in my case as single page layouyt:

functions.php:

function show_all_pages_on_index( $query ) {
    if ( (is_front_page() || is_home()) && $query->is_main_query() ) {
        $query->set('post_type', 'page');
        $query->set('post_parent', 0);
        $query->set('post_status', 'publish');
        $query->set('orderby', 'menu_order');
        $query->set('order', 'ASC');
    }
}
add_action( 'pre_get_posts', 'show_all_pages_on_index' );

index.php:

while ( have_posts() ) {
    the_post();
    get_template_part( 'content', 'page' );
}

From there on wordpress'own tempate logic takes over using content-page.php or content.php, which pretty much means you can create different templates for subpages but you need to create them so that they actually fit into single page layout.

Thanks to everybody who contributed:)

6
  • Do not use a separate query with get_posts(). Use the main query only.
    – fuxia
    Jun 30, 2013 at 8:33
  • What separate query.... The previous thread explained to me that this way i am modifying the main query. Thats like the whole reason this pre_get_posts hook exists.. no?
    – Zayatzz
    Jun 30, 2013 at 8:35
  • No, it doesn’t. Just use the regular if ( have_posts() ) ….
    – fuxia
    Jun 30, 2013 at 8:37
  • Well this changed output, but i still am not getting what i want. this:if (have_posts()){ while ( have_posts() ) : the_post(); echo '<a href="">'. the_title().'</a>'; endwhile; } gets me only 1st page printed out. Not all pages.
    – Zayatzz
    Jun 30, 2013 at 8:40
  • If you want all posts, you have to add $query->set( 'posts_per_page', -1 );.
    – fuxia
    Jun 30, 2013 at 8:43

2 Answers 2

1

And why do you think it should do anything else?

What you do is:

  1. You add your filter to modify default WordPress query, which is run on index page. Your modifications are correct - this query will select published root pages.

  2. Then you run get_posts with default set of params (see below) and loop through them.

Default params for get_posts:

$args = array(
    'posts_per_page'  => 5,
    'offset'          => 0,
    'category'        => '',
    'orderby'         => 'post_date',
    'order'           => 'DESC',
    'include'         => '',
    'exclude'         => '',
    'meta_key'        => '',
    'meta_value'      => '',
    'post_type'       => 'post',
    'post_mime_type'  => '',
    'post_parent'     => '',
    'post_status'     => 'publish',
    'suppress_filters' => true );

You should use default WordPress loop, if you already modified default query. So do it like this:

// this will iterate posts already selected by WordPress with its default query (modified with your filter)
while ( have_posts() ) {
    the_post();

    echo "<li><a href='". the_permalink() ."'>". the_title()."</a></li>";
}
8
  • Well now this is giving me my desired result, although i did it like this:$args = array( 'orderby' => 'menu_order', 'order' => 'ASC', 'post_type' => 'page', 'post_mime_type' => '', 'post_parent' => 0, 'post_status' => 'publish', 'suppress_filters' => true ); $myposts = get_posts( $args ); foreach( $myposts as $post ) : setup_postdata($post); echo "<li><a href=".the_permalink().">".the_title() ."</a></li>"; endforeach; wp_reset_postdata(); And i still dont understand the WHY...
    – Zayatzz
    Jun 30, 2013 at 9:54
  • 1
    @Zayatzz: Why are you making everything so hard... ;) Everyone here already told you, that you don't have to make your own get_posts call if you already use pre_get_posts filter. You select these pages 2 times - it's inefficient and redundant! Jun 30, 2013 at 10:06
  • Yes i used this filter - look my question. but it does not seemed like its working or doing something.
    – Zayatzz
    Jun 30, 2013 at 10:43
  • 1
    Read carefully pls. I've already told you why it didn't work. It's because you ignore results of this query, and run your own, custom query (get_posts) with different params. There is ready/working solution in my answer, but you're still ignoring it and doing it wrong... It's really hard to help someone who isn't listening... Jun 30, 2013 at 10:54
  • 1
    There is something wrong with your filter then. Do you use static page as front page or standard home page? Add $query->set('posts_per_page', -1); to your filter and it should do the trick. Jun 30, 2013 at 15:06
0

Because I know it's always hard for beginners to understand the different ways of getting posts maybe you should try kind of a minimal example. If you visit your blog, WordPress will look up for index.php which normally contains the following piece of code:

<?php if ( have_posts() ) : ?>

    <?php /* Start the Loop */ ?>
    <?php while ( have_posts() ) : the_post(); ?>

        <h1><?php the_title();?></h1>
        <?php the_content();?>                  

    <?php endwhile; ?>

<?php endif; ?>

By default, this piece of code will retrieve your latest 10 posts, which behaviour can be altered under Settings > Reading: http://www.pixelfrau.com/wp-content/uploads/2012/09/wordpress_reading_settings_01.png .

Now you could ignore the given code and try something completely new right beneath it. But as mentioned, you can change the standard query very comfortable with pre_get_posts. I had a small typo in my example I gave you, you have to change parent to post_parent. So now we hook into the mainquery if on the frontpage/home from the outside using functions.php:

function show_all_pages_on_index( $query ) { 
    if ( (is_front_page() || is_home()) && $query->is_main_query() ) {
        $query->set('post_type', 'page'); // ignore to show posttype "posts" which was set under Setting > Reading
        $query->set('post_parent', '0');
        $query->set('post_status', 'publish');
        $query->set('orderby', 'menu_order');
        $query->set('order', 'ASC');
        $query->set( 'posts_per_page', -1 ); // ignore limit which was set under Setting > Reading
    }
}
add_action( 'pre_get_posts', 'show_all_pages_on_index' );

Now you should see all root pages instead of the 10 latest posts. So there is no need the get posts with get_posts, because your posts are already there. You could begin working on the template file creating new queries like you already did for showing e.g. subpages. Or you can use functions.php again to show subpages always direct under the content of your root pages hooking into the_content:

function show_subpages_after_content( $content ) {
    // vars
    $output = '';
    $subpages = '';
    /* SUBPAGES  */
    // args
    $args_subpages = array(
            'post_type' => 'page',
            'post_parent' => get_the_ID()            
     );
    // get posts
    $subpages_query = new WP_Query($args_subpages);
    if ($subpages_query->have_posts()) {
            $subpages = '<ul class="subpages">';
            while ($subpages_query->have_posts()) {
                    $subpages_query->the_post();
                    $subpages .= '<li>';
                    $subpages .= get_the_title();
                    $subpages .= '</li>';
                    }                    
            $subpages .= '</ul>';
    }
    wp_reset_postdata();
    // output - 1st the unedited content, 2nd all subpages beloging to this post
    $output .= $content . $subpages;
    //return
    return $output;
}
add_action( 'the_content', 'show_subpages_after_content' );

Which way is the best depends on how complex your site will be and how many different content elements you have to handle. Finally I hope this helps as starting point.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.