AI Disclosure Labels
WordPress plugin: mark images as generated or modified by AI and show a disclosure label wherever they appear.
by Lukasz Warcholik · github.com/lukaszwarcholik/ai-disclosure-labels · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/lukaszwarcholik/ai-disclosure-labels/archive/refs/heads/main.zipA WordPress plugin. Mark an image as generated by AI, or as a real image modified using AI, and a disclosure label appears everywhere that image is shown.
Built because the EU AI Act (Article 50) has applied since 2 August 2026 and adding a caption by hand is something you forget on the fifth post.
What it does
The mark lives on the attachment, not on the post, so marking a file once covers every place it is reused.
- A Generated by AI / Modified using AI picker in the Media Library and in the media modal.
- An AI disclosure panel next to the featured image in the block editor, saved straight to the attachment over REST.
- An AI column in the media library list view.
- On the front end: a caption under large images, a compact badge on thumbnails — or a position and style you pick yourself.
- Settings for label text per kind, position (under the image or any of its four corners), style (plain, dark, white, translucent), size, opacity, and where to show it.
- Uninstall removes the settings and every mark.
Where the labels come from
Four entry points, all going through one scan with the same guards:
| Hook | Covers |
|---|---|
post_thumbnail_html |
featured images |
wp_get_attachment_image |
anything a theme renders with the standard function |
the_content |
content images, classic editor included |
render_block |
core image, gallery and media-and-text blocks |
Images a theme prints itself — <img src="<?php echo $field['url']; ?>"> straight out of an ACF field — pass through no filter at all. For those there is an optional pass over the finished page: the plugin already knows which attachments are marked, so it builds a file-name list for those few files only, caches it, and looks for exactly those names. No query per image, and matching on the file name survives a CDN or an offloaded upload path.
Or call it from the template yourself:
<?php aidl_label( $attachment_id ); ?>
[ai_disclosure id="123"]
Filters
apply_filters( 'aidl_label_text', $text, $attachment_id, $variant, $mode );
apply_filters( 'aidl_badge_text', $text, $attachment_id, $mode );
Layout
ai-disclosure-labels.php plugin header, constants, mode helpers
includes/media.php marking: meta, media fields, editor assets
includes/frontend.php labels on the front end
includes/catch-all.php optional pass over the finished page
includes/settings.php Settings -> AI Disclosure Labels
assets/editor.js block editor panel, no JSX and no build step
languages/ .pot, pl_PL .po/.mo and the JSON for wp.i18n
tools/build-lang.php regenerates everything in languages/
tools/tests.php label logic against WordPress stubs
uninstall.php removes settings and marks
No build step, no external requests, no database tables.
Development
php -l ai-disclosure-labels.php && for f in includes/*.php; do php -l "$f"; done
cd tools && php tests.php # 30 checks on the label logic
cd tools && php build-lang.php # after changing any translatable string
tools/tests.php stubs the handful of WordPress functions the label logic touches, so it runs anywhere PHP does. It covers the cases that actually broke something: a theme returning a whole <figure> for the featured image, a 150px thumbnail getting a full caption, <picture> from a WebP converter, a fragment coming back from a cache without the marker, and the two modes.
Releasing
.github/workflows/deploy.yml pushes a tag to the WordPress.org SVN repository. Set SVN_USERNAME and SVN_PASSWORD in the repository secrets, then:
git tag 1.2.0 && git push --tags
.distignore keeps tools/, tests and repository metadata out of the shipped plugin.
History
The first version was a prototype for one site (wd-oznaczenia-ai, first commit here). It was then rewritten for the plugin directory as ai-disclosure-labels, and went through 1.0.0, 1.0.1 and 1.1.0 in one evening before this repository existed — those were never released and their intermediate file states were not kept, so the second commit is 1.2.0. readme.txt carries the changelog.
AI assistance
This plugin was written with AI assistance, recorded in the commit trailers as Assisted-by. An assistant is not a contributor: the decisions, the review and the responsibility for the code are mine. Given that the plugin exists to make AI involvement visible, saying so here seemed like the least it could do.
License
GPL-2.0-or-later.