acambronero
acambronero
@acambronero@blogpocket.es

Este es el blog federado de Antonio Cambronero, fundador, autor y CEO de Blogpocket. Informático, blogger y profesor, con más de 20 años de experiencia en departamentos de soporte técnico informático, análisis de sistemas, productividad, optimización de procesos, atención al cliente y formación, en empresas multinacionales.

130 publicaciones
54 seguidores

Copia Estática Local v1.9: Exportar Custom Post Types

En los dos artículos anteriores he contado cómo generé una copia estática de Blogpocket y cómo recuperé los PDFs perdidos. Esos posts cubrían posts y páginas estándar, pero WordPress permite registrar tipos de publicación personalizados (Custom Post Types) y muchos blogs los usan: productos en WooCommerce, eventos, recetas, microblogs, fediposts, lo que sea. Hasta la versión 1.8 del plugin Copia Estática Local esos CPTs quedaban fuera.

La versión 1.9 lo resuelve. Y de paso incluye un fast-path para descargar imágenes que vale para cualquier blog en el que el plugin haga peticiones HTTP al propio servidor (más sobre esto al final).

Este post es un tutorial práctico: comandos esenciales que tendrás que ejecutar para actualizar el plugin, explorar tus CPTs y desplegarlos.

Lo que añade la v1.9

Tres cosas:

  1. Una tercera sección en el panel del plugin, «Exportar Custom Post Types», con un desplegable de los CPTs públicos registrados en tu WordPress.
  2. Las publicaciones del CPT seleccionado se generan en wp-content/uploads/copia-estatica-html/<nombre_del_cpt>/, con un index.html propio.
  3. Las imágenes se descargan y reescriben con la misma lógica defensiva que ya se aplicaba a posts y páginas. Sin sorpresas.

Más un fix técnico: si la imagen está en el mismo servidor donde corre el plugin, ahora se copia directamente del disco sin pasar por HTTP. Hablo de ello en la sección de problemas comunes.

Antes de empezar: activa el log

Sin log, si algo falla, te quedas sin pistas. En wp-config.php, antes de la línea /* That's all, stop editing! */, añade:

define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);

Con WP_DEBUG_DISPLAY en false, los errores no se imprimen en la pantalla del visitante; solo se acumulan en wp-content/debug.log. Esa es la fuente de verdad mientras pruebas.

Paso 1: actualiza el plugin

Descarga el ZIP desde la release v1.10 en GitHub y, desde el admin de WordPress, ve a Plugins → Añadir nuevo → Subir plugin. Sube el ZIP y elige «Reemplazar el plugin actual» si te pregunta. El proceso es idéntico a actualizar cualquier plugin.

Si prefieres terminal y tienes SSH:

cd /tu/ruta/a/wp-content/plugins/
rm -rf copia-estatica
wget https://github.com/blogpocket/copia-estatica/releases/latest/download/copia-estatica-plugin-1.9.zip
unzip copia-estatica-plugin-1.9.zip
rm copia-estatica-plugin-1.9.zip

Después, en el admin de WordPress, comprueba en Plugins que la versión instalada es 1.9 y que sigue activado. Si lo estaba antes, debería seguir estándolo.

Paso 2: identifica los CPTs que tienes registrados

El plugin solo va a mostrarte los CPTs registrados como públicos. Si no sabes cuáles son los tuyos, hay tres formas de averiguarlo.

Opción A: desde el propio plugin. Ve a Copia Estática en el menú lateral. Si la sección 3 te muestra un desplegable, los CPTs que aparezcan ahí son los que se pueden exportar. Si no aparece la sección (o aparece con un mensaje informativo), no hay CPTs públicos en este sitio.

Opción B: con WP-CLI, si lo tienes instalado:

wp post-type list --public=true --fields=name,label,public,_builtin

Te devuelve una tabla con todos los CPTs y sus etiquetas. Los que tengan _builtin=false son los personalizados (los que registró un plugin o tu tema). post, page y attachment los excluye el propio plugin Copia Estática Local porque ya están cubiertos por las otras secciones.

Opción C: con un fragmento de PHP en functions.php o un código snippet:

add_action('admin_footer', function() {
    $cpts = get_post_types(['public' => true, '_builtin' => false], 'objects');
    foreach ($cpts as $slug => $obj) {
        echo "<!-- CPT: $slug ({$obj->labels->name}) -->\n";
    }
});

