diff --git a/docs/creating-post-types-and-taxonomies.md b/docs/creating-post-types-and-taxonomies.md new file mode 100644 index 00000000..5302f1fb --- /dev/null +++ b/docs/creating-post-types-and-taxonomies.md @@ -0,0 +1,271 @@ +# Creating Post Types and Taxonomies in the MU-Plugin + +The MU plugin contains abstract classses that can be extended to easily register new post types and taxonomies. This document will explain how to use these classes to create new post types and taxonomies. + +If you want to jump right in, take a look at the `TenUpPlugin\PostTypes\Demo::class` and `TenUpPlugin\Taxonomies\Demo::class` classes. + + +## Post Types + +To create a new post type, you will need to create a new class that extends the `TenUpPlugin\PostTypes\AbstractPostType` class. This class will contain the configuration for the new post type. + +Once you've extended the class (or copied the `Demo` class), you will need to define the following methods: + +- `get_name()` - This should return the name of the post type as it will be used within the WordPress database. +- `get_singular_label()` - This should return the singular label for the post type. +- `get_plural_label()` - This should return the plural label for the post type. +- `get_menu_icon()` - This should return the dashicon to use for the post type in the WordPress admin menu, it can also return a base64 encoded SVG or the string `'none'`. +- `can_register()` - Whether the post type should be actively registered or not. See [Registering Classes](./registering-classes.md). + +Once those are defined, ensure that `can_register()` is returning `true` and you should be able to see your post type within the admin. + +### Hierarchical Post Types + +Should you need to create a hierarchical post type, you can override the `is_hierarchical()` method and return `true`. + +```php +/** + * Is the post type hierarchical? + * + * @return bool + */ +public function is_hierarchical() { + return true; +} +``` + +### Changing the Post Supports + +There are a few options that can exist within [post supports](https://developer.wordpress.org/reference/functions/register_post_type/#parameters:~:text=handling.%0ADefault%20false.-,supports,-array), the scaffold aims to set sensible defaults but sometimes they will need changing. There are two ways to do this: + +a. Override the `get_editor_supports()` method and return an array of the supports you want to enable. + +```php +/** + * Default post type supported feature names. + * + * @return array + */ +public function get_editor_supports() { + $supports = [ + 'title', + 'editor', + 'thumbnail', + 'custom-fields', + ]; + + return $supports; +} +``` +b. Merge your additional supports into the base version + +```php +/** + * Default post type supported feature names. + * + * @return array + */ +public function get_editor_supports() { + $supports = parent::get_editor_supports(); + $supports[] = 'custom-fields'; + + return $supports; +} +``` + +### Changing Post Type Options + +Much like with the Supports, the scaffold aims to set sensible defaults for the post type options. Should you want to change these, you can handle it in much the same way: + +a. Override the `get_options()` method and return an array of the options you want to enable. + +```php +/** + * Default post type supported feature names. + * + * @return array + */ +public function get_options() { + $options = [ + 'labels' => $this->get_labels(), + 'public' => false, + 'has_archive' => false, + 'show_ui' => true, + 'show_in_menu' => true, + 'show_in_nav_menus' => false, + 'show_in_rest' => true, + 'supports' => $this->get_editor_supports(), + 'menu_icon' => $this->get_menu_icon(), + 'menu_position' => $this->get_menu_position(), + 'hierarchical' => $this->is_hierarchical(), + ]; + + return $options; +} +``` +b. Merge your additional options into the base version + +```php +/** + * Default post type supported feature names. + * + * @return array + */ +public function get_options() { + $options = parent::get_options(); + $options['public'] = false; + $options['has_archive'] = false; + + return $options; +} +``` + +### Adding Taxonomies to a Post Type + +To add a taxonomy to a post type, you'll need to override the `get_supported_taxonomies()` method on the post type class and return an array of taxonomies you'd like to support. + +E.G. + +```php +/** + * Returns the default supported taxonomies. The subclass should declare the + * Taxonomies that it supports here if required. + * + * @return array + */ +public function get_supported_taxonomies() { + return [ + 'category', + 'post_tag', + ]; +} +``` + +### Registering Post Meta + +Whilst there is no official way to register post meta, the scaffold provides an `after_register()` method that's called after the post type is registered. + +A useful pattern is: + +```php +/** + * Run any code after the post type has been registered. + * + * @return void + */ +public function after_register() { + register_post_meta( + $this->get_name(), + 'my_test_meta_key', + [ + 'show_in_rest' => true, + 'single' => true, + 'type' => 'string', + ] + ); +} +``` + +The `after_register()` method can also be useful to hook into anything else you may need to do, directly related to the registration of the post type. + +## Taxonomies + +To create a new taxonomy, you will need to create a new class that extends the `TenUpPlugin\Taxonomies\AbstractTaxonomy` class. This class will contain the configuration for the new taxonomy. + +Once you've extended the class (or copied the `Demo` class), you will need to define the following methods: + +- `get_name()` - This should return the name of the taxonomy as it will be used within the WordPress database. +- `get_singular_label()` - This should return the singular label for the taxonomy. +- `get_plural_label()` - This should return the plural label for the taxonomy. +- `can_register()` - Whether the taxonomy should be actively registered or not. See [Registering Classes](./registering-classes.md). + +Once those are defined, ensure that `can_register()` is returning `true` and that you've [registered the taxonomy with a post type](#adding-taxonomies-to-a-post-type), then you should be able to see your taxonomy within the admin. + +### Hierarchical Taxonomies + +Should you need to create a hierarchical taxonomy, you can override the `is_hierarchical()` method and return `true`. + +```php +/** + * Is the taxonomy hierarchical? + * + * @return bool + */ +public function is_hierarchical() { + return true; +} +``` + +### Changing the Taxonomy Options + +The scaffold aims to set sensible defaults for the taxonomy options. Should you want to change these, you can handle it in much the same way as post types: + +a. Override the `get_options()` method and return an array of the options you want to enable. + +```php +/** + * Get the options for the taxonomy. + * + * @return array + */ +public function get_options() { + $options = [ + 'labels' => $this->get_labels(), + 'hierarchical' => $this->is_hierarchical(), + 'show_ui' => true, + 'show_admin_column' => true, + 'query_var' => true, + 'show_in_rest' => true, + 'public' => true, + ]; + + return $options; +} +``` +b. Merge your additional options into the base version + +```php +/** + * Get the options for the taxonomy. + * + * @return array + */ +public function get_options() { + $options = parent::get_options(); + $options['public'] = false; + + return $options; +} +``` + +### Registering Taxonomy Meta + +Whilst there is no official way to register taxonomy meta, the scaffold provides an `after_register()` method that's called after the taxonomy is registered. + +A useful pattern is: + +```php +/** + * Run any code after the taxonomy has been registered. + * + * @return void + */ +public function after_register() { + register_term_meta( + $this->get_name(), + 'my_test_meta_key', + [ + 'show_in_rest' => true, + 'single' => true, + 'type' => 'string', + ] + ); +} +``` + +## Further Information + +I encourage you to look at the abstract post classes, whilst they aim to provide a sensible set of defaults, everything within them can be overidden, should it need to be. + +If you find yourself making the same changes across multiple classes or projects, please consider [opening a ticket](https://github.com/10up/wp-scaffold/issues/new?assignees=&labels=type%3Aenhancement&projects=&template=2-enhancement.yml) which describes those changes. +That way we can look at updating the scaffold to help others in the future. diff --git a/mu-plugins/10up-plugin/includes/classes/PostTypes/AbstractCorePostType.php b/mu-plugins/10up-plugin/includes/classes/PostTypes/AbstractCorePostType.php new file mode 100644 index 00000000..0cf8e423 --- /dev/null +++ b/mu-plugins/10up-plugin/includes/classes/PostTypes/AbstractCorePostType.php @@ -0,0 +1,75 @@ +get_name() to get the post's type name. + * @return Bool Whether this theme has supports for this post type. + */ + public function register() { + $this->register_taxonomies(); + $this->after_register(); + + return true; + } +} diff --git a/mu-plugins/10up-plugin/includes/classes/PostTypes/AbstractPostType.php b/mu-plugins/10up-plugin/includes/classes/PostTypes/AbstractPostType.php new file mode 100644 index 00000000..04b20b8c --- /dev/null +++ b/mu-plugins/10up-plugin/includes/classes/PostTypes/AbstractPostType.php @@ -0,0 +1,241 @@ + $this->get_labels(), + 'public' => true, + 'has_archive' => true, + 'show_ui' => true, + 'show_in_menu' => true, + 'show_in_nav_menus' => false, + 'show_in_rest' => true, + 'supports' => $this->get_editor_supports(), + 'menu_icon' => $this->get_menu_icon(), + 'menu_position' => $this->get_menu_position(), + 'hierarchical' => $this->is_hierarchical(), + ]; + } + + /** + * Get the labels for the post type. + * + * @return array + */ + public function get_labels() { + $plural_label = $this->get_plural_label(); + $singular_label = $this->get_singular_label(); + + // phpcs:disable -- ignoring template strings without translators placeholder since this is dynamic + $labels = [ + 'name' => $plural_label, + // Already translated via get_plural_label(). + 'singular_name' => $singular_label, + // Already translated via get_singular_label(). + 'add_new_item' => sprintf( __( 'Add New %s', 'tenup-plugin' ), $singular_label ), + 'edit_item' => sprintf( __( 'Edit %s', 'tenup-plugin' ), $singular_label ), + 'new_item' => sprintf( __( 'New %s', 'tenup-plugin' ), $singular_label ), + 'view_item' => sprintf( __( 'View %s', 'tenup-plugin' ), $singular_label ), + 'view_items' => sprintf( __( 'View %s', 'tenup-plugin' ), $plural_label ), + 'search_items' => sprintf( __( 'Search %s', 'tenup-plugin' ), $plural_label ), + 'not_found' => sprintf( __( 'No %s found.', 'tenup-plugin' ), strtolower( $plural_label ) ), + 'not_found_in_trash' => sprintf( __( 'No %s found in Trash.', 'tenup-plugin' ), strtolower( $plural_label ) ), + 'parent_item_colon' => sprintf( __( 'Parent %s:', 'tenup-plugin' ), $plural_label ), + 'all_items' => sprintf( __( 'All %s', 'tenup-plugin' ), $plural_label ), + 'archives' => sprintf( __( '%s Archives', 'tenup-plugin' ), $singular_label ), + 'attributes' => sprintf( __( '%s Attributes', 'tenup-plugin' ), $singular_label ), + 'insert_into_item' => sprintf( __( 'Insert into %s', 'tenup-plugin' ), strtolower( $singular_label ) ), + 'uploaded_to_this_item' => sprintf( __( 'Uploaded to this %s', 'tenup-plugin' ), strtolower( $singular_label ) ), + 'filter_items_list' => sprintf( __( 'Filter %s list', 'tenup-plugin' ), strtolower( $plural_label ) ), + 'items_list_navigation' => sprintf( __( '%s list navigation', 'tenup-plugin' ), $plural_label ), + 'items_list' => sprintf( __( '%s list', 'tenup-plugin' ), $plural_label ), + 'item_published' => sprintf( __( '%s published.', 'tenup-plugin' ), $singular_label ), + 'item_published_privately' => sprintf( __( '%s published privately.', 'tenup-plugin' ), $singular_label ), + 'item_reverted_to_draft' => sprintf( __( '%s reverted to draft.', 'tenup-plugin' ), $singular_label ), + 'item_scheduled' => sprintf( __( '%s scheduled.', 'tenup-plugin' ), $singular_label ), + 'item_updated' => sprintf( __( '%s updated.', 'tenup-plugin' ), $singular_label ), + 'menu_name' => $plural_label, + 'name_admin_bar' => $singular_label, + ]; + // phpcs:enable + + return $labels; + } + + /** + * Registers a post type and associates its taxonomies. + * + * @uses $this->get_name() to get the post's type name. + * @return Bool Whether this theme has supports for this post type. + */ + public function register() { + $this->register_post_type(); + $this->register_taxonomies(); + + $this->after_register(); + + return true; + } + + /** + * Registers the current post type with WordPress. + * + * @return void + */ + public function register_post_type() { + register_post_type( + $this->get_name(), + $this->get_options() + ); + } + + /** + * Registers the taxonomies declared with the current post type. + * + * @return void + */ + public function register_taxonomies() { + $taxonomies = $this->get_supported_taxonomies(); + + $object_type = $this->get_name(); + + if ( ! empty( $taxonomies ) ) { + foreach ( $taxonomies as $taxonomy ) { + register_taxonomy_for_object_type( + $taxonomy, + $object_type + ); + } + } + } + + /** + * Returns the default supported taxonomies. The subclass should declare the + * Taxonomies that it supports here if required. + * + * @return array + */ + public function get_supported_taxonomies() { + return []; + } + + /** + * Run any code after the post type has been registered. + * + * @return void + */ + public function after_register() { + // Do nothing. + } +} diff --git a/mu-plugins/10up-plugin/includes/classes/PostTypes/Demo.php b/mu-plugins/10up-plugin/includes/classes/PostTypes/Demo.php new file mode 100644 index 00000000..2435bd72 --- /dev/null +++ b/mu-plugins/10up-plugin/includes/classes/PostTypes/Demo.php @@ -0,0 +1,84 @@ +get_name() to get the taxonomy's slug. + * @return bool + */ + public function register() { + \register_taxonomy( + $this->get_name(), + $this->get_post_types(), + $this->get_options() + ); + + $this->after_register(); + + return true; + } + + /** + * Get the options for the taxonomy. + * + * @return array + */ + public function get_options() { + return [ + 'labels' => $this->get_labels(), + 'hierarchical' => $this->is_hierarchical(), + 'show_ui' => true, + 'show_admin_column' => true, + 'query_var' => true, + 'show_in_rest' => true, + 'public' => true, + ]; + } + + /** + * Get the labels for the taxonomy. + * + * @return array + */ + public function get_labels() { + $plural_label = $this->get_plural_label(); + $singular_label = $this->get_singular_label(); + + // phpcs:disable + $labels = [ + 'name' => $plural_label, // Already translated via get_plural_label(). + 'singular_name' => $singular_label, // Already translated via get_singular_label(). + 'search_items' => sprintf( __( 'Search %s', 'tenup-plugin' ), $plural_label ), + 'popular_items' => sprintf( __( 'Popular %s', 'tenup-plugin' ), $plural_label ), + 'all_items' => sprintf( __( 'All %s', 'tenup-plugin' ), $plural_label ), + 'edit_item' => sprintf( __( 'Edit %s', 'tenup-plugin' ), $singular_label ), + 'update_item' => sprintf( __( 'Update %s', 'tenup-plugin' ), $singular_label ), + 'add_new_item' => sprintf( __( 'Add %s', 'tenup-plugin' ), $singular_label ), + 'new_item_name' => sprintf( __( 'New %s Name', 'tenup-plugin' ), $singular_label ), + 'separate_items_with_commas' => sprintf( __( 'Separate %s with commas', 'tenup-plugin' ), strtolower( $plural_label ) ), + 'add_or_remove_items' => sprintf( __( 'Add or remove %s', 'tenup-plugin' ), strtolower( $plural_label ) ), + 'choose_from_most_used' => sprintf( __( 'Choose from the most used %s', 'tenup-plugin' ), strtolower( $plural_label ) ), + 'not_found' => sprintf( __( 'No %s found.', 'tenup-plugin' ), strtolower( $plural_label ) ), + 'not_found_in_trash' => sprintf( __( 'No %s found in Trash.', 'tenup-plugin' ), strtolower( $plural_label ) ), + 'view_item' => sprintf( __( 'View %s', 'tenup-plugin' ), $singular_label ), + ]; + // phpcs:enable + + return $labels; + } + + /** + * Setting the post types to null to ensure no post type is registered with + * this taxonomy. Post Type classes declare their supported taxonomies. + * + * @return array|null + */ + public function get_post_types() { + return null; + } + + /** + * Run any code after the taxonomy has been registered. + * + * @return void + */ + public function after_register() { + // Do nothing. + } +} diff --git a/mu-plugins/10up-plugin/includes/classes/Taxonomies/Demo.php b/mu-plugins/10up-plugin/includes/classes/Taxonomies/Demo.php new file mode 100644 index 00000000..917f3a2a --- /dev/null +++ b/mu-plugins/10up-plugin/includes/classes/Taxonomies/Demo.php @@ -0,0 +1,50 @@ +