blueprint.json¶
What it is¶
In this repository, blueprint.json is the portable description of the initial Omeka S state that should exist inside a playground scope.
The default file is:
assets/blueprints/default.blueprint.json
It follows the shared Omeka S blueprint format, also used by Omeka-S-Cli. Settings that only make sense in the browser live under x-playground. It is inspired by WordPress Playground blueprints, but it is not the upstream WordPress schema.
- schema:
v0, the latestv0.x.yrelease of the shared format (local copy:assets/blueprints/shared/v0/blueprint-schema.json) - loading,
$importand normalization:src/shared/blueprint-imports.js,src/shared/blueprint.js - what the Playground does with each key: Support matrix
The same blueprint.json can be used by the Playground and by Omeka-S-Cli (blueprint:deploy, which the erseco/alpine-omeka-s Docker image runs from OMEKA_BLUEPRINT). Options for one of them go under its own x- key (x-playground here); the other ignores it.
Blueprints written for the earlier Playground format keep working; see Legacy format.
How the repository uses it¶
The shell loads a blueprint, normalizes missing values, and stores the active version for the current scope. The runtime then consumes that normalized blueprint during boot to:
- set install metadata such as title, locale, and timezone
- create and authenticate the primary admin account
- create additional users and apply per-user settings
- download, install, or activate modules and themes
- import RDF vocabularies and resource templates
- apply global settings
- create item sets, items, and media
- create one or more sites, assign per-site user permissions, and pick the default
- choose the landing page after boot
Because the blueprint influences first-boot behavior, a small JSON change can alter installation, login, routing, or demo content.
Structure used by this project¶
The most important top-level properties are:
| Property | Purpose | Notes |
|---|---|---|
$schema |
Editor/schema reference | https://omeka-s-contrib.github.io/omeka-s-blueprints/schema/v0/blueprint-schema.json |
meta |
Human-readable metadata | Good place for title, author, and description |
preferredVersions |
Informational runtime targets | Useful for intent, not a strict installer lockfile |
install |
Install values | title, locale, timezone, and the first administrator in admin (name, email, password) |
settings |
Global Omeka settings | Setting id → value, or a list of such maps merged in order; see Global settings |
users |
Omeka users to create | Each may carry settings; install.admin goes first; a user without role is an author and one without password gets the configured admin password; when no install.admin or global_admin user is declared, the configured administrator goes first |
themes |
Themes to install | See Add-on sources |
modules |
Modules to download, install, or activate | See Add-on sources; a repeated name overrides the earlier entry |
files |
Files placed in the Omeka S installation | See Files |
vocabularies |
RDF vocabularies to import | See Vocabularies |
resourceTemplates |
Resource-template exports to import | See Resource templates |
itemSets |
Collections created before items | Referenced by item titles later; an entry can also be a portable JSON-LD source; see Content errors |
items |
Sample resources and media | Media currently uses URL sources; items[].sites assigns sites by slug; an entry can also be a portable JSON-LD source; see Content errors |
sites |
One or more public sites with per-site permissions | One is the default |
x-playground |
Browser runtime settings | landingPage, login, debug, phpConstants; see Playground settings |
Every list except sites can also hold $import entries.
Playground settings (x-playground)¶
Other consumers of the format ignore this block.
| Property | Purpose | Notes |
|---|---|---|
landingPage |
Initial post-boot path | Should usually begin with / |
login |
Credentials used by autologin | Defaults to install.admin, else the first user |
debug.enabled |
Enables development-style diagnostics | Helpful for install/debug sessions |
phpConstants |
PHP constants defined before Omeka boots | Name → boolean / string / number; see PHP constants |
itemSets, items |
Portable JSON-LD content, the earlier notation | Still read, after the shared lists; write source entries in the shared itemSets and items instead |
Portable JSON-LD content¶
An entry of itemSets or items can point to a portable JSON-LD file with source, the format Omeka-S-Cli's item:export writes: Omeka's JSON-LD with an inline @context, one resource per file, where references name a record instead of an instance id. This is the shared format's source entry (omeka-s-blueprints#14), the one Omeka-S-Cli used to read from x-omeka-s-cli.
{
"itemSets": [{ "source": "./content/item-sets/photographs.jsonld" }],
"items": [
{
"source": "./content/items/harbour.jsonld",
"sites": ["collections"],
"media": [{ "url": "./content/media/harbour.png", "title": "Photograph" }],
"onError": "skip"
}
]
}
| Field | Notes |
|---|---|
source |
The JSON-LD file, relative to the file that declares it |
title |
The title in the file; only used in messages, and so that a simple item can name a source item set |
sites |
Items only: site slugs or titles that replace the file's o:site |
media |
Items only: as items[].media (URL media) |
onError |
See Content errors |
Simple and source entries are created in list order, item sets before items, with Omeka-S-Cli's rules:
- Properties are matched by namespace: a prefix of the file's
@contextmaps to the one this installation uses for that namespace. o-ref:id({"<term>": "<value>"}) identifies the record, else its title. A record that already exists is left as it is.o-ref:reflinks to another record (o:item_set, or a value of typeresource:*). Refer to records declared earlier or already in the installation.- Classes by
{"o:term"}, resource templates by{"o:label"}, sites by{"o:slug"}. An item with no site, or none that matches, goes to the default site.
The o-ref keys are recognized by their namespace, https://omeka-s-contrib.github.io/omeka-s-ref/ns#, under any prefix.
x-playground.itemSets and x-playground.items, the earlier notation for these entries, are still read, after the shared lists. Title-only x-omeka-s-cli entries have no x-playground form: write them as simple itemSets and items.
Content errors (onError)¶
Every itemSets and items entry, simple or with a source, takes onError:
| Value | What happens when the entry cannot be applied |
|---|---|
fail (default) |
The boot stops, with the reason in the log |
skip |
The entry is left out, with a warning that names the reason |
These are errors for an entry:
- a JSON-LD file that cannot be downloaded or is not a JSON-LD object;
- a missing vocabulary, or an unknown property, class, template or data type;
- an
o-ref:refthat matches no record, or more than one; - an item set in a simple item's
itemSetsthat was not created (a skipped one included); - a media file that cannot be fetched or that Omeka S rejects. An item created in that boot is removed again, so the item and its media are created together or not at all.
A record that already exists is not an error. After a boot that stopped, content is not marked as seeded, so the next boot tries again, and entries created before the error are found and left as they are. The default blueprint marks its sample content "skip", so a sample image that cannot be fetched does not stop the boot.
Add-on sources¶
modules[].source and themes[].source are a single string:
- a ZIP URL, used as is (it already pins a release, so it wins over
version); - a local ZIP release: a path relative to the file that declares the entry (see Relative paths), as in Omeka-S-Cli;
- a GitHub repository, as
gh:owner/repoorhttps://github.com/owner/repo(.git): the archive of the#refin the source, else ofversion(a tag or branch), else of the default branch; - nothing: the add-on shipped with the core is used (e.g. the
defaulttheme); otherwise the name is looked up in the omeka.org catalog (s_module.json/s_theme.json), atversionor the latest release.
Other git hosts, git@ URLs and other schemes are rejected. A release resolved from the catalog is cached, so later boots do not fetch the catalog again; change version to move to another release.
Files¶
files places files in the Omeka S installation after modules and themes, for example a module config file or an extra asset bundle for a module:
{
"files": [
{ "source": "./config/cleanurl.config.php", "destination": "config/cleanurl.config.php" },
{ "source": "https://example.org/editor.zip", "destination": "modules/ExeLearning/dist/static", "extract": true }
]
}
destinationis relative to the Omeka S root; absolute paths and..segments are rejected.- With
extract: true,sourceis a ZIP extracted intodestination; a single top-level folder in the archive is stripped, as with add-on ZIPs. - Files are cached by source and re-applied on every boot, because the Omeka S root is rebuilt from the core bundle.
- A relative
sourceresolves against the file that declares it (see Relative paths).
PHP constants¶
x-playground.phpConstants defines PHP constants in the runtime's auto_prepend file, which runs
before Omeka boots, so they are visible to module defined() / getenv() checks. Each
entry is emitted as a guarded define():
{
"x-playground": {
"phpConstants": {
"MY_FLAG": true,
"MY_LABEL": "demo",
"MY_LIMIT": 50
}
}
}
becomes:
if (!defined('MY_FLAG')) { define('MY_FLAG', true); }
if (!defined('MY_LABEL')) { define('MY_LABEL', 'demo'); }
if (!defined('MY_LIMIT')) { define('MY_LIMIT', 50); }
Values may be boolean, string or number; constant names must match ^[A-Z_][A-Z0-9_]*$
(other names are skipped). This lets a module's own blueprint enable module-specific
configuration without the playground engine knowing anything module-specific. For example,
the eXeLearning module declares the EXELEARNING_UNSAFE_LEGACY_IFRAME constant
so its demo renders the content iframe same-origin (the php-wasm service worker cannot serve
an opaque subframe); a real Omeka install never defines that constant.
Global settings¶
settings writes Omeka global settings (the setting table) by id. It accepts a map, or a
list of maps merged in order, where a later map overrides earlier values:
{
"settings": [
{ "installation_title": "Classroom Demo", "pagination_per_page": 50 },
{ "locale": "es" }
]
}
- Values are stored as-is (strings, numbers, booleans, arrays, or objects).
- Settings are applied after every module is installed, so they override module defaults,
and after
install, so for exampleinstallation_titlewins overinstall.title. - Like
install, they are re-applied on every boot of the same scope. - When the blueprint defines sites,
default_siteis set afterwards from them; usesetAsDefaultinstead. - In the list form, entries can be
$importreferences. An imported document is a map, or a list of maps and further references; everything is merged in order.
Example¶
{
"$schema": "https://omeka-s-contrib.github.io/omeka-s-blueprints/schema/v0/blueprint-schema.json",
"meta": {
"title": "Demo classroom blueprint",
"author": "ateeducacion",
"description": "Creates a reusable demo site with sample media."
},
"install": {
"title": "Classroom Demo",
"locale": "es",
"timezone": "Atlantic/Canary",
"admin": { "name": "admin", "email": "admin@example.com", "password": "password" }
},
"themes": ["foundation"],
"modules": [
{ "name": "CSVImport", "state": "activate" }
],
"itemSets": [
{ "title": "Playground Collection" }
],
"items": [
{
"title": "Openverse Sample Image",
"itemSets": ["Playground Collection"],
"media": [
{
"type": "url",
"url": "./assets/samples/playground-sample.png",
"title": "Playground sample image"
}
]
}
],
"sites": [
{ "title": "Demo Site", "slug": "demo-site", "theme": "foundation", "setAsDefault": true }
],
"x-playground": {
"landingPage": "/admin",
"debug": { "enabled": false }
}
}
Multiple sites, permissions, and per-user settings¶
Use the sites array to provision more than one site and to grant users access
to specific sites. This is what makes access-control modules such as
IsolatedSites testable
in the browser: give a user a per-site role, flip a per-user setting, and assign
items to individual sites.
sites[]acceptstitle,slug,summary,theme,isPublic,setAsDefaultandpermissions.slugmay only contain letters, digits,_and-, and is kept as written. Without one, Omeka S derives it from the title, and the title identifies the site on later boots.- A site that already exists (same slug, else same title) is left as it is, so changes made in the admin survive a reload. New sites add newly created items automatically, as in the Omeka admin, and the administrator who creates them is their owner and a site admin.
sites[].permissions[]grants a blueprint user (by email) a site role ofviewer(the default),editor, oradmin. A missing permission is added on every boot; a user who already has another role keeps it (with a warning); no permission is removed.- Exactly one site is the default. If no entry sets
setAsDefault: true, the first one is used. Thedefault_sitesetting is written when the site is created. users[].settingsis an object written verbatim to each user's settings (user_setting), e.g.limit_to_granted_sites.items[].siteslists the slugs or titles (case-insensitive) of the sites an item is assigned to. Without it, items go to the default site.
{
"users": [
{ "username": "admin", "email": "admin@example.com", "password": "password", "role": "global_admin" },
{
"username": "editor_a",
"email": "editor.a@example.com",
"password": "password",
"role": "site_editor",
"settings": { "limit_to_granted_sites": true, "limit_to_own_assets": true }
}
],
"sites": [
{
"title": "Site A",
"slug": "site-a",
"setAsDefault": true,
"permissions": [{ "user": "editor.a@example.com", "role": "admin" }]
},
{ "title": "Site B", "slug": "site-b" }
],
"items": [
{ "title": "Doc A1", "sites": ["site-a"] },
{ "title": "Doc B1", "sites": ["site-b"] }
]
}
With this blueprint, signing in as editor.a@example.com (with IsolatedSites
active) shows only Site A and its items, while the admin keeps full visibility.
Example file for Common + EasyAdmin¶
There is a ready-to-copy example at:
blueprint-sample.json
That sample installs Common first and then EasyAdmin. It is the better file to reuse here because it is already tracked as a real project sample, so the documentation should point at it instead of duplicating a second near-identical blueprint under docs/.
How to write and maintain it well¶
Keep it readable¶
- Prefer one clear responsibility per section.
- Keep related values grouped together instead of scattering overrides.
- Use descriptive
meta.titleandmeta.descriptionvalues so future contributors understand intent immediately.
Keep it stable¶
- Prefer bundled add-ons or omeka.org releases (no
source, with aversion) before remote ZIP URLs. - Avoid accidental duplicate module or theme names. The last occurrence wins, and a warning is logged when it changes the earlier definition.
- Keep
x-playground.landingPagesimple and explicit./adminis the safest default for contributor-oriented blueprints.
Keep it maintainable¶
- Declare the administrator in
install.admin; it becomes the first user and the autologin account. - Only set
x-playground.loginto sign in as another user. - Use a small number of representative sample items instead of large demo datasets that slow down resets and reviews.
- Prefer relative media URLs for repository-bundled samples when possible.
Comments (JSONC)¶
Blueprints and imported files may contain comments (// and /* */) and trailing commas, as Omeka-S-Cli reads them (.jsonc). This applies to every way a blueprint arrives: ?blueprint-url=, ?blueprint=, uploads, the editor and $import. JSON tooling and the shared schema only see the parsed document. The editor's Export writes plain JSON.
{
"modules": [
"Common", // needed by the module below
{ "$import": "./partials/modules.jsonc" },
],
}
Imports ($import)¶
Any entry of modules, themes, files, vocabularies, resourceTemplates, users,
sites, itemSets, items and the list form of settings can be a reference to another JSON file:
{
"modules": ["Common", { "$import": "./partials/modules.json" }],
"vocabularies": [{ "$import": "https://example.org/shared/vocabularies.json" }]
}
- The referenced file holds more entries of the same list, or a single entry, and they are spliced in place of the reference.
- An imported file can import further files. A cycle stops the boot with the chain of files
(
Circular $import: a.json -> b.json -> a.json); importing the same file twice from different places is fine. Nesting is limited to 16 levels. - The reference is an
http(s)URL, a path relative to the file that contains it, or a GitHub/GitLab file reference as Omeka-S-Cli accepts them:gh:owner/repo[@ref]:path,gl:group/repo[@ref]:path, or agithub.com/…/blob/…or…/-/blob/…page URL (turned into the raw file URL). - Absolute paths (
/…,\\…,C:\…) andfile:URLs are rejected, as in Omeka-S-Cli, in$importand in thesourceoffiles,vocabularies,resourceTemplatesand add-on entries, whether or not the blueprint has a URL. Other schemes (data:, …) are rejected too. - Imported files are fetched by the browser, like
?blueprint-url=itself, so their host must allow CORS (GitHub raw files do). - A failed download, a file that is not JSON, or a file that is not a list or an object stops the boot with the file's URL. When the blueprint declares the shared
$schema, every imported file is also validated against the schema of its list. sitestakes$importas in Omeka-S-Cli 0.18, although the sharedv0schema does not list it yet: imported sites are checked against the schema's site definition. An$importanywhere else (such as a settings map) is rejected instead of being ignored.
Relative paths¶
Relative paths resolve against the file that contains them (RFC 3986), not against the root blueprint:
| Where | Relative to |
|---|---|
$import in the blueprint |
the blueprint URL |
$import in an imported file |
that imported file |
files[].source, vocabularies[].source, resourceTemplates[].source |
the file that declares the entry |
modules[].source, themes[].source given as a path (a local ZIP) |
the file that declares the entry |
itemSets[].source, items[].source, items[].media[].url, and the same fields under x-playground |
the file that declares the entry |
How the blueprint arrives decides whether it has a URL:
| Blueprint | Base URL |
|---|---|
?blueprint-url=…, ?blueprint=https://…, the configured default blueprint |
that URL |
?blueprint=<base64> (also what the editor's Run uses), ?blueprint-data=, an uploaded file |
none |
Without a base URL, a relative $import stops the boot with an error (the editor and the upload already refuse it), because there is no file to resolve it against. Absolute references still work. For compatibility, relative files, vocabularies and resourceTemplates sources of such a blueprint keep resolving against the Playground page, as before. So do media URLs; a root-relative media path (/…) always does.
Vocabularies¶
vocabularies imports RDF vocabularies with Omeka's RDF importer, as Vocabularies › Import new vocabulary does:
{
"vocabularies": [
{
"prefix": "lrmi",
"namespaceUri": "http://purl.org/dcx/lrmi-terms/",
"label": "LRMI",
"format": "turtle",
"source": "https://www.dublincore.org/specifications/lrmi/lrmi_terms/2022-06-14/lrmi-terms.ttl"
}
]
}
| Field | Notes |
|---|---|
source |
Required. URL or relative path of the RDF file |
namespaceUri, prefix, label |
Required. How the vocabulary appears in Omeka S |
comment |
Vocabulary comment |
format |
guess (the default; auto means the same), rdfxml, turtle, ntriples, jsonld, or any other format name of the importer |
lang |
Preferred language of labels and comments |
labelProperty, commentProperty |
Full URIs of the RDF properties to read labels and comments from |
- The source is downloaded by the worker, directly first (RDF hosts such as schema.org and dublincore.org allow CORS) and through the add-on proxy otherwise, and cached under
/persist, so a reload does not download it again. Change the URL to get a new version. - A vocabulary whose namespace URI already exists is left as it is, whatever its prefix or label. That is what makes reloads idempotent, and why the vocabularies Omeka installs itself (
dcterms,dctype,bibo,foaf) do not need to be declared. - A different vocabulary that already uses the same prefix makes the import fail, as in the admin form.
- A failed download, invalid RDF, or an RDF file without terms in
namespaceUristops the boot with the vocabulary and its source. - Existing vocabularies are not updated from a newer file (Omeka-S-Cli does that only with
--update).
Resource templates¶
resourceTemplates imports resource-template JSON exports (Resource templates › Export):
{
"resourceTemplates": [
{ "source": "./templates/book.json" },
{ "source": "./templates/book.json", "label": "Book (copy)", "ignoreDeps": true }
]
}
| Field | Notes |
|---|---|
source |
Required. URL or relative path of the export |
label |
Label to use instead of the export's o:label |
ignoreDeps |
Import even when this installation lacks some of the template's vocabularies, classes, properties or data types; those are left out |
- The export is checked and matched with Omeka's own import code (the admin Import form): a file that is not a valid export stops the boot.
- Classes and properties are matched by namespace URI and local name, never by database id, so the templates can use the vocabularies declared in the same blueprint.
- Data types are kept when they are registered in this installation (core or module data types). Without
ignoreDeps, any missing class, property or data type stops the boot with the list of what is missing. With it, the template is imported without them and a warning lists them. - A template whose label (after
labeloverrides it) already exists is left as it is, so reloads are idempotent and the user's edits are kept.
Provisioning order¶
On every boot, after Omeka S is installed:
- Modules and themes are downloaded; modules are installed and activated (with a fresh PHP boot after each module, as module activation requires).
filesare placed.vocabularies, thenresourceTemplates, once every module is active (so their data types are registered) and before anything that could use their properties.usersand their settings, thensitesand their permissions.settings, last, so neither a module nor the sites (default_site) override them. This is Omeka-S-Cli's order.itemSets, thenitems, each in list order (thex-playgroundones last), only on the first boot of a scope that gets through it.
Steps 1 to 5 run on every boot and find what already exists, so a reload neither duplicates nor resets it. Content (step 6) is seeded once per scope, so deleted or edited demo items stay as the user left them. Reset Playground, ?clean=1 or another blueprint starts again from a clean installation.
Entry identity (duplicates)¶
When a list (after imports) holds two entries for the same thing, they collapse into the first one: the later entry is shallow-merged into it (each field it gives replaces the earlier value as a whole, the others are kept), and the entry keeps its first position, so module install order does not change. A warning is logged when the later entry changes something. The identity of an entry, as written and compared without case:
| List | Identity |
|---|---|
modules, themes |
name (or the name string) |
files |
destination |
vocabularies |
namespaceUri |
resourceTemplates |
label, or source without a label |
users |
email |
sites |
slug, or title without a slug |
itemSets, items |
title |
"modules": [
{ "$import": "./modules.base.json" },
{ "name": "Common", "version": "3.4.72" }
]
Here Common keeps the place and the state the imported file gave it, and only its version changes.
These rules are what Omeka-S-Cli 0.18 implements and what omeka-s-contrib/omeka-s-blueprints#10 proposes. The published v0 specification only says that the later entry applies, so they may still change; the table lives in ENTRY_IDENTITY (src/shared/blueprint.js).
Schema validation¶
The shell validates a blueprint against a local copy of the shared v0 schema before booting it, so no schema is fetched at boot:
- As in Omeka-S-Cli, the blueprint is validated once its imports are resolved, together with the cross-references a schema cannot express: an item set named by an item must be declared, a site slug may only contain letters, digits,
_and-, a site theme must be declared inthemes(defaultalways is), and a site permission must name a user ofusersorinstall.admin. - A blueprint whose
$schemais the sharedv0schema (or av0.x.yrelease) must pass: any error stops the boot as aBlueprintSchemaErrorlisting them, and every$imported file is also checked on its own against the schema of its list, with its URL in the message. - Other blueprints (the legacy format, or no
$schema) only get a console warning, so the legacy keys keep working. - The editor shows the same errors while you type (the cross-references only when the blueprint has no
$importto fetch). - Errors that the schema cannot see (a download that fails, a cycle, a relative import without a base URL) are reported as
BlueprintImportError; errors while provisioning Omeka S (an RDF file that does not parse, a template that needs a missing vocabulary) are reported by the runtime with the blueprint entry. Each is reported once, separately.
npm run build-worker bundles the validator (Ajv) into dist/blueprint-schema.bundle.js. To refresh the local copy after a new v0.x.y release, download the published schema/v0/blueprint-schema.json over assets/blueprints/shared/v0/blueprint-schema.json.
Support matrix¶
What the Playground does with each top-level key of the shared format (v0):
| Key | Support | Notes |
|---|---|---|
$schema |
Supported | Selects strict validation for the shared schema |
meta, preferredVersions |
Supported | preferredVersions picks the runtime when the URL does not; reloading the same blueprint keeps the tab's runtime, such as one restored by Import |
install |
Supported | install.admin is the first user and the autologin account; without one, the configured administrator is |
modules, themes |
Supported | ZIP URL, local ZIP, GitHub and omeka.org catalog sources; other git hosts and schemes are rejected |
files |
Supported | |
vocabularies |
Supported | All fields; see Vocabularies |
resourceTemplates |
Supported | All fields; see Resource templates |
settings |
Supported | Map or list, with imports |
users |
Supported | Role author and display name = email by default, as in Omeka-S-Cli; a user without password gets the configured password |
sites |
Supported | With $import, as Omeka-S-Cli does; assignNewItems is ignored |
itemSets, items |
Supported | Seeded once per scope; portable JSON-LD source entries; onError; media of type url |
$import |
Supported | Every list the schema allows, and sites; see Imports |
x-playground |
Supported | Playground settings and portable JSON-LD content |
Other x-* keys |
Ignored | As the specification requires |
| Schema validation | Supported | Schema and cross-references, strict when $schema is the shared schema |
Since Omeka-S-Cli 0.18 the two read a blueprint the same way: JSONC, $import (in sites too), relative references and the rejection of absolute paths, duplicates merged into the first entry, vocabularies identified by namespace URI, local ZIP add-ons, and validation with cross-references. Differences that remain when one blueprint serves both:
- Omeka-S-Cli reads local files and keeps relative paths inside the blueprint's directory (
--root); the Playground only reads URLs, so a relative path can go anywhere on the same host. - Omeka-S-Cli 0.18 does not create
itemSetsoritems; the release after 0.18.2 does (GhentCDH/Omeka-S-Cli#182). Itsx-omeka-s-clicontent entries also take other media ingesters (upload,youtube,html, …), where the Playground only takesurlmedia. The Docker image runs it with--skip core, soinstallcomes from its environment variables there. - Existing users: Omeka-S-Cli leaves them as they are; the Playground updates them on every boot (role, name, password), so autologin keeps working with the blueprint's credentials.
- Without
setAsDefault, the Playground makes the first site the default; Omeka-S-Cli sets no default site. - Omeka-S-Cli changes existing vocabularies, templates and sites, and site roles, with
--update; the Playground never does. - Omeka-S-Cli requires the Common module for resource templates; the Playground uses the core import code.
Project-specific rules and conventions¶
These conventions come from the current implementation, not generic JSON style advice:
x-playground.landingPageis normalized to start with/.- Any role id is accepted, including roles added by modules (e.g.
guest). As a Playground convenience,adminandsupervisorare mapped toglobal_adminandsite_admin. - Addon names must be a single path segment; slashes and traversal-like names are rejected.
- Remote addon URLs are absolutized against the current page URL.
modules[].statesupportsdownload(place files only),install, andactivate(default).modules[].versionandthemes[].versionselect the omeka.org release, or the tag/branch of a GitHub source.- Repeated entries follow Entry identity: they are merged into the first occurrence, which keeps its position.
items[].media[].typecurrently supportsurl.- Exactly one site is forced to be the default (the first one if none is flagged).
sites[].permissions[].roleis clamped to one ofviewer,editor,admin(defaults toviewer); a permission whoseuseremail matches no created user is skipped with a warning.- A site slug that Omeka S would not accept is turned into a valid one for blueprints in the earlier format; the shared format reports it as an error.
items[].sitesentries match a site slug or title, without case; items with no match fall back to the default site.users[].settingskeys are written verbatim touser_setting; values are stored as-is.
If you change the semantics of any of those rules, update both the schema and the documentation together.
How to validate changes¶
- Edit the blueprint JSON.
- Validate it against the
v0schema: editors do it from$schema, and the Playground editor and shell do it too (see Schema validation). - Start the app and trigger a clean boot by importing the blueprint or using a new scope.
- Confirm the expected landing page, users, modules, themes, and sample content appear.
- If something fails during boot, temporarily enable
x-playground.debug.enabled.
Useful targeted checks:
node --check src/shared/blueprint.js
node --check src/runtime/bootstrap.js
Common mistakes to avoid¶
- Using the upstream WordPress Playground schema as if it were identical. This repository implements its own Omeka-specific blueprint format.
- Adding hidden assumptions to runtime code instead of the blueprint. That makes the setup harder to reason about.
- Setting
x-playground.loginto a user the blueprint does not create. Autologin fails. - Using fragile remote ZIP URLs. If the URL needs unusual redirects or post-install steps, it may not work in-browser.
- Overloading the blueprint with too much sample content. Large initial datasets slow resets and make review harder.
Troubleshooting¶
The playground boots but lands on the wrong page¶
Check x-playground.landingPage, current shell session state, and whether autologin bypassed a saved /login path.
A module or theme does not install¶
Verify the addon name, the source definition, and whether the remote host is compatible with the configured proxy and outbound HTTP policy.
Media fails to load¶
Confirm the URL resolves correctly from the deployed base path or local dev server. Relative media paths are resolved against the blueprint that declares them (against the page URL for an inline blueprint).
A blueprint import appears to do nothing¶
The shell only applies imported data after parsing and normalization. Check the browser console, shell logs, and whether the payload is valid JSON/base64url for blueprint-data.
Legacy format¶
Blueprints written for the earlier Playground format still load. Each legacy key maps onto the shared format; when both forms are present, the shared one wins.
| Legacy | Shared format |
|---|---|
siteOptions |
install (title, locale, timezone) |
login |
install.admin, or x-playground.login for another account |
landingPage, debug, phpConstants |
x-playground.landingPage, x-playground.debug, x-playground.phpConstants |
site |
sites with one entry (ignored when sites is present) |
source: { "type": "url", "url": "…" } |
source: "…" |
source: { "type": "omeka.org", "slug": "…" }, { "type": "bundled" } |
no source (resolved by name) |
modules[].assets: [{ "url", "destination" }] |
files: [{ "source", "destination": "modules/<name>/<destination>", "extract": true }] |
The editor's Export always writes the shared format. The previous schema stays at assets/blueprints/blueprint-schema.json for blueprints that still point to it.