<?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> Loaded fields */
|
public array $fields = [];
|
|
/** @var array<string, array> Raw field configs from registry */
|
public array $fieldConfigs = [];
|
|
/** @var string|null Base key for options storage */
|
public ?string $baseKey = null;
|
|
/**
|
* WordPress default fields by object type
|
*/
|
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' => [
|
'name',
|
'description'
|
]
|
];
|
|
public function __construct(
|
int|string|null $id,
|
string $objectType,
|
?string $contentType = null
|
) {
|
$this->id = $id;
|
$this->objectType = $objectType;
|
$this->contentType = $contentType;
|
}
|
|
/**
|
* Check if field exists in configs
|
*/
|
public function hasField(string $name): bool
|
{
|
return isset($this->fields[$name]) || isset($this->fieldConfigs[$name]);
|
}
|
|
/**
|
* Get loaded field instance
|
*/
|
public function getField(string $name): ?Field
|
{
|
return $this->fields[$name] ?? null;
|
}
|
|
/**
|
* Set/add a field instance
|
*/
|
public function setField(Field $field): self
|
{
|
$this->fields[$field->name] = $field;
|
return $this;
|
}
|
|
/**
|
* Remove a field instance
|
*/
|
public function removeField(string $name): self
|
{
|
unset($this->fields[$name]);
|
return $this;
|
}
|
|
/**
|
* Get field configuration
|
*/
|
public function getFieldConfig(string $name): ?array
|
{
|
if (isset($this->fieldConfigs[$name])) {
|
return $this->fieldConfigs[$name];
|
}
|
|
// Search nested fields (repeaters, groups)
|
foreach ($this->fieldConfigs as $config) {
|
if (isset($config['fields'][$name])) {
|
return $config['fields'][$name];
|
}
|
}
|
|
return null;
|
}
|
|
/**
|
* Check if field is a WordPress default
|
*/
|
public function isWpDefault(string $name): bool
|
{
|
$defaults = self::WP_DEFAULTS[$this->objectType] ?? [];
|
return in_array($name, $defaults, true);
|
}
|
|
/**
|
* Get all dirty (changed) fields
|
* @return array<string, Field>
|
*/
|
public function getDirtyFields(): array
|
{
|
return array_filter($this->fields, fn(Field $f) => $f->isDirty);
|
}
|
|
/**
|
* Get all invalid fields
|
* @return array<string, Field>
|
*/
|
public function getInvalidFields(): array
|
{
|
return array_filter($this->fields, fn(Field $f) => !$f->isValid);
|
}
|
|
/**
|
* Mark all loaded fields as clean
|
*/
|
public function markAllClean(): self
|
{
|
foreach ($this->fields as $field) {
|
$field->markClean();
|
}
|
return $this;
|
}
|
|
/**
|
* Reset all fields to original values
|
*/
|
public function resetAll(): self
|
{
|
foreach ($this->fields as $field) {
|
$field->reset();
|
}
|
return $this;
|
}
|
|
/**
|
* Check if any fields are dirty
|
*/
|
public function hasDirtyFields(): bool
|
{
|
return !empty($this->getDirtyFields());
|
}
|
|
/**
|
* Check if all fields are valid
|
*/
|
public function isValid(): bool
|
{
|
return empty($this->getInvalidFields());
|
}
|
|
/**
|
* Get all field names from configs
|
*/
|
public function getFieldNames(): array
|
{
|
return array_keys($this->fieldConfigs);
|
}
|
|
/**
|
* Get loaded field values as array
|
*/
|
public function toArray(): array
|
{
|
$data = [];
|
foreach ($this->fields as $name => $field) {
|
$data[$name] = $field->value;
|
}
|
return $data;
|
}
|
}
|