Carga el admin y mira el código fuente. Te aparecerán los CPTs como comentarios HTML al final.

Paso 3: exporta un CPT

Desde Copia Estática, baja a la sección 3, elige uno en el desplegable y pulsa «Generar Publicaciones de este CPT». El plugin recorre todas las publicaciones publicadas del CPT, las procesa una a una (descargando imágenes incrustadas, reescribiendo enlaces internos a rutas locales) y las guarda en wp-content/uploads/copia-estatica-html/<nombre>/slug.html. Más un index.html con la lista.

Si tienes muchas publicaciones (decenas o cientos), te conviene tener el log abierto en otra ventana mientras tanto:

tail -f wp-content/debug.log

Verás líneas tipo:

[15-Jun-2026 14:11:16 UTC] [Copia Estática] [CPT fedipost 1] Procesando #79550: una-publicacion-ejemplo
[15-Jun-2026 14:11:16 UTC] [Copia Estática] [CPT fedipost 2] Procesando #79536: otra-publicacion

Si una publicación falla por algún motivo (contenido raro, imagen externa que da timeout, lo que sea), el plugin lo registra en el log y continúa con la siguiente. Al final el panel te muestra cuántas se procesaron correctamente y cuántas fallaron, con sus IDs y slugs.

Paso 4: verifica el resultado

Tres comprobaciones esenciales antes de dar el trabajo por bueno.

A) Cuenta cuántos HTML se generaron:

