How to make posts appear under pages

I’ve been using this template from twenty eleven. I must give great credit here to a great tutorial from digitalraindrops. I have rewritten this to suite my needs and it is currently written to suite the twentyfourteen theme.

You can check out the tutorial at the link given above. What I like about this template is that it can be reused a thousand times. What this template do, it let you choose a category from a drop down list. This category’s posts will then be displayed on that page. Here is the code that I use

First, all the meta functions that include options for posts per page, order, page title, post title, etc. This code will go in your functions.php or custom functions file

<?php
add_action( 'admin_init', function ()
{   
    $post_id = filter_input( INPUT_GET, 'post', FILTER_VALIDATE_INT );
    if ( $post_id ) {
        // Get the current page template
        $post_meta = get_post_meta( $post_id );

        // Make sure that we only target our desired template
        if (    isset ( $post_meta['_wp_page_template'][0] )
             && 'page-pop.php' === $post_meta['_wp_page_template'][0] 
        ) {
            add_meta_box(
                'pop_meta_box', 
                __( 'Page of Posts with the same name' ), 
                'pop_metabox_options', 
                'page', 
                'side', 
                'core'
            );
        } else {
            if( isset( $meta['_cat_id'][0] ) ) {
                $meta_value_array = [
                    '_cat_id',
                    '_page_title',
                    '_posts_title',
                    '_order_by',
                    '_asc',
                    '_post_count'
                ];
                foreach ( $meta_value_array as $value ) 
                    pop_helper_update_post_meta( $post_id, $value, '' );

                remove_meta_box( 'pop_meta_box', 'page', 'side' );
            }
        }
    }
    add_action( 'save_post',  'pop_update_post_meta_box' );
});

function get_pop_order_by_list()
{   
    // Set the sort order
    $sort = [
        [
            'DESC' => [
                    'value' => 'DESC',
                    'label' => 'Descending'
                ],
            'ASC'  => [
                    'value' => 'ASC',
                    'label' => 'Ascending'
                ],
        ]
    ];      

    // Create an array of values to order the posts by
    $order_list = [
        [
            'none'          => [
                    'value' => 'none',
                    'label' => 'None'
                ],
            'id'            => [
                    'value' => 'ID',
                    'label' => 'Post ID'
                ],
            'author'        => [
                    'value' => 'author',
                    'label' => 'Author'
                ],
            'title'         => [
                    'value' => 'title',
                    'label' => 'Post Title'
                ],
            'date'          => [
                    'value' => 'date', 
                    'label' => 'Post Date'
                ],
            'modified'      => [
                    'value' => 'modified',
                    'label' => 'Modified Date'
                ],
            'parent'        => [
                    'value' => 'parent',
                    'label' => 'Parent Post'
                ],
            'rand'          => [
                    'value' => 'rand',
                    'label' => 'Random'
                ],
            'comment_count' => [
                    'value' => 'comment_count',
                    'label' => 'Comment Count'
                ],
            'menu_order'    => [
                    'value' => 'menu_order',
                    'label' => 'Menu Order'
                ],
        ]
    ];

    return $list = array_merge( $sort, $order_list );
}

