-
Notifications
You must be signed in to change notification settings - Fork 51
Description
Is your enhancement related to a problem? Please describe.
All new 10up projects are based on this repo, but there is very little PHP scaffolding in place. This means that each different project ends up with a slightly different implementation for post types, taxonomies, REST endpoints etc.
This has two effects:
- Slows down the initial setup of a project, as the tech lead has to put these scaffolds in place.
- Increases the cognitive load for engineers that are switching between projects, as they have to learn the differences in setups.
Designs
Since the auto-initialisation of modules was merged in #158, it's allowed us to create much more modular scaffolds, with no requirement for factory classes etc.
I propose introducing abstract classes that contain all the base information needed to register a CPT/Taxonomy, which can then be extended to implement project-specific ones.
For example, the following abstract post type would then allow us to easily implement further ones:
<?php
/**
* AbstractPostType
*
* @package TenUpPlugin
*/
namespace TenUpPlugin\PostTypes;
use TenUpPlugin\Module;
/**
* Abstract class for post types.
*/
abstract class AbstractPostType extends Module {
/**
* Get the post type name.
*
* @return string
*/
abstract public function get_name();
/**
* Get the singular post type label.
*
* @return string
*/
abstract public function get_singular_label();
/**
* Get the plural post type label.
*
* @return string
*/
abstract public function get_plural_label();
/**
* Default post type supported feature names.
*
* @return array
*/
public function get_editor_supports() {
$supports = [
'title',
'editor',
'author',
'thumbnail',
'excerpt',
'revisions',
];
return $supports;
}
/**
* Get the options for the post type.
*
* @return array
*/
public function get_options() {
$options = [
'labels' => $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(),
];
return $options;
}
/**
* 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 = array(
'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.
}
}To implement a project-specific CPT, we'd then do something like:
<?php
/**
* Demo Post Type
*
* @package TenUpPlugin
*/
namespace TenUpPlugin\PostTypes;
/**
* Demo post type.
*/
class Demo extends AbstractPostType {
/**
* Get the post type name.
*
* @return string
*/
public function get_name() {
return 'tenup-demo';
}
/**
* Get the singular post type label.
*
* @return string
*/
public function get_singular_label() {
return esc_html__( 'Demo', 'tenup-plugin' );
}
/**
* Get the plural post type label.
*
* @return string
*/
public function get_plural_label() {
return esc_html__( 'Demos', 'tenup-plugin' );
}
/**
* Can the class be registered?
*
* @return bool
*/
public function can_register() {
return true;
}
/**
* Supported post type features.
*
* @return array
*/
public function get_editor_supports() {
return [
'title',
'editor',
'thumbnail',
'page-attributes',
'excerpt',
'revisions',
'custom-fields',
];
}
/**
* Get the options for the post type.
*
* @return array
*/
public function get_options() {
return array_merge(
parent::get_options(),
[
'hierarchical' => false,
'rewrite' => [
'slug' => 'demo',
],
]
);
}
/**
* 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 [
'tenup-tax-demo',
];
}
}Due to the fact that we have auto-initializing modules, the engineer would only need to create the sub-class and fill it out. There's no need to add anything to a factory, meaning less merge conflicts.
We can also do something very similar for taxonomies.
This solution would provide engineers with:
- A standardised, extendable way to register post types
- A pre-existing scaffold within the repo
- Loss cognitive overhead when switching between projects.
It also gives us a nice lead-in to creating a tool to help scaffold these items quickly, much like has been proposed in #89
Describe alternatives you've considered
Darshan has also submitted #104. I don't feel like this is an alternative to that approach, but it could be complimentary to it by proving a start for that modular scaffold.
Code of Conduct
- I agree to follow this project's Code of Conduct