JSON-LD WordPress senza plugin: guida implementazione

13 agosto 20267 minSEO
In breveAI

Guida tecnica per implementare Schema.org JSON-LD su WordPress senza plugin: codice production-ready per Organization, Article, BreadcrumbList e FAQ con hooks corretti.

Perché implementare JSON-LD manualmente

I plugin SEO come Yoast o RankMath aggiungono JSON-LD automaticamente, ma con tre problemi ricorrenti:

  • Output generico che non sfrutta metadati custom specifici dei tuoi progetti
  • Overhead di codice e query database non necessarie se serve solo structured data
  • Conflitti quando gestisci più siti client con requisiti diversi

L’implementazione manuale via wp_head o wp_footer ti dà controllo totale con ~50 righe di codice nel functions.php del tema child o in un mu-plugin dedicato.

Secondo i dati di HTTPArchive (gennaio 2026), il 73% dei siti WordPress usa ancora plugin per structured data, ma le agenzie che gestiscono fleet di siti stanno migrando verso soluzioni custom per ridurre dipendenze e migliorare performance.

Struttura base: Organization e WebSite

Ogni sito dovrebbe dichiarare l’entità principale (Organization o Person) e il WebSite con search action. Questo codice va nel functions.php:

<?php
function agencypilot_schema_organization() {
    if ( ! is_front_page() ) return;
    
    $schema = [
        '@context' => 'https://schema.org',
        '@graph' => [
            [
                '@type' => 'Organization',
                '@id' => home_url( '/#organization' ),
                'name' => get_bloginfo( 'name' ),
                'url' => home_url( '/' ),
                'logo' => [
                    '@type' => 'ImageObject',
                    'url' => get_theme_mod( 'custom_logo' ) 
                        ? wp_get_attachment_image_url( get_theme_mod( 'custom_logo' ), 'full' )
                        : '',
                ],
                'sameAs' => [
                    get_option( 'social_facebook', '' ),
                    get_option( 'social_linkedin', '' ),
                ]
            ],
            [
                '@type' => 'WebSite',
                '@id' => home_url( '/#website' ),
                'url' => home_url( '/' ),
                'name' => get_bloginfo( 'name' ),
                'publisher' => [
                    '@id' => home_url( '/#organization' )
                ],
                'potentialAction' => [
                    '@type' => 'SearchAction',
                    'target' => home_url( '/?s={search_term_string}' ),
                    'query-input' => 'required name=search_term_string'
                ]
            ]
        ]
    ];
    
    echo '<script type="application/ld+json">' . wp_json_encode( $schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) . '</script>';
}
add_action( 'wp_head', 'agencypilot_schema_organization' );
?>

