A lo largo de esta serie ya has aprendido a construir un primer sitio estático con Jekyll y a llenarlo de contenido, aprendiendo a ponerlo en funcionamiento en local. Ahora vamos a entender cómo está estructurado tu sitio y cómo procesa Jekyll cada parte, para poder hacer cualquier modificación y construir nuevos sitios desde cero.
Vamos a estudiar el lenguaje de plantillas que usa Jekyll, basado en un lenguaje de marcado denominado Liquid. De esta forma, podremos componer nuestras propias plantillas y parciales, que nos permitirán reunir los componentes necesarios para un nuevo sitio estático básico.
Marcado Liquid y variables
El marcado Liquid, creado por Shopify, no es exclusivo de Jekyll, sino que es un lenguaje común a otros motores de plantillas. La funcionalidad que ofrece es muy limitada, con la intención de que su ejecución sea segura, aunque tiene algunas características que lo asemejan a un lenguaje de programación. Este marcado tiene tres ingredientes básicos: los objetos, las etiquetas y los filtros.
Los objetos son marcas del tipo {{ nombre }}
que permiten sustituir variables por su valor en una página. Por ejemplo, el código <h1>{{ site.title }}</h1>
en una plantilla resultaría en una cabecera de primer nivel conteniendo el título del sitio web.
Los principales objetos que se pueden usar al componer plantillas para Jekyll son site
y page
. El primero contiene las variables que forman parte de la configuración del sitio y el contenido (por ejemplo, los posts). El segundo alberga los metadatos de la página que se está renderizando, de forma que cuando una plantilla se aplique a varias páginas, page
tendrá diferentes datos para cada una. Este objeto tiene algunos datos de uso común, como page.title
o page.date
. Además, en los datos iniciales o front matter de cada página se pueden establecer variables personalizadas que serán accesibles como propiedades de page
. Puedes encontrar la referencia completa de variables disponibles por defecto en la documentación de Jekyll.
Las etiquetas forman la lógica de la plantilla, y se escriben entre los delimitadores {%
y %}
. Mediante estas, Liquid proporciona variables, control de flujo con condicionales, e iteración con bucles. En el siguiente ejemplo, asignamos un valor a la variable cat
, iteramos a lo largo de los posts del sitio web buscando aquellos cuya categoría coincida con cat
.
{% assign cat = "Programación web" %}
Posts en la categoría "{{ cat }}":
<ul>
{% for post in site.posts %}
{% if post.category == cat %}
<li>{{ post.title }}</li>
{% endif %}
{% endfor %}
</ul>
Por último, los filtros son similares a los métodos en lenguajes de programación: se aplican sobre objetos y devuelven otros resultados. En su mayoría, sirven para trabajar con cadenas de caracteres y configurar con precisión cómo deben mostrarse los objetos en las páginas.
Para aplicar un filtro a un objeto, se añade tras una barra vertical y se especifican parámetros tras dos puntos. Por ejemplo, si en la configuración del sitio tenemos definido author: david
entonces el código siguiente mostrará "Por David":
{{ site.author | capitalize | prepend: "Por " }}
Los filtros disponibles se recogen en la documentación de Liquid, pero Jekyll añade algunos que están explicados en su propia documentación.
Estructura de un sitio Jekyll
Cualquier sitio estático Jekyll tiene tres partes diferenciadas: las plantillas o layouts, las parciales o includes y el contenido.
Plantillas
Las plantillas recogen la estructura general aplicable a las páginas del sitio web. Generalmente hay al menos dos: default.html
y post.html
. La primera establece la estructura base de cualquier página, y la segunda añade el marcado necesario para las correspondientes a artículos.
En este contexto contamos con un objeto importante: content
, que representa el contenido de la página a la que se le está aplicando la plantilla. Para mostrar el contenido, por tanto, es crucial insertar {{ content }}
en el punto que deseemos. A continuación incluyo una ejemplo escueto de lo que sería una plantilla default.html
adecuada para nuestro sitio:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>{{ page.title }}</title>
<link rel="stylesheet" href="/assets/css/estilo.css">
</head>
<body>
<header>
<div class="content">
<h1><a href="/">{{ site.title }}</a></h1>
</div>
</header>
<main>
<div class="content">
{{ content }}
</div>
</main>
<footer>
<div class="content">
<p>© {{ "now" | date: "%Y" }} {{ site.author }}</p>
</div>
</footer>
</body>
</html>
Para aplicarle esta plantilla a una página, simplemente habrá que especificarlo en los datos iniciales de la misma. Por ejemplo, las primeras líneas de la página index.html
serán las siguientes:
---
layout: default
title: Página principal
---
Las plantillas pueden heredar unas de otras de forma que no tengamos que repetir nada de código. Para ello, las tratamos como cualquier otra página e insertamos su propia sección de datos. Así, podemos construir plantillas para tipos de páginas específicos basadas en la plantilla por defecto. La plantilla correspondiente a los artículos de nuestro nuevo sitio estático será post.html
con el siguiente contenido:
---
layout: default
---
<article>
<h2>{{ page.title }}</h2>
{{ content }}
</article>
<time datetime="{{ page.date | date: "%Y-%m-%d" }}">{{ page.date | date: "%d/%m/%Y" }}</time> por {{ site.author }}
Parciales
Las parciales o includes en Jekyll son trozos de código que separamos para poder reutilizarlos en múltiples puntos de nuestro sitio web, por ejemplo, tanto en la página principal como en la plantilla de algún otro tipo de páginas. En ocasiones también se separan partes del código que sólo se van a usar una vez con la intención de aligerar las plantillas y producir archivos independientes con propósitos más específicos (uno para la cabecera del sitio, otro para el pie de página, etc.).
En nuestro caso, vamos a ejemplificar el uso de parciales mediante una lista de enlaces para compartir posts en redes sociales. Además, haremos uso de la funcionalidad de parámetros, para añadir versatilidad a la parcial. Tendremos un parámetro denominado url
al que accederemos desde el objeto include.url
como ves en el ejemplo a continuación:
<div class="share">
<a href="https://twitter.com/intent/tweet?text={{ include.url | absolute_url }}" class="tw">Twitter</a>
<a href="https://t.me/share/url?url={{ include.url | absolute_url }}" class="tg">Telegram</a>
</div>
Para utilizar esta parcial en nuestras plantillas, simplemente tendremos que utilizar la etiqueta correspondiente: {% include share.html url=post.url %}
. Podemos hacer esto en la página principal para la lista de artículos y en la plantilla post.html
.
Contenido y otros directorios
El contenido, como ya sabes, se guarda principalmente en la carpeta _posts
. Sin embargo, no es el único tipo de contenido que Jekyll puede procesar. Adicionalmente, podemos utilizar otras colecciones: carpetas con contenido diferente al de los posts, con las que se puede trabajar de la misma forma para crear sus propios índices y páginas. La diferencia principal que guardarán con los posts es que no irán nombradas con la fecha de publicación, sino que pueden tener cualquier nombre.
Por ejemplo, para añadir una colección travel necesitaríamos crear un directorio _travel
donde incluir el contenido (archivos que Jekyll sepa procesar, como Markdown) y añadir las siguientes líneas a la configuración general del sitio (en el archivo _config.yml
):
collections:
travel:
output: true
Para mostrar un índice de la colección, añadiremos una página a la raíz del sitio con el permalink /travel/
y el bucle que convenga para iterar sobre los elementos:
---
layout: default
permalink: /travel/
title: Mis viajes
---
{% for item in site.travel %}
<p><a href="{{ item.url }}">{{ item.title }}</a></p>
{% endfor %}
Si el contenido que queremos almacenar y mostrar no consta de documentos sino de datos, Jekyll permite procesar datos en YAML, JSON y CSV en la carpeta _data
. El archivo _data/ejemplo.csv
estará accesible en el objeto site.data.ejemplo
del sitio web, de forma que se pueda iterar a través de sus elementos y mostrarlos de la forma conveniente.
Por último, cualquier archivo que esté almacenado en un directorio que no comience por guion bajo y, si es de texto, que no tenga una sección de datos iniciales, no será procesado por Jekyll sino copiado directamente al sitio resultante.
Esto nos permite, por ejemplo, crear un directorio assets/
o similar que contenga todos los archivos de estilo y scripting necesarios. Si queremos que Jekyll los procese porque son archivos SCSS o CoffeeScript, entonces será necesario incluir una sección de datos vacía al principio de dichos archivos, como ya hemos visto.
En la figura a continuación te muestro un posible resultado al utilizar los ejemplos anteriores y añadir algo de estilo para construir un sitio estático desde cero:
Algunas páginas especiales
En Jekyll y GitHub Pages, algunas páginas aparte del contenido nos pueden ser útiles y se pueden tratar de forma especial, las siguientes son las más relevantes:
index.html
La página index.html
de la raíz del proyecto es el punto de entrada para las personas que visiten nuestra web. Si seguimos el ejemplo del capítulo anterior en cuanto a paginación, el archivo puede tener simplemente este contenido:
---
layout: default
title: Página principal
---
{% for post in paginator.posts %}
<article>
<h2>
<a href="{{ post.url }}">{{ post.title }}</a>
{% include share.html url=post.url %}
</h2>
{{ post.excerpt }}
<a href="{{ post.url }}">Seguir leyendo</a>
</article>
{% endfor %}
<nav class="pagination">
{% if paginator.previous_page %}
<a href="{{ paginator.previous_page_path }}">Más nuevo</a>
{% endif %}
{% if paginator.next_page %}
<a href="{{ paginator.next_page_path }}">Más antiguo</a>
{% endif %}
</nav>
Nota: Es muy importante no imponer un permalink a este tipo de páginas, puesto que interfiere con el sistema de paginación de Jekyll.
atom.xml
A partir de cualquier colección se puede construir un feed con formato Atom para lectores RSS. El siguiente es un pequeño ejemplo del posible contenido de atom.xml
que albergaría los posts más recientes en el sitio:
---
layout: none
---
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>{{ site.name | xml_escape }}</title>
<link>{{ site.url }}</link>
<atom:link href="{{ site.url }}/atom.xml" rel="self" type="application/rss+xml" />
{% for post in site.posts limit:10 %}
<item>
<title>{{ post.title | xml_escape }}</title>
<description>{{ post.content | xml_escape }}</description>
<pubDate>{{ post.date | date: "%a, %d %b %Y %H:%M:%S %z" }}</pubDate>
<link>{{ site.url }}/{{ post.url }}</link>
<guid isPermaLink="true">{{ site.url }}/{{ post.url }}</guid>
</item>
{% endfor %}
</channel>
</rss>
404.html
Si servimos nuestro sitio desde GitHub Pages, el archivo 404.html
nos permite mostrar un error personalizado cuando se trate de acceder a una página inexistente en nuestro sitio. Para ello, simplemente podemos rellenarla con un mensaje de error y un enlace a la página principal, como en el ejemplo a continuación:
---
layout: default
---
<h2>404</h2>
<p>No hemos encontrado esa página. <a href="/">Volver al inicio</a></p>
Con esto hemos dado un buen repaso a la estructura de un sitio con Jekyll y lo básico de creación de plantillas. Tienes el código con los ejemplos que hemos tratado para que puedas empezar ya a experimentar con un sitio funcional. Para lanzar el sitio basta con ejecutar en una terminal bundle
y luego bundle exec jekyll serve
.
En el siguiente capítulo de esta serie trataremos temas avanzados relativos a la compilación del sitio en la nube, y el uso de plugins para añadir funcionalidad al sitio.
Crea tu propia página o blog gratis con Jekyll y Github - Serie completa: