Registering Custom Post Type


I am not finding any information regarding registering a CPT. I’ve seen discussion about registering them as a plugin, but previously I would just register them in function.php.

Is there any other documentation anywhere? Coming from Laravel where the documentation is very detailed I feel that there is a considerable lack of information.

I can’t seem to find any information about how to add CPT as a plugin.

Thank you

Registering custom post types is kind of beyond the scope of Sage, and Sage doesn’t doesn’t anything special w/r/t to CPTs. The official docs are pretty good:

You might also check out extended-cpts for a little more functionality: might be of interest

Hi thank you for the reply.

I am confused? says to register it in the theme, but i’ve read else where on here to add them as a plugin… If “Registering custom post types is kind of beyond the scope of Sage” where and how do you register them.

Is there some documentation about this? Is it in the paid download?

Sorry for all the questions, it is really hard trying to find the solution amongst a variety of obscure answers online.


Hey @tomphilpotts, this is probably not the most technical solution, but it’ll do the trick! (assuming you’re using sage 9)

  1. Setup your CPT config - you may find this useful to get started:
  2. Copy & paste into app/setup.php -

Registering CPT in theme / plugin is totally up to you and depends on the context. Extract it out into a plugin if it’s not theme specific or will be shared across different sites. Pop it in the theme if it’s theme specific. I’d start in theme and extract out to a plugin later if you need to, no point adding extra boilerplate code early on!

1 Like

Thanks I ended up just putting as a mu-plugin.

I highly recommend using:

Quick install:

composer require johnbillion/extended-cpts

Then within your ‘app’ folder, register a php file eg. cpt-team.php and here is example code to register a ‘Team’ custom post type with roles taxonomy:


namespace App;

use Roots\Sage\Container;
use Roots\Sage\Assets\JsonManifest;
use Roots\Sage\Template\Blade;
use Roots\Sage\Template\BladeProvider;

add_action( 'init', function() {
	register_extended_post_type( 'team', [

'show_in_feed' => true,
'menu_icon'    => 'dashicons-groups',

# Add some custom columns to the admin screen:
		'admin_cols' => [
			'course_dept' => [
            'taxonomy' => 'department'
			'team_role' => [
				'taxonomy' => 'team-roles'

		'archive' => [
			'nopaging' => true,

	], [

		'singular' => 'Team',
		'plural'   => 'Teams',
		'slug'     => 'teams',

	] );

	register_extended_taxonomy( 'team-roles', 'team', array(

		'dashboard_glance' => true,

		'admin_cols' => array(
				'updated' => array(
						'title'       => 'Updated',
						'meta_key'    => 'updated_date',
						'date_format' => 'd/m/Y'

), array(

		'singular' => 'Role',
		'plural'   => 'Roles',
		'slug'     => 'team-roles'

) );

} );

We put the CPT definitions and other information architecture things like taxonomies in a mu-plugin. The idea is that if the client later wants to switch to a different theme, the IA would still be required.

But lately I’ve started to see the whole project as a singular app and the theme and IA are too intertwined to really tease apart cleanly. So I’m leaning towards migrating the IA stuff into the theme.

It’s really a matter of personal preference, though if you do go with a mu-plugin you have to add additional steps in any deploy script you write.

1 Like


Personally I create a custom-post-types.php file in the app folder, where I place the cpt declaration (using the johnbillion/extended-cpts plugin syntax)

In order to have the custom-post-types.php loaded, I am changing the “Sage required files” in functions php ( line 61 for me ) :
['helpers', 'setup', 'filters', 'admin', 'custom-post-types', 'acf']

As you can see, I’m also doing it for acf :slight_smile:


This topic was automatically closed after 42 days. New replies are no longer allowed.