Перегенерация пермалинков (слагов) — массовое изменение ЧПУ на сайте WordPress

Задача — настроить ЧПУ, чтобы вместо post_id использовался postname.

Проблема — после изменения настроек постоянных ссылок на сайте сгенерированы ЧПУ неправильно, еще на сайте настроена мультиязычность с помощью плагина Polylang, и в Рус версии урлы обрезаются на половине слова, а в Укр версии слаги проставлены как post_id .

Совет — для начала попробуйте плагин Cyr-To-Lat — у него в настройках есть замечательная функция Конвертер, с помощью которого можно сконвертировать свои пермалинки с возможностью транслитерации, но в моем случае это не сработало, думаю, что в 90% это вариант будет рабочим и более простым.

Решение проблемы — установка плагина Regenerate post permalink с доработками. Поскольку плагин не поддерживается уже на протяжении 5 лет и нам он нужен на один раз, а других плагинов для решения данной задачи нет, тогда можем смело внести необходимые нам исправления прям в плагин и после решения задачи просто удалить его.

Вносим изменения в файл regenerate-post-permalink.php — он там в принципе единственный.

1. Меняем таблицу транслитерации для кириллицы с укр. языком на такую:

$table = array( 'А' => 'A', 'Б' => 'B', 'В' => 'V', 'Г' => 'G', 'Ґ' => 'G', 'Д' => 'D', 'Е' => 'E', 'Ё' => 'YO', 'Є' => 'YE', 'Ж' => 'ZH', 'З' => 'Z', 'И' => 'Y', 'І' => 'I', 'Ї' => 'YI', 'Й' => 'J', 'К' => 'K', 'Л' => 'L', 'М' => 'M', 'Н' => 'N', 'О' => 'O', 'П' => 'P', 'Р' => 'R', 'С' => 'S', 'Т' => 'T', 'У' => 'U', 'Ф' => 'F', 'Х' => 'H', 'Ц' => 'CZ', 'Ч' => 'CH', 'Ш' => 'SH', 'Щ' => 'SHH', 'Ь' => '', 'Ъ' => '', 'Ю' => 'YU', 'Я' => 'YA', 'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'ґ' => 'g', 'д' => 'd', 'е' => 'e', 'ё' => 'yo', 'є' => 'ye', 'ж' => 'zh', 'з' => 'z', 'и' => 'y', 'і' => 'i', 'ї' => 'yi', 'й' => 'j', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n', 'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't', 'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'cz', 'ч' => 'ch', 'ш' => 'sh', 'щ' => 'shh', 'ь' => '', 'ъ' => '', 'ю' => 'yu', 'я' => 'ya', 'Ы' => 'Y', 'Э' => 'E', 'ы' => 'y', 'э' => 'e', '«' => '', '»' => '' );

2. Полностью заменяем функцию regenerate_post_permalink()

Старый код:

function regenerate_post_permalink($post_type = 'post') {
    global $wpdb;

    $myrows = $wpdb->get_results("SELECT id, post_title FROM $wpdb->posts WHERE post_status = 'publish' AND post_type='$post_type' ");
    $counter = 0;
    foreach ($myrows as $pid) :
        $post_title = regenerate_post_clear_diacritics($pid->post_title);
        $guid = home_url() . '/' . sanitize_title_with_dashes($post_title);
        $sql = "UPDATE $wpdb->posts 
                     SET post_name = '" . sanitize_title_with_dashes($post_title) . "',
                         guid = '" . $guid . "'
               WHERE ID = $pid->id";
        $wpdb->query($sql);
        $counter++;
    endforeach;

    return $counter;
}

Нам нужно выполнить проверку на дубли слагов, иначе плагин может сформировать с одинаковых заголовков одинаковые урлы:

$post_title = sanitize_title_with_dashes($post_title);
$new_slug = wp_unique_post_slug($post_title, $pid->id, 'publish', $post_type, $pid->post_parent);

Поскольку я знаю ,что у меня в постах нет вложенности, то я вместо параметра $pid->post_parent передаю 0. Для своего случая задавайте нужный параметр.

Важно: Так же нам не нужно менять guid — он должен оставаться в старом формате.

Новый код функции regenerate_post_permalink():

function regenerate_post_permalink($post_type = 'post') {
    global $wpdb;

    $myrows = $wpdb->get_results("SELECT id, post_title FROM $wpdb->posts WHERE post_status = 'publish' AND post_type='$post_type' ");
    $counter = 0;
    foreach ($myrows as $pid) :
        $post_title = regenerate_post_clear_diacritics($pid->post_title);
        $post_title = sanitize_title_with_dashes($post_title);
        $new_slug = wp_unique_post_slug($post_title, $pid->id, 'publish', $post_type, 0);
        $sql = "UPDATE $wpdb->posts SET post_name = '" . $new_slug . "' WHERE ID = $pid->id";
        $wpdb->query($sql);
        $counter++;
    endforeach;

    return $counter;
}

Затем переходим в настройки -> Permalinks regeneration -> выбираем Posts -> жмем Regenerate permalinks.

Получаем красивые урлы у всех записей и на украинском языке, и на русском.

