Overview
In this tutorial, we’ll cook up a custom post type with custom fields and its own block theme templates! Just like a signature dish needs the perfect presentation, your post type will come with tailored templates that integrate seamlessly with any active block theme. Follow along as we mix the right ingredients to create a fully customized content experience! 🍽️📜👨🍳
Celebrity Chef
This fantastic recipe comes from the talented Nick Diego, a true master in the world of blocks! Known for his brilliant creations like Block Visibility and the Icon Block, Nick brings his expertise and creativity to every dish he crafts. His work is a testament to innovation and flavor, making this recipe a must-try for any block enthusiast! 🍽️✨
Setup
You can choose to either use the repository which provides a development environment or to just download the standalone plugin
Standalone
Instructions
Run the following command in a terminal of your choice from inside the plugins directory of your local WordPress installation.
npx @wordpress/create-block@latest your-people --template @block-developer-cookbook/your-peopleOnce the scaffold has completed completed, start the build process from inside the newly created plugin
cd your-people && npm run startFinally, make sure to activate the plugin.
Repository
Instructions
Checkout the repository (skip this step if already done)
git clone git@github.com:ryanwelcher/block-developer-cookbook.gitInstall the dependencies
npm installStart the development environment (make sure you have Docker installed )
npm run env startRun the following script from the root of the repository
npm run prep:your-peopleOnce the scaffold has completed completed, start the build process from inside the newly created plugin
cd plugins/your-people && npm run startStep 1 – Register the data
This recipe requires a fair amount of setup to create the custom post type, the taxonomy, and all of the custom fields that will be associated with each person. To streamline the process, the template provides the majority of it for yuor
Open the your-people.php file and take a minute to familiarize yourself with the code
<?php
/**
* Plugin Name: Your People
* Description: Create a custom block to display team members or staff.
* Requires at least: 6.1
* Requires PHP: 7.0
* Version: 1.0.0
* Author: The WordPress Contributors
* License: GPL-2.0-or-later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: your-people
*
* @package block-developers-cookbook
*/
namespace BlockDevelopersCookbook;
/**
* Register the 'person' custom post type.
*/
function register_person_post_type() {
$labels = array(
'name' => _x( 'People', 'Post type general name', 'your-people' ),
'singular_name' => _x( 'Person', 'Post type singular name', 'your-people' ),
'menu_name' => _x( 'People', 'Admin Menu text', 'your-people' ),
'name_admin_bar' => _x( 'Person', 'Add New on Toolbar', 'your-people' ),
'add_new' => __( 'Add New Person', 'your-people' ),
'add_new_item' => __( 'Add New Person', 'your-people' ),
'new_item' => __( 'New Person', 'your-people' ),
'edit_item' => __( 'Edit Person', 'your-people' ),
'view_item' => __( 'View Person', 'your-people' ),
'all_items' => __( 'All People', 'your-people' ),
'search_items' => __( 'Search People', 'your-people' ),
'not_found' => __( 'No people found.', 'your-people' ),
'not_found_in_trash' => __( 'No people found in Trash.', 'your-people' ),
'featured_image' => _x( 'Person Profile Image', 'Overrides the "Featured Image" phrase', 'your-people' ),
'set_featured_image' => _x( 'Set profile image', 'Overrides the "Set featured image" phrase', 'your-people' ),
'remove_featured_image' => _x( 'Remove profile image', 'Overrides the "Remove featured image" phrase', 'your-people' ),
'use_featured_image' => _x( 'Use as profile image', 'Overrides the "Use as featured image" phrase', 'your-people' ),
);
$args = array(
'labels' => $labels,
'public' => true,
'has_archive' => 'people',
'hierarchical' => false,
'menu_icon' => 'dashicons-groups',
'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt', 'custom-fields' ),
'show_in_rest' => true,
);
register_post_type( 'person', $args );
}
add_action( 'init', __NAMESPACE__ . '\register_person_post_type' );
/**
* Register the 'role' taxonomy for the 'person' post type.
*/
function register_role_taxonomy() {
$labels = array(
'name' => _x( 'Roles', 'taxonomy general name', 'your-people' ),
'singular_name' => _x( 'Role', 'taxonomy singular name', 'your-people' ),
'search_items' => __( 'Search Roles', 'your-people' ),
'all_items' => __( 'All Roles', 'your-people' ),
'parent_item' => __( 'Parent Role', 'your-people' ),
'parent_item_colon' => __( 'Parent Role:', 'your-people' ),
'edit_item' => __( 'Edit Role', 'your-people' ),
'update_item' => __( 'Update Role', 'your-people' ),
'add_new_item' => __( 'Add New Role', 'your-people' ),
'new_item_name' => __( 'New Role Name', 'your-people' ),
'menu_name' => __( 'Role', 'your-people' ),
);
$args = array(
'labels' => $labels,
'show_admin_column' => true,
'query_var' => true,
'rewrite' => array( 'slug' => 'role' ),
'show_in_rest' => true,
);
register_taxonomy( 'role', array( 'person' ), $args );
}
add_action( 'init', __NAMESPACE__ . '\register_role_taxonomy' );
/**
* Register custom meta fields for the 'person' post type.
*/
function register_person_meta() {
register_post_meta(
'person',
'yp_job_title',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'label' => __( 'Job Title', 'your-people' ),
'description' => __( 'The person\'s job title', 'your-people' ),
'sanitize_callback' => 'wp_strip_all_tags'
)
);
}
add_action( 'init', __NAMESPACE__ . '\register_person_meta' );
/**
* Register the plugin templates.
*/
function register_plugin_templates() {
// Register your custom templates here.
}
add_action( 'init', __NAMESPACE__ . '\register_plugin_templates' );
/**
* Helper function to get the content of a template file.
*
* @param string $template The name of the template file.
* @return string The content of the template file.
*/
function get_template_content( $template ) {
ob_start();
include plugin_dir_path( __FILE__ ) . "/templates/{$template}";
return ob_get_clean();
}
// Include some files we need
require_once __DIR__ . '/includes/admin.php';
require_once __DIR__ . '/includes/editor.php';
There is a lot going on here but basically, this code is registering the person custom post type, role taxonomy, and a single custom field. When registering post types, taxonomies and custom fields it’s extremely important to make sure you set the show_in_rest parameter to true to ensure that these items are available to the block editor via the REST API.
There are 4 more custom fields to register so go ahead and add those to the register_person_meta functon now
<?php
/**
* Plugin Name: Your People
* Description: Create a custom block to display team members or staff.
* Requires at least: 6.1
* Requires PHP: 7.0
* Version: 1.0.0
* Author: The WordPress Contributors
* License: GPL-2.0-or-later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: your-people
*
* @package block-developers-cookbook
*/
namespace BlockDevelopersCookbook;
/**
* Register the 'person' custom post type.
*/
function register_person_post_type() {
$labels = array(
'name' => _x( 'People', 'Post type general name', 'your-people' ),
'singular_name' => _x( 'Person', 'Post type singular name', 'your-people' ),
'menu_name' => _x( 'People', 'Admin Menu text', 'your-people' ),
'name_admin_bar' => _x( 'Person', 'Add New on Toolbar', 'your-people' ),
'add_new' => __( 'Add New Person', 'your-people' ),
'add_new_item' => __( 'Add New Person', 'your-people' ),
'new_item' => __( 'New Person', 'your-people' ),
'edit_item' => __( 'Edit Person', 'your-people' ),
'view_item' => __( 'View Person', 'your-people' ),
'all_items' => __( 'All People', 'your-people' ),
'search_items' => __( 'Search People', 'your-people' ),
'not_found' => __( 'No people found.', 'your-people' ),
'not_found_in_trash' => __( 'No people found in Trash.', 'your-people' ),
'featured_image' => _x( 'Person Profile Image', 'Overrides the "Featured Image" phrase', 'your-people' ),
'set_featured_image' => _x( 'Set profile image', 'Overrides the "Set featured image" phrase', 'your-people' ),
'remove_featured_image' => _x( 'Remove profile image', 'Overrides the "Remove featured image" phrase', 'your-people' ),
'use_featured_image' => _x( 'Use as profile image', 'Overrides the "Use as featured image" phrase', 'your-people' ),
);
$args = array(
'labels' => $labels,
'public' => true,
'has_archive' => 'people',
'hierarchical' => false,
'menu_icon' => 'dashicons-groups',
'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt', 'custom-fields' ),
'show_in_rest' => true,
);
register_post_type( 'person', $args );
}
add_action( 'init', __NAMESPACE__ . '\register_person_post_type' );
/**
* Register the 'role' taxonomy for the 'person' post type.
*/
function register_role_taxonomy() {
$labels = array(
'name' => _x( 'Roles', 'taxonomy general name', 'your-people' ),
'singular_name' => _x( 'Role', 'taxonomy singular name', 'your-people' ),
'search_items' => __( 'Search Roles', 'your-people' ),
'all_items' => __( 'All Roles', 'your-people' ),
'parent_item' => __( 'Parent Role', 'your-people' ),
'parent_item_colon' => __( 'Parent Role:', 'your-people' ),
'edit_item' => __( 'Edit Role', 'your-people' ),
'update_item' => __( 'Update Role', 'your-people' ),
'add_new_item' => __( 'Add New Role', 'your-people' ),
'new_item_name' => __( 'New Role Name', 'your-people' ),
'menu_name' => __( 'Role', 'your-people' ),
);
$args = array(
'labels' => $labels,
'show_admin_column' => true,
'query_var' => true,
'rewrite' => array( 'slug' => 'role' ),
'show_in_rest' => true,
);
register_taxonomy( 'role', array( 'person' ), $args );
}
add_action( 'init', __NAMESPACE__ . '\register_role_taxonomy' );
/**
* Register custom meta fields for the 'person' post type.
*/
function register_person_meta() {
register_post_meta(
'person',
'yp_job_title',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'label' => __( 'Job Title', 'your-people' ),
'description' => __( 'The person\'s job title', 'your-people' ),
'sanitize_callback' => 'wp_strip_all_tags'
)
);
register_post_meta(
'person',
'yp_institution',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'label' => __( 'Institution/Employer', 'your-people' ),
'description' => __( 'The person\'s institution or employer', 'your-people' ),
'sanitize_callback' => 'wp_strip_all_tags'
)
);
register_post_meta(
'person',
'yp_location',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'label' => __( 'Location', 'your-people' ),
'description' => __( 'The person\'s location', 'your-people' ),
'sanitize_callback' => 'wp_strip_all_tags'
)
);
register_post_meta(
'person',
'yp_website_url',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'label' => __( 'Website', 'your-people' ),
'description' => __( 'The person\'s website', 'your-people' ),
'sanitize_callback' => 'wp_strip_all_tags'
)
);
register_post_meta(
'person',
'yp_linkedin_url',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'label' => __( 'LinkedIn URL', 'your-people' ),
'description' => __( 'The person\'s LinkedIn URL', 'your-people' ),
'sanitize_callback' => 'wp_strip_all_tags'
)
);
}
add_action( 'init', __NAMESPACE__ . '\register_person_meta' );
/**
* Register the plugin templates.
*/
function register_plugin_templates() {
// Register your custom templates here.
}
add_action( 'init', __NAMESPACE__ . '\register_plugin_templates' );
/**
* Helper function to get the content of a template file.
*
* @param string $template The name of the template file.
* @return string The content of the template file.
*/
function get_template_content( $template ) {
ob_start();
include plugin_dir_path( __FILE__ ) . "/templates/{$template}";
return ob_get_clean();
}
// Include some files we need
require_once __DIR__ . '/includes/admin.php';
require_once __DIR__ . '/includes/editor.php';
Step 2 – Managing the custom fields
Now that all of the custom fields are in place, you need a way to edit them in the block editor.
Jump over to the your-people.js file inside the src directory.
import { __ } from '@wordpress/i18n';
import { registerPlugin } from '@wordpress/plugins';
import { PluginDocumentSettingPanel } from '@wordpress/editor';
import { useEntityProp } from '@wordpress/core-data';
import { TextControl } from '@wordpress/components';
function SocialLinksPanel() {
return (
<>
<PluginDocumentSettingPanel
name="yp-general-info"
title={ __( 'General Info', 'your-people' ) }
className="yp-general-info"
initialOpen={ true }
>
<TextControl
label={ __( 'Title', 'your-people' ) }
value={ '' }
help={ __( "The person's job title(s).", 'your-people' ) }
/>
</PluginDocumentSettingPanel>
</>
);
}
registerPlugin( 'yp-social-links-panel', { render: SocialLinksPanel } );In this file you’re going to be using SlotFill to add panels to sidebar of the Person post where you can set the values of the custom fields. This initial template demonstrates how to register the plugin that contains the slot and it’s content to be added.
As is, this code will add a new panel to the sidebar with a single TextControl component to mange the person title field. However, it’s not actually connected to the custom field at this point.
To do this you will need to use the useEntityProp hook. This is a React hook that provides a way to retrieve and set the meta.
Adding the following code to the file:
import { __ } from '@wordpress/i18n';
import { registerPlugin } from '@wordpress/plugins';
import { PluginDocumentSettingPanel } from '@wordpress/editor';
import { useEntityProp } from '@wordpress/core-data';
import { TextControl } from '@wordpress/components';
function SocialLinksPanel() {
const [ meta, setMeta ] = useEntityProp( 'postType', 'person', 'meta' );
return (
<>
<PluginDocumentSettingPanel
name="yp-general-info"
title={ __( 'General Info', 'your-people' ) }
className="yp-general-info"
initialOpen={ true }
>
<TextControl
label={ __( 'Title', 'your-people' ) }
value={ meta?.yp_job_title || '' }
onChange={ ( newValue ) =>
setMeta( {
...meta,
yp_job_title: newValue,
} )
}
help={ __( "The person's job title(s).", 'your-people' ) }
/>
</PluginDocumentSettingPanel>
</>
);
}
registerPlugin( 'yp-social-links-panel', { render: SocialLinksPanel } );
The concept of entities can be a little confusing but you can thing of them as a data source. You can read more about them in the official documentation.
The useEnityProp hook is receiving three parameters:
- Entity kind. In your case this is
postTypebut it could also betaxonomy. - Entity name. The specific type of entity you wish to access.
- Prop. The information you want to access.
Once called, the hook returns an array of values, commonly referred to a as a tuple, where the first item is the data you’re requesting and the second is a function that can be used to save the data.
Using array destructuring, it’s possible to name these variable whatever you’d like. In your case, meta and setMeta but these can be anything but there is a best practice to use {{variable}} and set{{Variable}} when naming.
const [ personInfo, setPersonInfo ] = useEntityProp( 'postType', 'person', 'meta' );The rest of the change in the file are updating the TextControl to use the new meta values. The value prop is using optional chaining to display the title field if it is set or an empty string
value={ meta?.yp_job_title || '' }The onChange property is then updating the meta when the TextControl is updated and saving the meta. The setMeta function received an object of the meta values to save for this post.
onChange={ ( newValue ) =>
setMeta( {
...meta,
yp_job_title: newValue,
} )
}One thing to note there is that when calling setMeta, ALL of the meta for the post is saved and you need to be sure that you’re only changing the yp_job_title value. This is done by using the JavaScript spread operator to add all of the existing values in the meta variable and then we only change the value of the individual meta field being changed.
This ensures we’re only change the field for this control and that all existing meta is not lost.
There are 9 more custom fields that you need to manage so go ahead and update the code with the following
import { __ } from '@wordpress/i18n';
import { registerPlugin } from '@wordpress/plugins';
import { PluginDocumentSettingPanel } from '@wordpress/editor';
import { useEntityProp } from '@wordpress/core-data';
import { TextControl } from '@wordpress/components';
function SocialLinksPanel() {
const [ meta, setMeta ] = useEntityProp( 'postType', 'person', 'meta' );
return (
<>
<PluginDocumentSettingPanel
name="yp-general-info"
title={ __( 'General Info', 'your-people' ) }
className="yp-general-info"
initialOpen={ true }
>
<TextControl
label={ __( 'Title', 'your-people' ) }
value={ meta?.yp_job_title || '' }
onChange={ ( newValue ) =>
setMeta( {
...meta,
yp_job_title: newValue,
} )
}
help={ __( "The person's job title(s).", 'your-people' ) }
/>
<TextControl
label={ __( 'Employer/Institution', 'your-people' ) }
value={ meta?.yp_institution || '' }
onChange={ ( newValue ) =>
setMeta( {
...meta,
yp_institution: newValue,
} )
}
/>
<TextControl
label={ __( 'Location', 'your-people' ) }
value={ meta?.yp_location || '' }
onChange={ ( newValue ) =>
setMeta( {
...meta,
yp_location: newValue,
} )
}
/>
<TextControl
label={ __( 'Personal Website', 'your-people' ) }
value={ meta?.yp_website_url || '' }
onChange={ ( newValue ) =>
setMeta( {
...meta,
yp_website_url: newValue,
} )
}
/>
<TextControl
label={ __( 'LinkedIn URL', 'your-people' ) }
value={ meta?.yp_linkedin_url || '' }
onChange={ ( newValue ) =>
setMeta( {
...meta,
yp_linkedin_url: newValue,
} )
}
/>
</PluginDocumentSettingPanel>
</>
);
}
registerPlugin( 'yp-social-links-panel', { render: SocialLinksPanel } );
This code will add more fields and a second panel to the sidebar of the post. Take a second to make sure the field are saving and retrieving the custom fields as expected.
Step 3 – The templates
At this point, everything is in place to save and mange the team members. However, as the post type is stored in a plugin, there is no way that the active theme can know what needs to be displayed for the templates associated with the Person post type.
It’s possible to into the Templates section of the Site Editor and manually create a template for each one but there is a much better way to do this using the register_block_template function to add templates from your plugin to the used in the active theme
register_block_template accepts two parameters:
- The name of the template. This name must follow the
plugin_uri//template_nameformat - An array of arguments such as the
label,contentand some others
Update the register_plugin_templates function to register the provided single post template that is stored in the templates directory
<?php
/**
* Plugin Name: Your People
* Description: Create a custom block to display team members or staff.
* Requires at least: 6.1
* Requires PHP: 7.0
* Version: 1.0.0
* Author: The WordPress Contributors
* License: GPL-2.0-or-later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: your-people
*
* @package block-developers-cookbook
*/
namespace BlockDevelopersCookbook;
/**
* Register the 'person' custom post type.
*/
function register_person_post_type() {
$labels = array(
'name' => _x( 'People', 'Post type general name', 'your-people' ),
'singular_name' => _x( 'Person', 'Post type singular name', 'your-people' ),
'menu_name' => _x( 'People', 'Admin Menu text', 'your-people' ),
'name_admin_bar' => _x( 'Person', 'Add New on Toolbar', 'your-people' ),
'add_new' => __( 'Add New Person', 'your-people' ),
'add_new_item' => __( 'Add New Person', 'your-people' ),
'new_item' => __( 'New Person', 'your-people' ),
'edit_item' => __( 'Edit Person', 'your-people' ),
'view_item' => __( 'View Person', 'your-people' ),
'all_items' => __( 'All People', 'your-people' ),
'search_items' => __( 'Search People', 'your-people' ),
'not_found' => __( 'No people found.', 'your-people' ),
'not_found_in_trash' => __( 'No people found in Trash.', 'your-people' ),
'featured_image' => _x( 'Person Profile Image', 'Overrides the "Featured Image" phrase', 'your-people' ),
'set_featured_image' => _x( 'Set profile image', 'Overrides the "Set featured image" phrase', 'your-people' ),
'remove_featured_image' => _x( 'Remove profile image', 'Overrides the "Remove featured image" phrase', 'your-people' ),
'use_featured_image' => _x( 'Use as profile image', 'Overrides the "Use as featured image" phrase', 'your-people' ),
);
$args = array(
'labels' => $labels,
'public' => true,
'has_archive' => 'people',
'hierarchical' => false,
'menu_icon' => 'dashicons-groups',
'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt', 'custom-fields' ),
'show_in_rest' => true,
);
register_post_type( 'person', $args );
}
add_action( 'init', __NAMESPACE__ . '\register_person_post_type' );
/**
* Register the 'role' taxonomy for the 'person' post type.
*/
function register_role_taxonomy() {
$labels = array(
'name' => _x( 'Roles', 'taxonomy general name', 'your-people' ),
'singular_name' => _x( 'Role', 'taxonomy singular name', 'your-people' ),
'search_items' => __( 'Search Roles', 'your-people' ),
'all_items' => __( 'All Roles', 'your-people' ),
'parent_item' => __( 'Parent Role', 'your-people' ),
'parent_item_colon' => __( 'Parent Role:', 'your-people' ),
'edit_item' => __( 'Edit Role', 'your-people' ),
'update_item' => __( 'Update Role', 'your-people' ),
'add_new_item' => __( 'Add New Role', 'your-people' ),
'new_item_name' => __( 'New Role Name', 'your-people' ),
'menu_name' => __( 'Role', 'your-people' ),
);
$args = array(
'labels' => $labels,
'show_admin_column' => true,
'query_var' => true,
'rewrite' => array( 'slug' => 'role' ),
'show_in_rest' => true,
);
register_taxonomy( 'role', array( 'person' ), $args );
}
add_action( 'init', __NAMESPACE__ . '\register_role_taxonomy' );
/**
* Register custom meta fields for the 'person' post type.
*/
function register_person_meta() {
register_post_meta(
'person',
'yp_job_title',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'label' => __( 'Job Title', 'your-people' ),
'description' => __( 'The person\'s job title', 'your-people' ),
'sanitize_callback' => 'wp_strip_all_tags'
)
);
register_post_meta(
'person',
'yp_institution',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'label' => __( 'Institution/Employer', 'your-people' ),
'description' => __( 'The person\'s institution or employer', 'your-people' ),
'sanitize_callback' => 'wp_strip_all_tags'
)
);
register_post_meta(
'person',
'yp_location',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'label' => __( 'Location', 'your-people' ),
'description' => __( 'The person\'s location', 'your-people' ),
'sanitize_callback' => 'wp_strip_all_tags'
)
);
register_post_meta(
'person',
'yp_website_url',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'label' => __( 'Website', 'your-people' ),
'description' => __( 'The person\'s website', 'your-people' ),
'sanitize_callback' => 'wp_strip_all_tags'
)
);
register_post_meta(
'person',
'yp_linkedin_url',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'label' => __( 'LinkedIn URL', 'your-people' ),
'description' => __( 'The person\'s LinkedIn URL', 'your-people' ),
'sanitize_callback' => 'wp_strip_all_tags'
)
);
}
add_action( 'init', __NAMESPACE__ . '\register_person_meta' );
/**
* Register the plugin templates.
*/
function register_plugin_templates() {
// Register your custom templates here.
register_block_template( 'your-people//single-person', [
'title' => __( 'Single Person', 'your-people' ),
'description' => __( 'Displays a single person\'s profile page.', 'your-people' ),
'content' => get_template_content( 'single-person.php' )
] );
}
add_action( 'init', __NAMESPACE__ . '\register_plugin_templates' );
* Helper function to get the content of a template file.
*
* @param string $template The name of the template file.
* @return string The content of the template file.
*/
function get_template_content( $template ) {
ob_start();
include plugin_dir_path( __FILE__ ) . "/templates/{$template}";
return ob_get_clean();
}
// Include some files we need
require_once __DIR__ . '/includes/admin.php';
require_once __DIR__ . '/includes/editor.php';
This change will register the template and uses the `get_template_content` helper function to retrieve the content from the PHP files and assign it to the template.
Save the file and navigate to the Templates section of the site editor to see your new template!

