WP Manifestindependent plugin directory
manifest / i18n / wp-all-to-lat

All to Lat — Latin Slugs by Transliteration

All to Lat for WordPress — Latin slugs by transliteration for posts, products, terms and uploads, with a bulk converter, journal, revert and 301s

★ 0stars

Install

Download source zip No release zip yet

This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/catcodestudio/wp-all-to-lat/archive/refs/heads/main.zip
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

All to Lat — WordPress build

Plugin slug: all-to-lat · text domain: all-to-lat · namespace: CatCode\AllToLat Constants and the journal table are prefixed cc_translit, the same as the OpenCart builds.

Where the work happens

File Role
all-to-lat.php header, constants, autoloader, bootstrap
includes/Translit.php the transliteration tables — shared verbatim with the OpenCart builds, keep in sync
includes/Settings.php one option row, validated on save
includes/Installer.php journal table, created on activation and repaired on load
includes/Slugs.php sanitize_title (priority 9) and sanitize_file_name
includes/Bulk.php batch conversion of posts and terms, journal, revert
includes/Redirect.php 301 for renamed terms — WordPress only redirects posts
includes/Admin/* settings screen and the three ajax endpoints

Decisions worth remembering

Priority 9 on sanitize_title. Core's own sanitize_title_with_dashes runs at 10 and is what percent-encodes Cyrillic. Anything later than 9 sees %d0%b0 instead of а and has nothing left to transliterate.

Posts are written with $wpdb->update, not wp_update_post. A full save re-runs every save_post hook on the site — SEO plugins, caches, ERP syncs — for a change none of them care about; on a 20 000-product catalogue that is the difference between a minute and an afternoon. The _wp_old_slug meta that wp_update_post would have written is added by hand, so core's redirect for renamed posts keeps working.

Terms go through wp_update_term instead, because term slugs live in two tables and the caches around them are not worth reimplementing.

Drafts are never converted. WordPress leaves post_name empty on a draft on purpose and fills it in from the title at publish time. Writing a slug there freezes the address at a half-finished title, and the journal cannot undo it either — there is no previous slug to put back. Every scope query therefore carries post_name <> ''.

The preview filters in SQL, a run does not. The preview has to show the first rows that actually need work, or a site whose newest content is already Latin reads "nothing to change" next to a counter saying 900. A run walks the same scope by LIMIT offset, n and must see a stable set — filtering there would shrink the set under the walker and skip rows.

The 301 follows its own setting, not status. status governs slugs created from now on; switching it off on a converted site must not 404 every address the conversion replaced.

Table names go through %i, which is why the plugin requires WordPress 6.2. That is what keeps Plugin Check at 0/0 without blanket-ignoring the SQL sniffs.

Build

python build.py     # → all-to-lat.zip, ready for wp.org or a manual upload