feat(batch12): Woodmart theme helpers — detect, get/list/set options with reversible backup
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q8t9GEyyLZbUQu26na1JQg
This commit is contained in:
@@ -0,0 +1,143 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Batch 12 — Woodmart theme helpers (Pro-equivalent, net-new).
|
||||||
|
*
|
||||||
|
* Read/list/set Woodmart (XTemos) theme options with an automatic reversible
|
||||||
|
* backup, plus a detector. Writes go to the `xts-woodmart-options` store; every
|
||||||
|
* set records the prior value in a shadow option so it can be restored.
|
||||||
|
* Guarded — inert unless the active theme is Woodmart.
|
||||||
|
* GPL-2.0-or-later. See NOTICE.md.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace AskTamMCP\Extensions;
|
||||||
|
|
||||||
|
defined('ABSPATH') || exit;
|
||||||
|
|
||||||
|
class Batch12 {
|
||||||
|
|
||||||
|
private const OPT = 'xts-woodmart-options';
|
||||||
|
private const BACKUP = 'amp_wd_backup';
|
||||||
|
|
||||||
|
public static function register($registry): void {
|
||||||
|
if (!self::isWoodmart()) return;
|
||||||
|
|
||||||
|
$def = function (string $name, string $desc, array $props, array $required, string $scope, string $method) {
|
||||||
|
$schema = ['type' => 'object', 'properties' => $props];
|
||||||
|
if ($required) $schema['required'] = $required;
|
||||||
|
return ['name' => $name, 'description' => $desc, 'scope' => $scope,
|
||||||
|
'handler' => 'AskTamMCP\\Extensions\\Batch12::' . $method, 'inputSchema' => $schema];
|
||||||
|
};
|
||||||
|
|
||||||
|
$registry->register($def('woodmart_detect', 'Report whether the Woodmart theme is active and its version.',
|
||||||
|
[], [], 'read', 'detect'));
|
||||||
|
|
||||||
|
$registry->register($def('woodmart_get_option', 'Read one Woodmart theme option by key.',
|
||||||
|
['key' => ['type' => 'string']], ['key'], 'read', 'getOpt'));
|
||||||
|
|
||||||
|
$registry->register($def('woodmart_list_options', 'List Woodmart theme option keys (and value types), optionally filtered by prefix.',
|
||||||
|
['prefix' => ['type' => 'string']], [], 'read', 'listOpts'));
|
||||||
|
|
||||||
|
$registry->register($def('woodmart_set_option', 'Set one Woodmart theme option. value is parsed as JSON when valid (so arrays/booleans/numbers work), otherwise stored as a string. The prior value is auto-backed-up for woodmart_restore_option.',
|
||||||
|
['key' => ['type' => 'string'], 'value' => ['type' => 'string']], ['key', 'value'], 'write', 'setOpt'));
|
||||||
|
|
||||||
|
$registry->register($def('woodmart_restore_option', 'Restore one Woodmart option to the value saved before the last woodmart_set_option (or remove it if there was none).',
|
||||||
|
['key' => ['type' => 'string']], ['key'], 'write', 'restoreOpt'));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function isWoodmart(): bool {
|
||||||
|
if (function_exists('woodmart_get_opt')) return true;
|
||||||
|
$t = wp_get_theme();
|
||||||
|
$cands = [$t->get('TextDomain'), $t->get_template(), strtolower((string) $t->get('Name'))];
|
||||||
|
return in_array('woodmart', array_map('strtolower', array_filter($cands)), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function store(): array {
|
||||||
|
$o = get_option(self::OPT, []);
|
||||||
|
return is_array($o) ? $o : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function typeOf($v): string {
|
||||||
|
if (is_array($v)) return 'array';
|
||||||
|
if (is_bool($v)) return 'bool';
|
||||||
|
if (is_int($v)) return 'int';
|
||||||
|
if (is_float($v)) return 'float';
|
||||||
|
return 'string';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function detect(array $args): array {
|
||||||
|
$t = wp_get_theme();
|
||||||
|
$ver = defined('WOODMART_VERSION') ? WOODMART_VERSION : (string) $t->get('Version');
|
||||||
|
return [
|
||||||
|
'active' => self::isWoodmart(),
|
||||||
|
'name' => (string) $t->get('Name'),
|
||||||
|
'version' => $ver,
|
||||||
|
'option_store' => self::OPT,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getOpt(array $args): array {
|
||||||
|
$key = (string) ($args['key'] ?? '');
|
||||||
|
if ($key === '') throw new \RuntimeException('key required.');
|
||||||
|
$store = self::store();
|
||||||
|
$exists = array_key_exists($key, $store);
|
||||||
|
$val = $exists ? $store[$key] : (function_exists('woodmart_get_opt') ? woodmart_get_opt($key) : null);
|
||||||
|
return ['key' => $key, 'exists' => $exists, 'type' => self::typeOf($val), 'value' => $val];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function listOpts(array $args): array {
|
||||||
|
$prefix = isset($args['prefix']) ? (string) $args['prefix'] : '';
|
||||||
|
$store = self::store();
|
||||||
|
$keys = [];
|
||||||
|
foreach ($store as $k => $v) {
|
||||||
|
if ($prefix !== '' && strpos((string) $k, $prefix) !== 0) continue;
|
||||||
|
$keys[] = ['key' => (string) $k, 'type' => self::typeOf($v)];
|
||||||
|
}
|
||||||
|
usort($keys, fn($a, $b) => strcmp($a['key'], $b['key']));
|
||||||
|
return ['count' => count($keys), 'options' => $keys];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setOpt(array $args): array {
|
||||||
|
$key = (string) ($args['key'] ?? '');
|
||||||
|
if ($key === '') throw new \RuntimeException('key required.');
|
||||||
|
$raw = (string) ($args['value'] ?? '');
|
||||||
|
$decoded = json_decode($raw, true);
|
||||||
|
$value = (json_last_error() === JSON_ERROR_NONE && ($raw === 'null' || $decoded !== null)) ? $decoded : $raw;
|
||||||
|
|
||||||
|
$store = self::store();
|
||||||
|
$had = array_key_exists($key, $store);
|
||||||
|
$prior = $had ? $store[$key] : null;
|
||||||
|
|
||||||
|
// Record a one-slot backup so the change is reversible.
|
||||||
|
$backup = get_option(self::BACKUP, []);
|
||||||
|
if (!is_array($backup)) $backup = [];
|
||||||
|
$backup[$key] = ['had' => $had, 'value' => $prior];
|
||||||
|
update_option(self::BACKUP, $backup, false);
|
||||||
|
|
||||||
|
$store[$key] = $value;
|
||||||
|
update_option(self::OPT, $store);
|
||||||
|
|
||||||
|
return ['key' => $key, 'type' => self::typeOf($value), 'value' => $value, 'backed_up' => true, 'previously_set' => $had];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function restoreOpt(array $args): array {
|
||||||
|
$key = (string) ($args['key'] ?? '');
|
||||||
|
if ($key === '') throw new \RuntimeException('key required.');
|
||||||
|
$backup = get_option(self::BACKUP, []);
|
||||||
|
if (!is_array($backup) || !array_key_exists($key, $backup)) {
|
||||||
|
throw new \RuntimeException('No backup recorded for key: ' . $key);
|
||||||
|
}
|
||||||
|
$entry = $backup[$key];
|
||||||
|
$store = self::store();
|
||||||
|
if (!empty($entry['had'])) {
|
||||||
|
$store[$key] = $entry['value'];
|
||||||
|
$action = 'restored';
|
||||||
|
} else {
|
||||||
|
unset($store[$key]);
|
||||||
|
$action = 'removed';
|
||||||
|
}
|
||||||
|
update_option(self::OPT, $store);
|
||||||
|
unset($backup[$key]);
|
||||||
|
update_option(self::BACKUP, $backup, false);
|
||||||
|
return ['key' => $key, 'action' => $action];
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user