Usare i plugin di Pelican

Nel mio primo articolo relativo a Pelican, ho citato brevemente l’argomento Plugin in riferimento alla possibilità di creare siti multi-lingua con i18n_subsites.

Pelican dispone di una discreta libreria di Plugin su GitHub; per usare i Plugin occorre innanzitutto copiare i files da GitHub. Io, ho trovato comodo copiarli tutti nella directory “Lib\site-packages” di Python che, nell’account (rfusi) del mio PC Windows 10, è collocata in questo percorso:

C:\Users\rfusi\AppData\Local\Programs\Python\Python35-32\Lib\site-packages\pelican-plugins

Per copiare tutti questi plugin da GitHub, ho usato le seguenti istruzioni da “C:\Users\rfusi>”:

cd AppData\Local\Programs\Python\Python35-32\Lib\site-packages
git clone --recursive https://github.com/getpelican/pelican-plugins.git

In questo modo, git crea la directory pelican-plugins e ci copia i file da GitHub. A questo punto, è possibile usare ogni Plugin desiderato configurando le variabili PLUGIN_PATHS e PLUGINS nel file pelicanconf.py in modo da specificare l’elenco dei nomi dei plugin da usare. Per esempio:

PLUGIN_PATHS = ['C:\\Users\\rfusi\\AppData\\Local\\Programs\\Python\\Python35-32\\Lib\\site-packages\\pelican-plugins',]
PLUGINS = ['pelican-plugins.i18n_subsites','pelican-plugins.permalinks','pelican-plugins.sitemap']

I Plugin che preferisco e presento in questo articolo sono:

  1. i18n_subsites, per creare siti multi-lingua;
  2. permalink, per creare collegamenti stabili nel tempo;
  3. image_process, per ottimizzare le immagini e ridurre il peso delle pagine web;
  4. photos, per creare gallerie fotografiche;
  5. post_stats, per calcolare statistiche riguardo il testo di un articolo;
  6. related_posts, per correlare articoli;
  7. render_math, per visualizzare formule matematiche;
  8. sitemap, per generare la mappa del sito;
  9. tag_cloud, per generare l’elenco dei tag;
  10. pelican-minification, per compattare il codice html e css delle pagine web.

Siti multi lingua con i18n_subsites

Il Plugin i18n_subsites, genera un “sotto-sito” dove pubblicare le pagine e gli articoli in una lingua diversa da quella principale; per esempio, per questo sito, Pelican ha generato un sito per i contenuti in inglese che è accessibile tramite l’URL http://www.ipertesti.com/en/. Per attivare il Plugin nel proprio sito, occorre configurare pelicanconf.py come in questo esempio:

PLUGINS = ['pelican-plugins.i18n_subsites',]
I18N_SUBSITES = {
  'en': {
      'SITENAME': 'IpeRteSTi',
      'SITEURL': 'http://localhost:8000/en',
      'SITESUBTITLE': 'Projects in the WEB',
      'SITEDESCRIPTION': 'The notes of Roberto Fusi about the realization of web projects: Internet, Web Development and Digital Marketing',
      'MENUITEMS': (
        ('Author', SITEURL + '/pages/author.html'),
        ('Contacts', SITEURL + '/pages/contacts.html'),
        ('', ''),
        ('Archives', '/en/archives.html'),
        ('Tags', '/en/tags.html'),),
  },
}

Per adattare i template Jinja ai contenuti nelle altre lingue, occorre far ricorso alla variabile {{ DEFAULT_LANG }} e blocchi condizionali tipo:

{% if DEFAULT_LANG=='en' %}
  ...codice specifico per sito inglese
{% else %}
  ...codice per tutte le altre lingue
{% endif %}

Immagini ottimizzate con image_process

Il plugin image_process ridimensiona ed ottimizza le immagini in base alla classe CSS che vi è assegnata; risulta utile per automatizzare il lavoro di preparazione delle immagini per le diverse risoluzioni dei dispositivi. Inoltre, semplifica il processo di creazione di immagini responsive con l’attributo srcset ed il tag picture di HTML5. Questo plugin non si trova più su GitHub ma sul Python Package index; per usarlo, occorre installarlo con pip insieme alle librerie pillow, beautifulsoup4 e six.

pip install pillow beautifulsoup4 six minchin.pelican.plugins.image_process

Sembra per image_process non supporti ancora Python 2.7+; infatti con il mio ambiente Python 2.7.13 ho dovuto mettere mano al file image_process.py nella directory del plugin per modificare il seguente codice.

