'; $fragments =& pending_fragments(); $fragments[$marker] = $html; return $marker; } function restore_fragments(string $content): string { $fragments =& pending_fragments(); foreach ($fragments as $marker => $html) { if (str_contains($content, $marker)) { $content = str_replace($marker, $html, $content); unset($fragments[$marker]); } } return $content; } function notice_html(string $message, bool $retry = false): string { return '

' . esc_html($message) . '

' . ($retry ? '' : '') . '
'; } function render_ssr(string $id, string $theme = '', ?int $minimum_version = null): string { static $spent = 0.0; $origin = service_config()['render']; if ($origin === '') { return notice_html(__('The LiveblogAI service is not configured correctly.', 'liveblogai')); } $remaining = PAGE_REQUEST_BUDGET - $spent; if ($remaining < 0.5) { return notice_html(__('Live coverage could not be loaded in time.', 'liveblogai'), true); } $started = microtime(true); $url = $origin . '/v1/liveblogs/' . rawurlencode($id) . '/fragment'; if ($theme !== '') { $url = add_query_arg('theme', $theme, $url); } if ($minimum_version !== null) { $url = add_query_arg('version', $minimum_version, $url); } $response = request_service($url, min(REQUEST_TIMEOUT, $remaining), MAX_HTML_BYTES + 1); $spent += microtime(true) - $started; if (is_wp_error($response)) { return notice_html(__('Live coverage could not be loaded. Please try again.', 'liveblogai'), true); } $status = wp_remote_retrieve_response_code($response); if ($status === 404) { return notice_html(__('This liveblog is not available to readers yet, or does not exist.', 'liveblogai'), true); } if ($status === 410) { return notice_html(__('This liveblog has been taken offline.', 'liveblogai')); } $html = wp_remote_retrieve_body($response); $type = wp_remote_retrieve_header($response, 'content-type'); if ($status !== 200 || !is_string($type) || !preg_match('/\Atext\/html(?:\s*;|\s*\z)/i', $type) || $html === '' || strlen($html) > MAX_HTML_BYTES || !preg_match('/\A(?:]*>\s*)*
/', $html)) { return notice_html(__('Live coverage could not be loaded. Please try again.', 'liveblogai'), true); } $safe_html = sanitize_render_fragment($html, $id); if ($safe_html === '') { return notice_html(__('Live coverage could not be loaded safely. Please try again.', 'liveblogai'), true); } return protect_fragment($safe_html); } function render_js(string $id): string { $script = service_config()['script']; if ($script === '') { return notice_html(__('The LiveblogAI service is not configured correctly.', 'liveblogai')); } wp_enqueue_script('liveblog-embed', $script, array('liveblog-feedback'), null, array('strategy' => 'defer', 'in_footer' => true)); return '

' . esc_html__('Loading LiveblogAI…', 'liveblogai') . '

' . '' . '
'; } function render_embed($id, $mode): string { static $instances = array(); if (!is_string($id) || !preg_match('/\A[A-Za-z0-9_-]{1,128}\z/', $id)) { return notice_html(__('Enter a valid liveblog ID.', 'liveblogai')); } if (is_admin() || is_feed() || doing_filter('get_the_excerpt') || doing_filter('the_excerpt') || (defined('REST_REQUEST') && REST_REQUEST)) { return notice_html(__('Live coverage is available on the published page.', 'liveblogai')); } wp_enqueue_style('liveblog-frontend'); wp_enqueue_script('liveblog-feedback'); if (isset($instances[$id])) { return notice_html(__('This liveblog already appears on this page.', 'liveblogai')); } $instances[$id] = true; if (resolve_mode($mode) === MODE_JS) { return render_js($id); } prevent_page_cache(); return render_ssr($id); } function render_block(array $attributes): string { $content = render_embed($attributes['liveblogId'] ?? '', $attributes['mode'] ?? ''); return '
'liveblog-wordpress')) . '>' . $content . '
'; } function render_shortcode($attributes): string { $attributes = shortcode_atts(array('id' => '', 'mode' => ''), $attributes, SHORTCODE); return '
' . render_embed($attributes['id'], $attributes['mode']) . '
'; } function render_retry(): void { $id = isset($_GET['id']) && is_string($_GET['id']) ? wp_unslash($_GET['id']) : ''; $theme = isset($_GET['theme']) && is_string($_GET['theme']) ? wp_unslash($_GET['theme']) : ''; $version = isset($_GET['version']) && is_string($_GET['version']) ? wp_unslash($_GET['version']) : ''; if (!preg_match('/\A[A-Za-z0-9_-]{1,128}\z/', $id) || !preg_match('/\A(?:default|[a-f0-9]{64})\z/', $theme) || ($version !== '' && (!preg_match('/\A(?:0|[1-9][0-9]{0,15})\z/', $version) || (float) $version > 9007199254740991))) { status_header(400); exit; } prevent_page_cache(); header('Content-Type: text/html; charset=UTF-8'); header('X-Content-Type-Options: nosniff'); echo render_ssr($id, $theme, $version === '' ? null : (int) $version); exit; }