cd /tu/ruta/a/wp-content/uploads/copia-estatica-html/
ls <nombre_del_cpt>/*.html | wc -l

Compáralo con el número de publicaciones publicadas de ese CPT en tu admin (Posts → All posts, filtrado por tipo). Deberían coincidir, salvo los fallos que el log reportara.

B) Comprueba que las imágenes son reales (no HTML disfrazado de imagen, que es uno de los casos extraños que pueden pasar si tu blog tiene redirecciones):

file img/*.jp*g img/*.png 2>/dev/null | head -10

Cada línea debería decir algo como JPEG image data, baseline, precision 8, ... o PNG image data, .... Si en lugar de eso ves HTML document o ASCII text, alguna imagen no es realmente una imagen sino la respuesta de un servidor que redirige. En esos casos hay que aplicar el fast-path local que comento al final.

C) Cuenta cuántas imágenes únicas aparecen referenciadas en los HTML y compáralo con cuántas hay en img/:

grep -ohE 'src="\.\.\/img/[a-f0-9]+\.[a-z]+"' <nombre_del_cpt>/*.html | sort -u | wc -l
ls img/ | wc -l

Si las dos cifras coinciden, todo bien. Si el grep devuelve más que el ls, es que hay imágenes referenciadas que no se descargaron físicamente. Mira el log para ver los errores.

Paso 5: comprueba en el navegador

Abre uno de los HTML directamente en el navegador:

https://tudominio.com/wp-content/uploads/copia-estatica-html/<nombre_del_cpt>/<slug>.html

Si la página carga texto e imágenes correctamente, ya tienes la copia estática del CPT funcionando. Si las imágenes dan icono roto, abre la URL de una de ellas sola (sin el HTML) para descartar caché. Si la imagen sola da error, es que falta físicamente. Si sola se ve pero dentro del HTML no, suele ser que tu navegador tiene cacheado un 404 anterior: Cmd+Shift+R (Mac) o Ctrl+F5 (Windows) suele resolverlo.

Paso 6 (opcional): despliega en otro dominio

Si lo que querías era subir solo este CPT a otro hosting (por ejemplo, generar la copia en lanzatu.blog y publicarla en blogpocket.com), empaqueta solo lo que has añadido en esta generación:

cd /tu/ruta/a/wp-content/uploads/copia-estatica-html/
zip -r ~/cpt-export.zip <nombre_del_cpt>/ img/
ls -lh ~/cpt-export.zip

Descarga el ZIP, súbelo al destino vía cPanel o FTP, y extráelo en la carpeta donde tienes el resto de la copia estática. La carpeta <nombre_del_cpt>/ se crea íntegra (no había nada allí) y las imágenes se suman a img/ sin colisiones (cada imagen lleva su hash MD5 único).

Una cosa a tener en cuenta: si ya tenías un index.html en la raíz de la copia estática del destino, el ZIP no lo va a actualizar para que liste el nuevo CPT. Tienes dos opciones:

Opción rápida: edita index.html a mano y añade una entrada:

<li><a href="<nombre_del_cpt>/index.html">Publicaciones del CPT</a></li>

Opción limpia: si el index.html del origen ya lista el CPT (porque lo regeneraste hace poco), inclúyelo en el ZIP. Pero cuidado: ese index.html del origen también lista todos los años y páginas que tengas allí, así que la estructura del origen y la del destino deben coincidir.

Problemas comunes y cómo diagnosticarlos

Las imágenes salen como icono roto pero el archivo existe en img/. Comprueba si tu dominio tiene una redirección 301 a otro dominio. Cuando el plugin pide una imagen a https://tudominio.com/wp-content/uploads/..., si el servidor responde 301 a otro lado, el plugin acaba descargando lo que sea que devuelva el destino (típicamente la portada en HTML) y la guarda con el nombre de la imagen. El resultado: archivos llamados .jpg o .png que en realidad son HTML.

curl -I https://tudominio.com/wp-content/uploads/2024/01/cualquier-imagen.jpg

Si la primera línea dice HTTP/2 301, ese es el problema. La v1.9 del plugin lo soluciona con el llamado fast-path local: si la URL apunta a un host considerado interno y el archivo existe en wp-content/uploads/ del propio servidor, se copia directamente desde disco sin pasar por HTTP. Es más rápido y inmune a redirecciones, WAFs, certificados SSL y cualquier otra capa intermedia.

Hay imágenes que no se descargan y no aparece nada en el log. Suelen ser imágenes con URLs no convencionales (lazy loading con data-src, fondo CSS, iframes), que el detector no reconoce como <img>. El plugin solo procesa <img src> e <img data-src> estándar. Para casos exóticos hay que extender el procesador.

El log se llena de avisos de plugins terceros. WordPress es ruidoso por naturaleza, especialmente con WP_DEBUG activado. Los avisos que importan son los que empiezan por [Copia Estática] o los PHP Fatal error y PHP Warning. Los WordPress database error o PHP Deprecated de otros plugins puedes ignorarlos durante la prueba.

Recapitulando los comandos esenciales

Para tu referencia, los comandos que más vas a usar:

# Ver el log en tiempo real durante la generación
tail -f wp-content/debug.log

# Listar CPTs disponibles en tu WordPress
wp post-type list --public=true --fields=name,label,_builtin

# Contar HTML generados de un CPT
ls wp-content/uploads/copia-estatica-html/<cpt>/*.html | wc -l

# Verificar que las imágenes son reales y no HTML disfrazado
file wp-content/uploads/copia-estatica-html/img/*.jp*g

# Contar imágenes referenciadas vs imágenes existentes
grep -ohE 'src="\.\.\/img/[a-f0-9]+\.[a-z]+"' <cpt>/*.html | sort -u | wc -l
ls wp-content/uploads/copia-estatica-html/img/ | wc -l

# Empaquetar para subir a otro dominio
zip -r ~/cpt-export.zip <cpt>/ img/

Y el recordatorio principal: con WP_DEBUG_LOG activado, casi cualquier problema que tengas dejará un rastro en debug.log. Empieza siempre mirando ahí.

Para terminar

La v1.9 cierra un hueco que tenía el plugin desde su nacimiento: la mayoría de blogs modernos no son solo posts y páginas, sino que incluyen al menos un CPT (a veces varios). Cualquier copia estática que pretenda archivar el blog «tal como lo ven los visitantes» tiene que cubrirlos.

El plugin está en GitHub, las releases están etiquetadas y firmadas, y el código pasa el Plugin Check oficial de WordPress.org sin errores. Issues y pull requests son bienvenidos. Si encuentras una casuística de CPT que no contempla (un campo personalizado con imagen, un plugin que registra contenido de forma exótica, un permalink especial), abre un issue con el detalle y los logs.

Y como siempre: si solo quieres archivar tu blog y olvidarte, este plugin lo hace. Lo activas, eliges qué exportar, y al final tienes una carpeta de HTML autónomos que se pueden servir desde cualquier sitio. Memoria USB incluida.