Tutorial para blogear como Notxor
A raíz de haber publicado en Mastodon que había añadido alguna
característica más al código que soporta este blog. Me han
preguntado cómo funciona y si puedo explicar un poco el flujo de
trabajo. No hay nada más sencillo, lo único que hago es aprovecharme
de toda la funcionalidad que ya proporciona org-mode
para generar
html
. De esta manera, conseguir un sitio estático es sencillo. Pero
empezaré por el principio y explicaré un poco el código.
Por cierto, el código lo podéis encontrar en Codeberg y descargarlo
libremente. En el README explico en qué está basado y algunas
modificaciones que le he ido haciendo según lo he ido necesitando.
Concretamente las adicciones que le hice al código de
org-static-blog
durante el tiempo que estuvo sin mantenimiento.
Después ha seguido evolucionando y añadiendo características como el
hacer ficheros RSS
por etiqueta, que es algo que yo hice también en
su día. Por lo tanto, seguramente, os sea más cómodo instalar dicho
paquete y configurarlo en vuestro Emacs. Así empecé yo este blog.
Luego el código se ha ido modificando poco a poco para ajustarlo más a
mis necesidades y ya no uso el paquete de ELPA.
Las características que añadí por mi cuenta a esa versión antigua de
org-static-blog
son principalmente tres:
- La posibilidad de navegar el blog completo, mediante la
utilización de enlaces relativos, en un servidor de pruebas, como
el que proporciona Emacs con el comando
httpd-start
. En aquellos tiempos no se podía hacer, se tenía que publicar directamente. - La generación de ficheros
rss.xml
por etiquetas. - Que tenga en cuenta y muestre el autor del artículo. Esto último ha sido a petición, pero ya que está lo dejo, en mi blog no tiene mucho sentido.
El resto es sólo generación de sitio estático puro y duro, pero en
lugar de utilizar org-export
se utilizan las funciones de
publicación del código.
Además hay que recordar que mi código no es un paquete. Hay que
cargarlo con (load-file ...)
, todo el código para generar los html
está contenido en el fichero notxor-blog.el
. Pero es posible que
necesites más código que no está en mi repositorio. Ahí sólo
encontrarás el código elisp
y el archivo estilos.css
que es el que
da formato y color a las páginas. Pero además utilizo un par de
archivos javascript
, para el coloreo de sintaxis y el formateo de
fórmulas matemáticas, que luego comentaré.
Como explicar en abstracto cómo funciona el código y cómo es la estructura de directorios, voy a poner el ejemplo que tengo más a mano: este blog. ¿Qué estructura tiene el sitio? ¿Dónde pongo los archivos auxiliares? ¿Dónde pone los generados la herramienta?
Trasteando con los archivos auxiliares
Primero, antes de entrar en materia, vamos a echar un vistazo a la estructura de directorios:
. ├── 2017 │ ├── ... │ └── index.html ├── 2018 │ ├── ... │ └── index.html ├── 2019 │ ├── ... │ └── index.html ├── 2020 │ ├── ... │ └── index.html ├── 2021 │ ├── ... ├── 2022 │ ├── ... │ └── index.html ├── about │ └── index.html ├── archivo.html ├── etiquetas.html ├── favicon.png ├── index.html ├── medios │ ├── css │ │ └── estilos.css │ ├── fonts │ │ ├── Cantarell-Bold.otf │ │ ├── EBGaramond12-Regular.ttf │ │ ├── FiraCode-Retina.ttf │ │ └── Sugar & Vinegar.ttf │ ├── img │ │ ├── abatar.png │ │ ├── ... │ │ ├── mastodon-icono.png │ │ └── search.png │ ├── index.html │ └── js │ ├── es │ │ ├── ... │ ├── jquery-latest.min.js │ ├── main.js │ └── MathJax.js ├── rss.xml └── tags ├── acoso │ ├── index.html │ └── rss.xml ├── ... └── zettelkasten ├── index.html └── rss.xml 1301 directories, 3521 files
Puede parecer un poco complejo, pero no lo es tanto. Los directorios
2017-2022
los crea la herramienta automáticamente cuando publicas un
artículo lo guardará en una estructura de directorios tal que
/año/mes/día/título
.
Justo debajo de esos directorios, encontramos otro que se llama
about
, pero no es obligatorio llamarlo así, simplemente se pretende
tener un espacio donde puedes presentar el blog o cualquier otra
tontería (como tengo yo). Luego en el preámbulo de la página, donde
está el menú se enlaza a ese sitio con un simple enlace html
:
<li><a href=\"/about/\">Acerca de...</a></li>
Lo podéis llamarlo como queráis, pero recordad que siendo un enlace a
un directorio, cargará automáticamente index.html
.
Lo siguiente es el fichero archivo.html
. Eso lo genera la
herramienta y es un listado de todos los artículos publicados. Su
nombre se puede modificar, modificando una variable:
(defcustom notxor-blog-archive-file "archivo.html" "File name of the list of all blog posts. The archive page lists all posts as headlines." :type '(string) :safe t)
He visto también blogs que prefieren cargar directamente el archivo general. La lista son los títulos de los artículos y sus fechas, pero cuando se alarga la lista es un poco lento de carga. Prefiero el índice que muestra sólo unas pocas entradas. Esas se pueden configurar en la variable:
(defcustom notxor-blog-index-length 10 "Number of articles to include on index page." :type '(integer) :safe t)
También está el fichero etiquetas.html
. Este es un listado de las
etiquetas y los archivos que las portan. Lo genera automáticamente la
herramienta y también se pude configurar el nombre modificando una
variable:
(defcustom notxor-blog-tags-file "etiquetas.html" "File name of the list of all blog posts by tag. The tags page lists all posts as headlines." :type '(string) :safe t)
El fichero index.html
es el índice de portada del blog. Lo genera la
herramienta y también se puede configurar el nombre con una variable:
(defcustom notxor-blog-index-file "index.html" "File name of the blog landing page. The index page contains the most recent `notxor-blog-index-length` full-text posts." :type '(string) :Safe' t)
En este último caso está así hecho por si se quiere poner otra página de portada al cargar la URL principal y que haya un enlace al inicio del blog. He visto como otros usuarios, en blogs personales, más curriculares, que utilizan una carátula a modo de presentación o currículo y desde ahí, enlazan el blog. En mi caso, como no utilizo el blog para esos menesteres, prefiero que se muestre el índice directamente.
Después encuentras el directorio medios
que dentro tiene más
subdirectorios interesantes:
- Un directorio para la hoja de estilos
css
. - Un directorio donde guardar las fuentes que utiliza el sitio.
- Un directorio para meter el poco
javascript
que usa la página.
Voy a empezar por éste último. El javascript
que utilizo es muy
poco, fundamentalmente para dos cosas: el visionado de fórmulas
matemáticas con MathJax.js
y el coloreado de sintaxis, y también
para los botones de paypal y LiberaPay. Por supuesto, cada uno es
libre de si utilizar o no, las librerías js
que quiera y considere
oportuno. Para cargarlas, las llamo en otra variable:
(defcustom notxor-blog-page-postamble "<div> <script src=\"/medios/js/jquery-latest.min.js\"></script> <script src=\"https://polyfill.io/v3/polyfill.min.js?features=es6\"></script> <script id=\"MathJax-script\" async src=\"https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js\"></script> <script src=\"/medios/js/main.js\"></script> <div class=\"footer\"> <div class=\"redes\"> <p> <a rel=\"me\" href=\"https://masto.rocks/web/@Notxor\" target=\"_blank\"><img src=\"/medios/img/mastodon-icono.png\" width=\"24px\" float=\"left\" /></a> <a rel=\"me\" href=\"https://masto.nobigtech.es/@Notxor\" target=\"_blank\"><img src=\"/medios/img/mastodon-icono.png\" width=\"24px\" float=\"left\" /></a> <a href=\"https://diasp.org/people/15172490a88f01339a3f782bcb452bd5\" target=\"_blank\"><img src=\"/medios/img/diaspora-icono.png\" width=\"24px\" float=\"left\" /></a> </p> </div> <p>Generado con <code>notxor-blog</code> en <i>Emacs</i></p> <p> <img style=\"display: inline-block;\" src=\"/medios/img/cc-by-nc-sa.png\" align=\"middle\" /> <br />2012 - <span id=\"footerYear\"></span> <a href=\"mailto:notxor@nueva-actitud.org\">Notxor</a> - Powered by <a href=\"https://codeberg.org/Notxor/org-static-blog\" target=\"_blank\">notxor-blog</a> <script type=\"text/javascript\">document.getElementById(\"footerYear\").innerHTML = (new Date()).getFullYear();</script> </p> <table> <tr> <td> <b>Donar por Paypal</b> </td> <td> <b>Donar por Liberapay</b> </td> </tr> <tr> <td> <!-- Inserción de botón pypal --> <form action=\"https://www.paypal.com/cgi-bin/webscr\" method=\"post\" target=\"_top\"> <input type=\"hidden\" name=\"cmd\" value=\"_s-xclick\" /> <input type=\"hidden\" name=\"hosted_button_id\" value=\"29VXCW8SRNJ78\" /> <input type=\"image\" src=\"https://www.paypalobjects.com/es_ES/ES/i/btn/btn_donateCC_LG.gif\" border=\"0\" name=\"submit\" title=\"PayPal - Donar online de forma segura.\" alt=\"Botón Donar con PayPal\" /> <img alt=\"\" border=\"0\" src=\"https://www.paypal.com/es_ES/i/scr/pixel.gif\" width=\"1\" height=\"1\" /> </form> </td> <td> <!-- Inserción de botón liberapay --> <script src=\"https://liberapay.com/Notxor/widgets/button.js\"></script> <noscript> <a href=\"https://liberapay.com/Notxor/donate\"> <img alt=\"Donate using Liberapay\" src=\"https://liberapay.com/assets/widgets/donate.svg\"></a> </noscript> </td> </tr> </table> </div> </div>" "HTML to put after the content of each page." :type '(string) :safe t)
He querido pone completo todo el final de la página. En las primeras
líneas se aprecia la llamada a las librerías establecidas. La única
que no está accesible en la red es main.js
que hace unas pequeñas
conversiones:
$(document).ready(function() { /******************************************************************* * 1. replace css class "src" and "example" with "prettyprint", for * prettify.js to render * 2. replace detail language css class, e.g. "src-scheme" to * "lang-scheme" per the description of prettify.js ******************************************************************/ var $blocks = $('pre.src'); $blocks.each(function(index) { var self = $(this); var classes = self.removeClass('src').attr('class').split(/\s+/); $.each(classes, function(idx, cls) { if (cls.substring(0, 4) === 'src-') { var lang = cls.substring(4); self.removeClass(cls).addClass('lang-' + lang); } }); self.addClass('prettyprint'); }); $('pre.example').removeClass('example').addClass('prettyprint'); /******************************************************************* * 1. remove all org exported line number spans * 2. add css class "linenums" to code block per the description of * prettify.js ******************************************************************/ var $lines = $('span.linenr'); var $linedBlocks = $lines.parent(); $lines.remove(); $linedBlocks.each(function(index) { $(this).addClass('linenums'); }); /******************************************************************* * pretty print all code blocks ******************************************************************/ prettyPrint(); });
Hace un tiempo tenía activados los comentarios y se gestionaban con una herramienta libre que se llama hashover. El lugar del código desde donde se pueden incluir llamadas a esa u otras herramientas es otra variable:
(defcustom notxor-blog-post-comments "<section> <h1>Comentarios</h1> <blockquote> <p>Debido a algunos ataques mailintencionados a través de la herramienta de comentarios, he decidido no proporcionar dicha opción en el <i>Blog</i>. Si alguien quiere comentar algo, me puede encontrar en <a rel=\"me\" href=\"https://masto.rocks/web/@Notxor\" target=\"_blank\"><i>Mastodon</i></a> y en <a href=\"https://diasp.org/people/15172490a88f01339a3f782bcb452bd5\" target=\"_blank\"><i>Diaspora</i></a> con el <i>nick</i> de <b>Notxor</b>.</p> <p>También se ha abierto un grupo en Telegram (<a href=\"https://t.me/+S4-CQG2Mewod_lvj\" target=\"_blank\">enlace de invitación al grupo</a>), para usuarios de esa red.</p> <p>Disculpen las molestias.</p> </blockquote> </section>" "HTML code for comments to put after each blog post." :type '(string) :safe t)
En esa variable se pude establecer cualquier código html
que
necesite la herramienta de comentarios para que se despliegue.
Recomiendo HashOver porque es una herramienta libre, la descargas y
la pones en tu sitio, no necesita que se creen una cuenta o se logueen
en sitios de terceros cuando visiten tu página. El contenido se guarda
en texto plano en el directorio /hashover
del sitio y no necesitas
montar tampoco una base de datos para ello1.
Siguiendo, vemos que también hay un fichero rss.xml
donde se
actualiza el índice de las últimas entradas. Este se actualiza cada
vez que publicas en el blog y hace que tus fieles seguidores
tengan noticia de lo último que vas publicando.
Flujo de trabajo
Una vez configurado tu sitio y funcionando todo. Si te gusta reflexionar antes de publicar y corregir y pulir lo que se publicará2 como a mí, sólo tienes que realizar los siguientes pasos.
- Tener una idea para un artículo.
Crear un borrador con
M-x notxor-blog-create-draft
. Ese comando pregunta por el título, genera toda la estructura en un archivo que se guardará en el directorio de borradores. Ese directorio se guarda en la variable:(defcustom notxor-blog-drafts-directory "~/blog/borradores/" "Directory where unpublished ORG files are stored. When publishing, draft are rendered as HTML, but not included in the index, archive, tags, or RSS feed." :type '(directory))
La estructura con la que comenzará dicho artículo está determinado también en el código y lo puedes ajustar a tu gusto:
(defun notxor-blog-create-new-post (&optional draft) "Create a new blog post. Prompts for a title and proposes a file name. The file name is only a suggestion; You can choose any other file name if you so choose. if DRAFT, create a new blog draft." (interactive) (let ((title (read-string (notxor-blog-gettext 'title)))) (find-file (concat (if draft notxor-blog-drafts-directory notxor-blog-posts-directory) (read-string (notxor-blog-gettext 'filename) (concat (format-time-string "%Y-%m-%d-" (current-time)) (replace-regexp-in-string "\s" "-" (downcase title)) ".org")))) (insert "#+title: " title "\n" "#+date: " (format-time-string "<%Y-%m-%d %H:%M>") "\n" "#+author: " "\n" "#+filetags: " "\n" "#+options: H:4 num:nil toc:nil \\n:nil ::t |:t ^:{} -:nil f:t *:t <:t")))
- Normalmente cuando estoy escribiendo en un artículo para el blog
suelo cambiar a
notxor-blog-mode
. Ese modo es simplemente un derivado deorg-mode
pero me permite definir teclas directas para las acciones más habituales. Se escribe el borrador, se repasa y se edita las veces que hagan falta hasta que se considere publicable. En ese momento, el artículo debe pasar al directorio correspondiente. En mi caso dicho directorio se encuentra configurado como:
(defcustom notxor-blog-posts-directory "~/blog/articulos/" "Directory where published ORG files are stored. When publishing, posts are rendered as HTML, and included in the index, archive, tags, and RSS feed." :type '(directory))
Cuando se ha pasado el borrador a artículo, se invoca a la función
notxor-blog-publish
. Esta función genera el artículo, actualiza elindex.html
,archivo.html
,rss.xml
y actualiza los ficheroshtml
de etiquetas, con el formato:/tags/etiqueta/index.html
. Esos archivos los escribe en el directorio que esté configurado como salida:(defcustom notxor-blog-publish-directory "~/public_html/" "Directory where published HTML files are stored." :type '(directory))
En mi caso los mando a un directorio local de mi ordenador. En él hago pruebas de visualización y compruebo que todo funciona: enlaces, imágenes, etc. Suelo hacer un servidor de pruebas desde línea de comandos con:
python3 -m http.server 8080
- Si necesito un fichero
rss.xml
por etiquetas llamo a la funciónnotxor-blog-assemble-rss-by-tag
. Igual que en el paso anterior se generaban los índices de las etiquetas, ahora se generan los feed en/tags/etiqueta/rss.xml
. Por tanto, puedes pasar la URLhttps://tags/etiqueta/rss.xml
a quien esté interesado sólo en alguno de los temas que toca el blog. - Después de comprobar que todo ha salido bien3 lo subo al sitio con FileZilla.
Posteriormente cuando la gente lo lee y encuentra los errores que se
me han colado, vuelvo al original4, arreglo el error y utilizo la
función notxor-blog-publish-file
. Esto genera sólo el ejecutable y
lo pone en su sitio, así que sólo hay que subir un archivo corregido.
Conclusiones
Veo más acertado que utilices una herramienta más general que la
mía, que la tengo ya bastante acomodada a mí. En algunos casos se ha
quedado atrás con respecto a las características que le han metido a
las nuevas versiones de org-static-blog
.
No sé si todo lo explicado hasta aquí ha quedado suficientemente
claro. Todo lo que he contado es cómo me apaño yo con esto para
mantener un blog pequeñito, con sólo html
, css
y un poquitín de
javascript
. Como tampoco soy diseñador, pues queda como queda:
simple y sin grandes pretensiones.
Lo hago con Emacs porque es la herramienta, si pudiera engancharle una sartén también me haría unos huevos fritos.
Footnotes:
Sin embargo, eso no implica que haya un montón de imbéciles intentando hacer saltar tu base de datos inyectando SQL, sin conocimiento de lo que están haciendo. Hasta bloquear un servidor modesto como el que sostiene este humilde blog.
Aún así se te escaparán errores.
Por mucho cuidado que tengas siempre se te colará algún error.
En el directorio articulos
no en el de borradores
.
Comentarios