Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Routing dinamico e pagine singole con Astro

Parliamo di routing dinamico e pagine singole con Astro nella creazione di un sito Web headless basato su WordPress
Parliamo di routing dinamico e pagine singole con Astro nella creazione di un sito Web headless basato su WordPress
Link copiato negli appunti

Nella lezione precedente abbiamo creato la pagina di un blog Astro prelevando i contenuti da un sito WordPress. Torniamo per un attimo al codice del file index.astro per analizzare l'attributo href dell'elemento a:

<a href={`/blog/${post.slug}/`}>
	<img src={typeof post._embedded['wp:featuredmedia'] !== "undefined" ? post._embedded['wp:featuredmedia']['0'].media_details.sizes.large.source_url : 'https://images.pexels.com/photos/270404/pexels-photo-270404.jpeg'} alt="" />
	<h4 class="title">{post.title.rendered}</h4>
	<FormattedDate date={post.date} />
</a>

Routing statico e routing dinamico

Di default, i file con estensione .astro, .html, .md, .mdx, .js e .ts presenti nella cartella src/pages diventano automaticamente pagine del sito. Il percorso di ogni pagina corrisponde al percorso e al nome del file all'interno della cartella. In questo caso parliamo di routing statico.

Quando il sito si compone di decine o centinaia di pagine, è poco pratico affidarsi al routing statico. Astro permette di specificare parametri di percorso dinamici nel nome del file per generare più pagine da uno stesso file, ad esempio [param].astro.

In modalità statica, le pagine sono generate al momento della build. Quindi è necessario predeterminare un elenco di valori corrispondenti per il parametro che costituisce il nome del file. Ciò avviene esportando la funzione getStaticPaths(), che dovrà restituire i diversi percorsi da generare.

Ad esempio, [author].astro definisce il parametro author. Nell'esempio che segue, vediamo come utilizzare getStaticPaths() nel file [author].astro in modo che restituisca un array di oggetti che contengano il parametro author:

---
export function getStaticPaths() {
	return [
		{params: {author: 'carlo'}},
		{params: {author: 'marco'}},
		{params: {author: 'anna'}},
	];
}
const { author } = Astro.params;
---
<div>Pagina di {author}!</div>

Il file [slug].astro

Ora torniamo al nostro progetto. Creiamo un file [slug].astro all'interno della cartella src/pages/blog e scriviamo il seguente codice:

---
import BlogPost from '../../layouts/BlogPost.astro';
import FormattedDate from '../../components/FormattedDate.astro';
const { slug } = Astro.params;
let res = await fetch(`https://developer.wordpress.org/news/wp-json/wp/v2/posts?slug=${slug}&_embed`);
let [post] = await res.json();
export async function getStaticPaths() {
	let data = await fetch("https://developer.wordpress.org/news/wp-json/wp/v2/posts?per_page=21");
	let posts = await data.json();
	return posts.map((post) => ({
		params: { slug: post.slug },
		props: { post: post },
	}));
}
---

Abbiamo importato il layout BlogPost e il componente FormattedDate. Abbiamo dichiarato la proprietà slug, recuperato il post corrente grazie alla Rest API di WordPress. Infine, abbiamo esportato la funzione getStaticPaths(). All'interno di essa abbiamo prima recuperato 21 articoli del blog WordPress, quindi mappato ogni post al corrispondente slug.

Se si dovesse aver bisogno di inserire nell'URL un percorso di file, basterà aggiungere il parametro rest nel nome del file .astro (ad esempio [...slug].astro).

Uso dei dati nel template del componente

Vediamo ora come utilizzare i dati nel template del componente:

<BlogPost title={post.title.rendered}>
	<article>
		<div class="hero-image">
			<img width={1020} height={510} src={typeof post._embedded['wp:featuredmedia'] !== "undefined" ? post._embedded['wp:featuredmedia']['0'].media_details.sizes.large.source_url : 'https://images.pexels.com/photos/270404/pexels-photo-270404.jpeg'} alt="" />
		</div>
		<div class="prose">
			<div class="title">
				<h1 set:html={post.title.rendered} />
				<FormattedDate date={post.date} />
			</div>
			<hr />
			<slot />
		</div>
		<Fragment set:html={post.content.rendered} />
	</article>
</BlogPost>

Rispetto al codice illustrato nella precedente lezione, qui abbiamo fatto ricorso ad alcune utility di Astro.

  • set:html è una direttiva Astro che permette di inserire una stringa HTML in un elemento. Il tag <h1> utilizzato nel codice qui sopra è equivalente a <h1>{post.title.rendered}</h1>.
  • L'elemento Fragment è utilizzato per evitare di racchiudere il valore di set:html in un container, ad esempio un elemento div. È utile in questo caso in quanto il contenuto del post include la struttura HTML generata da WordPress.

