En el post anterior ja vaig comentar que he canviat de WordPress a Hugo, ara explico tècnicament com ho fet (i em serveix d’autodocumentació). Trobareu molts articles a Internet sobre com fer-ho, jo indico més avall els que he fet servir, perquè de maneres de fer-ho n’hi ha tantes com vulgueu.

Els passos, a grans trets, han estat aquests:

  1. Exportar el contingut de WordPress
  2. Passar la exportació a fitxers Markdown
  3. Desplegar Hugo
  4. Generar el contingut i detalls finals
  5. Publicació i notificacions

A continuació explico amb més detall els passos.

1. Exportar el contingut de WordPress

Hi ha diferents opcions per importar a Hugo el contingut des de WordPress, de manera senzilla, i que incorporen tot el contingut del blog:

  • Articles
  • Comentaris
  • Categories
  • Etiquetes

Jo m’he basat en un parell d’articles per fer-me una idea:

De les diferents maneres, en vaig provar dues:

  1. WordPress to Hugo Exporter: teòricament la opció més ràpida, ja que genera directament tot el contingut en fitxers Markdown i YAML.
  2. Exportació de WordPress a XML: Una utilitat pròpia de WordPress que genera un fitxer XML amb tot el contingut de la base de dades de Wordpress. Requereix la conversió posterior de tot l’XML a fitxers Markdown.

Sens dubte, la opció més ràpida semblava la primera, i és la que vaig provar, però no em va funcionar bé: vaig instal·lar el plugin tal i com diuen les instruccions, però al moment de generar els fitxers, semblava quedar-se penjat. Vaig buscar documentació sobre el problema i no vaig poder-ho solucionar.

Així que finalment vaig utilitzar la opció nadiua de WordPress i vaig generar un fitxer XML d’uns quants megabytes al servidor, que vaig descarregar (ftp) al meu disc local.

Neteja de codificacions antigues

Una vegada tinc l’XML, el reviso i veig que tinc caràcters estranys deguts a migracions antigues de versions de WP que no han fet bé la conversió de jocs de caràcter. Amb un editor de text simple qualsevol (gedit, kate o altre) em dedico pacientment a substituir allò que no està bé.

No deixa de ser un avantatge: si ho hagués tingut distribuit en diferents fitxers ja tot no hagués estat tan fàcil la substitució.

Acabats aquests passos, disposo de tot el contingut del blog en un sol fitxer XML en UTF-8.

2. Passar la exportació a fitxers Markdown

Per generar els fitxers Markdown amb el contingut del blog usaré Blogger to Markdown que, a banda del que el seu nom diu, també serveix per Wordpress. El que fa és generar un conjunt de fitxers, un per article, amb totes el contingut i les metadades de l’article, i els comentaris si es vol.

blog2md és una aplicació Node.js, així que cal primer instal·lar aquest motor de JavaScript i veure una mica com va. No va malament tenir alguna noció de JavaScript per tasques posteriors.

blog2md permet generar els articles amb els comentaris inclosos o en un fitxer apart (nom-article-comments.md). Jo he preferit mantenir-ho tot junt, per mantenir la unicitat del blog.

Conversió dels articles a Markdown

Els passos van ser:

  1. Si no el teinu instal·lat, instal·lar Node.js
  2. Descarregar blog2md de GitHub en el directori que volgueu (aconsellable crear-ne un a propòsit) i executar npm install per descarregar dependències
  3. Comprovar que funciona bé l’aplicació, obrint un terminal a la carpeta on l’heu descarregat i executant node index.js (la documentació de blog2md al propi github és prou entenedora!) Si és queixa, és que funciona
  4. Copiar el fitxer XML amb l’export de WordPress a la carpeta on teniu blog2md i crear un directori on es guardaran els fitxers (exemple: ./posts)
  5. Executar node index.js w fitxer_export_wp.xml posts. Això genera tot el conjunt de fitxers en markdown del post, fitxers que ja es podrien usar per crear el blog en Hugo.

Però queden alguns passos per poder tenir bé tot el contingut: falta els comentaris, i blog2md no exporta bé els comentaris en el mateix fitxer del post, fa un trencament de l’estructura de la informació que fa que no es vegin bé els documents. Anem per passos

