WordPress Image SEO: Alt Text, Filenames and File Size
WordPress image SEO is three separate jobs, not one: alt text, filenames and byte weight. Here is which to fix before upload, and which decides your LCP.
Sort the media library of any site that has been publishing for three years. You will find unnamed.png, 2c4f9a1b.jpg, image-3-1.jpg, and a hero on your best page weighing 2.4 MB. Nobody chose those names. Nobody typed that alt text, because there is none. The uploads folder is 11 GB and the last backup took forty minutes.
That is what most WordPress image SEO problems look like, and the cause is rarely carelessness at the upload button. It is that the files never came through it at all.
We build and sell the two WordPress plugins named below, so weigh the article accordingly. Everything about alt text, filenames and byte weight applies whatever tooling put the files there.
Where WordPress image SEO debt starts: the automated routes
A file a human dragged into the editor usually gets a decent name, because the human named it on their desktop first. A file that arrived any other way did not.
Three common other ways. A migration or bulk import, where filenames are whatever the old system generated. A scraper: our WordPress Image Scraper takes a URL, fetches every .jpg and .png on that page and stores each locally in the media library - what you want when pulling your own assets off an old site, and a whole page of machine-named files in one pass. And an in-editor picker: our AI Images for WordPress searches a 9-million-prompt database built on Lexica.art and Stable Diffusion, downloading the chosen image into your own media library rather than hot-linking it - the right architecture, and still a file whose name and alt text nobody decided.
Local hosting is correct and hot-linking is the failure mode. But an importer can only fetch bytes; it cannot know what the image contributes to your page. That leaves three jobs on your desk.
| Job | Serves | Cost before upload | Cost after |
|---|---|---|---|
| Filename | Crawlers, humans reading URLs | Rename the file. Seconds. | Rewrite post content, regenerate sizes, redirect the old URL |
| Alt text | Screen reader users, then image search | Not possible - it is per-usage | Edit the attachment or block. Cheap, but nobody does it |
| Byte weight | Every visitor, and your LCP score | Resize and convert once | Bulk conversion across the library |
The filename row is the one people get backwards. Cheapest to get right, most expensive to fix later.
Alt text is an accessibility job that happens to be a ranking signal
Write alt text for the person using a screen reader. The search benefit follows from doing that well; it does not survive doing it for the crawler.
The mechanics matter. WordPress stores a default alt string on the attachment, in the _wp_attachment_image_alt post meta field. The Gutenberg image block stores its own value and overrides that default. So the same photograph on two pages can and often should carry two different descriptions, because alt text describes what the image contributes to this page, not what is in the frame.
- A missing
altis worse than an empty one. With no attribute, assistive technology commonly falls back to announcing the filename, so your reader hearsDSC-0043-1024x683-jpg. An explicitalt=""tells it to skip the image, which is correct for decoration. - Most images are decorative, so empty most of them. A gradient divider, a mood-setting header, an icon beside a label already saying the same word. This is what people most often get wrong while trying to be thorough.
- Transcribe text inside the image. A pricing table shipped as a PNG is invisible to everyone who cannot see it, and to every crawler. The alt text is the only copy that exists.
- One sentence is the ceiling, roughly 125 characters. If it needs a paragraph, it needs a caption. And do not open with “image of” - the screen reader already said it is a graphic.
The neighbouring fields get misused. title does close to nothing and is not announced reliably. The attachment description only surfaces on the attachment page, which most sites should not index. The caption is visible to everyone and read by skimmers - a better home for context than alt will ever be.
Rename image files before upload, because after is expensive
When WordPress accepts an upload it sanitises the name once, then bakes it into the attachment’s guid and post meta, every generated size on disk (name-1024x683.jpg), the srcset of every block that renders it, and the literal URL saved into post_content for every post using it. Your CDN caches it. Google indexes it.
Renaming afterwards means rewriting all of that and redirecting the old URL, or accepting a broken image you have not found. Almost nobody issues the redirect.
So: rename on the filesystem, then upload. For automated imports where you cannot, do not fix the whole library - fix the featured image and hero of your twenty highest-traffic pages.
Conventions worth standardising:
- Lowercase, ASCII only. Non-ASCII gets percent-encoded and behaves inconsistently across hosts, CDNs and archive tools.
- Hyphens between words, never underscores.
- Three or four descriptive words:
perfex-invoice-pdf-template.jpg. Not a keyword list, notbest-crm-software-2026-cheap-crm.jpg. - Nothing like
Screenshot 2026-02-11 at 14.03.22.png, which sanitises into hyphens or%20depending on your setup, neither of which you chose.
Be honest about the payoff: the filename is a weak signal alone. It is worth doing because it is free at the right moment.
Byte weight decides Largest Contentful Paint, and nothing else does
On a content page the LCP element is nearly always the hero image, and Largest Contentful Paint is the Core Web Vitals metric most likely to fail. The threshold is 2.5 seconds at the 75th percentile of real visits, not on your laptop.
LCP for an image has four parts: time to first byte, resource load delay, resource load time, render delay. Bytes only affect the third. The part people lose is the second, and they lose it in the markup.
- Never lazy-load the LCP image.
loading="lazy"defers discovery until layout runs, adding hundreds of milliseconds to the one image that must not be late. WordPress core tries to skip it on the first content image and addfetchpriority="high", but a hero rendered from a template part, a page builder, or a CSSbackground-imagedefeats that heuristic silently. Open DevTools, find the LCP element, read its attributes. - Lazy-load everything below it. Free, and WordPress does it by default.
- Stop uploading camera originals. Since WordPress 5.3, anything wider than
big_image_size_threshold(2560px by default) gets a-scaledcopy served in its place while the original stays on disk. So a 6 MB upload leaves a 6 MB file inuploadsforever - keeping its EXIF, GPS coordinates included, at a guessable URL. Strip metadata before upload if the photographs came off a phone. - Convert to WebP and set a budget. WebP typically lands 25 to 35 percent under JPEG at equivalent quality. Aim for a hero under 200 KB at 1600px wide. If a photograph cannot get there, it is the wrong photograph.
What a local media library can and cannot do without a CDN
Hosting files yourself, which both our plugins do, buys real capability. Know where it stops.
It can emit a proper srcset and sizes, because a real attachment records its generated sizes in _wp_attachment_metadata, so a phone pulls the 768px file, not the 1600px one. A hot-linked remote <img> with a bare src gets none of this - the strongest practical argument for downloading rather than embedding somebody else’s URL.
It cannot resize on demand. srcset picks from pre-generated sizes, so if your card grid renders at 400px and your registered sizes are 300 and 768, every visitor downloads the 768. Register a size matching your layout, or accept the overhead knowingly.
It cannot negotiate formats. WordPress has accepted WebP uploads since 5.8 and AVIF since 6.5, but will not transcode an existing JPEG library. That is a plugin or a build step.
It will ship a default sizes of roughly (max-width: 1024px) 100vw, 1024px, wrong for any layout with a sidebar, which makes browsers over-fetch. Filter wp_calculate_image_sizes if your content column is narrower than the viewport.
Regenerating thumbnails is how your uploads folder doubles
Change your theme and you change the registered image sizes. The new theme wants six of its own; the old theme’s six are already on disk. Multiply by 3,000 uploads: 18,000 files nothing will request again.
The mechanism explains why nothing cleans up after itself. WordPress deletes sized files by reading the list recorded in _wp_attachment_metadata when an attachment is deleted. A regeneration rewrites that record with only the currently registered sizes. The old files stay on disk but vanish from the record, so from that moment nothing in WordPress knows they exist. They survive every cleanup, go into every backup, slow every migration.
Before you regenerate: list the sizes both themes register, pick a tool that deletes unregistered sizes, back up the database because regeneration rewrites attachment metadata with no undo, then compare folder size before and after. If it grew, the cleanup did not run.
Do these six things, in this order
Not the whole library. Sort pages by organic traffic, take the top twenty, work down.
- Measure first. Confirm the LCP element is what you think. If it is a web font or a hero video, none of the above is your bottleneck.
- Fix the LCP image on those twenty pages: resize to the width it renders at, convert to WebP, get it under 200 KB, remove
loading="lazy", confirmfetchpriority="high". - Write alt text on the images that carry meaning and set
alt=""on the ones that do not. Expect more of the second than the first. - Rename only those twenty featured images, and only if you will redirect the old URL. Otherwise apply the convention from the next upload onward.
- Write the convention down where whoever imports images can see it: lowercase, hyphens, ASCII, three or four words, resized before upload.
- Schedule the bulk WebP conversion for the rest of the library as one job.
If you only ever do step two, you still recover most of the value. Everything else is maintenance; the hero image is the one costing you a passing Core Web Vitals score today.