P.S. Пока искал разные варианты решения проблемы перепробовал кучу плагинов и пересмотрел кучу блогов зарубежных. Как же надоели копирайтеры и бестолковые контентщики. Ищешь ответ на конкретный вопрос «как массово переконвертировать пермалинки» и находишь кучу статей на 5-6-7 экранов, в которых описано что такое пермалинки, зачем, почему, как их настраивать, как делать 301 редиректы, как оптимизировать для Гугла и тд, а ответа на вопрос просто нету, зато куча теории и воды… Достали контентщики, которые работают ради количества символов, а не ради решения вопросов, которые указаны в заголовке статьи. «Выговорился».

Как выводить кастомные типы записей в поиске

По умолчанию WordPress не включает пользовательские типы записей в результаты поиска. Из-за этого вам нужно самостоятельно…

Как выводить кастомные типы записей в стандартных рубриках или тегах

По умолчанию WordPress не включает кастомные типы записей в архивы категорий и тегов. Из-за этого вам…

Как исправить ошибку 404 при постраничной навигации, если используются кастомные ссылки для записей и категорий в CMS WordPress

Итак, суть проблемы — при переходе на 2-3 и так далее страницы блога возникает 404…

Как заменить пагинацию WooCommerce на WP-PageNavi

Простой способ подключить вместо стандартной пагинации WooCommerce woocommerce_pagination пагинацию с помощью плагина WP-PageNavi. Устанавливаем и…

4 комментария

Сергей Кизим

Спасибо за наводку! Я сейчас как раз тоже озаботился массовой сменой урлов на сайте.

По последнему пункту (P.S.) могу сказать, что сейчас стало всё еще хуже. Теперь пустопорожние темы пишет ChatGPT, а людям приходится их читать в поисках решения ))

О дааа, было куча мусора и воды ради количества символов, то теперь под рекламу и для раздутия сайтов-помоек с помощью ChatGPT будет еще больше сгенерированного бреда, чем полезного контента…

Решил проблему
только по другому
у меня стоял Permalink Manager
который может сохранять, старые урл, спецом искал сразу с этой функций, и также там есть регенерация урлов, ну то такое
фишка и втом что там можно структуру УРЛ ставить

ну в общем о проблема, тоже обрезало и не работали укр символы на айфонах ,не знаю почему пока. было решено перепилить все в транслитт и убрать обрезку исмволов, причем чтобы старые урл схохрнаились

был создан файл в папке /wp-content/mu-plugins/permalink-manager-uk-translit.php

с таким содержимим
мозг парило что / меняло на — рпишлось вставить костиль, пили вместе с нейросетью.
само решение

<?php
/*
Plugin Name: Permalink Manager Ukrainian Translit
Description: Adds Ukrainian Cyrillic to Latin transliteration
*/

add_filter('permalink_manager_filter_default_post_uri', 'uk_translit_permalinks', 10, 5);
add_filter('permalink_manager_filter_default_term_uri', 'uk_translit_permalinks', 10, 5);

function uk_translit_permalinks($default_uri, $element, $slug, $native_uri, $is_attachment) {
    $translit_table = array(
        'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'h', 'ґ' => 'g',
        'д' => 'd', 'е' => 'e', 'є' => 'ie', 'ж' => 'zh', 'з' => 'z',
        'и' => 'y', 'і' => 'i', 'ї' => 'i', 'й' => 'i', 'к' => 'k',
        'л' => 'l', 'м' => 'm', 'н' => 'n', 'о' => 'o', 'п' => 'p',
        'р' => 'r', 'с' => 's', 'т' => 't', 'у' => 'u', 'ф' => 'f',
        'х' => 'kh', 'ц' => 'ts', 'ч' => 'ch', 'ш' => 'sh', 'щ' => 'shch',
        'ю' => 'iu', 'я' => 'ia', 'А' => 'A', 'Б' => 'B', 'В' => 'V',
        'Г' => 'H', 'Ґ' => 'G', 'Д' => 'D', 'Е' => 'E', 'Є' => 'Ye',
        'Ж' => 'Zh', 'З' => 'Z', 'И' => 'Y', 'І' => 'I', 'Ї' => 'Yi',
        'Й' => 'Y', 'К' => 'K', 'Л' => 'L', 'М' => 'M', 'Н' => 'N',
        'О' => 'O', 'П' => 'P', 'Р' => 'R', 'С' => 'S', 'Т' => 'T',
        'У' => 'U', 'Ф' => 'F', 'Х' => 'Kh', 'Ц' => 'Ts', 'Ч' => 'Ch',
        'Ш' => 'Sh', 'Щ' => 'Shch', 'Ю' => 'Yu', 'Я' => 'Ya',
        'ь' => '', "'" => '', '’' => ''
    );
    
    // Разделяем URL на части, сохраняя слеши
    $uri_parts = explode('/', $default_uri);
    
    // Транслитерируем только текстовые сегменты (не трогаем цифровые)
    foreach($uri_parts as &$part) {
        // Пропускаем пустые сегменты и цифры (годы, месяцы и т.д.)
        if(empty($part) || is_numeric($part)) continue;
        
        // Декодируем и транслитерируем
        $decoded_part = urldecode($part);
        $transliterated_part = strtr($decoded_part, $translit_table);
        $part = sanitize_title($transliterated_part);
    }
    
    // Собираем обратно в URL
    $default_uri = implode('/', $uri_parts);
    
    return $default_uri;
}

Ответить