Back to Deck
[snippet]
WooCommerce Transliterate Slugs
SOURCE PHP
VERSION 1.0
AUTHOR Cododel
A one-time execution PHP snippet for WordPress/WooCommerce that transliterates Cyrillic attribute and term slugs to Latin. Preserves original display names while fixing URL-unsafe slugs.
The Problem
WooCommerce attributes and terms with Cyrillic names create URL-unsafe slugs:
- Attribute:
pa_цвет→ Should bepa_cvet - Term:
красный→ Should bekrasnyj
This causes issues with:
- SEO (non-Latin URLs)
- URL encoding problems
- Database indexing
- API compatibility
⚠️ Important Warnings
- BACKUP YOUR DATABASE before running this script
- This is a one-time execution snippet
- It modifies your database directly
- Remove the code after execution
- Test on staging environment first
Features
- ✅ Transliterates Cyrillic to Latin for attribute slugs
- ✅ Updates term slugs while preserving names
- ✅ One-time execution with option check
- ✅ Proper WooCommerce API usage
- ✅ Cache invalidation
- ✅ Error logging
Usage Instructions
-
Backup database:
Terminal window # Via wp-cliwp db export backup.sql -
Add to
functions.php:// Add the entire code below to your theme's functions.php -
Load any page on your WordPress site to trigger execution
-
Verify results:
- Check WooCommerce → Attributes
- Verify product attribute URLs
-
Remove the code from
functions.phpafter execution
Example Transformations
| Before | After |
|---|---|
pa_цвет | pa_cvet |
pa_размер | pa_razmer |
красный | krasnyj |
большой | bolshoy |
Source Code
update-wc-attributes-terms-slugs.php
<?phpfunction update_woocommerce_attributes_and_terms() { // Получаем все атрибуты WooCommerce $attributes = wc_get_attribute_taxonomies();
if (empty($attributes)) { return; }
foreach ($attributes as $attribute) { $old_taxonomy = wc_attribute_taxonomy_name($attribute->attribute_name); $new_attribute_name = cyr_to_lat_sanitize($attribute->attribute_name); $new_taxonomy = wc_attribute_taxonomy_name($new_attribute_name);
// Если slug атрибута нужно обновить if ($new_attribute_name !== $attribute->attribute_name) { // Обновляем атрибут через WooCommerce $attribute_data = [ 'id' => $attribute->attribute_id, 'name' => $attribute->attribute_label, // Оставляем оригинальное название 'slug' => $new_attribute_name, 'type' => $attribute->attribute_type, 'order_by' => $attribute->attribute_orderby, 'has_archives' => $attribute->attribute_public ];
$result = wc_update_attribute($attribute->attribute_id, $attribute_data);
if (is_wp_error($result)) { error_log("Failed to update attribute {$attribute->attribute_name}: " . $result->get_error_message()); continue; }
// Обновляем термины для старой таксономии $terms = get_terms([ 'taxonomy' => $old_taxonomy, 'hide_empty' => false, ]);
if (!is_wp_error($terms)) { foreach ($terms as $term) { $new_term_slug = cyr_to_lat_sanitize($term->slug); if ($new_term_slug !== $term->slug) { wp_update_term($term->term_id, $new_taxonomy, [ 'slug' => $new_term_slug, // Название термина не меняем ]); } } }
// Удаляем старую таксономию и регистрируем новую unregister_taxonomy($old_taxonomy); register_taxonomy( $new_taxonomy, 'product', [ 'label' => $attribute->attribute_label, 'public' => (bool) $attribute->attribute_public, 'hierarchical' => false, 'show_ui' => false, ] ); }
// Обновляем slug терминов даже если атрибут не менялся $terms = get_terms([ 'taxonomy' => $new_taxonomy, 'hide_empty' => false, ]);
if (!is_wp_error($terms)) { foreach ($terms as $term) { $new_term_slug = cyr_to_lat_sanitize($term->slug); if ($new_term_slug !== $term->slug) { wp_update_term($term->term_id, $new_taxonomy, [ 'slug' => $new_term_slug, // Название термина не меняем ]); } } } }
// Очищаем кэш delete_transient('wc_attribute_taxonomies'); WC_Cache_Helper::invalidate_cache_group('woocommerce-attributes'); wp_cache_flush();}
// Выполняем один разadd_action('init', function() { if (get_option('update_wc_attributes_and_terms') !== 'done') { update_woocommerce_attributes_and_terms(); update_option('update_wc_attributes_and_terms', 'done'); }});
// Функция транслитерацииfunction cyr_to_lat_sanitize($text) { $cyr = [ 'а'=>'a', 'б'=>'b', 'в'=>'v', 'г'=>'g', 'д'=>'d', 'е'=>'e', 'ё'=>'yo', 'ж'=>'zh', 'з'=>'z', 'и'=>'i', 'й'=>'y', 'к'=>'k', 'л'=>'l', 'м'=>'m', 'н'=>'n', 'о'=>'o', 'п'=>'p', 'р'=>'r', 'с'=>'s', 'т'=>'t', 'у'=>'u', 'ф'=>'f', 'х'=>'h', 'ц'=>'ts', 'ч'=>'ch', 'ш'=>'sh', 'щ'=>'sht', 'ъ'=>'', 'ы'=>'y', 'ь'=>'', 'э'=>'e', 'ю'=>'yu', 'я'=>'ya', 'А'=>'A', 'Б'=>'B', 'В'=>'V', 'Г'=>'G', 'Д'=>'D', 'Е'=>'E', 'Ё'=>'Yo', 'Ж'=>'Zh', 'З'=>'Z', 'И'=>'I', 'Й'=>'Y', 'К'=>'K', 'Л'=>'L', 'М'=>'M', 'Н'=>'N', 'О'=>'O', 'П'=>'P', 'Р'=>'R', 'С'=>'S', 'Т'=>'T', 'У'=>'U', 'Ф'=>'F', 'Х'=>'H', 'Ц'=>'Ts', 'Ч'=>'Ch', 'Ш'=>'Sh', 'Щ'=>'Sht', 'Ъ'=>'', 'Ы'=>'Y', 'Ь'=>'', 'Э'=>'E', 'Ю'=>'Yu', 'Я'=>'Ya' ];
$text = strtr($text, $cyr); $text = preg_replace('/[^a-zA-Z0-9\s-]/', '', $text); return sanitize_title(trim($text));}