How to create custom post types and taxonomies in WordPress
WordPress.org Function Reference/register post type
WordPress.org Code Reference: register_post_type
Smashing: Extending WordPress with Custom Content Types
register_post_type( string $post_type, array|string $args = array() )
ex:
if (!post_type_exists('person')) {
// Set up all the labels to use for your content type
$labels = array(
'name' => 'People',
'singular_name' => 'Person',
'menu_name' => 'People',
'name_admin_bar' => 'People',
'add_new' => 'Add New',
'add_new_item' => 'Add New Person',
'new_item' => 'New Person',
'edit_item' => 'Edit Person',
'view_item' => 'View Person',
'all_items' => 'All People',
'search_items' => 'Search People',
'parent_item_colon' => 'Parent Person',
'not_found' => 'No People Found',
'not_found_in_trash' => 'No People Found in Trash'
);
// Set the permalink structure for your content type. 'with_front' is whether the permalink for your content type should be prepended with the front base. (example: if your permalink structure is /blog/, then your links will be: false->/news/, true->/blog/news/). Defaults to true
$rewrite = [
'slug' => 'our-team',
'with_front' => false,
];
// Features this content type supports in Post Editor
$supports = [
'title',
'editor',
'comments',
'author',
'thumbnail',
'excerpt',
'custom-fields',
'revisions',
];
// plug in all the arguments you just set up, along with a bunch more
$args = [
'labels' => $labels,
'rewrite' => $rewrite,
'supports' => $supports,
'public' => true,
'exclude_from_search' => false,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_nav_menus' => true,
'show_in_menu' => true,
'show_in_admin_bar' => true,
'menu_position' => 4,
'menu_icon' => 'dashicons-groups',
// note that any custom taxonomies need to be created, then added here
'taxonomies' => ['slugs', 'of', 'desired', 'taxonomies'],
'capability_type' => 'post',
'hierarchical' => false,
'has_archive' => false,
'query_var' => true,
'show_in_rest' => true,
];
register_post_type('person', $args);
}
WordPress.org: Function Reference/register taxonomy
WordPress.org: Code Reference -- register_taxonomy
Smashing: How To Create A Custom Taxonomy In WordPress
register_taxonomy( $taxonomy, $object_type, $args );
ex:
/**
* Add 'role' taxonomy to the 'person' content type
*
* http://codex.wordpress.org/Function_Reference/register_taxonomy
*/
if (!taxonomy_exists('role')) {
// This array of options controls the labels displayed in the WordPress Admin UI
$labels = [
'name' => _x( 'Roles', 'taxonomy general name' ),
'singular_name' => _x( 'Roles', 'taxonomy singular name' ),
'search_items' => __( 'Search Locations' ),
'all_items' => __( 'All Locations' ),
'parent_item' => __( 'Parent Role' ),
'parent_item_colon' => __( 'Parent Role:' ),
'edit_item' => __( 'Edit Role' ),
'update_item' => __( 'Update Role' ),
'add_new_item' => __( 'Add New Role' ),
'new_item_name' => __( 'New Role Name' ),
'menu_name' => __( 'Roles' ),
];
// This array of options controls the slugs used for this taxonomy
$rewrite = [
// 'slug' controls the base slug that will display before each term
'slug' => 'roles',
// 'with_front controls whether to display the category base before "/roles/"
'with_front' => false,
// Whether to allow nested URLs like "/roles/employees/team-lead/"
'hierarchical' => true
];
$args = [
// Hierarchical taxonomy (like categories)
'hierarchical' => true,
'public' => true,
'show_admin_column' => true,
'show_ui' => true,
'show_in_rest' => true,
'labels' => $labels,
'rewrite' => $rewrite,
];
register_taxonomy('role', 'person', $args);
}
When you create your custom content type, you need to include the following in the $args:
'taxonomies' => ['any', 'slugs', 'for', 'desired', 'taxonomies'],
ex: To add
'taxonomies' => ['category', 'post_tag', 'event_category', 'event_type'],
If you create a custom post type that shares tags or categories with posts, it's important to add that custom post type to the query for the tags/categories archive pages! Insipred by StackExchange:
/**
* Show events on archive pages
*
* Because posts and events use common tags and
* categories, we need to add events to the tags and
* categories queries so they show up on those archive pages
*/
function radicati_include_events($query)
{
if (($query->is_tag() || $query->is_category()) && $query->is_main_query()) {
$query->set('post_type', array('post', 'event'));
}
}
add_action('pre_get_posts', 'radicati_include_events');
Smashing: Customizing Admin Columns In WordPress
ex:
add_filter( 'manage_event_posts_columns', 'radicati_filter_events_columns' );
// set the columns to appear on the events admin page
function radicati_filter_events_columns( $columns ) {
$columns = array(
'cb' => $columns['cb'],
'title' => __('Title'),
'event_date' => __('Date', 'radicati'),
'event_category' => __('Event Category', 'radicati'),
'event_type' => __('Event Type', 'radicati'),
'tags' => __('Tags', 'radicati'),
'date' => __('Date Modified', 'radicati'),
'author' => __('Author'),
);
return $columns;
}
// Add content to custom/non-standard columns
add_action('manage_event_posts_custom_column', 'radicati_event_column', 10, 2);
function radicati_event_column($column, $post_id)
{
// Date column
if ('event_date' === $column) {
$date = get_post_meta($post_id, 'dates', true);
if (!$date) {
_e('n/a');
} else {
echo $date;
}
}
// Event Category column
if ('event_category' === $column) {
$categories = get_the_term_list($post_id, 'event_category', null, ', ', null);
if (!$categories) {
_e('n/a');
} else {
echo $categories;
}
}
// Event Type column
if ('event_type' === $column) {
$types = get_the_term_list($post_id, 'event_type', null, ', ', null);
if (!$types) {
_e('n/a');
} else {
echo $types;
}
}
}
// Make event date column sortable
add_filter('manage_edit-event_sortable_columns', 'radicati_event_sortable_columns');
function radicati_event_sortable_columns($columns)
{
$columns['event_date'] = 'end_date';
return $columns;
}
add_action('pre_get_posts', 'radicati_posts_orderby');
function radicati_posts_orderby($query)
{
if (!is_admin() || !$query->is_main_query()) {
return;
}
if ('end_date' === $query->get('orderby')) {
$query->set('orderby', 'meta_value');
$query->set('meta_key', 'end_date');
$query->set('meta_type', 'numeric');
}
}
ex:
// Change dashboard Posts to Articles
function wp_change_post_object()
{
$get_post_type = get_post_type_object('post');
$labels = (object) [
'name' => 'Articles',
'singular_name' => 'Article',
'add_new' => 'Add New',
'add_new_item' => 'Add New Article',
'edit_item' => 'Edit Article',
'new_item' => 'New Article',
'view_item' => 'View Article',
'view_items' => 'View Articles',
'search_items' => 'Search Articles',
'not_found' => 'No articles found.',
'not_found_in_trash' => 'No articles found in Trash.',
'parent_item_colon' => null,
'all_items' => 'All Articles',
'archives' => 'Article Archives',
'attributes' => 'Article Attributes',
'insert_into_item' => 'Insert into article',
'uploaded_to_this_item' => 'Uploaded to this article',
'featured_image' => 'Featured Image',
'set_featured_image' => 'Set featured image',
'remove_featured_image' => 'Remove featured image',
'use_featured_image' => 'Use as featured image',
'filter_items_list' => 'Filter articles list',
'items_list_navigation' => 'Articles list navigation',
'items_list' => 'Articles list',
'item_published' => 'Article published.',
'item_published_privately' => 'Article published privately.',
'item_reverted_to_draft' => 'Article reverted to draft.',
'item_scheduled' => 'Article scheduled.',
'item_updated' => 'Article updated.',
'menu_name' => 'Articles',
'name_admin_bar' => 'Article',
];
foreach($labels as $key => $value) {
$get_post_type->labels->$key = $value;
}
$get_post_type->menu_icon = 'dashicons-welcome-write-blog';
}
Then call wp_change_post_object()
inside the radicati_theme_init
function