I've created new page in WP administration called Blog and created custom page template for it. In the template, I have a simple paged custom query.

$query = new WP_Query(array( 'post_type' => 'post', 'posts_per_page' => 1, 
'paged' => $paged ));

Everything seems to look ok, except when I manually type bigger page number than is available after the '/page/' part of url. The page won't throw a 404 error but will render the page as normal without the custom loop. Is it normal behaviour? If so, how should I throw the 404 template page?

Also, I have one sub question:

Is it possible, to create custom theme page, without the need to create the page in the wordpress adminstration? In most cases I don't even use the content of the page and leave it empty. Then if someone will delete the page, or change the page slug, part of website can be broken.

Is there more fool proof and more administrator friendly solution?

PS: here is the full page-blog.php source code:

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

        <h1><?=get_theme_mod('crochelou-blog-main-headline') ?><span class="sub-headline"><?=get_theme_mod('crochelou-blog-sub-headline') ?></span></h1>
        <section id="page-container">
        <nav id="blog-nav-wrapper"><?php
            wp_nav_menu( array(
                'menu_id'        => 'category-menu',
                'menu' => 'category-menu'
            ) );

            $query = new WP_Query(array( 'post_type' => 'post', 'posts_per_page' => 1, 'paged' => $paged )); ?>

            <section id="main-blog-loop"><?php
                if($paged > 1){ ?>
                    <a href="<?= get_pagenum_link($paged - 1) ?>" class="pagination-arrow arrow left arrow-left prev"></a>
                <?php }

                ?><div class="wrapper articles">
                    while($query->have_posts()): $query->the_post(); ?>

                    <article class="crochelou-card blog">
                        <div class="blog image" style="background-image: url('<?=esc_url(the_post_thumbnail_url('medium'))  ?>')"></div>
                        <div class="categories"><?php
                            $categories = get_the_category();
                             foreach($categories as $category){ 
                                 $name = $category->name;
                                 $link = get_category_link($category->term_id); ?>
                                 <a href="<?= $link ?>" class="catgory"><?= $name ?></a>
                        <span class="date"><?= get_the_date('d') . '\\' . get_the_date('m') . '\\' . get_the_date('Y') ?></span>
                        <h4 class="headline blog"><a href="<?= get_the_permalink() ?>"><?= get_the_title() ?></a></h4>
                        <div class="perex excerpt"><?php the_excerpt(); ?></div>
                        <a class="link read-more" href="<?= get_the_permalink() ?>" >číst..</a>

                    <?php endwhile;
                if($paged < $query->max_num_pages){ ?>
                    <a href="<?= get_pagenum_link($paged + 1) ?>" class="pagination-arrow arrow right arrow-right right"></a>
                <?php }


                <?php if($paged < $query->max_num_pages){  ?>
                    <div id="blog-pagination">
                        <nav class="pagination">
                                for($i=1; $i <= $query->max_num_pages; $i++){

                                    if($i === $paged){ ?>

                                    <span class="current"><?= $i ?><?php if($i < $query->max_num_pages){ echo ','; } ?></span>

                                    <?php }else{ ?>

                                    <a href="<?= get_pagenum_link($i) ?>"><?= $i ?><?php if($i < $query->max_num_pages){ echo ','; } ?></a>

                                    <?php }

               <?php     }       

            <div class="separator"></div>
            <?php $page = get_page_by_path( 'o-mne' ); ?>
            <article id="about">
                <h3 class="title"><?= $page->post_title ?></h3>
                $content = $page->post_content;
                $content = apply_filters('the_content', $content);
                $content = str_replace(']]>', ']]&gt;', $content);
                <div id="about-content"><?= $content ?></div>

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

1 Answer 1


You won't get a 404 because WP can find the page, and it then delegates the request to the template file where you added your own logic.

You could build your own 404 handling in that file, but a better way is to use a the archive.php (or archive-post.php for just this post type) to render the output, and use the pre_get_posts action to manipulate the WP_Query that is used to find posts (customize page size). If you're doing it that way, you'll find that WP will trigger a 404 correctly if the requested page is greater than the last available page.

  • Thank you for your answer. But using archive.php I still have to request the archive by author, category, post-type, custom taxonomy, date or tag. Don't I? That will make link to this archive less pretty, if not anything else. To use archive-post.php, I tried to request the link for tak archive using get_post_type_archive_link('post') and it returns me link to the homepage. I already use that page. I have woocommerce and blog on one domain, so homepage acts as gateway to the blog and eshop. Dec 23, 2017 at 21:04
  • Using pre_get_posts, you can filter the posts by whatever criteria you like. To build pretty URLs, use WP's rewrite rules.
    – janh
    Dec 23, 2017 at 21:19

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.