Custom Post Loop in Archive returns same the_permalink

This is an extention to your answer. Your pre_get_posts action has a few flaws

function add_custom_types_to_tax( $query ) {
  if( is_category() || is_tag() && empty( $query->query_vars['suppress_filters'] ) ) {
    // Get all your post types
    $post_types = get_post_types();

    $query->set( 'post_type', $post_types );
    return $query;
  }
}
add_filter( 'pre_get_posts', 'add_custom_types_to_tax' );
  • is_category() and is_tag() should be properties to $query

  • There is not real benefit in checking whether suppress_filters is true or false. The main query is always set to to true unless set otherwise by pre_get_posts

  • pre_get_posts is an action, not a filter

  • Actions do not need to be returned.

  • pre_get_posts alters all instances of WP_Query ( the main query also uses WP_Query), front end and backend. You should always use is_main_query() to target the main query only, and also use !is_admin() to only target the front end ( this check is not necessary on the home page )

Your code should look something like this

function add_custom_types_to_tax( $query ) {
  if( !is_admin() && $query->is_main_query() ) {
    if ( $query->is_category() || $query->is_tag() ) {
    // Get all your post types
    $post_types = get_post_types();

    $query->set( 'post_type', $post_types );
    }
  }
}
add_action( 'pre_get_posts', 'add_custom_types_to_tax' );

This should solve your issue without any further code needed

ADDITIONAL NOTES:

  • get_post_types() in the current state you are using it, it returns all registered post types including revisions and nav menu items. You would want to look at build_in parameter to exclude all build in types and just return custom post types.

  • For non paginated custom queries, use get_posts or add the following two parameters to WP_Query

    • 'suppress_filters' => true This will inhibit all filters from altering your custom query.

    • no_found_rows' => true' This will get the desired amount of posts and immediatly bail out. Default behavior of WP_Query is to look for all posts matching the query in order to count the posts for pagination purposes. This wastes time. Setting no_found_rows to true, WP_Query skips this process. If it hit the desired amount of posts, it immediately stops execution of the query and returns the posts. This saves execution time, making the query faster.

(NOTE: get_posts() uses WP_Query with these two parameters already set accordingly. That is why get_posts cannot be sanely paged and why get_posts is not altered by filters)

Leave a Comment