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

19 мар. 2012 г., 18:38:12
Просмотры: 26.3K
Голосов: 17

возможно ли программно перегенерировать ЧПУ (slugs) после изменения заголовков постов? Множество заголовков постов были обновлены, но их ЧПУ не обновились вместе с заголовками, поэтому мне нужно перегенерировать все эти ЧПУ.

1
Комментарии

Мне приходилось делать это несколько раз, и я обнаружил, что в разных серверных средах, где не удается обрабатывать большие массивы (при установке numberposts в "неограниченно") или многократно вызывать wp_update_post с высоким потреблением памяти, разбивка на вызов WP_Query с пагинацией и использование $wpdb делает процесс более управляемым и производительным. Я предоставил пример кода в похожем посте.

codearachnid codearachnid
27 февр. 2014 г. 05:14:30
Все ответы на вопрос 5
3
28

Да, это возможно.

Пример кода, который нужно протестировать и доработать:

// получить все записи
$posts = get_posts( array (  'numberposts' => -1 ) );

foreach ( $posts as $post )
{
    // проверить ярлык и обновить при необходимости
    $new_slug = sanitize_title( $post->post_title );
    if ( $post->post_name != $new_slug )
    {
        wp_update_post(
            array (
                'ID'        => $post->ID,
                'post_name' => $new_slug
            )
        );
    }
}

Я только что придумал этот код, вероятно, в нём есть некоторые ошибки и неучтённые случаи, но он должен дать вам представление о том, как это можно сделать. Кроме того, это может занять некоторое время, поэтому может быть полезно разбить обновление на более мелкие части.

19 мар. 2012 г. 21:20:32
Комментарии

Хмм... По моему опыту, это не работает. Аргумент post_name игнорируется в функции wp_update_post, по крайней мере в версии ядра 3.9

Alexandre Bourlier Alexandre Bourlier
4 сент. 2014 г. 16:55:37

В настоящее время post_name игнорируется внутри функции wp_update_post(), но учитывается при вызове функции wp_insert_post() при обновлении записи: это означает, что передача нового слага при обновлении фактически изменит его для обновляемой записи.

Erenor Paz Erenor Paz
30 мая 2018 г. 11:00:27

@fuxia, я пробовал что-то похожее, но это приводит к таймауту. Не могли бы вы предложить подход?

Motivated Motivated
5 окт. 2022 г. 08:39:53
0

Этот плагин также выполняет задачу: http://www.jerrytravis.com/598/wordpress-plugin-to-generate-post-slugs

Однако, поскольку он работает только с записями, у которых еще нет слага (URL-адреса), если вам нужно перегенерировать слаги, отредактируйте следующую строку в плагине:

if ($post->post_name == "") {

Например, вы можете изменить её на:

if (true) {

24 июл. 2014 г. 11:31:09
2

Я пробовал метод, предложенный Toscho, который является "инстинктивным", но во многих случаях он не работает (см. код ядра, чтобы понять, что я имею в виду под "многими случаями").

Изучая код, я обнаружил хук фильтра wp_insert_post_data, вызываемый функцией wp_update_post непосредственно перед вставкой записи в базу данных.

Используя этот фильтр и изменя значение $data['post_name'], мне удалось заставить это работать правильно. WordPress классный, но так плохо документирован...

Я отредактировал документацию, чтобы больше людей могли найти это решение, если оно понадобится.

4 сент. 2014 г. 17:30:06
Комментарии

Можешь указать, почему wp_update_post перезаписывает post_name? Единственная причина, которую я вижу для этого — если пользователь, пытающийся изменить post_name, является только участником (или того же уровня), и в этом случае этому пользователю не должно быть разрешено изменять slug. Нашел ли ты какие-либо другие случаи, когда post_name перезаписывается?

jnhghy - Alexandru Jantea jnhghy - Alexandru Jantea
16 окт. 2014 г. 10:32:59

Да, это правильный способ сделать это. Спасибо, @Alexandre

User User
10 мар. 2017 г. 10:44:41
0

Вы можете сделать это напрямую в MySQL, если это необходимо. (Наш сайт WooCommerce содержит сотни тысяч товаров):

update wp_posts set post_name = concat(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(lower(post_title), '"', ''), "'", ''), ",", '-'), " ", '-'), "&", ''), ";", ''), "@", ''), ".", ''), ":", ''), "/", ''), "+", ''), "(", ''), ")", ''), "--", '-'), "---", '-'), "--", '-'), "--", '-'), '-', id) where post_type = 'product';

где post_type = 'product' - это ограничит обновление только товарами WooCommerce; вам следует определить, какие ограничения вы хотите установить для этого запроса.

7 янв. 2020 г. 07:19:26
0

У нас возникла проблема при миграции и объединении нескольких типов записей. Также у нас было много пустых заголовков. Я написал WP CLI команду, чтобы исправить их все, но вот суть того, что я сделал:

    global $wpdb;
    $types = [
      'page',
      // Имена ваших пользовательских типов записей
    ];

    // Правильно форматируем запрос IN
    $final = array_map(function($type) {
      return "'" . esc_sql($type) . "'";
    }, $types);

    // Получаем все записи с пустыми заголовками
    $query = sprintf("SELECT post_title, ID FROM `%s` WHERE post_type IN (%s) AND post_name = ''",
      $wpdb->posts,
      implode(",", $final)
    );

    foreach ($wpdb->get_results($query) as $post) {
      $title = sanitize_title_with_dashes( $post->post_title );
      $wpdb->update('wp_posts', ['post_name' => $title], ['ID' => $post->ID]);
    }

Пришлось делать прямое обновление MySQL, так как wp_update_post не обновляет post_name.

12 июн. 2020 г. 16:44:19