Ordenando alfabéticamente las etiquetas en Jekyll

5 minuto(s) de lectura

En el presente documento, echaremos un vistazo a la página que desglosa los artículos de un sitio web en función de las etiquetas que para ellos hayamos declarado. Si no hemos realizado demasiadas modificaciones tras instalar un tema, podremos acceder a dicha página a través del menú superior, haciendo clic sobre Tags. En el caso particular de haber escogido el tema Hooligan, esta presenta el siguiente aspecto:

Etiquetas desordenadas

Enseguida nos daremos cuenta de un hecho: el listado de etiquetas no está ordenado alfabéticamente. El orden que allí aparece (intro - beginner - jekyll - tutorial) corresponde al establecido en el único post disponible. En esta ocasión, dado que estamos lidiando con apenas cuatro etiquetas, la forma en la que estas se muestren no posee mayor relevancia. Sin embargo, a medida que el sitio web crezca y acumule una cantidad razonable de artículos, no parece demasiado sensato que la página de etiquetas se genere de manera desordenada.

Aprovechando la excelente orientación que ofrece este artículo, vamos a subsanar esta situación y, además, añadiremos después una funcionalidad similar a la sección de categorías de la web.

Usando nuestro editor de texto plano favorito, vamos a examinar el contenido del archivo tags.html, que se encuentra en la raíz del directorio donde hayamos decidido almacenar nuestro sitio web. En mi caso particular, tras la instalación del tema Hooligan, presentaba el siguiente aspecto:

---
layout: page
title: Tags
header: Posts By Tag
group: navigation
---
{% include JB/setup %}

<ul class="tag_box inline">
  {% assign tags_list = site.tags %}  
  {% include JB/tags_list %}
</ul>


{% for tag in site.tags %} 
  <h2 id="{{ tag[0] }}-ref">{{ tag[0] }}</h2>
  <ul>
    {% assign pages_list = tag[1] %}  
    {% include JB/pages_list %}
  </ul>
{% endfor %}

Aquí he de confesar que, directamente, llevé a cabo las modificaciones en el propio archivo tags.html, en lugar de generar ficheros adicionales y luego enlazarlos desde la propia página de etiquetas utilizando include (que sería el proceder más recomendable de cara a posibles futuros mantenimientos).

Así pues, con las alteraciones oportunas, el código de mi versión de tags.html es el que aparece acto seguido:

---
layout: page
title: Etiquetas
header: Artículos por etiqueta
group: navigation
---
{% include JB/setup %}

{% capture site_tags %}{% for tag in site.tags %}{{ tag | first }}{% unless forloop.last %},{% endunless %}{% endfor %}{% endcapture %}
{% assign tag_words = site_tags | split:',' | sort %}

<div id="tags">  
  <ul class="tag_box inline">
  {% for tag in tag_words %}
    <li><a href="#{{ tag | cgi_escape }}">{{ tag }} <sup>{{ site.tags[tag].size }}</sup></a></li>
  {% endfor %}
  </ul>  

  {% for item in (0..site.tags.size) %}{% unless forloop.last %}
    {% capture this_word %}{{ tag_words[item] | strip_newlines }}{% endcapture %}
  <h2 id="{{ this_word | cgi_escape }}">{{ this_word }}</h2>
  <ul class="posts">
    {% for post in site.tags[this_word] %}{% if post.title != null %}
    <li itemscope><span class="entry-date" style="font-family:monospace"><time datetime="{{ post.date | date_to_xmlschema }}" itemprop="datePublished">{{ post.date | date: "%d/%m/%Y" }}</time></span> &raquo; <a href="{{ post.url }}">{{ post.title }}</a></li>
    {% endif %}{% endfor %}
  </ul>
  {% endunless %}{% endfor %}
</div>

Ahora, siguiendo la misma filosofía, para que en nuestra página de categorías éstas se muestren también ordenadas alfabéticamente, vamos a sustituir el código fuente original que el tema Hooligan generó:

---
layout: page
title: Categories
header: Posts By Category
group: navigation
---
{% include JB/setup %}

<ul class="tag_box inline">
  {% assign categories_list = site.categories %}
  {% include JB/categories_list %}
</ul>


{% for category in site.categories %} 
  <h2 id="{{ category[0] }}-ref">{{ category[0] | join: "/" }}</h2>
  <ul>
    {% assign pages_list = category[1] %}  
    {% include JB/pages_list %}
  </ul>
{% endfor %}

