Site settings
Values used across the whole site — social links, a contact email, an announcement, a font choice — are site settings. The theme defines them, editors change them in the admin, and every template reads them.
Defining settings
Define them in theme/config/site_settings.json, in the same JSON Schema form a section’s {% schema %} uses — the same field types, title, description, default and group:
{
"title": "Site settings",
"type": "object",
"additionalProperties": false,
"properties": {
"announcement_text": {
"type": "string",
"title": "Announcement bar text",
"description": "Shown above the header on every page. Leave empty to hide.",
"default": "",
"group": "Announcement bar"
},
"announcement_link": {
"type": "string",
"format": "url",
"title": "Announcement bar link",
"default": "",
"group": "Announcement bar"
},
"instagram_url": {
"type": "string",
"format": "url",
"title": "Instagram link",
"default": "",
"group": "Social links"
},
"headline_font": {
"type": "string",
"title": "Headline font",
"enum": ["Serif", "Sans-serif"],
"default": "Serif",
"group": "Typography"
}
}
}
Shopify uses config/settings_schema.json for its own, different format, and Shopify’s VS Code extension marks a Minamo file of that name as wrong — which can lead to it being “fixed” into Shopify’s form, where Minamo can’t read it. Sites made with 0.7.0 or 0.7.1 used that name: it still works in Minamo’s form, with a warning to rename it to site_settings.json.
Using settings in templates
Every layout, section, block and snippet reads them as {{ settings.<name> }} — including snippets pulled in with {% render %}, with no need to pass them along. (section.settings and block.settings are different: those belong to one section or block.)
{% if settings.announcement_text != blank %}
<div class="announcement">
{% if settings.announcement_link != blank %}
<a href="{{ settings.announcement_link }}">
{{ settings.announcement_text }}
</a>
{% else %}
<p>{{ settings.announcement_text }}</p>
{% endif %}
</div>
{% endif %}
- Defaults fill the gaps. A setting nobody has saved yet has its
default, or is blank without one. A property inrequiredmust have a validdefault, as for sections. - Check a link isn’t blank before rendering it, as above.
- Fonts: offer the choices with
enumand map each to a font stack in the layout, so the site only ever uses fonts it was designed for — the theme loads the font files itself:Liquid{% if settings.headline_font == 'Sans-serif' %} <style>:root { --headline: var(--sans); }</style> {% endif %}
Grouping settings
Settings with the same "group" appear under one collapsible heading on the admin’s Settings screen. Group by part of the site: Header, Announcement bar, Footer, Social links, Contact, Typography. See Grouping fields for the general advice.
Where the values live
The values editors save are content, in content/settings.json:
{
"schemaVersion": 7,
"settings": {
"instagram_url": "https://instagram.com/example",
"headline_font": "Sans-serif"
}
}
- No drafts. Like menus, a save is committed and live at once, and recorded in the site’s history. The admin’s preview shows unsaved changes as they’re made, before they’re saved.
- Pull and push carry them with the rest of the content, protected the same way as pages: settings changed on the live site since your last pull stop a push, and a copy with no
settings.jsonnever clears the live ones. See Pull, push & upgrading. - No file, no settings. A theme without
config/site_settings.jsonsimply has none. A file that can’t be used (not valid JSON, not a JSON Schema object, or a required property with no valid default) is left out with a start-up warning, like a broken section.