>|null */ public static function ops(): ?array { $fromQuery = isset($_GET[self::PARAM]) ? sanitize_text_field(wp_unslash((string) $_GET[self::PARAM])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- the preview token is its own credential. if ($fromQuery === 'exit') { self::clearCookie(); return null; } $token = $fromQuery !== '' ? $fromQuery : (isset($_COOKIE[self::COOKIE]) ? sanitize_text_field(wp_unslash((string) $_COOKIE[self::COOKIE])) : ''); if ($token === '' || !preg_match(self::TOKEN, $token)) { return null; } if ((string) Options::get('site_key') === '' || (string) Options::get('sidecar_key') === '') { return null; } $ops = self::cached($token); if ($ops === null) { if ($fromQuery === '') { self::clearCookie(); } return null; } if ($fromQuery !== '') { self::setCookie($token); } return $ops; } /** @return array>|null */ private static function cached(string $token): ?array { $key = 'sarcio_pv_' . md5($token); $stored = get_transient($key); if (is_array($stored)) { return isset($stored['ops']) && is_array($stored['ops']) ? $stored['ops'] : null; } $ops = self::fetch($token); set_transient($key, ['ops' => $ops], self::CACHE_SEC); return $ops; } /** @return array>|null */ private static function fetch(string $token): ?array { $url = sprintf( '%s/api/sites/%s/preview/server', Options::apiUrl(), rawurlencode((string) Options::get('site_key')), ); $response = wp_remote_post($url, [ 'body' => (string) wp_json_encode(['token' => $token]), 'headers' => [ 'Authorization' => 'Bearer ' . (string) Options::get('sidecar_key'), 'Content-Type' => 'application/json', ], 'redirection' => 0, 'timeout' => 3, ]); if (is_wp_error($response) || (int) wp_remote_retrieve_response_code($response) !== 200) { return null; } $body = json_decode((string) wp_remote_retrieve_body($response), true); $ops = is_array($body) && is_array($body['preview'] ?? null) ? ($body['preview']['ops'] ?? null) : null; if (!is_array($ops) || $ops === []) { return null; } return array_values(array_filter($ops, static fn (mixed $op): bool => is_array($op) && is_string($op['route'] ?? null))); } private static function setCookie(string $token): void { if (headers_sent()) { return; } setcookie(self::COOKIE, $token, [ 'expires' => time() + self::COOKIE_SEC, 'httponly' => true, 'path' => defined('COOKIEPATH') && COOKIEPATH !== '' ? COOKIEPATH : '/', 'samesite' => 'Lax', 'secure' => is_ssl(), ]); } private static function clearCookie(): void { if (headers_sent() || !isset($_COOKIE[self::COOKIE])) { return; } setcookie(self::COOKIE, '', [ 'expires' => time() - 3600, 'httponly' => true, 'path' => defined('COOKIEPATH') && COOKIEPATH !== '' ? COOKIEPATH : '/', 'samesite' => 'Lax', 'secure' => is_ssl(), ]); } }