0

I have created a custom post type called news

Here is the code

function create_post_type_news() {

$supports = array(
'title', // post title
'editor', // post content
'author', // post author
'thumbnail', // featured images
'excerpt', // post excerpt
'custom-fields', // custom fields
'comments', // post comments
'revisions', // post revisions
'post-formats', // post formats
);
 
$labels = array(
'name' => _x('News', 'plural'),
'singular_name' => _x('News', 'singular'),
'menu_name' => _x('News', 'admin menu'),
'name_admin_bar' => _x('News', 'admin bar'),
'add_new' => _x('Add New', 'add new'),
'add_new_item' => __('Add New News'),
'new_item' => __('New News'),
'edit_item' => __('Edit News'),
'view_item' => __('View News'),
'all_items' => __('All News'),
'search_items' => __('Search News'),
'not_found' => __('No News found.'),
);
 
$args = array(
'supports' => $supports,
'labels' => $labels,
'description' => 'Holds our News and specific data',
'public' => true,
'taxonomies' => array( 'category', 'post_tag' ),
'show_ui' => true,
'show_in_menu' => true,
'show_in_nav_menus' => true,
'show_in_admin_bar' => true,
'can_export' => true,
'capability_type' => 'post',
'show_in_rest' => true,
'query_var' => true,
'rewrite' => array('slug' => 'news'), 
'has_archive' => true,
'hierarchical' => false,
'menu_position' => 6,
'menu_icon' => 'dashicons-megaphone',
);
 
register_post_type('news', $args); // Register Post type
}
add_action('init', 'create_post_type_news');

I have shown this news in my index.php like this

<div class="row">
    <?php 
    $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1; // Get the current page number
    $args = array( 
        'posts_per_page' => 4, // Number of posts per page
        'post_type' => 'news', 
        'orderby' => 'date', 
        'order' => 'DESC',
        'paged' => $paged // Use the current page number
    );
    $news_query = new WP_Query( $args ); // Create a new query
    if ( $news_query->have_posts() ) : ?>
        <?php while ( $news_query->have_posts() ) : $news_query->the_post(); ?>
            
           MY HTML CONTENT 

        <?php endwhile; ?>
        <!-- Pagination -->
        <div class="pagination">
            <?php echo paginate_links( array( 'total' => $news_query->max_num_pages ) ); ?>
        </div>
        <?php wp_reset_postdata(); ?>
    <?php endif; ?>
</div>

But the problem is in homepage. pagination ui is comeing perfectly. but when i click on page 2 it's showing page not found. This is my sample url of page 2 http://localhost/tr/page/2/

I haven't created anypage called home or index from dashboard/pages. I am using index.php as my home page http://localhost/tr this is my home page.

This problem is making me crazy. Thank you.

2
  • 1
    pagination operates on the main query, and it's the main query that determines if it's a 404 or not. If there is no page 2 for the homepage then it will 404, even if your custom query has multiple pages. If you want to change the main query, use pre_get_posts filter to change its options, don't create a brand new query with WP_Query/get_posts/query_posts. Also note that index.php is not the homepage template, it's the fallback template for all pages. Use home.php or frontpage.php instead
    – Tom J Nowell
    Commented Feb 26 at 14:24
  • Thanks for your answer. Can you give me some code snippets. I am very new to wordpress and couldn't understand what you just said. @TomJNowell
    – Vivek Saha
    Commented Feb 26 at 14:28

1 Answer 1

4

You registered your post type correctly, the problem is a common pitfall many new WordPress developers fall into, you created a second new query to change the posts WP displays, rather than modifying the original.

Why It's Broken

A lot of people don't understand the main query and think that if they want to change what gets displayed on a page, that they should create a new query and tell it what they want using WP_Query/get_posts/query_posts. This might be to change the number of posts or to pull in different posts, or filter to a category or tag, etc.

AKA this part of your code:

    $news_query = new WP_Query( $args ); // Create a new query
    if ( $news_query->have_posts() ) : ?>
        <?php while ( $news_query->have_posts() ) : $news_query->the_post(); ?>         

But this is a trap! You've just doubled the amount of work WordPress needs to do slowing things down, and the main query is still there loading the same posts it did before you made the change.

So if you ignore that main query WP generates, and don't use a standard main loop but create your own, you now have a problem, the pagination is broken and it always shows the first page of results. That's what this is trying to patch over:

    $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1; // Get the current page number
....
        'paged' => $paged // Use the current page number
...
            <?php echo paginate_links( array( 'total' => $news_query->max_num_pages ) ); ?>

This is a lot of messy complicated code to fix things. Except if the homepage only has 3 pages of posts, but your new custom query has 4, what happens when you try to load page 4? It 404's because there is no page 4.

How Do I Fix It?

First get rid of the second new custom query in your template. Your loop should look more like this:

<div class="row">
    <?php 
    if ( have_posts() ) :
        while ( have_posts() ) : the_post(); ?>
            
           MY HTML CONTENT 

        <?php endwhile; ?>
        <div class="pagination">
            <?php echo paginate_links(); ?>
        </div>
    <?php endif; ?>
</div>

Notice the loop has no WP_Query and it uses have_posts/the_post without any extra stuff. There's also no complicated pagination code.

Changing What Gets Shown On The Homepage Correctly/Safely

To change what gets shown in the main query, don't create a new query, use pre_get_posts, for example this filter changes the main query on the homepage so it has a maximum of 3 posts per page:

function only_3_posts_on_homepage( \WP_Query $query ) {
    if ( $query->is_home() && $query->is_main_query() ) {
        $query->set( 'posts_per_page', 3 );
    }
}
add_action( 'pre_get_posts', 'only_3_posts_on_homepage' );

Now on all pages where is_home() is true the number of posts per page is changed to 3. You can use $query->set( to change any of the other options WP_Query accepts, such as the post_type or order.

This method is both faster, safer, and easier to type.

Further reading:

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.