The last step is to add an Archive template for the Person post type and a template for the Role taxonomy
<?php
/**
* Plugin Name: Your People
* Description: Create a custom block to display team members or staff.
* Requires at least: 6.1
* Requires PHP: 7.0
* Version: 1.0.0
* Author: The WordPress Contributors
* License: GPL-2.0-or-later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: your-people
*
* @package block-developers-cookbook
*/
namespace BlockDevelopersCookbook;
/**
* Register the 'person' custom post type.
*/
function register_person_post_type() {
$labels = array(
'name' => _x( 'People', 'Post type general name', 'your-people' ),
'singular_name' => _x( 'Person', 'Post type singular name', 'your-people' ),
'menu_name' => _x( 'People', 'Admin Menu text', 'your-people' ),
'name_admin_bar' => _x( 'Person', 'Add New on Toolbar', 'your-people' ),
'add_new' => __( 'Add New Person', 'your-people' ),
'add_new_item' => __( 'Add New Person', 'your-people' ),
'new_item' => __( 'New Person', 'your-people' ),
'edit_item' => __( 'Edit Person', 'your-people' ),
'view_item' => __( 'View Person', 'your-people' ),
'all_items' => __( 'All People', 'your-people' ),
'search_items' => __( 'Search People', 'your-people' ),
'not_found' => __( 'No people found.', 'your-people' ),
'not_found_in_trash' => __( 'No people found in Trash.', 'your-people' ),
'featured_image' => _x( 'Person Profile Image', 'Overrides the "Featured Image" phrase', 'your-people' ),
'set_featured_image' => _x( 'Set profile image', 'Overrides the "Set featured image" phrase', 'your-people' ),
'remove_featured_image' => _x( 'Remove profile image', 'Overrides the "Remove featured image" phrase', 'your-people' ),
'use_featured_image' => _x( 'Use as profile image', 'Overrides the "Use as featured image" phrase', 'your-people' ),
);
$args = array(
'labels' => $labels,
'public' => true,
'has_archive' => 'people',
'hierarchical' => false,
'menu_icon' => 'dashicons-groups',
'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt', 'custom-fields' ),
'show_in_rest' => true,
);
register_post_type( 'person', $args );
}
add_action( 'init', __NAMESPACE__ . '\register_person_post_type' );
/**
* Register the 'role' taxonomy for the 'person' post type.
*/
function register_role_taxonomy() {
$labels = array(
'name' => _x( 'Roles', 'taxonomy general name', 'your-people' ),
'singular_name' => _x( 'Role', 'taxonomy singular name', 'your-people' ),
'search_items' => __( 'Search Roles', 'your-people' ),
'all_items' => __( 'All Roles', 'your-people' ),
'parent_item' => __( 'Parent Role', 'your-people' ),
'parent_item_colon' => __( 'Parent Role:', 'your-people' ),
'edit_item' => __( 'Edit Role', 'your-people' ),
'update_item' => __( 'Update Role', 'your-people' ),
'add_new_item' => __( 'Add New Role', 'your-people' ),
'new_item_name' => __( 'New Role Name', 'your-people' ),
'menu_name' => __( 'Role', 'your-people' ),
);
$args = array(
'labels' => $labels,
'show_admin_column' => true,
'query_var' => true,
'rewrite' => array( 'slug' => 'role' ),
'show_in_rest' => true,
);
register_taxonomy( 'role', array( 'person' ), $args );
}
add_action( 'init', __NAMESPACE__ . '\register_role_taxonomy' );
/**
* Register custom meta fields for the 'person' post type.
*/
function register_person_meta() {
register_post_meta(
'person',
'yp_job_title',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'label' => __( 'Job Title', 'your-people' ),
'description' => __( 'The person\'s job title', 'your-people' ),
'sanitize_callback' => 'wp_strip_all_tags'
)
);
register_post_meta(
'person',
'yp_institution',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'label' => __( 'Institution/Employer', 'your-people' ),
'description' => __( 'The person\'s institution or employer', 'your-people' ),
'sanitize_callback' => 'wp_strip_all_tags'
)
);
register_post_meta(
'person',
'yp_location',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'label' => __( 'Location', 'your-people' ),
'description' => __( 'The person\'s location', 'your-people' ),
'sanitize_callback' => 'wp_strip_all_tags'
)
);
register_post_meta(
'person',
'yp_website_url',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'label' => __( 'Website', 'your-people' ),
'description' => __( 'The person\'s website', 'your-people' ),
'sanitize_callback' => 'wp_strip_all_tags'
)
);
register_post_meta(
'person',
'yp_linkedin_url',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'label' => __( 'LinkedIn URL', 'your-people' ),
'description' => __( 'The person\'s LinkedIn URL', 'your-people' ),
'sanitize_callback' => 'wp_strip_all_tags'
)
);
}
add_action( 'init', __NAMESPACE__ . '\register_person_meta' );
/**
* Register the plugin templates.
*/
function register_plugin_templates() {
// Register your custom templates here.
register_block_template( 'your-people//single-person', [
'title' => __( 'Single Person', 'your-people' ),
'description' => __( 'Displays a single person\'s profile page.', 'your-people' ),
'content' => get_template_content( 'single-person.php' )
] );
register_block_template( 'your-people//archive-person', [
'title' => __( 'Archive Person', 'your-people' ),
'description' => __( 'Displays a list of people.', 'your-people' ),
'content' => get_template_content( 'archive-person.php' )
] );
register_block_template( 'your-people//taxonomy-role', [
'title' => __( 'Role Archive', 'your-people' ),
'description' => __( 'Displays a list of people in a specific role.', 'your-people' ),
'content' => get_template_content( 'taxonomy-role.php' )
] );
}
add_action( 'init', __NAMESPACE__ . '\register_plugin_templates' );
/**
* Helper function to get the content of a template file.
*
* @param string $template The name of the template file.
* @return string The content of the template file.
*/
function get_template_content( $template ) {
ob_start();
include plugin_dir_path( __FILE__ ) . "/templates/{$template}";
return ob_get_clean();
}
// Include some files we need
require_once __DIR__ . '/includes/admin.php';
require_once __DIR__ . '/includes/editor.php';
Great job! Order up!