*/ public static function headers(): array { $out = []; foreach ($_SERVER as $name => $value) { if (!is_string($name) || !is_scalar($value)) { continue; } if (str_starts_with($name, 'HTTP_')) { $out[strtolower(str_replace('_', '-', substr($name, 5)))] = (string) wp_unslash($value); } elseif ($name === 'CONTENT_TYPE' || $name === 'CONTENT_LENGTH') { $out[strtolower(str_replace('_', '-', $name))] = (string) wp_unslash($value); } } return $out; } /** * The request body as an array: decoded JSON for a JSON request, otherwise * the form fields. Mirrors the Symfony listener's `body()`. * * @return array */ public static function body(): array { if (self::isJson()) { $decoded = json_decode(self::rawBody(), true); return is_array($decoded) ? $decoded : []; } return is_array($_POST) ? wp_unslash($_POST) : []; } public static function isJson(): bool { $type = isset($_SERVER['CONTENT_TYPE']) ? (string) wp_unslash($_SERVER['CONTENT_TYPE']) : ''; return str_contains(strtolower($type), 'json'); } public static function rawBody(): string { $raw = file_get_contents('php://input'); return is_string($raw) ? $raw : ''; } /** The preview token a tester's browser carries, if any. */ public static function previewToken(): string { return isset($_SERVER['HTTP_X_SARCIO_PREVIEW']) ? (string) wp_unslash($_SERVER['HTTP_X_SARCIO_PREVIEW']) : ''; } /** * Whether this request is headed for the REST API. `REST_REQUEST` is defined * too late to help (it lands on `parse_request`, after `init`), so the path * and the `rest_route` fallback are what the generic interceptor can trust. * * The REST prefix sits under WordPress' own home path, so a site installed * in a subdirectory (`example.com/blog`) serves it at `/blog/wp-json/…`. * Matching only a root-level `/wp-json/` would hand those requests to the * generic interceptor as well as the REST integration, evaluating each * patched route twice. */ public static function isRestRequest(): bool { if (defined('REST_REQUEST') && REST_REQUEST) { return true; } if (isset($_GET['rest_route'])) { return true; } $prefix = function_exists('rest_get_url_prefix') ? trim((string) rest_get_url_prefix(), '/') : 'wp-json'; if ($prefix === '') { return false; } return str_starts_with(ltrim(self::path(), '/'), self::homePath() . $prefix . '/'); } /** WordPress' home path without its leading slash: '' at the root, 'blog/' in a subdirectory. */ private static function homePath(): string { $home = function_exists('home_url') ? wp_parse_url((string) home_url('/'), PHP_URL_PATH) : '/'; $home = is_string($home) ? trim($home, '/') : ''; return $home === '' ? '' : $home . '/'; } }