Importación de contenido

En esta página

El sistema de importación de EmDash usa una arquitectura de fuentes pluggable. Cada fuente sabe cómo sondear, analizar y obtener contenido de una plataforma específica.

Fuentes de importación

ID de fuentePlataformaSondeoOAuthImportación completa
wxrArchivo de exportación WordPressNoNo
wordpress-comWordPress.com
wordpress-restWordPress autoalojadoNoSolo sondeo

Subida de archivo WXR

El método de importación más completo. Sube un archivo de exportación WordPress eXtended RSS (WXR) directamente al panel de administración.

Capacidades:

  • Todos los tipos de entrada (incluidos los personalizados)
  • Todos los campos meta
  • Borradores y entradas privadas
  • Jerarquía completa de taxonomías
  • Metadatos de adjuntos de medios

Cómo obtener un archivo WXR:

  1. En el admin de WordPress, ve a Herramientas → Exportar
  2. Selecciona Todo el contenido o tipos de entrada específicos
  3. Haz clic en Descargar archivo de exportación
  4. Sube el archivo .xml a EmDash

OAuth de WordPress.com

Para sitios alojados en WordPress.com, conéctate vía OAuth para importar sin exportaciones manuales de archivos.

  1. Introduce la URL de tu sitio WordPress.com
  2. Haz clic en Conectar con WordPress.com
  3. Autoriza EmDash en la ventana emergente de WordPress.com
  4. Selecciona el contenido a importar

Qué incluye:

  • Contenido publicado y borradores
  • Entradas privadas (con autorización)
  • Archivos de medios vía API
  • Campos personalizados expuestos a la REST API

Sondeo de la REST API de WordPress

Cuando introduces una URL, EmDash sondea el sitio para detectar WordPress y mostrar el contenido disponible:

Detected: WordPress 6.4
├── Posts: 127 (published)
├── Pages: 12 (published)
└── Media: 89 files

Note: Drafts and private content require authentication
or a full WXR export.

El sondeo REST es informativo. Para importaciones completas, sugiere subir un archivo WXR o conectarse vía OAuth (para WordPress.com).

Flujo de importación

Todas las fuentes siguen el mismo flujo:

┌─────────────┐     ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   Conectar  │────▶│   Analizar  │────▶│   Preparar  │────▶│   Ejecutar  │
│  (sondear/  │     │  (verificar │     │  (crear     │     │  (importar  │
│   subir)    │     │   esquema)  │     │   esquema)  │     │   contenido)│
└─────────────┘     └─────────────┘     └─────────────┘     └─────────────┘

Paso 1: Conectar

Introduce una URL para sondear o sube un archivo directamente.

El sondeo de URL ejecuta todas las fuentes registradas en paralelo. La coincidencia con mayor confianza determina la acción sugerida:

  • Sitio WordPress.com → Ofrecer conexión OAuth
  • WordPress autoalojado → Mostrar instrucciones de exportación
  • Desconocido → Sugerir subida de archivo

Paso 2: Analizar

La fuente analiza el contenido y verifica la compatibilidad del esquema:

Post Types:
├── post (127) → posts [Nueva colección]
├── page (12)  → pages [Existente, compatible]
├── product (45) → products [Añadir 3 campos]
└── revision (234) → [Omitir - tipo interno]

Required Schema Changes:
├── Crear colección: posts
├── Añadir campos a pages: featured_image
└── Crear colección: products

Cada tipo de entrada muestra su estado:

EstadoSignificado
ReadyLa colección existe con campos compatibles
New collectionSe creará automáticamente
Add fieldsLa colección existe, se añaden campos faltantes
IncompatibleConflictos de tipo de campo (corrección manual necesaria)

Paso 3: Preparar esquema

Haz clic en Crear esquema e importar para:

  1. Crear nuevas colecciones vía SchemaRegistry
  2. Añadir campos faltantes con los tipos de columna correctos
  3. Configurar tablas de contenido con índices

Paso 4: Ejecutar importación

El contenido se importa secuencialmente:

  • Gutenberg/HTML convertido a Portable Text
  • Estado de WordPress mapeado a estado de EmDash
  • Autores de WordPress mapeados a propiedad (authorId) y bylines de presentación
  • Taxonomías creadas y vinculadas
  • Bloques reutilizables (wp_block) importados como Secciones
  • Progreso mostrado en tiempo real

Comportamiento de importación de autores:

  • Si un mapeo de autor apunta a un usuario de EmDash, la propiedad se establece a ese usuario y se crea/reutiliza un byline vinculado para el mismo usuario.
  • Si no hay mapeo de usuario, se crea/reutiliza un byline de invitado a partir de la identidad del autor de WordPress.
  • Las entradas importadas obtienen créditos de byline ordenados, con el primer crédito establecido como primaryBylineId.

Paso 5: Importación de medios (Opcional)

Después del contenido, opcionalmente importa los medios:

  1. Análisis — Muestra conteos de adjuntos por tipo

    Media found:
    ├── Images: 75 files
    ├── Video: 10 files
    └── Other: 4 files
  2. Descarga — Transmite desde URLs de WordPress con progreso

    Importing media...
    ├── 45 of 89 (50%)
    ├── Current: vacation-photo.jpg
    └── Status: Uploading
  3. Reescritura de URLs — El contenido se actualiza automáticamente con las nuevas URLs

