'object', 'properties' => $props]; if ($required) $schema['required'] = $required; return ['name' => $name, 'description' => $desc, 'scope' => $scope, 'handler' => 'AskTamMCP\\Extensions\\Batch21::' . $method, 'inputSchema' => $schema]; }; $registry->register($def('litespeed_detect', 'Report LiteSpeed Cache version and whether object cache / crawler are active.', [], [], 'read', 'detect')); $registry->register($def('litespeed_list_options', 'List LiteSpeed Cache settings (litespeed.conf.* options), optionally filtered by key substring.', ['filter' => ['type' => 'string'], 'limit' => ['type' => 'integer', 'default' => 200]], [], 'read', 'listOptions')); $registry->register($def('litespeed_set_option', 'Set one LiteSpeed Cache setting. key may be given with or without the litespeed.conf. prefix. value is parsed as JSON when valid. Prior value auto-backed-up for litespeed_restore_option.', ['key' => ['type' => 'string'], 'value' => ['type' => 'string']], ['key', 'value'], 'write', 'setOption')); $registry->register($def('litespeed_restore_option', 'Restore one LiteSpeed setting to the value saved before the last litespeed_set_option.', ['key' => ['type' => 'string']], ['key'], 'write', 'restoreOption')); $registry->register($def('litespeed_purge', 'Purge LiteSpeed cache. scope = all (default) | url | post | tag. Provide url, post_id, or tag accordingly.', ['scope' => ['type' => 'string', 'enum' => ['all', 'url', 'post', 'tag']], 'url' => ['type' => 'string'], 'post_id' => ['type' => 'integer'], 'tag' => ['type' => 'string']], [], 'write', 'purge')); } private static function fullKey(string $key): string { return strpos($key, self::OPT_PREFIX) === 0 ? $key : self::OPT_PREFIX . $key; } public static function detect(array $args): array { return [ 'version' => defined('LSCWP_V') ? LSCWP_V : (defined('LSCWP_CUR_V') ? LSCWP_CUR_V : 'unknown'), 'object_cache' => wp_using_ext_object_cache(), 'crawler' => (bool) get_option(self::OPT_PREFIX . 'crawler', false), ]; } public static function listOptions(array $args): array { global $wpdb; $filter = isset($args['filter']) ? (string) $args['filter'] : ''; $limit = max(1, (int) ($args['limit'] ?? 200)); $like = self::OPT_PREFIX . '%'; $rows = $wpdb->get_results($wpdb->prepare( "SELECT option_name, option_value FROM {$wpdb->options} WHERE option_name LIKE %s ORDER BY option_name LIMIT %d", $like, $limit ), ARRAY_A); $out = []; foreach ((array) $rows as $r) { $k = substr($r['option_name'], strlen(self::OPT_PREFIX)); if ($filter !== '' && stripos($k, $filter) === false) continue; $v = maybe_unserialize($r['option_value']); $out[] = ['key' => $k, 'value' => is_scalar($v) ? $v : $v]; } return ['count' => count($out), 'options' => $out]; } public static function setOption(array $args): array { $key = (string) ($args['key'] ?? ''); if ($key === '') throw new \RuntimeException('key required.'); $opt = self::fullKey($key); $raw = (string) ($args['value'] ?? ''); $decoded = json_decode($raw, true); $value = (json_last_error() === JSON_ERROR_NONE && ($raw === 'null' || $decoded !== null)) ? $decoded : $raw; $had = (get_option($opt, '__amp_absent__') !== '__amp_absent__'); $prior = $had ? get_option($opt) : null; $backup = get_option(self::BACKUP, []); if (!is_array($backup)) $backup = []; $backup[$opt] = ['had' => $had, 'value' => $prior]; update_option(self::BACKUP, $backup, false); update_option($opt, $value); if (defined('LSCWP_V')) do_action('litespeed_purge_all'); return ['key' => $key, 'stored_as' => $opt, 'value' => $value, 'backed_up' => true, 'previously_set' => $had]; } public static function restoreOption(array $args): array { $key = (string) ($args['key'] ?? ''); if ($key === '') throw new \RuntimeException('key required.'); $opt = self::fullKey($key); $backup = get_option(self::BACKUP, []); if (!is_array($backup) || !array_key_exists($opt, $backup)) { throw new \RuntimeException('No backup recorded for key: ' . $key); } $entry = $backup[$opt]; if (!empty($entry['had'])) { update_option($opt, $entry['value']); $action = 'restored'; } else { delete_option($opt); $action = 'removed'; } unset($backup[$opt]); update_option(self::BACKUP, $backup, false); if (defined('LSCWP_V')) do_action('litespeed_purge_all'); return ['key' => $key, 'action' => $action]; } public static function purge(array $args): array { $scope = (string) ($args['scope'] ?? 'all'); switch ($scope) { case 'url': $url = (string) ($args['url'] ?? ''); if ($url === '') throw new \RuntimeException('url required for scope=url.'); do_action('litespeed_purge_url', $url); return ['scope' => 'url', 'url' => $url, 'purged' => true]; case 'post': $pid = (int) ($args['post_id'] ?? 0); if (!$pid) throw new \RuntimeException('post_id required for scope=post.'); do_action('litespeed_purge_post', $pid); return ['scope' => 'post', 'post_id' => $pid, 'purged' => true]; case 'tag': $tag = (string) ($args['tag'] ?? ''); if ($tag === '') throw new \RuntimeException('tag required for scope=tag.'); do_action('litespeed_purge', $tag); return ['scope' => 'tag', 'tag' => $tag, 'purged' => true]; default: do_action('litespeed_purge_all'); return ['scope' => 'all', 'purged' => true]; } } }