Rigenera gli Slug dal Titolo dei Post
Sì, è possibile.
Codice di esempio, da testare e perfezionare:
// ottieni tutti i post
$posts = get_posts( array ( 'numberposts' => -1 ) );
foreach ( $posts as $post )
{
// controlla lo slug ed esegui un aggiornamento se necessario
$new_slug = sanitize_title( $post->post_title );
if ( $post->post_name != $new_slug )
{
wp_update_post(
array (
'ID' => $post->ID,
'post_name' => $new_slug
)
);
}
}
L'ho appena creato, probabilmente ci sono alcuni errori e casi particolari, ma dovrebbe darti un'idea. Inoltre, potrebbe richiedere del tempo, quindi potrebbe essere utile suddividere l'aggiornamento in blocchi più piccoli.

Uhm... dalla mia esperienza, questo non funziona.
L'argomento post_name
viene ignorato dalla funzione wp_update_post
, almeno nella versione 3.9 del core

Attualmente, post_name
viene ignorato all'interno della funzione wp_update_post()
, ma viene preso in considerazione quando l'aggiornamento del post richiama la funzione wp_insert_post()
: ciò significa che passare il nuovo slug all'aggiornamento, risulterà nella modifica effettiva dello slug per il post che viene aggiornato.

@fuxia, ho provato qualcosa di simile ma va in timeout. Saresti in grado di suggerire un approccio?

Anche questo plugin svolge il lavoro: http://www.jerrytravis.com/598/wordpress-plugin-to-generate-post-slugs
Tuttavia, dato che lo fa solo per i post che non hanno ancora uno slug, se hai bisogno di rigenerare gli slug modifica la seguente linea nel plugin:
if ($post->post_name == "") {
Ad esempio, potresti cambiarla con:
if (true) {

Stavo provando il metodo suggerito da Toscho, che è quello "istintivo", ma in molti casi non funziona (vedi il codice core per capire cosa intendo con "molti casi").
Analizzando il codice, ho trovato l'hook filter wp_insert_post_data
, chiamato dalla funzione wp_update_post
poco prima di inserire il post nel database.
Chiamando questo filtro e modificando il valore di $data['post_name']
, sono riuscito a farlo funzionare correttamente. WordPress è fantastico ma così male documentato...
Ho modificato la documentazione, in modo che più persone possano trovare questa soluzione alternativa se necessario.

Puoi indicare perché wp_update_post sovrascrive il post_name? L'unica ragione che vedo perché questo accada è se l'utente che cerca di modificare il post_name è solo un collaboratore (o livello simile) nel qual caso non dovrebbe permettere a quell'utente di cambiare lo slug, hai trovato altri casi in cui il post_name viene sovrascritto?

puoi farlo direttamente in mysql se necessario. (il nostro sito woocommerce ha centinaia di migliaia di prodotti):
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';
dove post_type = 'product' - questo limiterà l'aggiornamento ai soli prodotti woocommerce; dovresti capire quali limiti vuoi impostare su questa query.

Abbiamo avuto un problema durante la migrazione e unione di diversi tipi di post. Avevamo anche molti titoli vuoti. Ho scritto un comando WP CLI per sistemarli tutti, ma ecco l'essenza di ciò che ho fatto:
global $wpdb;
$types = [
'page',
// I nomi machine dei vostri CPT
];
// Formatta correttamente la nostra query IN.
$final = array_map(function($type) {
return "'" . esc_sql($type) . "'";
}, $types);
// Recupera tutti i campi titolo vuoti.
$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]);
}
È stato necessario fare un aggiornamento MySQL diretto poiché wp_update_post non aggiorna il post_name.
