From b7aed073c23396afa7eccb488dd25bfa222c1819 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Thu, 28 May 2026 19:54:05 +0000
Subject: [PATCH] =gitblit switch

---
 users/artists.php |  271 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 242 insertions(+), 29 deletions(-)

diff --git a/users/artists.php b/users/artists.php
index 63e0eb0..6b6cd8b 100644
--- a/users/artists.php
+++ b/users/artists.php
@@ -252,17 +252,18 @@
         'max'     => 1,
         'label'     => 'You are a:'
     ]);
-//    $fields->addCommon('wiki');
-//    $fields->addCommon('alternate_name');
-//    $fields->addCommon('specialties');
-//    $fields->addCommon('rate');
-//    $fields->addCommon('awards');
-//    $fields->addCommon('ratings');
-//    $fields->addCommon('reviews');
-//    $fields->addCommon('services');
-//    $fields->addCommon('languages');
-//    $fields->addCommon('credentials');
-//    $fields->addCommon('keywords');
+    $fields->addCommon('wiki');
+    $fields->addCommon('alternate_name');
+    $fields->addCommon('specialties');
+    $fields->addCommon('rate');
+    $fields->addCommon('awards');
+    $fields->addCommon('ratings');
+    $fields->addCommon('reviews');
+    $fields->addCommon('services');
+    $fields->addCommon('languages');
+    $fields->addCommon('credentials');
+    $fields->addCommon('keywords');
+    $fields->modifyField('keywords', 'default', [ 'Edmonton tattoos', 'Edmonton tattoo artist', 'Edmonton tattooist' ]);
 
 
     $contact = $profile->addSection('contact')
@@ -291,20 +292,20 @@
 
     $seo = $profile->getSEO();
 
-//    $seo = $profile->addSection('seo')
-//        ->setIcon('robot')
-//        ->setFields([
-//            'alternate_name',
-//            'specialties',
-//            'rate',
-//            'awards',
-//            'ratings',
-//            'reviews',
-//            'services',
-//            'languages',
-//            'credentials',
-//            'keywords'
-//        ]);
+    $seo = $profile->addSection('seo')
+        ->setIcon('robot')
+        ->setFields([
+            'alternate_name',
+            'specialties',
+            'rate',
+            'awards',
+            'ratings',
+            'reviews',
+            'services',
+            'languages',
+            'credentials',
+            'keywords'
+        ]);
 
 }
 