import codecs # aggiunto alla riga 11
with codecs.open(path, 'r+', encoding=context['IMAGE_PROCESS_ENCODING']) as # invece di "with open(path, 'r+', encoding=context['IMAGE_PROCESS_ENCODING']) as f:" alla riga 191

image_process analizza il template Jinja ed associa speciali classi assegnate ai tag img a delle istruzioni per trasformare le immagini. Le classi riconosciute dal plugin devono iniziare con “image-process-“. La configurazione di pelicanconf.py prevede delle istruzioni, come nell’esempio riportato di seguito.

PLUGINS = ['minchin.pelican.plugins.image_process',]
IMAGE_PROCESS_DIR = 'derivees'
IMAGE_PROCESS = {
  'thumb': {
    'type': 'image',
    'ops': ["crop 0 0 50% 50%", "scale_out 150 150 True", "crop 0 0 150 150"],
  },
  'article-image': {
    'type': 'image',
    'ops': ["scale_in 300 300 True"],
  },
  'crisp': {
    'type': 'responsive-image',
    'srcset': [('1x', ["scale_in 800 600 True"]),
               ('2x', ["scale_in 1600 1200 True"]),
               ('4x', ["scale_in 3200 2400 True"]),
               ],
    'default': '1x',
  },
  'large-photo': {
    'type': 'responsive-image',
    'sizes': '(min-width: 1200px) 800px, (min-width: 992px) 650px, (min-width: 768px) 718px, 100vw',
    'srcset': [('600w', ["scale_in 600 450 True"]),
               ('800w', ["scale_in 800 600 True"]),
               ('1600w', ["scale_in 1600 1200 True"]),
               ],
    'default': '800w',
  },
  'cover-image': {
    'type': 'picture',
    'sources': [{
      'name': 'default',
      'media': '(min-width: 640px)',
      'srcset': [('640w', ["scale_in 640 480 True"]),
                 ('1024w', ["scale_in 1024 683 True"]),
                 ('1600w', ["scale_in 1600 1200 True"]),
                 ],
      'sizes': '100vw',
    },{
      'name': 'source-1',
      'srcset': [('1x', ["crop 100 100 200 200"]),
                 ('2x', ["crop 100 100 300 300"]),
                 ],
    }],
   'default': ('default', '640w'),
   },
}

Per processare le immagini secondo le istruzioni impostate in pelicanconf.py, occorre attribuire l’opportuno nome di classe alle immagini, come nei seguenti modelli HTML.

<img class="image-process-thumb" src="...URL-IMMAGINE-ORIGINALE-DA-CUI-RICAVARE-MINIATURA...">
<img class="image-process-article-image" src="...URL-IMMAGINE-ORIGINALE-PER-ARTICOLO...">
<img class="image-process-crisp" src="...URL-IMMAGINE-ORIGINALE-PER-DIFFERENTI-ZOOM...">
<img class="image-process-large-photo" src="...URL-IMMAGINE-ORIGINALE-PER-SERIE-RESPONSIVE...">

Il nome della classe, può essere specificata sia nel modello HTML (Jinja), che nell’articolo; in MarkDown, per inserire una immagine da ridimensionare automaticamente, posso usare la seguente sintassi.

![...ALT...]({filename}...URL-IMMAGINE-ORIGINALE-PER-ARTICOLO...){.image-process-article-image}

Con il tag picture di HTML5, consente più flessibilità nel fornire diverse opzioni di immagini al browser, come nell’esempio seguente.

<picture>
  <source class="source-1" src="...URL-IMMAGINE-ORIGINALE-PER-DIFFERENTI-ZOOM..."></source>
  <img class="image-process-cover-image" src="...URL-IMMAGINE-ORIGINALE-PER-SERIE-RESPONSIVE...">
</picture>

Le trasformazioni supportate dal plugin sono:

  • crop top left right bottom
  • flip_horizontal
  • flip_vertical
  • grayscale
  • resize width height
  • rotate degree
  • scale_in width height upscale
  • scale_out width height upscale
  • blur
  • contour
  • detail
  • edge_enhance
  • edge_enhance_more
  • emboss
  • find_edges
  • smooth
  • smooth_more
  • sharpen

E’ possibile creare delle trasformazioni personalizzate, manipolando l’oggetto pillow.Image in Python.

def crop_face(image):
  """Detect face in image and crop around it."""
  # TODO: Fancy algorithm.
  return image

IMAGE_PROCESS = {
  'face-thumbnail': [crop_face, "scale_out 150 150 True"]
}

