Custom Post Types and Taxonomy helper classes for WordPress projects.
- Register Custom Post Types and Taxonomies through an array notation. Labels will be set accordingly. Currently, English, German and Dutch are supported.
- Change the query arguments for posts in the front- and backend via a list of arguments, e.g. to set a custom post order wit the
query
option. - Change the admin columns for posts in the backend via a list of arguments.
- Set a specific page as the archive page for a custom post type with the
page_for_archive
option. - Set post slugs dynamically when posts are saved.
- Table of Contents
- Installation
- Register post types
- Update existing post types
- Change admin column settings for existing post type
- Register taxonomies
- Update existing taxonomies
- Customize a post slug
- Support
You can install the package via Composer:
composer require mindkomm/types
<?php
/**
* Register post types for your theme.
*
* Pass a an array of arrays to the registration function.
*/
add_action( 'init', function() {
Types\Post_Type::register( [
// Always use an English lowercase singular name to name a post type.
'example' => [
'name_singular' => 'Example',
'name_plural' => 'Examples',
'args' => [
/**
* For a list of possible menu-icons see
* https://developer.wordpress.org/resource/dashicons/
*/
'menu_icon' => 'dashicons-building',
'hierarchical' => false,
'has_archive' => false,
'supports' => [
'title',
'editor',
],
// Whether post is accessible in the frontend
'public' => false,
],
'admin_columns' => [
'date' => false,
],
],
] );
} );
The args
parameter is used for the arguments that are passed to register_post_type
. The name_singular
and name_plural
parameters are used for the generating the labels in the backend.
You can use more options:
Arguments that are used for querying this post type in the back- and frontend. You can use this to define the sort order. Here’s an example for a post type event
, where we want to order the posts by the value of a custom field named date_start
.
'query' => [
'meta_key' => 'date_start',
'orderby' => 'meta_value_num',
'order' => 'DESC',
],
If you want to have different queries for the front- and the backend, you can use separate frontend
and backend
keys:
'query' => [
'frontend' => [
'meta_key' => 'date_start',
'orderby' => 'meta_value_num',
'order' => 'ASC',
],
'backend' => [
'meta_key' => 'date_start',
'orderby' => 'meta_value_num',
'order' => 'DESC',
],
],
If you only use one key and omit the other, then the query will only be applied to your choice.
Arguments that are used to add and remove admin columns in the backend. Pass an associative array of column names with arguments.
Here’s an example for a Custom Post Type event
.
'admin_columns' => [
'date' => false,
'date_start' => [
'title' => 'Start Date',
'transform' => function( $value ) {
return date_i18n(
get_option( 'date_format' ),
DateTime::createFromFormat( 'Ymd', $value )->getTimeStamp()
);
},
],
'location' => [
'title' => 'Location',
'sortable' => true,
'searchable' => true,
'transform' => function( $post_id ) {
return get_the_title( $post_id );
},
],
'width' => [
'title' => 'Width',
'sortable' => true,
'orderby' => 'meta_value_num',
],
],
These are the possible arguments:
- title – (string) The title to use for the column. Default empty.
- transform – (callable) The function to use on the value that is displayed. The function defined here will get a
$value
parameter that you can transform. E.g., if you have a post ID saved in post meta, you could display the post’s title. Defaultnull
. - type – (string) The type for the column. One of
meta
,acf
,thumbnail
,image
orcustom
. Defaultmeta
. - sortable – (bool) Whether the column is sortable. Default
false
. - orderby – (string) What to order by when the
sortable
argument is used. You don’t need to provide ameta_key
parameter, because it is automatically set. Defaultmeta_value
. - searchable – (bool) Whether the column is searchable. Will include the meta values when searching the post list. Only applied if using the default type
meta
. Defaultfalse
. - column_order – (int) An order number to sort by. You can use this to change the order of your columns. Default
10
.
If you need more possibilities for defining admin columns you could use the fantastic Admin Columns plugin.
The type
argument defines how your column is interpreted. The following types exist:
meta
acf
thumbnail
image
custom
With the meta
type, the column name is the name of the meta field you want to display.
You can also use acf
as a type you use Advanced Custom Fields and want to apply its filters to the value.
Use this key to display the featured image thumbnail for a post.
'location' => [
'thumbnail' => true,
],
You can also set the width and height. The defaults are 80
× 80
pixels.
'location' => [
'thumbnail' => [
'width' => 100,
'height' => 100,
],
],
The type
allows you to display an image other than the featured image. This type will also use the key of the column to get an attachment ID from the post’s meta values.
'admin_columns' => [
'profile_image' => [
'title' => 'Profile image',
'type' => 'image',
],
],
By default, it will display the thumbnail
size. If you want to request a different size, use the image_size
parameter.
'admin_columns' => [
'profile_image' => [
'title' => 'Profile image',
'type' => 'image',
'image_size' => 'medium',
],
],
And if you want to restrict the width and the height of the image, you can provide pixel values for width
and height
.
'admin_columns' => [
'profile_image' => [
'title' => 'Profile image',
'type' => 'image',
'width' => 100,
'height' => 100,
],
],
If you want to do something custom, you can use the custom
type. If you use the custom
type, you need to provide a value
, which is a callback function that receives the post’s ID as a single parameter.
In this example, we call a function that extracts an attribute value from a certain block of the post.
'email' => [
'title' => __( 'Email', 'theme-module-teammember' ),
'type' => 'custom',
'value' => function( $post_id ) {
return $this->get_block_attribute( $post_id, 'email' );
},
],
You can also update or hide existing columns. Existing columns can be updated with the title
and the column_order
argument.
If you want to the change the title of an existing column, use the title
attribute.
'admin_columns' => [
'title' => [
'title' => 'Event title',
],
],
If you want to move the column, you can use the column_order
argument. In this example, we would move the date
column to the end.
'admin_columns' => [
'date' => [
'column_order' => 100,
],
],
The default order is 10
. So if you wanted to move a column like the thumbnail to the start, you could use 5
.
'admin_columns' => [
'thumbnail' => [
'column_order' => 5,
],
],
To hide an existing column, you can use false
.
'admin_columns' => [
'date' => false,
],
The page_for_archive
option allows you to set a specific page as the archive page for a custom post type:
'event' => [
'args' => [
'public' => true,
],
'page_for_archive' => [
'post_id' => get_option( 'page_for_event' ),
'is_singular_public' => false,
],
],
In this example, the ID for the page that’s saved in the page_for_event
option will act as the archive page for the event
post type.
You need to flush your permalinks whenever you make changes to this option.
Behind the curtains, Types uses the has_archive
option when registering a post type and sets the slug of the page you passed in the page_for_archive
option.
The is_singular_public
option allows you to set, whether singular templates for this post type should be accessible in the frontend. Singular template requests will then be redirected to the archive page. We can’t use the public
or publicly_queryable
option for this, because then the archive page wouldn’t work either.
If you want Types to register an option to select the page you want to use as your archive in the Customizer, you can use the customizer_section
argument:
'event' => [
'page_for_archive' => [
'post_id' => get_option( 'page_for_event' ),
'customizer_section' => 'event',
],
],
With customizer_section
, you can define in which Customizer section the option should be displayed. This needs to be an existing section. This way, you can decide yourself whether you want to have a separate Customizer section for each custom post type, or whether you want to list all of your custom post type pages in the same section.
Types will display a post state in the pages overview for the page that you selected. If you want to disable this functionality, use the show_post_state
option.
'event' => [
'page_for_archive' => [
'post_id' => get_option( 'page_for_event' ),
'show_post_state' => false,
],
],
To make use of that page, you will use it in your archive page where you can now use your page as the main post.
archive-event.php
$post = get_post( get_option( 'page_for_event' ) );
Use the update()
function to change the settings for an existing post type. Here’s an example for changing the settings for posts to make them not directly accessible in the frontend.
functions.php
Types\Post_Type::update( [
'post' => [
'args' => [
'public' => false,
'show_ui' => true,
'show_in_nav_menus' => true,
],
'admin_columns' => [
'date' => false,
],
],
] );
The update()
function accepts an associative array of post types and their arguments. Make sure you use this function before the init
hook.
Please be aware that it’s not possible to change post type support features through the update()
function. To remove support for an existing feature, you will have to use the remove_post_type_support
function.
add_action( 'init', function() {
remove_post_type_support( 'post', 'thumbnail' );
} );
In the same manner, if you want to add features, you should do it through the add_post_type_support
function:
add_post_type_support( 'page', 'excerpt' );
Sometimes you might want to rename an existing post type to better reflect what it’s used for.
functions.php
Types\Post_Type::rename( 'post', 'Beispiel', 'Beispiele' );
The rename()
function accepts a post type as the first parameter, the new singular name of the post type as a second parameter and the plural name of the post type as a third parameter. If you omit the third parameter, the second parameter will be used as the plural form instead. Make sure you use this function before the init
hook.
This is practically a shorthand function for:
Types\Post_Type::update( [
'post' => [
'name_singular' => 'Beispiel',
'name_plural' => 'Beispiele',
],
] );
If you only want to rename one of the labels, e.g. the menu label, you can use the post_type_labels_{$post_type}
filter. Here’s an example for changing the menu name for posts:
add_filter( 'post_type_labels_post', function( $labels ) {
$labels->menu_name = 'Aktuelles';
return $labels;
}, 11 );
To change the admin column settings for existing post types like post
or page
, you can use the admin_columns()
function, which accepts an associative array of post types and their admin column settings.
Here’s an example that disables the date, comments and author columns and adds a thumbnail instead:
Types\Post_Type::admin_columns( [
'page' => [
'date' => false,
'comments' => false,
'author' => false,
'thumbnail' => [
'width' => 80,
'height' => 80,
],
],
] );
<?php
use Types\Taxonomy;
/**
* Register taxonomies for your theme.
*
* Pass a an array of arrays to the registration function.
*/
add_action( 'init', function() {
Taxonomy::register( [
// Always use an English lowercase singular name to name a taxonomy.
'example_tax' => [
'name_singular' => 'Example Category',
'name_plural' => 'Example Categories',
// For which post types do you want to register this taxonomy?
'for_post_types' => [ 'example' ],
'args' => [
// Hide the meta box from the edit view
// 'meta_box_cb' => false,
//
// Make it selectable in the navigation menus
// 'show_in_nav_menus' => true,
],
],
] );
} );
The args
parameter is used for the arguments that are passed to register_taxonomy
. Use the for_post_types
parameter to assign taxonomies to certain post types. The name_singular
and name_plural
parameters are used for the generating the labels in the backend.
Use the update()
function to change the settings for an existing taxonomy. Here’s an example for changing the settings for categories to make them not directly accessible in the frontend.
functions.php
Types\Taxonomy::update( [
'category' => [
'args' => [
'public' => false,
'show_ui' => true,
'show_in_nav_menus' => true,
],
],
] );
The update()
function accepts an associative array of taxonomies and their arguments. Make sure you use this function before the init
hook.
Sometimes you might want to rename an existing taxonomy to better reflect what it’s used for.
functions.php
Types\Taxonomy::rename( 'category', 'Topic', 'Topics' );
The rename()
function accepts a taxonomy as the first parameter, the new singular name of the taxonomy as a second parameter and the plural name of the taxonomy as a third parameter. If you omit the third parameter, the second parameter will be used as the plural form instead. Make sure you use this function before the init
hook.
This is practically a shorthand function for:
Types\Taxonomy::update( [
'category' => [
'name_singular' => 'Topic',
'name_plural' => 'Topics,
],
] );
If you only want to rename one of the labels, e.g. the menu label, you can use the taxonomy_labels_{$post_type}
filter. Here’s an example for changing the menu name for posts:
add_filter( 'taxonomy_labels_category', function( $labels ) {
$labels->menu_name = 'Topics';
return $labels;
}, 11 );
If you want to unregister taxonomies for certain post types, it’s best to do it through the unregister_taxonomy_for_object_type()
function.
/**
* Unregister post categories and post tags.
*/
add_action( 'init', function() {
unregister_taxonomy_for_object_type( 'category', 'post' );
unregister_taxonomy_for_object_type( 'post_tag', 'post' );
} );
Sometimes you want to overwrite the post slug when a post is saved. Possible use cases:
- Common post duplication plugin often only add
-copy
or-2
as a suffix to the post slug. You want to use your own pattern. - Multiple posts have the same name, but differ in the meta data they display. For example, event posts could have a different date. You want to add the date of the event to the post slug automatically.
To initalize, you’ll need to create an instance of Post_Slug
and call the init()
function:
$post_slugs = new Types\Post_Slug();
$post_slugs->init();
Here’s an example for a custom post slug for a post type course
, where you want the permalink to be built from the post title. In this scenario, the post title would be a course number.
$post_slugs = new Types\Post_Slug();
$post_slugs->init();
$post_slugs->register( [
'course' => function( $post_slug, $post_data, $post_id ) {
return $post_data['post_title'];
},
] );
You don’t have to use sanitize_title
in the callback, because the class uses that function internally.
Here’s another example for the event post mentioned earlier:
$post_slugs->register_suffix_date( [
'event' => [
'meta_key' => 'date_start',
],
] );
The register_suffix_date
function is a special function that makes it easier to append a date taken from a post’s meta data and append it to the slug. The function takes an associative array of post types and their args for the function:
- meta_key – Used to define the name of the meta key that is used. Default
date_start
. - input_format – Defines the date format of the meta value. Default
Ymd
. - output_format – Defines the output date format that should be used for the suffix. Default
Y-m-d
.
This is a library that we use at MIND to develop WordPress themes. You’re free to use it, but currently, we don’t provide any support.