Temas Liquid
Guia completa para crear temas Liquid en Karrito. Motor de plantillas, filtros, tags, bloques, live-edit y el editor visual.
Que 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 28+ secciones.
- 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 | Descripcion |
|---|---|---|
shop.name |
string | Nombre de la tienda |
shop.url |
string | URL del subdominio |
shop.description |
string | Descripcion |
shop.logo |
string | URL del logo |
shop.currency |
string | Codigo de moneda (USD, MXN, etc.) |
shop.money_format |
string | Formato de precio (${{amount}}) |
store.whatsapp_number |
string | Numero de WhatsApp |
product
Disponible en la pagina de producto. Interfaz dual (nativa + Shopify compat).
| Campo | Tipo | Descripcion |
|---|---|---|
product.title / product.name |
string | Nombre |
product.handle / product.slug |
string | URL slug |
product.url |
string | /products/slug |
product.description |
string | Descripcion |
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 resenas (0-5) |
product.review_count |
number | Total de resenas |
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 (categoria principal) |
product.vendor |
string | Vendedor (nombre de tienda) |
product.tags |
array | Tags del producto |
collection / category
Disponible en paginas de coleccion.
| Campo | Tipo | Descripcion |
|---|---|---|
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 coleccion |
collection.products_count |
number | Total |
Globals
| Variable | Descripcion |
|---|---|
products |
Todos los productos activos |
categories / collections |
Todas las categorias |
settings |
Settings del tema (colores, fonts, etc.) |
page_title |
Titulo de la pagina |
page_description |
Meta description |
canonical_url |
URL canonica |
current_page |
Pagina actual (para paginacion) |
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 seccion. 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 %}
Pagina una coleccion.
{% 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 automaticamente en CSS variables (--color-primary).
Shared snippets
Los snippets compartidos viven en themes/_shared/snippets/ y estan disponibles para todos los temas:
| Snippet | Descripcion |
|---|---|
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 |
Galeria de imagenes con thumbnails |
karrito-trust-badges |
Badges de confianza |
karrito-share |
Botones de compartir |
karrito-breadcrumb |
Migas de pan |
karrito-reviews |
Display de resenas |
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 tipografia 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 automaticamente en todo tema Liquid. Provee:
- Cart drawer con 3 vistas (carrito, checkout, confirmacion 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 seccion. 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 pagina.
Para que tus secciones sean compatibles con live-edit:
- Usa CSS variables para colores, fonts y bordes. Los cambios de diseno se aplican instantaneamente via CSS.
- Mantiene el wrapper
karrito-section. Cada seccion se envuelve automaticamente 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 seccion via API (~200ms)
- Reorder → Animacion FLIP local (~0ms)
- Agregar/quitar seccion → Render + inyeccion animada (~300ms)
Templates JSON
Los templates definen que secciones aparecen en cada pagina:
{
"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.