Skip to content
WP Visibility

Docs

Everything needed to install WP Visibility, run your SEO by hand, and connect your AI assistant safely. Work through Getting Started on a new install; every other section stands alone.

Everything needed to install WP Visibility, run your SEO by hand, and connect your AI assistant safely. Work through Getting Started on a new install; every other section stands alone.

Getting Started

Requirements

WP Visibility requires WordPress 7.0 or newer and PHP 8.1 or newer. On an unsupported environment the plugin stays idle and shows a single admin notice naming the versions you are running. Nothing breaks and nothing is written.

To check your versions, open Tools → Site Health in your WordPress admin and select the Info tab. The WordPress section lists your core version and the Server section lists your PHP version.

Install and activate

Download the plugin zip from your account. In your WordPress admin, go to Plugins → Add New Plugin, click “Upload Plugin”, choose the zip, then install and activate it.

After activation, a top-level “WP Visibility” entry appears in the admin menu with one submenu item, “Settings”. The settings screen is a single searchable page. Type in the search box to filter every section and field by label. Two more submenu items appear as you enable their modules: “Redirects” with the Redirects module, and “Review queue” with the Autopilot module.

A “Get started” checklist at the top of the settings screen walks the three setup steps: enter your license, connect your AI assistant, and turn on Autopilot review. It tracks itself, hides once the steps are done, and a “Hide this” button dismisses it early.

Enter your license key

The license unlocks plugin updates. Features are never locked: an expired or missing key only means you stop receiving updates.

Open WP Visibility → Settings and find the “License” section. Paste your key into the “License key” field and click “Activate”. The badge next to the button reads “Active” on success, with a “Renews:” date when one is known. “Invalid” means the server rejected the key. “Could not verify” means the activation server could not be reached; the plugin keeps working, so retry later. A license is $99 a year and covers unlimited sites. For key problems, write to support@wpvisibility.com.

Preview an import with a dry run

The Import module is on by default and migrates SEO data from Yoast SEO, Rank Math, SEOPress, The SEO Framework, or All in One SEO. Imports never modify or delete the source plugin’s data, so rollback is reactivating the old plugin.

Start every import as a dry run. A dry run writes nothing and reports exactly what would change. With WP-CLI:

wp visibility import yoast --dry-run

Use rank-math, seopress, tsf, or aioseo for the other sources. The dry run logs a running count of posts that would change, then prints a before/after preview table for the first 10 changed posts, with the title and meta description before and after. Template variables are translated during mapping, for example Yoast’s %%sitename%% becomes {site} and Rank Math’s %title% becomes {title}.

Run the import

When the preview looks right, run the same command without the flag:

wp visibility import yoast

The import runs in batches of 200 posts and logs progress after each batch. The first live batch also imports mapped settings (the title separator, homepage title, and homepage meta description) and term-level meta. Re-running is safe: posts whose values already match are skipped.

The same runner is available over REST at POST /wp-json/wpvis/v1/import/run for administrators. dry_run defaults to true, so a bare request is always a preview. Send dry_run: false to apply, and repeat the call with a higher offset until the response reports remaining: 0.

Titles and Meta

WP Visibility builds every document title and meta description from site-wide templates, and lets any post or page override the result from the editor. Configure the templates once under WP Visibility → Settings; override individual posts in the editor sidebar.

How precedence works

For each request the plugin resolves the title in a fixed order. A per-post value entered in the editor always wins. On the homepage, if no per-post value exists, the “Homepage title” field in the General section applies next. Otherwise the template for that page type (post, archive, author, search, 404) renders the title.

Meta descriptions follow the same order: per-post value first, then the “Homepage meta description” field on the homepage, then the matching description template. Search, 404, date, and author pages ship with no description template, so they output no description tag unless you add one.

Per-post values are templates too. Type plain text, or use variables such as {title} and {sep}; both render through the same engine.

Set the title separator

Open WP Visibility → Settings and find “Title separator” in the General section. The character you pick replaces the {sep} variable in every template. The default is an en dash.

