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

by CatCode · github.com/catcodestudio/wp-all-to-lat · website

0stars
0forks

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/catcodestudio/wp-all-to-lat/archive/refs/heads/main.zip

Readme

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

Read the full README on GitHub →