diff --git a/web/app/mu-plugins/nebula-core/includes/classes/Contracts/PostType.php b/web/app/mu-plugins/nebula-core/includes/classes/Contracts/PostType.php index 96d17f4..b80b20a 100644 --- a/web/app/mu-plugins/nebula-core/includes/classes/Contracts/PostType.php +++ b/web/app/mu-plugins/nebula-core/includes/classes/Contracts/PostType.php @@ -53,70 +53,142 @@ * @return PostType */ abstract class PostType implements Bootable { + /** * Post type name. * * @var string */ - protected $post_type; + protected string $post_type; /** - * Post type arguments. + * Boot method from Bootable interface * - * @var array + * @return void */ - protected $args = []; + public function boot(): void { + add_action( 'init', [ $this, 'register_post_type' ] ); + add_action( 'init', [ $this, 'register_post_type_meta' ] ); + add_action( 'rest_api_init', [ $this, 'register_post_type_rest_routes' ] ); + } /** - * Post type names. + * Post types can be booted by default. * - * @var array + * @return bool */ - protected $names = []; + public function can_boot(): bool { + return true; + } /** - * Boots the class by running `add_action()` and `add_filter()` calls. + * Get post type name. * - * @return void + * @return string */ - public function boot(): void { - add_action( 'init', [ $this, 'register' ] ); + abstract public function get_name(): string; + + /** + * Get post type singular label. + * + * @return string + */ + abstract public function get_singular_label(): string; + + /** + * Get post type plural label. + * + * @return string + */ + abstract public function get_plural_label(): string; + + /** + * Get post type menu icon. + * + * @return string + */ + abstract public function get_menu_icon(): string; + + /** + * Editor supports. + * + * @return array + */ + abstract public function get_editor_supports(): array; + + /** + * Post type options configuration. + * + * @return array + */ + protected function get_options(): array { + return [ + 'menu_icon' => $this->get_menu_icon(), + 'supports' => $this->get_editor_supports(), + 'show_in_rest' => true, + 'public' => true, + ]; } /** - * Determines if the class can be booted. + * Post type labels configuration. * - * @return bool + * @return array */ - public function can_boot(): bool { - return true; + protected function get_labels(): array { + return [ + 'singular' => $this->get_singular_label(), + 'plural' => $this->get_plural_label(), + 'slug' => $this->get_name(), + ]; + } + + /** + * Register post type using Extended CPTs. + */ + public function register_post_type(): void { + register_extended_post_type( + $this->get_name(), + $this->get_options(), + $this->get_labels() + ); } /** - * Validate the post type name format. + * Automatically register meta fields from child class. + */ + public function register_post_type_meta(): void { + foreach ( $this->get_custom_post_meta() as $meta_key => $meta_args ) { + register_post_meta( $this->get_name(), $meta_key, $meta_args ); + } + } + + /** + * Register REST routes. * - * @param string $post_type The post type name. * @return void - * @throws Exception If the taxonomy name is invalid. */ - protected function validate( string $post_type ): void { - if ( ! preg_match( '/^[a-z_]+$/', $post_type ) ) { - throw new Exception( 'Invalid post type name: ' . esc_html( $post_type ) . '. Must be lowercase, contain no spaces or hyphens, and underscores between words.' ); + public function register_post_type_rest_routes(): void { + foreach ( $this->get_custom_rest_routes() as $route ) { + register_rest_route( $route['namespace'], $route['route'], $route['args'] ); } } /** - * Register the post type. + * Get custom post meta. * - * @return void + * @return array */ - public function register(): void { - $this->validate( $this->post_type ); + public function get_custom_post_meta(): array { + return []; + } - register_extended_post_type( - $this->post_type, - $this->args, - $this->names - ); + /** + * Child class can override this to provide REST route definitions. + * + * @return array + */ + public function get_custom_rest_routes(): array { + return []; } }