Custom Post Types in WordPress

Define a Custom Post Type

Always attach register_post_type() to the init hook.

add_action( 'init', 'ww_create_posttype' );
function ww_create_posttype()
{
    register_post_type( 'ww_portfolio', array( // The unique post type ID, should be prefixed.
        'labels' => array( // UI labels for screens, links, buttons and page titles in the admin.
            'name' =>                __( 'Portfolio' ),
            'singular_name' =>       __( 'Portfolio' ),
            'add_new' =>             __( 'Add New Portfolio Project' ),
            'add_new_item' =>        __( 'Add New Portfolio Project' ),
            'edit_item' =>           __( 'Edit Portfolio Project' ),
            'view_item' =>           __( 'View Portfolio Project' ),
    	    'new_item' =>            __( 'New Portfolio Project' ),
    	    'all_items' =>           __( 'All Portfolio Projects' ),
    	    'view_item' =>           __( 'View Portfolio Project' ),
    	    'search_items' =>        __( 'Search Portfolio Projects' ),
    	    'not_found' =>           __( 'No Portfolio Projects Found' ),
    	    'not_found_in_trash' =>  __( 'No Portfolio Projects found in Trash' ), 
    	    'parent_item_colon' =>   __( '' ),
    	    'menu_name' =>           __( 'Portfolio Projects' ),
        ),
        'supports' => array(
            'title',            // The main title of the post.
            'editor',           // Content of the post.
            'author',           // 
            'thumbnail',        // Featured image, current theme must also support post-thumbnails
            'excerpt',
            'trackbacks',
            'custom-fields',
            'comments',         // Also will see comment count balloon on edit screen
            'revisions',        // Will store revisions.
            'page-attributes',  // Menu order, hierarchical must be true to show Parent option.
            'post-formats',     // Add post formats
        ),
        'public' => true,
        'has_archive' => true,  // Allow archive pages for this post type.
	'taxonomies' => array( 'post_tag', 'category' ), // Assign taxonomies to use with this post type.
        'rewrite' => array( 'slug' => 'portfolio' ), // The URL slug this post type will use.
    ));
}

Add Post Types to the Main Query

// Add custom post-types to the 'Main Query' (Home page).
add_action( 'pre_get_posts', 'add_my_post_types_to_query' );
function add_my_post_types_to_query( $query )
{
    if ( is_home() && $query->is_main_query() )
    {
        $query->set( 'post_type', array(
            'post',         // Keep the standard 'posts' in the Main Query.
            'ww_portfolio', // Add the custom post-type 'ww_portfolio' to the Main Query.
            //'page',       // Add pages to the Main Query.
        ) );
    }
    return $query;
}

Custom Post Type Template Files

single-{post type ID}.php
archive-{post type ID}.php

Custom Post Type Conditionals

// Single custom post type page.
if( is_singular( 'ww_portfolio' ) )
{
    do something.
}

// Check within The Loop.
if( 'ww_portfolio' == get_post_type() )
{
    do something.
}

Sources