Temas Liquid
Guía completa para crear temas Liquid en Karrito. Motor de plantillas, filtros, tags, bloques, live-edit y el editor visual.
Qué es un tema Liquid
Los temas Liquid son plantillas HTML con variables dinamicas que se renderizan en el servidor. Son la base del marketplace de temas de Karrito. Si conoces Shopify, ya conoces la sintaxis.
Karrito tiene dos motores de temas:
- Veloz (React) — El tema por defecto. Editor visual completo con 40 secciones (6 en el plan gratis).
- Liquid — Motor de plantillas para temas personalizables. Editor basado en schemas.
Estructura de un tema
themes/mi-tema/
config/
settings_schema.json <- Settings editables (colores, fonts, layout)
settings_data.json <- Valores por defecto
layout/
theme.liquid <- Layout principal (HTML, head, body)
locales/
es.default.json <- Traducciones
sections/
header.liquid <- Secciones con {% schema %}
hero.liquid
product-grid.liquid
footer.liquid
snippets/ <- Fragmentos reutilizables del tema
mi-componente.liquid
templates/
index.json <- Homepage (que secciones, en que orden)
product.json <- Pagina de producto
collection.json <- Pagina de coleccion
search.json <- Busqueda
404.json <- Pagina no encontrada
policy.json <- PoliticasObjetos disponibles
shop / store
Datos de la tienda.
| Campo | Tipo | Descripción |
|---|---|---|
shop.name |
string | Nombre de la tienda |
shop.url |
string | URL del subdominio |
shop.description |
string | Descripción |
shop.logo |
string | URL del logo |
shop.currency |
string | Código de moneda (USD, MXN, etc.) |
shop.money_format |
string | Formato de precio (${{amount}}) |
store.whatsapp_number |
string | Número de WhatsApp |
product
Disponible en la página de producto. Interfaz dual (nativa + Shopify compat).
| Campo | Tipo | Descripción |
|---|---|---|
product.title / product.name |
string | Nombre |
product.handle / product.slug |
string | URL slug |
product.url |
string | /products/slug |
product.description |
string | Descripción |
product.price |
number | Precio en centavos |
product.price_display |
string | Precio como decimal ("25.00") |
product.compare_at_price |
number/null | Precio anterior |
product.featured_image |
object/null | { src, alt } |
product.images |
array | [{ src, alt, position }] |
product.available |
boolean | Disponible |
product.badge |
string/null | Badge (Nuevo, Oferta, etc.) |
product.avg_rating |
number | Promedio de reseñas (0-5) |
product.review_count |
number | Total de reseñas |
product.variants |
array | Variantes del producto |
product.options |
array | Nombres de opciones (["Color", "Talla"]) |
product.options_with_values |
array | [{ name, values }] |
product.selected_or_first_available_variant |
object/null | Primera variante activa |
product.has_only_default_variant |
boolean | Si no tiene variantes |
product.type |
string | Tipo (categoría principal) |
product.vendor |
string | Vendedor (nombre de tienda) |
product.tags |
array | Tags del producto |
collection / category
Disponible en páginas de colección.
| Campo | Tipo | Descripción |
|---|---|---|
collection.title / collection.name |
string | Nombre |
collection.handle / collection.slug |
string | URL slug |
collection.url |
string | /collections/slug |
collection.image |
object/null | { src, alt } |
collection.products |
array | Productos de la colección |
collection.products_count |
number | Total |
Globals
| Variable | Descripción |
|---|---|
products |
Todos los productos activos |
categories / collections |
Todas las categorías |
settings |
Settings del tema (colores, fonts, etc.) |
page_title |
Título de la página |
page_description |
Meta description |
canonical_url |
URL canonica |
current_page |
Página actual (para paginación) |
powered_by_link |
HTML del footer de branding |
Filtros custom
Precios
{{ product.price | money }} <!-- $25.00 -->
{{ product.price | money_without_trailing_zeros }} <!-- $25 -->
{{ product.price | money_with_currency }} <!-- $25.00 USD -->URLs
{{ "base.css" | asset_url }} <!-- /liquid/assets/base.css -->
{{ product.featured_image.src | image_url: width: 500 }}
{{ "Hola Mundo" | url_encode }} <!-- Hola%20Mundo -->Strings
{{ 'products.add_to_cart' | t }} <!-- Agregar al carrito -->
{{ 'cart.item_count' | t: count: 5 }} <!-- 5 productos en tu carrito -->
{{ "Mi Producto!" | handle }} <!-- mi-producto -->
{{ 5 | pluralize: "producto", "productos" }} <!-- productos -->Colores
{{ "#10B981" | color_lighten: 20 }} <!-- Aclara 20% -->
{{ "#10B981" | color_darken: 10 }} <!-- Oscurece 10% -->
{{ "#ff0000" | color_mix: "#0000ff", 50 }} <!-- Mezcla 50% -->
{{ "#fff" | color_contrast: "#000" }} <!-- 21 (ratio WCAG) -->HTML
{{ "img.jpg" | image_tag }} <!-- <img src="img.jpg" loading="lazy"> -->
{{ "Ver mas" | link_to: "/products" }} <!-- <a href="/products">Ver mas</a> -->Fonts
{{ "montserrat_n4" | font_face }} <!-- @font-face CSS -->
{{ "poppins_n4" | font_url }} <!-- URL de Google Fonts -->Tags custom
{% style %} / {% endstyle %}
Renderiza un bloque <style> con variables Liquid.
{% style %}
.hero { background: {{ section.settings.color_bg }}; }
{% endstyle %}{% javascript %} / {% endjavascript %}
Renderiza un bloque <script>.
{% form %} / {% endform %}
Genera un <form> wrapper.
{% schema %} / {% endschema %}
Define los settings editables de una sección. Se muestra en el ThemeStudio.
{% schema %}
{
"name": "Hero",
"settings": [
{ "type": "text", "id": "heading", "label": "Titulo", "default": "" },
{ "type": "textarea", "id": "subheading", "label": "Subtitulo" },
{ "type": "range", "id": "columns", "label": "Columnas", "min": 2, "max": 4, "default": 3 },
{ "type": "color", "id": "bg_color", "label": "Fondo", "default": "#ffffff" },
{ "type": "checkbox", "id": "show_badge", "label": "Mostrar badge", "default": true },
{ "type": "select", "id": "font", "label": "Fuente", "options": [
{ "value": "outfit", "label": "Outfit" },
{ "value": "inter", "label": "Inter" }
]}
]
}
{% endschema %}{% paginate %} / {% endpaginate %}
Página una colección.
{% paginate products by 12 %}
{% for product in products %}
<!-- renderizar producto -->
{% endfor %}
{% if paginate.pages > 1 %}
<nav>
{% if paginate.previous %}
<a href="{{ paginate.previous.url }}">Anterior</a>
{% endif %}
{% for part in paginate.parts %}
{% if part.is_link %}
<a href="{{ part.url }}">{{ part.title }}</a>
{% else %}
<span>{{ part.title }}</span>
{% endif %}
{% endfor %}
{% if paginate.next %}
<a href="{{ paginate.next.url }}">Siguiente</a>
{% endif %}
</nav>
{% endif %}
{% endpaginate %}Settings schema
Los settings del tema se definen en config/settings_schema.json:
[
{
"name": "Colores",
"settings": [
{ "type": "color", "id": "color_primary", "label": "Color principal", "default": "#10B981" },
{ "type": "color", "id": "color_bg", "label": "Fondo", "default": "#ffffff" }
]
},
{
"name": "Tipografia",
"settings": [
{ "type": "select", "id": "font_heading", "label": "Fuente titulos", "options": [
{ "value": "outfit", "label": "Outfit" },
{ "value": "inter", "label": "Inter" }
]}
]
}
]Los settings se acceden en templates como {{ settings.color_primary }} y se convierten automáticamente en CSS variables (--color-primary).
Shared snippets
Los snippets compartidos viven en themes/_shared/snippets/ y están disponibles para todos los temas:
| Snippet | Descripción |
|---|---|
karrito-product-card |
Card de producto con imagen, precio, badge |
karrito-price |
Precio con descuento |
karrito-star-rating |
Estrellas de rating |
karrito-variant-selector |
Selector de variantes (color, talla) |
karrito-color-swatches |
Swatches de colores |
karrito-product-gallery |
Galería de imágenes con thumbnails |
karrito-trust-badges |
Badges de confianza |
karrito-share |
Botones de compartir |
karrito-breadcrumb |
Migas de pan |
karrito-reviews |
Display de reseñas |
karrito-whatsapp-fab |
Boton flotante de WhatsApp |
Uso:
{% render 'karrito-star-rating', rating: product.avg_rating, count: product.review_count %}
{% render 'karrito-breadcrumb', current_page: product.title %}CSS variables
Los settings de color y tipografía se inyectan como CSS variables en :root:
--color-bg: #ffffff;
--color-text: #0f172a;
--color-primary: #10B981;
--color-secondary: #64748b;
--color-surface: #f8fafc;
--color-border: #e2e8f0;
--font-heading: 'Outfit', sans-serif;
--font-body: 'Outfit', sans-serif;
--border-radius: 12px;Siempre usa CSS variables con fallbacks: color: var(--color-text, #0f172a).
karrito-cart.js
El script karrito-cart.js se inyecta automáticamente en todo tema Liquid. Provee:
- Cart drawer con 3 vistas (carrito, checkout, confirmación WhatsApp)
- Free shipping bar
- Shipping selector
- Search overlay (Cmd+K)
KarritoCart.add(productId, quantity, variantId)— API publica
No necesitas implementar el carrito — ya esta incluido.
Bloques (blocks)
Los bloques son contenido repetible dentro de una sección. Ejemplo: testimonios, features, slides.
Definir bloques en el schema:
{% schema %}
{
"name": "Testimonios",
"settings": [],
"blocks": [
{
"type": "testimonial",
"name": "Testimonio",
"settings": [
{ "type": "text", "id": "author", "label": "Autor" },
{ "type": "textarea", "id": "text", "label": "Texto" }
]
}
],
"max_blocks": 6
}
{% endschema %}Usar bloques en el template:
{% for block in section.blocks %}
<div>
<p>"{{ block.settings.text }}"</p>
<strong>— {{ block.settings.author }}</strong>
</div>
{% endfor %}Los bloques se definen en el template JSON:
{
"type": "testimonials",
"settings": {},
"blocks": {
"block_1": { "type": "testimonial", "settings": { "author": "Maria", "text": "Excelente!" } },
"block_2": { "type": "testimonial", "settings": { "author": "Carlos", "text": "Muy bueno" } }
},
"block_order": ["block_1", "block_2"]
}Live-edit (ThemeStudio)
Cuando un usuario edita settings desde el ThemeStudio, los cambios se reflejan en tiempo real sin recargar la página.
Para que tus secciones sean compatibles con live-edit:
- Usa CSS variables para colores, fonts y bordes. Los cambios de diseño se aplican instantaneamente via CSS.
- Mantiene el wrapper
karrito-section. Cada sección se envuelve automáticamente en<div id="karrito-section-{id}" class="karrito-section" data-section-type="{type}">. - No dependas de
<script>dentro de secciones. Cuando se hace hot-swap, los scripts inline NO se re-ejecutan. Usa event delegation okarrito-cart.js.
Flujo de cambios:
- Color/font/radius → CSS variable update instantaneo (~0ms)
- Texto/imagen → Re-render parcial de la sección via API (~200ms)
- Reorder → Animación FLIP local (~0ms)
- Agregar/quitar sección → Render + inyección animada (~300ms)
Templates JSON
Los templates definen que secciones aparecen en cada página:
{
"sections": {
"header": { "type": "header", "settings": {} },
"hero": { "type": "hero", "settings": { "heading": "", "subheading": "" } },
"grid": { "type": "product-grid", "settings": { "columns": 3 } },
"footer": { "type": "footer", "settings": {} }
},
"order": ["header", "hero", "grid", "footer"]
}El store owner puede personalizar los settings y el orden de secciones desde el ThemeStudio.