Транслитерация на PHP и WordPress: готовые решения для разработчиков

В веб-разработке задача транслитерации возникает постоянно: нужно преобразовать русский текст в латиницу для ЧПУ-адресов, имен файлов, SEO-заголовков или отправки данных во внешние системы. В этой статье я покажу, как реализовать транслитерацию на PHP и в WordPress, используя только встроенные средства и простые функции, без внешних API и плагинов.

Зачем программисту транслитерация?

В веб-разработке транслитерация нужна для:

  • ЧПУ-адресов (Человеко-понятных URL): вместо ?id=12345 — o-kompanii.

  • Имен файлов: загрузка изображений с названиями на русском → автоматическое переименование в латиницу.

  • SEO: правильная транслитерация заголовков и мета-тегов.

  • Интеграций с внешними API: многие сервисы принимают данные только в латинице.

  • Формирования логинов и ников: автоматическая генерация username на основе ФИО.


Решение 1. Базовая транслитерация на чистом PHP

Самое простое решение — функция с ассоциативным массивом правил. Она не требует внешних библиотек и работает на любой версии PHP с поддержкой UTF-8.

<?php
/**
 * Базовая транслитерация кириллицы в латиницу
 * 
 * @param string $text Исходный текст
 * @return string Транслитерированный текст
 */
function transliterate($text) {
    // Карта замены (кириллица → латиница)
    $map = [
        'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd',
        'е' => 'e', 'ё' => 'e', 'ж' => 'zh', 'з' => 'z', 'и' => 'i',
        'й' => 'y', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n',
        'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't',
        'у' => 'u', 'ф' => 'f', 'х' => 'kh', 'ц' => 'ts', 'ч' => 'ch',
        'ш' => 'sh', 'щ' => 'shch', 'ъ' => '', 'ы' => 'y', 'ь' => '',
        'э' => 'e', 'ю' => 'yu', 'я' => 'ya'
    ];
    
    // Приводим к нижнему регистру
    $text = mb_strtolower($text, 'UTF-8');
    
    $result = '';
    $length = mb_strlen($text, 'UTF-8');
    
    for ($i = 0; $i < $length; $i++) {
        $char = mb_substr($text, $i, 1, 'UTF-8');
        $result .= isset($map[$char]) ? $map[$char] : $char;
    }
    
    return $result;
}
// Пример использования
echo transliterate('Привет, мир!'); // privet-mir
echo transliterate('SEO-заголовок'); // seo-zagolovok
?>

Важно: используйте mb_-функции (mb_strtolower, mb_substr, mb_strlen) для корректной работы с многобайтовой кодировкой UTF-8. Без них функция будет неправильно обрабатывать русские буквы.

Решение 2. Транслитерация для ЧПУ (URL)

Для генерации человекопонятных URL нужно не только заменить буквы, но и удалить лишние символы, заменить пробелы на дефисы и привести всё к нижнему регистру.

<?php
/**
 * Транслитерация для создания ЧПУ-адресов
 * 
 * @param string $text Исходный текст
 * @return string Готовый slug для URL
 */
function transliterateUrl($text) {
    $map = [
        'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd',
        'е' => 'e', 'ё' => 'e', 'ж' => 'zh', 'з' => 'z', 'и' => 'i',
        'й' => 'y', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n',
        'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't',
        'у' => 'u', 'ф' => 'f', 'х' => 'kh', 'ц' => 'ts', 'ч' => 'ch',
        'ш' => 'sh', 'щ' => 'shch', 'ъ' => '', 'ы' => 'y', 'ь' => '',
        'э' => 'e', 'ю' => 'yu', 'я' => 'ya'
    ];
    
    // Приводим к нижнему регистру
    $text = mb_strtolower($text, 'UTF-8');
    
    $result = '';
    $length = mb_strlen($text, 'UTF-8');
    
    for ($i = 0; $i < $length; $i++) {
        $char = mb_substr($text, $i, 1, 'UTF-8');
        
        if (isset($map[$char])) {
            $result .= $map[$char];
        } elseif (preg_match('/[a-z0-9]/', $char)) {
            $result .= $char;
        } elseif ($char === ' ') {
            $result .= '-';
        }
    }
    
    // Убираем лишние дефисы и спецсимволы
    $result = preg_replace('/-+/', '-', $result);
    $result = preg_replace('/[^a-z0-9\-]/', '', $result);
    $result = trim($result, '-');
    
    return $result;
}
// Примеры использования
echo transliterateUrl('Привет, мир!');          // privet-mir
echo transliterateUrl('SEO-оптимизация 2024'); // seo-optimizatsiya-2024
echo transliterateUrl('Новый год!');           // novyy-god
?>

