0

My Situation :

I have a custom post type in my theme, called article.

My website has a dozen of categories, which i publish my posts in, and 1 specific category (named BLOG) just to publish article in it (has no post in it, only article).

My articles have different structure, so i can't show them in the same list that I show normal posts in archives. So, i decided to show articles only in BLOG category, and the normal posts in the rest of the categories.

This is the normal loop i have in my archives.php:

if ( have_posts() ) {
    while ( have_posts() ) {
        the_post(); 
        the_title();
    }
}

And this goes in my theme's functions.php:

function archive_filtering($query){
    if ( $query->is_main_query() && $query->have_posts()){
        $query->set('post_type', 'article' );
    }
}

My Problem :

I expect the above code to check to see if there is a post in this category, if there is no posts in it, then we might be in BLOG category. So, it should include the article post type in the query and then output it.

But it doesn't seem to work. Is this the proper approach? Is there any way to do this?

Thanks!

11
  • Have you tried re-saving the permalink structure? This looks like one of those times...
    – Dan.
    May 17, 2017 at 15:21
  • @Dan. Yes, unfortunately flushing the permalink and tweaking with register_post_type parameters doesn't work for me.
    – Johansson
    May 17, 2017 at 15:23
  • :(... Try setting the blog posts per page setting (in Settings->Reading) to 1 and then see if that works. If that works, then I think you need to specify the posts_per_page parameter in the WP_Query args for the custom post type part..
    – Dan.
    May 17, 2017 at 15:26
  • Nope... no success either. My blog has more than 10 posts and the post per page is set to 4.
    – Johansson
    May 17, 2017 at 15:40
  • 404s have nothing to do with the contents of template files, your archive template never gets loaded on a 404. WordPress determines if it's a 404 based on the results of the main query- the main query has no page 2.
    – Milo
    May 17, 2017 at 21:37

2 Answers 2

3

The reason your code isn't working is because by the time archive.php runs, the pre_get_posts hook has already fired.

You can easily accomplish the task in your functions.php file:

add_action( 'pre_get_posts', 'wpse_pre_get_posts' );
function wpse_pre_get_posts( $query ) {
  remove_action( 'pre_get_posts', 'wpse_pre_get_posts' );
  //* $query->have_posts() will always return false from this hook
  //* So get the posts with the query to check if they're empty
  $posts = get_posts( $query->query );
  if( empty( $posts ) && $query->is_main_query() ) {
    $query->set( 'post_type', 'article' );
  }
}

And then your archive.php would be a simple loop:

if( have_posts() ) :
  while( have_posts() ) :
    the_post(); 
    the_title();
  endwhile;
endif;

This will run the query twice per request, which I wouldn't do, but offhand I can't see another way to do what you want.

Thanks @Milo. Edited because at the pre_get_posts hook, the query hasn't run yet. Duh.

6
  • Thanks. That was the first thing i tried, and it didn't work. That's why i'm confused.
    – Johansson
    May 18, 2017 at 16:34
  • 2
    You can't know if the query has posts before making the query.
    – Milo
    May 18, 2017 at 16:39
  • @Milo So, How to achieve this? You mentioned that we can't alter the query this way, but didn't provide any solution (Please accept my apologies, i don't mean to be rude in ANY way.). If i use it in archive.php, the query has already been run. If i use it in functions.php, the query hasn't run yet. Seems like being stuck to me.
    – Johansson
    May 18, 2017 at 16:41
  • @JackJohansson I'm just not getting what "this" is. You want to paginate all the posts until there are no posts, then you want to show just articles on subsequent pages? It all just seems weird and unintuitive.
    – Milo
    May 18, 2017 at 16:48
  • @Milo My original problem is that i have to have pagination on this. If you take a look at my original question (before first edit) you will see a custom loop that does 'this' for me, but can't have pagination on it. Now Wp-PageNavi offers pagination on custom queries, but i also need a basic pagination in case the customer doesn't want to install wp-pagenavi. If you give me 2 minutes of your time, i can explain it to you in chat.
    – Johansson
    May 18, 2017 at 16:50
2

The problem in your scenario is that you can't know what changes need to be made to the query until after the query runs. Of course, after it runs, it's too late to make the changes!

You mentioned that you don't know what that single category all the articles are in might be. Well, the simplest way to solve this is to change that. You need some way to store that choice, so you can check if that's the category currently being requested, and make adjustments before the query is run.

add_action( 'pre_get_posts', 'wpd_check_cat' );
function wpd_check_cat( $query ) {
    if( $query->is_category()
        && isset( $query->query_vars['category_name'] )
        && 'blog' == $query->query_vars['category_name'] ){
            $query->set( 'post_type', 'article' );
        }
}
4
  • Thank you Milo, but the other answer seems to work for now. Is there any reason not to use the answer provided by @Nathan?
    – Johansson
    May 18, 2017 at 17:33
  • I thought maybe it would result in an extra query, but I'm actually not sure now, since WordPress is usually pretty smart about caching queries.
    – Milo
    May 18, 2017 at 17:35
  • I appreciate your interest in this question in the past 2 days, but i could use a is_category('blog') myself if i knew the category's name. Thank you both.
    – Johansson
    May 18, 2017 at 17:39
  • 1
    Yeah, it looks like WP grabs the taxonomy object first, so $query->is_category('blog') seems to work.
    – Milo
    May 18, 2017 at 18:06

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.