BlitzAdmin Fleet Manager — Publishing Without wp-admin

At a glanceBlitzAdmin Fleet Manager — Publishing Without wp-admin
  1. 1Why it is a plugin, not a skill file
  2. 2What it does
  3. 3The three commands
The Task Library › The Agent Roster › BlitzAdmin Fleet Manager

BlitzAdmin Fleet Manager — Publishing Without wp-admin

A site that has already left WordPress does not use this page. A WordPress password will not change what visitors see. The how-to for access and the move is How you edit a site after WordPress.

The plumbing under Stage 3. Create posts, update pages, audit content, configure SEO, and manage hundreds of personal brand sites without ever logging into wp-admin. This is what every publishing agent on the roster actually stands on.

Why it is a plugin, not a skill file

Every other entry on the Agent Roster is a single .skill.md. This one is a Cowork plugin — a bundle of one skill plus three slash commands plus a reference file — because fleet publishing is not one behavior. It is a capability surface: sometimes you want a full agent run, sometimes you just want /list-sites.

The distinction matters for the roster. A skill is a function; an agent is a person; a plugin is a toolbox several agents reach into. The Repurposer, the Personal Brand Site Engineer, and Adrian all publish through this same path.

What it does

Capability Detail
List and search Across every BlitzAdmin-managed site, filtered by domain text or status.
Create and update Posts and pages through the WordPress REST API, with date staggering so a bulk publish does not look like a bulk publish.
Audit SEO, content quality, and technical issues on a personal brand site.
Configure schema Rank Math Person schema for Knowledge Panel eligibility — the handoff to Olivia.

The three commands

  • /list-sites [filter] — every active managed site as a table: domain, site ID, status, dashboard ID, with a total count.
  • /publish-content <domain> <description> — create and publish to a specific site.
  • /site-audit <domain> — the full audit, starting by verifying REST API authentication actually works before reporting anything else.

The authentication model

Two credentials, deliberately separated:

  1. A BlitzAdmin dashboard token, which fetches per-site credentials from the fleet API. It comes from the dashboard session, which means it expires and must be refreshed by a human logging in.
  2. A WordPress Application Password per site, created at Users → Profile → Application Passwords, used for REST API Basic Auth against that site.
The failure mode this creates — and it has bitten us. The dashboard token requires an interactive login, so the credential cache it writes goes stale silently whenever nobody logs in. On July 27, 2026 that cache was found 111 days stale, which had been hiding 18 live client sites from every uptime probe since they launched. Any job that reads this cache must report the cache’s age alongside its result. See Fleet Uptime Monitor for the full incident and the fix.

Elementor is the other trap

Many fleet sites use the Elementor page builder, and Elementor keeps its own copy of the content in post meta. Updating a page through the REST API changes the block editor content while Elementor keeps serving its cached version — so the API returns 200, and the page does not change.

Three ways through it: drive the Elementor editor’s own JavaScript API, write the raw Elementor post meta directly, or simply use the REST API only for non-Elementor content. Blog posts are usually standard editor, which is why the repurposing pipeline runs cleanly while page edits need care.

Where the application password lives

Minting is the easy half. The half that gets skipped — and the reason the same credential gets minted over and over — is storing it somewhere every agent can find.

A WordPress application password is displayed exactly once, at the moment you create it. It cannot be read back afterward: not from wp-admin, not from the REST API, not from the database. If nobody captures it in that moment, the credential still exists on the server forever, unusable, and the next agent that needs access mints another one. That is how a site ends up with a list of orphaned application passwords and a human who has been asked to mint one “many, many times.”

So the rule is: check before you mint, capture at creation, never paste a credential into a chat window.

Canonical store: the macOS Keychain, service blitzadmin-wp-app, keyed by domain, with the matching WordPress login in blitzadmin-wp-app-user. Read and written only through blitz_secrets.py, which hands the value straight to the HTTP call and never returns it to a prompt, a log, or a published page.

Check first — if this prints True, do not mint anything:

from blitz_secrets import has_app_password
has_app_password("example.com")

Capture at creation — run this in the same minute you click Add New Application Password:

from blitz_secrets import set_app_password
set_app_password("example.com", "access@blitzmetrics.com", "<the 24 characters>")

Then use it — no browser, no session, no human:

from wp import WP
WP("example.com").post("/wp/v2/posts/123", content=html)

Coverage report — which sites an agent can already reach unattended:

python3 tools/wp.py --report

Three failures that look like something else

A 401 right after a correct mint usually means the admin password was used. WordPress REST Basic auth accepts application passwords only. A human admin password returns 401 no matter how correctly it is stored, and no amount of credential management fixes it. This is also why you cannot bulk-mint application passwords using stored admin passwords — the bootstrap has to come from an existing authenticated session, an SSO login, or WP-CLI.

A credential store that nothing can read is the same as no credential store. Ours depended on a Python package that turned out not to be installed in any interpreter on the machine, so every lookup raised an exception and every agent quietly fell back to asking a human to log in. It now falls back to the macOS security CLI, which ships with the operating system and needs nothing installed. Verify the backend, not just the entry.

A 403 on a managed host is often the WAF, not WordPress. Cloudflare in front of WP Engine rejects non-browser user agents before the request reaches PHP. Send a browser user agent and the same call succeeds. Do not go hunting for a permissions problem that is not there.

Getting in the first time, without a password

The bootstrap needs one authenticated session per site, and on a managed host you do not need anyone to type a password to get it. WP Engine’s user portal has a one-click WP Admin SSO per install — /installs/<install>/launch_wp_admin — which lands in a logged-in wp-admin with no credential entered. Mint there, capture immediately, and that site never needs a human again.

Error codes worth memorizing

