'aeohelper-markdown'], $args), admin_url('admin.php')); } private static function field(string $name, string $default = ''): string { // All calls occur after check_admin_referer() in save(). $v = isset($_POST[$name]) && is_scalar($_POST[$name]) ? wp_unslash((string) $_POST[$name]) : $default; return sanitize_text_field($v); } private static function textarea_field(string $name): string { // All calls occur after check_admin_referer() in save(). $v = isset($_POST[$name]) && is_scalar($_POST[$name]) ? wp_unslash((string) $_POST[$name]) : ''; return sanitize_textarea_field($v); } private static function start(string $task, int $id = 0): void { echo '
'; wp_nonce_field('zire_ai_save'); echo ''; } public static function save(): void { if (!current_user_can('manage_options')) { wp_die('Not permitted.', '', ['response'=>403]); } check_admin_referer('zire_ai_save'); $task = self::field('task'); $id = absint(self::field('id')); $message = 'Saved.'; $tab = 'pages'; $allowed_tasks = ['settings', 'activity_settings', 'clear_activity', 'llms', 'page', 'exclusions', 'generate', 'publish', 'withdraw', 'audit']; if (!in_array($task, $allowed_tasks, true)) { wp_die('Invalid request.', '', ['response' => 400]); } $post_tasks = ['page', 'exclusions', 'generate', 'publish', 'withdraw', 'audit']; if (in_array($task, $post_tasks, true)) { if (!$id || !get_post($id) || !current_user_can('edit_post', $id)) { wp_die('Not permitted.', '', ['response' => 403]); } } if ($task === 'settings') { $s = Zire_AI_Plugin::settings(); $s['mode'] = self::field('mode') === 'all' ? 'all' : 'specific'; $refresh_mode = self::field('refresh_mode', 'manual'); $s['refresh_mode'] = in_array($refresh_mode, ['manual','draft','publish'], true) ? $refresh_mode : 'manual'; unset($s['autorefresh']); update_option('zire_ai_settings', $s, false); $message = 'Settings saved. First publication always requires preview approval.'; $tab = 'settings'; } elseif ($task === 'activity_settings') { $s = Zire_AI_Plugin::settings(); $s['logging'] = isset($_POST['logging']) ? 1 : 0; $retention = absint(self::field('retention', '30')); $s['retention'] = in_array($retention, [7, 30, 90], true) ? $retention : 30; update_option('zire_ai_settings', $s, false); Zire_AI_Activity::cleanup(); $message = $s['logging'] ? 'Request activity logging enabled.' : 'Request activity logging disabled. Existing records remain until cleared or expired.'; $tab = 'activity'; } elseif ($task === 'clear_activity') { if (isset($_POST['confirm_clear'])) { Zire_AI_Activity::clear(); $message = 'Request activity cleared.'; } else { $message = 'Request activity was not cleared. Confirm the checkbox first.'; } $tab = 'activity'; } elseif ($task === 'llms') { $s = Zire_AI_Plugin::settings(); $want = isset($_POST['llms']); // On first enabling, refuse to take over any responding existing endpoint. if ($want && !$s['llms']) { $r = wp_safe_remote_get(Zire_AI_Plugin::llms_url(), ['timeout'=>10,'redirection'=>0,'limit_response_size'=>1024,'cookies'=>[]]); if (Zire_AI_Plugin::llms_conflict() || is_wp_error($r) || wp_remote_retrieve_response_code($r) !== 404) { $want = false; $message = 'llms.txt was NOT enabled: an existing endpoint, redirect or network error was detected. Keep your current manager, or disable it and confirm /llms.txt returns 404 first.'; } } $s['llms'] = $want ? 1 : 0; $s['title'] = self::field('title') ?: get_bloginfo('name'); $s['summary'] = self::field('summary'); $s['context'] = self::textarea_field('context'); $s['section_order'] = self::textarea_field('section_order'); update_option('zire_ai_settings', $s, false); $tab = 'llms'; } elseif ($task === 'page' && get_post($id)) { if (!current_user_can('edit_post', $id)) { wp_die('Not permitted.'); } foreach (['include','exclude','no_manifest','allow_shortcodes'] as $key) { update_post_meta($id, '_zire_ai_' . $key, isset($_POST[$key]) ? 1 : 0); } $selector = self::field('selector'); if ($selector && !preg_match('/^(?:[a-z][a-z0-9-]*|[.#][a-zA-Z_][a-zA-Z0-9_-]*)$/', $selector)) { wp_die('Use a single tag, #id or .class selector.'); } if ($selector !== get_post_meta($id, '_zire_ai_selector', true)) { delete_post_meta($id, Zire_AI_Plugin::DATA); delete_post_meta($id, Zire_AI_Plugin::DRAFT); } foreach (['selector','section','title','description'] as $key) { update_post_meta($id, '_zire_ai_' . $key, self::field($key)); } $manifest_order_raw = self::field('manifest_order'); if ($manifest_order_raw === '') { delete_post_meta($id, '_zire_ai_manifest_order'); } else { update_post_meta($id, '_zire_ai_manifest_order', absint($manifest_order_raw)); } if (!Zire_AI_Plugin::enabled($id)) { delete_post_meta($id, Zire_AI_Plugin::DATA); delete_post_meta($id, Zire_AI_Plugin::DRAFT); delete_post_meta($id, Zire_AI_Plugin::REFRESH_STATUS); } $manifest_configured = self::field('section') !== '' || self::field('title') !== '' || self::field('description') !== '' || $manifest_order_raw !== ''; if ($manifest_configured && !Zire_AI_Plugin::document($id)) { $message = 'Page settings saved. Publish the Markdown version of this page before it can appear in llms.txt.'; } else { $message = 'Page settings saved.'; } } elseif ($task === 'exclusions' && get_post($id)) { if (!current_user_can('edit_post', $id)) { wp_die('Not permitted.'); } $raw = self::textarea_field('exclude_selectors'); $lines = preg_split('/\R/u', $raw, -1, PREG_SPLIT_NO_EMPTY) ?: []; $selectors = []; foreach ($lines as $line) { $line = trim($line); if ($line === '') { continue; } if (!preg_match('/^[.#][a-zA-Z_][a-zA-Z0-9_-]*$/', $line)) { wp_die('Use one simple .class or #id selector per line.'); } $selectors[] = $line; } $selectors = array_values(array_unique($selectors)); if (count($selectors) > 30) { wp_die('Use no more than 30 exclusion selectors.'); } $value = implode("\n", $selectors); if ($value !== (string) get_post_meta($id, '_zire_ai_exclude_selectors', true)) { update_post_meta($id, '_zire_ai_exclude_selectors', $value); delete_post_meta($id, Zire_AI_Plugin::DATA); delete_post_meta($id, Zire_AI_Plugin::DRAFT); $message = 'Exclusions saved. Generate a fresh preview before publishing.'; } else { $message = 'Exclusions unchanged.'; } } elseif ($task === 'generate') { $r = Zire_AI_Plugin::generate($id); $message = is_wp_error($r) ? $r->get_error_message() : 'Preview generated. Review it below, then approve publication.'; } elseif ($task === 'publish') { $message = isset($_POST['reviewed']) && Zire_AI_Plugin::publish($id) ? 'Markdown published. Purge any page cache to refresh discovery links.' : 'Not published. Confirm the review checkbox and generate a current preview.'; } elseif ($task === 'withdraw') { delete_post_meta($id, Zire_AI_Plugin::DATA); delete_post_meta($id, Zire_AI_Plugin::DRAFT); delete_post_meta($id, Zire_AI_Plugin::REFRESH_STATUS); $message = 'Markdown withdrawn. Purge any external cache if applicable.'; } elseif ($task === 'audit' && Zire_AI_Plugin::eligible($id)) { $results = []; // Small user-selected probe, not a bulk crawler. User-agent alone does not verify bot origin. $agent = self::field('agent', 'AEOHelper-Audit/0.1'); if (!in_array($agent, ['AEOHelper-Audit/0.1','OAI-SearchBot','ChatGPT-User','Claude-SearchBot','Claude-User','PerplexityBot','Googlebot'], true)) { $agent = 'AEOHelper-Audit/0.1'; } try { $response = Zire_AI_Plugin::fetch($id, $agent); $data = (new Zire_AI_Markdown($response['url']))->extract($response['body'], (string) get_post_meta($id, '_zire_ai_selector', true), Zire_AI_Plugin::exclude_selectors($id)); $results = ['agent'=>$agent,'time'=>gmdate('c'),'http'=>$response['code'],'content_type'=>$response['type'],'html_bytes'=>strlen($response['body']),'words'=>$data['words'],'markdown_bytes'=>$data['bytes'],'canonical'=>$data['canonical'] ?: 'Not found','headings'=>$data['headings'],'note'=>'This is a same-server simulated user-agent check, not proof that a real crawler can access the site.']; } catch (Throwable $e) { $results = ['agent'=>$agent,'error'=>$e->getMessage()]; } update_post_meta($id, '_zire_ai_audit', $results); $message = 'Audit finished. Results appear below.'; } set_transient('zire_ai_notice_' . get_current_user_id(), $message, 120); wp_safe_redirect(self::url(['tab'=>$tab] + ($id ? ['edit'=>$id] : []))); exit; } public static function page(): void { if (!current_user_can('manage_options')) { return; } $id = isset($_GET['edit']) && is_scalar($_GET['edit']) ? absint($_GET['edit']) : 0; $tab = isset($_GET['tab']) && is_string($_GET['tab']) ? sanitize_key($_GET['tab']) : ($id ? 'pages' : 'overview'); $s = Zire_AI_Plugin::settings(); echo '
✦

AEOHelper - Markdown Publisher

Publish clear, reviewed Markdown versions of your public content.

Version ' . esc_html(ZIRE_AI_VERSION) . '
'; $notice = get_transient('zire_ai_notice_' . get_current_user_id()); if ($notice) { echo '

' . esc_html($notice) . '

'; delete_transient('zire_ai_notice_' . get_current_user_id()); } if (!class_exists('DOMDocument')) { echo '

PHP DOM/XML is missing. Enable it with your host before generating Markdown.

'; } if (!get_option('blog_public')) { echo '

Search engine visibility is disabled in WordPress Reading settings. All exports are blocked.

'; } if (Zire_AI_Plugin::llms_conflict()) { echo '

Another llms.txt file or Rank Math module was detected. AEOHelper will not serve its own manifest while that conflict exists.

'; } echo ''; if ($id && get_post($id)) { self::editor($id); } elseif ($tab === 'overview') { self::overview($s); } elseif ($tab === 'activity') { self::activity($s); } elseif ($tab === 'llms') { self::llms($s); } elseif ($tab === 'settings') { self::settings($s); } elseif ($tab === 'help') { self::help(); } else { self::pages($s); } echo '
'; } private static function overview(array $s): void { $published = 0; $ids = get_posts(['post_type'=>['page','post'],'post_status'=>'publish','posts_per_page'=>-1,'fields'=>'ids','meta_key'=>Zire_AI_Plugin::DATA]); foreach ($ids as $id) { if (Zire_AI_Plugin::document((int) $id)) { $published++; } } $last = Zire_AI_Activity::last_request(); echo '
Published Markdown' . (int) $published . 'Approved and currently available
Requests in 30 days' . (int) Zire_AI_Activity::count_since(30) . '' . ($s['logging'] ? 'Local logging is enabled' : 'Enable logging to collect activity') . '
llms.txt' . ($s['llms'] && !Zire_AI_Plugin::llms_conflict() ? 'Live' : 'Off') . 'Optional curated site directory
Last request' . esc_html($last ? self::display_time($last) : 'None yet') . 'Markdown or llms.txt endpoint
'; echo '
GET STARTED

Publish your first Markdown page

Choose a public page, generate its logged-out preview, remove visual-only content and approve the result. First publication is never automatic.

1Select a pageSpecific pages mode is safest while testing.
2Review the extractionCheck facts, prices, links, tables and examples.
3Approve publicationThe original HTML remains unchanged.

Manage pages Read testing guidance

'; echo '
RECENT ACTIVITY

Most-requested Markdown pages

'; $top = Zire_AI_Activity::top_pages(); if (!$s['logging']) { echo '
Request logging is off

Enable it to see whether published Markdown and llms.txt endpoints are requested.

Configure activity
'; } elseif (!$top) { echo '
No requests recorded yet

Open a public Markdown link in a private browser to test the activity log.

'; } else { echo '
'; foreach ($top as $i=>$row) { echo '
' . (int) ($i + 1) . '' . esc_html(get_the_title((int) $row['post_id']) ?: 'Page ID ' . (int) $row['post_id']) . 'Last requested ' . esc_html(self::display_time($row['last_request'])) . '' . (int) $row['requests'] . '
'; } echo '

View all request activity →

'; } echo '
'; } private static function pages(array $s): void { echo '
CONTENT

Pages and Markdown

Choose public content, review the extracted Markdown and control what is published.

Publishing settings
'; $search = isset($_GET['s']) && is_string($_GET['s']) ? sanitize_text_field(wp_unslash($_GET['s'])) : ''; $paged = isset($_GET['paged']) && is_scalar($_GET['paged']) ? max(1, absint($_GET['paged'])) : 1; $query = new WP_Query(['post_type'=>['page','post'],'post_status'=>'publish','posts_per_page'=>20,'paged'=>$paged,'s'=>$search,'orderby'=>'title','order'=>'ASC']); echo '

Blocked pages cannot be exported. Exclusion always wins over inclusion.

'; foreach ($query->posts as $p) { $eligible = Zire_AI_Plugin::eligible($p->ID); $enabled = Zire_AI_Plugin::enabled($p->ID); $live = Zire_AI_Plugin::document($p->ID); $issues = Zire_AI_Plugin::eligibility_issues((int) $p->ID); $last = Zire_AI_Activity::last_for_page((int) $p->ID); echo ''; } if (!$query->posts) { echo ''; } echo '
PageScopeMarkdownLast requestedAction
' . esc_html(get_the_title($p->ID) ?: '(Untitled)') . '
' . esc_html($p->post_type) . ' · ID ' . (int) $p->ID . '
' . ($eligible ? ($enabled ? 'Enabled' : 'Not selected') : 'Blocked
' . esc_html($issues[0] ?? 'A site integration blocked this page.') . '') . '
' . ($live ? 'Published' : 'Not published') . '' . esc_html($last ? self::display_time($last) : '—') . 'Manage page
No pages found.
' . wp_kses_post(paginate_links(['base'=>add_query_arg('paged','%#%',self::url(['tab'=>'pages','s'=>$search])),'current'=>$paged,'total'=>$query->max_num_pages])) . '
'; } private static function editor(int $id): void { echo '

← All pages

' . esc_html(get_the_title($id)) . '

View original page ↗

'; self::start('page', $id); foreach (['include'=>'Enable this page in Specific pages mode','exclude'=>'Exclude this page in every mode','no_manifest'=>'Keep out of llms.txt (Markdown can still be published)','allow_shortcodes'=>'Allow shortcode-rendered content on this page (review the public preview carefully)'] as $key=>$label) { echo '

'; } foreach (['section'=>'llms.txt section (e.g. Start here, Platform features or AEO guides)','title'=>'llms.txt link title (optional; SEO title used when blank)','description'=>'llms.txt description (optional; SEO meta description used when blank)','selector'=>'Content selector (optional: main, article, #content or .entry-content)'] as $key=>$label) { echo '


'; } echo '



Leave blank for the default order. Set the section hub to 1 to place it before individual pages.

'; submit_button('Save page settings', 'primary', 'submit', false); echo '
'; if (!Zire_AI_Plugin::enabled($id)) { $issues = Zire_AI_Plugin::eligibility_issues($id); echo '

Not enabled for generation

'; if ($issues) { echo '

Why this page is blocked:

'; } else { echo '

This page is eligible but has not been selected in Specific pages mode.

'; } echo '

Change only the relevant setting above, save again, and review the generated public-content preview before publishing.

'; return; } echo '

1. Generate a review preview

Fetches the public page without your login cookies. Does not rewrite content or send it to an AI provider. CSS files and JavaScript are not executed.

'; self::start('generate', $id); submit_button('Generate / refresh preview', 'primary', 'submit', false); echo ''; $error = get_post_meta($id, '_zire_ai_error', true); if ($error) { echo '

' . esc_html($error) . '

'; } $draft = get_post_meta($id, Zire_AI_Plugin::DRAFT, true); if (is_array($draft) && !empty($draft['markdown'])) { echo '

2. Review the extracted content

' . (int) $draft['words'] . ' words · ' . (int) $draft['bytes'] . ' Markdown bytes · selector: ' . esc_html($draft['selector']) . '

'; $diagnostics = wp_parse_args((array) ($draft['diagnostics'] ?? []), ['duplicate_h1_removed'=>0,'decorative_headings_removed'=>0,'block_links_rewritten'=>0,'tables'=>0,'disclosures'=>0,'contexts'=>0]); echo '
' . (int) $diagnostics['duplicate_h1_removed'] . ' duplicate H1 removed' . (int) $diagnostics['decorative_headings_removed'] . ' decorative headings removed' . (int) $diagnostics['block_links_rewritten'] . ' card links rewritten' . (int) $diagnostics['tables'] . ' tables' . (int) $diagnostics['disclosures'] . ' disclosures / FAQs' . (int) $diagnostics['contexts'] . ' context notes

Check facts, prices, links, tables and FAQs. Check that navigation, account data and animation examples are not included as factual page content. Complex tables and CSS-hidden elements need manual review.

'; self::extraction_controls($id); echo '
'; self::start('publish', $id); echo '

'; submit_button('Approve & publish Markdown', 'primary', 'submit', false); echo ''; } else { self::extraction_controls($id); } $live = Zire_AI_Plugin::document($id); if ($live) { echo '

Published

Open public Markdown ↗ · Download .md file

'; } $refresh_status = get_post_meta($id, Zire_AI_Plugin::REFRESH_STATUS, true); if (is_array($refresh_status) && !empty($refresh_status['message'])) { echo '

Source-update status: ' . esc_html($refresh_status['message']) . (!empty($refresh_status['time']) ? ' (' . esc_html(self::display_time((string) $refresh_status['time'])) . ')' : '') . '

'; } self::start('withdraw', $id); echo '

'; echo '

Access & extraction probe

Tests the public page from your server with a chosen user-agent. It cannot verify a genuine crawler IP, evaluate every robots.txt rule, or see firewall events upstream of WordPress.

'; self::start('audit', $id); echo ' '; $audit = get_post_meta($id, '_zire_ai_audit', true); if ($audit) { echo '
' . esc_html(wp_json_encode($audit, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)) . '
'; } echo '

Open robots.txt ↗ · Use Plesk/server logs and Search Console for actual crawler access evidence.

'; } private static function extraction_controls(int $id): void { echo ''; } private static function activity(array $s): void { $endpoint = isset($_GET['endpoint']) && is_string($_GET['endpoint']) ? sanitize_text_field(wp_unslash($_GET['endpoint'])) : ''; $agent = isset($_GET['agent']) && is_string($_GET['agent']) ? sanitize_text_field(wp_unslash($_GET['agent'])) : ''; $rows = Zire_AI_Activity::recent(100, $endpoint, $agent); echo '
LOCAL MONITORING

Request Activity

See when published Markdown and llms.txt endpoints are requested.

'; echo '
Last 24 hours' . (int) Zire_AI_Activity::count_since(1) . 'Endpoint requests
Last 7 days' . (int) Zire_AI_Activity::count_since(7) . 'Endpoint requests
Last 30 days' . (int) Zire_AI_Activity::count_since(30) . 'Endpoint requests
'; echo '

Recent requests

Stored locally. Crawler names come from unverified user-agent strings and can be spoofed.

' . ($s['logging'] ? 'Logging on' : 'Logging off') . '
'; echo '
'; foreach ($rows as $row) { $post_id = (int) $row['post_id']; $page = $post_id ? (get_the_title($post_id) ?: 'Page ID ' . $post_id) : '—'; echo ''; } if (!$rows) { echo ''; } echo '
TimeEndpointPageClaimed crawlerMethodStatus
' . esc_html(self::display_time($row['requested_at'])) . '' . esc_html($row['endpoint']) . '' . esc_html($page) . '' . esc_html($row['agent_label']) . '' . esc_html($row['request_method']) . '' . (int) $row['response_status'] . '
No matching requests

' . ($s['logging'] ? 'Open a published Markdown endpoint in a private browser to test the log.' : 'Enable local request logging using the controls on this page.') . '

Shows the latest 100 matching observations. Identical requests are collapsed into 15-minute observations and storage is capped at 10,000 records. It does not verify crawler IP addresses or record visits that only request the original HTML page.

'; } private static function settings(array $s): void { echo '
CONFIGURATION

Publishing settings

Control which public Pages and Posts are eligible for reviewed Markdown.

Publishing scope

Every first publication still requires a generated preview and manual approval.

'; self::start('settings'); echo '
'; echo '

After an approved source page changes

'; echo ''; echo ''; echo ''; echo '

Background updates use WP-Cron and may be delayed on low-traffic sites. Page caches can also delay changes in the fetched public HTML.

'; submit_button('Save publishing settings', 'primary', 'submit', false); echo '
'; echo '

Safe defaults

✓Manual first publicationAutomatic updates never publish a page that has not already been approved.
✓Private content blockedDrafts, passwords and common account routes are excluded.
✓Original HTML unchangedNo user-agent switching or same-URL content negotiation.
✓No external AI callsConversion and optional activity logging stay on this site.
'; } private static function display_time(string $gmt): string { if ($gmt === '') { return ''; } return get_date_from_gmt($gmt, get_option('date_format') . ' ' . get_option('time_format')); } private static function llms(array $s): void { echo '

Optional llms.txt manager

Off by default. Keep this off if Rank Math, another plugin or a physical file already manages llms.txt.

The page list is maintained automatically: approved, currently eligible Markdown appears using each page\'s llms.txt section. Link titles and descriptions use the page\'s rendered SEO metadata when manual overrides are blank. Withdrawing or invalidating Markdown removes it from the generated file.

'; self::start('llms'); echo '

'; foreach (['title'=>'Website name','summary'=>'One-line website summary'] as $key=>$label) { echo '


'; } echo '

'; echo '


Listed sections appear first in this order. Any unlisted sections keep their existing fallback order.

'; submit_button('Save llms.txt settings','primary','submit',false); echo '

Preview

Check live /llms.txt ↗

'; } private static function help(): void { echo '

Start with one page

  1. Leave scope on Specific pages and llms.txt management off.
  2. Search for one public page, open Manage page, enable it and save.
  3. Generate a preview. Check its text against the public page.
  4. Approve it, then open the public Markdown link in a logged-out/private browser.
  5. Purge the HTML page cache and check page source for rel="alternate".
  6. Edit the original page: in manual mode, the old export must stop being served until you generate and approve a fresh preview.

Safety and indexing

Approved Markdown responses use clean /index.md URLs and send an HTTP Link canonical pointing to the original HTML page. Successful Markdown responses do not carry noindex. Unpublished, missing and error responses remain noindex. The original HTML remains the primary indexable page and advertises its Markdown version using rel="alternate".

Legacy query-based Markdown URLs redirect permanently to their corresponding clean URL. Markdown endpoints send no-store while this feature is being tested. Do not block the clean Markdown URLs in robots.txt if you want AI crawlers to retrieve them. The plugin does not add Markdown URLs to XML sitemaps. A physical llms.txt file can be advertised using rel="describedby" without allowing the plugin to overwrite or serve that file.

Limitations

Only published Pages and Posts are supported. Shortcodes are blocked unless explicitly allowed on each page after confirming they render only public content. Passwords, common account routes and known SEO noindex settings remain blocked. Membership sites require a separate access-control review before use. The renderer does not run JavaScript or compute external CSS; use previews and content selectors. Use the per-page exclusion field to remove every matching .class or #id, or use the HTML attributes panel for one exact wrapper, visual grids or Markdown-only context.

All eligible mode widens eligibility only; every first publication still needs review. Source edits withdraw stale Markdown immediately. Optional background modes can prepare a review draft or automatically replace Markdown that was approved previously. WP-Cron and page caches may delay updates. Theme-only changes need manual withdrawal or regeneration.

Request Activity and crawler evidence

Request Activity is optional and records requests to the separate Markdown and llms.txt endpoints only. Crawler labels are taken from user-agent strings and are not verified identities. The Access & extraction probe is a simulation and is excluded from this log because it requests the original HTML. Use server/CDN logs and provider IP-verification guidance when verified crawler evidence is required.

A request, HTTP 200 response or smaller Markdown document does not demonstrate indexing, provider token savings or citation uplift.

Privacy and removal

No telemetry, external AI calls or API keys. Generation makes a public HTTP request to your own site. Optional activity records stay in the local WordPress database and contain no IP addresses, cookies or referrers. Previews, approved copies and settings are also stored locally. Deactivation stops plugin routes but preserves settings; deleting the plugin removes its stored data and request table. Purge external caches after withdrawal, deactivation or deletion.

llms.txt proposal · Google noindex guidance

'; } }