slug = $slug; $this->type = $type; $this->singular = $singular; $this->plural = $plural; // $this->init(); // $this->initClasses(); $this->setFields(); add_action('init', [$this, 'register'], 0); add_filter('jvbDashboardPage', [$this, 'renderDashPage'], 10, 3); } protected function initRegistrar():void { $this->registrar = match ($this->type) { 'post' => new Posts($this->slug, $this->singular, $this->plural), 'term' => new Terms($this->slug, $this->singular, $this->plural), default => false, }; } protected function initClasses():void { $this->breadcrumbs = new Breadcrumbs($this->slug); $this->dashboard = new Dashboard($this->slug); $this->directory = new Directory($this->singular); $this->feed = new Feed($this->slug); // $this->management = new Management($this->slug); // $this->responses = new Responses($this->slug); $this->seo = new SEO($this->slug); // $this->trackChanges = new TrackChanges($this->slug); // $this->Verification = new Verification($this->slug); } /** * Instantiates for post types * @param string $slug * @return self */ public static function forPost(string $slug, string $singular, string $plural):self { if (!isset(self::$instances[$slug])) { self::$instances[$slug] = new self($slug, $singular, $plural,'post'); } return self::$instances[$slug]; } /** * Instantiates for term types * @param string $slug * @return self */ public static function forTerm(string $slug, string $singular, string $plural):self { if (!isset(self::$instances[$slug])) { self::$instances[$slug] = new self($slug, $singular, $plural,'term'); } return self::$instances[$slug]; } /** * Instantiates for user types * @param string $slug * @return self */ public static function forUser(string $slug, string $singular, string $plural):self { if (!isset(self::$instances[$slug])) { self::$instances[$slug] = new self($slug, $singular, $plural, 'user'); } return self::$instances[$slug]; } /** * Adds the properties for register_post_type or register_taxonomy * @param array $args * @return $this */ public function make(array $args):self { $this->initRegistrar(); if (!$this->registrar) { return $this; } $this->args = $args; foreach ($args as $property => $value) { $this->registrar->$property = $value; } if (isset($this->icon) && !str_contains($this->icon, 'dashicons')){ $this->registrar->menu_icon = IconsManager::for()->getCSSIcon($this->icon); } return $this; } public function fields():Fields { return $this->fields; } public function args():array { return $this->args; } public function setFields():void { $this->fields = new Fields($this->type, $this); } public function getFields():array { return array_map(function ($field) { return $field->getConfig(); }, $this->fields->getFields() ); } public function setIcon(string $icon):self { $this->icon = $icon; return $this; } public function getIcon(?string $default = null):string { if (!$default) { $default = jvbDefaultIcon(); } return $this->icon ?: $default; } public function getSingular():string { return $this->singular; } public function getPlural():string { return $this->plural; } public function getDescription():string { return $this->description; } public function setDescription(string $description):self { $this->description = $description; return $this; } public function getType():string { return $this->type; } public function setIntegration(string $integration):self { if (!Features::forSite()->has($integration)){ error_log('Integration not available for '.$this->slug.': '.$integration); return $this; } $this->integrationConfigs[$integration] = new Integration($integration, $this); $this->integrationFields[$integration] = new AddIntegrationFields($integration, $this); return $this; } public function getIntegrationFields(string $integration):AddIntegrationFields|false { if (!Features::forSite()->has($integration)){ error_log('Integration not available for '.$this->slug.': '.$integration); return false; } if (!in_array($integration, $this->integrationFields)) { error_log('No integration fields intitialized for '.$integration); return false; } return $this->integrationFields[$integration]; } public function getIntegrations():array { return $this->integrationConfigs; } public function hasIntegration(string $integration) { return in_array($integration, $this->integrationConfigs); } public function setUploadTitle(string $title):self { $this->upload_title = $title; return $this; } public function getUploadTitle():string { return ($this->upload_title) ?: 'Upload '.$this->plural; } public function getSlug():string { return $this->slug; } public function setTimeline(bool $set):self { $this->is_timeline = $set; // if ($set) { // $this->timeline = new MakeTimelineType($this->slug, $this); // } return $this; } public function isTimeline():bool { return $this->is_timeline; } public function setCalendar(bool $set):self { $this->is_calendar = $set; if ($set) { $this->calendar = new MakeCalendarType($this->slug, $this); } return $this; } public function setAll(array $flags):self { $flags = array_filter($flags, function($flag) { return in_array($flag, static::$allFlags); }); foreach ($flags as $flag) { $this->$flag = true; switch ($flag) { case 'is_content': add_action('init', [$this, 'setupContent'], 20); break; } } return $this; } public function removeAll(array $flags):self { $flags = array_filter($flags, function($flag) { return in_array($flag, static::$allFlags); }); foreach ($flags as $flag) { $this->$flag = false; } return $this; } public function hasFeature(string $feature):bool { if (!in_array($feature, static::$allFlags)) { return false; } return isset($this->$feature) && $this->$feature === true; } public static function getFeatured(string $feature, ?string $type = null):array { if (!in_array($feature, static::$allFlags)) { error_log('Feature requested not found: '.$feature); return []; } return array_map(function($inst) { return $inst->slug; },array_filter(self::$instances, function ($inst) use ($feature, $type){ return isset($inst->$feature) && $inst->$feature === true && (is_null($type) || $inst->type === $type); })); } public function config(string $config):mixed { $allowed = ['breadcrumbs','calendar','dashboard','directory','feed','management','has_responses','seo','trackchanges','verification']; if (!in_array(strtolower($config), $allowed)) { error_log('Invalid config requested from Registrar: '.$config); return []; } return match(strtolower($config)) { 'breadcrumbs' => $this->getBreadcrumbs(), 'dashboard' => $this->getDashboard(), 'directory' => $this->getDirectory(), 'feed' => $this->getFeed(), 'management' => $this->getManagement(), 'has_responses' => $this->getResponses(), 'seo' => $this->getSEO(), 'trackchanges' => $this->getTrackChanges(), 'verification' => $this->getVerification() }; } protected function getBreadcrumbs():Breadcrumbs { $this->breadcrumbs = new Breadcrumbs($this->slug, $this); return $this->breadcrumbs; } protected function getCalendar():MakeCalendarType|false { if ($this->is_calendar){ $this->calendar = new MakeCalendarType($this->slug, $this); } else { $this->calendar = false; } return $this->calendar; } protected function getDashboard():Dashboard { $this->dashboard = new Dashboard($this->plural, $this); return $this->dashboard; } protected function getDirectory():Directory|false { if ($this->show_directory) { $this->directory = new Directory($this->singular, $this); } else { $this->directory = false; } return $this->directory; } protected function getFeed():Feed|false { if ($this->show_feed) { $this->feed = new Feed($this->slug, $this); } else { $this->feed = false; } return $this->feed; } public function getSEO():SEO { if (!isset($this->seo)){ $this->seo = new SEO($this->slug, $this); } return $this->seo; } public function getSections():array { $allSections = array_map(function($section) { return $section->getConfig; }, $this->sections); if (!empty($this->sectionOrder)) { $allSections['order'] = $this->sectionOrder; } return $allSections; } public function addSection(string $title):Section { $section = new Section($title, $this); $this->sections[] = $section; return $section; } public function setSectionOrder(array $sections):self { $allSections = array_map(function($section) { return $section->getSlug; }, $this->sections); $this->sectionOrder = array_intersect($allSections, $sections); return $this; } public function getSectionOrder():array { return $this->sectionOrder; } public function getConfig(string $config):array { $allowed = ['breadcrumbs','calendar','dashboard','directory','feed','management','has_responses','seo','trackchanges','verification']; if (!in_array(strtolower($config), $allowed)) { error_log('Invalid config requested from Registrar: '.$config); return []; } $config = $this->config($config); return ($config) ? $config->getConfig() : []; } public function getIntegration(string $service_name):Integration|false { if (array_key_exists($service_name, $this->integrationConfigs)) { return $this->integrationConfigs[$service_name]; } return false; } public function getIntegrationConfig(string $service_name):array|false { $integration = $this->getIntegration($service_name); if ($integration){ return $integration->getConfig(); } return false; } public function register():void { if ($this->registrar) { $this->registrar->register(); } } public static function getInstance(string $slug):Registrar|false { $slug = jvbNoBase($slug); if (array_key_exists($slug, static::$instances)) { return static::$instances[$slug]; } return false; } public static function getFieldsFor(string $slug):array { if (!array_key_exists($slug, static::$instances)) { return []; } $instance = static::$instances[$slug]; return $instance->getFields(); } public static function getRegistered(?string $type = null):array { $instances = ($type) ? array_filter(static::$instances, function($instance) use ($type) { return $instance->type === $type; }) : static::$instances; return array_keys($instances); } public static function getLabels():array { return array_map(function ($instance) { return ['singular' => $instance->getSingular(), 'plural' => $instance->getPlural()]; }, static::$instances); } public function getCreatable():array { if ($this->type !== 'user') { return []; } return $this->can_create; } public function setCreatable(string|array $creatable):self { $this->can_create = $creatable; return $this; } public function getManageOthers():array { if ($this->type !== 'user'){ return []; } return $this->manage_others; } public function setManageOthers(array $manageable):self { $this->manage_others = $manageable; return $this; } public function renderDashPage(string $content, string $page, string $slug):string { if ($slug === $this->slug) { ob_start(); $crud = new CRUD($slug); $crud->render(); return ob_get_clean(); } return $content; } public function setupContent():void { if (!$this->is_content) return; //We need a pseudo-archive page for this content taxonomy. We create a post with the plural name $this->page = get_option(BASE.$this->slug.'_archive', false); if (!$this->page || !(bool)get_post((int)$this->page)) { $exists = new WP_Query([ 'post_type' => 'page', 'title'=> $this->plural, 'posts_per_page' => 1, 'post_status' => 'publish', 'fields' => 'ids', ]); if ($exists->have_posts()) { $page = $exists->posts[0]; } else { $page = wp_insert_post([ 'post_type' => 'page', 'post_title' => $this->plural, 'post_content' => '', 'post_status' => 'publish', ]); } if ($page && !is_wp_error($page)) { update_post_meta($page, BASE.'for_type', $this->slug); update_option(BASE.$this->slug.'_archive', $page); $this->page = $page; } wp_reset_postdata(); } add_filter('jvb_post_content_output', [$this, 'renderContent'], 20, 2); } public function renderContent(string $content, array $block):string { if (!is_page($this->page)) { return $content; } if ($block['blockName'] !== 'core/post-content') { return $content; } if (JVB_TESTING) { Cache::for($this->slug)->flush(); } $out = Cache::for($this->slug)->remember( get_the_ID(), function() { $items = get_terms([ 'taxonomy' => jvbCheckBase($this->slug), // 'hide_empty' => true, 'fields' => 'ids', ]); $out = []; if ($items && !is_wp_error($items)) { foreach ($items as $item) { $meta = Meta::forTerm($item); $slug = sanitize_title($meta->get('name')); $item = sprintf( '
%s