Does Wordpress support an unlimited or large number of custom post types?

I want to build a directory site where the posts would be post types and the directory items would be standard post archive entries.


Does Wordpress support an unlimited or large number of custom post types?

Yes-ish, but that would lead to a WP Admin area that's impractically large. Also, keep in mind it would make the REST API discovery slower due to the larger number of items, as well as making templating more cumbersome due to the larger number of templates.

Keep in mind as well that because post types are registered on every page load, and stored in memory, that if you registered hundreds of post types that would mean a slowdown on every possible type of request WP could handle.

I want to build a directory site where the posts would be post types and the directory items would be standard post archive entries.

Aha, I would strongly advise against this, it's a bad idea, and will cause issues for your with complexity.

You would be better off with a single CPT, and using a custom taxonomy to organise them. Custom post types shouldn't be used to group things, that's what a taxonomy is for. Taxonomies can provide the URLs, archives, templates etc that you'd need for a directory.

As an additional note, it's much easier to list terms in a taxonomy, then to list all the registered post types. Just call get_terms, there are even some helper functions that will give you a formatted list of terms. Terms can have subterms too, so you can add additional hierarchy. Posts can have terms in multiple taxonomies too!

Edit: I decided to run some experiments. Behold! A truly awful plugin:

 * Plugin Name: 200 post types
 * Description: An awful plugin to prove a point

add_action( 'init', 'tomjn_add_post_types' );
function tomjn_add_post_types() {
    for ($i=0; $i < 200; $i++) {

        $labels = array(
            'name'               => _x( 'CPT '.$i, 'post type general name', 'your-plugin-textdomain' ),
            'singular_name'      => _x( 'CPT'.$i, 'post type singular name', 'your-plugin-textdomain' ),
            'menu_name'          => _x( 'CPTs '.$i, 'admin menu', 'your-plugin-textdomain' ),
            'name_admin_bar'     => _x( 'CPT'.$i, 'add new on admin bar', 'your-plugin-textdomain' ),
            'add_new'            => _x( 'Add New', 'cpt'.$i, 'your-plugin-textdomain' ),
            'add_new_item'       => __( 'Add New CPT'.$i, 'your-plugin-textdomain' ),
            'new_item'           => __( 'New CPT'.$i, 'your-plugin-textdomain' ),
            'edit_item'          => __( 'Edit CPT'.$i, 'your-plugin-textdomain' ),
            'view_item'          => __( 'View CPT'.$i, 'your-plugin-textdomain' ),
            'all_items'          => __( 'All CPTs'.$i, 'your-plugin-textdomain' ),
            'search_items'       => __( 'Search CPTs'.$i, 'your-plugin-textdomain' ),
            'parent_item_colon'  => __( 'Parent CPTs:'.$i, 'your-plugin-textdomain' ),
            'not_found'          => __( 'No CPTs found.', 'your-plugin-textdomain' ),
            'not_found_in_trash' => __( 'No CPTs found in Trash.', 'your-plugin-textdomain' )

        $args = array(
            'labels'             => $labels,
            'public'             => true,
            'publicly_queryable' => true,
            'show_ui'            => true,
            'show_in_menu'       => true,
            'query_var'          => true,
            'capability_type'    => 'post',
            'has_archive'        => true,
            'hierarchical'       => false,
            'supports'           => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments' )

        register_post_type( 'cpt'.$i, $args );

This allowed me to modify the number in the for loop to register progressively higher numbers of post types. There's a very real cost to registering post types.

Here is a truncated screenshot of 200:

enter image description here

I had firefox take a fullpage screenshot, and tweeted it, but Twitters image service could not handle the dimensions.

This is on a fast machine with the default theme, and only query monitor activated for timing measurements, on WP 5.2.4.

Of note, the average speed was ~0.1s/0.2s, and with 200 CPTs it rose to 0.4/0.6s. Also note that the admin side menu is completely unusable, and the menu order system has broken down. You will need to account for this, and specify a value when registering the post type.

Clearly this isn't enough, I decided to push it further.

Around 400 CPTs the side menu broke and overflows, at this point the average load time was ~1.6-1.7s, meaning at least a second and a half was added by CPT registration alone.

I bumped it up to 2000 CPTs:

enter image description here

Notice that pages now take on average 10 seconds to load. Memory consumption has also skyrocketed to 30MB

I bumped the number up to 20k, and the site failed to load. I reduced this to 10k, then 5k, and finally the site came back at 4k CPTs

In order to get the permalinks settings page to load, I had to go down to 2k CPTs. At this point the page took 13 seconds to load, and the resulting admin page was 12.7MB to transfer, most of which was side menu markup

  • Thanks. Do you have any better idea for creating a directory site using native Wordpress functionality only? I mean no directory themes, no plugins, only cooking it with native Wordpress functionality. I am also confused a bit about the query: if i use the scenario you recommended (single CPT, custom taxonomy), when I query the archive to display per post, must the archive category title match the post title in order for WP Query to match the right archive to the right post? Or is it the ID's that must match? I know WP Query seeks for several matchings, so I don't even need a custom query? – Mobil Home Oct 25 at 20:20
  • And if we digged into this so far, I'll still ask: if you build a wp directory like this, what's the best way to make sure that Google and anything else will not index the posts the archive entries are pointing to? Because I don't want them on display ever. Only the archive entries. – Mobil Home Oct 25 at 20:37
  • Eh better to ask a new question, Google doesn't care how it got implemented as it never sees the internal details. For that you'll need to refer to SEO circles, particularly stuff like nofollow/no referrers/no index, etc, which aren't related to post types/archives/site/taxonomies/etc – Tom J Nowell Oct 25 at 20:53
  • As for your question about querying the archive, I honestly have no idea what you're referring to there. The problem with "directory" questions is that everybody has their own set of terms and terminology that they understand but mean different things, so I don't understand. But I can tell you, you have no business using WP_Query, just use the archive URLs that WP gives you for free. CPT's and taxonomy automatically create a set of archives and templates, there's no need to use WP_Query or page templates – Tom J Nowell Oct 25 at 20:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.