La importación de medios usa hashing de contenido (xxHash64) para deduplicación. La misma imagen usada en múltiples posts se almacena una sola vez.

Interfaz de fuente

Las fuentes de importación implementan una interfaz estándar:

interface ImportSource {
	/** Identificador único */
	id: string;

	/** Nombre para mostrar */
	name: string;

	/** Sondear una URL (opcional) */
	probe?(url: string): Promise<SourceProbeResult | null>;

	/** Analizar contenido de esta fuente */
	analyze(input: SourceInput, context: ImportContext): Promise<ImportAnalysis>;

	/** Transmitir elementos de contenido */
	fetchContent(input: SourceInput, options: FetchOptions): AsyncGenerator<NormalizedItem>;
}

Tipos de entrada

Las fuentes aceptan diferentes tipos de entrada:

// Subida de archivo (WXR)
{ type: "file", file: File }

// URL con token opcional (REST API)
{ type: "url", url: string, token?: string }

// Conexión OAuth (WordPress.com)
{ type: "oauth", url: string, accessToken: string }

Salida normalizada

Todas las fuentes producen el mismo formato normalizado:

interface NormalizedItem {
	sourceId: string | number;
	postType: string;
	status: "publish" | "draft" | "pending" | "private" | "future";
	slug: string;
	title: string;
	content: PortableTextBlock[];
	excerpt?: string;
	date: Date;
	author?: string;
	authors?: string[];
	categories?: string[];
	tags?: string[];
	meta?: Record<string, unknown>;
	featuredImage?: string;
}

Endpoints de API

El sistema de importación expone estos endpoints:

Sondear URL

POST /_emdash/api/import/probe
Content-Type: application/json

{ "url": "https://example.com" }

Devuelve la plataforma detectada y la acción sugerida.

Analizar WXR

POST /_emdash/api/import/wordpress/analyze
Content-Type: multipart/form-data

file: [Exportación WordPress .xml]

Devuelve el análisis de tipos de entrada con compatibilidad de esquema.

Preparar esquema

POST /_emdash/api/import/wordpress/prepare
Content-Type: application/json

{
  "postTypes": [
    { "name": "post", "collection": "posts", "enabled": true }
  ]
}

Crea colecciones y campos.

Ejecutar importación

POST /_emdash/api/import/wordpress/execute
Content-Type: multipart/form-data

file: [Exportación WordPress .xml]
config: { "postTypeMappings": { "post": { "collection": "posts" } } }

Importa contenido a las colecciones especificadas.

Importar medios

POST /_emdash/api/import/wordpress/media
Content-Type: application/json

{
  "attachments": [{ "id": 123, "url": "https://..." }],
  "stream": true
}

Transmite actualizaciones de progreso NDJSON durante la descarga/subida.

Reescribir URLs

POST /_emdash/api/import/wordpress/rewrite-urls
Content-Type: application/json

{
  "urlMap": { "https://old.com/image.jpg": "/_emdash/media/abc123" }
}

Actualiza el contenido Portable Text con las nuevas URLs de medios.

Manejo de errores

Errores recuperables

  • Timeout de red — Reintento con backoff
  • Fallo de análisis de un elemento — Registrado, omitido, la importación continúa
  • Fallo de descarga de medios — Marcado para manejo manual

Errores fatales

  • Formato de archivo inválido — La importación se detiene con mensaje de error
  • Conexión a base de datos perdida — La importación se pausa, permite reanudar
  • Cuota de almacenamiento excedida — La importación se detiene, muestra el uso

Informe de errores

Después de la importación:

Import Complete

✓ 125 posts imported
✓ 12 pages imported
✓ 85 media references recorded

⚠ 2 items had warnings:
  - Post "Special Characters ñ" - title encoding fixed
  - Page "About" - duplicate slug renamed to "about-1"

✗ 1 item failed:
  - Post ID 456 - content parsing error (saved as draft)

Los elementos fallidos se guardan como borradores con el contenido original en _importError para revisión.

Crear fuentes personalizadas

Crea una fuente para otras plataformas:

import type { ImportSource } from "emdash/import";

export const mySource: ImportSource = {
	id: "my-platform",
	name: "My Platform",
	description: "Import from My Platform",
	icon: "globe",
	canProbe: true,

	async probe(url) {
		const response = await fetch(`${url}/api/info`);
		if (!response.ok) return null;

		return {
			sourceId: "my-platform",
			confidence: "definite",
			detected: { platform: "my-platform" },
			// ...
		};
	},

	async analyze(input, context) {
		// Analizar contenido
		// Devolver ImportAnalysis
	},

	async *fetchContent(input, options) {
		// Producir NormalizedItem para cada pieza de contenido
		for (const item of items) {
			yield {
				sourceId: item.id,
				postType: "post",
				title: item.title,
				content: convertToPortableText(item.body),
				// ...
			};
		}
	},
};

Registra la fuente en tu configuración de EmDash:

import { mySource } from "./src/import/custom-source";

export default defineConfig({
	integrations: [
		emdash({
			import: {
				sources: [mySource],
			},
		}),
	],
});

Próximos pasos