Rispondere a “Quanto?” con post_stats

Il plugin post_stats calcola alcune statistiche del testo di un articolo, e le registra nella variabile article.stats per rendere disponibili questi valori nel template Jinja:

<ul>
  <li>{{ article.stats['wc'] }} parole</li>
  <li>{{ article.stats['read_mins'] }} minuti di lettura stimati</li>
  <li>Facilità di lettura Flesch–Kincaid {{ article.stats['fi'] }}</li>
  <li>Complessità Flesch–Kincaid {{ article.stats['fk'] }}</li>
</ul>

Per attivare il Plugin nel proprio sito, occorre installare il package BeautifulSoup:

pip install beautifulsoup4

La configurazione di pelicanconf.py richiede solo di impostare la variabile PLUGINS:

PLUGINS = ['pelican-plugins.post_stats']

Potrebbe interessarti anche questo… con related_posts

Questo plugin rende disponibile la variabile related_posts in Jinja:

{% if article.related_posts %}
    <ul>
    {% for related_post in article.related_posts %}
        <li><a href="{{ SITEURL }}/{{ related_post.url }}">{{ related_post.title }}</a></li>
    {% endfor %}
    </ul>
{% endif %}

Per attivare il plugin, il file pelicanconf.py può essere configurato come in questo esempio:

PLUGINS = ['pelican-plugins.related_posts']
RELATED_POSTS_MAX = 10
RELATED_POSTS_SKIP_SAME_CATEGORY = False

Gli articoli correlati vanno elencati nel meta-dato Related_posts del file sorgente:

Related_posts: slug1, slug2, slug3, ... slugN

Formule matematiche più eleganti con render_math

Il plugin render_math permette di visualizzare delle formule matematiche nelle pagine web grazie allo script JavaScript MathJax che interpreta e formatta le formule scritte con la notazione LaTeX, MathML, and AsciiMath. I requisiti minimi per funzionare, sono: Pelican 3.6+, Typogrify 2.0.7+, BeautifulSoup4.

Per attivare il Plugin nel proprio sito, occorre configurare pelicanconf.py come in questo esempio:

PLUGINS = ['pelican-plugins.render_math']
MATH_JAX = {
  'align': 'center',
  'auto_insert': True,
  'indent': '0em',
  'show_menu': True,
  'process_escapes': True,
  'mathjax_font': 'default',
  'latex_preview': 'Tex',
  'color': 'black',
  'linebreak_automatic': False,
  'tex_extensions': [],
  'responsive': True,
  'responsive_break': 768,
  'process_summary': True,
  'message_style': 'normal'
}

In questo modo è possibile scrivere formule matematiche scrivendole nel documento MarkDown inline e block-style:

$e=mc^2$

Con il simbolo \($\) singolo, la formula viene visulizzata inline: \(e=mc^2\).

$$e=mc^2$$

Con il simbolo

$$$$ doppio, la formula viene visulizzata *block-style*: $$

e=mc^2$$

Altro esempio/test:

$$\forall x \in X, \quad \exists y \leq \epsilon$$
$$\alpha, \beta, \gamma, \Gamma, \pi, \Pi, \phi, \varphi, \mu, \Phi$$
$$\cos (2\theta) = \cos^2 \theta - \sin^2 \theta$$
$$\lim_{x \to \infty} \exp(-x) = 0$$
$$k_{n+1} = n^2 + k_n^2 - k_{n-1}$$
$$f(n) = n^5 + 4n^2 + 2 |_{n=17}$$
$$\frac{n!}{k!(n-k)!} = \binom{n}{k}$$
$$\begin{equation}
  x = a_0 + \cfrac{1}{a_1
      + \cfrac{1}{a_2
      + \cfrac{1}{a_3 + \cfrac{1}{a_4} } } }
  \end{equation}$$
$$\forall x \in X, \quad \exists y \leq \epsilon$$
$$\alpha, \beta, \gamma, \Gamma, \pi, \Pi, \phi, \varphi, \mu, \Phi$$
$$\cos (2\theta) = \cos^2 \theta - \sin^2 \theta$$
$$\lim_{x \to \infty} \exp(-x) = 0$$
$$k_{n+1} = n^2 + k_n^2 - k_{n-1}$$
$$f(n) = n^5 + 4n^2 + 2 |_{n=17}$$
$$\frac{n!}{k!(n-k)!} = \binom{n}{k}$$
$$\begin{equation} x = a_0 + \cfrac{1}{a_1 + \cfrac{1}{a_2 + \cfrac{1}{a_3 + \cfrac{1}{a_4} } } } \end{equation}$$

Ma dove vai se la sitemap non ce l’hai?

Il Plugin sitemap, genera un file di testo in formato XML conforme allo XMLSchema Sitemap 0.9 e lo salva nella cartella principale del sito. Per attivare il Plugin nel proprio sito, occorre configurare pelicanconf.py come in questo esempio:

PLUGINS = ['pelican-plugins.sitemap']
SITEMAP = {
    'format': 'xml',
    'priorities': {
        'articles': 1.0,
        'indexes': 0.8,
        'pages': 0.5
    },
    'changefreqs': {
        'articles': 'weekly',
        'indexes': 'daily',
        'pages': 'monthly'
    },
    'exclude': ['it/','en/it/','en/en/']
}

Gli attributi priorities e changefreqs definiscono rispettivamente l’importanza dei contenuti del sito (in una scala da 0.0=non importante a 1.0=fondamentale) e la frequenza di aggiornamento (always, hourly, daily, weekly, monthly, yearly, never).

Attraversare le nuvole con tag_cloud

Il Plugin tag_cloud, crea un elenco orizzontale dei tag usati per gli articoli del blog; ogni tag ha una dimensione proporzionale al numero di articoli ad esso associati. Per attivare il Plugin nel proprio sito, occorre configurare pelicanconf.py come in questo esempio:

PLUGINS = ['pelican-plugins.tag_cloud']
TAG_CLOUD_STEPS = 5
TAG_CLOUD_MAX_ITEMS = 100
TAG_CLOUD_SORTING = 'random'
TAG_CLOUD_BADGE = False

Inoltre, occorre personalizzare i fogli stile CSS, come nel seguente esempio:

#extras .tagcloud {
    margin: 0;
    padding: 0;
    list-style-type: none;
    text-align: center;
    border-bottom: 1px solid #000;
    margin-bottom: 1em;
    padding-bottom: 1em;
}
#extras .tagcloud li {
    display: inline;
    margin: 0 0.2em;
}
#extras .tagcloud li.tag-1 {
  font-size: 3em;
}
#extras .tagcloud li.tag-2 {
  font-size: 2.5em;
}
#extras .tagcloud li.tag-3 {
  font-size: 2em;
}
#extras .tagcloud li.tag-4 {
  font-size: 1.5em;
}
#extras .tagcloud li.tag-5 {
  font-size: 1em;
}

Compattare il codice html con pelican-minification

Il Plugin pelican-minification, rimuove gli spazi bianchi dal codice html riducendo la dimensione dei file delle pagine web e quindi permettendo al browser di visualizzare la pagine più rapidamente.

Per installare questo Plugin, occorre installarlo, ad esempio con con pip:

pip install pelican-minification

Per attivare il Plugin nel proprio sito, occorre configurare pelicanconf.py come in questo esempio:

PLUGINS = ['pelican-plugins.pelican-minification']

Gallerie fotografie ottimizzate con photos

Uso photos per aggiungere una galleria di foto un articolo, o al corpo di un testo. Le foto sono mantenute in una libreria di foto in alta risoluzione: photos le ridimensiona e crea delle anteprime nella directory output/photos.

Per prima cosa, ho installato i package Pillow (Python Imaging Library) e piexif:

pip install Pillow piexif

Il file pelicanconf.py si configura come in questo esempio:

PLUGINS = ['pelican-plugins.photos']
PHOTO_LIBRARY = "_src\\Gallery"
PHOTO_GALLERY = (1170, 1170, 100)
PHOTO_ARTICLE = (600, 600, 80)
PHOTO_THUMB = (192, 192, 60)
PHOTO_RESIZE_JOBS = 5
PHOTO_WATERMARK = True
PHOTO_WATERMARK_TEXT = SITENAME
PHOTO_WATERMARK_IMG = ''
PHOTO_EXIF_KEEP = True
PHOTO_EXIF_REMOVE_GPS = True
# PHOTO_EXIF_COPYRIGHT = 'COPYRIGHT'
# PHOTO_EXIF_COPYRIGHT_AUTHOR

Per creare una galleria di foto in un articolo del blog, occorre aggiungere il metadato gallery come in questo esempio:

Gallery: {photo}/folder{Title of my photos}

Per aggiungere una immagine singola nel testo di un articolo, si usa la parola chiave {photo} come in questo esempio

{photo}folder/image.jpg

