WordPress Development

Getting Started with WordPress Custom Post Types

WordPress ships with Posts and Pages, but most real-world projects demand something more: portfolios, products, events, testimonials. That is exactly what Custom Post Types (CPTs) solve — and since WordPress 3.0 introduced register_post_type(), they have been the backbone of serious WordPress development.

Registering a Custom Post Type

All you need is a call to register_post_type() inside a function hooked to init. The example below creates a Portfolio CPT:

function my_register_portfolio_cpt() {
    $args = array(
        'label'               => __( 'Portfolio', 'mytheme' ),
        'public'              => true,
        'has_archive'         => true,
        'supports'            => array( 'title', 'editor', 'thumbnail' ),
        'rewrite'             => array( 'slug' => 'portfolio' ),
        'menu_icon'           => 'dashicons-portfolio',
    );
    register_post_type( 'portfolio', $args );
}
add_action( 'init', 'my_register_portfolio_cpt' );

Once registered, WordPress automatically creates admin-menu entries, archive and single template hooks, and includes the CPT in queries when public is true.

Adding Custom Meta Boxes

CPTs rarely travel alone — they carry extra data. Before Advanced Custom Fields became ubiquitous, developers wrote meta boxes by hand using add_meta_box() and save_post. This approach gives you complete control over sanitisation and output:

add_action( 'add_meta_boxes', function() {
    add_meta_box( 'portfolio_url', 'Project URL', 'portfolio_url_cb', 'portfolio' );
} );

function portfolio_url_cb( $post ) {
    $url = get_post_meta( $post->ID, '_portfolio_url', true );
    echo '<input type="url" name="portfolio_url" value="' . esc_attr( $url ) . '">';
}

add_action( 'save_post_portfolio', function( $post_id ) {
    if ( isset( $_POST['portfolio_url'] ) ) {
        update_post_meta( $post_id, '_portfolio_url', esc_url_raw( $_POST['portfolio_url'] ) );
    }
} );

Displaying CPT Content

WordPress follows the Template Hierarchy for CPTs. Create archive-portfolio.php for the listing page and single-portfolio.php for individual entries. Use WP_Query to fetch CPT posts anywhere on the site:

$projects = new WP_Query( array(
    'post_type'      => 'portfolio',
    'posts_per_page' => 6,
    'post_status'    => 'publish',
) );

Taxonomies

Pair your CPT with a custom taxonomy via register_taxonomy() — for example a Project Type taxonomy linked to Portfolio. This gives editors a familiar category-like interface and keeps your query logic clean.

Custom Post Types are the foundation of scalable WordPress development. Master them now and the rest of the WordPress CMS landscape opens up.

Share this post:
Copied!

Leave a Comment

Your email will not be published.

READY TO BUILD?

Let's Build Something
Amazing Together

Tell us about your project. We'll have a proposal in your inbox within 24 hours.

Free Consultation
NDA Available
Fixed-price Options
Dedicated PM