function pop_metabox_options()
{
    $post_id = filter_input( INPUT_GET, 'post', FILTER_VALIDATE_INT );
    if ( !$post_id )
        return;

    // Make sure the current user have the edit_page ability
    if ( !current_user_can( 'edit_post', $post_id ) )
        return;

    // Get the current page template
    $template_file = get_post_meta( $post_id, '_wp_page_template', true );

    // Make sure that we only target our desired template
    if ( 'page-pop.php' !== $template_file ) 
        return;

    // Get all the post meta values and sanitize/validate them
    $post_meta = get_post_meta( $post_id );

    $filters = [
        '_cat_id'      => [
            'filter'   => FILTER_VALIDATE_INT,
            'default'  => 1
        ],
        '_page_title'  => [
            'filter'   => FILTER_SANITIZE_STRING,
            'default'  => ''
        ],
        '_posts_title' => [
            'filter'   => FILTER_SANITIZE_STRING,
            'default'  => ''
        ],
        '_order_by'    => [
            'filter'   => FILTER_SANITIZE_STRING,
            'default'  => 'ID'
        ],
        '_asc'       => [
            'filter'   => FILTER_SANITIZE_STRING,
            'default'  => 'DESC'
        ],
        '_post_count'  =>  [
            'filter'   => FILTER_VALIDATE_INT,
            'default'  => get_option( 'posts_per_page' )
        ],
    ];  

    foreach ( $filters as $key=>$value ) {
        if ( !array_key_exists( $key, $post_meta  ) ) {
            $post_meta[$key][0] = $value['default'];
        } else {
            $post_meta[$key][0] = filter_var( $post_meta[$key][0], $value['filter'], $value['default'] );
        }
    }

    ?>
        <!-- Sart the meta boxes -->
    <div class="inside">
        <p>
            <label>
                <strong><?php _e( 'Page Title' ); ?></strong>
            </label>
        </p>    
        <input id="_posts_title" name="_posts_title" type="text" style="width: 98%;" value="<?php echo $post_meta['_page_title'][0]; ?>"/>  

        <p>
            <label>
                <strong><?php _e( 'Post Title' ); ?></strong>
            </label>
        </p>    
        <input id="_page_title" name="_page_title" type="text" style="width: 98%;" value="<?php echo $post_meta['_posts_title'][0]; ?>"/>

        <p>
            <label>
                <strong><?php _e( 'Category', 'pietergoosen' ); ?></strong>
            </label>
        </p>
        <select id="_cat_id" name="_cat_id">
            <?php 
            // Get all the categories
            $categories = get_categories();
            foreach ( $categories as $cat ) {
                $selected = ( $cat->cat_ID == $post_meta['_cat_id'][0] ) ? ' selected = "selected" ' : '';

                $option = '<option '.$selected .'value="' . $cat->cat_ID;
                $option = $option .'">';
                $option = $option .$cat->cat_name;
                $option = $option .'</option>';
                echo $option;
            } //endforeach
            ?>
        </select>

        <?php 
        if ( function_exists( 'get_pop_order_by_list' ) ) {
            $list = get_pop_order_by_list();
            ?>

            <p>
                <label>
                    <strong><?php _e( 'Order' )?><strong>
                </label>
            </p>
            <select id="_asc" name="_asc">
                <?php 
                foreach ( $list[0] as $output ) {
                    $selected = ( $output['value'] == $post_meta['_asc'][0] ) ? ' selected = "selected" ' : '';

                    $option = '<option '.$selected .'value="' . $output['value'];
                    $option = $option .'">';
                    $option = $option .$output['label'];
                    $option = $option .'</option>';
                    echo $option;
                } //endforeach
                unset ( $output );
                ?>
            </select>

            <p>
                <label>
                    <strong><?php _e( 'Sort by' )?></strong>
                </label>
            </p>
            <select id="_order_by" name="_order_by">
                <?php 
                foreach ( $list[1] as $output ) {
                    $selected = ( $output['value'] == $post_meta['_order_by'][0] ) ? ' selected = "selected" ' : '';

                    $option = '<option '.$selected .'value="' . $output['value'];
                    $option = $option .'">';
                    $option = $option .$output['label'];
                    $option = $option .'</option>';
                    echo $option;
                } //endforeach
                unset ( $output );
                ?>
            </select>       

            <?php
        }
        ?>

        <p>
            <label>
                <strong><?php _e( 'Posts per Page' ); ?><strong>
            </label>
        </p>
        <input id="_post_count" name="_post_count" type="text" value="<?php echo $post_meta['_post_count'][0]; ?>" size="3" />

    </div>
    <!-- End page of posts meta box -->
    <?php
}

function pop_update_post_meta_box( $post_id )
{
    // Make sure we have a valid $_POST method
    if ( !$_POST )
        return;

    // Make sure the current user have the edit_page ability
    if ( !current_user_can( 'edit_page', $post_id ) )
        return;

    // Get the current page template
    $template_file = get_post_meta( $post_id, '_wp_page_template', true );

    // Make sure that we only target our desired template
    if ( 'page-pop.php' !== $template_file ) 
        return;

    // Do nothing on auto save, just bail
    if (    defined( 'DOING_AUTOSAVE' ) 
         && DOING_AUTOSAVE 
    )
        return;

    $args = [
        '_cat_id'       => [
                               'filter' => FILTER_VALIDATE_INT,
                               'default' => 1
                           ],   
        '_page_title'   => [
                               'filter' => FILTER_SANITIZE_STRING,
                               'default' => ''
                           ],
        '_posts_title'  => [
                               'filter' => FILTER_SANITIZE_STRING,
                               'default' => ''
                           ],
        '_order_by'     => [
                               'filter'  => FILTER_SANITIZE_STRING,
                               'default' => 'date'
                           ],
        '_asc'        => [
                               'filter'  => FILTER_SANITIZE_STRING,
                               'default' => 'DESC'
                           ],
        '_post_count'   => [
                               'filter'  => FILTER_VALIDATE_INT,
                               'default' => get_option( 'posts_per_page' )
                           ],  
    ];  

    $meta = filter_input_array( INPUT_POST, $args );

    if ( !$meta )
        return;

    // Loop throught the array and update meta values
    foreach ( $meta as $k=>$v ) 
        pop_helper_update_post_meta( $post_id, $k, $v );
}   

