PluginProbe
Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) / 2.1.0
Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) v2.1.0
2.1.3 2.1.2 2.1.1 2.1.0 2.0.4 2.0.3 2.0.2 2.0.1 2.0.0 1.5.5 1.5.4 1.5.3 1.5.2 1.5.1 1.5.0 trunk 1.0.1 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 All 57 releases
darkify / src / Admin / Schema / SchemaDefaults.php

SchemaDefaults.php in Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) 2.1.0, at src/Admin/Schema/SchemaDefaults.php

160 lines 6.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Schema default resolution.
5 *
6 * The default of every field lives in the config classes (src/Admin/Views/*.php)
7 * and is read back out of the SchemaRegistry. Two callers need it:
8 *
9 * - the settings REST controller, which merges defaults under the saved values
10 * so the React admin renders a documented default for a field never saved;
11 * - the install seeder (Admin::seed_default_options), which writes those same
12 * defaults into the `darkify` option the first time the plugin runs.
13 *
14 * The seeder is what keeps the two sides of the plugin agreeing on a fresh
15 * install. Until the option row exists, the admin resolved a default from the
16 * schema while the frontend fell back to whatever literal its template carried —
17 * so the admin showed the Orbit switcher while the site rendered Classic. Seeding
18 * makes the stored values the single source both read.
19 *
20 * @package darkify
21 * @subpackage darkify/src/Admin/Schema
22 * @author ThemeAtelier<themeatelierbd@gmail.com>
23 */
24
25 namespace ThemeAtelier\Darkify\Admin\Schema;
26
27 if (! defined('ABSPATH')) {
28 die;
29 }
30
31 class SchemaDefaults
32 {
33 /**
34 * Config keys whose values are trusted markup rendered as raw HTML. They must
35 * NOT be entity-decoded into text.
36 */
37 const HTML_LABEL_KEYS = ['desc', 'help', 'title_help', 'content', 'before', 'after'];
38
39 /**
40 * Build the id => default map for a section list, preserving each field's
41 * NESTED storage shape so a fresh-install value map matches exactly what the
42 * frontend templates and the React form read.
43 *
44 * The subtlety this handles: a `fieldset` stores its children under its OWN id
45 * as a nested object — e.g. `switcher_button_position` holds
46 * `['dark_mode_switch_position' => 'bottom_right', 'switch_position_top_right'
47 * => ['top' => '40', 'right' => '40'], …]`, and the frontend reads them as
48 * `$options['switcher_button_position']['switch_position_top_right']['top']`
49 * (see Frontend/Templates/views/switch.php). Flattening those child defaults
50 * to the top level would leave the nested object the UI actually reads absent,
51 * so a fieldset's default is BUILT as that nested object instead.
52 *
53 * `group`/`repeater` stay leaves: they store a LIST of rows and carry their
54 * own `default`; their sub-fields are a per-row template applied when a row
55 * is added, not top-level or nested-object defaults. `section_tab` sub-tabs
56 * save their fields flat, so those recurse to the top level unchanged.
57 *
58 * @param array $sections Registered section configs.
59 * @return array
60 */
61 public static function collect(array $sections): array
62 {
63 $defaults = [];
64 foreach ($sections as $section) {
65 if (! empty($section['fields']) && \is_array($section['fields'])) {
66 self::collect_fields($section['fields'], $defaults);
67 }
68 }
69 return $defaults;
70 }
71
72 /**
73 * Every registered section for an option key, resolved to its defaults.
74 *
75 * @param string $unique The option key (Darkify keeps everything under one).
76 * @return array
77 */
78 public static function for_option(string $unique): array
79 {
80 $sections = SchemaRegistry::$sections[$unique] ?? [];
81 return \is_array($sections) ? self::collect($sections) : [];
82 }
83
84 /**
85 * Recursive worker for collect(). Writes into $out by reference, building a
86 * fieldset's default as the nested object of its own children.
87 *
88 * @param array $fields The fields list to walk.
89 * @param array $out Accumulator, keyed by field id.
90 */
91 protected static function collect_fields(array $fields, array &$out): void
92 {
93 foreach ($fields as $field) {
94 if (! \is_array($field)) {
95 continue;
96 }
97 $id = $field['id'] ?? '';
98 $type = $field['type'] ?? '';
99
100 // A fieldset's default is the nested object of its children's
101 // defaults, stored under the fieldset's own id (recurses, so a
102 // fieldset nested inside a fieldset nests correctly too).
103 if (
104 $type === 'fieldset'
105 && $id !== ''
106 && ! empty($field['fields'])
107 && \is_array($field['fields'])
108 ) {
109 $nested = [];
110 self::collect_fields($field['fields'], $nested);
111 if (! empty($nested)) {
112 $out[$id] = $nested;
113 }
114 continue;
115 }
116
117 // An ordinary field with a declared default (this also covers
118 // group/repeater, whose own `default` is a list of rows — we do NOT
119 // recurse into their per-row template fields).
120 if ($id !== '' && \array_key_exists('default', $field)) {
121 $out[$id] = self::decode_labels($field['default']);
122 }
123
124 // section_tab sub-tabs: their fields save flat at the top level.
125 if (! empty($field['tabs']) && \is_array($field['tabs'])) {
126 foreach ($field['tabs'] as $tab) {
127 if (! empty($tab['fields']) && \is_array($tab['fields'])) {
128 self::collect_fields($tab['fields'], $out);
129 }
130 }
131 }
132 }
133 }
134
135 /**
136 * Entity-decode config strings so a label written as `&amp;` reaches the
137 * consumer as `&`. Trusted-markup keys are left alone.
138 *
139 * @param mixed $value
140 * @param string $key
141 * @return mixed
142 */
143 protected static function decode_labels($value, string $key = '')
144 {
145 if (\is_array($value)) {
146 $out = [];
147 foreach ($value as $k => $v) {
148 $out[$k] = self::decode_labels($v, (string) $k);
149 }
150 return $out;
151 }
152
153 if (\is_string($value) && ! \in_array($key, self::HTML_LABEL_KEYS, true)) {
154 return \html_entity_decode($value, ENT_QUOTES | ENT_HTML5, 'UTF-8');
155 }
156
157 return $value;
158 }
159 }
160