Por el siguiente conjunto de instrucciones, que es idéntico al anterior (salvando pequeñas modificaciones para que lidie con categorías ahora):

---
layout: page
title: Categorías
header: Artículos por categoría
group: navigation
---
{% include JB/setup %}

{% capture site_categ %}{% for categ in site.categories %}{{ categ | first }}{% unless forloop.last %},{% endunless %}{% endfor %}{% endcapture %}
{% assign categ_words = site_categ | split:',' | sort %}

<div id="categs">  
  <ul class="tag_box inline">
  {% for categ in categ_words %}
    <li><a href="#{{ categ | cgi_escape }}">{{ categ }} <sup>{{ site.categories[categ].size }}</sup></a></li>
  {% endfor %}
  </ul>  

  {% for item in (0..site.categories.size) %}{% unless forloop.last %}
    {% capture this_word %}{{ categ_words[item] | strip_newlines }}{% endcapture %}
  <h2 id="{{ this_word | cgi_escape }}">{{ this_word }}</h2>
  <ul class="posts">
    {% for post in site.categories[this_word] %}{% if post.title != null %}
    <li itemscope><span class="entry-date" style="font-family:monospace"><time datetime="{{ post.date | date_to_xmlschema }}" itemprop="datePublished">{{ post.date | date: "%d/%m/%Y" }}</time></span> &raquo; <a href="{{ post.url }}">{{ post.title }}</a></li>
    {% endif %}{% endfor %}
  </ul>
  {% endunless %}{% endfor %}
</div>

Como ya tenemos la página de categorías preparada al estilo de la de etiquetas, únicamente resta que añadamos una funcionalidad similar a la existente para estas últimas en la plantilla que genera los posts (de manera que estén disponibles enlaces desde los artículos hacia la página de categorías y viceversa). Examinemos pues el contenido del archivo post.html, ubicado en el directorio _includes\themes\hooligan\. El apartado que gestiona el modo en el que se muestran las categorías es el siguiente:

{% if page.categories %}
  <section>
    <h4>{% if page.categories.size == 1 %}Categoría:{% else %}Categorías:{% endif %}</h4>
    {% for category in page.categories %}
      <span class="category">
        {{ category }}
      </span>
    {% endfor %}
  </section>
{% endif %} 

A continuación, lo modificaremos hasta que su aspecto sea similar al que presenta el bloque dedicado a la gestión del comportamiento de las etiquetas para los posts. Es decir, lo sustituiremos por:

{% if page.categories %}
  <section>
    <h4>{% if page.categories.size == 1 %}Categoría:{% else %}Categorías:{% endif %}</h4>
	<ul class="tag_box">
      {% assign categories_list = page.categories %}  
  	  {% include JB/categories_list %}
    </ul>
  </section>
{% endif %} 

Así pues, tanto las etiquetas en tags.html, como las categorías en categories.html aparecerán ordenadas alfabéticamente.

Dejo aquí algunas notas a tener en consideración:

  • La ordenación se lleva a cabo a la hora de generar la propia página de etiquetas, no así para cada artículo en particular. Es decir, si queremos que las etiquetas asociadas a cada artículo se muestren ordenadas alfabéticamente, bien las escribimos así directamente, bien implementamos una lógica similar a la vista aquí, pero en el archivo correspondiente. Personalmente, como estimo que no utilizaremos demasiadas etiquetas en los posts, no considero que suponga mucha molestia declararlas ordenadas de forma manual, por lo que, en mi caso, no he añadido modificaciones adicionales para resolver el asunto planteado en este punto.
  • La función sort que hemos utilizado es “case sensitive”, con un comportamiento un tanto curioso. Primero ordena las etiquetas que comienzan por letras mayúsculas (desde la A a la Z), y luego ubica las que empiezan por letras minúsculas (desde la a a la z). Esto provoca que etiquetas como R y readr, que deberían aparecer razonablemente juntas, se muestren un tanto alejadas entre sí. Podemos refinar los anteriores bloques de código para modificar este comportamiento o, simplemente, actuar como un servidor y escribir todas las etiquetas utilizando letras minúsculas.

Nota: esta entrada se ha almacenado dentro del proyecto MetaBlog, quedando así disponible para su consulta también a través del siguiente enlace.

Comentar