Scrivere un plugin WordPress direttamente dalla Dashboard andando subito al nòcciolo e saltando tutte le parti noiose

Volevo aggiungere una sezione link a questo sito per archiviare le notizie interessanti che incontro in giro per la Rete e per avere un unico indirizzo da condividere su Facebook e Linkedin.

Potevo installare un plugin già pronto, ma avrei dovuto cercarne e trovarne uno adatto, oppure potevo scriverne uno io, ma avrei dovuto preparare la struttura di cartelle e file necessari per il codice che spesso contiene ripetizioni di blocchi simili {chi lo ha già fatto sa di cosa sto parlando ;-)}.
Entrambe le soluzioni hanno dunque qualche punto debole.

Ho deciso quindi di provare ad usare i plugin Pods e Code Snippets per prendere il meglio da ciascuna delle due opzioni precedenti: ottenere un plugin che faccia esattamente quello che mi serve concentrandomi solo sul codice che implementa il comportamento del modulo.

Per prima cosa ho dunque scaricato e attivato i due plugin. Possiamo pensare a ciascuno di essi come una specie di plugin potenziale perché per conto suo non fa assolutamente nulla ma compilando alcune pagine dalla Dashboard possiamo accelerare molto lo sviluppo, soprattutto grazie a Pods.

Il modello dei dati

Una volta scaricati i plugin possiamo subito dedicarci a progettare alla struttura del database. Per gestire la sezione link sarà sufficiente una sola entità informativa. L’ho chiamata News Link e avrà le seguenti caratteristiche:

TitlePlain Text
ImageFile / Image / Video
DescriptionWYSIWYG (Visual Editor)
URLWebsite
Date CreatedDate / Time
PermalinkPermalink (url-friendly)
Caratteristiche dell’entità News Link e loro tipologie

Ogni News Link avrà quindi un Titolo (Title) e una Descrizione (Description, gestibile tramite un editor visuale), un’immagine (image), un’URL per memorizzare l’indirizzo del link, una data di creazione (Date Created, questo è l’unico campo tra quelli predefiniti che ho conservato) e un codice testuale univoco per individuare la scheda del Link in maniera SEO friendly (Permalink).

Pods permette di definire due tipi di entità: i Custom Post Type (CPT), che vengono memorizzati nelle tabelle usate da WordPress per i post o le pagine, e gli Advanced Custom Type (ACT), che sono completamente autonomi e ciascuno è memorizzato in una tabella dedicata.
La seconda opzione è un po’ più azzardata {avanzata, appunto :-)} perché dovremo pensare noi ad alcuni pezzi del modulo, con i Custom Post Type sarebbe stato molto più semplice.

Dato che spesso uso questo sito come cavia per testare nuove soluzioni ho deciso di scegliere proprio questa possibilità.

Ho dunque creato un Advanced Custom Type di nome News Link e ho modificato la lista dei campi predefiniti con quelli che mi interessavano:

Poi, per semplicità, ho scelto di lasciare che fosse Pods a creare le pagine per la gestione dei link:

Nella Dashboard del sito comparirà una nuova voce “News Link” che porterà all’elenco dei link che al momento sarà ovviamente vuoto.

Se andiamo a vedere cosa è successo nel database possiamo constatare come sia stata creata una nuova tabella di nome wp_pods_news_link con la seguente struttura:

Struttura della tabella wp_pods_news_link

Nella tabella sono presenti i 4 campi testuali e la data ma manca completamente ogni riferimento all’immagine.
Questo perché nella configurazione delle caratteristiche di quel campo ho scelto di archiviare le immagini nella Media Library di WordPress.
Le informazioni relative all’immagine saranno quindi memorizzate come Meta Tag di WordPress nella tabella wp_postmeta. Sarà poi Pods (tramite la tabella wp_podsrel) a memorizzare la relazione tra il record della tabella wp_pods_news_link (dove sono memorizzate le informazioni alfanumeriche) e quello della tabella wp_postmeta.

Osserviamo anche che, a parte quello di chiave primaria, non ci sono indici. Se avrò problemi di prestazione forse dovrò crearne qualcuno per migliorare i tempi di risposta.

Ora possiamo caricare i primi record con le pagine del back-office costruite da Pods:

La presentazione delle informazioni