When a variable renders empty (for example {tagline} on a site with no tagline), the plugin collapses leftover separators, so a blank value never leaves a stray separator at the edge of a title.

Site-wide templates

The “Titles & descriptions” section holds one template per page type. Title templates: “Homepage title template”, “Post & page title template”, “Archive title template”, “Author archive title template”, “Search results title template”, and “404 page title template”. Description templates: “Homepage description template”, “Post & page description template”, and “Archive description template”.

On page 2 and beyond of any paginated view, the plugin appends the separator and the page number automatically. You do not need a pagination variable in the template.

Template variables

Variables are lowercase names in curly braces. The core set: {site}, {tagline}, {sep}, {title}, {term_title}, {author}, {search_query}, {excerpt}, {term_description}. Also available: {date}, {modified}, {page}, {pagenumber}, {post_type_singular}, {post_type_plural}, {category}, {currentyear}, {currentdate}, and {custom_field:KEY} to pull a post meta value by its key.

Unknown variables render as empty text. Developers can resolve custom variables through the wpvis_template_variable filter.

A concrete example

The shipped “Post & page title template” is:

{title} {sep} {site}

On a site named Garden Notes with the default separator, a post titled “How to Prune Tomatoes” renders as How to Prune Tomatoes – Garden Notes. To add the publish date, change the template to {title} {sep} {date} {sep} {site}.

Per-post overrides in the editor

In the block editor, open the “WP Visibility” sidebar from the plugin icon in the top toolbar. The “Search appearance” panel opens first and contains a live search-result preview plus two fields: “Search title” and “Search description”. Leave either field empty to fall back to the site template; an empty description falls back to an excerpt generated from the content.

The preview shows the URL, the rendered title, and the rendered description, each with a character meter marking the typical range: 30 to 60 characters for titles, 70 to 160 for descriptions. Variables the editor cannot resolve on the client, such as {term_title}, are stripped from the preview but resolve on the live page.

Overrides store as regular post meta, so autosave and revisions include them. The classic editor offers the same “Search title” and “Search description” fields in a “WP Visibility” metabox.

Schema and Sitemaps

What structured data is generated

When the Schema module is on, WP Visibility prints one JSON-LD @graph in a single <script type="application/ld+json"> tag on each page. The graph contains a publisher node (Organization or Person), a WebSite node, a WebPage node, and a BreadcrumbList. Blog posts also get an Article node with the post author attached as a Person.

Nothing is printed on 404 or search results pages. Author archives get a ProfilePage node instead of a plain WebPage. The plugin never emits FAQPage, HowTo, or SearchAction markup, since Google no longer shows rich results for any of them.

Identify your organization or person

Open WP Visibility → Settings and find the Schema section. Set “This site represents” to “An organization” for a company site or “A person” for a personal site. That choice decides which entity search engines tie your content to.

For an organization, fill in “Organization name” (leave it empty to use the site title) and pick an “Organization logo”. For a person, enter the WordPress user ID in “Person (user ID)”. Add your official account links under “Social profile URLs”; they become sameAs properties that confirm those accounts are yours.

The aggregate schema endpoint

Turn on “Aggregate schema endpoint” to publish your site’s entity graph at one public address: /wp-json/wpvis/v1/schema-map. AI tools can fetch the whole document there instead of crawling page by page. The response is cached for 12 hours, and a “View schema graph” link appears in the Schema section once the toggle is on.

Validate your markup

Load any page, view the source, and find the application/ld+json script tag. Paste the page URL into Google’s Rich Results Test (search.google.com/test/rich-results) to see which rich result types Google detects, and into validator.schema.org for a strict syntax check. Recheck after changing the Schema settings.

XML sitemaps

With the Sitemaps module on, your sitemap index lives at /sitemap.xml. Documents are generated on request; no files are written to disk. By default the sitemap includes every published post and page of a public post type (attachments are excluded), plus term archives such as categories and tags that contain at least one post.

Anything marked noindex stays out automatically, as do password-protected posts. In the Sitemaps section, set “URLs per sitemap page” (up to 2000 are served per file), toggle “Include featured images” to list each post’s featured image, and use “Exclude post types from the sitemap” to drop whole post types. A “View sitemap.xml” link opens the live document.

