Frequently asked questions

Do I need a database?

No. CTXR stores everything as JSON files on disk. The filesystem is the database. There’s nothing to install, configure, back up separately, or migrate.

What programming language do I need to know?

Templates are PHP. The platform runs on PHP 8.5 with zero dependencies — no Composer, no framework. If you can write HTML and read a JSON object, you can build a template. The helper functions (the_value(), block(), menu()) handle the heavy lifting.

Can I use my own CSS framework or JavaScript library?

Yes. Templates produce plain HTML. The editor layer attaches to data-* attributes, not to a component tree. You can use Tailwind, Bootstrap, vanilla CSS, Alpine.js, HTMX, or nothing at all. The platform doesn’t care what your markup looks like.

How do I deploy changes?

Upload your build/ directory to the space. Templates take effect immediately — there’s no build step, no compilation of assets, no deployment pipeline. Change a PHP file, reload the page.

Is content lost if the server crashes?

No. Everything is on disk as JSON files. If the server restarts, the space is exactly as it was. There’s no in-memory state to lose, no transaction log to replay. Backups are directory copies.

Can visitors see my draft content?

No. Drafts are only visible to authenticated editors. Visitors always see the compiled live graph. A node that has never been approved is invisible to the outside world.

Are my uploaded files private?

No. Files you upload become part of your space’s publishable content. Enabling view gating restricts access to the pages of your space, but the platform does not provide encrypted private storage. If you need to handle genuinely sensitive files — contracts, medical information, personal identifiers — use a dedicated secure storage service and link out. See the security and privacy page for the full picture.

Can I have multiple editors?

Yes, up to the limit set by your plan. Each editor has their own person account with email-code authentication and an individual permissions array. One editor might have full access while another can only create drafts.

What happens if a login code is intercepted?

Login codes are short-lived and single-use. Once entered, the code is consumed; a second attempt will fail. Codes also expire on their own after a short window. The biggest risk isn’t interception in transit — it’s someone having access to the editor’s mailbox. Protect editor email accounts with multi-factor authentication, and treat the mailbox as the credential it effectively is.

Can external systems read my content?

Yes. Create a WebAPI key with view permission in your space config. External systems authenticate with the bearer token and can query the full graph — by type, by identifier, by reference. The query API returns clean JSON without internal metadata.

What happens when I approve a change?

The compiler runs. It resolves all @id references in the draft into full node data, calculates derived values (like aggregate ratings), writes the compiled result as the live graph, and cascades to every node that references the changed content. One click, everything updates.

Can two spaces share content?

No. Spaces are fully isolated — separate data, separate config, separate templates. This is intentional. If you need content in two places, the API lets external systems query one space and push data to another.

What’s the difference between a page and a block?

A page has both @path and a pages/* build — that combination gives it a URL and a full HTML document. A block has a blocks/* build and no path — it renders as a fragment inside a page. A menu works the same way as a block (menus/* build, no path). The type alone doesn’t determine which one a node is — the same Place can be a page in one space and a card in another.

Can I use types that aren’t in Schema.org?

The platform doesn’t validate against Schema.org — it uses the vocabulary as a convention. You can use any @type value. However, sticking to Schema.org types means your structured data output (JSON-LD) is automatically valid for search engines and AI systems.

How does the editor know which fields are editable?

The template declares it. Elements rendered with the_value() or manual data-* attributes are editable. Elements without those attributes are static. The developer has full control over what editors can and cannot change.

Is there an admin dashboard?

No. Editors work directly on the live site. The toolbar, browser panel, and inspector provide the editing interface on top of the actual pages. There’s no separate admin area to learn, maintain, or secure.

How do I handle images?

Templates mark an element with data-inline-type="image" (the the_value('image', ['type' => 'image']) helper emits the attributes for you). The editor provides click-to-pick and drag-and-drop upload. Images are stored as files in the space’s files/ directory and referenced as ImageObjects in the node data, with optional focus point support for object-position.

Can I password-protect a space?

Yes. Enable viewGating in the organisation config. When active, even reading live content requires authentication. Without a valid bearer token, visitors see nothing.

Is CTXR GDPR-compliant?

CTXR acts as a processor; you, the organisation operating the space, are the controller of whatever personal data flows through it. The platform itself holds a minimal set — editor emails, display names, and short-lived session records — hosted in the EU by default. Anything you introduce on top (forms, content about individuals, uploaded files) is yours to document and manage. The security and privacy page covers what’s in place and what you’re expected to arrange on your side, including a data processing agreement.

What are identifiers for?

Identifiers link nodes to external systems. A Place with identifier: [{propertyID: "oup", value: "1234"}] can be found by querying byIdentifier("oup", "1234"). This lets partner systems ask “what do you have about our item?” without knowing your internal IDs.