You inherited a WordPress site with 600 images. Half are tagged alt="" because the contributor uploaded and never typed a description, a quarter open with filler like "image of a houseplant" or "photo of a watering can," and the rest were typed in a hurry and read like the filename with the dashes removed.
Now you want them to actually work. You want a real description on every image, short enough that a screen reader does not truncate it, free of the filler a screen reader already announces, and (on posts that hinge on a target keyword) carrying that keyword on at least one image.
Your options, as the site stands today, are all bad. Writing 600 alt texts by hand is a week of work. A WordPress AI alt text plugin will write something on save and ship it to the live post with no validator and no diff. You could paste each image into ChatGPT, but that is 600 conversations, all producing the same flat opener: "image of a houseplant."
Scratch, the desktop app, takes a different path. It pulls your posts as local files. Your AI writes a small validator for what makes alt text useful, generates alt text against it, runs the validator over its own output, and only stops when every post passes. You review each rewrite as a diff before anything touches the live site. And if a description goes live and reads wrong an hour later, reject the row and the original goes back.
The prompt
Paste this into Claude Code at your Scratch project root. The AI will read a sample of your posts, ask you about any rules you want to enforce beyond the obvious ones (focus keywords, voice notes), write a validator, edit one post for sign-off, and only then work through the rest.
The validator is the safety. The AI checks its own work against the same rules a screen reader and a search engine actually care about. The bad ones never reach your review.
You are writing alt text for the <img> tags inside a folder of
WordPress post JSON files. Each file is one post as the WordPress REST
API returns it; the editable body lives in content.raw. Scratch pulled
these from a live site. The edits land on disk; a human reviews each
one as a diff in Scratch before anything ships.
Edit only the alt attributes inside content.raw. Do not touch any
other field, do not edit the body prose, do not edit content.rendered
(WordPress regenerates that). Do not invent detail the surrounding
context does not support. A purely decorative image (a divider, a
spacer, an ornament the prose never refers to) gets alt="" so screen
readers skip it; do not write a description for it.
Before you start:
1. Read a handful of posts to understand the site. What kinds of
images, how figcaptions and surrounding prose describe them, what
filename conventions are used.
2. Ask me anything you cannot infer. Specifically: any focus-keyword
convention I use, any voice notes for the site, any rules I want
the validator to enforce beyond the obvious ones.
3. Write a validator at .scratch/validators/generate-alt-text.py that
exits 0 only when every image's alt is useful, descriptive, unique
within its post, and free of the common failures: missing, filler
openers, filename-as-alt, or empty on an image the surrounding
context treats as informative. An intentional decorative alt=""
passes. Add anything I asked for in step 2. On failure, exit 1
with one diagnostic per broken rule, prefixed with the post's
filename.
4. Edit alt attributes on one post. Show me. Only continue once I am
happy with the shape of the descriptions.
Then work through the rest. Edit alt attributes in place, re-run the
validator, fix what it flags, repeat until every post passes.
If an image is genuinely ambiguous (filename mislabeled, no caption,
no descriptive prose nearby), leave its alt alone.
When you finish, print: count of posts edited, count skipped, then
one line per skipped image with the filename and a one-line reason,
ending with "READY · review diff in Scratch". The edits on disk are
the deliverable. Do not dump rewrites to chat.
What the rewrite actually looks like
This is the loop Scratch runs for every task. Here is what each step looks like for alt text.
1. Pull
Scratch pulls your WordPress posts into a local folder, one .json per post, in the shape the WordPress REST API returns: the editable body in content.raw, a read-only copy in content.rendered, plus title, meta, status, and the rest. Six hundred posts land as six hundred files. Nothing on the live site has changed.
2. AI edits
Open Claude Code at your Scratch project root and paste the prompt above. The AI reads a sample of the posts, asks about focus-keyword conventions and any site-specific rules, writes a validator at .scratch/validators/generate-alt-text.py, edits one post for sign-off, then works through the rest. The validator runs after every save; what fails gets rewritten until it passes. Scratch keeps the original alongside the rewrite so it can diff them later. You did not give the AI an API token. It cannot touch the live site even if it wanted to.
3. Review
Open the Scratch desktop app. Every post with changed alt text shows up as a row in the review table, the old alt on the left, the new one on the right. Scan the diff. The validator already confirmed every alt is well-formed, unique, and free of filler. What you confirm is the one thing it cannot: does this description match the actual photo? The AI inferred from filename, caption, and surrounding prose. Only you can match the alt to what the image actually shows. Rows where the AI got it right get one-click approve. Rows where the alt drifted get one-click reject or a quick fix in place.
4. Ship
When you have approved the rows you want live, hit publish in Scratch. Scratch writes the approved alt text back through the WordPress REST API, one post at a time, with a log of which posts went out. Rejected and unedited rows stay where they were. And rollback still works after publish: if an alt reads wrong on the live site an hour later, reject the row in Scratch and the original alt goes back. No bulk plugin. No 600-window ChatGPT marathon. No "publish all and pray."
Why not just use an AI alt text plugin
Most teams reach for a plugin. Here is the cost.
The plugin path produces alt text but does not check it. No validator, no rule layer, no per-post diff. The plugin ships filler ("a photo of a houseplant") to your live site with the same authority it ships a real description. And once it is published, the only "rollback" is editing each post by hand. The Scratch path inverts every one of those properties. Your posts exist as 600 small files. Your validator runs before you look. You approve per image. You roll back per image.
When not to use this skill
- Your AI can't touch local files. Scratch is a desktop app; it works on a folder of posts on your machine. A web-only chat with no file system access can't drive the loop. The /with/ pages cover the AIs that can.
- Your images live outside
content.raw. This skill edits<img>alt attributes inside the WordPress RESTcontent.rawfield. Page-builder posts that store images in serialized block data or shortcode payloads (Elementor, Divi, ACF flexible content) need a different mapping. Pull a sample first and confirm where the alt text actually lives. - Posts without surrounding context. The AI infers descriptions from filename, caption, and surrounding prose. If your posts are bare images with no captions and no descriptive text nearby, the AI will correctly skip most of them and the skip list at the end of the run will be longer than the edits. Add captions first or plan to do this by hand.
The shape is simple: the AI does the describing and the checking, you do the matching against the real image. Six hundred images get the same polish, and not one ships without you seeing it.
Related
- Scratch for WordPress covers every other field Scratch can edit on a WordPress site.
- Bulk-rewrite Shopify product descriptions is the same loop applied to product copy.
- Make the agent define done before it starts pairs well with this prompt on long sessions.