Jake Vanderwerf
2026-03-03 772462eeca3002a1d52508aeba485aab2b4742ad
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
<?php
namespace JVBase\managers\SEO\schemas\resolvers;
 
use JVBase\managers\SEO\schemas\SchemaDefinition;
use JVBase\managers\SEO\SchemaReferenceBuilder;
use JVBase\meta\Meta;
use JVBase\registrar\Registrar;
 
if (!defined('ABSPATH')) {
    exit;
}
 
/**
 * Resolver for Person schema (artists, staff, authors).
 *
 * Auto-enrichment:
 * - Adds `worksFor` from shop/organization association
 * - Adds `makesOffer` / sample `workExample` from their content
 * - Derives `knowsAbout` from their content's taxonomy terms
 */
class PersonResolver extends BaseResolver
{
    public function getAutoFields(SchemaDefinition $definition): array
    {
        $fields = [];
 
        if (!$definition->objectId) {
            return $fields;
        }
 
        // For user-type Person schemas (author pages)
        if ($definition->objectType === 'user') {
            $worksFor = $this->buildWorksFor($definition->objectId);
            if (!empty($worksFor)) {
                $fields['worksFor'] = $worksFor;
            }
 
            $examples = $this->buildWorkExamples($definition->objectId);
            if (!empty($examples)) {
                $fields['workExample'] = $examples;
            }
        }
 
        return $fields;
    }
 
    /**
     * Find Organization/LocalBusiness the person works for.
     *
     * Checks taxonomy terms assigned to the user (e.g., shop terms).
     */
    private function buildWorksFor(int $userId): ?array
    {
        $contentTypes = Registrar::getFeatured('is_content', 'term');
        if (empty($contentTypes)) {
            return null;
        }
 
        foreach ($contentTypes as $content) {
            $fullTax = jvbCheckBase($content);
            $terms = wp_get_object_terms($userId, $fullTax);
 
            if (is_wp_error($terms) || empty($terms)) {
                continue;
            }
 
            // Return first associated organization
            $term = $terms[0];
 
            return SchemaReferenceBuilder::build(
                'term',
                $term->term_id
            );
        }
 
        return null;
    }
 
    /**
     * Build work examples from the person's authored content.
     */
    private function buildWorkExamples(int $userId, int $limit = 5): array
    {
        $role = jvbUserRole($userId);
        $registrar = Registrar::getInstance($role);
 
        if (!$registrar){
            return [];
        }
        $types = $registrar->getCreatable();
        if (empty($types)){
            return [];
        }
 
        $examples = [];
 
        foreach ($types as $slug) {
            $type = jvbCheckBase($slug);
 
            $posts = get_posts([
                'post_type'      => $type,
                'author'         => $userId,
                'posts_per_page' => $limit,
                'post_status'    => 'publish',
                'fields'         => 'ids',
            ]);
 
            if (empty($posts)) {
                continue;
            }
 
            $refs = SchemaReferenceBuilder::buildMultiple('post', $posts, null, true);
 
            if (!empty($refs)) {
                $examples = array_merge($examples, $refs);
            }
 
            // Cap total examples
            if (count($examples) >= $limit) {
                $examples = array_slice($examples, 0, $limit);
                break;
            }
        }
 
        return $examples;
    }
}