Submit your sitemap to search engines

WP Visibility adds a Sitemap: line to your robots.txt, so most crawlers find the index on their own. Submitting it yourself also unlocks indexing reports. In Google Search Console, open Sitemaps and enter sitemap.xml. In Bing Webmaster Tools, open Sitemaps and submit the full URL.

If you have not verified your site yet, paste the verification codes into the “Google Search Console” and “Bing Webmaster Tools” fields in the Site verification section. For faster Bing indexing, enable the IndexNow module, which notifies Bing and Yandex the moment you publish or update.

Enable the “Breadcrumbs” toggle in the Modules section. On classic themes, place the [wpvis_breadcrumbs] shortcode where the trail should render; pass separator="/" to override the default, which is your “Title separator” setting. On block themes, use the core Breadcrumbs block that ships with WordPress 7.0; the plugin adds no block of its own.

The shortcode outputs semantic nav > ol > li markup with the class wpvis-breadcrumbs and ships no CSS or JavaScript, so style the trail in your theme. The matching BreadcrumbList JSON-LD comes from the Schema module whether or not you render a visible trail.

Redirects

The Redirects module stores redirect rules in their own database table and answers matching requests before WordPress renders anything else. Each rule records a hit count and last hit time, so you can see which redirects still earn traffic. Turn the module on under WP Visibility → Settings with the “Redirects” toggle in the “Modules” section; once it is on, the manager appears as its own page in the WP Visibility menu.

Add, edit, and delete rules

Rules are managed on their own page, WP Visibility → Redirects: a searchable list of every rule with its hit count, add and inline edit, delete, and a CSV import with a dry-run preview. Your assistant can manage them too, and the same rules are available over the REST API under wpvis/v1/redirects. Every route requires the manage_options capability.

  • GET /wp-json/wpvis/v1/redirects lists rules, with page, per_page (up to 100), and search parameters.
  • POST /wp-json/wpvis/v1/redirects creates a rule from source, target, status, and is_regex.
  • PUT /wp-json/wpvis/v1/redirects/{id} is a partial update: fields you omit keep their stored values.
  • DELETE /wp-json/wpvis/v1/redirects/{id} removes one rule and returns the deleted row.

With the Assistant connection module on, your assistant manages the same table through the abilities labeled “List redirects”, “Create a redirect”, and “Delete a redirect”. For one page, the editor sidebar also offers a “Redirect (301) to” field; that field lives on the post itself and does not create a rule in the redirects table.

Source and target rules

The source is a path on your site, starting with /. You may paste a full URL from your own domain; the plugin reduces it to its path and rejects URLs on other hosts. Sources are normalized (query string dropped, trailing slash trimmed, encoding decoded), and a duplicate source is rejected: “A redirect for this source already exists.”

The target is an absolute http(s) URL or a site-relative path starting with /. The visitor’s query string passes through to the target. Set is_regex for pattern rules: patterns are compiled and checked at save time with the same construction the matcher runs, they match anywhere in the path unless you anchor them, and $1, $2 backreferences work in the target. Up to 200 regex rules are evaluated per request.

Redirect types

Six status codes are supported: 301, 302, 307, 308, 410, and 451. 301 and 308 are permanent; 302 and 307 are temporary. 410 (content gone) and 451 (unavailable for legal reasons) are served in place rather than redirected, and they are the only statuses that accept an empty target.

Loop and chain protection

A rule whose target resolves straight back to its own source is rejected: “The target redirects straight back to the source.” A rule whose target matches another rule’s source is saved but returns a creates_chain warning so you can flatten the chain to a single hop.

When a published post’s permalink changes, the module creates a 301 from the old path to the new one, rewrites existing rules that pointed at the old path so they point at the new one, and deletes any rule that would redirect visitors away from the now-live URL. Hit counts are written after the response is sent, and HEAD probes are not counted.

Import redirects from another plugin

