glueful / thallo-importers
Thallo content format importers (CSV / Markdown / WordPress) as a removable capability pack.
Requires
- php: ^8.3
- glueful/aegis: ^1.14.0
- glueful/framework: ^1.64.0
- glueful/import-export: ^1.1.1
- glueful/thallo-contracts: v1.0.0-beta.55
- glueful/users: ^2.3.0
- league/commonmark: ^2.8
- symfony/html-sanitizer: ^7.0 || ^8.0
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- dev-main
- v1.0.0-beta.55
- v1.0.0-beta.54
- v1.0.0-beta.53
- v1.0.0-beta.52
- v1.0.0-beta.51
- v1.0.0-beta.50
- v1.0.0-beta.49
- v1.0.0-beta.48
- v1.0.0-beta.47
- v1.0.0-beta.46
- v1.0.0-beta.45
- v1.0.0-beta.44
- v1.0.0-beta.43
- v1.0.0-beta.42
- v1.0.0-beta.41
- v1.0.0-beta.40
- v1.0.0-beta.39
- v1.0.0-beta.38
- v1.0.0-beta.37
- v1.0.0-beta.36
- v1.0.0-beta.35
- v1.0.0-beta.34
- v1.0.0-beta.33
- v1.0.0-beta.32
- v1.0.0-beta.31
- v1.0.0-beta.30
- v1.0.0-beta.29
- v1.0.0-beta.28
- v1.0.0-beta.27
- v1.0.0-beta.26
- v1.0.0-beta.25
- v1.0.0-beta.24
- v1.0.0-beta.23
- v1.0.0-beta.22
- v1.0.0-beta.21
This package is auto-updated.
Last update: 2026-09-23 15:31:30 UTC
README
Content format importers for Thallo — CSV, Markdown/MDX, and
WordPress (WXR) ingestion, plus CSV user provisioning — packaged as a capability pack. It
writes all content through Thallo's public ContentWriter contract and never reaches into the
application; an operator can switch it off without touching the core.
It is the reference pack of the composable-core
architecture: a library package that depends only on glueful/thallo-contracts (+ the framework
and glueful/import-export), declares a capability, and contributes a capability-gated admin
surface.
What it provides
Five import adapters, registered with the import_export.importer container tag and discovered by
the glueful/import-export engine:
| Adapter key | Label | What it ingests |
|---|---|---|
csv.content |
CSV | One content entry per CSV row; fields ↔ columns. |
markdown.content |
Markdown / MDX | YAML front matter → fields; body → a chosen text field (raw vs HTML by the field's format). |
markdown.folder |
Markdown folder (.zip) | A folder of Markdown as the pages of a content type — a documentation section. The import thallo:import:markdown runs, from an upload: repeatable, and it never deletes. See docs/documentation-sites.md. |
wordpress.content |
WordPress (WXR) | Posts/pages from a WXR export; title/excerpt/slug/date/status/author + content. |
csv.users |
Users (CSV) | Bulk user provisioning (profile + roles) via glueful/users + glueful/aegis. |
The content adapters resolve the target content type and its schema through ContentTypeReader,
map and coerce each row, then write via ContentWriter (validate() for dry-run previews,
createDraft() + optional publish() on commit). Validation failures surface as the contract
ValidationFailed exception — so the pack carries no reference to the engine. Mappings and
body_field are validated against the target schema at plan time, so a typo'd field fails
fast instead of silently importing entries with missing data.
Imported files are treated as untrusted. Markdown bodies are rendered with raw HTML stripped
and unsafe link schemes dropped; WordPress HTML bodies are run through symfony/html-sanitizer
(safe elements only — scripts, iframes, event handlers, and javascript: URLs are removed) before
being stored. A .zip is unpacked by Markdown\MarkdownZip, which writes only Markdown files,
refuses an archive holding a name that points outside the import, and counts the bytes it really
reads against a cap. User provisioning note: imported accounts are stamped email-verified (bulk
provisioning by an admin who vouches for the addresses) — don't import unvetted address lists.
The capability
The provider registers a single capability in boot():
new Capability('thallo.importers', label: 'Content importers', description: '…');
- Follows its engine. The capability's owning package is
glueful/import-export. Left untouched, it is on whenever that extension is enabled, which it is in a new project'sconfig/extensions.php. An operator turns it off or on in the admin under Extensions › Capabilities; the switch is stored system-wide and overrides the deploy-timethallo.capabilitiesconfig map. Enabling is refused whileglueful/import-exportis not enabled and schema-ready. - Backend-gated, not just UI. Every adapter calls
assertImportersEnabled()(theRequiresImportersCapabilitytrait) as the first line of its plan step — so a directPOST /import-export/importsfor a Thallo adapter fails closed when the capability is disabled, not only the admin controls. - UI-gated. The admin's format-import controls (Settings → Import / Export) and the users
bulk-CSV-import are shown only when
thallo.importersis enabled (via the admin capabilities store).
Boundary
This package depends on glueful/thallo-contracts, glueful/framework, glueful/import-export,
glueful/users, glueful/aegis, and league/commonmark — and never on glueful/thallo (the
application). The repo's composer boundaries check enforces this at both the Composer-dependency
and the source level (no Thallo\Core\ references in src/ or routes/).
Install
The pack ships with Thallo: glueful/thallo-core requires it at the same version and the project's
config/serviceproviders.php loads its provider, so there is nothing to install or enable per pack.
When the capability is off:
- Content delivery and the admin work unchanged.
- Snapshot export/import still works — the full-database NDJSON snapshot engine
(
ContentExporter/ContentImporter), its/v1/admin/import-export/uploadand/v1/admin/import-export/jobs/{uuid}/downloadendpoints, and the snapshot UI are core-owned, not part of this pack. - The
thallo.importerscapability drops out ofGET /v1/admin/capabilities, so the format-import admin section and the users bulk-CSV import hide.
Not included (deliberately)
Snapshot/backup restore (raw NDJSON of Thallo's own tables, versions, routes, publications, and
blob manifest) stays in core — it necessarily understands Thallo's internal storage model, so it is
not "import through the public content API" and is not exposed through thallo-contracts.
Contributing
This repository is a read-only mirror, published from
glueful/thallo on every release; its main is overwritten
by the next split, so nothing can land here. Issues and pull requests belong in glueful/thallo,
where this code lives at packages/thallo-importers/.