Come disabilitare la visualizzazione singola per un custom post type?
Dato questo custom post type:
register_post_type(
'sample_post_type',
[
'labels' => [
'name' => _x('Post di Esempio', 'nome generale del tipo di post'),
'singular_name' => _x('Post di Esempio', 'nome singolare del tipo di post'),
],
'public' => true,
'show_in_nav_menus' => false,
'exclude_from_search' => true,
]
);
Come posso disabilitare la visualizzazione del post singolo per questo particolare tipo di post? Va bene mostrare una semplice pagina 404 o reindirizzare alla homepage. Dato che questo è un plugin, non posso creare un file single-sample_post_type.php
per impostare una pagina vuota.

Sembra essere la soluzione per impedire al tuo CPT di creare pagine web effettive mantenendo comunque tutti i riferimenti al database.

Per disabilitare la visualizzazione singola per un CPT puoi reindirizzare gli utenti a un URL specifico, oppure disabilitarla durante la registrazione del CPT stesso.
METODO 1:
Reindirizza la visualizzazione singola del CPT a un URL personalizzato, la pagina archivio rimane pubblicamente disponibile.
Puoi usare l'hook template_redirect
per reindirizzare un utente, puoi usare qualsiasi URL al posto di home_url()
e il codice di errore desiderato come secondo argomento.
<?php
add_action( 'template_redirect', 'wpse_128636_redirect_post' );
function wpse_128636_redirect_post() {
if ( is_singular( 'tipo_di_post_personalizzato' ) ) :
wp_redirect( home_url(), 301 );
exit;
endif;
}
?>
METODO 2:
Disabilita completamente la pagina Singola e Archivio dal front-end; Funziona solo per Custom Post Types.
Un approccio alternativo è impostare publicly_queryable
su false durante la registrazione del post personalizzato.
'publicly_queryable' => false
Questo nasconde sia la visualizzazione singola che la pagina archivio per il CPT, può essere usato solo per post personalizzati.
Anche se l'archivio e la visualizzazione singola sono nascosti, puoi comunque aggiungere un template di pagina o un blocco personalizzato per elencare i post se necessario.

Una buona soluzione. Ho trovato utile eseguire questo reindirizzamento solo per gli utenti non autenticati, verificando se get_current_user_id()
restituisce 0.

perché non usare solo is_singular('post-type-slug')
nella condizione if()
invece di 2 condizioni?

@AkashK. Sì, anche quello potrebbe funzionare, non conoscevo la funzione.

il suggerimento remove_rewrite_tag( '%post-type-slug%' ); è una buona soluzione

Ho testato tutte le soluzioni menzionate sopra e la soluzione effettiva è più semplice di qualsiasi reindirizzamento suggerito.
Per avere l'archivio accessibile e che elenchi gli elementi, e il singolo post non accessibile con reindirizzamento automatico alla pagina 404, imposta
'query_var' => false
durante la registrazione del tuo CPT. Se imposti publicly_queryable
su false, i tuoi archivi verranno reindirizzati alla home, qualsiasi altra combinazione non funzionerà. Imposta query_var
su false e il gioco è fatto.
Ecco il CPT completo https://gist.github.com/danyj/bfd038d3c8d578548c4d700bd0a7942a
vedi riga 50 https://gist.github.com/danyj/bfd038d3c8d578548c4d700bd0a7942a#file-thz_cpt_items_single_view_redirect-php-L50
come indicato qui
https://codex.wordpress.org/Function_Reference/register_post_type
Nota: Se query_var è vuoto, null, o un booleano FALSE, WordPress cercherà comunque di interpretarlo (4.2.2) e le anteprime/visualizzazioni del tuo custom post restituiranno errori 404.

Sembra un po' un hack ma sembra funzionare. Vorrei che aggiungessero semplicemente una proprietà dedicata has_single insieme alla proprietà esistente has_archive.