POST /wp-json/wpvis/v1/redirects/import-csv accepts a CSV upload in the file field and recognizes three layouts: the plugin’s own source,target,status,is_regex columns, a Redirection plugin export, and a Rank Math redirections CSV. Imports run as a dry run by default: every row is validated and the first ten are previewed, but nothing is written until you repeat the call with dry_run=false. Each run handles up to 5,000 rows; duplicates and unsupported match types are skipped with a per-row message.

The SEO importer that migrates titles and descriptions from Yoast, Rank Math, SEOPress, The SEO Framework, or AIOSEO does not move redirects. Carry those over with this CSV endpoint.

Worked example: retire a page

Suppose the page at /spring-sale-2025 is over and /promotions replaces it. Create the redirect first, while the old page is still published; the matcher runs before the page would render, so there is no 404 window.

curl -u admin:APP_PASSWORD \
  -X POST "https://example.com/wp-json/wpvis/v1/redirects" \
  -H "Content-Type: application/json" \
  -d '{"source":"/spring-sale-2025","target":"/promotions","status":301}'

Then move the old page to the trash. If nothing replaces the page, send "status": 410 with an empty target instead; the URL then answers 410 Gone and crawlers drop it.

Social Cards and Open Graph

The Social module adds Open Graph and Twitter/X card tags for rich link previews. When someone shares a page on Facebook, LinkedIn, X, Slack, or a chat app, those tags decide the title, description, and image the preview shows. Turn the module on under WP Visibility → Settings in the “Modules” section with the “Social” toggle.

Sitewide settings

With the module on, a “Social” section appears on the same settings screen. “Output Open Graph tags” and “Output Twitter/X card tags” control the two tag families independently. “Twitter/X card type” chooses between “Summary” (small square thumbnail) and “Summary with large image” (full-width image card).

“X (Twitter) site handle” attributes cards to your account, for example @yoursite. The plugin normalizes the leading @ for you. “Facebook app ID” accepts digits only and is omitted from output when empty. “Default social image” sets the fallback image, “Shown when a page has no image of its own and gets shared on social media.”

What the plugin outputs

On every page except 404s, the Open Graph generator writes og:type (article for single posts and pages, website elsewhere), og:site_name, og:title, og:description, og:url (the canonical URL), and og:locale. Single posts also get article:published_time and article:modified_time. When an image resolves, the plugin adds og:image plus its width, height, and alt text.

The Twitter/X generator stays deliberately small. It emits twitter:card and, when a handle is set, twitter:site. X falls back to the og: tags for title, description, and image, so the plugin repeats nothing it does not have to.

Per-post overrides in the editor

Open the “WP Visibility” sidebar in the block editor and expand the “Social sharing” panel. “Social title” and “Social description” override the shared preview text; left empty, each falls back to the search title and search description. Click “Select social image” to pick an image for this post, “Replace social image” to change it, or “Remove” to clear it.

The “X (Twitter) overrides” link reveals “X title” and “X description”. These apply to X only. Facebook and LinkedIn keep using the social title and description above them.

How the social image is chosen

The plugin resolves one image per page and reuses it for Open Graph, Twitter/X cards, and schema. The order is per-post social image first, then the post’s featured image, then the “Default social image” from settings. If none of those exist, no image tags are output and the network picks its own preview.

The full-size version of the chosen image is used, with its dimensions and the attachment’s alt text included so networks can lay out the card before downloading the image.

Image size guidance

Use 1200 by 630 pixels (a 1.91:1 ratio). That size renders sharp on Facebook and LinkedIn and works for the “Summary with large image” card on X. Keep the subject centered, since X may crop the edges to a slightly wider ratio and the plain “Summary” card crops to a square. Keep files under 5 MB.

Set an image on the “Default social image” field even if most posts have featured images. It guarantees your homepage, archives, and image-free pages never share as a bare gray card.

Filters for developers

Three filters adjust output in code. wpvis_og_tags and wpvis_twitter_tags receive the property map before rendering; wpvis_social_image receives the resolved image array (url, width, height, alt) or null.

add_filter( 'wpvis_og_tags', function ( array $props, $state ) {
    $props['og:image:secure_url'] = $props['og:image'] ?? '';
    return $props;
}, 10, 2 );