Per la visualizzazione ho scelto di usare una struttura abbastanza comune: una pagina di elenco che mostri la lista degli elementi e da cui si acceda alla pagina di dettaglio di ciascun elemento.
Le informazioni saranno praticamente le stesse ma la pagina di dettaglio è utile per la condivisione sui social netowork.

Per la pagina di elenco ho usato lo Shortcode di Pods che permette di eseguire delle estrazione di elementi.
Ho creato una nuova pagina (che ho intitolato “Notizie selezionate in giro per la Rete“) e ho inserito il seguente blocco HTML:

[pods name="news_link" pagination="true" limit="10" orderby="created DESC"]
<h2><a href="news-link/{@permalink, esc_attr}">{@title}</a></h2>
{@image._img.thumbnail}
<div>
  {@description}
  Fonte: {@url}
</div>
[/pods]

Ho anche indicato direttamente nello Shortcode il blocco HTML che Pods userà per visualizzare ogni elemento trovato.

Se fino a questo punto le funzioni automatiche di Pods ci hanno semplificato molto il lavoro ora per procedere con la creazione della pagina di dettaglio dovremo cominciare a scrivere un po’ di codice per integrarci con il normale funzionamento di WordPress.
Per farlo ci appoggeremo a Code Snippets evitando di dover gestire un plugin ordinario.

Il collegamento tra pagina di elenco e pagina di dettaglio avverrà con un link che avrà la struttura <URL della pagina lista>/news-link/<permalink dello News Link>.
Si tratta di un URL inesistente ma la cui parte centrale, che è sempre “/news-link/”, ci permetterà di intercettare la richiesta e modificare il comportamento predefinito di WordPress.

Passiamo dunque alla scrittura del codice.

Per prima cosa rileveremo la richiesta di una pagina di dettaglio (cercheremo la stringa “/news-link/” nell’URL), estrarremo il permalink del News Link (è quello che segue “/news-link/”) e memorizzeremo in una variabile globale le informazioni dell’elemento:

// Intercept the call for the News Link detail page
function art_init() {
	global $_art_pod;
	
	$url_parts = explode('/', rtrim(explode('?', $_SERVER['REQUEST_URI'])[0], '/'));
	$permalink = end($url_parts);
	if (prev($url_parts)=="news-link") {
		$_art_pod = pods('news_link', $permalink);
		$_SERVER['ART_PAGENAME'] = prev($url_parts);
	}
}
add_action('init', 'art_init');

Poi dovremo dire a WordPress quale pagina realmente esistente deve caricare. Ho deciso di far caricare la pagina con l’elenco tanto poi ne cambierò il contenuto:

// Call parent page (the page before '/news-link/') for the News Link detail page
function art_request($request) {
	global $_art_pod;
	if ($_SERVER['ART_PAGENAME'] && $_art_pod) {
		$request['pagename'] = $_SERVER['ART_PAGENAME'];
		$request['error'] = '';		
	}

    return $request;
}
add_filter('request', 'art_request');

Nella pagina con l’elenco, però, dovremo fare alcune sistemazioni.

Per prima cosa imposteremo il tag Title corretto:

// Set the Title for the News Link detail page
function art_document_title_parts($title) {
	global $_art_pod;
	if ($_SERVER['ART_PAGENAME'] && $_art_pod) {
		$title['title'] = $title['title'].' - '.$_art_pod->field('title');
		return $title;
	} else {
		return $title;
	}
};
add_filter('document_title_parts', 'art_document_title_parts', 10, 1);

Poi sistemeremo il Canonical URL:

// Set the Canonical URL for the News Link detail page
function art_get_canonical_url($canonical_url, $post) {
	global $_art_pod;
	if ($_SERVER['ART_PAGENAME'] && $_art_pod) {
	    return rtrim($canonical_url, '/').'/news-link/'.$_art_pod->field('permalink'); 
	} else {
	    return $canonical_url; 
	}
}; 
add_filter('get_canonical_url', 'art_get_canonical_url', 10, 2);

Cancelleremo i link per lo Shortlink e per il protocollo Oembed:

