We’re going to create a more easy to manage the way of generating multiple Custom Post Types.

First of all, we’re going to create a file that we’ll call it post-types.php and place it in a folder inside your theme called ‘config’.

In post-types.php we’ll create a class that generates Custom Post Types. I’ll call it DM_Project_Post_Types.

<?php
class DM_Project_Post_Types {


} // End class

new DM_Project_Post_Types;

In here we create 3 fuctions: a __construct, one to define the custom post types and one that will register them.

<?php
class DM_Project_Post_Types {

    public function __construct() {
        
    }

    public function all_post_types() {
     
    }

    private function dm_register_post_type() {

    }


} // End class

new DM_Project_Post_Types;

In the all_post_types function we define all the custom post types that we want to use and will pass that data into the dm_register_post_types.

    public function all_post_types() {
        $post_types = [
            [
                'post_type' => 'director',
                'singular'  => 'Director',
                'slug'      => 'director',
            ],
            [
                'post_type' => 'photographer',
                'singular'  => 'Photographer',
                'slug'      => 'photographer',
            ],


        ];

        foreach ($post_types as $key => $post_type) {
            $this -> dm_register_post_type( $post_type );
        }
    }

If you need to add custom data for ‘plural’ or other arguments, you can add them in the all_post_types function and pass them in dm_register_post_type to be used.

And the dm_register_post_type will look like this

    private function dm_register_post_type( $data ) {

        $singular  = $data['singular'];
        $plural    = ( isset( $data['plural'] ) ) ? $data['plural'] : $data['singular'] . 's';
        $post_type = $data['post_type'];
        $slug      = $data['slug'];

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

        $args = array(
            'labels'             => $labels,
            'description'        => __( $singular .'.', 'dm-artillerie-theme' ),
            'public'             => true,
            'publicly_queryable' => true,
            'show_ui'            => true,
            'show_in_menu'       => true,
            'query_var'          => true,
            'rewrite'            => array( 'slug' => $slug ),
            'capability_type'    => 'post',
            'has_archive'        => false,
            'hierarchical'       => false,
            'menu_position'      => null,
            'supports'           => array( 'title', 'author', 'editor', 'thumbnail', 'excerpt', 'comments' )
        );

        register_post_type( $post_type, $args );

    }

By default I added a $plural variable that will just add an ‘s’ at the end of the custom post type single in case you don’t define a plural in all_post_types.

If you want to do a small adjustment you can also define a variable from ‘textdomain’. In my case that is ‘dm-artillerie-theme’ and it’s hardcoded in there.

Now in the __construct we make sure to init the all_post_types function

    public function __construct() {
        add_action( 'init', array( $this, 'all_post_types' ) );
    }

Your final code in the post-types.php file should look like this:

<?php
class DM_Project_Post_Types {

    public function __construct() {
        add_action( 'init', array( $this, 'all_post_types' ) );
    }

    public function all_post_types() {
        $post_types = [
            [
                'post_type' => 'director',
                'singular'  => 'Director',
                'slug'      => 'director',
            ],
            [
                'post_type' => 'photographer',
                'singular'  => 'Photographer',
                'slug'      => 'photographer',
            ],


        ];

        foreach ($post_types as $key => $post_type) {
            $this -> dm_register_post_type( $post_type );
        }
    }

    private function dm_register_post_type( $data ) {

        $singular  = $data['singular'];
        $plural    = ( isset( $data['plural'] ) ) ? $data['plural'] : $data['singular'] . 's';
        $post_type = $data['post_type'];
        $slug      = $data['slug'];

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

        $args = array(
            'labels'             => $labels,
            'description'        => __( $singular .'.', 'dm-artillerie-theme' ),
            'public'             => true,
            'publicly_queryable' => true,
            'show_ui'            => true,
            'show_in_menu'       => true,
            'query_var'          => true,
            'rewrite'            => array( 'slug' => $slug ),
            'capability_type'    => 'post',
            'has_archive'        => false,
            'hierarchical'       => false,
            'menu_position'      => null,
            'supports'           => array( 'title', 'author', 'editor', 'thumbnail', 'excerpt', 'comments' )
        );

        register_post_type( $post_type, $args );

    }


} // End class

new DM_Project_Post_Types;

Now in functions.php add the PHP file that you just worked on:

require_once('config/post-types.php');

You will be able to generate as many custom post types you want and control the aspect of each of them without repeating the code. You also endup with a clean functions.php file and it will be easier to read in the future.

You can use this approach on other customizations that you’re doing on the site, creating a separate PHP file and call them from inside functions.php.

You can find a similar article on how to create multiple Custom Taxonomies with the same approach.