f in x
Custom Post Types e Taxonomy in WordPress senza plugin: guida operativa per sviluppatori
> cd .. / HUB_EDITORIALE > Visualizza in Inglese
Analisi dei dati e metriche

Custom Post Types e Taxonomy in WordPress senza plugin: guida operativa per sviluppatori

[2026-06-05] Author: Ing. Calogero Bono

Hai mai aperto il pannello di amministrazione di un WordPress e pensato: “Qui mi servirebbe un tipo di contenuto che non sia ‘Articoli’ o ‘Pagine’”? Perfetto. Se gestisci un portale immobiliare, un sito di corsi, un catalogo prodotti personalizzato — o anche solo una sezione “Testimonianze” — la soluzione non è un plugin da 10 euro che ti rallenta il sito. La soluzione è scrivere codice pulito, che controlli tu.

Noi di Meteora Web lo facciamo da anni. Abbiamo costruito piattaforme con proprietà immobiliari, portfolio progetti, schede tecniche, eventi. Sempre partendo da functions.php o da un plugin mu (must-use). Il motivo? Un plugin ready-made ti dà il 90% di ciò che non ti serve e il 50% di ciò che ti serve, ma con 500 righe di PHP in più, query lente e interfacce che non assomigliano al tuo progetto.

In questa guida vediamo come registrare Custom Post Types (CPT) e Taxonomy personalizzate in WordPress, senza plugin. Impariamo a farlo bene: con rewrite puliti, permessi corretti, metabox custom e — soprattutto — testing con dati reali.

Perché registrare un CPT manualmente?

Immagina un cliente che vende corsi online. Ha bisogno di un tipo di contenuto “Corso” con campi come durata, livello, prezzo. Con i normali Articoli dovresti ricorrere a categorie e tag forzati, e i campi extra li infileresti in ACF (altro plugin). Ma un CPT nativo ti dà una tassonomia personalizzata per argomento del corso, un rewrite URL pulito /corsi/nome-corso/, e la possibilità di separare nettamente la logica di business. Noi lo abbiamo fatto per un cliente che vendeva corsi di formazione professionale: la differenza in termini di manutenzione e performance è stata netta.

Ecco i vantaggi concreti:

  • Controllo totale: modifichi ogni parametro senza dipendere da aggiornamenti esterni.
  • Pulizia del database: nessuna tabella extra di plugin, solo wp_posts con post_type = 'corso'.
  • Velocità: query WP_Query più mirate, senza filtri di plugin che girano in background.
  • SEO: rewrite slug e permalink esattamente come vuoi tu.

Struttura base: registrare un Custom Post Type

WordPress mette a disposizione la funzione register_post_type() da chiamare durante l'hook init. Mettiamo il codice in un file separato, ad esempio /wp-content/mu-plugins/cpt-corsi.php (così non dipende dal tema).

Il codice minimo funzionante


add_action('init', function() {
    $labels = [
        'name'               => 'Corsi',
        'singular_name'      => 'Corso',
        'add_new'            => 'Aggiungi Corso',
        'add_new_item'       => 'Aggiungi nuovo Corso',
        'edit_item'          => 'Modifica Corso',
        'view_item'          => 'Vedi Corso',
        'search_items'       => 'Cerca Corsi',
        'not_found'          => 'Nessun corso trovato',
        'not_found_in_trash' => 'Nessun corso nel cestino',
    ];

    $args = [
        'labels'             => $labels,
        'public'             => true,
        'has_archive'        => true,
        'rewrite'            => ['slug' => 'corsi'],
        'supports'           => ['title', 'editor', 'thumbnail', 'excerpt'],
        'menu_icon'          => 'dashicons-welcome-learn-more',
        'show_in_rest'       => true, // necessario per Gutenberg e API
    ];

    register_post_type('corso', $args);
});

Attenzione: show_in_rest = true abilita Gutenberg e l'API REST. Se stai costruendo un frontend headless o usi Vue/React, è essenziale. Noi lo attiviamo sempre, anche per siti classici — l'API REST non pesa se non la chiami.

Taxonomy personalizzate: legare i contenuti tra loro

Un CPT senza taxonomy è come un libro senza indice. La taxonomy ti permette di raggruppare, filtrare, navigare. Per i corsi, potresti avere “Argomento” (gerarchica, come le categorie) e “Livello” (non gerarchica, come i tag).

Registrare una taxonomy gerarchica (es. Argomento)


add_action('init', function() {
    $labels = [
        'name'              => 'Argomenti',
        'singular_name'     => 'Argomento',
        'search_items'      => 'Cerca Argomenti',
        'all_items'         => 'Tutti gli Argomenti',
        'parent_item'       => 'Argomento padre',
        'parent_item_colon' => 'Argomento padre:',
        'edit_item'         => 'Modifica Argomento',
        'update_item'       => 'Aggiorna Argomento',
        'add_new_item'      => 'Aggiungi nuovo Argomento',
        'new_item_name'     => 'Nuovo Argomento',
        'menu_name'         => 'Argomenti',
    ];

    $args = [
        'labels'            => $labels,
        'hierarchical'      => true,
        'public'            => true,
        'rewrite'           => ['slug' => 'argomento'],
        'show_in_rest'      => true,
        'show_admin_column' => true,
    ];

    register_taxonomy('argomento_corso', 'corso', $args);
});

Nota il parametro show_admin_column: mostra la taxonomy nella lista dei post del CPT in amministrazione. Un dettaglio che fa risparmiare tempo ogni giorno.