Note tecniche:

  • Usa @graph per collegare entità multiple in un unico blocco JSON-LD
  • @id con fragment (#organization) crea riferimenti riutilizzabili
  • JSON_UNESCAPED_SLASHES evita escape non necessari degli URL
  • Filtra i social con array_filter() se vuoi rimuovere valori vuoti

Article Schema per post e custom post type

Per post singoli, implementa Article (o varianti come BlogPosting, NewsArticle). Questo codice gestisce autore, immagine featured e date:

<?php
function agencypilot_schema_article() {
    if ( ! is_singular( ['post', 'case-study'] ) ) return;
    
    $post_id = get_the_ID();
    $author_id = get_post_field( 'post_author', $post_id );
    
    $schema = [
        '@context' => 'https://schema.org',
        '@type' => 'Article',
        '@id' => get_permalink() . '#article',
        'headline' => get_the_title(),
        'description' => get_the_excerpt(),
        'image' => has_post_thumbnail() ? get_the_post_thumbnail_url( $post_id, 'full' ) : '',
        'datePublished' => get_the_date( 'c', $post_id ),
        'dateModified' => get_the_modified_date( 'c', $post_id ),
        'author' => [
            '@type' => 'Person',
            'name' => get_the_author_meta( 'display_name', $author_id ),
            'url' => get_author_posts_url( $author_id )
        ],
        'publisher' => [
            '@id' => home_url( '/#organization' )
        ],
        'mainEntityOfPage' => [
            '@type' => 'WebPage',
            '@id' => get_permalink()
        ]
    ];
    
    echo '<script type="application/ld+json">' . wp_json_encode( $schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) . '</script>';
}
add_action( 'wp_head', 'agencypilot_schema_article' );
?>

Dettagli implementativi:

  • Usa formato ISO 8601 ('c') per le date, richiesto da Google
  • Collega publisher all’Organization tramite @id reference
  • Per NewsArticle aggiungi campi articleSection e wordCount
  • Valida sempre con Rich Results Test di Google

BreadcrumbList per navigazione gerarchica

Le breadcrumb aiutano Google a capire la struttura del sito. Implementazione per post con categoria singola:

<?php
function agencypilot_schema_breadcrumb() {
    if ( is_front_page() ) return;
    
    $items = [[
        '@type' => 'ListItem',
        'position' => 1,
        'name' => 'Home',
        'item' => home_url( '/' )
    ]];
    
    $position = 2;
    
    if ( is_singular( 'post' ) ) {
        $category = get_the_category()[0];
        $items[] = [
            '@type' => 'ListItem',
            'position' => $position++,
            'name' => $category->name,
            'item' => get_category_link( $category->term_id )
        ];
    }
    
    $items[] = [
        '@type' => 'ListItem',
        'position' => $position,
        'name' => get_the_title(),
        'item' => get_permalink()
    ];
    
    $schema = [
        '@context' => 'https://schema.org',
        '@type' => 'BreadcrumbList',
        'itemListElement' => $items
    ];
    
    echo '<script type="application/ld+json">' . wp_json_encode( $schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) . '</script>';
}
add_action( 'wp_head', 'agencypilot_schema_breadcrumb' );
?>

Estensioni comuni:

  • Per custom post type con tassonomie custom, sostituisci get_the_category() con get_the_terms()
  • Per e-commerce WooCommerce, aggiungi categoria prodotto e shop base
  • Gestisci gerarchie categoria multiple scegliendo la primary (Yoast) o la prima

FAQ Schema per contenuti Q&A

Se usi blocchi Gutenberg o ACF Repeater per FAQ, questo codice genera FAQPage schema automaticamente:

<?php
function agencypilot_schema_faq() {
    if ( ! is_singular() ) return;
    
    // Esempio con ACF Repeater
    $faqs = get_field( 'faq_items' ); // [{"question": "", "answer": ""}]
    if ( ! $faqs ) return;
    
    $questions = [];
    foreach ( $faqs as $faq ) {
        $questions[] = [
            '@type' => 'Question',
            'name' => $faq['question'],
            'acceptedAnswer' => [
                '@type' => 'Answer',
                'text' => wp_strip_all_tags( $faq['answer'] )
            ]
        ];
    }
    
    $schema = [
        '@context' => 'https://schema.org',
        '@type' => 'FAQPage',
        'mainEntity' => $questions
    ];
    
    echo '<script type="application/ld+json">' . wp_json_encode( $schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) . '</script>';
}
add_action( 'wp_head', 'agencypilot_schema_faq' );
?>

Considerazioni:

  • Google mostra FAQ rich snippet solo per contenuti effettivamente visibili nella pagina
  • Usa wp_strip_all_tags() per rimuovere HTML dalla risposta, oppure converti in plain text
  • Massimo 1 FAQPage schema per pagina, non combinare con QAPage

Performance e testing in ambiente multi-client

Quando gestisci JSON-LD per decine di siti client:

  1. Centralizza in mu-plugin: crea wp-content/mu-plugins/agency-schema.php con configurazione per site_id
  2. Usa transient cache: per Organization schema che non cambia, usa set_transient() con durata 1 mese
  3. Hook priority: esegui dopo altri plugin SEO con add_action('wp_head', 'function', 99)
  4. Conditional loading: evita output su pagine non indicizzabili (login, admin preview)

Esempio di verifica automatizzata con WP-CLI custom command:

wp eval "echo json_encode(agencypilot_schema_organization_data());" | jq

Per monitoraggio continuo su fleet di siti, puoi integrare validazione Schema.org nell’uptime check di AgencyPilot, verificando presence e validità del JSON-LD a ogni scan.

Checklist implementazione completa

Prima di considerare l’implementazione production-ready:

  • Valida ogni tipo di schema con Google Rich Results Test e Schema.org validator
  • Verifica che non ci siano duplicati JSON-LD (disabilita output da plugin attivi)
  • Testa con view-source: che il JSON sia valido (niente caratteri escaped male)
  • Controlla Search Console dopo 2-3 settimane per errori Enhancements
  • Documenta quale schema è attivo su quali post type per il team

I rich snippet non sono ranking factor diretto, ma il CTR aumenta mediamente del 15-30% secondo studi Backlinko 2025, quindi l’impatto su traffico organico è misurabile.

FAQ

Devo usare @graph o singoli script JSON-LD separati?

@graph è preferibile quando hai entità collegate (Organization + WebSite, Article + BreadcrumbList) perché permette di usare @id reference evitando duplicazioni. Per schema indipendenti come FAQ puoi usare script separati, Google li processa comunque correttamente.

Come gestire JSON-LD multilingua con WPML/Polylang?

Avvolgi le funzioni con check if (function_exists('pll_current_language')) e usa pll_home_url() invece di home_url(). Per Organization sameAs, crea array di social per lingua usando option con suffisso lingua (get_option('social_facebook_' . pll_current_language())).

Meglio wp_head o wp_footer per JSON-LD?

Google legge JSON-LD ovunque nel DOM, ma wp_head è standard e consigliato. Usa wp_footer solo se hai conflitti con altri script o vuoi priorità bassa. Evita di splittare: metti tutto in head per consistenza e facilità debug.

Come validare JSON-LD in staging prima del deploy?

Usa ngrok o LocalWP Live Link per esporre staging a Google Rich Results Test, oppure copia view-source del JSON e incollalo nel Schema.org validator. Per CI/CD, integra schema-validator npm package nei test automatici pre-deploy.

I transient cache di Schema.org possono causare contenuto stale?

Sì, se usi transient per Article schema con date modificate. Usa cache solo per dati statici (Organization, WebSite). Per contenuti dinamici, implementa invalidazione cache con hook save_post che fa delete_transient('schema_article_' . $post_id).

Gestisci i siti WordPress dei tuoi clienti?

AgencyPilot ti dà report AI, uptime monitoring, backup e portale clienti in un’unica dashboard. Gratis per 3 siti.

Prova gratis
Leggi anche
Tutti gli articoli
Tutti gli articoli