Jake Vanderwerf
2026-01-29 e6672fe38ce5d99f3b3f026154f777aded7361de
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
<?php
namespace JVBase\meta;
 
if (!defined('ABSPATH')) {
    exit;
}
 
/**
 * Data container for a single WordPress object (post, term, user, or options)
 * Holds the WP object reference and a collection of Field instances
 */
final class Item
{
    public int|string|null $id;
    public string $objectType;      // post, term, user, options
    public ?string $contentType;    // tattoo, artist, style (without BASE prefix)
    public ?object $wpObject;       // WP_Post, WP_Term, WP_User
 
    /** @var array<string, Field> */
    public array $fields = [];
 
    /** @var array<string, array> Raw field configs from registry */
    public array $fieldConfigs = [];
 
    public ?string $baseKey = null; // For options
 
    public const WP_DEFAULTS = [
        'post' => [
            'post_title',
            'post_excerpt',
            'post_content',
            'post_date',
            'post_status',
            'post_modified',
            'post_thumbnail',
            'menu_order'
        ],
        'user' => [
            'first_name',
            'last_name',
            'display_name',
            'description',
            'user_email',
        ],
        'term' => [
            'term_name',
            'description'
        ]
    ];
 
    public function __construct(
        int|string|null $id,
        string $objectType,
        ?string $contentType = null
    ) {
        $this->id = $id;
        $this->objectType = $objectType;
        $this->contentType = $contentType;
    }
 
    public function hasField(string $name): bool
    {
        return isset($this->fields[$name]) || isset($this->fieldConfigs[$name]);
    }
 
    public function getField(string $name): ?Field
    {
        return $this->fields[$name] ?? null;
    }
 
    public function setField(Field $field): self
    {
        $this->fields[$field->name] = $field;
        return $this;
    }
 
    public function getFieldConfig(string $name): ?array
    {
        return $this->fieldConfigs[$name] ?? null;
    }
 
    public function isWpDefault(string $name): bool
    {
        $defaults = self::WP_DEFAULTS[$this->objectType] ?? [];
        return in_array($name, $defaults, true);
    }
 
    public function getDirtyFields(): array
    {
        return array_filter($this->fields, fn(Field $f) => $f->isDirty);
    }
 
    public function getInvalidFields(): array
    {
        return array_filter($this->fields, fn(Field $f) => !$f->isValid);
    }
 
    public function markAllClean(): self
    {
        foreach ($this->fields as $field) {
            $field->markClean();
        }
        return $this;
    }
 
    public function hasDirtyFields(): bool
    {
        return !empty($this->getDirtyFields());
    }
 
    public function isValid(): bool
    {
        return empty($this->getInvalidFields());
    }
}