Что делает этот код:

  1. Заменяет русские буквы на латинские.

  2. Оставляет латинские буквы и цифры.

  3. Заменяет пробелы на дефисы.

  4. Удаляет все остальные символы (знаки препинания, спецсимволы).

  5. Убирает повторяющиеся и лишние дефисы.

Решение 3. Генерация ЧПУ в WordPress

В WordPress транслитерация чаще всего используется для генерации ЧПУ (slug) заголовков записей. Встроенная функция sanitize_title() работает с кириллицей, но не идеально — она просто удаляет русские буквы, оставляя только латиницу. Чтобы исправить это, используйте фильтр.

Способ 1. Фильтр sanitize_title (рекомендуемый)

Этот способ перехватывает генерацию slug и применяет вашу функцию транслитерации.

<?php
/**
 * Фильтр для генерации ЧПУ на основе транслитерации
 */
add_filter('sanitize_title', 'custom_transliterate_slug', 10, 3);
function custom_transliterate_slug($title, $raw_title, $context) {
    // Применяем транслитерацию только при сохранении записей
    if ($context !== 'save') {
        return $title;
    }
    
    // Транслитерируем заголовок для URL
    $transliterated = transliterateUrl($raw_title);
    
    // Если результат не пустой, возвращаем его
    return !empty($transliterated) ? $transliterated : $title;
}
?>

Способ 2. Генерация slug при сохранении поста (с проверкой уникальности)

Этот способ даёт больше контроля и позволяет проверить уникальность slug.

<?php
/**
 * Генерация уникального slug при сохранении поста
 */
add_action('save_post', 'generate_transliterated_slug', 10, 3);
function generate_transliterated_slug($post_id, $post, $update) {
    // Пропускаем автосохранения, ревизии и черновики
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
        return;
    }
    if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) {
        return;
    }
    
    // Если slug уже задан вручную, не трогаем
    if (!empty($post->post_name)) {
        return;
    }
    
    // Генерируем slug из заголовка
    $new_slug = transliterateUrl($post->post_title);
    
    // Если ничего не получилось, выходим
    if (empty($new_slug)) {
        return;
    }
    
    // Проверяем уникальность slug
    $new_slug = wp_unique_post_slug($new_slug, $post_id, $post->post_status, $post->post_type, $post->post_parent);
    
    // Обновляем запись с новым slug
    wp_update_post([
        'ID' => $post_id,
        'post_name' => $new_slug
    ]);
}
?>

Решение 4. Расширенная транслитерация с поддержкой разных стандартов

Если ваш проект требует разных стандартов транслитерации (например, для загранпаспорта, ISO 9, URL), можно сделать функцию с выбором стандарта.

<?php
/**
 * Получить правила транслитерации для выбранного стандарта
 */
