Jake Vanderwerf
2026-03-29 275c0d74cd68677622a5431505c5c870c473063d
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
<?php
namespace JVBase\meta;
 
if (!defined('ABSPATH')) {
    exit;
}
 
/**
 * Single field data container
 * Holds value, config, and tracks dirty state
 */
final class Field
{
    public string $name;
    public mixed $value;
    public mixed $originalValue;
    public array $config;
    public bool $isDirty = false;
    public bool $isValid = true;
    public bool $isDefault = false;
    public array $errors = [];
 
    public function __construct(string $name, mixed $value, array $config = [])
    {
        $this->name = $name;
        $this->value = $value;
        $this->originalValue = $value;
        $this->config = $config;
        if (array_key_exists('wp', $config) && $config['wp'] === true) {
            $this->isDefault = true;
        }
    }
 
    /**
     * Set field value and track dirty state
     */
    public function set(mixed $value): self
    {
        error_log('Checking if value is the same as old value: '.print_r($value, true));
        if ($value !== $this->value) {
            error_log('Saving new value: '.print_r($value, true));
            $this->value = $value;
            $this->isDirty = true;
        }
        return $this;
    }
 
    /**
     * Get current value
     */
    public function get(): mixed
    {
        return $this->value;
    }
 
    /**
     * Mark field as clean (after save)
     */
    public function markClean(): self
    {
        $this->originalValue = $this->value;
        $this->isDirty = false;
        return $this;
    }
 
    /**
     * Reset to original value
     */
    public function reset(): self
    {
        $this->value = $this->originalValue;
        $this->isDirty = false;
        return $this;
    }
 
    /**
     * Add validation error
     */
    public function addError(string $message): self
    {
        $this->errors[] = $message;
        $this->isValid = false;
        return $this;
    }
 
    /**
     * Clear all errors
     */
    public function clearErrors(): self
    {
        $this->errors = [];
        $this->isValid = true;
        return $this;
    }
 
    /**
     * Get field type from config
     */
    public function type(): string
    {
        return $this->config['type'] ?? 'text';
    }
 
    /**
     * Check if this is a WordPress default field
     */
    public function isWpDefault(): bool
    {
        return $this->isDefault ?? false;
    }
 
    /**
     * Check if this is a taxonomy relationship field (not taxonomy_type)
     */
    public function isTaxonomy(): bool
    {
        return ($this->type() === 'taxonomy' || ($this->type() === 'selector' && isset($this->config['subtype']) && $this->config['subtype'] === 'taxonomy')) && !isset($this->config['isReference']);
    }
 
    /**
     * Check if field is required
     */
    public function isRequired(): bool
    {
        return !empty($this->config['required']);
    }
 
    /**
     * Get field label
     */
    public function label(): string
    {
        return $this->config['label'] ?? $this->name;
    }
 
    /**
     * Get field description
     */
    public function description(): string
    {
        return $this->config['description'] ?? '';
    }
}