Importação de conteúdo

Nesta página

O sistema de importação do EmDash usa uma arquitetura de fontes plugáveis. Cada fonte sabe sondar, analisar e buscar conteúdo de uma plataforma específica.

Fontes de importação

ID da fontePlataformaSondaOAuthImportação completa
wxrArquivo de exportação WPNãoNãoSim
wordpress-comWordPress.comSimSimSim
wordpress-restWordPress auto-hospedadoSimNãoApenas sonda

Upload de arquivo WXR

O método mais completo. Envie um arquivo de exportação WordPress eXtended RSS (WXR) diretamente no painel de administração.

Capacidades:

  • Todos os tipos de post (incluindo personalizados)
  • Todos os campos meta
  • Rascunhos e posts privados
  • Hierarquia taxonômica completa
  • Metadados de anexos de mídia

Como obter um arquivo WXR:

  1. No admin do WordPress, vá em Ferramentas → Exportar
  2. Selecione Todo o conteúdo ou tipos de post específicos
  3. Clique em Baixar arquivo de exportação
  4. Envie o .xml para o EmDash

OAuth WordPress.com

Para sites no WordPress.com, conecte via OAuth sem exportações manuais.

  1. Informe a URL do site WordPress.com
  2. Clique em Conectar com WordPress.com
  3. Autorize o EmDash no pop-up do WordPress.com
  4. Selecione o conteúdo a importar

O que inclui:

  • Conteúdo publicado e rascunho
  • Posts privados (com autorização)
  • Arquivos de mídia via API
  • Campos personalizados expostos na REST API

Sonda REST do WordPress

Ao informar uma URL, o EmDash sonda o site, detecta WordPress e mostra o conteúdo disponível:

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.

A sonda REST é informativa. Para importações completas, sugere upload WXR ou OAuth (WordPress.com).

Fluxo de importação

Todas as fontes seguem o mesmo fluxo:

┌─────────────┐     ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   Connect   │────▶│   Analyze   │────▶│   Prepare   │────▶│   Execute   │
│  (probe/    │     │  (schema    │     │  (create    │     │  (import    │
│   upload)   │     │   check)    │     │   schema)   │     │   content)  │
└─────────────┘     └─────────────┘     └─────────────┘     └─────────────┘

Etapa 1: Conectar

Informe uma URL para sondar ou envie um arquivo diretamente.

A sonda por URL executa todas as fontes registradas em paralelo. A correspondência com maior confiança determina a ação sugerida:

  • Site WordPress.com → Oferecer conexão OAuth
  • WordPress auto-hospedado → Mostrar instruções de exportação
  • Desconhecido → Sugerir upload de arquivo

Etapa 2: Analisar

A fonte analisa o conteúdo e verifica compatibilidade de esquema:

Post Types:
├── post (127) → posts [New collection]
├── page (12)  → pages [Existing, compatible]
├── product (45) → products [Add 3 fields]
└── revision (234) → [Skip - internal type]

Required Schema Changes:
├── Create collection: posts
├── Add fields to pages: featured_image
└── Create collection: products

Cada tipo de post mostra um status:

StatusSignificado
ReadyColeção existe com campos compatíveis
New collectionSerá criada automaticamente
Add fieldsColeção existe; campos faltantes adicionados
IncompatibleConflitos de tipo de campo (correção manual)

Etapa 3: Preparar esquema

Clique em Criar esquema e importar para:

  1. Criar novas coleções via SchemaRegistry
  2. Adicionar campos faltantes com tipos de coluna corretos
  3. Configurar tabelas de conteúdo com índices

Etapa 4: Executar importação

O conteúdo é importado em sequência:

  • Gutenberg/HTML convertido para Portable Text
  • Status WordPress mapeado para status EmDash
  • Autores WordPress mapeados para propriedade (authorId) e linhas de crédito na apresentação
  • Taxonomias criadas e vinculadas
  • Blocos reutilizáveis (wp_block) importados como Sections
  • Progresso em tempo real

Comportamento de importação de autores:

  • Se o mapeamento de autor aponta para um usuário EmDash, a propriedade é definida para esse usuário e uma linha de crédito vinculada é criada/reutilizada para o mesmo usuário.
  • Sem mapeamento de usuário, uma linha de crédito convidado é criada/reutilizada a partir da identidade do autor no WordPress.
  • Entradas importadas recebem créditos de linha ordenados; o primeiro crédito é primaryBylineId.

Etapa 5: Importar mídia (opcional)

Após o conteúdo, importe mídia opcionalmente:

  1. Análise — Mostra contagens de anexos por tipo

    Media found:
    ├── Images: 75 files
    ├── Video: 10 files
    └── Other: 4 files
  2. Download — Transmite das URLs WordPress com progresso

    Importing media...
    ├── 45 of 89 (50%)
    ├── Current: vacation-photo.jpg
    └── Status: Uploading
  3. Reescrever URLs — O conteúdo é atualizado automaticamente com novas URLs

A importação de mídia usa hash de conteúdo (xxHash64) para deduplicação. A mesma imagem em vários posts é armazenada uma vez.

Interface da fonte

As fontes de importação implementam uma interface padrão:

interface ImportSource {
	/** Unique identifier */
	id: string;

	/** Display name */
	name: string;

	/** Probe a URL (optional) */
	probe?(url: string): Promise<SourceProbeResult | null>;

	/** Analyze content from this source */
	analyze(input: SourceInput, context: ImportContext): Promise<ImportAnalysis>;

	/** Stream content items */
	fetchContent(input: SourceInput, options: FetchOptions): AsyncGenerator<NormalizedItem>;
}

Tipos de entrada

As fontes aceitam entradas diferentes:

// File upload (WXR)
{ type: "file", file: File }

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

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

Saída normalizada

Todas as fontes produzem o mesmo 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 da API

O sistema de importação expõe estes endpoints:

Sondar URL

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

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

Retorna a plataforma detectada e a ação sugerida.

Analisar WXR

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

file: [WordPress export .xml]

Retorna análise de tipos de post e compatibilidade de esquema.

Preparar esquema

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

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

Cria coleções e campos.

Executar importação

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

file: [WordPress export .xml]
config: { "postTypeMappings": { "post": { "collection": "posts" } } }

Importa conteúdo para as coleções indicadas.

Importar mídia

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

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

Transmite atualizações de progresso NDJSON durante download/upload.

Reescrever URLs

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

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

Atualiza conteúdo Portable Text com novas URLs de mídia.

Tratamento de erros

Erros recuperáveis

  • Timeout de rede — Nova tentativa com backoff
  • Falha ao analisar um item — Registrado, ignorado, importação continua
  • Falha no download de mídia — Marcado para tratamento manual

Erros fatais

  • Formato de arquivo inválido — Importação para com mensagem
  • Conexão com banco perdida — Importação pausa, permite retomar
  • Cota de armazenamento excedida — Importação para, mostra uso

Relatório de erros

Após a importação:

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)

Itens com falha são salvos como rascunhos com conteúdo original em _importError para revisão.

Fontes personalizadas

Crie uma fonte para outras 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) {
		// Check if URL matches your platform
		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) {
		// Parse and analyze content
		// Return ImportAnalysis
	},

	async *fetchContent(input, options) {
		// Yield NormalizedItem for each content piece
		for (const item of items) {
			yield {
				sourceId: item.id,
				postType: "post",
				title: item.title,
				content: convertToPortableText(item.body),
				// ...
			};
		}
	},
};

Registre a fonte na configuração EmDash:

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

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

Próximos passos