// Clear the Shortlink for the News Link detail page
function art_get_shortlink($shortlink, $id, $context, $allow_slugs) { 
	global $_art_pod;
	if ($_SERVER['ART_PAGENAME'] && $_art_pod) {
	    return ''; 
	} else {
	    return $shortlink; 
	}
}; 
add_filter('get_shortlink', 'art_get_shortlink', 10, 4);


// Clear the JSON Oembed link for the News Link detail page
function art_oembed_discovery_links($output) { 
	global $_art_pod;
	if ($_SERVER['ART_PAGENAME'] && $_art_pod) {
	    return ''; 
	} else {
	    return $output; 
	}
};         
add_filter('oembed_discovery_links', 'art_oembed_discovery_links', 10, 1);

Aggiungeremo i Meta tag per l’Open Graph, utili per la condivisione della pagina su Facebook:

// Put Meta tags for Facebook Open Graph for the News Link detail page
function art_wp_head() {
	global $_art_pod;
	if ($_SERVER['ART_PAGENAME'] && $_art_pod) {
		?>
<meta property="og:locale" content="<?php echo(esc_attr(get_locale())) ?>" />
<meta property="og:site_name" content="<?php echo(esc_attr(get_bloginfo('name'))) ?>" />
<meta property="og:url" content="<?php echo(esc_attr($_SERVER['REQUEST_URI'])) ?>" />
<meta property="og:type" content="article" />
<meta property="og:title" content="<?php echo(esc_attr($_art_pod->field('title'))) ?>" />
<meta property="og:description" content="<?php echo(esc_attr($_art_pod->field('description'))) ?>" />
<meta property="og:image" content="<?php echo(esc_attr(pods_image_url($_art_pod->field('image'), 'full'))) ?>" />
		<?php
	}
}
add_action('wp_head', 'art_wp_head');

E finalmente sostituiremo il contenuto con quello specifico dello News Link che stiamo mostrando:

// Set the Content for the News Link detail page
function art_the_content($content) {
 	global $_art_pod;
    // Check if we are inside the main loop in a single Post and if is a News Link detail page
    if (is_singular() && in_the_loop() && is_main_query() && $_SERVER['ART_PAGENAME'] && $_art_pod) {
		$ret = "";
		$ret .= "<h2>".$_art_pod->field('title')."</h2>";
		$ret .= pods_image($_art_pod->field('image'), 'large');
		$ret .= "<div>";
		$ret .= $_art_pod->display('description');
		$ret .= "Fonte: ".$_art_pod->display('url');
		$ret .= "<div>";

        return $ret;
    }
 
    return $content;
}
add_filter( 'the_content', 'art_the_content', 10, 1);

Per semplicità ho cablato direttamente nel codice la struttura HTML del contenuto della pagina di dettaglio. Per operare in modo più rigoroso avrei dovuto creare un Template di Pods e usare quello.

Una nota a margine

Code Snippets prima del salvataggio esegue sempre un controllo sulla sintassi del codice scritto (e in caso di errore annulla la modifica) ma se ci sono errori logici che non riesce ad intercettare il sito si bloccherà e non riusciremo più ad accedere al codice per correggerlo.
Se dovesse succedere una simile eventualità sarà sufficiente disabilitare i plugin oppure disabilitare il solo snippet di codice cambiandone lo stato modificando direttamente la tabella che si chiama wp_snippets.

Conclusione

Siamo dunque arrivati al nostro obiettivo lavorando sempre dalla Dashboard e scrivendo il codice indispensabile.

Naturalmente una fase realizzativa semplificata non prescinde da una attenta progettazione iniziale. Quindi prima di lanciarsi a definire campi e scrivere codice è sempre meglio riflettere un po’ su come ottenere ciò che si desidera.

Anche il fatto di poter scrivere codice direttamente in un form non significa che dobbiamo farlo senza aver studiato bene il problema.

Attenzione che bloccare il sito è davvero semplice!

Il mio consiglio è di lavorare su un sito di sviluppo e usare le comode funzione di esportazione e importazione che entrambi i plugin hanno per trasferire le parti già verificate sul sito di produzione.


Alla fine però non è poi molto complicato e nella maggior parte dei casi si tratta di agganciarsi agli Hook di WordPress per modificarne o integrarne il comportamento. In questo caso la documentazione ufficiale e qualche ricerca mirata in Rete sono di grande aiuto.

Buon divertimento, dunque!

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *