CartistoDocs

Dynamic sources

Data-driven sections — smart product lists and latest posts, resolved server-side.

Some settings don’t store content — they store a query. The server runs it and hands your section the resolved, localized, currency-correct result, so a theme can offer a data-driven section (a “bestsellers” strip, a “from the journal” block) without the merchant hand-picking items or the theme calling an API.

products_by — a smart product list

The value is a small config; the resolved value is a product array shaped exactly like the products picker (translated, prices pre-converted), so it drops into the same product-card markup.

{ "type": "products_by", "name": "featured", "maxItems": 8 }
source Returns
newest (default) Most recently created active products.
bestselling Products ranked by total quantity sold. Empty until the store has orders.
tag Products carrying tag (also set "tag": "summer").
brand Products of brand (also set "brand": "Acme").
{% for product in component.featured %}
  {% render 'product-card', product: product %}
{% endfor %}

maxItems on the setting caps the count.

blog_posts — latest posts

Resolves to the most recent published posts, each with title, url, excerpt, and coverImage — real content instead of the merchant re-typing it.

{ "type": "blog_posts", "name": "journal", "maxItems": 3 }
{% for post in component.journal %}
  <a href="{{ post.url }}">
    {% if post.coverImage %}<img src="{{ post.coverImage | image_url: width: 600 }}" alt="{{ post.title }}" />{% endif %}
    <h3>{{ post.title }}</h3>
    <p>{{ post.excerpt }}</p>
    <time>{{ post.publishedAt | format_date }}</time>
  </a>
{% endfor %}
Note

Closed set, on purpose Dynamic sources are a curated vocabulary, not an open query language — the server controls exactly what each one costs and returns. That’s what lets a theme stay pure presentation while the data stays localized, converted, and safe. Need a source that doesn’t exist yet? It’s a platform addition, not a theme workaround.