Why I Built a WordPress Alt Text Generator Without AI
Opening a WordPress media library and finding hundreds of images without alt text used to drive me crazy.
It was not just a matter of organization. Missing alt attributes weaken on-page SEO, create accessibility problems, and usually reveal that image optimization was never treated as part of the publishing workflow.
Fixing ten images manually is easy.
Fixing hundreds or thousands of them across multiple WordPress websites is a completely different situation.
I also got tired of testing plugins that looked almost identical. Many of them depended on external APIs, required paid credits, added unnecessary complexity, or tried to solve a simple problem with a much larger system.
So I built my own solution.
The result is Webby Simple Alt Builder, a WordPress plugin that generates structured alt text using information that already exists inside WordPress.
No AI.
No external API.
No remote image processing.
Just predictable rules and local data.
The Problem I Wanted to Solve
Anyone who manages WordPress websites has probably seen at least one of these situations:
- hundreds of images with empty alt attributes;
- old media libraries that were never reviewed;
- filenames such as
IMG_4837.jpg; - inconsistent descriptions across similar images;
- plugins that require third-party services;
- tools that overwrite existing manual work;
- large libraries that cannot be processed safely in one request.
For me, the most frustrating part was seeing a technically solid page weakened by something so basic.
The content could be well written. The page title could be optimized. The heading structure could be correct. The internal links could be carefully planned.
Then I would inspect the images and find empty alt attributes everywhere.
It is a small field in the WordPress media library, but it has an important role in accessibility, content context, and on-page SEO.
I wanted a practical way to improve that workflow without pretending that every image needed advanced computer vision.
Why I Did Not Use Artificial Intelligence
Using AI seemed like the obvious option.
An image could be sent to a model, analyzed, and returned with a detailed description.
That can be useful, especially when the goal is to understand the actual visual content of an image. However, it would also introduce several new dependencies:
- API credentials;
- request costs;
- usage limits;
- external service availability;
- privacy concerns;
- unpredictable output;
- additional error handling;
- remote processing of website data.
For this plugin, I did not need creative descriptions.
I needed consistency.
Most of the websites I manage already contain useful context. WordPress knows the image filename, attachment title, post title, category, and the page where an image is being used.
That information is often enough to generate a cleaner and more useful alt text than an empty attribute or a raw filename.
A rules-based system also gives me something I value a lot: control.
I can understand why a result was generated. I can reproduce it. I can adjust the rules. I do not have to wonder why an external model produced a completely different answer for the same type of image.
What the Plugin Uses
Instead of visually analyzing an image, the plugin can build alt text using information already available in WordPress, including:
- the image filename;
- the attachment title;
- the post title;
- the post category;
- an optional keyword;
- the selected content context.
The goal is not to create perfect descriptions for every possible image.
The goal is to create a reliable baseline for real WordPress workflows.
That distinction shaped the entire project.
What the Plugin Does
The current version can generate alt text automatically when an image is uploaded.
It can also process older media libraries in configurable batches and provide manual suggestions for both alt text and attachment titles.
Its main features include:
- automatic generation during upload;
- frontend fallback when saved alt text is empty;
- batch processing for existing media libraries;
- manual ALT and title suggestions;
- automatic, product, service, and generic context modes;
- decorative image detection;
- maximum word controls;
- maximum character controls;
- ignored words;
- optional post title usage;
- optional category usage;
- optional custom keywords;
- media library statistics.
One rule has remained unchanged since the first version:
Existing alt text is never overwritten.
Why Preserving Existing Alt Text Matters
This was one of the easiest decisions in the project.
If an editor, developer, SEO professional, or content writer has already created an alt description manually, the plugin should not assume it can do a better job.
Manual alt text may contain important context that cannot be extracted from a filename or post title.
It may describe the function of an image instead of its appearance.
It may also have been written specifically for accessibility.
Because of that, the plugin only fills gaps.
It does not replace intentional human work.
I have seen automation tools overwrite carefully written metadata simply because the tool considered its own output more consistent. I did not want that behavior anywhere near this plugin.
Keeping the Main Plugin File Small
I wanted the main plugin file to remain simple.
It defines the plugin metadata, creates shared constants, loads the required classes, and starts the plugin.
It does not contain the complete generation logic, admin interface, attachment handling, and settings code in one large file.
The first small but important protection is this:
if (!defined('ABSPATH')) {
exit;
}
WordPress defines ABSPATH during a normal application load.
If someone attempts to execute the plugin file directly, the script stops immediately.
This is a common WordPress security practice, but it is still worth including and understanding. Small plugins do not get a free pass on basic security.
Separating Responsibilities
The plugin loads different classes for different parts of the application:
require_once WEBBY_SAC_DIR . 'includes/class-webby-smart-alt-settings.php';
require_once WEBBY_SAC_DIR . 'includes/class-webby-smart-alt-generator.php';
require_once WEBBY_SAC_DIR . 'includes/class-webby-smart-alt-attachments.php';
require_once WEBBY_SAC_DIR . 'includes/class-webby-smart-alt-admin.php';
require_once WEBBY_SAC_DIR . 'includes/class-webby-smart-alt-plugin.php';
Webby_Smart_ALT_Plugin::instance();
Each class has a clearer responsibility:
-
settingsmanages plugin options; -
generatorcontains the alt text generation rules; -
attachmentshandles media and attachment behavior; -
adminmanages the WordPress dashboard interface; -
plugincoordinates the initialization process.
The final line starts the main plugin instance.
This structure makes the code easier to navigate and maintain.
I have worked with WordPress plugins where the main file slowly became a collection of unrelated functions, hooks, HTML, SQL, and business rules. It usually starts small, then becomes difficult to understand after a few updates.
I wanted to avoid that from the beginning.
Why I Used Constants
The main file also defines values that are reused throughout the plugin:
define('WEBBY_SAC_VERSION', '1.7.5');
define('WEBBY_SAC_FILE', __FILE__);
define('WEBBY_SAC_DIR', plugin_dir_path(__FILE__));
define('WEBBY_SAC_URL', plugin_dir_url(__FILE__));
define('WEBBY_SAC_OPTION', 'webby_sac_settings');
This keeps file paths, version information, option names, and identifiers in one predictable place.
It also prevents the same strings from being repeated across multiple classes.
This may look like a minor detail, but small structural decisions become increasingly valuable as a plugin grows.
The Challenge of Large Media Libraries
Generating alt text for a few images is easy.
Processing thousands of attachments in a single request is not.
Large operations can cause:
- PHP timeouts;
- high memory usage;
- frozen admin screens;
- incomplete processing;
- server load spikes;
- inconsistent results after a failed request.
This was especially important to me because the plugin was created for practical use, not just as a coding exercise.
Some WordPress websites have been active for years. Their media libraries may contain thousands of files uploaded by different people using different naming conventions.
Trying to process everything at once would be careless.
That is why older images are handled in configurable batches.
Smaller groups reduce the risk of resource exhaustion and make the plugin more compatible with different hosting environments.
It is not the most exciting feature to describe, but it is one of the features that makes the plugin usable outside a development environment.
Frontend Fallback for Empty Alt Text
The plugin can also provide a frontend fallback when an image does not have saved alt text.
This means a value can be generated during rendering without immediately updating the attachment metadata in the database.
That can be useful for older websites where changing the entire media library at once is not desirable.
It also provides a gradual way to improve output while reviewing existing content.
However, this fallback has limits.
A rules-based plugin cannot fully understand what an image visually contains. It works with the context WordPress provides.
When an image contains important visual information, a manually written description is still the better option.
I do not think automation should hide its own limitations.
Decorative Images Need Different Treatment
One of the mistakes I often see is the assumption that every image must have descriptive alt text.
That is not true.
Purely decorative images should often use an empty alt attribute so assistive technologies can ignore them.
A background shape, visual divider, decorative icon, or layout element may add no useful information to the page content.
Forcing a generated phrase into every decorative image can make accessibility worse, not better.
Because of this, the plugin includes decorative image detection.
The purpose of automation is not to fill every field at any cost.
The purpose is to make better decisions consistently.
Why Simple Rules Can Be Better
While building the plugin, I kept returning to the same question:
Does this problem really need more complexity?
For many websites, the answer was no.
Rules-based generation offers several advantages:
- the output is reproducible;
- the logic can be explained;
- unwanted words can be removed;
- character limits can be enforced;
- context can be selected;
- no external service is required;
- the same input produces a consistent result.
That predictability is useful for testing and maintenance.
It also makes troubleshooting much easier.
When a generated result is not good, I can inspect the input and the rule that produced it. I am not trying to reverse engineer the reasoning of an external model.
What I Learned While Building It
The biggest lesson was that not every modern feature needs to begin with AI.
Artificial intelligence is useful when the problem genuinely requires interpretation.
It makes sense when the application needs to identify objects, understand visual relationships, or describe details that do not exist anywhere in the website data.
But many WordPress problems are workflow problems.
They require better defaults, safer automation, and clearer rules.
Building this plugin also forced me to think about questions that are easy to ignore:
- When should automation act?
- When should it do nothing?
- Which content should be preserved?
- How should large libraries be processed?
- What happens when the available context is poor?
- How can the plugin remain understandable to non-technical users?
- Which features are genuinely useful, and which ones only make the settings screen longer?
The actual string generation was not the hardest part.
The hardest part was deciding where the plugin should stop.
What I Want to Improve Next
I still have several ideas for future versions:
- WP-CLI support;
- additional composition rules;
- more context options;
- improved batch processing;
- more detailed reporting;
- better manual review tools.
I am interested in adding features, but I do not want the plugin to become one of the bloated tools that originally frustrated me.
Its main principle should remain the same:
Use local WordPress data to create predictable alt text without unnecessary dependencies.
Where to Find the Plugin
Webby Simple Alt Builder is available for free in the official WordPress plugin directory.
Webby Simple Alt Builder on WordPress.org
I also maintain a project page with additional information and documentation on the Webby website:
Webby Simple Alt Builder documentation
Final Thoughts
I built Webby Simple Alt Builder because I was tired of finding the same problem across WordPress websites.
Hundreds of empty alt attributes.
Unoptimized media libraries.
Plugins that added external dependencies to solve something that could often be handled with existing data.
The plugin does not pretend to understand every image.
It does not replace a thoughtful human description.
It does not send files to an external service and hope for a good response.
It uses the context WordPress already has, follows predictable rules, and preserves existing work.
For this particular problem, that was exactly the solution I wanted.
Sometimes the best improvement is not adding more intelligence.
Sometimes it is removing unnecessary complexity.