Skip to content

Store page template and data

The app’s blocks cover most cases. But a brand sometimes wants to show its stores elsewhere or differently: the hours in the footer of a store page, the stores of a city in a blog post, a custom section of the agency’s theme. All of this is possible in Liquid, because the app publishes each store that has a page in the shop’s metaobjects, which the theme reads as it reads products.

This page explains how this data is organized, shows how to read it, then details each field.

The merchant manages their stores in the app. Each time a store with a page is saved, the app publishes it to the shop, in about a second, in a Store page metaobject entry ($app:store_page): its page, with its address on the shop, its title and meta description, and all the store’s data: name, address, hours, photos, type…

A store without a page, only on the store locator (a stockist, for example), has no entry: the app’s blocks (store locator, store list) read it from data of their own, which Liquid can’t read outside them.

Store types (“Flagship”, “Stockist”…) are Store type entries ($app:store_type), and services (“Click & Collect”, “Repairs”…) Store service entries ($app:store_service): each page references them, and their names are translated.

An entry has the same handle as the store, which is also the end of its page’s address: paris-le-marais. A draft store is published as hidden: Liquid doesn’t see it. A store without a page, or deleted, has no entry.

The merchant sees these entries in Content > Metaobjects, read-only: they are always edited from the app.

In the app’s blocks, the types are written $app:store_page. In a theme section or snippet, they need their full name, with the app’s identifier on the shop: app--<id>--store_page. To find it:

  1. In Shopify, open Online Store > Themes, then, in the theme’s … menu, Edit code.
  2. Open the templates/metaobject folder.
  3. The store pages’ template is named app--<id>--store_page.json: the number is the app’s identifier.

The template only exists once created in the theme editor (see Set up the app).

Every store page shares the Store page template. The Store page block makes up the page, but you can place other theme sections around it: a banner, a brand text, featured products. Their texts connect to the store’s data without code:

  1. In the theme editor, open the Store page template.
  2. Add a theme section, for example a rich text.
  3. In a text setting, click the dynamic source (the small plug icon), then choose a field of the store: Name, City, Description…

Each page then shows its own store’s data.

On the Store page template, metaobject is the Store page entry shown, with all the store’s data. Each field is read by its key, followed by .value.

<ul class="services">
{%- for service in metaobject.store_services.value -%}
<li>{{ service.name.value }}</li>
{%- endfor -%}
</ul>

opening_hours is a JSON with a key per open day (see its format). Monday’s hours:

{%- assign hours = metaobject.opening_hours.value -%}
{%- for slot in hours.monday -%}
{{ slot.opens }}–{{ slot.closes }}
{%- else -%}
Closed
{%- endfor -%}

Translate “Closed” with your theme’s language files.

Anywhere else in the theme, read the entries by the type’s full name. For example, the links to the pages of the stores in Lyon:

{%- for store in metaobjects['app--<id>--store_page'].values -%}
{%- if store.city.value == 'Lyon' -%}
<a href="{{ store.system.url }}">{{ store.name.value }}</a>
{%- endif -%}
{%- endfor -%}

A given entry is read by its handle: metaobjects['app--<id>--store_page']['paris-le-marais']. This is how the nearby stores are read, whose handles nearby_stores gives.

Field Type Content
name text The name. Translatable.
address1, address2 text The address lines.
city, zip text The city, the postal code.
province_code text The Shopify province code (NY, QC, JP-13), empty for a country without provinces.
country_code text The two-letter ISO country code (FR).
address text The whole address on one line.
latitude, longitude decimal The coordinates, empty until the address is placed.
timezone text The store’s IANA time zone (Europe/Paris), from its coordinates.
phone, email text The contact.
access multi-line text How to get there, one line per stop or car park. Translatable.
opening_hours JSON The weekly hours (format below).
special_hours JSON The current and upcoming exceptional hours (format below).
description rich text The presentation text, to show with metafield_tag. Translatable.
photos list of files The photos; the first one is the main one.
store_services list of references to Store service The services; each one’s name is in name, translatable.
tags list of texts The tags.
store_type reference to Store type The type, empty without a type.
store_locator boolean True if the store is also on the store locator; false if it only has a page.
nearby_stores list of texts The handles of the 3 nearest stores with a page, nearest first.
seo_title text The page’s title: the one entered in the app, else the name. Translatable.
seo_description text The meta description: the one entered in the app, else the presentation text as plain text, cut at 160 characters. Translatable.
structured_data multi-line text Written by the app: the opening hours, position and address of the page’s structured data, which the Store page block inserts. Not to translate or edit.

The page’s address: system.url.

opening_hours has a key per open day, in English (monday to sunday), with its slots in the store’s local time. A closed day has no key; a day with a lunch break has several slots.

{
"monday": [{ "opens": "10:00", "closes": "13:00" }, { "opens": "14:00", "closes": "19:00" }],
"saturday": [{ "opens": "10:00", "closes": "19:00" }]
}

special_hours lists the days and periods outside the usual week (public holidays, vacations, late openings), in date order. from and to are dates in the store’s calendar, the same for a single day; label is optional. A period without slots is closed. On those days, it replaces the weekly hours. Past periods go away by themselves.

[
{ "from": "2026-12-24", "to": "2026-12-24", "label": "Christmas Eve", "slots": [{ "opens": "10:00", "closes": "16:00" }] },
{ "from": "2026-12-25", "to": "2026-12-25", "label": "Christmas", "slots": [] }
]
Field Type Content
name text The type’s name (“Flagship”). Translatable.
color color The color of its markers, empty without a color.
marker URL The address of its custom marker’s SVG, empty without a marker.

One entry per country with enough stores, created by the app when country pages are on; the texts are edited in Content > Metaobjects > Country page. The stores are not in the entry: the Country or city page block, on this template, reads them in the store locator’s data.

Field Type Content
country_code text The country’s code (ISO 3166-1, FR), written by the app.
seo_title text The page’s title: the country’s name by default. Translatable.
seo_description text The meta description. Translatable.
introduction rich text The text shown under the country’s name. Translatable.

One entry per city with enough stores, created by the app when city pages are on; the texts are edited in Content > Metaobjects > City page. The city is its name as written on the stores.

Field Type Content
country_code text The country’s code (ISO 3166-1, FR), written by the app.
city text The city, as written on its stores, written by the app.
seo_title text The page’s title: the city’s name by default. Translatable.
seo_description text The meta description. Translatable.
introduction rich text The text shown under the city’s name. Translatable.

The file the merchant imports into the app (CSV or Excel) has its columns and formats described in the import format reference, served by the app and readable by AI assistants. To bring in the stores from another tool or from a brand’s file, start from this reference.

  • Theme blocks: what the blocks already do with this data.
  • SEO: the pages’ title, meta description and structured data.