| | |
| | | namespace JVBase\managers; |
| | | |
| | | use JVBase\managers\UserTermsManager; |
| | | use JVBase\meta\MetaForm; |
| | | use JVBase\meta\MetaManager; |
| | | use JVBase\utility\Features; |
| | | use WP_User; |
| | | |
| | | if (!defined('ABSPATH')) { |
| | |
| | | protected array $filters; |
| | | protected array $bulkActions; |
| | | protected MetaManager $meta; |
| | | protected MetaForm $form; |
| | | protected array $taxonomies; |
| | | protected array $statuses; |
| | | protected array $fields; |
| | | protected array $sections; |
| | | protected array $stuck; |
| | | |
| | | |
| | | //For Timeline-specific posts |
| | | protected bool $isTimeline = false; |
| | | protected array $nonTimelineFields = []; |
| | | protected array $timelineSharedFields = []; |
| | | protected array $timelineUniqueFields = []; |
| | | |
| | | protected bool $userCanPublish = false; |
| | | |
| | | public function __construct(string $content) |
| | |
| | | $this->plural = $this->config['plural']; |
| | | $this->content = $content; |
| | | $this->fields = jvbGetFields($this->content, 'post'); |
| | | $this->maybeSetupTimeline(); |
| | | $this->sections = jvbGetSections($this->content, 'post'); |
| | | $this->stuck = [ |
| | | 'post_title', |
| | |
| | | ]; |
| | | |
| | | $this->init(); |
| | | |
| | | if ($this->isTimeline) { |
| | | $this->stuck[] = 'post_thumbnail'; |
| | | } |
| | | add_filter('jvbAdditionalActions', [$this, 'createItem']); |
| | | } |
| | | |
| | | protected function init():void |
| | |
| | | $this->initTaxonomies(); |
| | | $this->initFilters(); |
| | | $this->meta = new MetaManager(null, 'post', $this->content); |
| | | |
| | | $this->form = new MetaForm(); |
| | | $plural = strtolower($this->config['plural']??$this->content.'s'); |
| | | $this->userCanPublish = (jvbUserIsVerified()) ? |
| | | user_can($this->user_id, "publish_{$plural}") : false; |
| | | |
| | | } |
| | | |
| | | protected function maybeSetupTimeline():void { |
| | | $this->isTimeline = Features::forContent($this->content)->has('is_timeline'); |
| | | |
| | | if (!$this->isTimeline) { |
| | | return; |
| | | } |
| | | $this->timelineSharedFields = array_keys(array_filter($this->fields, function ($field) { |
| | | if (!array_key_exists('for_all', $field) || $field['for_all'] === false){ |
| | | return true; |
| | | } |
| | | return false; |
| | | })); |
| | | array_unshift($this->timelineSharedFields, 'post_thumbnail'); |
| | | array_unshift($this->timelineSharedFields, 'post_title'); |
| | | array_unshift($this->timelineSharedFields, 'post_status'); |
| | | |
| | | $this->timelineUniqueFields = array_keys(array_filter($this->fields, function ($field) { |
| | | if (array_key_exists('for_all', $field) && $field['for_all'] === true) { |
| | | return true; |
| | | } |
| | | return false; |
| | | })); |
| | | |
| | | $all = array_merge($this->timelineUniqueFields, $this->timelineSharedFields); |
| | | $this->nonTimelineFields = array_filter($this->fields, function ($field) use ($all) { |
| | | return !in_array($field, $all); |
| | | }, ARRAY_FILTER_USE_KEY); |
| | | } |
| | | |
| | | protected function initTaxonomies():void |
| | | { |
| | | $this->taxonomies = array_filter(JVB_TAXONOMY, function ($config) { |
| | |
| | | ], |
| | | 'future'=> [ |
| | | 'label' => 'Upcoming', |
| | | 'icon' => 'future', |
| | | 'icon' => 'clock-clockwise', |
| | | ], |
| | | 'past' => [ |
| | | 'label' => 'Past', |
| | | 'icon' => 'past', |
| | | 'icon' => 'clock-counter-clockwise', |
| | | ], |
| | | 'repeat'=> [ |
| | | 'label' => 'Recurring', |
| | | 'icon' => 'repeat', |
| | | ], |
| | | 'draft' => [ |
| | | 'icon' => 'hide', |
| | | 'icon' => 'eye-closed', |
| | | 'label' => 'Hidden', |
| | | ], |
| | | 'trash' => [ |
| | | 'label' => 'Scrapped', |
| | | 'icon' => 'delete', |
| | | 'icon' => 'trash', |
| | | ], |
| | | ] : |
| | | [ |
| | | 'all' => [ |
| | | 'icon' => 'all', |
| | | 'icon' => 'infinity', |
| | | 'label' => 'Everything', |
| | | ], |
| | | 'publish'=> [ |
| | | 'icon' => 'publish', |
| | | 'icon' => 'eye', |
| | | 'label' => 'Live', |
| | | ], |
| | | 'draft' => [ |
| | | 'icon' => 'hide', |
| | | 'icon' => 'eye-closed', |
| | | 'label' => 'Hidden', |
| | | ], |
| | | 'trash' => [ |
| | | 'label' => 'Scrapped', |
| | | 'icon' => 'delete', |
| | | 'icon' => 'trash', |
| | | ], |
| | | ]; |
| | | } |
| | |
| | | foreach ($this->taxonomies as $taxonomy=> $config) { |
| | | $this->filters['taxonomy'][$taxonomy] = [ |
| | | 'label' => $config['singular'], |
| | | 'icon' => $taxonomy |
| | | 'icon' => $config['icon']??'folder' |
| | | ]; |
| | | } |
| | | } |
| | |
| | | { |
| | | ob_start(); |
| | | ?> |
| | | <div class="dashboard-page <?= esc_attr($this->content) ?>"> |
| | | <div class="dashboard-page <?= esc_attr($this->content) ?>"<?=($this->isTimeline) ? ' data-timeline' : ''?>> |
| | | <?php |
| | | $this->renderHeader(); |
| | | $this->renderContent(); |
| | |
| | | protected function renderHeaderActions():void |
| | | { |
| | | $uploadConfig = [ |
| | | 'type' => 'image', |
| | | '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'], |
| | |
| | | 'singular' => $this->singular, |
| | | 'plural' => $this->plural, |
| | | 'multiple' => true, |
| | | 'destination' => 'post' |
| | | ]; |
| | | if (!jvbCheck('single_image', $this->config)) { |
| | | $uploadConfig['imageType'] = 'groupable'; |
| | | if (!array_key_exists('single_image', $this->config) || $this->config['single_image'] === false) { |
| | | $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> |
| | | $uploadConfig['label'] = 'Create '.$this->config['plural']; |
| | | $uploadConfig['upload_text'] = '<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> |
| | |
| | | $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 |
| | |
| | | ob_start(); |
| | | ?> |
| | | <div class="empty-state"> |
| | | <h3><?=jvbIcon($this->content)?>Nothing here<?=jvbIcon($this->content)?></h3> |
| | | <h3><?=jvbIcon($this->config['icon'])?>Nothing here<?=jvbIcon($this->config['icon'])?></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> |
| | | <p><small><i>Add many by uploading images above.</i>, or click the "<?=jvbIcon('plus-square')?>" 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="all-filters col start" data-ignore> |
| | | <div class="search row start nowrap"> |
| | | <span class="label">Search:</span> |
| | | <?= jvbSearch() ?> |
| | |
| | | $this->renderDateFilters(); |
| | | ?> |
| | | <button type="button" class="clear-filters row" hidden> |
| | | <?= jvbIcon('close', ['title' => 'Clear']); ?> |
| | | <?= jvbIcon('x', ['title' => 'Clear']); ?> |
| | | Clear All Filters |
| | | </button> |
| | | </div> |
| | |
| | | 'alphabetical' => 'Order alphabetically' |
| | | ], |
| | | 'order' => [ |
| | | 'asc' => 'In ascending order (Z-A, oldest to newest)', |
| | | 'desc' => 'In descending order (A-Z, newest to oldest)' |
| | | 'sort-ascending' => 'In ascending order (Z-A, oldest to newest)', |
| | | 'sort-descending' => 'In descending order (A-Z, newest to oldest)' |
| | | ] |
| | | ]; |
| | | |
| | |
| | | <?php |
| | | $i = 0; |
| | | foreach ($option as $opt => $label) { |
| | | $icon = $opt === 'date' ? 'calendar' : $opt; |
| | | ?> |
| | | <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> |
| | | <label for="<?=$opt?>" title="<?=$label?>"><?=jvbIcon($icon)?></label> |
| | | <?php |
| | | $i++; |
| | | } |
| | |
| | | |
| | | <?php |
| | | $views = [ |
| | | 'grid' => ['icon' => 'grid', 'label' => 'Grid View'], |
| | | 'list' => ['icon' => 'list', 'label' => 'List View'], |
| | | 'grid' => ['icon' => 'squares-four', 'label' => 'Grid View'], |
| | | 'list' => ['icon' => 'rows', 'label' => 'List View'], |
| | | 'table' => ['icon' => 'table', 'label' => 'Table View'] |
| | | ]; |
| | | |
| | |
| | | |
| | | protected function renderModals():void |
| | | { |
| | | $this->renderCreateModal(); |
| | | // $this->renderCreateModal(); |
| | | $this->renderEditModal(); |
| | | $this->renderBulkEditModal(); |
| | | } |
| | |
| | | { |
| | | ob_start(); |
| | | ?> |
| | | <form class="edit-form" data-save="content" data-form-id="edit-<?=$this->content?>"> |
| | | <form class="edit-form" data-save="content" data-form-id="edit-<?=$this->content?>" data-autosave<?= ($this->isTimeline) ? ' data-timeline' : ''?>> |
| | | <?= jvbFormStatus() ?> |
| | | <input type="hidden" name="form-id" value="<?=uniqid('new-')?>" /> |
| | | <input type="hidden" name="content" value="<?=$this->content?>" /> |
| | | <div class="fields"> |
| | |
| | | } else { |
| | | $tabs = false; |
| | | } |
| | | |
| | | |
| | | $fields = $this->fields; |
| | | if (!$this->isTimeline) { |
| | | $first = ['post_thumbnail', 'post_title', 'price']; |
| | | |
| | | $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]); |
| | | 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]); |
| | | } |
| | | |
| | | unset($fields[$f]); |
| | | } |
| | | } |
| | | |
| | | if ($this->isTimeline) { |
| | | $temp = array_filter($fields, function ($field) { |
| | | return in_array($field, $this->timelineUniqueFields); |
| | | }, ARRAY_FILTER_USE_KEY); |
| | | |
| | | $config = [ |
| | | 'type' => 'gallery', |
| | | 'subtype' => 'timeline', |
| | | 'data' => 'timeline', |
| | | 'label' => 'Progression', |
| | | 'fields' => $temp |
| | | ]; |
| | | $content = ''; |
| | | foreach ($fields as $slug=> $field) { |
| | | if (in_array($slug, $this->timelineSharedFields)) { |
| | | $content .= $this->form->render($slug, null, $field, false, true); |
| | | } |
| | | } |
| | | |
| | | |
| | | $content .= $this->meta->render('form', 'timeline', $config, false,true); |
| | | |
| | | $tabs['progression']['content'] = $content; |
| | | $fields = $this->nonTimelineFields; |
| | | } |
| | | foreach ($fields as $n => $config) { |
| | | if ($tabs) { |
| | | $section = (array_key_exists('section', $config)) ? $config['section'] : 'basic'; |
| | |
| | | } else { |
| | | $this->meta->render('form', $n, $config); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | if ($tabs) { |
| | | jvbRenderTabs($tabs); |
| | | } |
| | |
| | | return ob_get_clean(); |
| | | } |
| | | |
| | | |
| | | protected function renderRowFields():void |
| | | { |
| | | $fields = $this->fields; |
| | | |
| | | // Render priority fields first |
| | | $first = ['post_thumbnail', 'post_title', 'price']; |
| | | foreach ($first as $f) { |
| | | if (array_key_exists($f, $fields)) { |
| | | $this->meta->render('form', $f, $fields[$f]); |
| | | unset($fields[$f]); |
| | | } |
| | | } |
| | | |
| | | // Render remaining fields |
| | | foreach ($fields as $name => $config) { |
| | | if (!array_key_exists('hidden', $config) || !$config['hidden']) { |
| | | $this->meta->render('form', $name, $config); |
| | | } |
| | | } |
| | | } |
| | | |
| | | protected function getApplicableStatuses(string $prefix) { |
| | | foreach ($this->statuses as $status => $config) { |
| | | if ($status === 'all') { |
| | |
| | | if ($status === 'future') { |
| | | $status = 'publish'; |
| | | $config = [ |
| | | 'icon' => 'publish', |
| | | 'icon' => 'eye', |
| | | 'label' => 'Live', |
| | | ]; |
| | | } else { |
| | |
| | | ob_start(); |
| | | ?> |
| | | <form class="bulk-edit-form" data-save="content" data-form-id="bulk-edit-<?=$this->content?>"> |
| | | <?= jvbFormStatus() ?> |
| | | <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> |
| | |
| | | $this->renderGridView(); |
| | | $this->renderTableView(); |
| | | $this->renderTableRow(); |
| | | if ($this->isTimeline) { |
| | | $temp = array_filter($this->fields, function ($field) { |
| | | return in_array($field, $this->timelineUniqueFields); |
| | | }, ARRAY_FILTER_USE_KEY); |
| | | $form = new MetaForm(); |
| | | echo '<template class="timelineItem">'; |
| | | $form->renderImagePreview(null,['fields' => $temp]); |
| | | echo '</template>'; |
| | | } |
| | | echo jvbGetEmptyStateTemplate(); |
| | | echo jvbGetGalleryPreviewTemplate(); |
| | | |
| | |
| | | ?> |
| | | <div class="item-actions"> |
| | | <button type="button" class="action" data-action="edit" title="Edit <?= $this->singular ?>"> |
| | | <?=jvbIcon('edit')?> |
| | | <?=jvbIcon('pencil-simple')?> |
| | | <span class="screen-reader-text">Edit <?= $this->singular ?></span> |
| | | </button> |
| | | <button type="button" class="action" data-action="trash" title="Scrap <?= $this->singular ?>"> |
| | | <?=jvbIcon('delete')?> |
| | | <?=jvbIcon('trash')?> |
| | | <span class="screen-reader-text">Scrap <?= $this->singular ?></span> |
| | | </button> |
| | | <!-- <button type="button" class="action" data-action="toggle-status">--> |
| | |
| | | |
| | | protected function renderTableView():void |
| | | { |
| | | if ($this->isTimeline) { |
| | | $this->renderTimelineTableView(); |
| | | return; |
| | | } |
| | | ?> |
| | | <template class="contentTable"> |
| | | <form class="table" |
| | | data-save="content" |
| | | data-content="<?= esc_attr($this->content) ?>" |
| | | data-form-id="content-table-<?= esc_attr($this->content) ?>"> |
| | | |
| | | <?= jvbFormStatus() ?> |
| | | <?= $this->renderTableActions() ?> |
| | | |
| | | <table> |
| | |
| | | * Render table row template |
| | | */ |
| | | protected function renderTableRow(): void { |
| | | if ($this->isTimeline) { |
| | | $this->renderTimelineTableGroup(); |
| | | return; |
| | | } |
| | | ?> |
| | | <template class="tableView"> |
| | | <tr class="item"> |
| | | <td class="select"> |
| | | <?= $this->renderItemSelect() ?> |
| | | </td> |
| | | <td class="status"> |
| | | <td class="status" data-field="post_status"> |
| | | <?= $this->renderStatusRadios() ?> |
| | | </td> |
| | | <?php |
| | |
| | | </template> |
| | | <?php |
| | | } |
| | | |
| | | protected function renderTimelineTableView():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) ?>"> |
| | | <?= jvbFormStatus() ?> |
| | | <?= $this->renderTableActions() ?> |
| | | |
| | | <table> |
| | | <thead> |
| | | <?= $this->renderTimelineTableHeader() ?> |
| | | </thead> |
| | | <!-- Rows are inserted as tbody groups --> |
| | | <tfoot> |
| | | <?= $this->renderTimelineTableHeader() ?> |
| | | </tfoot> |
| | | </table> |
| | | </form> |
| | | </template> |
| | | <?php |
| | | } |
| | | |
| | | protected function renderTimelineTableGroup():void |
| | | { |
| | | $makeDetails = [ |
| | | 'group', |
| | | 'repeater', |
| | | 'checkbox', |
| | | 'radio' |
| | | ]; |
| | | ?> |
| | | <template class="tableView"> |
| | | <tbody class="item"> |
| | | <tr class="shared"> |
| | | <td class="select"> |
| | | <?= $this->renderItemSelect() ?> |
| | | </td> |
| | | <td class="show-post_status field" data-field="post_status"> |
| | | <?= $this->renderStatusRadios() ?> |
| | | </td> |
| | | <?php |
| | | foreach ($this->fields as $name => $config) { |
| | | if(array_key_exists('hidden', $config) || $name === 'post_status') { |
| | | continue; |
| | | } |
| | | if (!in_array($name, $this->timelineSharedFields)) { |
| | | echo '<td></td>'; |
| | | 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 |
| | | } |
| | | |
| | | ?> |
| | | </tr> |
| | | <tr class="timeline-point"> |
| | | <td class="select"> |
| | | <button class="drag-handle" title="Drag to reorder" aria-label="Drag to reorder this timeline point"><?= jvbIcon('dots-six') ?></button> |
| | | </td> |
| | | <td class="show-post_status field" data-field="post_status"> |
| | | <?= $this->renderStatusRadios() ?> |
| | | </td> |
| | | <?php |
| | | foreach ($this->fields as $name => $config) { |
| | | if(array_key_exists('hidden', $config) || $name === 'post_status') { |
| | | continue; |
| | | } |
| | | if (!in_array($name, $this->timelineUniqueFields)) { |
| | | echo '<td></td>'; |
| | | 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 |
| | | } |
| | | ?> |
| | | </tr> |
| | | </tbody> |
| | | </template> |
| | | <?php |
| | | } |
| | | /** |
| | | * Render status radio buttons |
| | | */ |
| | |
| | | if ($status === 'future') { |
| | | $status = 'publish'; |
| | | $config = [ |
| | | 'icon' => 'publish', |
| | | 'icon' => 'eye', |
| | | 'label' => 'Live' |
| | | ]; |
| | | } elseif ($status === 'past') { |
| | |
| | | return ob_get_clean(); |
| | | } |
| | | |
| | | protected function renderTimelineTableHeader(): 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="show-post_status"> |
| | | Status |
| | | </th> |
| | | <?php foreach ($this->fields as $name => $config): |
| | | if (array_key_exists('hidden', $config) || $name === 'post_status'){ |
| | | 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 |
| | | */ |
| | |
| | | 'vertical', |
| | | 'TAB NAV:', |
| | | '', |
| | | jvbIcon('down'), |
| | | jvbIcon('right') |
| | | jvbIcon('caret-double-down'), |
| | | jvbIcon('caret-double-right') |
| | | ) ?> |
| | | |
| | | <button type="button" class="add-row" title="Add new row"> |
| | | <?= jvbIcon('add') ?> |
| | | <?= jvbIcon('plus-square') ?> |
| | | <span>Add Row</span> |
| | | </button> |
| | | </div> |
| | | <?php |
| | | return ob_get_clean(); |
| | | } |
| | | |
| | | public function createItem(array $actions):array |
| | | { |
| | | ob_start(); |
| | | $this->renderCreateModal(); |
| | | $content = ob_get_clean(); |
| | | $create = [ |
| | | 'button' => '<button type="button" class="create-item row" title="Create New '.$this->singular.'">'.jvbIcon('plus-square').'<span class="screen-reader-text">Create New '.$this->singular.'</span></button>', |
| | | 'content' => $content, |
| | | ]; |
| | | $actions[] = $create; |
| | | return $actions; |
| | | } |
| | | } |