Registrare una taxonomy non gerarchica (es. Livello)

Stessa funzione, ma con hierarchical => false e slug diverso:


register_taxonomy('livello_corso', 'corso', [
    'hierarchical' => false,
    'labels'       => [
        'name'          => 'Livelli',
        'singular_name' => 'Livello',
    ],
    'rewrite'      => ['slug' => 'livello'],
    'show_in_rest' => true,
]);

Errori comuni (e come evitarli)

Li abbiamo visti decine di volte, specialmente su siti “fatti bene” ma con scorciatoie.

1. Mancato flush delle rewrite rules

Dopo aver registrato un CPT o una taxonomy, devi forzare il refresh delle regole di riscrittura. Vai su Impostazioni → Permalink e clicca “Salva modifiche” (anche senza cambiare niente). In produzione, non fare il flush a ogni richiesta: chiama flush_rewrite_rules() solo una volta, all'attivazione del tuo mu-plugin.


register_activation_hook(__FILE__, function() {
    // Simula la registrazione e poi flush
    // (meglio richiamare la funzione di registrazione qui)
    flush_rewrite_rules();
});

2. Slug in conflitto

Se hai già una pagina chiamata “corsi” e registri un CPT con slug ‘corsi’, scatta un 404. Verifica sempre che lo slug non sia già occupato da pagine, pagine di archivio o altri CPT. Noi usiamo un semplice controllo: var_dump(get_posts(['post_type' => 'any', 'name' => 'slug_candidato']));.

3. Dimenticare show_in_rest

Senza show_in_rest => true, il tuo CPT non apparirà nell'editor Gutenberg e non sarà accessibile via API REST. Se il client usa il block editor, salta tutto.

Metabox personalizzati: dati extra senza ACF

I CPT servono a poco se non hai campi aggiuntivi. Per un corso: durata (numero), livello (select), prezzo (numero). Invece di ACF (che aggiunge ~600 KB al caricamento), puoi creare metabox semplici con add_meta_box.

Esempio: metabox prezzo e durata


add_action('add_meta_boxes', function() {
    add_meta_box(
        'corso_meta',
        'Dettagli Corso',
        function($post) {
            $prezzo = get_post_meta($post->ID, '_corso_prezzo', true);
            $durata = get_post_meta($post->ID, '_corso_durata', true);
            wp_nonce_field('corso_meta_nonce', 'corso_meta_nonce');
            ?>
            



Nota: i nomi dei campi con prefisso underscore (_corso_prezzo) sono nascosti dalla lista dei custom fields nell'admin — più pulito.

Query sul frontend: mostrare i CPT

Una volta registrati, puoi recuperare i corsi con WP_Query o get_posts. Esempio per la pagina archivio automatica:


// archive-corso.php
while (have_posts()) {
    the_post();
    $prezzo = get_post_meta(get_the_ID(), '_corso_prezzo', true);
    ?>
    

Prezzo: €

Se vuoi filtrare per taxonomy, usa WP_Query con tax_query:


$corsi_avanzati = new WP_Query([
    'post_type' => 'corso',
    'tax_query' => [[
        'taxonomy' => 'livello_corso',
        'field'    => 'slug',
        'terms'    => 'avanzato',
    ]],
]);

Checklist operativa per chi implementa

  1. Definisci i CPT necessari: non uno di più del necessario. Ogni CPT è una nuova entità da mantenere.
  2. Usa un mu-plugin: meglio di functions.php perché sopravvive ai cambi di tema.
  3. Abilita show_in_rest: anche se non usi REST ora, preparati al futuro.
  4. Flush delle rewrite rules: fallo al momento dell'attivazione, non a ogni pagina.
  5. Testa con dati reali: crea 10-15 post, inserisci custom field, verifica la ricerca.
  6. Controlla la velocità: con molti CPT, potresti aver bisogno di indicizzare i metadati. Noi usiamo wp_postmeta indicizzato su meta_key di default — va bene per la maggior parte dei casi.

In sintesi — cosa fare adesso

  1. Vai in /wp-content/mu-plugins/ e crea un file cpt-personalizzati.php.
  2. Copia il codice di registrazione del CPT e delle taxonomy di esempio sopra.
  3. Adatta labels, slug e supports alle tue esigenze.
  4. Salva, vai su Impostazioni → Permalink e clicca “Salva modifiche”.
  5. Crea un paio di post di test, assegna taxonomy, inserisci custom field.
  6. Se tutto funziona, congratulazioni: hai appena smesso di dipendere da un plugin per il content management.

Se vuoi approfondire la gestione dei dati con il REST API, dai un’occhiata alla nostra guida su Express.js per capire come consumare i dati in un frontend moderno. E se stai valutando se usare Vue o React per un'app headless, leggi la nostra comparazione tra Composition API e Options API.

Sponsored Protocol

Ing. Calogero Bono

> AUTHOR_EXTRACTED

Ing. Calogero Bono

Co-founder di Meteora Web. Ingegnere informatico, sviluppo ecosistemi digitali ad alte prestazioni. AI, automazione, SEO tecnica e infrastrutture web. Scrivo di tecnologia per rendere complesso… semplice.

[ Read Full Dossier ]

Hai bisogno di applicare questa strategia?

Esegui il protocollo di contatto per iniziare un progetto con noi.

> INIZIA_PROGETTO

Sponsored