<?php
|
namespace JVBase\managers;
|
|
use JVBase\managers\UserTermsManager;
|
use JVBase\meta\MetaManager;
|
use WP_User;
|
|
if (!defined('ABSPATH')) {
|
exit; // Exit if accessed directly
|
}
|
|
class CRUD {
|
protected WP_User $user;
|
protected int $user_id;
|
protected array $config;
|
protected string $content;
|
protected string $singular;
|
protected string $plural;
|
protected array $filters;
|
protected array $bulkActions;
|
protected MetaManager $meta;
|
protected array $taxonomies;
|
protected array $statuses;
|
protected array $fields;
|
protected array $sections;
|
protected array $stuck;
|
|
protected bool $userCanPublish = false;
|
|
public function __construct(string $content)
|
{
|
//If we haven't defined this content, bail early
|
if (!array_key_exists($content, JVB_CONTENT)) {
|
return;
|
}
|
$this->user = wp_get_current_user();
|
$this->user_id = $this->user->ID;
|
$this->config = JVB_CONTENT[$content];
|
$this->singular = $this->config['singular'];
|
$this->plural = $this->config['plural'];
|
$this->content = $content;
|
$this->fields = jvbGetFields($this->content, 'post');
|
$this->sections = jvbGetSections($this->content, 'post');
|
$this->stuck = [
|
'post_title',
|
'term_name'
|
];
|
|
$this->init();
|
}
|
|
protected function init():void
|
{
|
$this->initStatuses();
|
$this->initBulkActions();
|
$this->initTaxonomies();
|
$this->initFilters();
|
$this->meta = new MetaManager(null, 'post', $this->content);
|
|
$plural = strtolower($this->config['plural']??$this->content.'s');
|
$this->userCanPublish = (jvbUserIsVerified()) ?
|
user_can($this->user_id, "publish_{$plural}") : false;
|
|
}
|
|
protected function initTaxonomies():void
|
{
|
$this->taxonomies = array_filter(JVB_TAXONOMY, function ($config) {
|
return in_array($this->content, $config['for_content']);
|
});
|
}
|
|
protected function initStatuses():void
|
{
|
$this->statuses = (array_key_exists('is_calendar', $this->config)) ?
|
[
|
'all' => [
|
'icon' => 'calendar',
|
'label' => 'Everything',
|
],
|
'future'=> [
|
'label' => 'Upcoming',
|
'icon' => 'future',
|
],
|
'past' => [
|
'label' => 'Past',
|
'icon' => 'past',
|
],
|
'repeat'=> [
|
'label' => 'Recurring',
|
'icon' => 'repeat',
|
],
|
'draft' => [
|
'icon' => 'hide',
|
'label' => 'Hidden',
|
],
|
'trash' => [
|
'label' => 'Scrapped',
|
'icon' => 'delete',
|
],
|
] :
|
[
|
'all' => [
|
'icon' => 'all',
|
'label' => 'Everything',
|
],
|
'publish'=> [
|
'icon' => 'publish',
|
'label' => 'Live',
|
],
|
'draft' => [
|
'icon' => 'hide',
|
'label' => 'Hidden',
|
],
|
'trash' => [
|
'label' => 'Scrapped',
|
'icon' => 'delete',
|
],
|
];
|
}
|
|
protected function initBulkActions():void
|
{
|
$this->bulkActions = [
|
'edit' => 'Edit',
|
'publish' => 'Show',
|
'draft' => 'Hide',
|
// 'copy' => 'Duplicate',
|
'trash' => 'Scrap'
|
];
|
}
|
|
protected function initFilters():void
|
{
|
$this->filters = [
|
'status' => $this->statuses,
|
'date' => [
|
'label' => 'Date',
|
'icon' => 'calendar'
|
]
|
];
|
|
foreach ($this->taxonomies as $taxonomy=> $config) {
|
$this->filters['taxonomy'][$taxonomy] = [
|
'label' => $config['singular'],
|
'icon' => $taxonomy
|
];
|
}
|
}
|
|
public function render():void
|
{
|
ob_start();
|
?>
|
<div class="dashboard-page <?= esc_attr($this->content) ?>">
|
<?php
|
$this->renderHeader();
|
$this->renderContent();
|
$this->renderModals();
|
$this->renderTemplates();
|
?>
|
</div>
|
<?php
|
echo ob_get_clean();
|
|
}
|
|
protected function renderHeader():void
|
{
|
?>
|
<h1>Your <?= $this->config['plural'] ?></h1>
|
<?php
|
if (array_key_exists('page_description', $this->config)) {
|
?>
|
<p class="page-description"><?=$this->config['page_description']?></p>
|
<?php
|
}
|
$this->renderHeaderActions();
|
}
|
|
protected function renderHeaderActions():void
|
{
|
$uploadConfig = [
|
'type' => 'upload',
|
'subtype' => 'image',
|
'mode' => (jvbCheck('single_image', $this->config)) ? 'direct' : 'selection',
|
'create_new' => true,
|
'label' => (array_key_exists('image_title', $this->config)) ? $this->config['image_title'] : 'Upload More '.$this->config['plural'],
|
'content' => $this->content,
|
'singular' => $this->singular,
|
'plural' => $this->plural,
|
'multiple' => true,
|
'destination' => 'post'
|
];
|
if (!jvbCheck('single_image', $this->config)) {
|
$uploadConfig['destination'] = 'post_group';
|
}
|
$uploadConfig['destination'] = 'post_group';
|
if (!jvbCheck('single_image', $this->config)) {
|
$uploadConfig['group_title'] = 'Create '.$this->config['plural'];
|
$uploadConfig['group_description'] = '<p>Drag images into groups. Each group becomes its own '.$this->singular.'.</p>
|
<p>You can also select multiple images and click the "Add to Group" button.</p>
|
<p>If a '.$this->singular.' has multiple images, you can select the '.jvbIcon('star').' to set an image as the main one.</p>
|
<p>Images left ungrouped will become individual '.$this->plural.'</p>
|
<p>Once finished, click the \'Save Changes\' button to send to server for processing.</p>';
|
} else {
|
$uploadConfig['description'] = 'Each image will become its own '.$this->singular.'.';
|
}
|
?>
|
<button type="button" class="create-item row" title="Create New <?= $this->singular?>"><?=jvbIcon('add') ?><span class="screen-reader-text">Create New <?= $this->singular?></span></button>
|
<details open class="uploader">
|
<summary class="row btw"><?= $this->config['upload_title'] ?? 'Bulk Upload '.$this->plural?></summary>
|
<?php
|
$this->meta->render(
|
'form',
|
'new_'.$this->content,
|
$uploadConfig
|
);
|
?>
|
</details>
|
<?php
|
}
|
|
protected function renderContent():void
|
{
|
?>
|
<section class="items-list <?=$this->content?> crud" data-content="<?= $this->content ?>">
|
<?php
|
$this->renderFilters();
|
$this->renderBulkControls();
|
?>
|
<div class="<?= $this->content ?> item-grid" role="grid"></div>
|
<div class="scroll-sentinel" aria-hidden="true"></div>
|
</section>
|
<?php
|
$state = apply_filters('jvbEmptyState', $this->renderEmptyState(), $this->content);
|
|
echo '<template class="emptyState">'.$state.'</template>';
|
?>
|
<?php
|
}
|
|
protected function renderEmptyState():string
|
{
|
ob_start();
|
?>
|
<div class="empty-state">
|
<h3><?=jvbIcon($this->content)?>Nothing here<?=jvbIcon($this->content)?></h3>
|
<p>It doesn't look like you have any <?=$this->config['plural'] ?> yet.</p>
|
<p><small><i>Add many by uploading images above.</i>, or click the "<?=jvbIcon('add')?>" button to add one at a time.</small></p>
|
</div>
|
<?php
|
return ob_get_clean();
|
}
|
|
protected function renderFilters():void
|
{
|
?>
|
<div class="all-filters col start">
|
<div class="search row start nowrap">
|
<span class="label">Search:</span>
|
<?= jvbSearch() ?>
|
</div>
|
<div class="controls col start">
|
<?php
|
$this->renderViewFilters();
|
$this->renderStatusFilters();
|
$this->renderOrderFilters();
|
?>
|
</div>
|
<div class="filters row start">
|
<span class="label">Filters:</span>
|
<?php
|
$this->renderTaxonomyFilters();
|
$this->renderDateFilters();
|
?>
|
<button type="button" class="clear-filters row" hidden>
|
<?= jvbIcon('close', ['title' => 'Clear']); ?>
|
Clear All Filters
|
</button>
|
</div>
|
|
<?= $this->renderColumnSelector(); ?>
|
</div>
|
<?php
|
}
|
|
protected function renderOrderFilters():void
|
{
|
?>
|
<div class="radio-options order row btw w-full">
|
<?php
|
$order = [
|
'orderby' => [
|
'date' => 'Order by date created',
|
'alphabetical' => 'Order alphabetically'
|
],
|
'order' => [
|
'asc' => 'In ascending order (Z-A, oldest to newest)',
|
'desc' => 'In descending order (A-Z, newest to oldest)'
|
]
|
];
|
|
foreach ($order as $o => $option) {
|
?>
|
<div class="row start">
|
<span class="label"><?= ucfirst($o)?>:</span>
|
<?php
|
$i = 0;
|
foreach ($option as $opt => $label) {
|
?>
|
<input id="<?=$opt?>" class="btn" type="radio" name="<?=$o?>" data-filter="<?=$o?>" value="<?=$opt?>"<?=$i===0 ? ' checked':''?>>
|
|
<label for="<?=$opt?>" title="<?=$label?>"><?=jvbIcon($opt)?></label>
|
<?php
|
$i++;
|
}
|
?>
|
</div>
|
<?php
|
}
|
?>
|
</div>
|
<?php
|
}
|
protected function renderStatusFilters():void
|
{
|
if (empty($this->statuses)) {
|
return;
|
}
|
?>
|
<div class="radio-options status row">
|
<span class="label">Status:</span>
|
<?php
|
$i = 1;
|
foreach ($this->statuses as $status => $config) {
|
$checked = ($i == 1) ? ' checked' : '';
|
?>
|
<input type="radio" class="btn" data-filter="status" value="<?=$status?>" name="status" id="<?=$status?>"<?=$checked?>>
|
<label for="<?=$status?>">
|
<?= jvbIcon($config['icon']) ?>
|
<span><?=$config['label']?><span class="count"></span></span>
|
</label>
|
<?php
|
$i++;
|
}
|
?>
|
</div>
|
<?php
|
}
|
|
protected function renderViewFilters():void
|
{
|
?>
|
<div class="radio-options view row">
|
<span class="label">View:</span>
|
|
<?php
|
$views = [
|
'grid' => ['icon' => 'grid', 'label' => 'Grid View'],
|
'list' => ['icon' => 'list', 'label' => 'List View'],
|
'table' => ['icon' => 'table', 'label' => 'Table View']
|
];
|
|
$first = true;
|
foreach ($views as $view => $config):
|
?>
|
<input type="radio"
|
data-view="<?= esc_attr($view) ?>"
|
value="<?= esc_attr($view) ?>"
|
class="btn"
|
name="view"
|
id="view-<?= esc_attr($view) ?>"
|
<?= $first ? 'checked' : '' ?>>
|
<label for="view-<?= esc_attr($view) ?>"
|
title="<?= esc_attr($config['label']) ?>">
|
<?= jvbIcon($config['icon']) ?>
|
<span class="screen-reader-text"><?= esc_html($config['label']) ?></span>
|
</label>
|
<?php
|
$first = false;
|
endforeach;
|
?>
|
</div>
|
<?php
|
}
|
/**
|
* Render column selector for table view
|
*/
|
protected function renderColumnSelector(): string {
|
ob_start();
|
?>
|
<details class="multi-select" title="Select columns" hidden>
|
<summary class="row start nowrap">
|
<?= jvbIcon('columns') ?>
|
<span class="labels">Toggle Columns</span>
|
</summary>
|
<div class="column-list">
|
<?php foreach ($this->fields as $fieldName => $config):
|
if (array_key_exists('hidden', $config)){
|
continue;
|
}
|
?>
|
<input type="checkbox"
|
id="show-<?= esc_attr($fieldName) ?>"
|
class="column-toggle ch"
|
name="show-<?= esc_attr($fieldName) ?>"
|
checked>
|
<label for="show-<?= esc_attr($fieldName) ?>">
|
<?= esc_html($config['label']) ?>
|
</label>
|
<?php endforeach; ?>
|
</div>
|
</details>
|
<?php
|
return ob_get_clean();
|
}
|
protected function renderTaxonomyFilters():void
|
{
|
if (empty($this->taxonomies)) {
|
return;
|
}
|
$out = '';
|
foreach ($this->taxonomies as $taxonomy => $config) {
|
$terms = $this->getCommonTerms($taxonomy);
|
if (!empty($terms)) {
|
$out .= sprintf(
|
'<div class="row nowrap"><label for="filter-%s">%s<span class="screen-reader-text">Filter by %s</span></label>
|
<select id="filter-%s" class="filter %s" name="%s" data-filter="taxonomies" data-taxonomy="%s">
|
<option value="">by %s</option>',
|
$taxonomy,
|
jvbIcon($config['icon'], ['title' => $config['plural']]),
|
esc_html($config['plural']),
|
$taxonomy,
|
$taxonomy,
|
$taxonomy,
|
$taxonomy,
|
$config['plural']
|
);
|
|
|
foreach ($terms as $term) {
|
$out .= sprintf(
|
'<option value="%s">%s</option>',
|
esc_attr($term['term_id']),
|
esc_html($term['name'])
|
);
|
}
|
$out .= '</select></div>';
|
}
|
}
|
echo $out;
|
}
|
/**
|
* Get common terms for taxonomy
|
* @param string $taxonomy
|
* @return array
|
*/
|
protected function getCommonTerms(string $taxonomy):array {
|
$manager = new UserTermsManager();
|
return $manager->getUserTerms($this->user_id, $taxonomy);
|
}
|
|
protected function renderDateFilters():void
|
{
|
$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
|
");
|
|
// Quick filters
|
$out = '<div class="row nowrap">
|
<label for="filter-date">'.
|
jvbIcon('calendar',['title'=>'Date']).
|
'<span class="screen-reader-text">by Date</span>
|
</label>
|
<select id="filter-date" class="date-filter" data-filter="date">
|
<option value="">by Date</option>
|
<option value="today">Today</option>
|
<option value="week">Past Week</option>
|
<option value="month">Past Month</option>
|
<option value="year">Past Year</option>
|
<option value="custom">Custom Range...</option>
|
</select>
|
</div>';
|
|
$form = '<div class="custom-range row">
|
<label for="date-start" class="col">
|
From
|
</label>
|
<input type="date" id="date-start" class="date-start">
|
<label for="date-end" class="col">
|
To
|
</label>
|
<input type="date" id="date-end" class="date-end">
|
</div>
|
<div class="month-picker">
|
<label>
|
<span>Or select month</span>
|
<select class="month-select">
|
<option value="">  . . .  </option>';
|
|
|
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);
|
$form .= sprintf(
|
'<option value="%s">%s</option>',
|
esc_attr($value),
|
esc_html($month_name)
|
);
|
}
|
|
$form .= '</select>
|
</label>
|
</div>';
|
|
// Custom date range
|
$out .= jvbNewModal(
|
'date-range',
|
'Filter Results by Date:',
|
$form
|
);
|
|
echo $out;
|
}
|
|
protected function renderBulkControls():void
|
{
|
if (empty($this->bulkActions)) {
|
return;
|
}
|
?>
|
<div class="bulk-controls row nowrap btw">
|
<div class="bulk-select">
|
<input type="checkbox" id="select-all" class="select-all">
|
<label for="select-all" class="row"><span>Select All</span><span class="selected-count" hidden></span></label>
|
</div>
|
<div class="bulk-actions row nowrap" hidden>
|
<label for="bulk-action-select" class="screen-reader-text">
|
Select what to do with this selection.
|
</label>
|
<select class="bulk-action-select" id="bulk-action-select">
|
|
</select>
|
</div>
|
</div>
|
|
<template class="notTrashOptions">
|
<select class="wrap">
|
<option value="">Bulk Actions...</option>
|
<?php
|
foreach ($this->bulkActions as $control => $label) {
|
$disabled = ($control === 'publish' && !$this->userCanPublish) ? ' disabled' : '';
|
?>
|
<option value="<?=$control?>"<?=$disabled?>><?=$label?></option>
|
<?php
|
}
|
foreach ($this->taxonomies as $taxonomy => $config) {
|
?>
|
<option value="tax-<?=$taxonomy?>">Add to <?= $config['singular'] ?></option>
|
<?php
|
}
|
?>
|
</select>
|
|
</template>
|
<template class="trashOptions">
|
<select class="wrap">
|
<option value="">Bulk Actions...</option>
|
<option value="restore">Restore</option>
|
<option value="delete">Permanently Delete</option>
|
</select>
|
</template>
|
<?php
|
}
|
|
protected function renderModals():void
|
{
|
$this->renderCreateModal();
|
$this->renderEditModal();
|
$this->renderBulkEditModal();
|
}
|
protected function renderCreateModal():void
|
{
|
echo jvbNewModal(
|
'create',
|
'Creating <span class="count"></span> New '.$this->config['singular'],
|
str_replace('edit-form"', 'create-form" data-noautosave', $this->editForm())
|
);
|
}
|
|
protected function editForm():string
|
{
|
ob_start();
|
?>
|
<form class="edit-form" data-save="content" data-form-id="edit-<?=$this->content?>">
|
<input type="hidden" name="form-id" value="<?=uniqid('new-')?>" />
|
<input type="hidden" name="content" value="<?=$this->content?>" />
|
<div class="fields">
|
<div class="field-group radio-options row">
|
<span>Status:</span>
|
<?php
|
$this->getApplicableStatuses('edit');
|
?>
|
</div>
|
<?php if (!$this->userCanPublish) { ?>
|
<p class="description">Your account needs to be verified before you can publish content.</p>
|
<?php }
|
|
if (!empty($this->sections)) {
|
$tabs = [];
|
foreach ($this->sections as $slug => $title) {
|
$tabs[$slug] = [
|
'title' => $title,
|
'content' => '',
|
'description' => jvbSectionDescription($slug)??'',
|
];
|
$icon = jvbSectionIcon($slug);
|
if ($icon !== '') {
|
$tabs[$slug]['icon'] = $icon;
|
}
|
}
|
} else {
|
$tabs = false;
|
}
|
$fields = $this->fields;
|
|
$first = ['post_thumbnail', 'post_title', 'price'];
|
foreach ($first as $f) {
|
if (array_key_exists($f, $fields)) {
|
if ($tabs) {
|
$tabs['basic']['content'] .= $this->meta->render('form', $f, $fields[$f], false, true);
|
} else {
|
$this->meta->render('form', $f, $fields[$f]);
|
}
|
|
unset($fields[$f]);
|
}
|
}
|
foreach ($fields as $n => $config) {
|
if ($tabs) {
|
$section = (array_key_exists('section', $config)) ? $config['section'] : 'basic';
|
$tabs[$section]['content'] .= $this->meta->render('form', $n, $config, false, true);
|
} else {
|
$this->meta->render('form', $n, $config);
|
}
|
|
}
|
|
|
if ($tabs) {
|
jvbRenderTabs($tabs);
|
}
|
?>
|
</div>
|
</form>
|
<?php
|
return ob_get_clean();
|
}
|
|
protected function getApplicableStatuses(string $prefix) {
|
foreach ($this->statuses as $status => $config) {
|
if ($status === 'all') {
|
continue;
|
}
|
if (in_array($status, ['future', 'past'])) {
|
if ($status === 'future') {
|
$status = 'publish';
|
$config = [
|
'icon' => 'publish',
|
'label' => 'Live',
|
];
|
} else {
|
continue;
|
}
|
}
|
$disabled = ($status === 'publish' && !$this->userCanPublish) ? ' disabled' : '';
|
?>
|
<input type ="radio"
|
name="post_status"
|
class="btn"
|
value="<?= esc_attr($status)?>"
|
id="<?=$prefix?>set-<?= esc_attr($status) ?>"
|
<?= $disabled?>>
|
<label for="<?=$prefix?>set-<?=esc_attr($status)?>">
|
<?= jvbIcon($config['icon'], ['title' => $config['label']]) ?>
|
<span><?= esc_html($config['label'])?></span>
|
</label>
|
<?php
|
}
|
}
|
protected function renderEditModal():void
|
{
|
echo jvbNewModal(
|
'edit',
|
'Edit your '.$this->singular,
|
$this->editForm()
|
);
|
}
|
|
protected function renderBulkEditModal():void
|
{
|
if (empty($this->bulkActions)) return;
|
ob_start();
|
?>
|
<form class="bulk-edit-form" data-save="content" data-form-id="bulk-edit-<?=$this->content?>">
|
<div class="selected"></div>
|
<p class="description">You can unselect items by clicking the image here.</p>
|
<p class="hint"><strong>IMPORTANT: </strong> Whatever changes you make here will be applied to all selected <?=$this->plural?>.</p>
|
<div class="fields">
|
<div class="field-group radio-options row">
|
<?php
|
$this->getApplicableStatuses('bulk-');
|
?>
|
</div>
|
<?php
|
if (!empty($this->taxonomies)) {
|
?>
|
<div class="taxonomies">
|
<?php
|
foreach ($this->taxonomies as $taxonomy => $config) {
|
$this->meta->render(
|
'form',
|
'bulk-edit-'.$taxonomy,
|
[
|
'type' => 'taxonomy',
|
'label' => $config['singular'],
|
'taxonomy' => $taxonomy,
|
'createNew' => jvbUserIsVerified(),
|
'multiple' => true,
|
'mode' => 'append'
|
]
|
);
|
}
|
?>
|
</div>
|
<?php
|
}
|
$fields = $this->fields;
|
$fields = array_filter($fields, function ($field) {
|
return array_key_exists('bulkEdit', $field);
|
});
|
foreach ($fields as $fieldName => $config) {
|
$this->meta->render('form', $fieldName, $config);
|
}
|
?>
|
</div>
|
</form>
|
<template class="bulkItem">
|
<label>
|
<input type="checkbox">
|
<img>
|
</label>
|
</template>
|
<?php
|
$form = ob_get_clean();
|
echo jvbNewModal(
|
'bulkEdit',
|
'Bulk Edit <span class="selected"></span> '.$this->config['plural'],
|
$form
|
);
|
}
|
|
protected function renderTemplates():void
|
{
|
$this->renderListView();
|
$this->renderGridView();
|
$this->renderTableView();
|
$this->renderTableRow();
|
echo jvbGetEmptyStateTemplate();
|
echo jvbGetGalleryPreviewTemplate();
|
|
|
}
|
|
protected function renderItemSelect():string
|
{
|
ob_start();
|
?>
|
<div class="item-select">
|
<input type="checkbox" class="select-item">
|
<label class="select-item-label">
|
<span class="screen-reader-text">Select this <?= $this->singular ?></span>
|
</label>
|
</div>
|
<?php
|
return ob_get_clean();
|
}
|
|
protected function renderImage():string
|
{
|
ob_start();
|
?>
|
<img loading="lazy" alt="">
|
<?php
|
return ob_get_clean();
|
}
|
|
protected function renderItemActions():string
|
{
|
ob_start();
|
?>
|
<div class="item-actions">
|
<button type="button" class="action" data-action="edit" title="Edit <?= $this->singular ?>">
|
<?=jvbIcon('edit')?>
|
<span class="screen-reader-text">Edit <?= $this->singular ?></span>
|
</button>
|
<button type="button" class="action" data-action="trash" title="Scrap <?= $this->singular ?>">
|
<?=jvbIcon('delete')?>
|
<span class="screen-reader-text">Scrap <?= $this->singular ?></span>
|
</button>
|
<!-- <button type="button" class="action" data-action="toggle-status">-->
|
<!-- <span class="screen-reader-text">Toggle --><?php //= $this->singular ?><!-- Visibility</span>-->
|
<!-- </button>-->
|
</div>
|
<?php
|
return ob_get_clean();
|
}
|
|
protected function renderItemFields(bool $form = false):string
|
{
|
ob_start();
|
foreach ($this->fields as $name => $config) {
|
$renderMode = $form ? 'form' : 'render';
|
|
$field = $this->meta->render($renderMode, $name, $config, false, true);
|
|
// Special handling for title in grid view
|
if ($name === 'post_title' && !$form) {
|
$field = str_replace('<p', '<h3', str_replace('</p>', '</h3>', $field));
|
}
|
|
echo $field;
|
}
|
return ob_get_clean();
|
}
|
|
protected function renderGridView():void
|
{
|
?>
|
<template class="gridView">
|
<div class="item <?= $this->content ?>">
|
<input type="checkbox" class="select-item" name="select-item">
|
<label title="Select this <?= $this->singular?>" class="select-item-label">
|
<?= $this->renderImage() ?>
|
</label>
|
<?= $this->renderItemActions(); ?>
|
</div>
|
</template>
|
<?php
|
}
|
|
protected function renderListView():void
|
{
|
?>
|
<template class="listView">
|
<div class="item <?=esc_attr($this->content)?> row nowrap">
|
<?= $this->renderItemSelect()?>
|
<?=$this->renderImage() ?>
|
<div class="col start w-full">
|
<?= $this->renderItemActions()?>
|
<h3 data-field="post_title"></h3>
|
<p data-attr="date"></p>
|
<p data-field="price"></p>
|
<div data-field="post_excerpt"></div>
|
</div>
|
</div>
|
</template>
|
<?php
|
}
|
|
protected function renderTableView():void
|
{
|
?>
|
<template class="contentTable">
|
<form class="table"
|
data-save="content"
|
data-content="<?= esc_attr($this->content) ?>"
|
data-form-id="content-table-<?= esc_attr($this->content) ?>">
|
|
<?= $this->renderTableActions() ?>
|
|
<table>
|
<thead>
|
<?= $this->renderTableHeader() ?>
|
</thead>
|
<tbody>
|
<!-- Rows will be inserted here -->
|
</tbody>
|
<tfoot>
|
<?= $this->renderTableHeader() ?>
|
</tfoot>
|
</table>
|
</form>
|
</template>
|
<?php
|
}
|
/**
|
* Render table row template
|
*/
|
protected function renderTableRow(): void {
|
?>
|
<template class="tableView">
|
<tr class="item">
|
<td class="select">
|
<?= $this->renderItemSelect() ?>
|
</td>
|
<td class="status">
|
<?= $this->renderStatusRadios() ?>
|
</td>
|
<?php
|
$makeDetails = [
|
'group',
|
'repeater',
|
'checkbox',
|
'radio'
|
];
|
foreach ($this->fields as $name => $config):
|
if (array_key_exists('hidden', $config)){
|
continue;
|
}
|
$makeThisDetailed = (in_array($config['type'], $makeDetails));
|
?>
|
<td class="field show-<?= esc_attr($name) ?>" data-field="<?= esc_attr($name) ?>" data-field-type="<?=$config['type']?>"<?=(in_array($name, $this->stuck)) ? ' data-stuck':''?>>
|
<?= $makeThisDetailed ? '<details><summary class="row btw">See Value</summary>' : '' ?>
|
<?php $this->meta->render('form', $name, $config); ?>
|
<?= $makeThisDetailed ? '</details>' : '' ?>
|
</td>
|
<?php endforeach; ?>
|
</tr>
|
</template>
|
<?php
|
}
|
/**
|
* Render status radio buttons
|
*/
|
protected function renderStatusRadios(): string {
|
ob_start();
|
?>
|
<div class="radio-options status-options row">
|
<?php foreach ($this->statuses as $status => $config):
|
if ($status === 'all') continue;
|
|
// Handle special cases
|
if ($status === 'future') {
|
$status = 'publish';
|
$config = [
|
'icon' => 'publish',
|
'label' => 'Live'
|
];
|
} elseif ($status === 'past') {
|
continue;
|
}
|
?>
|
<input type="radio"
|
name="post_status"
|
id="status-<?= esc_attr($status) ?>"
|
value="<?= esc_attr($status) ?>">
|
<label for="status-<?= esc_attr($status) ?>">
|
<?= jvbIcon($config['icon']) ?>
|
<span class="screen-reader-text"><?= esc_html($config['label']) ?></span>
|
</label>
|
<?php endforeach; ?>
|
</div>
|
<?php
|
return ob_get_clean();
|
}
|
/**
|
* Render table header
|
*/
|
protected function renderTableHeader(): string {
|
ob_start();
|
|
?>
|
<tr>
|
<th scope="col" class="select-header">
|
<input type="checkbox" id="select-all" name="select-all">
|
<label for="select-all">All</label>
|
</th>
|
<th scope="col" class="status-header">Status</th>
|
<?php foreach ($this->fields as $name => $config):
|
if (array_key_exists('hidden', $config)){
|
continue;
|
}
|
?>
|
<th scope="col" class="show-<?= esc_attr($name) ?>"<?= (in_array($name, $this->stuck)) ? ' data-stuck':''?>>
|
<?= esc_html($config['label']) ?>
|
</th>
|
<?php endforeach; ?>
|
</tr>
|
<?php
|
return ob_get_clean();
|
}
|
|
/**
|
* Render table action controls
|
*/
|
protected function renderTableActions(): string {
|
ob_start();
|
?>
|
<div class="table-actions row btw nowrap">
|
<?= jvbRenderToggleTextField(
|
'vertical',
|
'TAB NAV:',
|
'',
|
jvbIcon('down'),
|
jvbIcon('right')
|
) ?>
|
|
<button type="button" class="add-row" title="Add new row">
|
<?= jvbIcon('add') ?>
|
<span>Add Row</span>
|
</button>
|
</div>
|
<?php
|
return ob_get_clean();
|
}
|
}
|