Returning an empty string for a property removes that tag from output.

AI Crawlers and llms.txt

The AI Visibility module controls which AI crawlers may read your site, publishes an optional llms.txt file, and adds an optional Content-Signal line to robots.txt. Turn it on under WP Visibility → Settings with the “AI Visibility” toggle in the “Modules” section. Its settings live in the “AI Visibility” section of the same screen.

Set the crawler policy

The plugin groups known AI crawlers into two classes, each with one policy. “Model training crawlers” covers bots that collect content for model training: GPTBot, ClaudeBot, Google-Extended, Applebot-Extended, CCBot, meta-externalagent, and Bytespider. Blocking this class opts your content out of AI model training and costs no search or answer visibility.

“AI search crawlers” covers bots that index or fetch pages for AI answers: OAI-SearchBot, Claude-SearchBot, PerplexityBot, ChatGPT-User, Claude-User, and DuckAssistBot. Set either class to “Allow” or “Block”. When you set this class to “Block”, the screen warns you: “Blocking AI-search crawlers removes your site from ChatGPT/Perplexity answers.”

Use “Per-bot overrides” to override the class policy for individual crawlers. Resolution order is per-bot override first, then the class default; anything unset resolves to allow. Developers can extend the registry with the wpvis_ai_bots filter, and added bots inherit their class policy.

What the policy writes to robots.txt

Blocked bots are appended to the virtual robots.txt as one grouped block: a User-agent: line per blocked crawler over a single Disallow: /. If Settings → Reading discourages search engines, the site already serves a blanket disallow and the plugin appends nothing.

The “Content-Signals policy” field publishes an optional Content-Signal: line in robots.txt, for example search=yes, ai-input=no, ai-train=no. Confirm the output with the “View robots.txt” link in the section.

Serve an llms.txt file

Turn on “Serve an llms.txt file” to answer requests for /llms.txt with a markdown document in the llmstxt.org format. The endpoint is virtual: no rewrite rules, no file written to disk. It is off by default, and the setting’s help text states the honest caveat: no major AI crawler currently fetches llms.txt (verified June 2026), so treat it as low-cost preparation, not a ranking lever.

The document looks like this:


> Your site tagline

Your custom body, if you set one.

## Pages

