Documentation
Getting started with verklein.nu
Installing, setting up and automating. Start at Installing, or jump straight to what you need.
Installing
- The plugin is coming to WordPress.org soon. Then, in WordPress, go to Plugins → Add New Plugin and search for verklein.nu.
- Activate the plugin. You then find it as verklein.nu in the admin menu, right below Media.
- Open the System & help tab and check whether your server can create WebP and AVIF.
- Back up your database and the
wp-content/uploadsfolder before you convert the library for the first time.
Nothing changes after installing: nothing is converted until you start it or switch on converting uploads.
The admin: five tabs
| Existing images | A wizard in four steps: look at the library, choose, example, convert. You usually only use it once. |
|---|---|
| New uploads | The start screen: the switch to convert while uploading, the latest converted uploads, and the status of your library with a button to the wizard while there is still something to convert. |
| Settings | All settings in one place, for existing images and new uploads: format, quality, originals and scaling down uploads that are too large. Everything else is collapsed under More options. |
| Restore & clean up | Put originals back, update or repair URLs again, view skipped images and delete backups. |
| System & help | The system check, a test whether your server delivers WebP and AVIF correctly, and help with the nginx rules for your site. |
New uploads
Automatic conversion is on by default; the switch is on the New uploads tab. Every new JPG and PNG is converted while it is uploaded: WordPress writes the main file and every size straight in WebP or AVIF, without making JPGs first.
- Format and quality (under Settings): the same as for existing images by default, but uploads can have their own format or quality. AVIF makes each upload a few seconds slower; WebP is fast.
- Maximum dimensions (under Settings): photos from a camera or phone are often 4000 to 6000 pixels. Set a maximum width and height. Choose whether a larger upload is first made smaller or refused. Also works when automatic conversion is off.
- Maximum file size per image (under Settings): for example 1 MB. Larger images are refused with a message. The check happens after scaling down.
- Upload limit (under Settings): the maximum size for all files. The page shows what PHP on your server allows. A plugin can only set a lower limit; for a higher one, ask your host or change php.ini.
- Where it works: the Media Library, the block editor, the media modal of page builders, WooCommerce product imports, the REST API and
wp media import. GIF, SVG and PDF are left alone on upload.
When you switch it off, uploads stay JPG or PNG until you convert them: one by one with the Convert button in the Media Library, or together with the rest of the library.
Existing images
What is already in your library you convert in one run with the wizard on the Existing images tab. While there is still something to convert, New uploads also shows a button to the wizard at the top.
- Your library: how many images can get smaller, and whether your server can create WebP and AVIF.
- Choose: the format (WebP, AVIF or keep JPG/PNG), what happens to the originals and how much to compress. The recommended choices are already selected.
- Example: an image from your library in the three levels. Drag the line to compare with the original, or pick an image yourself to test with. Nothing is saved yet.
- Convert: confirm you have a backup and start. The task runs in small batches; keep the page open for the fastest result. If you close it, the task continues through WP-Cron.
When it is done you see what was saved. New uploads get the same treatment automatically. Caches are cleared; clear your CDN or Varnish cache yourself. To run it again later, for example with other settings, just use the same tab.
Settings
These settings apply to existing images and to new uploads. For most sites the four main choices are enough.
| Convert to | WebP (recommended), AVIF, or keep the format, only compress. |
|---|---|
| Compression level | Lossy (smallest), Glossy (for photography and shops), Lossless (no visible difference) or Custom, with your own quality per format. |
| Delivery | Replace (in place, URLs updated) or next to the original with fallback (copies and <picture>). The overview page compares them side by side. |
| Original files | To a backup folder (recommended), leave them in place or delete them. |
Collapsed under More options:
- PNG, JPG, GIF and PDF: PNG to lossless WebP, PNG to 256 colours or to JPG, progressive JPGs, GIF to WebP, compressing PDFs and the effort.
- Backups and URLs: smart backup, deleting backups automatically, updating URLs in every table, redirecting old URLs and checking every page for old URLs that were left behind.
- Which images are left alone: file types, names and folders, file size, upload period, post types and the site icon.
- Image sizes: per thumbnail size, do not compress or do not create, and the maximum size.
- Fallback mode:
<picture>elements, the whole page, the Accept header rule and front-end exclusions. - Advanced: metadata, only when smaller, caches, batch length, uninstall and e-mail reports.
Exporting and importing settings as a JSON file is at the bottom of the same page.
Requirements
| WordPress | 6.7 or newer (tested up to 7.1). From 6.7 on, WordPress converts the full-size file itself as well, so nothing is compressed twice. |
|---|---|
| PHP | 7.4 or newer. |
| Image library | Imagick (recommended) or GD with WebP support. AVIF needs an Imagick or GD build with AVIF support. The System check shows what your server can do. |
| Permissions | Administrators (manage_options). Can be changed with a filter. |
| Disk space | Room for the new files next to the old ones, and for the backups for as long as you keep them. |
| nginx | A few lines in your server configuration: see the questions below. Apache and LiteSpeed need nothing extra. |
| WP-CLI | Optional, but the fastest way for large libraries. |
nginx
nginx ignores the .htaccess file that closes the backup folder, so add a rule to the server configuration yourself. The second rule sends old JPG and PNG URLs to WordPress, for the 301 redirect. The exact folder name for your site is on the System & help tab, and the system check tests whether the folder is closed.
location ^~ /wp-content/uploads/verklein-backup-<name>/ {
deny all;
}
location ~* ^/wp-content/uploads/.+\.(jpe?g|png)$ {
try_files $uri /index.php?$args;
}
types { image/webp webp; image/avif avif; }
Apache and LiteSpeed need nothing extra.
WP-CLI
Everything in the dashboard also works from the terminal, without time limits. Options you leave out come from the settings. wp byt still works as an alias, for scripts written for the old mu-plugin.
wp verklein convert --to=webp --dry-run # see what would happen first
wp verklein convert --to=webp # convert, update URLs, clear caches
wp verklein convert --to=avif --quality=55 --effort=4
wp verklein convert --to=avif --mode=fallback # keep JPG/PNG, add AVIF and WebP copies, <picture>
wp verklein convert --to=webp --originals=keep # leave the originals in place
wp verklein convert --to=webp --ids=12,15 # only these attachments
wp verklein convert --to=webp --network # multisite: every site
wp --url=https://example.com/site-2 verklein convert --to=webp # one subsite
wp verklein restore --dry-run
wp verklein restore --ids=12,15
wp verklein rewrite --dry-run
wp verklein repair
wp verklein status
wp verklein cleanup --yes
wp verklein job run # finish a task started in the dashboard
wp verklein convert
Converts images to WebP or AVIF, including every size and (by default) the URLs in the database. Without --to, --ids or --network the command shows its help.
--to=<webp|avif> | Target format. |
|---|---|
--mode=<replace|fallback> | Replace (in place, URLs updated) or next to the original with fallback (copies and <picture>). Default from the settings. |
--no-webp-fallback | Fallback mode with --to=avif: only make AVIF copies, no extra WebP copies (which are made by default). |
--quality=<1-100> | Quality. Default from the settings (WebP 75, AVIF 60). |
--effort=<0-9> | Effort: 0 is fastest, 9 gives the smallest file. Default 5. |
--originals=<backup|keep|delete> | What happens to the originals: move to the backup folder, leave in place or delete. |
--no-rewrite-urls | Do not update the URLs in the database (by default it does). |
--no-all-tables-with-prefix | Only search the WordPress core tables, not the tables of plugins. |
--no-only-smaller | Convert even when the result is not smaller. |
--force-reencode | Also re-encode images that are already in the target format. |
--ids=<ids> | Only these attachment IDs, comma-separated. |
--retry | Also retry images that were skipped or failed before. |
--dry-run | Show what would happen without changing anything. |
--network | Multisite: run the command for every site. |
--yes | Skip the confirmation (for media in the cloud, or when URLs are not updated while the originals are moved). |
| Old flags | --no-keep-original (same as --originals=delete), --rewrite-urls, --all-tables-with-prefix, --rewrite-meta and --from-original are still accepted. |
wp verklein restore
Puts the original JPG and PNG files and their URLs back. Also works for images converted with the old mu-plugin. For images with copies (fallback mode) only the copies are deleted.
--ids=<ids> | Only these attachment IDs. |
|---|---|
--keep-converted | Leave the WebP and AVIF files on disk. |
--dry-run | Show what would be restored. |
--network | Multisite: for every site. |
Other commands
wp verklein rewrite [--all-tables-with-prefix] [--dry-run] | Updates the URLs in the database again for every converted file. Useful after importing content, or if you converted with --no-rewrite-urls. Also finishes a restore that was stopped. |
|---|---|
wp verklein repair [--dry-run] | Repairs URLs that point to a missing file. URLs of existing files are never changed. |
wp verklein status | The chosen mode, statistics (still to convert, converted, with copies, restorable, saved) and the full system check. |
wp verklein cleanup [--yes] | Deletes the backups of the originals. Restoring is no longer possible afterwards. |
wp verklein job <status|run|pause|cancel|clear> | Manages the task started in the dashboard. Use run to finish it in the terminal. |
wp verklein help [convert|restore] | Overview of every command and option. |
For developers
Use these filters and actions to change the behaviour from your theme or your own plugin.
verklein_capabilityfilter · string $capability | The capability needed for the admin page, the Media Library actions and the AJAX requests. Default manage_options. |
|---|---|
verklein_excluded_idsfilter · int[] $ids, array $options | Attachment IDs that are skipped when the library is converted. Already contains the site icon and the WooCommerce e-mail header. $options are the settings of the task. |
verklein_convert_uploadfilter · bool $convert, array $file | Return false to leave a new upload unconverted. $file is the WordPress upload array (name, type, tmp_name, size). |
verklein_resize_uploadfilter · bool $resize, array $file | Return false to leave a new upload at its size, even when scaling uploads down is on. |
verklein_rewrite_hostsfilter · string[] $hosts | Host names whose upload URLs are rewritten. By default those of your home URL, site URL and uploads URL. Add a CDN or an old domain. |
verklein_rewrite_skip_tablesfilter · string[] $prefixes | Tables (without the WordPress prefix) the URL update skips. Every table whose name starts with one of these strings is skipped. |
verklein_purge_cachesaction · no arguments | Fires after the plugin has cleared the caches. Clear your own cache or CDN here. |
verklein_convertedaction · int $id, array $record | After an attachment is converted, in both modes. $record includes format, quality, bytes_before and bytes_after. In replace mode also new_files; in fallback mode delivery ('fallback'), formats and files. |
verklein_restoredaction · int $id, array $record | After an attachment is restored, with the restore data that was used. In fallback mode that is the data of the deleted copies. |
verklein_picture_enabledfilter · bool $enabled | Fallback mode: return false to add no <picture> elements on this page. Already off in the admin, feeds, the REST API, AJAX, cron, WP-CLI, AMP and WooCommerce e-mails. |
verklein_picture_htmlfilter · string $html, string $img, int $attachment_id | Fallback mode: the <picture> markup for one image. $img is the original img tag, $attachment_id is 0 when unknown. |
// Also rewrite URLs on your CDN.
add_filter( 'verklein_rewrite_hosts', function ( $hosts ) {
$hosts[] = 'cdn.example.com';
return $hosts;
} );
// Let editors convert too.
add_filter( 'verklein_capability', function () {
return 'edit_others_posts';
} );
// Never convert the logo and IDs 42 and 43.
add_filter( 'verklein_excluded_ids', function ( $ids ) {
return array_merge( $ids, array( 42, 43, (int) get_theme_mod( 'custom_logo' ) ) );
} );
// Do not convert uploads with "original" in the file name.
add_filter( 'verklein_convert_upload', function ( $convert, $file ) {
return false === stripos( $file['name'], 'original' ) ? $convert : false;
}, 10, 2 );
// Also skip the tables of your own logging plugin.
add_filter( 'verklein_rewrite_skip_tables', function ( $prefixes ) {
$prefixes[] = 'mylog_';
return $prefixes;
} );
// Clear the CDN cache after a task as well.
add_action( 'verklein_purge_caches', 'my_cdn_purge_all' );
// No <picture> on the checkout page.
add_filter( 'verklein_picture_enabled', function ( $enabled ) {
return function_exists( 'is_checkout' ) && is_checkout() ? false : $enabled;
} );
// Add a class to every <picture> element.
add_filter( 'verklein_picture_html', function ( $html ) {
return str_replace( '<picture>', '<picture class="vk-picture">', $html );
} );
// Log how much was saved per image.
add_action( 'verklein_converted', function ( $id, $record ) {
error_log( sprintf( 'Attachment %d: %d bytes saved', $id, $record['bytes_before'] - $record['bytes_after'] ) );
}, 10, 2 );