keyed by tag name). */ final class Registry { private static ?Registry $instance = null; /** @var array */ private array $tags = []; public static function instance(): self { if (self::$instance === null) { self::$instance = self::with_defaults(); } return self::$instance; } /** Test helper: forget the shared instance (the next instance() call rebuilds it). */ public static function reset(?self $registry = null): void { self::$instance = $registry; } /** * Built-in tags + plugin tags (only when the plugin API function exists) + the filter. * * @param callable(string): bool|null $function_exists injectable for tests */ public static function with_defaults(?callable $function_exists = null): self { $exists = $function_exists ?? static fn(string $fn): bool => function_exists($fn); $registry = new self(); $builtin = [ new Tags\PostTitle(), new Tags\PostExcerpt(), new Tags\PostContent(), new Tags\PostDate(), new Tags\PostAuthor(), new Tags\PostUrl(), new Tags\PostId(), new Tags\PostTerms(), new Tags\CommentsNumber(), new Tags\CustomField(), new Tags\FeaturedImage(), new Tags\FeaturedImageUrl(), new Tags\ArchiveTitle(), new Tags\ArchiveDescription(), new Tags\SiteTitle(), new Tags\SiteTagline(), new Tags\SiteUrl(), new Tags\SiteLogo(), new Tags\UserInfo(), new Tags\CurrentDate(), new Tags\UrlParam(), ]; foreach ($builtin as $tag) { $registry->register($tag); } foreach ([Tags\AcfField::class, Tags\Pods::class, Tags\Toolset::class, Tags\MetaBox::class] as $class) { if ($exists($class::required_function())) { $registry->register(new $class()); } } $filtered = apply_filters('zadex/dynamic/tags', $registry->tags, $registry); if (is_array($filtered)) { $registry->tags = []; foreach ($filtered as $tag) { if ($tag instanceof Tag) { $registry->register($tag); } } } return $registry; } public function register(Tag $tag): void { $name = $tag->name(); if (preg_match('/^[a-z0-9][a-z0-9_-]*$/', $name)) { $this->tags[$name] = $tag; } } public function get(string $name): ?Tag { return $this->tags[$name] ?? null; } public function has(string $name): bool { return isset($this->tags[$name]); } /** @return array */ public function all(): array { return $this->tags; } /** @return array> window.ZADEX.dynamicTags */ public function for_editor(): array { $out = []; foreach ($this->tags as $tag) { $out[] = $tag->to_array(); } return $out; } /** @return array tag controls keyed by id (Sanitizer) */ public function controls(string $name): array { $tag = $this->get($name); if (!$tag) { return []; } $out = []; foreach ($tag->controls() as $control) { if (isset($control['id']) && is_string($control['id'])) { $out[$control['id']] = $control; } } return $out; } }