WordPress Custom Post Types are a core feature for theme and plugin development, allowing you to create and manage content types different from standard 'posts' and 'pages'. This article explains how to create a custom post type, add taxonomies and custom fields (meta boxes), and display the content on the front end.
Creating a Custom Post Type
To create a new post type, use the register_post_type() function. Typically, you add this code to your theme's functions.php file.
function my_custom_post_type() {
$labels = array(
'name' => _x( 'Products', 'post type general name' ),
'singular_name' => _x( 'Product', 'post type singular name' ),
'menu_name' => __( 'Products' ),
'add_new' => __( 'Add New' ),
'add_new_item' => __( 'Add New Product' ),
'edit_item' => __( 'Edit Product' ),
'new_item' => __( 'New Product' ),
'all_items' => __( 'All Products' ),
'view_item' => __( 'View Product' ),
'search_items' => __( 'Search Products' ),
'not_found' => __( 'No products found' ),
'not_found_in_trash' => __( 'No products found in Trash' )
);
$args = array(
'labels' => $labels,
'description' => 'Holds product data',
'public' => true,
'menu_position' => 5,
'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt' ),
'has_archive' => true,
'show_in_rest' => true // Enables Gutenberg/block editor support
);
register_post_type( 'product', $args );
}
add_action( 'init', 'my_custom_post_type' );
After adding the code and refreshing the WordPress admin, you should see a new 'Products' menu item, indicating successful registration.
Adding a Taxonomy to a Custom Post Type
Use the register_taxonomy() function to add a category or tag-like taxonomy to your post type. You must specify the associated post type.
function my_product_taxonomy() {
$labels = array(
'name' => _x( 'Product Categories', 'taxonomy general name' ),
'singular_name' => _x( 'Product Category', 'taxonomy singular name' ),
'search_items' => __( 'Search Categories' ),
'all_items' => __( 'All Categories' ),
'parent_item' => __( 'Parent Category' ),
'parent_item_colon' => __( 'Parent Category:' ),
'edit_item' => __( 'Edit Category' ),
'update_item' => __( 'Update Category' ),
'add_new_item' => __( 'Add New Category' ),
'new_item_name' => __( 'New Category Name' ),
'menu_name' => __( 'Categories' )
);
$args = array(
'labels' => $labels,
'hierarchical' => true, // true for categories, false for tags
'show_admin_column' => true, // show column in post list
'show_in_rest' => true // needed for block editor
);
register_taxonomy( 'product_cat', 'product', $args );
}
add_action( 'init', 'my_product_taxonomy', 0 );
After adding this, the 'Product Categories' meta box will appear on the 'Product' edit screen.
Adding Custom Fields (Meta Boxes)
Custom fields allow you to store additional information for a post type. For example, add a 'Product URL' field.
First, register the meta box using add_meta_box():
add_action( 'add_meta_boxes', 'add_product_url_meta_box' );
function add_product_url_meta_box() {
add_meta_box(
'product_url_meta_box', // Unique ID
'Product URL', // Box title
'render_product_url_box', // Callback function for HTML
'product', // Post type
'side', // Context
'default' // Priority
);
}
Then, define the callback function to create the form field and handle data saving:
// Render the meta box HTML
function render_product_url_box( $post ) {
wp_nonce_field( 'save_product_url', 'product_url_nonce' );
$value = get_post_meta( $post->ID, '_product_url', true );
echo '';
echo '';
}
// Save the meta box data
add_action( 'save_post', 'save_product_url_meta' );
function save_product_url_meta( $post_id ) {
// Security checks
if ( ! isset( $_POST['product_url_nonce'] ) || ! wp_verify_nonce( $_POST['product_url_nonce'], 'save_product_url' ) ) {
return;
}
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
if ( isset( $_POST['product_url'] ) ) {
$url = sanitize_text_field( $_POST['product_url'] );
update_post_meta( $post_id, '_product_url', $url );
}
}
You can also display this custom field in the admin post list:
// Add column to post list
add_filter( 'manage_product_posts_columns', 'add_product_url_column' );
function add_product_url_column( $columns ) {
$columns['product_url'] = 'Product URL';
return $columns;
}
// Populate the column
add_action( 'manage_product_posts_custom_column', 'show_product_url_column', 10, 2 );
function show_product_url_column( $column, $post_id ) {
if ( $column === 'product_url' ) {
echo esc_html( get_post_meta( $post_id, '_product_url', true ) );
}
}
Displaying Data on the Front End
In your theme template files, you can retrieve and display custom field values:
echo 'Product URL: ' . esc_url( get_post_meta( get_the_ID(), '_product_url', true ) );
To query and loop through custom post type content, use WP_Query:
$args = array(
'post_type' => 'product',
'posts_per_page' => 10,
'tax_query' => array( // Optional: filter by taxonomy
array(
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => 'featured'
)
)
);
$query = new WP_Query( $args );
if ( $query->have_posts() ) :
while ( $query->have_posts() ) : $query->the_post();
the_title( '', '
' );
the_content();
$url = get_post_meta( get_the_ID(), '_product_url', true );
if ( $url ) {
echo '';
}
endwhile;
wp_reset_postdata();
else :
echo 'No products found.
';
endif;
Following these steps, you can create a fully functional custom post type and manage its content effectively.