Il file BlogPost.astro

Ora creiamo il file BlogPost.astro nella cartella src/layouts e scriviamo il seguente codice:

---
import BaseHead from '../components/BaseHead.astro';
import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro';
import { SITE_TITLE, SITE_DESCRIPTION } from '../consts';
---
<html lang="en">
	<head>
		<BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />
		<style>...</style>
	</head>
	<body>
		<Header />
		<main>
			<slot />
		</main>
		<Footer />
	</body>
</html>

Non riportiamo il codice CSS, per il quale facciamo rinvio al repository GitHub del progetto. La pagina di un post sarà simile a quella dell'immagine che segue.

La pagina singola di un post di WordPress in un sito statico Astro

La pagina singola di un post di WordPress in un sito statico Astro

Archivi WordPress e paginazione dei risultati in Astro

Quando il numero di articoli cresce, può essere opportuno aggiungere al blog un sistema di paginazione. Possiamo gestire tutto con diverse chiamate all'API di WordPress. O lasciare che sia Astro a gestire la paginazione.

Astro, infatti, dispone nativamente della funzione paginate(). Questa genera automaticamente l'array restituito da getStaticPaths() con un URL per ogni pagina della collezione. In questo modo possiamo creare un archivio di post suddiviso in pagine. Creiamo, quindi, una pagina [page].astro in una nuova cartella src/pages/archive e scriviamo il seguente codice JavaScript:

---
import PostPreview from '../../layouts/PostPreview.astro';
import FormattedDate from '../../components/FormattedDate.astro';
export async function getStaticPaths({ paginate }) {
	const res = await fetch("https://developer.wordpress.org/news/wp-json/wp/v2/posts?per_page=21&_fields=id,slug,date,title,excerpt,content,link,_links&_embed=author,wp:featuredmedia,wp:term");
	const archivePages = await res.json();
	return paginate(archivePages, { pageSize: 7 });
}
type Props = any;
const { page } = Astro.props;
---

L'URL trasmessa alla Rest API rimane la stessa del blog. Il risultato in formato JSON viene passato come primo argomento alla funzione paginate. Il secondo argomento è un oggetto i cui elementi stabiliscono le proprietà della paginazione. Qui pageSize stabilisce il numero di elementi di ogni pagina. Nell'URL, il parametro page sarà convertito nel numero di pagina.

Il template del file [page].astro

Passiamo ora al codice del template del file [page].astro.

<PostPreview tytle="Blog">
<section>
    <h1>Archives</h1>
	<h3>Page {page.currentPage}</h3>
	<ul>
	{
		page.data.map((post) => (
			<li>
				<a href={`/blog/${post.slug}/`}>
					<img src={typeof post._embedded['wp:featuredmedia'] !== "undefined" ? post._embedded['wp:featuredmedia']['0'].media_details.sizes.large.source_url : 'https://images.pexels.com/photos/270404/pexels-photo-270404.jpeg'} alt="" />
					<h4 class="title">{post.title.rendered}</h4>
					<FormattedDate date={post.date} />
				</a>
			</li>
		))
	}
	</ul>
</section>
<hr />
<div class="pagination">
	{page.url.prev ? <a href={page.url.prev}>Previous</a> : null}
	{page.url.next ? <a href={page.url.next}>Next</a> : null}
</div>
</PostPreview>

Con la paginazione, viene passata ad ogni pagina renderizzata una proprietà page che rappresenta una singola pagina di dati. Si tratta dei dati che sono stati suddivisi in pagine (page.data) e dei metadati corrispondenti. Tra di essi page.url, page.start, page.end, page.total, page.currentPage, ecc.

Nel codice qui sopra abbiamo utilizzato page.currentPage per il numero di pagina corrente, e page.url.prev e page.url.next per i link di navigazione. Le pagine di archivio così generate avranno lo stesso aspetto della pagina del blog. Con la sola differenza del numero di post per pagina e dei link di navigazione in basso.

I link di navigazione generati da Astro

I link di navigazione generati da Astro

La build e la distribuzione di un sito Astro

Il comando npm run build avvia il processo di build del progetto Astro. Questo genera una cartella dist all'interno della quale vengono archiviati i file HTML del sito.

La distribuzione sul servizio di hosting sarà diversa a seconda dell'host. Per questo, rinviamo alla documentazione online di Astro. Dove vengono riportate guide specifiche per ogni host. Il codice illustrato in questa guida è disponibile su GitHub.

Ti consigliamo anche