function getTransliterationRules($standard = 'url') {
    $base = [
        'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd',
        'е' => 'e', 'ё' => 'e', 'ж' => 'zh', 'з' => 'z', 'и' => 'i',
        'й' => 'y', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n',
        'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't',
        'у' => 'u', 'ф' => 'f', 'х' => 'kh', 'ц' => 'ts', 'ч' => 'ch',
        'ш' => 'sh', 'щ' => 'shch', 'ъ' => '', 'ы' => 'y', 'ь' => '',
        'э' => 'e', 'ю' => 'yu', 'я' => 'ya'
    ];
    
    $standards = [
        'url' => [],
        'passport' => ['щ' => 'shch', 'ъ' => 'ie', 'ы' => 'y', 'ё' => 'e'],
        'gibdd' => ['ё' => 'e', 'ю' => 'iu', 'я' => 'ia', 'щ' => 'shch'],
        'iso' => ['ё' => 'ë', 'ж' => 'ž', 'й' => 'j', 'х' => 'h', 'ц' => 'c', 'ч' => 'č', 'ш' => 'š', 'щ' => 'ŝ', 'ъ' => 'ʺ', 'ы' => 'y', 'ь' => 'ʹ', 'э' => 'è', 'ю' => 'û', 'я' => 'â']
    ];
    
    return array_merge($base, $standards[$standard] ?? []);
}
/**
 * Транслитерация с выбором стандарта
 */
function transliterateWithStandard($text, $standard = 'url') {
    $text = mb_strtolower($text, 'UTF-8');
    $map = getTransliterationRules($standard);
    
    $result = '';
    $length = mb_strlen($text, 'UTF-8');
    
    for ($i = 0; $i < $length; $i++) {
        $char = mb_substr($text, $i, 1, 'UTF-8');
        $result .= $map[$char] ?? $char;
    }
    
    // Для URL дополнительная очистка
    if ($standard === 'url') {
        $result = preg_replace('/\s+/', '-', $result);
        $result = preg_replace('/[^a-z0-9\-]/', '', $result);
        $result = preg_replace('/-+/', '-', $result);
        $result = trim($result, '-');
    }
    
    return $result;
}
// Примеры использования
echo transliterateWithStandard('Щукин Александр', 'url');      // shchukin-aleksandr
echo transliterateWithStandard('Щукин Александр', 'passport'); // shchukin-aleksandr
echo transliterateWithStandard('Юлия', 'passport');            // iuliia
echo transliterateWithStandard('Ёлкин', 'iso');                // ëlkin
?>

Частые ошибки и их решение

При реализации транслитерации на PHP и в WordPress часто возникают одни и те же проблемы. Вот самые распространённые и способы их решения.

Проблема Причина Решение
Вместо букв появляются вопросы (????) Неправильная кодировка файла или данные не в UTF-8 Убедитесь, что файл сохранён в UTF-8 без BOM. Используйте mb_-функции.
WordPress генерирует slug только из первого слова Фильтр sanitize_title обрезает заголовок Используйте sanitize_title с приоритетом 10 и проверяйте контекст (‘save’).
В URL появляются двойные слэши Некорректная обработка слэшей Используйте untrailingslashit() и trailingslashit() для путей.
Транслитерация работает на локалке, но не на сервере На сервере отключено расширение mbstring Установите расширение PHP mbstring на сервере.
Slug не генерируется для записей, созданных через API WordPress пропускает фильтр sanitize_title для API-запросов Используйте хук wp_insert_post_data для принудительной генерации slug.
Транслитерация удаляет символы, которые нужно сохранить Слишком агрессивная очистка в preg_replace Настройте регулярное выражение: разрешите точки, дефисы, нижние подчёркивания.

Вывод: выбирайте решение под свою задачу

Для простых проектов достаточно базовой функции с массивом правил. Если нужно генерировать ЧПУ-адреса в WordPress — используйте фильтр sanitize_title. Для проектов, где важна точность (документы, госстандарты), добавьте поддержку разных стандартов через расширенную функцию.

Главное — не забывайте про кодировку UTF-8 и mb_-функции, проверяйте уникальность slug и обрабатывайте краевые случаи (пустые строки, спецсимволы).

Для разработчиков: Хотите быстро проверить, как транслитерируется ваш текст по разным стандартам? Используйте наш сервис Translit PRO — просто введите текст и выберите нужный стандарт из списка.