Migrar post de Wordpress.com a Nikola

Ahora sí. Pasé todos los posts que tenía en Wordpress.com a mi nuevo blog de Nikola. Si bien ya había probado varias veces hacer esto, hace un tiempo el importador de Wordpress estaba un poco más verde y yo tampoco le quería dedicar tanto tiempo a la migración.

Hoy dejé de lado algunos prejuicios y tomé algunas decisiones de las cuales antes no estaba seguro y finalmente decidí empezar al revés. Primero, antes de migrar, creo el sitio con Nikola, hago que funcione y escribo un post que diga que me fui de Wordpress.com. Después de eso, cuando todo esté funcionando me voy a preocupar por migrar los posts viejos. Y finalmente, acá lo hice. Mucho antes de lo que pensaba.

Note

Utilicé este commit de Nikola e14a5244fb3596c2c89f228cec39c9233b226e64

Estos son los pasos que seguí para hacer una migración lo más sana posible de esos posts viejos. Todavía me falta arreglar algunas cositas a mano (como algunos videos de YouTube o algunas cositas de estilo), pero el trabajo que pude automatizar es demasiado.

  1. Instalar Nikola

  2. Aplicar este parche que:

    • Elimina la fecha del post del slug de la url (por ejemplo: 20120907mi-casa.html -> mi-casa.html)
    • Corrige los ^M que agrega Wordpress.com para generar un nuevo párrafo y al importar quedan juntos (agrega un </p>\n\n<p> por cada ^M que encuentra para que realmente funcione como un párrafo finalmente)

    import_wordpress.py.diff

    diff --git a/nikola/plugins/command/import_wordpress.py b/nikola/plugins/command/import_wordpress.py
    index 1aded89..6468104 100644
    --- a/nikola/plugins/command/import_wordpress.py
    +++ b/nikola/plugins/command/import_wordpress.py
    @@ -332,7 +332,7 @@ class CommandImportWordpress(Command, ImportMixin):
         def transform_multiple_newlines(self, content):
             """Replaces multiple newlines with only two."""
             if self.squash_newlines:
    -            return re.sub(r'\n{3,}', r'\n\n', content)
    +            return re.sub(r'\n{3,}', r'</p>\n\n<p>', content)
             else:
                 return content
    
    @@ -359,6 +359,10 @@ class CommandImportWordpress(Command, ImportMixin):
             if isinstance(path, utils.bytes_str):
                 path = path.decode('utf8')
             slug = utils.slugify(path)
    +
    +        # Remove date form the slug
    +        slug = utils.slugify(path)[8:]
    +
             if not slug:  # it happens if the post has no "nice" URL
                 slug = get_text_tag(
                     item, '{{{0}}}post_name'.format(wordpress_namespace), None)
    
  3. Exportar el dump (y bajar el archivo .xml) desde Wordpress.com

  4. Crear un nuevo blog importando el dump de Wordpress.com

    nikola import_wordpress --no-downloads --no-drafts --squash-newlines Downloads/humitos.wordpress.2013-09-09.xml temp-blog
    
  5. Copiar los posts importados de nikola a nuestro blog. Yo los puse dentro wordpress, para hacer una diferencia.

    cd temp-blog
    cp -r posts/ ~/blog/posts/wordpress
    
  6. Instalar pandoc

    sudo yum install pandoc
    
  7. Convertir los .html a .rst utilizando pandoc. Lo hice con este script:

    migrate_with_pandoc.sh

    set -e
    mkdir -p migrated
    for x in `ls *.wp`;
    do pandoc \
        --from=html \
        --to=rst \
        --normalize \
        --reference-links \
        --output=migrated/$(basename $x .wp).rst \
        --template=/home/humitos/blog/nikola/utils/pandoc_template.rst \
        --variable="title:$(cat $(basename $x .wp).meta | head -n 1 | tail -n 1)" \
        --variable="slug:$(cat $(basename $x .wp).meta | head -n 2 | tail -n 1)" \
        --variable="date:$(cat $(basename $x .wp).meta | head -n 3 | tail -n 1)" \
        --variable="tags:$(cat $(basename $x .wp).meta | head -n 4 | tail -n 1)" \
        $x;
    done
    
  8. Meter la información del .meta dentro del .rst. Yo usé este script:

    migrate_meta.py

    import os
    import glob
    
    
    CONTENT = '''.. link:
    .. description:
    .. tags: %(tags)s
    .. date: %(date)s
    .. title: %(title)s
    .. slug: %(slug)s
    
    '''
    
    for f in glob.glob('*.meta'):
        print f
        fd = open(f, 'r')
        fd_content = fd.readlines()
        # print fd_content
        fd.close()
    
        title = fd_content[0].strip()
    
        slug = fd_content[1].strip()
        date = fd_content[2].replace('-', '/').strip()
        tags = ', '.join(fd_content[3].split(',')).strip()
    
        rst_content = CONTENT % {'title': title,
                                 'tags': tags,
                                 'slug': slug,
                                 'date': date}
    
        rst_filename = os.path.join('migrated', slug + '.rst')
        fd = open(rst_filename, 'r')
        content = fd.readlines()
        first_line = content[0]
        fd.close()
    
        if '.. link:' in first_line:
            print 'SKIP:', f
            continue
        else:
            fd = open(rst_filename, 'w')
            rst_content += ''.join(content)
            fd.write(rst_content)
            fd.close()
            # break
    
  9. Tuve algunos problemas con las imágenes ya que por algún motivo escapaba los "_"; así que escribí otro script para reemplazarlos

    replace_bars.py

    import glob
    
    for f in glob.glob('*.rst'):
        print f
        fd = open(f, 'r')
        fd_content = fd.read()
        fd.close()
    
        fd = open(f, 'w')
        new_content = fd_content.replace('\\_', '_')
        fd.write(new_content)
        fd.close()
    
  10. Para migrar los comentarios tuve que:

    • Subir mi archivo .xml que bajé de Wordpres.com a disqus.com en la sección "Discussions" y luego en "Import", seleccionando Wordpress y luego eligiendo el .xml (demora un rato)
    • Edité el .csv generado por el comando "nikola import_wordpress" para que apunte a mi nueva dirección.
    • Luego en "Tools" utilizé la herramienta "Upload a URL map" y subí ese archivo.

    Warning

    Sin embargo, esto no fue suficiente. Wordpress estaba usando el ID de cada uno de los blog post como valor para la variable "disqus_identifier" y Nikola está usando el path de la carpeta "cache/" dónde se encuentra el post

    ¿Se puede decirle a Nikola que use otro ID para los posts? ¿Quizás con uno de los metadatos del principio del archivo .rst?

Por el momento, estoy contento con los resultados. Vamos a ver cómo sigue todo.

UPDATE 10-09-2013

  1. Utilicé este script para cambiar el plugin de wordpress de YouTube para en cambio usar la directiva .. media:: de Nikola

    replace_youtube.py

    import re
    import glob
    
    SEARCH_FOR = '[youtube='
    REPLACE_RE = r'\[youtube=(.*)\]'
    REPLACE_CONTENT = r'.. media:: \1'
    
    for f in glob.glob('*.rst'):
        fd = open(f, 'r')
        content = fd.read()
        fd.close()
        if SEARCH_FOR in content:
            print f
            # import epdb;epdb.set_trace()
            # raw_input('Press a key...')
            new_content = re.sub(REPLACE_RE, REPLACE_CONTENT, content)
            fd = open(f, 'w')
            fd.write(new_content)
            fd.close()
            # break
    

Comentarios

Comments powered by Disqus