type = 'post'; $this->constant = JVB_CONTENT; } elseif (array_key_exists($content, JVB_TAXONOMY)) { $this->type = 'term'; $this->constant = JVB_TAXONOMY; } elseif (array_key_exists($content, JVB_USER)) { $this->type = 'user'; $this->constant = JVB_USER; } else { return; } $this->user_id = get_current_user_id(); $this->config = $this->constant[$content]; $this->content = $content; $this->cache = Cache::for('crud')->connect('post')->connect('taxonomy'); if (JVB_TESTING) { $this->cache->flush(); } // Create and configure skeleton $this->skeleton = new CRUDSkeleton(); $this->configure(); } /** * Configure CRUDSkeleton from WordPress config */ protected function configure(): void { // Basic info $this->skeleton ->content($this->content, $this->config['singular'], $this->config['plural']) ->title( 'Your ' . $this->config['plural'], $this->config['page_description'] ?? '' ); // Initialize meta $this->skeleton->addSearch(); // Timeline if applicable if (Features::forContent($this->content)->has('is_timeline')) { $this->skeleton->setTimeline(); } // Fields and sections $this->skeleton->setFields($this->config['fields']); $sections = array_key_exists('sections', $this->config) ? $this->config['sections'] : []; foreach ($sections as $id => $config) { $this->skeleton->addSection($id, $config); } // Taxonomies $this->initTaxonomies(); // Statuses if (Features::forContent($this->content)->has('is_calendar')) { $this->skeleton->setCalendar(); } $this->skeleton->setDefaultStatus(); // Views $this->skeleton ->addViews() ->defaultView('grid'); $this->skeleton->addItemActions(); // Filters $this->skeleton->addDateFilter(); $this->skeleton->addCustomDateRange($this->addDateRanges()); if (!empty($this->taxonomies)) { $this->skeleton->addTaxonomyFilter(array_keys($this->taxonomies), 'user'); } // Capabilities $this->skeleton->addCapabilities(['view', 'edit', 'create', 'delete']); $plural = strtolower($this->config['plural'] ?? $this->content . 's'); $canPublish = jvbUserIsVerified() && user_can($this->user_id, "publish_{$plural}"); $this->skeleton->userCanPublish($canPublish); // Bulk actions $this->skeleton->addBulkActions(['edit', 'publish', 'draft', 'trash']); // Uploader $this->setupUploader(); // Sticky fields $stuck = ['post_title', 'term_name']; if ($this->skeleton->get('isTimeline')) { $stuck[] = 'post_thumbnail'; } $this->skeleton->stickFields($stuck); // Hook for create button add_filter('jvbAdditionalActions', [$this, 'createItem']); } /** * Setup uploader configuration */ protected function setupUploader(): void { $isSingleImage = jvbCheck('single_image', $this->config); $config = [ 'type' => 'upload', 'subtype' => 'image', 'mode' => $isSingleImage ? 'direct' : 'selection', 'create_new' => true, 'label' => $this->config['upload_title'] ?? 'Bulk Upload ' . $this->config['plural'], 'content' => $this->content, 'singular' => $this->config['singular'], 'plural' => $this->config['plural'], 'multiple' => true, 'destination' => $isSingleImage ? 'post' : 'post_group' ]; if (!$isSingleImage) { $config['upload_text'] = '

Drag images into groups. Each group becomes its own ' . $this->config['singular'] . '.

You can also select multiple images and click the "Add to Group" button.

If a ' . $this->config['singular'] . ' has multiple images, you can select the ' . jvbDashIcon('star') . ' to set an image as the main one.

Images left ungrouped will become individual ' . $this->config['plural'] . '

Once finished, click the \'Save Changes\' button to send to server for processing.

'; } else { $config['description'] = 'Each image will become its own ' . $this->config['singular'] . '.'; } $this->skeleton->addUploader($config); } /** * Initialize taxonomies from WordPress config */ protected function initTaxonomies(): void { $this->taxonomies = array_filter(JVB_TAXONOMY, function ($config) { return in_array($this->content, $config['for_content']); }); } /** * Get statuses - calendar or standard */ protected function getStatuses(): array { return array_key_exists('is_calendar', $this->config) ? [ 'all' => [ 'icon' => 'calendar', 'label' => 'Everything', ], 'future' => [ 'label' => 'Upcoming', 'icon' => 'clock-clockwise', ], 'past' => [ 'label' => 'Past', 'icon' => 'clock-counter-clockwise', ], 'repeat' => [ 'label' => 'Recurring', 'icon' => 'repeat', ], 'draft' => [ 'icon' => 'eye-closed', 'label' => 'Hidden', ], 'trash' => [ 'label' => 'Scrapped', 'icon' => 'trash', ], ] : [ 'all' => [ 'icon' => 'infinity', 'label' => 'Everything', ], 'publish' => [ 'icon' => 'eye', 'label' => 'Live', ], 'draft' => [ 'icon' => 'eye-closed', 'label' => 'Hidden', ], 'trash' => [ 'label' => 'Scrapped', 'icon' => 'trash', ], ]; } /** * Add create button to dashboard actions */ public function createItem(array $actions): array { $actions[] = [ 'button' => '', 'content' => '', // Modal is rendered by skeleton ]; return $actions; } protected function addDateRanges():array { return $this->cache->remember( 'dateRanges', function() { $postType = jvbCheckBase($this->content); // Get available months global $wpdb; $months = $wpdb->get_results(" SELECT DISTINCT YEAR(post_date) as year, MONTH(post_date) as month FROM $wpdb->posts WHERE post_type = '{$postType}' AND post_author = '{$this->user_id}' ORDER BY post_date DESC "); $ranges = []; foreach ($months as $date) { $month_name = date('F Y', mktime(0, 0, 0, $date->month, 1, $date->year)); $value = $date->year . '-' . str_pad($date->month, 2, '0', STR_PAD_LEFT); $ranges[$value] = $month_name; } return $ranges; } ); } /** * Render the interface */ public function render(): void { $this->skeleton->render(); } /** * Get the skeleton instance for further customization */ public function getSkeleton(): CRUDSkeleton { return $this->skeleton; } }