I am looking for the best way to create custom post-types which are only used as an archive for their posts. As an example I want an archive showing all employees of a company, but I don't want the employees to have a singular page. This is a use-case that I stumbled upon various times, but never found the perfect solution.

The main requirements are:

  • disable the singular view of posts;
  • be able to use archive.php of the theme as the archive page;
  • remove links to the singular view from WordPress.

All methods that I've found are not able to tick all the requirements above.

By setting a filter with a template_redirect for the single page, the links to the singular pages are still being shown in WordPress (and probably in sitemaps and such), which is confusing for the end-user.

By setting publicly_queryable to false the links in the back-end are removed, but so is the archive page, even though has_archive is set to true. This can be solved by creating a page with a page template that loads the posts from the post-type. But that's not ideal either.

  • Try this one: wordpress.stackexchange.com/a/319465/60844 Commented Oct 2, 2021 at 4:01
  • 1
    @TonyDjukic Yes, I tried this one before and it mostly solves the problem. The only thing is that WordPress is still showing the 'view' buttons in the post-type overview. Also slugs are still registered for the posts, which is unneeded but that's not a real problem for me.
    – ProxxiM
    Commented Oct 4, 2021 at 8:51
  • The solution found here: wordpress.stackexchange.com/a/403951/14064 met the above requirements. Other "correct" solutions set the query_vars value to false but as of this comment this no longer works.
    – Gazillion
    Commented Aug 11, 2023 at 14:58

1 Answer 1


I've 'fixed' my problem with the code below. This is a function that checks the post-type settings. If query_var has been set to false, the view button is removed from the post-type archive in the back-end.

For my use-case, this solves the problem. There are no links to the posts anymore.

The reason why both post_row_actions and page_row_actions is being used, is because post-types with hierarchical set to false are running through the first one, otherwise trough the second one.

function modify_list_row_actions( $actions, $post ) {
    // Retrieve the post-type object
    $post_type_object = get_post_type_object(get_post_type($post));

    // check if query_var has been set to 'false'
    if ($post_type_object->query_var == false) {
        // if so, removing the 'view' link

    return $actions;
add_filter( 'post_row_actions', 'modify_list_row_actions', 10, 2);
add_filter( 'page_row_actions', 'modify_list_row_actions', 10, 2);

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.