Ciao, ho provato a fare lo stesso ma non ha funzionato. Nonostante abbia impostato query_var
su false
, riesco ancora a visitare i link delle pagine singole. Puoi aiutarmi?

@iSaumya prova a svuotare i tuoi permalink (vai nella pagina dei permalink e salva di nuovo) o usa il comando wp-cli wp rewrite flush && wp cache flush

Non funziona più (agosto 2022). La nota che le visualizzazioni singole sono state rimosse non esiste più nemmeno nella documentazione.

@blorf la nota è ancora nella documentazione - è elencata sotto publicly_queryable

Un modo più semplice per farlo può essere passare i seguenti argomenti durante la registrazione del Custom Post Type
register_post_type('sample_post_type',array(
'labels' => array(
'name' => _x('Post di Esempio', 'nome generale del post type'),
'singular_name' => _x('Post di Esempio', 'nome singolare del post type')
),
'public' => true,
'exclude_from_search' => true,
'show_in_admin_bar' => false,
'show_in_nav_menus' => false,
'publicly_queryable' => false,
'query_var' => false
));

In realtà avresti bisogno che publically_querable
sia impostato su true affinché gli archivi dei Post Type funzionino.

Questo non funziona per me. Quando provo ad accedere all'archivio, viene semplicemente reindirizzato alla homepage

Uno. Dal tuo file functions.php.
add_action( 'template_redirect', 'redirect_cpt_singular_posts' );
function redirect_cpt_singular_posts() {
if ( is_singular('your-cpt-slug') ) {
wp_redirect( home_url(), 302 );
exit;
}
}
Due. Dal tuo file single.cpt.php:
<?php wp_redirect( home_url() ); exit; ?>

Mi piaceva la seconda opzione. Ma ho bisogno di sapere se ci sono svantaggi con questa seconda opzione.

@user2584538 Se non hai un file personalizzato single-cpt_name.php
non potresti farlo. Se metti la funzione in un semplice file plugin, potresti attivarlo/disattivarlo senza modificare alcun file.

Basandomi sulla risposta davvero buona di Sven, ho riscritto la sua funzione per rendere più semplice aggiungere più tipi di post utilizzando in_array()
nell'istruzione if e poi reindirizzando alla pagina archivio invece che alla home page.
(tra l'altro, penso che impostare query_var
e/o publically_queryable
su false disabiliti non solo le viste singole, ma anche la vista archivio nativa, sovrascrivendo 'has_archive' => true
. In quel caso puoi comunque configurare una WP_query personalizzata e creare la tua pagina archivio, in un template, ma la query principale non lo farà più, giusto?)
function fq_disable_single_cpt_views() {
$queried_post_type = get_query_var('post_type');
$cpts_without_single_views = array( 'my-post-type', 'my-other-post-type' );
if ( is_single() && in_array( $queried_post_type, $cpts_without_single_views ) ) {
wp_redirect( home_url( '/' . $queried_post_type . '/' ), 301 );
exit;
}
}
add_action( 'template_redirect', 'fq_disable_single_cpt_views' );

era una buona idea, ma non funziona se cambi il reindirizzamento per i CPT

Ho modificato la tua riga wp_redirect in wp_redirect( get_post_type_archive_link( $queried_post_type ), 301 );
funziona perfettamente!