Incloure els comentaris als articles

  1. Executar node index.js w fitxer_export_wp.xml posts m

En el meu cas, jo tenia comentaris i alguns articles amb HTML inclòs dintre, així que tal i com diu la documentació vaig executar node index.js w fitxer_export_wp.xml posts m paragraph-fix

Tot i així, no m’acabaven de quadrar els comentaris dins del blog, així que vaig fer una petita modificació del fitxer node.js original:

A partir de la línia 15 vaig incloure:

var moment = require('moment');
var showDebug = true;
var wpCreateAlias = true;
var wpURLOriginAlias = "http://blog.manelguerra.com"; //in case you want to mantain redirects from older or different URL
var postSlug = "/blog" // assumed "/post" by default;

i de la línia 106 a la 187:

// console.log(posts)
console.log(`Post count: ${posts.length}`);

var title = '';
var content = '';
var catList = [];
var tags = [];
var draft = false;
var published = '';
var comments = [];
var fname = '';
var markdown = '';
var fileContent = '';
var fileHeader = '';
var postMaps = {};

posts.forEach(function(post){
    var postMap = {};

    title = post.title[0].trim();

    title = title.replace(/'/g, "\\\'");
    title = title.replace(/"/g, "\\\"");

    draft = post["wp:status"] == "draft"
    published = post.pubDate;
    comments = post['wp:comment'];
    fname = sanitize(decodeURI(post["wp:post_name"][0])) || post["wp:post_id"];
    markdown = '';

    console.log(`\n-----------\ntitle: '${title}'`);
    console.log(`published: '${published}'`);

    if (comments & showDebug){
        console.log(`comments: '${comments.length}'`);
    }

    catList = [];
    tags = [];

    var categories = post.category;
    var catString = '';
    var tagString = '';

    if (categories && categories.length){
        categories.forEach(function (category){
            if (category['$'].domain == 'post_tag') {
                tags.push(category['_']);
            } else {
                catList.push(category['_']);
            }
        });

        tagString = 'tags: [\"' + tags.join("\", \"") + "\"]";
        catString = 'categories: [\"' + catList.join("\", \"") + "\"]";
    }

    var wpAlias = post.link[0].trim();

    if (wpCreateAlias) {
        console.log(wpAlias);
        wpAlias = 'alias:\n  - ' + postSlug + wpAlias.replace(wpURLOriginAlias,'')
        console.log(wpAlias);
    }

    var pmap = {fname:'', comments:[]};
    pmap.fname = outputDir+'/'+fname+'-comments.md';

    fname = outputDir+'/'+fname+'.md';
    pmap.postName = fname;
    if (showDebug) console.log(`fname: '${fname}'`);

    if (post["content:encoded"]){
        // console.log('content available');
        var postContent = post["content:encoded"].toString();
        //if (applyParagraphFix && !/<p>/i.test(postContent)) {
            postContent = '<p>' + postContent.replace(/(\r?\n){2}/g, '</p>\n\n<p>') + '</p>';
        //}
        content = '<div>'+postContent+'</div>'; //to resolve error if plain text returned
        markdown = tds.turndown(content);
        //console.log(markdown);

        fileHeader = `---\ntitle: "${title}"\ndate: ${published}\ndraft: ${draft}\n${catString}\n${tagString}\n${wpAlias}\n---\n`;
        fileContent = `${fileHeader}\n${markdown}`;
        pmap.header = `${fileHeader}\n`;

        writeToFile(fname, fileContent);

    }
/* resta de linies */
}

Em queda pendent passar l’issue a github, però mentrestant ho deixo aquí documentat.

Aplicant aquests canvis, jo vaig aconseguir la generació en MarkDown de tot allò que tenia al blog, incloent tots els comentaris i referències.

Tot i així, s’han de fer alguns treballs manuals finals:

  • Enllaços entre articles: la importació deixa els enllaços originals que hi havia al blog, si s’està canviant d’adreça, com és el meu cas, caldrà buscar les adreces antigues a tots els articles i canviar-les per les noves per mantenir la navegació.
  • Imatges: si son del propi blog, cal descarregar-les (la part de mèdia del WP) i deixar-les a la carpeta /static/img de Hugo (veure secció següent), i canviar també les adreces a cada article on siguin.
    • Hugo permet centrar les imatges afegint #center al final de l’adreça.
    • En format Markdown: ![Títol de la imatge](/img/nom_imatge.png#center)

3. Desplegar Hugo

Hugo té una documentació d’instal·lació molt bona, i també m’ha anat molt bé l’article de Flavio Copes per crear un primer blog amb Hugo.

Per no repetir el que altres expliquen millor, mireu els links que indico per instal·lar Hugo i després usar-lo: per una primera aproximació, és més que suficient. La part important és l’estructura de carpetes d’Hugo i, sobretot, allà on posarem el contingut del blog.

L’estructura que tindreu serà similar a aquesta:

manel@circe:~/paginaweb$ ls -li
total 48
14811744 drwxr-xr-x  2 usuari usuari 4096 29 de juny  22:24 archetypes
14026746 -rw-r--r--  1 usuari usuari 1562 29 de juny  23:02 config_minimal.toml
14026741 -rw-r--r--  1 usuari usuari 4536  4 de set.  16:52 config.yml
14811184 drwxr-xr-x  3 usuari usuari 4096  3 de set.  00:03 content
14811747 drwxr-xr-x  2 usuari usuari 4096 29 de juny  22:24 data
14811174 drwxr-xr-x  3 usuari usuari 4096  6 de jul.  18:27 layouts
14158263 drwxr-xr-x 10 usuari usuari 4096  4 de set.  16:59 public
14811807 drwxr-xr-x  3 usuari usuari 4096 29 de juny  22:24 resources
14811746 drwxr-xr-x  3 usuari usuari 4096  2 de set.  22:20 static
14811748 drwxr-xr-x  3 usuari usuari 4096 21 de jul.  18:49 themes

A la carpeta content és on hi ha el que realment ens interessa: tot el cos de les planes i articles de la web (Hugo genera planes, les que siguin, no només blogs) en fitxers de format MarkDown. En aquesta carpeta és on s’ha de deixar tot el contingut que teniu a la carpeta posts de l’apartat 2.

Triar un tema

Hi ha temes per avorrir-se buscant. Si no us agrada el que té per defecte, busqueu-ne un que us agradi i desplegueu-lo.

És tan senzill com descomprimir el zip del tema a la carpeta themes de l’estructura anterior, i indicar al fitxer de configuració quin és el tema:

baseURL: "http://www.manelguerra.com/"
title: Manel Guerra
paginate: 7
theme: PaperMod

Jo he utilitzat i particularitzat el tema PaperMod d’Aditya Telange.

4. Generar el contingut i detalls finals

Obriu un terminal a la carpeta on tingueu Hugo desplegat, i arrenqueu el servidor on-linies

manel@circe:~/paginaweb$ hugo server

i aneu amb el navegador a la URL localhost:1313

Per generar les planes html definitives, només cal fer anar

manel@circe:~/paginaweb$ hugo

i a la carpeta public hi tindrem tot el codi html per pujar.

A partir d’aquí, cal familiaritzar-se amb el tema i les característiques d’Hugo per fer la pàgina al gust propi.

5. Publicació i notificacions

De cara a la publicació, en molts llocs es parla d’usar gihub pages i sincronitzar en línia per publicar automàticament, d’altres usen rsync… Fer-ho així et permet automatitzar la publicació, posant dates de publicació al post, de manera que quan arribi la data, el cron munti directament el site de nou i el publiqui automàticament.

Jo de moment, donada el poc que canvio, ho faré manualment, amb ftp, i potser més endavant automatitzo amb rsync. Ara mateix, però, no vull complicar-me la vida ni renunciar a usar el hosting que tinc, però usar github i aprofitar els seus avantatges em crida.

En quant a notificacions a xarxes socials, WordPress tenia plugins per Twitter, Facebook, Telegram, qualsevol cosa. Hugo no ho té (o jo encara no ho he trobat).

Jo aprofito IFTTT i hi he definit un parell d’applets que llegeixen el RSS i publiquen les novetats tant al meu twitter com al canal de Telegram del blog.


I això és tot. Ara toca centrar-se en el contingut a publicar i gaudir de l’eina!