| 1 |
<?php |
| 2 |
|
| 3 |
namespace FluentCart\App\Services\Theme\Readers; |
| 4 |
|
| 5 |
use FluentCart\App\Services\Theme\ColorMath; |
| 6 |
use FluentCart\App\Services\Theme\ThemePalette; |
| 7 |
use FluentCart\Framework\Support\Arr; |
| 8 |
|
| 9 |
/** |
| 10 |
* GeneratePress's Customizer colours, read from its settings rather than its |
| 11 |
* palette slots. |
| 12 |
* |
| 13 |
* GeneratePress keeps every colour in the `generate_settings` option row, each |
| 14 |
* a Global Color reference (`var(--accent)`) or a custom colour. Its dynamic |
| 15 |
* CSS reads that row over its own defaults (inc/css-output.php) — the body |
| 16 |
* keys over `generate_get_defaults()` in generate_base_css(), the area keys |
| 17 |
* over `generate_get_color_defaults()` in generate_advanced_css() — and so |
| 18 |
* does this reader. `generate_get_option()` is not used: it only answers keys |
| 19 |
* `generate_get_defaults()` knows, and the content and button colours are not |
| 20 |
* among them. |
| 21 |
* |
| 22 |
* The roles, from the selectors GeneratePress prints: |
| 23 |
* - Content background (`content_background_color`) paints |
| 24 |
* `.separate-containers .inside-article` and `.one-container .container` |
| 25 |
* — the area the store is rendered in on both layouts. Saved empty, the |
| 26 |
* content area is transparent and the Body background (`background_color`) |
| 27 |
* shows through. |
| 28 |
* - Content text / link (`content_text_color`, `content_link_color`) repaint |
| 29 |
* that area when set; otherwise the Body text (`text_color`) and Link |
| 30 |
* (`link_color`) colours reach it. The link colour is the accent: it is |
| 31 |
* what GeneratePress paints its brand colour through (its default is |
| 32 |
* `var(--accent)`), and it moves with the owner when they repoint it. |
| 33 |
* - Buttons (`form_button_background_color`, `form_button_text_color` and |
| 34 |
* their `_hover` pair) paint `button`, `a.button` and core button blocks. |
| 35 |
* GeneratePress's default button is a grey `#55555e`, not its accent. |
| 36 |
* GeneratePress has no general border colour (`form_border_color` is only its |
| 37 |
* inputs' border), so no border is stated. |
| 38 |
* |
| 39 |
* A saved '' prints nothing (GeneratePress_CSS::add_property() skips it). For |
| 40 |
* the button that leaves GeneratePress's stylesheet painting it — main.css |
| 41 |
* `button{background:#55555e;color:#fff}` — so that is what an empty button |
| 42 |
* states; its stylesheet has no button hover, so an empty hover states none |
| 43 |
* and FluentCart derives it. An empty body colour leaves the browser's, which |
| 44 |
* is no theme choice, so it states nothing. |
| 45 |
* |
| 46 |
* `var(--slug)` stays live, measured through the Global Colors GeneratePress |
| 47 |
* prints on :root (see paletteValues()). A value that cannot be measured — an |
| 48 |
* rgba(), a named colour, a reference to a Global Color that does not exist — |
| 49 |
* is not stated, and a set-but-unwritable value is not replaced by the next |
| 50 |
* setting in its chain: GeneratePress is painting it, just not in a form |
| 51 |
* FluentCart can write. |
| 52 |
* |
| 53 |
* Verified against GeneratePress 3.6.1. |
| 54 |
*/ |
| 55 |
class GeneratePressSettingsReader implements ThemeSettingsReader |
| 56 |
{ |
| 57 |
/** |
| 58 |
* What GeneratePress's stylesheet paints a button with when its colour is |
| 59 |
* saved empty (assets/css/main.min.css). |
| 60 |
* |
| 61 |
* @var array |
| 62 |
*/ |
| 63 |
protected static $stylesheetButton = [ |
| 64 |
'background' => '#55555e', |
| 65 |
'text' => '#ffffff', |
| 66 |
]; |
| 67 |
|
| 68 |
/** |
| 69 |
* Detected by GeneratePress's own API — its version constant, its option |
| 70 |
* defaults, its Global Colors, and its dynamic-CSS printer hooked on |
| 71 |
* `wp_enqueue_scripts` (inc/css-output.php) — not by theme name, so a |
| 72 |
* child theme or renamed folder keeps working. The hook is what makes the |
| 73 |
* settings real: it is the printer that paints every colour read here. |
| 74 |
* |
| 75 |
* @return bool |
| 76 |
*/ |
| 77 |
public static function applies(): bool |
| 78 |
{ |
| 79 |
return defined('GENERATE_VERSION') |
| 80 |
&& function_exists('generate_get_defaults') |
| 81 |
&& function_exists('generate_get_color_defaults') |
| 82 |
&& function_exists('generate_get_global_colors') |
| 83 |
&& has_action('wp_enqueue_scripts', 'generate_enqueue_dynamic_css') !== false; |
| 84 |
} |
| 85 |
|
| 86 |
/** |
| 87 |
* @return array Role => hex or `var(--slug, #hex)`. |
| 88 |
*/ |
| 89 |
public static function roles(): array |
| 90 |
{ |
| 91 |
if (!self::applies()) { |
| 92 |
return []; |
| 93 |
} |
| 94 |
|
| 95 |
$settings = self::settings(); |
| 96 |
|
| 97 |
$roles = [ |
| 98 |
'accent' => self::first($settings, ['content_link_color', 'link_color']), |
| 99 |
'text' => self::first($settings, ['content_text_color', 'text_color']), |
| 100 |
'surface' => self::first($settings, ['content_background_color', 'background_color']), |
| 101 |
]; |
| 102 |
|
| 103 |
$button = self::button($settings); |
| 104 |
|
| 105 |
if ($button) { |
| 106 |
$roles = array_merge($roles, $button); |
| 107 |
} |
| 108 |
|
| 109 |
return array_filter($roles, function ($value) { |
| 110 |
return $value !== ''; |
| 111 |
}); |
| 112 |
} |
| 113 |
|
| 114 |
/** |
| 115 |
* Each Global Color's property and current colour: `--{slug}` => colour, |
| 116 |
* from `generate_get_global_colors()` — the list GeneratePress prints the |
| 117 |
* properties on :root from (generate_base_css()), and publishes to the |
| 118 |
* editor palette as bare `var(--{slug})`. |
| 119 |
* |
| 120 |
* @return array Property => colour, as GeneratePress saved it |
| 121 |
* (ThemePalette drops non-hex). |
| 122 |
*/ |
| 123 |
public static function paletteValues(): array |
| 124 |
{ |
| 125 |
if (!self::applies()) { |
| 126 |
return []; |
| 127 |
} |
| 128 |
|
| 129 |
$values = []; |
| 130 |
|
| 131 |
try { |
| 132 |
foreach ((array)generate_get_global_colors() as $color) { |
| 133 |
$slug = (string)Arr::get((array)$color, 'slug', ''); |
| 134 |
$value = (string)Arr::get((array)$color, 'color', ''); |
| 135 |
|
| 136 |
// GeneratePress prints only a slug with a colour. |
| 137 |
if ($slug !== '' && $value !== '') { |
| 138 |
$values['--' . $slug] = $value; |
| 139 |
} |
| 140 |
} |
| 141 |
} catch (\Throwable $e) { |
| 142 |
// GeneratePress's API misbehaving means no palette values: |
| 143 |
// references stay bare and unmeasurable, which resolve() refuses. |
| 144 |
return []; |
| 145 |
} |
| 146 |
|
| 147 |
return $values; |
| 148 |
} |
| 149 |
|
| 150 |
/** |
| 151 |
* The button and its hover. |
| 152 |
* |
| 153 |
* A background saved empty is GeneratePress's stylesheet grey; one that is |
| 154 |
* set but unwritable states no button, and its hover goes with it. A text |
| 155 |
* saved empty is the stylesheet's white; one that cannot be written gets |
| 156 |
* the colour that reads on the background. A hover background is stated |
| 157 |
* only when written, and a hover text only when written — otherwise the |
| 158 |
* resting text carries over, as resolve() already does. |
| 159 |
* |
| 160 |
* @param array $settings |
| 161 |
* @return array |
| 162 |
*/ |
| 163 |
protected static function button(array $settings): array |
| 164 |
{ |
| 165 |
$background = self::read($settings, 'form_button_background_color', self::$stylesheetButton['background']); |
| 166 |
|
| 167 |
if ($background === '') { |
| 168 |
return []; |
| 169 |
} |
| 170 |
|
| 171 |
$text = self::read($settings, 'form_button_text_color', self::$stylesheetButton['text']); |
| 172 |
|
| 173 |
if ($text === '') { |
| 174 |
$text = ColorMath::readableText(ThemePalette::measurable($background)); |
| 175 |
} |
| 176 |
|
| 177 |
$roles = [ |
| 178 |
'button_bg' => $background, |
| 179 |
'button_text' => $text, |
| 180 |
]; |
| 181 |
|
| 182 |
$hoverBg = self::read($settings, 'form_button_background_color_hover'); |
| 183 |
|
| 184 |
if ($hoverBg !== '') { |
| 185 |
$roles['button_hover_bg'] = $hoverBg; |
| 186 |
$roles['button_hover_text'] = self::read($settings, 'form_button_text_color_hover'); |
| 187 |
} |
| 188 |
|
| 189 |
return array_filter($roles, function ($value) { |
| 190 |
return $value !== ''; |
| 191 |
}); |
| 192 |
} |
| 193 |
|
| 194 |
/** |
| 195 |
* The first setting in a chain that GeneratePress prints — one saved |
| 196 |
* non-empty — as FluentCart writes it. A set value that cannot be written |
| 197 |
* ends the chain: it is what GeneratePress paints there. |
| 198 |
* |
| 199 |
* @param array $settings |
| 200 |
* @param array $keys |
| 201 |
* @return string |
| 202 |
*/ |
| 203 |
protected static function first(array $settings, array $keys): string |
| 204 |
{ |
| 205 |
foreach ($keys as $key) { |
| 206 |
if (self::isSet($settings, $key)) { |
| 207 |
return self::read($settings, $key); |
| 208 |
} |
| 209 |
} |
| 210 |
|
| 211 |
return ''; |
| 212 |
} |
| 213 |
|
| 214 |
/** |
| 215 |
* One setting as FluentCart writes it; empty takes `$default`. |
| 216 |
* |
| 217 |
* @param array $settings |
| 218 |
* @param string $key |
| 219 |
* @param string $default |
| 220 |
* @return string Hex, `var(--slug, #hex)`, or ''. |
| 221 |
*/ |
| 222 |
protected static function read(array $settings, string $key, string $default = ''): string |
| 223 |
{ |
| 224 |
$raw = self::isSet($settings, $key) ? trim((string)$settings[$key]) : $default; |
| 225 |
|
| 226 |
$value = ThemePalette::settingValue($raw); |
| 227 |
|
| 228 |
return ThemePalette::measurable($value) !== '' ? $value : ''; |
| 229 |
} |
| 230 |
|
| 231 |
/** |
| 232 |
* Whether GeneratePress prints this setting: a non-empty string. |
| 233 |
* |
| 234 |
* @param array $settings |
| 235 |
* @param string $key |
| 236 |
* @return bool |
| 237 |
*/ |
| 238 |
protected static function isSet(array $settings, string $key): bool |
| 239 |
{ |
| 240 |
return isset($settings[$key]) && is_string($settings[$key]) && trim($settings[$key]) !== ''; |
| 241 |
} |
| 242 |
|
| 243 |
/** |
| 244 |
* The saved `generate_settings` row over GeneratePress's defaults — both |
| 245 |
* sets, merged the way its dynamic CSS merges each. |
| 246 |
* |
| 247 |
* @return array |
| 248 |
*/ |
| 249 |
protected static function settings(): array |
| 250 |
{ |
| 251 |
$saved = get_option('generate_settings', []); |
| 252 |
$saved = is_array($saved) ? $saved : []; |
| 253 |
|
| 254 |
try { |
| 255 |
$defaults = array_merge((array)generate_get_color_defaults(), (array)generate_get_defaults()); |
| 256 |
} catch (\Throwable $e) { |
| 257 |
$defaults = []; |
| 258 |
} |
| 259 |
|
| 260 |
return wp_parse_args($saved, $defaults); |
| 261 |
} |
| 262 |
} |
| 263 |
|