Creating a custom post type in WordPress: A comprehensive guide with PHP examples

Marc Wag­ner

Sep­tem­ber 5, 2024

4 min read|

Word­Press is known for its fle­xi­bi­li­ty and expan­da­bili­ty. Crea­ting a cus­tom post type is also part of this fle­xi­bi­li­ty. The­se allow you to crea­te spe­ci­fic con­tent in addi­ti­on to the stan­dard con­tent such as posts and pages. For exam­p­le, if you are crea­ting a web­site for movies, you can crea­te a cus­tom post type for movies that is dif­fe­rent from nor­mal blog posts.

In this blog artic­le, we’ll show you how to crea­te a cus­tom post type in Word­Press using PHP, how to regis­ter it and what you need to pay atten­ti­on to.

What is a custom post type? #

By default, Word­Press uses dif­fe­rent post types such as posts (post), pages (page) and media (attachment). With Cus­tom Post Types, you can extend this list to mana­ge cus­tom con­tent, such as port­fo­li­os, pro­ducts, recipes or events.

Creating a custom post type in WordPress #

Prerequisites

Befo­re we start, make sure that you:

  • have access to the functions.php file of your the­me or use a cus­tom plug­in.
  • Has basic know­ledge of PHP and Word­Press.

Step 1: Register custom post type

To crea­te a cus­tom post type, use the Word­Press func­tion register_post_type(). This func­tion regis­ters the new post type and allows you to defi­ne para­me­ters such as name, dis­play and func­tion­a­li­ty.

PHP example: Custom Post Type “Movies”

Here is an exam­p­le of how to crea­te a cus­tom post type for movies:

// Custom Post Type für Filme registrieren
function cpt_filme() {

    $labels = array(
        'name'               => _x( 'Filme', 'post type general name', 'textdomain' ),
        'singular_name'      => _x( 'Film', 'post type singular name', 'textdomain' ),
        'menu_name'          => _x( 'Filme', 'admin menu', 'textdomain' ),
        'name_admin_bar'     => _x( 'Film', 'add new on admin bar', 'textdomain' ),
        'add_new'            => _x( 'Neuen Film hinzufügen', 'Film', 'textdomain' ),
        'add_new_item'       => __( 'Neuen Film hinzufügen', 'textdomain' ),
        'new_item'           => __( 'Neuer Film', 'textdomain' ),
        'edit_item'          => __( 'Film bearbeiten', 'textdomain' ),
        'view_item'          => __( 'Film ansehen', 'textdomain' ),
        'all_items'          => __( 'Alle Filme', 'textdomain' ),
        'search_items'       => __( 'Filme durchsuchen', 'textdomain' ),
        'not_found'          => __( 'Keine Filme gefunden', 'textdomain' ),
        'not_found_in_trash' => __( 'Keine Filme im Papierkorb gefunden', 'textdomain' )
    );

    $args = array(
        'labels'             => $labels,
        'public'             => true,
        'publicly_queryable' => true,
        'show_ui'            => true,
        'show_in_menu'       => true,
        'query_var'          => true,
        'rewrite'            => array( 'slug' => 'filme' ),
        'capability_type'    => 'post',
        'has_archive'        => true,
        'hierarchical'       => false,
        'menu_position'      => 5,
        'supports'           => array( 'title', 'editor', 'excerpt', 'thumbnail', 'comments' ),
    );

    register_post_type( 'filme', $args );
}

add_action( 'init', 'cpt_filme' );

Explanation of the code

  1. Labels: Here you defi­ne the labels that are dis­play­ed in the backend, e.g. in the admin navi­ga­ti­on or when crea­ting a new post.
    • nameGene­ral name for the enti­re post type group.
    • singular_name: Sin­gu­lar name used in the user inter­face.
    • add_newName of the but­ton for adding new con­tent.
  2. Args: The­se are the argu­ments that deter­mi­ne how the cus­tom post type works.
    • public: Indi­ca­tes whe­ther the post type is publicly acces­si­ble.
    • publicly_queryable: Makes the post type addressa­ble via the URL.
    • rewrite: Deter­mi­nes the URL slug (in this case “fil­me”).
    • supportsDefi­nes the default edi­tor opti­ons that are sup­port­ed for the post type (e.g. title, edi­tor, thumb­nail, etc.).
  3. register_post_type(): This func­tion regis­ters the post type in Word­Press.
  4. add_action(‘init’, ‘cpt_filme’): The post type is regis­tered when Word­Press is initia­li­zed.

Step 2: Make the custom post type visible in the admin area

Once you have crea­ted the post type, it should be visi­ble in the menu in the Word­Press dash­board. The­re you can add and mana­ge new “movies”, simi­lar to nor­mal posts.

Step 3: Customize archive pages and templates

To con­trol the archi­ve pages or indi­vi­du­al views of your cus­tom post type, you can crea­te spe­cial tem­p­la­te files in your the­me:

  • archive-filme.phpThis file con­trols the dis­play of the archi­ve page of the cus­tom post type.
  • single-filme.phpThis file con­trols the dis­play of indi­vi­du­al posts of your cus­tom post type.

If the­se files are not available, Word­Press uses the stan­dard tem­pla­tes archive.php and single.php.

Bonus: Add taxonomies

To fur­ther enhan­ce your cus­tom post type, you can also add cus­tom taxo­no­mies (simi­lar to cate­go­ries and tags):

function create_filme_taxonomy() {
    register_taxonomy(
        'genre',
        'filme',
        array(
            'label' => __( 'Genre' ),
            'rewrite' => array( 'slug' => 'genre' ),
            'hierarchical' => true, // ähnlich wie Kategorien
        )
    );
}

add_action( 'init', 'create_filme_taxonomy' );

Conclusion #

With cus­tom post types, you can cus­to­mi­ze Word­Press to work for any type of web­site — be it a port­fo­lio web­site, a blog, an online store or a movie site. The code abo­ve gives you the tools to crea­te and cus­to­mi­ze your own post types.

If you need even more func­tion­a­li­ty, you can use plug­ins like “Cus­tom Post Type UI” to fur­ther sim­pli­fy the pro­cess. But with a litt­le PHP know­ledge, you can use register_post_type() to crea­te your own post types accor­ding to your needs.

Have fun crea­ting your own cus­tom post type in Word­Press!

88e86fcb816eff22bc917094df2862d8dd5c0e978b333e6dd5f36f808990c261 96

Arti­kel von:

Marc Wag­ner

Hi Marc here. I’m the foun­der of Forge12 Inter­ac­ti­ve and have been pas­sio­na­te about buil­ding web­sites, online stores, appli­ca­ti­ons and SaaS solu­ti­ons for busi­nesses for over 20 years. Befo­re foun­ding the com­pa­ny, I alre­a­dy work­ed in publicly lis­ted com­pa­nies and acqui­red all kinds of know­ledge. Now I want to pass this know­ledge on to my cus­to­mers.

Hast du eine Fra­ge? Hin­ter­lass bit­te einen Kom­men­tar