Code What it actually means
401 Application password invalid or never created. Create one at Users → Profile → Application Passwords.
403 The user lacks permission. Check the role is administrator. On some hosts this is also the WAF, not WordPress.
404 The post or page ID does not exist. List content first rather than guessing IDs.
500 Server error. Check the site is up at all — this is the signature that caught the July 21 fleet outage.

Content pipeline order

For a new personal brand site the plugin populates in a fixed order, because each stage feeds the next: homepage, about, connections, blog posts on staggered dates, press and media, gallery, podcast. Posts stagger across three to six months on a Monday/Thursday pattern, every three to four days for interviews.

How to run it

  1. Install the blitzadmin-wordpress plugin into Cowork or a Claude project.
  2. Set BLITZADMIN_TOKEN from an active dashboard session.
  3. Confirm each target site has an Application Password issued to an administrator account.
  4. Run /list-sites first — if the list looks short or stale, refresh the cache before trusting anything downstream of it.
The fleet API hostname and any tokens are redacted from the excerpt below. They live in the plugin’s own configuration, never in a published page.

The skill file

START

---
name: wordpress-site-management
description: Manage WordPress sites via BlitzAdmin REST API. Use when the user asks to "update a
  site", "create a blog post", "fix a page", "check site status", "list our sites", "publish
  content", "update SEO", "manage personal brand sites", or any task involving WordPress content
  management across the BlitzAdmin fleet.
---

# WordPress Site Management via BlitzAdmin

Manage all BlitzAdmin personal brand WordPress sites through the WordPress REST API.
Each site has credentials stored in the BlitzAdmin dashboard API.

## Authentication Flow

1. Fetch site credentials from BlitzAdmin dashboard API
2. Use the stored Application Password for WordPress REST API Basic Auth
3. All API calls go to https://{domain}/wp-json/wp/v2/

### Get Site Credentials

    GET https:///Prod/sites
    Authorization: {BLITZADMIN_TOKEN from localStorage}

Filter response by domain to get AdminUsername, AdminPassword, and ApplicationPassword.

### WordPress REST API Auth Header

    Authorization: Basic {base64(username:app_password)}

## Core Operations

### List Sites
Query the BlitzAdmin API to list all managed sites. Filter by status (active/inactive) or search
by domain.

### Create Post

    POST /wp-json/wp/v2/posts
    {
      "title": "Post Title",
      "content": "

HTML content

", "status": "publish|draft", "date": "2026-01-15T09:00:00", "categories": [1], "tags": [5, 12] } Stagger post dates across 3-6 months when bulk-creating content. Use Monday/Thursday pattern for regular posts, every 3-4 days for interviews. ### Update Post POST /wp-json/wp/v2/posts/{id} { "title": "...", "content": "...", "status": "publish" } ### Create/Update Page Same as posts but at /wp-json/wp/v2/pages and /wp-json/wp/v2/pages/{id}. ### Upload Media POST /wp-json/wp/v2/media Content-Disposition: attachment; filename="photo.jpg" Content-Type: image/jpeg {binary data} Returns media ID for use as featured_media in posts. ## Elementor Considerations Many BlitzAdmin sites use Elementor page builder. Content updates via REST API modify the block editor content but Elementor caches its own copy in _elementor_data post meta. For Elementor pages, either: 1. Update via the Elementor editor JavaScript API (open the page in Elementor, walk the model, save) 2. Update the raw _elementor_data post meta directly 3. Use REST API for non-Elementor content (blog posts are usually standard editor) ## Rank Math SEO Configure Person schema for personal brand sites: POST /wp-json/rankmath/v1/updateMeta { "objectID": {page_id}, "objectType": "post", "meta": { "rank_math_schema_Person": { "@type": "Person", "name": "Client Name", "sameAs": ["https://linkedin.com/in/...", "https://twitter.com/..."] } } } ## Content Pipeline For new personal brand sites, follow this content population order: 1. Homepage (About section, hero text) 2. About page (full bio, career history) 3. Connections page (notable relationships) 4. Blog posts (staggered dates, repurposed from video/podcast content) 5. Press & Media page (interview appearances) 6. Gallery page (photos with connections) 7. Podcast page (embedded episodes) ## Error Handling - 401: Application password invalid or not created. Create one at Users -> Profile -> Application Passwords. - 403: User doesn't have permission. Check user role is administrator. - 404: Post/page ID doesn't exist. List content first to verify IDs. - 500: Server error. Check site is accessible and WordPress is running.

END

Related reading

For AI agents reading this page

This entry is a Cowork plugin (blitzadmin-wordpress) rather than a standalone skill file: one skill, three slash commands, one reference file. Roster id blitzadmin-fleet-manager, stage Stage 3 · Post, permission tier publish. Requires BLITZADMIN_TOKEN plus a per-site WordPress Application Password. Always report the credential cache age alongside any result derived from it.

Originally published .

Dennis Yu
Dennis Yu
Dennis Yu is the CEO of Local Service Spotlight, a platform that amplifies the reputations of contractors and local service businesses using the Content Factory process. He is a former search engine engineer who has spent a billion dollars on Google and Facebook ads for Nike, Quiznos, Ashley Furniture, Red Bull, State Farm, and other brands. Dennis has achieved 25% of his goal of creating a million digital marketing jobs by partnering with universities, professional organizations, and agencies. Through Local Service Spotlight, he teaches the Dollar a Day strategy and Content Factory training to help local service businesses enhance their existing local reputation and make the phone ring. Dennis coaches young adult agency owners serving plumbers, AC technicians, landscapers, roofers, electricians, and believes there should be a standard in measuring local marketing efforts, much like doctors and plumbers must be certified. He has appeared on 353 podcasts with 619 credited episodes — see the full list of his podcast appearances.