function pop_helper_update_post_meta( $post_id = '', $key = '', $data="" ) 
{
    // Make sure we have valid values, if not, return false
    if ( !$post_id
         || !$key
    )
        return false;

    // Sanitize and validate values
    $post_id = filter_var( $post_id, FILTER_VALIDATE_INT    );
    $key     = filter_var( $key,     FILTER_SANITIZE_STRING );
    $data    = filter_var( $data,    FILTER_SANITIZE_STRING );

    // Get the  post meta values
    $post_meta = get_post_meta( $post_id, $key, true );

    if(    $data
        && $post_meta != $data
    ) {
        update_post_meta( $post_id, $key, $data );
    } 

    if (    $post_meta 
         && !$data
    ) {
        delete_post_meta( $post_id, $key );
    }
}

Secondly, the page template. You have to call this template page-pop.php

<?php
/**
 * Template Name: Page of Posts
 */
get_header(); ?>

<?php
    //See if we have any values and set defaults in case
    $post_meta   = get_post_meta( get_queried_object_id() );

    $catid       = isset( $post_meta['_cat_id'] )      ? $post_meta['_cat_id'][0]      : 1;
    $page_title  = isset( $post_meta['_page_title'] )  ? $post_meta['_page_title'][0]  : '';
    $posts_title = isset( $post_meta['_posts_title'] ) ? $post_meta['_posts_title'][0] : '';
    $orderby     = isset( $post_meta['_order_by'] )    ? $post_meta['_order_by'][0]    : 'date';
    $asc         = isset( $post_meta['_asc'] )         ? $post_meta['_asc'][0]         : 'DESC';
    $post_count  = isset( $post_meta['_post_count'] )  ? $post_meta['_post_count'][0]  : get_option('posts_per_page');
?>  

<div id="main-content" class="main-content">

    <div id="primary" class="content-area">
        <div id="content" class="site-content" role="main">

    <!-- Page Title -->
    <?php if( $page_title ) { ?>
        <article id="posts-title">
            <header class="entry-header">
                <h2 class="entry-title"><?php echo $page_title; ?></h2>
            </header><!-- .entry-header -->
        </article><!-- #posts-title -->
    <?php } ?>

        <?php the_post(); ?>
        <?php global $post;
        if( $post->post_content || $page_title ) : ?>
        <div class="entry-content">
            <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
                <?php if( $posts_title ) : ?>
                    <header class="entry-header">
                        <h1 class="entry-title"><?php echo $posts_title; ?></h1>
                    </header><!-- .entry-header -->

                <?php endif; ?>
            <?php if( $post->post_content ) : ?>    
                <div class="entry-content">
                    <?php the_content(); ?>
                    <?php wp_link_pages( ['before' => '<div class="page-link"><span>' . __( 'Pages:' ) . '</span>', 'after' => '</div>'] ); ?>
                </div><!-- .entry-content -->
                <footer class="entry-meta">

                </footer><!-- .entry-meta -->
            <?php endif; ?>
            </article><!-- #post-<?php the_ID(); ?> -->
        </div>  
        <?php endif; ?>

<?php 

/**-----------------------------------------------------------------------------
 *
 *  Start our custom query to display category posts
 *
*------------------------------------------------------------------------------*/   

        $args = [
            'cat'                   => $catid,
            'posts_per_page'        => $post_count,
            'paged'                 => $paged,
            'orderby'               => $orderby,
            'order'                 => $asc,
            'ignore_sticky_posts'   => 1,
        ];

        $cat_query = new WP_Query($args);

        // Output
        if ( $cat_query->have_posts() ) {
            // Start the Loop.
            while ( $cat_query->have_posts() ) { 
                $cat_query->the_post(); 

                    get_template_part( 'content', get_post_format() );

            }

            if ( function_exists( 'pietergoosen_pagination' ) )
                pietergoosen_pagination();  

            wp_reset_postdata();

        } else { 

                get_template_part( 'content', 'none' );

        } 
        ?>

    </div><!-- #content -->
    </div><!-- #primary -->

    <?php get_sidebar(); ?>

</div><!-- #main-content -->

<?php
get_footer();

You can now simply create a new page and choose the “page of posts” template, and publish your page. Once that is done, the Page of Posts metabox will appear. From that you can choose the category to display on that page. Hope this helps you