Cambiare la struttura dei permalink per i custom post type
Ho 2 custom post type: software
e hardware
. Per motivi SEO vorrei avere i permalink delle singole pagine software
e hardware
così:
https://domain.com/custom-post-name/
Ma di default WordPress aggiunge lo slug del post-type come:
https://domain.com/post-type-slug/custom-post-name/
Ho rimosso lo slug con questo script che fa una sostituzione della stringa. Ora la singola pagina è raggiungibile con entrambi gli URL descritti sopra e Google Search Console trova 2 pagine con lo stesso identico contenuto, il che non è positivo per la SEO. È possibile modificare completamente la struttura di un permalink ed eliminare lo slug del custom post type?
register_post_type( 'hardware',
array (
'labels' => $labels,
'has_archive' => true,
'public' => true,
'supports' => array( 'title', 'editor', 'excerpt', 'custom-fields', 'thumbnail' ),
'taxonomies' => array( 'hardware-post_tag', 'hardware-category' ),
'exclude_from_search' => false,
'capability_type' => 'post',
'rewrite' => array( 'slug' => 'hardware' ),
)
);

Nota una cosa importante riguardo alla risposta precedente:
Sebbene a prima vista funzioni bene, causerà problemi di performance.
Tutto questo codice verrà eseguito sull'hook init
quindi ogni caricamento di pagina lo farà girare e flush_rules()
è un'operazione molto costosa in termini di tempo.
Quindi è consigliato chiamare il flush delle regole solo all'attivazione del tema/plugin. Inoltre puoi usare le funzioni add_permastruct
senza bisogno di accedere a global $wp_rewrite
La soluzione finale migliorata sarebbe:
add_action('init', 'my_custom_rewrite');
function my_custom_rewrite() {
add_permastruct('hardware', '/%customname%/', false);
add_permastruct('produkt', '/%customname%/', false);
}
add_filter( 'post_type_link', 'my_custom_permalinks', 10, 2 );
function my_custom_permalinks( $permalink, $post ) {
return str_replace( '%customname%/', $post->post_name, $permalink );
}
/* nel caso di un plugin */
register_activation_hook(__FILE__,'my_custom_plugin_activate');
function my_custom_plugin_activate() {
flush_rewrite_rules();
}
/* nel caso di un Tema personalizzato in Functions.php */
add_action('after_switch_theme', 'mytheme_setup');
function mytheme_setup () {
flush_rewrite_rules();
}

Sono riuscito a risolverlo utilizzando {$field_no_prefix}_save_pre
con post_name
.
/**
* Personalizza i permalink.
*
* @param string $post_name
*
* @return string
* Restituisce una combinazione nome-SKU per i prodotti, se tutti i componenti sono disponibili.
*/
function my_custom_permalinks( $post_name ) {
if (
($_POST['post_type'] !== 'product')
|| ($_POST['post_status'] === 'auto-draft')
) {
return $post_name;
}
$post_name = sanitize_title_with_dashes(
{ modifica $_POST['post_title'] come preferisci }
);
return $post_name;
}
add_filter('name_save_pre', 'my_custom_permalinks', 1, 1);

Se osservi l'argomento rewrite
per register_post_type
, c'è un'opzione with_front
per disabilitare la base predefinita che viene anteposta al permalink del tipo di post personalizzato. Se imposti questo valore su false, /blog/prodotti/
per esempio diventa /prodotti/
.
https://developer.wordpress.org/reference/functions/register_post_type/#rewrite
'rewrite' => array(
'slug' => 'prodotti',
'with_front' => false
)

RISOLTO
utilizzando $wp_rewrite
puoi aggiungere una nuova struttura di permalink
add_action('init', 'my_custom_rewrite');
function my_custom_rewrite() {
global $wp_rewrite;
$wp_rewrite->add_permastruct('hardware', '/%customname%/', false);
$wp_rewrite->add_permastruct('produkt', '/%customname%/', false);
$wp_rewrite->flush_rules();
}
poi sostituisci il tuo tag personalizzato con str_replace
quando filtri l'URL del link
add_filter( 'post_type_link', 'my_custom_permalinks', 10, 2 );
function my_custom_permalinks( $permalink, $post ) {
return str_replace( '%customname%/', $post->post_name, $permalink );
}
NOTA: se usi questa funzione così com'è scritta (rimuovendo lo slug del post type dal permalink) puoi aspettarti problemi gravi perché non c'è alcun controllo se crei un permalink di post personalizzato uguale a una pagina o a un post standard

Chiunque si imbatta in questa domanda e abbia affrontato il fastidioso problema del link rot con il collegamento "following script" menzionato nella domanda, ecco lo script gentilmente fornito dalla Wayback Machine, con una correzione a quello che credo fosse un errore nel codice:
/**
* Rimuove lo slug dai permalink dei post pubblicati. Interessa solo il nostro CPT.
*/
function vipx_remove_cpt_slug( $post_link, $post, $leavename ) {
if ( ! in_array( $post->post_type, array( 'your_post_type' ) ) || 'publish' != $post->post_status )
return $post_link;
$post_link = str_replace( '/' . $post->post_type . '/', '/', $post_link );
return $post_link;
}
add_filter( 'post_type_link', 'vipx_remove_cpt_slug', 10, 3 );
function vipx_parse_request_tricksy( $query ) {
// Intervieni solo sulla query principale
if ( ! $query->is_main_query() )
return;
// Intervieni solo in caso di corrispondenza con la nostra specifica regola di rewrite
if ( 2 != count( $query->query )
|| ! isset( $query->query['page'] ) )
return;
// 'name' sarà impostato se i permalink dei post sono solo post_name, altrimenti verrà applicata la regola della pagina
if ( ! empty( $query->query['name'] ) )
$query->set( 'post_type', array( 'post', 'your_post_type', 'page' ) );
}
add_action( 'pre_get_posts', 'vipx_parse_request_tricksy' );
Insieme alla revisione di Mikhail della soluzione di 3ky, se come me non ti era immediatamente chiaro, ho trovato necessario implementare la funzione vipx_parse_request_tricksy()
e la corrispondente azione. Ma la funzione vipx_remove_cpt_slug()
duplica ciò che fa my_custom_permalinks()
, quindi entrambe non sono necessarie—scegline una?
