Given this custom post type:
register_post_type(
'sample_post_type',
[
'labels' => [
'name' => _x('Sample Posts', 'post type general name'),
'singular_name' => _x('Sample Post', 'post type singular name'),
],
'public' => true,
'show_in_nav_menus' => false,
'exclude_from_search' => true,
]
);
How can I disable the single post view for this particular post type? Displaying a simple 404 is fine, or redirecting to the homepage. Since this is a plugin, I can’t create a single-sample_post_type.php
file to set up an empty page.
To be able to disable the single view for a CPT you can either redirect users to a specific URL, or disable it while registering CPT itself.
METHOD 1:
Redirect CPT single to a custom URL, archive page is publicly available.
You can use
template_redirect
hook to redirect a user, you can use any URL you want in place ofhome_url()
and the desired error code as 2nd argument.METHOD 2:
Completely disable Single and Archive page from front-end; Works for Custom Post Types only.
An alternative approach is to set
publicly_queryable
to false while registering the custom post.This hides single as well as archive page for the CPT, this can be used for custom posts only.
Even though the archive and single is hidden, you can still add a page template or a custom block to list posts if needed.
Just setting the argument
when you call register_post_type()
Tested all the ones mentioned above and the actual solution is simpler than any redirects suggested.
In order to have archive be accessible and list the items, and single post not be accessible and auto redirect to 404 set
when registering your CPT. If you set
publicly_queryable
to false your archives will be redirected to home, any other combo wont work. Set thequery_var
to false and that is it.Here is full CPT https://gist.github.com/danyj/bfd038d3c8d578548c4d700bd0a7942a
see line 50 https://gist.github.com/danyj/bfd038d3c8d578548c4d700bd0a7942a#file-thz_cpt_items_single_view_redirect-php-L50
as stated here
https://codex.wordpress.org/Function_Reference/register_post_type
A simpler way to do that can be passing the following args when registering the Custom Post Type
One. From your functions file.
Two. From your single.cpt.php file:
Working from of Sven’s really good answer, I rewrote his function to make it easier to add multiple post types using
in_array()
in the if statement and then redirecting to the archive page instead of the home page.(by the way, I think the setting
query_var
and/orpublically_queryable
to false will disable not only the single views, but also the native archive view, overriding'has_archive' => true
. In that case you can still set up a custom WP_query and create your own archive page, in a template, but the main query won’t do that any more, will it?)In case you want to completely disable custom post type single view on frontend but be able to display archive page things are getting a little complicated.
Setting
publicly_queryable
tofalse
orrewrite
tofalse
will prevent for displaying both single and archive view. There is no flag inregister_post_type
function arguments to prevent creating only single view rewrite rules.https://github.com/WordPress/WordPress/blob/5.2.3/wp-includes/class-wp-post-type.php#L540
However you can remove rewrite tag after registering your post type and this will leave archive view rewrite rules untouched but remove only single view rewrite rules.
Another bonus is that from now on you can create simple WordPress pages using event post type permalink structure (
event/simple-page
) which can be helpful in complex websites.Remember to flush rewrite rules after code modification.
In WordPress
5.9.0
a new filter was added which allows not only disabling the single but removing any links to it from the admin screens.The single won’t load but if you enter the URL manually, the home page will load instead of a 404. To show a 404 instead of the home page, you may remove the rewrite rule after the post type is registered.
After making these changes you will need to flush the rewrite rules.
Using these 2 methods will accomplish the goal without extra template, redirects and broken links in the admin.
My current solution (mostly “the redirect solution”) with a slight implementation difference.
This will keep archive pages enabled (
has_archive = TRUE
)But will allow you to enable or disable single pages when using
register_post_type()
withx_has_single = TRUE
(the param is passed along with the post type object properties).