From f383c3a4325bc173b6f9676274bc19694be6f9c0 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Fri, 05 Jun 2026 16:49:44 +0000
Subject: [PATCH] =Modified the Feed Fields config in Registrar, to utilize the built in functionality there

---
 content/progress.php |  932 ++++++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 719 insertions(+), 213 deletions(-)

diff --git a/content/progress.php b/content/progress.php
index 38bbe49..7f910eb 100644
--- a/content/progress.php
+++ b/content/progress.php
@@ -1,212 +1,713 @@
 <?php
 // /content/progress.php
-use JVBase\meta\Meta;
 
-function altr_progress():array
-{
-    return [
-        'singular'       => 'Before & After',
-        'plural'       => 'Before & Afters',
-        'dash_title'    => 'Progress',
-        'dash_description' => 'Manage your before and after posts',
-        'breadcrumb'    => 'Before & Afters',
-        'capability_type' => ['progress', 'progress'],
-        'hide_children' => true,
-        'is_timeline'   => true,
-        'show_feed'    => true,
-        'show_directory'=> true,
-        'directory_extra'=> ['goal', 'skin-type','age'],
-        'hierarchical'  => true,
-        'icon'         => 'arrows-left-right',
-        'rewrite'      => [
-            'slug'       => 'before-and-after',
-            'with_front' => false,
-        ],
-        'sections'  => [
-            'progression'   => [
-                'label' => 'Progression',
+use JVBase\base\SchemaHelper;
+use JVBase\inc\managers\SEO\render\Thing\CreativeWork\Article\Report;
+use JVBase\inc\managers\SEO\render\Thing\CreativeWork\WebPage\CollectionPage\ImageGallery;
+use JVBase\inc\managers\SEO\render\Thing\MedicalEntity\MedicalProcedure;
+use JVBase\meta\Meta;
+use JVBase\registrar\config\seo\Resolver;
+use JVBase\registrar\Registrar;
+if (!defined('ABSPATH')) {
+    exit;
+}
+
+add_action('jvbDefineRegistrar', 'altr_progress');
+add_action('jvbDefineRegistrarFields', 'altr_progress_fields');
+
+add_action('plugins_loaded', 'altr_progress',1);
+//Add fields later so we can verify taxonomies/post types exist
+add_action('plugins_loaded', 'altr_progress_fields', 2);
+
+
+add_filter('altr_ProgressSchemaDefault', 'altr_progress_schema');
+add_filter('altr_ProgressMetaDefault', 'altr_progress_meta');
+add_filter('altr_ProgressArchiveDefault', 'altr_progress_archive');
+add_filter('altr_progressTitleAlts', 'altr_progress_title_alts');
+
+function altr_progress(){
+    if (!class_exists('JVBase\registrar\Registrar')) {
+        return;
+    }
+    $progress = Registrar::forPost('progress', 'Before & After', 'Before & Afters')
+        ->setIcon('arrows-left-right')
+        ->make([
+            'rewrite'   => [
+                'slug'          => 'before-and-after',
+                'with_front'    => false,
+            ],
+            'taxonomies'    => [
+                'age',
+                'body_part',
+                'goal',
+                'number',
+                'person',
+                'skin_type',
+                'style',
+                'theme',
+                'timeline',
             ]
-        ],
-        'custom_order' => [
-            'number'    => [
+        ])
+        ->setAll([
+            'show_directory',
+            'show_feed',
+            'hide_children',
+            'is_timeline',
+            'add_image_column'
+        ]);
+
+    $breadcrumb = $progress->config('breadcrumbs');
+    $breadcrumb->setTitle('Before & Afters');
+//$directory = $progress->getConfig('directory');
+
+}
+
+function altr_progress_fields():void
+{
+    if (!class_exists('JVBase\registrar\Registrar')) {
+        return;
+    }
+    $progress = Registrar::getInstance('progress');
+    $breadcrumbs = $progress->config('breadcrumbs');
+    $breadcrumbs->setCrumb(['project', 'form']);
+
+    $fields = $progress->fields();
+    $fields->modifyField('post_title', 'for_all', true);
+    $fields->modifyField('post_status', 'for_all', true);
+    $fields->modifyField('post_date', 'for_all', true);
+    $fields->modifyField('post_thumbnail', 'for_all', true);
+    $fields->addField('person', [
+        'type'      => 'selector',
+        'subtype'   => 'taxonomy',
+        'taxonomy'  => 'person',
+        'label'     => 'Person',
+        'quickEdit'     => true,
+        'createNew'     => true,
+        'section'     => 'progression',
+        'hint'     => 'Not public, just to make it easier to find',
+    ]);
+    $fields->addField('body_part', [
+        'type'      => 'selector',
+        'subtype'   => 'taxonomy',
+        'taxonomy'  => 'body_part',
+        'label'     => 'Body Part',
+        'quickEdit'     => true,
+        'createNew'     => true,
+        'section'     => 'progression',
+    ]);
+    $fields->addField('goal', [
+        'type'      => 'selector',
+        'subtype'   => 'taxonomy',
+        'taxonomy'  => 'goal',
+        'label'     => 'Goal',
+        'quickEdit'     => true,
+        'createNew'     => true,
+        'section'     => 'progression',
+    ]);
+    $fields->addField('timeline', [
+        'type'      => 'selector',
+        'subtype'   => 'taxonomy',
+        'taxonomy'  => 'timeline',
+        'label'     => 'Timeline',
+        'quickEdit'     => true,
+        'for_all'     => true,
+        'createNew'     => true,
+        'section'     => 'progression',
+    ]);
+    $fields->addField('style', [
+        'type'      => 'selector',
+        'subtype'   => 'taxonomy',
+        'taxonomy'  => 'style',
+        'label'     => 'Tattoo Style',
+        'quickEdit'     => true,
+        'createNew'     => true,
+        'section'     => 'progression',
+    ]);
+    $fields->addField('theme', [
+        'type'      => 'selector',
+        'subtype'   => 'taxonomy',
+        'taxonomy'  => 'theme',
+        'label'     => 'Tattoo Theme',
+        'quickEdit'     => true,
+        'createNew'     => true,
+        'section'     => 'progression',
+    ]);
+    $fields->addField('skin_type', [
+        'type'      => 'selector',
+        'subtype'   => 'taxonomy',
+        'taxonomy'  => 'skin_type',
+        'label'     => 'Skin Type',
+        'quickEdit'     => true,
+        'createNew'     => true,
+        'section'     => 'progression',
+    ]);
+    $fields->addField('age', [
+        'type'      => 'selector',
+        'subtype'   => 'taxonomy',
+        'taxonomy'  => 'age',
+        'label'     => 'Age of Tattoo',
+        'quickEdit'     => true,
+        'createNew'     => true,
+        'section'     => 'progression',
+    ]);
+    $fields->addField('number', [
+        'type'      => 'text',
+        'subtype'   => 'number',
+        'label'     => 'Number of Treatments',
+        'quickEdit'     => true,
+        'for_all'     => true,
+        'section'     => 'progression',
+    ]);
+    $fields->modifyField('post_content', 'for_all', true);
+    $fields->modifyField('post_content', 'label', 'About this Timeline Point');
+    $fields->addField('last_date', [
+        'type'      => 'text',
+        'subtype'   => 'number',
+        'label'     => 'Last Date',
+        'hidden'     => true,
+    ]);
+    $fields->addField('is_update', [
+        'type'  => 'true_false',
+        'label' => 'Is Update',
+        'hint'  => 'If this point is not another treatment, but just an update in the progress',
+        'for_all'   => true,
+    ]);
+
+    $feed = $progress->config('feed');
+    $feed->setCustomOrder([
+            [
+                    'slug' => 'number',
                 'label' => 'Number of Treatments',
                 'icon'  => 'hash-straight',
-                'for'   => 'progress',
+                'for'   => 'progress'
             ]
-        ],
-        'seo' => [
-            'schema' => [
-                'type' => 'BeforeAfter',
-                'name' => '{{post_title}}',
-                'description' => '{{post_excerpt}}',
-                'temporalCoverage' => '{{post_date}}/{{last_date}}',
-                'additionalProperty' => [
-                    ['name' => 'Number of sessions', 'value' => '{{number.name}}'],
-                    ['name' => 'Treatment area', 'value' => '{{body-part.name}}'],
-                    ['name' => 'Tattoo style', 'value' => '{{style.name}}'],
-                    ['name' => 'Skin type', 'value' => '{{skin-type.name}}'],
-                    ['name' => 'Goal', 'value' => '{{goal.name}}'],
-                ],
-                'associatedMedia' => '{{timeline_photos}}',
-            ],
-            'meta' => [
-                'title' => '{{style.name}} {{theme.name}} Tattoo – Before & After {{number}} Laser Removal Sessions',
-                'description' => 'See this {{style.name}} {{theme.name}} {{age.name}}-old tattoo before and after {{number}} laser tattoo removal treatments on the {{body-part.name}}.',
-            ],
-            'archive' => [
-                'type' => 'CollectionPage',
-                'name' => 'Tattoos Before and After Laser Tattoo Removal',
-            ],
-        ],
-        'feed'      => [
-            'single'    => [
-                'pre_title' => 'Before & After Laser Tattoo Removal',
-            ],
-            'archive'   => [
+        ]
+    );
+    $feed->setFields([
+        'post_title',
+        'post_date',
+        'post_modified',
+        'post_excerpt',
+        'goal',
+        'body_part',
+        'skin_type',
+        'age',
+        'style',
+        'theme',
+    ]);
 
-            ],
-            'config'    => [
-                'is_gallery'    => false,
-                'content'       => 'progress',
-                'context'       => 'progress',
-                'id'            => [],
-                'class'         => [],
-            ]
-        ],
-        'fields'       => [
-            'post_title'     => [
-                'type'  => 'text',
-                'label' => 'Title',
-                'quickEdit' => true,
-                'section'   => 'progression',
-                'for_all'   => true,
-            ],
-            'post_status'         => [
-                'type'      => 'radio',
-                'label'     => 'Status',
-                'options'   => [
-                    'publish'   => 'Show',
-                    'draft'     => 'Hide',
-                    'trash'     => 'Scrap',
-                    'delete'    => 'Permanently Delete'
-                ],
-                'for_all'   => true,
-            ],
-            'post_date'  => [
-                'type'      => 'date',
-                'label'     => 'Date',
-                'for_all'   => true,
-            ],
-            'post_thumbnail'                => [
-                'type'      => 'upload',
-                'label'     => 'Image',
-                'quickEdit' => true,
-                'section'   => 'progression',
-                'for_all'   => true,
-            ],
-            'person' => [
-                'type'  => 'taxonomy',
-                'taxonomy'  => 'person',
-                'autocomplete' => true,
-                'label' => 'Person',
-                'quickEdit' => true,
-                'createNew' => true,
-                'section'   => 'progression',
-                'hint'      => 'Not public, just to make it easier to find'
-            ],
-            'body-part' => [
-                'type'  => 'taxonomy',
-                'taxonomy'  => 'body-part',
-                'label' => 'Body Part',
-                'autocomplete' => true,
-                'quickEdit' => true,
-                'createNew' => true,
-                'section'   => 'progression'
-            ],
-            'goal' => [
-                'type'  => 'taxonomy',
-                'taxonomy'  => 'goal',
-                'autocomplete' => true,
-                'label' => 'Goal',
-                'quickEdit' => true,
-                'createNew' => true,
-                'section'   => 'progression'
-            ],
-            'timeline' => [
-                'type'  => 'taxonomy',
-                'taxonomy'  => 'timeline',
-                'autocomplete' => true,
-                'label' => 'Timeline',
-                'quickEdit' => true,
-                'createNew' => true,
-                'section'   => 'progression',
-                'for_all'   => true,
-                'hidden'    => true,
-            ],
-            'style' => [
-                'type'  => 'taxonomy',
-                'taxonomy'  => 'style',
-                'autocomplete' => true,
-                'label' => 'Tattoo Style',
-                'quickEdit' => true,
-                'createNew' => true,
-                'section'   => 'progression'
-            ],
-            'theme' => [
-                'type'  => 'taxonomy',
-                'taxonomy'  => 'theme',
-                'autocomplete' => true,
-                'label' => 'Tattoo Theme',
-                'quickEdit' => true,
-                'createNew' => true,
-                'section'   => 'progression'
-            ],
-            'skin-type' => [
-                'type'  => 'taxonomy',
-                'taxonomy'  => 'skin-type',
-                'label' => 'Skin Type',
-                'autocomplete' => true,
-                'quickEdit' => true,
-                'createNew' => true,
-                'section'   => 'progression'
-            ],
-            'age' => [
-                'type'  => 'taxonomy',
-                'taxonomy'  => 'age',
-                'autocomplete'      => true,
-                'label' => 'Age of Tattoo',
-                'quickEdit' => true,
-                'createNew' => true,
-                'section'   => 'progression'
-            ],
-            'number' => [
-                'type'  => 'text',
-                'subtype'  => 'number',
-                'label' => 'Number of Treatments',
-                'quickEdit' => true,
-                'section'   => 'progression',
-                'for_all'   => true,
-                'hidden'    => true,    //auto calculated
-            ],
-            'post_content'   => [
-                'type'  => 'textarea',
-                'quill' => true,
-                'label' => 'Notes',
-                'section'   => 'progression',
-                'for_all'   => true,
-            ],
-            'last_date' => [
-                'type'  => 'number',
-                'label' => 'Last Date',
-                'hidden'    => true,
-                'default'   => 0,
-                'for_all'   => true,
-            ]
-        ],
-        'upload_title' => 'Upload Before & Afters',
+//    $directory = $progress->config('directory');
+//    $directory->setDirectoryExtra([
+//         'goal',
+//        'skin_type',
+//        'age'
+//    ]);
+}
+
+function altr_progressTitleAlts():array
+{
+    return [
+        ': Before & After Laser Tattoo Removal',
+        ': Before & After Tattoo Removal',
+        ': Tattoo Removal Progress',
+        ': Tattoo Removal Results',
+        ': Before & After',
     ];
 }
 
+function altr_progress_schema():array
+{
+    return [
+        'type'              => 'JVBase\inc\managers\SEO\render\Thing\CreativeWork\WebPage\CollectionPage\ImageGallery',
+        'name'              => '{{post_title}} | Before and After Laser Tattoo Removal',
+        'description'       => '{{post_excerpt}}',
+        'temporalCoverage'  => '{{post_date}}/{{last_date}}',
+        'additionalProperty'=> [
+            ['id'=> 'number-of-sessions','name' => 'Number of sessions', 'value' => '{{number}}'],
+            ['id' => 'treatment-area','name' => 'Treatment area', 'value' => '{{body_part.name}}'],
+            ['id' => 'tattoo-style','name' => 'Tattoo style', 'value' => '{{style.name}}'],
+            ['id' => 'skin-type','name' => 'Skin type', 'value' => '{{skin_type.name}}'],
+            ['id' => 'goal','name' => 'Goal', 'value' => '{{goal.name}}'],
+        ],
+
+    ];
+}
+
+function altr_build_singular_progress_schema(int $ID):array
+{
+    $schema = [];
+
+    $work = new Report();
+    $meta = Meta::forPost($ID);
+    $title = $meta->get('post_title');
+    $id = 'case-study-'.sanitize_title($title);
+
+    $work->setId($id);
+    $work->setName($meta->get('post_title'). ' | Before & After Tattoo Removal');
+    $work->setDescription($meta->get('post_excerpt'));
+
+    $procedure = new MedicalProcedure();
+    $procedure->setId('laser-tattoo-removal');
+    $procedure->setName('Laser Tattoo Removal');
+    if (!empty($meta->get('body_part'))) {
+        $parts = array_map('absint', explode(',', $meta->get('body_part')));
+        $parts = array_filter(array_map(function($ID) {
+            $term = get_term($ID, BASE.'body_part');
+            if ($term && !is_wp_error($term)) {
+                return $term->name;
+            }
+            return false;
+        }, $parts));
+        $location = jvbCommaList($parts);
+        $procedure->setBodyLocation($location);
+    }
+    $work->setAbout($procedure);
+
+    $fields = ['goal', 'style', 'theme','skin_type', 'age'];
+    $keywords = ['laser tattoo removal', 'PicoWay',];
+    foreach ($fields as $tax) {
+        $terms = $meta->get($tax);
+        if (!empty($terms)) {
+            $terms = array_map('absint', explode(',', $terms));
+            $terms = array_filter(array_map(function($ID) use ($tax) {
+                $term = get_term($ID, BASE.$tax);
+                if ($term && !is_wp_error($term)) {
+                    $base = match ($tax) {
+                        'skin_type' => 'FitzPatrick Type ',
+                        'age'   => 'removing a ',
+                        default => ''
+                    };
+
+                    $suffix = $tax === 'age' ? ' old tattoo' : '';
+
+                    $value = $term->name === 'Complete Removal' ? 'Complete Tattoo Removal' : $term->name;
+
+                    return $base.$value.$suffix;
+                }
+                return false;
+            }, $terms));
+            $keywords = array_merge($keywords, $terms);
+        }
+    }
+
+    $work->setKeywords($keywords);
+
+    //Setup the various parts;
+    $observations = [];
+    $gallery = new ImageGallery();
+    $gallery->setId($id.'-gallery');
+    $gallery->setName('Before & After Photo Gallery');
+    $galleryItems = [];
+
+    //Grab the children and set the parent at the front
+    $points = get_children(['post_parent' => $ID, 'orderby' => 'date', 'order' => 'ASC', 'post_status' => 'publish', 'fields' => 'ids']);
+    array_unshift($points, $ID);
+
+    $temporalCoverage = date('Y-m-d', strtotime($meta->get('post_date')));
+    $base = sanitize_title($meta->get('post_title'));
+
+    $last = array_key_last($points);
+
+    foreach ($points as $index => $point) {
+        $pointMeta = Meta::forPost($point);
+
+//        $observation = new \JVBase\inc\managers\SEO\render\Thing\Intangible\Observation();
+
+        $image = Resolver::imgIDToSchema($pointMeta->get('post_thumbnail'));
+        $id = $index === 0 ? '-before-tattoo-removal' : '-treatment-'.$index;
+
+//        $observation->setId($base.'-observation'.$id);
+
+        $image->setId($base . $id);
+        $name = $index === 0 ?
+            'Before Laser Tattoo Removal' :
+            'After Treatment '.$index;
+        $image->setName($name);
+        $description = $pointMeta->get('post_excerpt');
+
+        $timeline = $pointMeta->get('timeline');
+        if (!empty($timeline)) {
+            $time = array_map('absint', explode(',', $timeline));
+            $time = array_filter(array_map(function($ID) {
+                $term = get_term($ID, BASE.'timeline');
+                return $term->name??false;
+            }, $time));
+            $time = jvbCommaList($time);
+
+            $description .= 'Photo taken '.$time.' after treatment '.$index;
+        }
+
+        $image->setDescription($description);
+
+        $image->setDateCreated($pointMeta->get('post_date'));
+
+
+        $galleryItems[] = $image;
+
+        if ((int)$index === (int)$last) {
+            $temporalCoverage .= '/'. date('Y-m-d', strtotime($pointMeta->get('post_date')));
+        }
+    }
+
+    $hasPart= [];
+    if (!empty ($galleryItems)) {
+        $gallery->setImage($galleryItems);
+        $schema[] = $gallery->outputSchema();
+        $hasPart[] = ['@id' => $gallery->getId()];
+    }
+
+    //Set the temporal coverage (date start/date end)
+    $work->setTemporalCoverage($temporalCoverage);
+
+    $work->setCreator(SchemaHelper::reference('organization'));
+
+
+    $output = $work->outputSchema();
+    if (!empty($hasPart)) {
+        $output['hasPart'] = $hasPart;
+    }
+
+
+
+    array_unshift($schema, $output);
+
+    return $schema;
+}
+
+function altr_build_singular_progress_schema_reference(int $ID):Report
+{
+    $work = new Report();
+    $meta = Meta::forPost($ID);
+    $url = get_the_permalink($ID);
+    $title = $meta->get('post_title');
+    $id = 'case-study-'.sanitize_title($title);
+    $work->setId($url.'/#'.$id);
+    $work->setUrl($url);
+    $work->setName($title.' | Before & After Tattoo Removal');
+
+    $points = get_children(['post_parent' => $ID, 'orderby' => 'date', 'order' => 'ASC', 'post_status' => 'publish', 'fields' => 'ids']);
+
+    $description = 'A ';
+    $themes = $meta->get('theme');
+    if (!empty($themes)) {
+        $description .= jvbCommaList(array_filter(array_map(function($ID) {
+            $term = get_term($ID, BASE.'theme');
+            return $term->name??false;
+        }, explode(',', $themes)))).' ';
+    }
+    $style = $meta->get('style');
+    if (!empty($style)) {
+        $description .= jvbCommaList(array_filter(array_map(function($ID) {
+                $term = get_term($ID, BASE.'theme');
+                return $term->name??false;
+            }, explode(',', $style)))).' ';
+    }
+    $description .= 'tattoo before any laser tattoo removal treatments, and after '.count($points).' treatments.';
+
+    $work->setDescription($description);
+
+    $last = $points[array_key_last($points)];
+    $lastMeta = Meta::forPost($last);
+
+    $temporalCoverage = date('Y-m-d', strtotime($meta->get('post_date'))).'/'.
+        date('Y-m-d', strtotime($lastMeta->get('post_date')));
+
+    $work->setTemporalCoverage($temporalCoverage);
+
+    return $work;
+}
+
+function altr_progress_meta():array
+{
+    return[
+        'title' => '{{post_title}}',
+        'description' => 'See this {{style.name}} {{theme.name}} {{age.name}}-old tattoo before and after {{number}} laser tattoo removal treatments on the {{body_part.name}}.',
+    ];
+}
+
+function altr_progress_archive(array $defaults):array
+{
+    return array_merge($defaults, [
+        'name' => 'Tattoos Before and After Laser Tattoo Removal',
+    ]);
+}
+
+function altr_progress_reference_schema(array $defaults):array
+{
+    return $defaults;
+}
+
+//function altr_progress():array
+//{
+//    return [
+//        'singular'       => 'Before & After',
+//        'plural'       => 'Before & Afters',
+//        'dash_title'    => 'Progress',
+//        'dash_description' => 'Manage your before and after posts',
+//        'breadcrumb'    => 'Before & Afters',
+//        'capability_type' => ['progress', 'progress'],
+//        'hide_children' => true,
+//        'is_timeline'   => true,
+//        'show_feed'    => true,
+//        'show_directory'=> true,
+//        'directory_extra'=> ['goal', 'skin-type','age'],
+//        'hierarchical'  => true,
+//        'icon'         => 'arrows-left-right',
+//        'rewrite'      => [
+//            'slug'       => 'before-and-after',
+//            'with_front' => false,
+//        ],
+//        'sections'  => [
+//            'progression'   => [
+//                'label' => 'Progression',
+//            ]
+//        ],
+//        'custom_order' => [
+//            'number'    => [
+//                'label' => 'Number of Treatments',
+//                'icon'  => 'hash-straight',
+//                'for'   => 'progress',
+//            ]
+//        ],
+//        'seo' => [
+//            'schema' => [
+//                'type' => 'BeforeAfter',
+//                'name' => '{{post_title}}',
+//                'description' => '{{post_excerpt}}',
+//                'temporalCoverage' => '{{post_date}}/{{last_date}}',
+//                'additionalProperty' => [
+//                    ['name' => 'Number of sessions', 'value' => '{{number.name}}'],
+//                    ['name' => 'Treatment area', 'value' => '{{body-part.name}}'],
+//                    ['name' => 'Tattoo style', 'value' => '{{style.name}}'],
+//                    ['name' => 'Skin type', 'value' => '{{skin-type.name}}'],
+//                    ['name' => 'Goal', 'value' => '{{goal.name}}'],
+//                ],
+//                'associatedMedia' => '{{timeline_photos}}',
+//            ],
+//            'meta' => [
+//                'title' => '{{style.name}} {{theme.name}} Tattoo – Before & After {{number}} Laser Removal Sessions',
+//                'description' => 'See this {{style.name}} {{theme.name}} {{age.name}}-old tattoo before and after {{number}} laser tattoo removal treatments on the {{body_part.name}}.',
+//            ],
+//            'archive' => [
+//                'type' => 'CollectionPage',
+//                'name' => 'Tattoos Before and After Laser Tattoo Removal',
+//            ],
+//        ],
+//        'feed'      => [
+//            'single'    => [
+//                'pre_title' => 'Before & After Laser Tattoo Removal',
+//            ],
+//            'archive'   => [
+//
+//            ],
+//            'config'    => [
+//                'is_gallery'    => false,
+//                'content'       => 'progress',
+//                'context'       => 'progress',
+//                'id'            => [],
+//                'class'         => [],
+//            ]
+//        ],
+//        'fields'       => [
+//            'post_title'     => [
+//                'type'  => 'text',
+//                'label' => 'Title',
+//                'quickEdit' => true,
+//                'section'   => 'progression',
+//                'for_all'   => true,
+//            ],
+//            'post_status'         => [
+//                'type'      => 'radio',
+//                'label'     => 'Status',
+//                'options'   => [
+//                    'publish'   => 'Show',
+//                    'draft'     => 'Hide',
+//                    'trash'     => 'Scrap',
+//                    'delete'    => 'Permanently Delete'
+//                ],
+//                'for_all'   => true,
+//            ],
+//            'post_date'  => [
+//                'type'      => 'date',
+//                'label'     => 'Date',
+//                'for_all'   => true,
+//            ],
+//            'post_thumbnail'                => [
+//                'type'      =>  'upload',
+//                'label'     => 'Image',
+//                'quickEdit' => true,
+//                'section'   => 'progression',
+//                'for_all'   => true,
+//            ],
+//            'person' => [
+//                'type'  => 'taxonomy',
+//                'taxonomy'  => 'person',
+//                'autocomplete' => true,
+//                'label' => 'Person',
+//                'quickEdit' => true,
+//                'createNew' => true,
+//                'section'   => 'progression',
+//                'hint'      => 'Not public, just to make it easier to find'
+//            ],
+//            'body-part' => [
+//                'type'  => 'taxonomy',
+//                'taxonomy'  => 'body-part',
+//                'label' => 'Body Part',
+//                'autocomplete' => true,
+//                'quickEdit' => true,
+//                'createNew' => true,
+//                'section'   => 'progression'
+//            ],
+//            'goal' => [
+//                'type'  => 'taxonomy',
+//                'taxonomy'  => 'goal',
+//                'autocomplete' => true,
+//                'label' => 'Goal',
+//                'quickEdit' => true,
+//                'createNew' => true,
+//                'section'   => 'progression'
+//            ],
+//            'timeline' => [
+//                'type'  => 'taxonomy',
+//                'taxonomy'  => 'timeline',
+//                'autocomplete' => true,
+//                'label' => 'Timeline',
+//                'quickEdit' => true,
+//                'createNew' => true,
+//                'section'   => 'progression',
+//                'for_all'   => true,
+//                'hidden'    => true,
+//            ],
+//            'style' => [
+//                'type'  => 'taxonomy',
+//                'taxonomy'  => 'style',
+//                'autocomplete' => true,
+//                'label' => 'Tattoo Style',
+//                'quickEdit' => true,
+//                'createNew' => true,
+//                'section'   => 'progression'
+//            ],
+//            'theme' => [
+//                'type'  => 'taxonomy',
+//                'taxonomy'  => 'theme',
+//                'autocomplete' => true,
+//                'label' => 'Tattoo Theme',
+//                'quickEdit' => true,
+//                'createNew' => true,
+//                'section'   => 'progression'
+//            ],
+//            'skin-type' => [
+//                'type'  => 'taxonomy',
+//                'taxonomy'  => 'skin-type',
+//                'label' => 'Skin Type',
+//                'autocomplete' => true,
+//                'quickEdit' => true,
+//                'createNew' => true,
+//                'section'   => 'progression'
+//            ],
+//            'age' => [
+//                'type'  => 'taxonomy',
+//                'taxonomy'  => 'age',
+//                'autocomplete'      => true,
+//                'label' => 'Age of Tattoo',
+//                'quickEdit' => true,
+//                'createNew' => true,
+//                'section'   => 'progression'
+//            ],
+//            'number' => [
+//                'type'  => 'text',
+//                'subtype'  => 'number',
+//                'label' => 'Number of Treatments',
+//                'quickEdit' => true,
+//                'section'   => 'progression',
+//                'for_all'   => true,
+//                'hidden'    => true,    //auto calculated
+//            ],
+//            'post_content'   => [
+//                'type'  => 'textarea',
+//                'quill' => true,
+//                'label' => 'Notes',
+//                'section'   => 'progression',
+//                'for_all'   => true,
+//            ],
+//            'last_date' => [
+//                'type'  => 'number',
+//                'label' => 'Last Date',
+//                'hidden'    => true,
+//                'default'   => 0,
+//                'for_all'   => true,
+//            ]
+//        ],
+//        'upload_title' => 'Upload Before & Afters',
+//    ];
+//}
+function altr_render_progress_field_post_modified(?int $ID = null, bool $isTemplate = false):string
+{
+    $points = is_null($ID) ? [] : jvbTimelinePoints($ID, BASE.'progress');
+    $value = '';
+    if (!empty($points)){
+        $last = $points[array_key_last($points)];
+        $lastMeta = Meta::forPost($last);
+        $value = $lastMeta->get('post_date');
+    }
+    return $isTemplate || !empty($value) ? sprintf(
+         '<div class="row left"><span class="label">Last Treated:</span><time data-field="post_modified"%s>%s</time></div>',
+        date('c', strtotime($value)),
+        date('M Y', strtotime($value))
+    ) : '';
+}
+function altr_render_progress_field_post_date(?int $ID = null, bool $isTemplate = false):string
+{
+    $meta = ($ID) ? Meta::forPost($ID) : false;
+    $value = ($meta) ? $meta->get('post_date') : '';
+    return $isTemplate || !empty($value) ? sprintf(
+        '<div class="row left"><span class="label">Started:</span><time data-field="post_date"%s>%s</time></div>',
+        date('c', strtotime($value)),
+        date('M Y', strtotime($value))
+    ) : '';
+}
+function altr_render_progress_feed_item_images(?int $ID = null, array $images = []):string
+{
+    $meta = ($ID) ? Meta::forPost($ID) : false;
+    $points = is_null($ID) ? [] : get_children([
+        'post_parent'   => $ID,
+        'post_type'     => BASE.'progress',
+        'post_status'   => 'publish',
+        'orderby'       => 'date',
+        'order'         => 'ASC',
+        'fields'        => 'ids',
+    ]);
+
+    $lastImg = '';
+    if (!empty($points)) {
+        $last = $points[array_key_last($points)];
+        $lastMeta = Meta::forPost($last);
+        $lastImg = $lastMeta->get('post_thumbnail');
+    }
+
+    $defaultBefore = '<img data-field="before" width="300px" height="300px" loading="lazy" decoding="async">';
+    $defaultAfter = '<img data-field="after" width="300px" height="300px" loading="lazy" decoding="async">';
+
+    $total = count($points);
+    return sprintf(
+        '<span class="before-text">Before</span>
+        %s%s
+        <span class="after-text">After%s</span>',
+        $meta ? str_replace('<img', '<img data-field="before" class="before"',jvbFormatImage($meta->get('post_thumbnail'), 'tiny', 'medium')) : $defaultBefore,
+        !empty($lastImg) ? str_replace('<img', '<img data-field="after" class="after"',jvbFormatImage($lastImg, 'tiny', 'medium')) : $defaultAfter,
+        empty($points) ? '' : ' '.$total.' Tx'
+    );
+
+}
+
+add_filter('jvbFeedItemData', 'altr_progress_item_data', 10, 2);
+function altr_progress_item_data(string $out, string $content) {
+    if ($content === 'progress') {
+        return ' data-timeline';
+    }
+    return $out;
+}
+
 add_filter('jvbFeedItem', 'altr_progress_item', 10, 2);
 
 function altr_progress_item(string $out, string $content):string
@@ -234,12 +735,12 @@
                 <p data-field="started">Started: <time></time></p>
                 <p data-field="updated">Last treated: <time></time></p>
                 <p data-field="number">Total Treatments: <b></b></p>
-                <ul data-field="goal" class="term-list"><?= array_key_exists('icon', JVB_TAXONOMY['goal']) ? jvbIcon(JVB_TAXONOMY['goal']['icon']) : '' ?><li><a></a></li></ul>
-                <ul data-field="body-part" class="term-list"><?= array_key_exists('icon', JVB_TAXONOMY['body-part']) ? jvbIcon(JVB_TAXONOMY['body-part']['icon']) : '' ?><li><a><i></i></a></li></ul>
-                <ul data-field="skin-type" class="term-list"><?= array_key_exists('icon', JVB_TAXONOMY['skin-type']) ? jvbIcon(JVB_TAXONOMY['skin-type']['icon']) : '' ?><li><a><i></i></a></li></ul>
-                <ul data-field="age" class="term-list"><?= array_key_exists('icon', JVB_TAXONOMY['age']) ? jvbIcon(JVB_TAXONOMY['age']['icon']) : '' ?><li><a><i></i></a></li></ul>
-                <ul data-field="style" class="term-list"><?= array_key_exists('icon', JVB_TAXONOMY['style']) ? jvbIcon(JVB_TAXONOMY['style']['icon']) : '' ?><li><a><i></i></a></li></ul>
-                <ul data-field="theme" class="term-list"><?= array_key_exists('icon', JVB_TAXONOMY['theme']) ? jvbIcon(JVB_TAXONOMY['theme']['icon']) : '' ?><li><a><i></i></a></li></ul>
+                <ul data-field="goal" class="term-list"><?= jvbIcon(Registrar::getInstance('goal')->getIcon()) ?><li><a></a></li></ul>
+                <ul data-field="body_part" class="term-list"><?= jvbIcon(Registrar::getInstance('body_part')->getIcon()) ?><li><a><i></i></a></li></ul>
+                <ul data-field="skin_type" class="term-list"><?= jvbIcon(Registrar::getInstance('skin_type')->getIcon()) ?><li><a><i></i></a></li></ul>
+                <ul data-field="age" class="term-list"><?= jvbIcon(Registrar::getInstance('age')->getIcon()) ?><li><a><i></i></a></li></ul>
+                <ul data-field="style" class="term-list"><?= jvbIcon(Registrar::getInstance('style')->getIcon()) ?><li><a><i></i></a></li></ul>
+                <ul data-field="theme" class="term-list"><?=jvbIcon(Registrar::getInstance('theme')->getIcon()) ?><li><a><i></i></a></li></ul>
             </div>
         </details>
     </div>
@@ -255,16 +756,21 @@
     if ($postType !== BASE.'progress') {
         return $out;
     }
-    $route = JVB()->routes('content');
 
+    $route = JVB()->routes('content');
     global $post;
     $data = $route->formatTimeline($post);
-    $timeline = $data['fields']['timeline'];
+    $timeline = $data['fields']['timeline_gallery'];
+
+    if (!is_array($timeline)) {
+        return $out;
+    }
     $total = count($timeline);
     if ($total === 1) {
         return $out;
     }
 
+
     $total--;
     $first = '<span class="before">Before</span>'.jvbFormatImage($timeline[0]['post_thumbnail'],'tiny','medium',false);
     $last = '<span class="after">After '.$total.' Tx</span>'.jvbFormatImage($timeline[$total]['post_thumbnail'],'tiny','medium',false);
@@ -285,11 +791,11 @@
         $after = jvbIcon('logo-triangle-fill').jvbFormatImage(get_post_thumbnail_id($last),'tiny','directory-preview',false);
     }
 
-    return '<li class="row btw">
+    return '<li class="row x-btw">
         
                     <a href="'.$item['url'].'" title="More about '.$item['name'].'">
-                        '.$item['name'].'</a>'.$extra.'
-                        <div class="image">'.$before.$after.'</div>
+                        '.$item['name'].'</a>
+                        <div class="image">'.$before.$after.'</div>'.$extra.'
                 </li>';
 }
 
@@ -329,9 +835,9 @@
     if (!$thumbnail || $thumbnail === 0) {
         return;
     }
-    $meta = new Meta($ID, 'post');
+    $meta = Meta::forPost($ID);
     $number = $meta->get('number');
-    $terms = $meta->getAll(['style', 'body-part','goal', 'skin-type', 'age', 'timeline']);
+    $terms = $meta->getAll(['style', 'body_part','goal', 'skin_type', 'age', 'timeline']);
     foreach($terms as $slug => $value) {
         $terms = array_filter(
                 array_map(function($term) use($slug) {
@@ -343,10 +849,10 @@
         );
 
         switch ($slug) {
-            case 'skin-type':
+            case 'skin_type':
                 $slug = 'skinType';
                 break;
-            case 'body-part':
+            case 'body_part':
                 $slug = 'bodyPart';
                 break;
         }

--
Gitblit v1.10.0