@@ -313,15 +314,17 @@
     return [
         'type'              => 'JVBase\managers\SEO\render\Thing\CreativeWork\WebPage\ProfilePage',
         'name'              => '{{post_title}} | Edmonton\'s Best {{artist_type.name}}',
-        'about'             => [
+        'mainEntity'             => [
             'type'  => 'JVBase\managers\SEO\render\Thing\Person',
             'name'  => '{{post_title}}',
+            'image' => '{{image_portrait}}',
             'givenName' => '{{first_name',
             'description' => '{{post_excerpt}}',
             'memberOf'  => ['@id' => get_home_url().'/#organization'],
             'alternateName' => '{{alternate_name}}',
-            'workLocation'  => '{{city}}'
-
+            'workLocation'  => '{{city.reference}}',
+            'worksFor'      => '{{shop.name}}',
+            'jobTitle'      => '{{artist_type.name}}',
         ],
         'description'       => '{{post_excerpt}}',
     ];
@@ -330,6 +333,9 @@
 add_filter('jvb_single_artit_profile_schema_output', 10, 2);
 function aei_artist_schema_output(ProfilePage $profile, int $ID):ProfilePage
 {
+    /**
+     * @var \JVBase\managers\SEO\render\Thing\Person\Person $person
+     */
     $person = $profile->getAbout();
     $meta = Meta::forPost($ID);
     $public_contact = $meta->get('public_contact');
@@ -371,6 +377,210 @@
 //        ])
 //    }
 
+    $userID = get_post_meta($ID, BASE.'profile_link', true);
+    $owns = JVB()->roles()->getOwnedTerms($userID);
+    if (!empty($owns)) {
+        $shops = [];
+        foreach ($owns as $shopID) {
+            $term = get_term($shopID);
+            if ($term && !is_wp_error($term)) {
+                $shopRegistrar = Registrar::getInstance($term->taxonomy);
+                if ($shopRegistrar) {
+                    $temp = $shopRegistrar->getSEO()->schema();
+                    $shops[] = $temp->outputReferenceSchema($shopID, $shopRegistrar->getType());
+                }
+            }
+        }
+        if (!empty($shops)) {
+            $person->setOwns($shops);
+        }
+    }
+
+    $get = ['style', 'theme'];
+    $knowsAbout = [];
+    foreach ($get as $g) {
+        $registrar = Registrar::getInstance($g);
+        $tmp = $registrar->getSEO()->schema();
+        $top = $meta->get("top_{$g}s");
+        if (empty($top)) {
+            $top = $meta->get($g);
+        }
+        if (is_string($top)) {
+            $top = array_map('absint', explode(',', $top));
+        }
+        foreach ($top as $t) {
+            $knowsAbout[] = $tmp->outputReferenceSchema($t, $registrar->getType());
+        }
+    }
+    if (!empty($knowsAbout)) {
+        $person->setKnowsAbout($knowsAbout);
+    }
+
+    /**
+     * Specialties
+     */
+    $specialties = $meta->get('specialties');
+
+
+    /**
+     * Build the offers this artist creates
+     *  - first, we check each post type to see if they have any published
+     *  - Next, we get the users'
+     *          - city (or cities)
+     *          - rate
+     *          - average rating
+     *          - reviews
+     *     and attach them to the services/products
+     *  - the resulting array gets set to the Person's makesOffer
+     */
+    $types = ['tattoo', 'piercing', 'artwork'];
+    $offers = [];
+    $cities = $meta->get('city');
+    $rate = $meta->get('rate');
+    $reviews = $meta->get('reviews');
+    $rating = $meta->get('aggregateRating');
+    $theCities = $theRate = $theReviews = $theRating = null;
+    foreach ($types as $type){
+        $based = jvbCheckBase($type);
+        $hasAny = new WP_Query([
+            'post_type'         => $based,
+            'posts_per_page'    => 1,
+            'fields'            => 'ids',
+            'post_author'       => $userID
+        ]);
+        if ($hasAny->have_posts()) {
+            $offer = new \JVBase\managers\SEO\render\Thing\Intangible\Offer();
+            $service = $type === 'artwork' ? new \JVBase\managers\SEO\render\Thing\Product\Product() : new \JVBase\managers\SEO\render\Thing\Intangible\Service();
+            if (is_null($theCities)) {
+                $theCities = [];
+                if (!empty($cities)) {
+                    if (is_string($cities)) {
+                        $cities = array_map('absint', explode(',', $cities));
+                    }
+                    foreach ($cities as $termID) {
+                        $city = get_term($termID);
+                        $theCities[] = ['@type' => 'City','name' => $city->name];
+                    }
+                }
+            }
+            if (!empty($theCities)) {
+                $service->setAreaServed($theCities);
+            }
+            if (is_null($theRate)) {
+                $theRate = false;
+                if (!empty($rate)) {
+                    $theRate = new \JVBase\managers\SEO\render\Thing\Intangible\StructuredValue\PriceSpecification();
+                    $theRate->setPrice($rate);
+                    $theRate->setPriceCurrency('CAD');
+                    $theRate->setUnitText('HOUR');
+                }
+            }
+            if ($theRate) {
+                $offer->setPriceSpecification($theRate);
+            }
+
+            if (is_null($theReviews)) {
+                $theReviews = [];
+                foreach ($reviews as $r) {
+                    $review = new \JVBase\managers\SEO\render\Thing\CreativeWork\Review();
+
+                    if (!empty($r['name'])) {
+                        $review->setAuthor(['type' => 'JVBase\managers\SEO\render\Thing\Person\Person', 'name' => $r['name']]);
+                    }
+                    if (!empty($r['date'])) {
+                        $review->setDateCreated([$r['date']]);
+                    }
+                    if (!empty($r['review'])) {
+                        $review->setReviewBody($r['review']);
+                    }
+                    if (array_key_exists('rating', $r) && $r['rating'] !== 'none') {
+                        $rating = new \JVBase\managers\SEO\render\Thing\Intangible\Rating\Rating();
+                        $rating->setRatingValue($r['rating']);
+                        $rating->setBestRating(5);
+                        $rating->setWorstRating(1);
+                        $review->setReviewRating($rating);
+                    }
+                    if (!empty($r['url'])) {
+                        $review->setUrl($r['url']);
+                    }
+                    $theReviews[] = $review;
+                }
+            }
+            if (!empty($theReviews)) {
+                $service->setReview($theReviews);
+            }
+
+            if (is_null($theRating)) {
+                $theRating = false;
+                if (!empty($rating) && $rating !== 'none') {
+                    $theRating = new \JVBase\managers\SEO\render\Thing\Intangible\Rating\AggregateRating();
+                    $theRating->setRatingValue($rating);
+                    $count = $meta->get('total_ratings')?:1;
+                    $theRating->setRatingCount($count);
+                }
+            }
+            if ($theRating) {
+                $service->setAggregateRating($theRating);
+            }
+
+
+            switch ($type) {
+                case 'tattoo':
+                    $service->setName('Custom Tattoos');
+                    break;
+                case 'piercing':
+                    $service->setName('Piercings');
+                    break;
+                case 'artwork':
+                    $service->setName('Artwork');
+                    break;
+            }
+
+            $offer->setItemOffered($service);
+            $offers[] = $offer;
+        }
+    }
+    if (!empty($offers)) {
+        $person->setMakesOffer($offers);
+    }
+
+    /**
+     * Build Artist Portfolio
+     */
+    $portfolio = new WP_Query([
+       'post_author'    => $userID,
+       'post_type'      => [BASE.'tattoo', BASE.'piercing', BASE.'artwork'],
+       'meta_key'       => BASE.'karma',
+        'orderby'       => 'meta_value_num',
+        'order'         => 'DESC',
+        'posts_per_page'=> 20,
+        'fields'        => 'ids'
+    ]);
+
+    if ($portfolio->have_posts()) {
+        $hasPart = new JVBase\inc\managers\SEO\render\Thing\CreativeWork\WebPage\CollectionPage\CollectionPage();
+        $hasPart->setName($meta->get('post_title').'\'s Portfolio');
+        $hasPart->setUrl(get_the_permalink($ID));
+        $itemList = new JVBase\managers\SEO\render\Thing\Intangible\ItemList\ItemList();
+        $pos = 1;
+        $collection = array_map(function ($ID) use ($pos) {
+            $type = get_post_type($ID);
+            $registrar = Registrar::getInstance($type);
+            $schema = $registrar->getSEO()->schema();
+            $item = $schema->outputReferenceSchema($ID, $registrar->getType(), false);
+            $listItem = new \JVBase\managers\SEO\render\Thing\Intangible\ListItem();
+            $listItem->setPosition($pos);
+            $pos++;
+            $listItem->setItem($item);
+            return $listItem;
+        }, $portfolio->posts);
+        $itemList->setItemListElement($collection);
+        $itemList->setItemListElement($itemList);
+        $hasPart->setMainEntity($itemList);
+
+        $profile->setHasPart($hasPart);
+    }
+
 
 
     return $profile;
@@ -387,11 +597,14 @@
 function aei_artist_archive(array $defaults):array
 {
     return array_merge($defaults, [
-        'name' => '{{name}}\'s Best Tattoo Artists',
+        'name' => 'Edmonton\'s Best Tattoo Artists',
     ]);
 }
 
 function aei_artist_reference_schema(array $defaults):array
 {
+    $defaults['image'] = '{{image_portrait}}';
+    $defaults['worksFor'] = '{{shop.name}}';
+    $defaults['knowsAbout'] = '{{style.name}}';
     return $defaults;
 }
\ No newline at end of file

--
Gitblit v1.10.0