Se desideri disabilitare completamente la visualizzazione singola di un custom post type nel frontend ma mantenere la possibilità di visualizzare la pagina archivio, le cose si complicano leggermente.
Impostare publicly_queryable
a false
o rewrite
a false
impedirà la visualizzazione sia della vista singola che dell'archivio. Non esiste un flag negli argomenti della funzione register_post_type
per prevenire la creazione delle regole di rewrite solo per la vista singola.
https://github.com/WordPress/WordPress/blob/5.2.3/wp-includes/class-wp-post-type.php#L540
Tuttavia, puoi rimuovere il tag di rewrite dopo aver registrato il tuo post type e questo lascerà intatte le regole di rewrite per la vista archivio, rimuovendo solo quelle per la vista singola.
/**
* Registra il post type per gli eventi
*/
function wpse_128636_register_event_post_type() {
$labels = array(
'name' => __( 'Eventi' ),
'singular_name' => __( 'Evento' ),
'add_new' => __( 'Aggiungi nuovo' ),
'add_new_item' => __( 'Aggiungi nuovo' ),
'edit_item' => __( 'Modifica' ),
'new_item' => __( 'Nuovo' ),
'view_item' => __( 'Visualizza' ),
'search_items' => __( 'Cerca' ),
'not_found' => __( 'Non trovato' ),
'not_found_in_trash' => __( 'Nessun Evento trovato nel cestino' ),
'parent_item_colon' => __( 'Genitore' ),
'menu_name' => __( 'Eventi' ),
);
$args = array(
'labels' => $labels,
'hierarchical' => false,
'supports' => array( 'title', 'page-attributes' ),
'public' => true,
'show_ui' => true,
'show_in_menu' => true,
'show_in_nav_menus' => true,
'publicly_queryable' => true,
'exclude_from_search' => true,
'has_archive' => true,
'rewrite' => array('slug' => 'evento'),
'capability_type' => 'post',
);
register_post_type( 'event', $args );
remove_rewrite_tag( '%event%' ); // Questa riga rimuoverà le regole di rewrite per la vista singola degli eventi
}
add_action( 'init', 'wpse_128636_register_event_post_type' );
Un ulteriore vantaggio è che da ora in poi puoi creare semplici pagine WordPress utilizzando la struttura dei permalink del post type evento (evento/pagina-semplice
), il che può essere utile in siti web complessi.
Ricorda di svuotare le regole di rewrite dopo aver modificato il codice.

Questa dovrebbe essere la risposta accettata, è breve, semplice e non interferisce con le pagine di archivio.

In WordPress 5.9.0
è stato aggiunto un nuovo filtro che consente non solo di disabilitare il single post ma anche di rimuovere qualsiasi link ad esso dagli schermi di amministrazione.
add_filter( 'is_post_type_viewable', function( $is_viewable, $post_type ) {
if ( 'sample_post_type' === $post_type->name ) {
return false;
}
return $is_viewable;
}, 10, 2 );
Il single post non verrà caricato ma se si inserisce l'URL manualmente, verrà caricata la home page invece di un 404. Per mostrare un 404 invece della home page, è possibile rimuovere la regola di rewrite dopo la registrazione del post type.
remove_rewrite_tag( '%sample_post_type%' );
Dopo aver apportato queste modifiche sarà necessario ripulire le regole di rewrite.
Utilizzando questi 2 metodi si raggiungerà l'obiettivo senza template aggiuntivi, redirects e link rotti nell'admin.

La mia soluzione attuale (principalmente "la soluzione di reindirizzamento") con una leggera differenza nell'implementazione.
Questo manterrà abilitate le pagine di archivio (has_archive = TRUE
)
Ma ti permetterà di abilitare o disabilitare le pagine singole quando usi register_post_type()
con x_has_single = TRUE
(il parametro viene passato insieme alle proprietà dell'oggetto post type).
add_action( 'init', function() {
$args = [
... // altre variabili
'public' => FALSE,
'publicly_queryable' => TRUE,
'show_ui' => TRUE,
'has_archive' => 'customers',
'rewrite' => [ 'slug' => 'customers', 'with_front' => FALSE ],
'x_has_single' => FALSE,
];
register_post_type( 'customers', $args );
} );
add_action( 'template_redirect', function() {
$post_type = get_post_type() ?: FALSE;
$post_type_obj = get_post_type_object( $post_type );
$has_single = $post_type_obj->x_has_single ?? TRUE;
if ( FALSE === $has_single && $post_type && is_singular( $post_type ) ) {
wp_redirect( get_post_type_archive_link( $post_type ) ?: '/', 301 );
exit;
}
} );