E’ anche possibile usare una lightbox per mostrare l’immagine inclusa nel testo di un articolo, con il seguente codice:

{lightbox}folder/image.jpg

Il plugin, rende disponibili le varibili article.photo_image e article.photo_gallery nel template Jinja.

Per mostrate una foto in un articolo del blog, occorre includere questo codice nel template article.html:

{% if article.photo_image %}<img src="{{ SITEURL }}/{{ article.photo_image[1] }}" />{% endif %}

Per mostrate una galleria di foto in un articolo del blog, occorre includere questo codice nel template article.html:

{% if article.photo_gallery %}
<div class="gallery">
{% for title, gallery in article.photo_gallery %}
  <h1>{{ title }}</h1>
    {% for name, photo, thumb, exif, caption in gallery %}
        <a href="{{ SITEURL }}/{{ photo }}" title="{{ name }}" exif="{{ exif }}" caption="{{ caption }}"><img src="{{ SITEURL }}/{{ thumb }}"></a>
    {% endfor %}
{% endfor %}
</div>
{% endif %}

Per vedere un esempio, clicca qui.

Collegamenti saldi con permalinks

Il Plugin Permalinks permette di creare link resistenti al cambiamento del nome del file o della posizione; per ottenere questo risultato, crea delle pagine web aggiuntive aventi sempre lo stesso nome di file e le salva nella cartella specificata dalla variabile PERMALINK_PATH. I file HTML creati nella cartella PERMALINK_PATH, contengono il codice per reindirizzare l’utente alla pagina o all’articolo originale. Con la variabile PERMALINK_ID_METADATA_KEY si definisce il nome del metadato, inserito nel file sorgente delle pagine o degli articoli, che definisce l’identificativo univoco per la pagina nel sito.

Per esempio, il file pelicanconf.py potrebbe includere la seguente impostazione:

PLUGINS = ['pelican-plugins.permalinks',]
PERMALINK_PATH = 'permalinks'
PERMALINK_ID_METADATA_KEY = 'permalinkid'

Mentre un articolo formattato con MarkDown, potrebbe includere il seguente metadato:

PermalinkId: IT201705050000

Il valore IT201705050000 rappresenta il codice univoco dell’articolo che diventerà il nome del file HTML per costruire il Permalink e può essere scelto arbitrariamente. Si noti che il valore di PERMALINK_ID_METADATA_KEY deve essere tutto in minuscolo, mentre nel sorgente del contenuto si possono usare indifferentemente lettere minuscole o maiuscole. In definitiva, il permalink dell’esempio, avrà il seguente valore:

/permalink/IT201705050000.html

Una volta creati i permalink per pagine ed articoli, li si possono usare come indirizzi costanti per i link. Ogni volta che il browser aprirà la pagina di un permalink, sarà automaticamente reindirizzato all’URL corretto dell’articolo o della pagina.

In aggiunta a quanto operato dal Plugin, ho modificato il template article.html per aggiungere riferimenti al permalink. Per esempio, nella sezione head della pagina, ho inserito:

<link rel="bookmark" href="{{ SITEURL }}/{{ PERMALINK_PATH }}/{{ article.permalinkid }}.html">

Nel footer dell’articolo, ho invece aggiunto un link al permalink con questo codice:

{% if article.permalinkid %}<a href="{{ SITEURL }}/{{ PERMALINK_PATH }}/{{ article.permalinkid }}.html" class="permalink">#PERMALINK</a>. {% endif %}

Riferimenti

  1. Pelican plugins
  2. Wikipedia permalink
  3. Flesch–Kincaid readability tests
  4. LaTeX/Mathematics
  5. Responsive Images Done Right: A Guide To And srcset

Libri suggeriti

Condividi questo articolo

Se ti è piaciuto questo articolo e pensi possa essere utile anche ad altri, condividilo con i tuoi amici e conoscenti, facendo click sui pulsanti dei tuoi social network preferiti.

P.S. Grazie!

Commenti

Cosa pensi di questo articolo? Hai dei suggerimenti da darmi o vuoi segnalare la tua esperienza in questa pagina? Registrati con Disqus ed inserisci il tuo commento qui sotto!

Inoltre, se lo desideri puoi anche scrivermi una e-mail.

Presentazione

IpeRteSTi é un blog curato da Roberto Fusi. Raccoglie suggerimenti ed esperienze personali riguardo Internet, Web Development e Digital Marketing.

Seguimi sui social

LinkedInTwitterGooglePlusFeedburner for IpeRteSTi

Iscriviti alla mia newsletter