| | |
| | | <?php |
| | | namespace JVBase\managers; |
| | | |
| | | use JVBase\base\Site; |
| | | use JVBase\registrar\Registrar; |
| | | use JVBase\ui\CRUDSkeleton; |
| | | use JVBase\utility\Features; |
| | | |
| | | if (!defined('ABSPATH')) { |
| | | exit; |
| | |
| | | */ |
| | | class CRUD { |
| | | protected CRUDSkeleton $skeleton; |
| | | protected CacheManager $cache; |
| | | protected array $config; |
| | | protected Cache $cache; |
| | | protected string $content; |
| | | protected array $taxonomies = []; |
| | | protected int $user_id; |
| | | protected ?string $type = null; |
| | | protected ?array $constant = null; |
| | | protected Registrar $registrar; |
| | | |
| | | public function __construct(string $content) { |
| | | if (array_key_exists($content, JVB_CONTENT)) { |
| | | $this->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 { |
| | | $this->registrar = Registrar::getInstance($content); |
| | | |
| | | if (!$this->registrar) { |
| | | return; |
| | | } |
| | | |
| | | $this->user_id = get_current_user_id(); |
| | | $this->config = $this->constant[$content]; |
| | | $this->content = $content; |
| | | $this->cache = CacheManager::for($content); |
| | | $this->cache = Cache::for('crud')->connect('post')->connect('taxonomy'); |
| | | |
| | | if (JVB_TESTING) { |
| | | $this->cache->flush(); |
| | | } |
| | | |
| | | // Create and configure skeleton |
| | | $this->skeleton = new CRUDSkeleton(); |
| | |
| | | protected function configure(): void { |
| | | // Basic info |
| | | $this->skeleton |
| | | ->content($this->content, $this->config['singular'], $this->config['plural']) |
| | | ->content($this->content, $this->registrar->getSingular(), $this->registrar->getPlural()) |
| | | ->title( |
| | | 'Your ' . $this->config['plural'], |
| | | $this->config['page_description'] ?? '' |
| | | $this->registrar->config('dashboard')->getTitle(), |
| | | $this->registrar->config('dashboard')->getDescription()?? '' |
| | | ); |
| | | |
| | | // Initialize meta |
| | | $this->skeleton->initMeta($this->type, $this->content); |
| | | |
| | | $this->skeleton->addSearch(); |
| | | |
| | | // Timeline if applicable |
| | | if (Features::forContent($this->content)->has('is_timeline')) { |
| | | if ($this->registrar && $this->registrar->hasFeature('is_timeline')) { |
| | | $this->skeleton->setTimeline(); |
| | | } |
| | | |
| | | // Fields and sections |
| | | $this->skeleton->setFields($this->config['fields']); |
| | | $this->skeleton->setFields($this->registrar->getFields()); |
| | | |
| | | $sections = array_key_exists('sections', $this->config) ? $this->config['sections'] : []; |
| | | foreach ($sections as $id => $config) { |
| | | $this->skeleton->addSection($id, $config); |
| | | foreach ($this->registrar->getSections() as $config) { |
| | | $this->skeleton->addSection($config['id'], $config); |
| | | } |
| | | |
| | | // Taxonomies |
| | | $this->initTaxonomies(); |
| | | |
| | | // Statuses |
| | | if (Features::forContent($this->content)->has('is_calendar')) { |
| | | if ($this->registrar->hasFeature('is_calendar')) { |
| | | $this->skeleton->setCalendar(); |
| | | } |
| | | |
| | | $this->skeleton->setDefaultStatus(); |
| | | if ($this->registrar->getType() === 'post') { |
| | | $this->skeleton->setDefaultStatus(); |
| | | } else { |
| | | $this->skeleton->setStatuses([]); |
| | | } |
| | | |
| | | |
| | | // Views |
| | | $this->skeleton |
| | |
| | | $this->skeleton->addDateFilter(); |
| | | $this->skeleton->addCustomDateRange($this->addDateRanges()); |
| | | if (!empty($this->taxonomies)) { |
| | | $this->skeleton->addTaxonomyFilter(array_keys($this->taxonomies), 'user'); |
| | | $this->skeleton->addTaxonomyFilter($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}"); |
| | | $plural = strtolower($this->registrar->getPlural() ?? $this->content . 's'); |
| | | $canPublish = $this->userIsVerified() && user_can($this->user_id, "publish_{$plural}"); |
| | | $this->skeleton->userCanPublish($canPublish); |
| | | |
| | | // Bulk actions |
| | | $this->skeleton->addBulkActions(['edit', 'publish', 'draft', 'trash']); |
| | | |
| | | // Uploader |
| | | $this->setupUploader(); |
| | | if ($this->registrar->getType() === 'post') { |
| | | $this->setupUploader(); |
| | | } |
| | | |
| | | |
| | | // Sticky fields |
| | | $stuck = ['post_title', 'term_name']; |
| | |
| | | add_filter('jvbAdditionalActions', [$this, 'createItem']); |
| | | } |
| | | |
| | | protected function userIsVerified():bool { |
| | | $membership = Site::membership(); |
| | | |
| | | return !($membership && $membership->has('member_verified')) || current_user_can('skip_moderation'); |
| | | } |
| | | /** |
| | | * Setup uploader configuration |
| | | */ |
| | | protected function setupUploader(): void { |
| | | $isSingleImage = jvbCheck('single_image', $this->config); |
| | | |
| | | $isSingleImage = $this->registrar->hasFeature('single_image'); |
| | | |
| | | $config = [ |
| | | 'type' => 'upload', |
| | | 'subtype' => 'image', |
| | | 'mode' => $isSingleImage ? 'direct' : 'selection', |
| | | 'create_new' => true, |
| | | 'label' => $this->config['upload_title'] ?? 'Bulk Upload ' . $this->config['plural'], |
| | | 'label' => $this->registrar->getUploadTitle(), |
| | | 'content' => $this->content, |
| | | 'singular' => $this->config['singular'], |
| | | 'plural' => $this->config['plural'], |
| | | 'singular' => $this->registrar->getSingular(), |
| | | 'plural' => $this->registrar->getPlural(), |
| | | 'multiple' => true, |
| | | 'destination' => $isSingleImage ? 'post' : 'post_group' |
| | | ]; |
| | | |
| | | if (!$isSingleImage) { |
| | | $config['upload_text'] = '<p>Drag images into groups. Each group becomes its own ' . $this->config['singular'] . '.</p> |
| | | $config['upload_text'] = '<p>Drag images into groups. Each group becomes its own ' . $this->registrar->getSingular() . '.</p> |
| | | <p>You can also select multiple images and click the "Add to Group" button.</p> |
| | | <p>If a ' . $this->config['singular'] . ' has multiple images, you can select the ' . jvbDashIcon('star') . ' to set an image as the main one.</p> |
| | | <p>Images left ungrouped will become individual ' . $this->config['plural'] . '</p> |
| | | <p>If a ' . $this->registrar->getSingular() . ' has multiple images, you can select the ' . jvbDashIcon('star') . ' to set an image as the main one.</p> |
| | | <p>Images left ungrouped will become individual ' . $this->registrar->getPlural() . '</p> |
| | | <p>Once finished, click the \'Save Changes\' button to send to server for processing.</p>'; |
| | | } else { |
| | | $config['description'] = 'Each image will become its own ' . $this->config['singular'] . '.'; |
| | | $config['description'] = 'Each image will become its own ' . $this->registrar->getSingular() . '.'; |
| | | } |
| | | |
| | | $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', |
| | | ], |
| | | ]; |
| | | $this->taxonomies = ($this->registrar->getType() === 'post') ? $this->registrar->registrar->taxonomies : []; |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | public function createItem(array $actions): array { |
| | | $actions[] = [ |
| | | 'button' => '<button type="button" class="create-item row" title="Create New ' . $this->config['singular'] . '">' |
| | | 'button' => '<button type="button" class="create-item row" title="Create New ' . $this->registrar->getSingular() . '">' |
| | | . jvbDashIcon('plus-square') |
| | | . '<span class="screen-reader-text">Create New ' . $this->config['singular'] . '</span></button>', |
| | | . '<span class="screen-reader-text">Create New ' . $this->registrar->getSingular() . '</span></button>', |
| | | 'content' => '', // Modal is rendered by skeleton |
| | | ]; |
| | | |