- [Post title](https://example.com/post/): short description

The “## Pages” list holds up to 50 of your most recently updated published posts and pages. Noindexed and password-protected content is excluded, and each description line is trimmed to 120 characters.

Edit the llms.txt body

Once the toggle is on, an “llms.txt body” field appears in the “AI Visibility” section. It accepts owner-authored markdown and is inserted after the site name and tagline and before the auto-generated page list. Leave it empty to auto-generate only.

The plugin composes the H1 and tagline lines itself from your site title and tagline; the body field does not change them. For full control over the finished document, use the wpvis_llms_txt filter. Check the live output with the “View llms.txt” link.

Run the site audit

The audit engine performs read-only checks at the site and post level. Site checks cover search engine visibility, permalink structure, the site’s represented entity, the default social image, and the sitemaps module, plus counts of published posts, missing descriptions, noindexed posts, and redirects.

Per-post checks measure the SEO title against a 30 to 60 character band and the meta description against a 70 to 160 character band, then flag noindex, canonicals pointing to a different host, thin content under 150 words, a missing social image, and more than one H1 in the content.

Results appear where you request them. Run wp visibility audit or wp visibility post-audit <id> in WP-CLI, or call the REST endpoints GET /wp-json/wpvis/v1/audit/site and GET /wp-json/wpvis/v1/audit/post/{id}. When the Assistant connection module is on, your assistant reaches the same engine through the audit-site, audit-post, and get-site-seo-health abilities. With Autopilot’s “Weekly audit” enabled, the plugin finds posts missing a meta description once a week and queues a fix proposal for each; nothing publishes automatically.

Connect Your AI Assistant

WP Visibility includes its own MCP endpoint, so any MCP-capable assistant (Claude Code, Claude Desktop, Cursor, and others) can read and manage your site’s SEO. There is nothing extra to install: no adapter plugin, no bridge service, no cloud account. The endpoint is part of the plugin and uses standard WordPress authentication.

Turn on the Assistant connection module

The agent surface is off by default. Go to WP Visibility → Settings, open the “Modules” section, and enable the “Assistant connection” toggle. Enable “Autopilot” as well so assistant writes are held for your review: that is the recommended setup, and holding for review is the default behavior once Autopilot is on.

The built-in MCP endpoint

The endpoint lives at:

https://your-site.com/wp-json/wp-visibility/mcp

It accepts POST requests carrying JSON-RPC 2.0 messages, the stateless form of the MCP Streamable HTTP transport. Any MCP client that supports HTTP servers can talk to it. Authentication is a WordPress application password sent as HTTP Basic auth, so your site must be served over HTTPS.

Create an application password

In wp-admin, go to Users → Profile and scroll to the “Application Passwords” section. Enter a name, click “Add New Application Password”, and copy the generated password. It is shown once.

Name the password after the assistant, for example “Claude Code” or “Claude Desktop”. The plugin’s activity log records that label as the client on every call, so a well-named password tells you later which assistant did what. To cut off an assistant, return to the same screen and revoke its password. Access ends immediately and no other credentials are affected.

Configure your client

Every MCP client needs the same three values: the endpoint URL, your WordPress username, and the application password. The username and password travel together as a Basic auth header.

For Claude Code, encode the credentials and add the server:

AUTH=$(printf '%s' 'yourusername:xxxx xxxx xxxx xxxx xxxx xxxx' | base64)
claude mcp add --transport http wp-visibility \
  "https://your-site.com/wp-json/wp-visibility/mcp" \
  --header "Authorization: Basic $AUTH"

For other assistants the path is the same in words. Open the client’s MCP server configuration, add an HTTP server pointing at the endpoint URL, and set an Authorization header whose value is Basic followed by the base64 encoding of username:application-password. No OAuth flow, no session token, no streaming setup.

What the assistant can do

The endpoint exposes about 30 abilities: 18 read-only and 12 that write. Reads cover post and site audits, settings, redirects, sitemap status, llms.txt, AI crawler policy, the AI traffic report, the internal link graph, and the agent activity log. Writes cover post SEO fields, bulk updates, redirects, settings, llms.txt, crawler policy, and imports. Two playbooks are served as MCP prompts rather than tools.

One write ability, “Approve an Autopilot proposal”, ships disabled so an agent cannot approve its own changes. Every call runs the same capability checks as the settings screen and is recorded in the activity log with the client name, target, and outcome.

Writes go through your review queue

The review queue lives in the Autopilot module, so turn Autopilot on when you turn the connection on: the “Assistant changes” setting only exists, and only holds anything back, while that module is enabled. With it on, “Hold for my review” is the default, and the assistant’s SEO writes (post fields, bulk edits, settings, redirects, llms.txt, and crawler policy) produce a proposal instead of a direct change. Two writes stay outside the queue by design: pausing the agent takes effect at once, because a stop you have to approve is not a stop, and a full import from another SEO plugin is a migration you run deliberately from WP Visibility → Settings → Import, where it previews every change first. Nothing on your site changes until you approve the proposal under WP Visibility → Review queue, where each one shows a field-level before and after diff. Write abilities also accept an optional reason, shown on the proposal card as the agent’s rationale, so encourage your assistant to explain each change it requests.

The assistant sees a queued proposal as a success, not an error, so it moves on instead of retrying. Choose “Apply immediately” only when you trust the connected assistant to write without review; the setting warns you when you pick it. Questions about a specific client’s setup: support@wpvisibility.com.

The Review Queue and Guardrails

Autopilot puts a human checkpoint between an AI agent and your live site. Agent writes become proposals, each with a before and after diff, and nothing applies until you approve it.

Where the queue lives

Turn on the “Autopilot” toggle in the Modules section of the settings screen. A “Review queue” entry then appears in the admin menu under “WP Visibility”, next to “Settings”.

When proposals are waiting, the menu entry shows a count bubble, the pattern WordPress uses for pending comments. The bubble counts proposals that are pending or stale, exactly the set the queue’s default “Needs review” filter shows.

The queue page has two tabs. “Proposals” is the review surface described below. “Activity log” shows every action your assistant has taken, newest first, with a line confirming the log’s tamper-evident chain last verified cleanly.

A status bar sits above both tabs: whether assistant access is active or paused (with a one-click “Pause agent” button), the current guard mode, how much of the hourly write budget is used, and the assistant’s last activity.

Reading a proposal

Each proposal card names its target (for example post #42 plus the post title), the source that proposed it, its status, and an optional note explaining the change. Post targets include an “Edit post” link.

Below that sits a field level diff table with “Field”, “Before”, and “After” columns. The Before column always shows the target’s current live value, so what you approve is what changes. The exact words that differ are highlighted, struck through on the Before side and underlined on the After side. Long values, such as an llms.txt body, collapse behind a “Show more” toggle. When the assistant supplied a rationale for the change, it appears on the card as “Agent rationale”.

Approve, reject, and bulk actions

“Approve” applies the change through the same validated executors a direct write would use, and the confirmation toast carries an “Undo” for about ten seconds that reverts the change on the spot. “Reject” discards the proposal without writing anything, after a confirmation. An applied proposal gains a “Revert this change” button that restores the state captured at approval.

For batches, tick the checkbox on each card or use “Select all needing review”, then click “Approve selected” or “Reject selected”. Bulk actions run each proposal through the same server side checks as a single approval.

The queue also works from the keyboard: j and k move between proposals, a approves the focused one, r rejects it, and x ticks its checkbox. The keys are printed on the buttons, and shortcuts never fire while you are typing in a field.

Stale proposals

At proposal time the plugin stores a hash of the target’s current state and rechecks it on approval. If the content changed in the meantime, the proposal flips to “stale” and nothing is written.

A stale proposal shows a “Refresh diff” button, which re-baselines it against the current content and returns it to pending for a fresh review. In a bulk approval, stale rows are skipped and reported, never force applied. Resolved proposals, stale ones included, are pruned after 90 days.

Guard mode, the kill switch, and the write budget

The Autopilot section of the settings screen has a setting labeled “Assistant changes” with two values: “Apply immediately” and “Hold for my review”. It defaults to “Hold for my review”, so every assistant write ability (post SEO updates, bulk updates, settings, redirects, llms.txt, crawler policy) lands in the queue instead of writing. Choosing “Apply immediately” shows a warning, because it removes the review step. The separate “Weekly audit” toggle queues a fix proposal for each post missing a meta description; nothing publishes automatically.

When the Assistant connection module is on, its settings section adds two more guardrails. “Pause all agent access” is the kill switch, also available as the “Pause agent” button on the Review queue’s status bar: while paused, every assistant ability is refused until you resume from either place or run wp visibility agent resume. An assistant can trip the pause but never release it, and the proposal approval ability ships disabled so an assistant cannot approve its own work.

“Assistant write limit (per hour)” caps write actions per user and client per hour; the status bar shows how much of the budget the current hour has used. Requests over the budget receive a 429 error; 0 turns the limit off.

The activity log

Every agent ability execution is recorded in a hash chained log table (wpvis_agent_log). Each row commits to the hash of the previous row, so any edit or deletion inside the chain is detectable by verification. Rows record the time, user, client (the application password label), ability, target, a truncated input excerpt with license values redacted, outcome, and duration.

The log retains 90 days of entries, up to 10,000 rows. Read it on the Review queue’s “Activity log” tab, or through the get-agent-log ability, which also returns the chain status.

Troubleshooting

If the queue shows “The review queue could not be loaded.”, the browser could not reach your site’s REST API. Check that a security plugin or firewall is not blocking /wp-json/wpvis/v1/, then click “Try again”.

If proposals never appear, confirm “Assistant changes” is set to “Hold for my review” and the “Show” filter is on “Needs review”. Bulk dry runs are reads and never create proposals, and the menu bubble can lag by a minute.

For anything else, email support@wpvisibility.com with your WordPress and plugin versions.