NAV Navbar
HTML/JS Liquid + HTML
  • Bienvenida
  • Liquid 101
  • Variables globales y locales
  • Estructura de plantillas
  • Etiquetas Bootic
  • Archivos e imágenes
  • Bootic.js y los módulos Javascript
  • Ejemplos y trucos
  • Bienvenida

    ¡Buenas!

    Éste es nuestro nuevo sitio para desarrolladores. Aquí encontrarás toda la documentación necesaria para construir, modificar y extender las tiendas que corren sobre nuestra plataforma.

    Y si no lo encuentras, ¡lo inventamos! (En serio, si alguna etiqueta o método te ayudaría a hacer la pega mejor o más rápido, avísanos y lo vemos).

    Sin contar esta parte, este sitio se divide las siguientes secciones o capítulos:

    1. Liquid 101 (introducción a Liquid)
    2. Variables globales y locales
    3. Estructura de plantillas
    4. Etiquetas Bootic
    5. Archivos e imágenes de apoyo (assets)
    6. Bootic.js y los módulos Javascript
    7. Ejemplos y trucos

    Como ves, el sitio funciona con tres columnas, por lo que normalmente verás ejemplos en código a la derecha de lo que estés leyendo aquí; en esta columna. A la izquierda hay un menú con todas las secciones de este sitio (que es básicamente una sola gran página) y con un búscador AJAX bien rápido para ayudarte a encontrar lo que busques.

    Historial de cambios

    26 de Enero, 2018:

    Lo logramos. La versión 1.0 de la nueva documentación sale al aire.

    29 de Agosto, 2017:

    Bootic cumple 10 años. Empezamos a redactar la nueva documentación. No se entiende ni jota.

    29 de Agosto, 2007:

    Se escribe la primera línea de código de Bootic. Tiene un error de sintaxis.

    29 de Agosto, 1997:

    Día del Juicio Final. Todo comienza.

    Primeros pasos

    Cada tienda en Bootic funciona en base a un conjunto de plantillas, también llamados "temas", al igual que lo hace Wordpress u otros gestores de contenido.

    Un tema de diseño es, en esencia, un conjunto de plantillas HTML acompañadas de imágenes y hojas de estilo (CSS), opcionalmente con archivos de apoyo (assets) como librerías Javascript, tipografías, íconos (SVG), y cómo no, canciones MIDI.

    Ofrecemos varios temas para elegir, que puedes usar a modo de ejemplo o bien como punto de partida para crear tus propios diseños.

    Cambiando temas

    Por defecto, las tiendas nuevas en Bootic utilizan nuestro tema Oxygen, que posee un diseño simple y limpio y por lo tanto funciona muy bien para diversos tipos de tiendas (aquí puedes ver Oxygen en acción). Si quieres probar otro diseño, puedes entrar a la seccion Diseño del panel de administración Bootic y elegir otro.

    Una vez cambiado, basta con que abras o refresques la portada de tu tienda y verás cómo se ve con el nuevo diseño. Algunos temas ofrecen algunas opciones básicas como por ejemplo la cantidad de elementos por fila o si deseas que se muestre el nivel de stock de los productos en catálogo.

    Modificando las plantillas

    Para modificar una plantilla puedes hacerlo usando el editor de plantillas que está disponible en el panel de administración, dentro del menú Diseño.

    Bootic code editor

    Ahora, si prefieres trabajar en forma local con Sublime Text, Vim, Atom o tu editor favorito también puedes hacerlo. Para eso deberás usar el comando bootic themes que es parte de nuestro Bootic CLI.

    Para empezar a modificar el código, es necesario que entiendas cómo funciona nuestro sistema de plantillas, empezando por la sintaxis que ellas utilizan.

    Liquid 101

    {% for product in products %}
    <div class="product">
      <h3><a href="{{ product.url }}">{{ product.model }}</a></h3>
      <span class="price">{{ product.price }}</span>
    </div>
    {% endfor %}
    

    Bootic usa Liquid como lenguaje para crear y modificar las plantillas que generan el HTML de una tienda. Al igual que otros sistemas de templating, Liquid permite combinar código HTML con etiquetas especiales para desplegar el contenido.

    Por ejemplo, para mostrar una lista de productos en la plantilla products.html, usaríamos el código que ves a la derecha.

    La sintaxis de Liquid define tres tipos de elementos: variables, filtros y etiquetas. Pero vamos por parte (dijo el forense).

    Variables y objetos

    Una variable es, esencialmente, una expresión que representa un valor, que puede ser:

    En Liquid, las variables se rodean con {{ y }} e insertan el valor en el HTML generado:

    Bienvenido a <strong>{{ shop.name }}</strong>!
    

    Resulta en:

    Bienvenido a <strong>Mi tienda</strong>!
    

    Al primer tipo de variable se le puede aplicar los filtros de texto, que a su vez tienen como subconjunto los filtros de URLs y los filtros de imágenes (ambos cadenas de texto, pero de un tipo especial).

    Pero en caso de que la variable represente un conjunto de elementos, necesitamos poder iterar sobre ellos para entonces usar los bigotes sobre los atributos que queramos usar o desplegar. Para esto usamos la etiqueta for:

    <!-- Iterando sobre un conjunto de fabricantes (vendor) -->
    {% for vendor in shop.vendors %}
      {{ vendor.url }}
    {% endfor %}
    

    A las variables que corresponden a conjunto de elementos, nos referimos como variables iterables. A ellas también se les puede aplicar filtros, pero aquellos que se aplican sobre éste tipo particular de variables: los filtros de conjunto.

    Por último, dependiendo de la plantilla que estés editando, tendrás distintas variables disponibles para usar. Algunas variables están disponibles para todas las plantillas, ya que son globales (como por ejemplo shop, que es algo que no cambia dependiendo de la página) mientras otras son locales.

    Más adelante entramos al detalle de las variables globales versus las locales.

    Filtros: ¿Para qué sirven y cómo se usan?

    {{ 'Esta es una frase muy recontra requete larga.' | truncate: 20 }}
    

    Resulta en:

    Esta es una frase mu...
    

    Un filtro modifica el valor contenido en una variable o expresión. La sintáxis de un filtro es expresión | filtro. La barra vertical quiere decir "toma el valor de la expresión y pásalo a través del filtro".

    Los filtros se pueden encadenar:

    {{ 'estilos.css' | asset_url | stylesheet_tag }}
    

    Lo de arriba genera:

    <link rel="stylesheet" src="/themes/1234/assets/estilos.css" />
    

    Dependiendo de cuán complejo sea lo que quieres hacer, puede que necesites usar filtros o puede que no. Nosotros en general los usamos para cosas bien específicas, como por ejemplo para linkear hacia los archivos CSS y JS de una tienda.

    A la derecha puedes ver esto en acción. Lo que estamos haciendo aquí es pasar la cadena 'estilos.css' al filtro asset_url, que lo que hace es buscar la ruta hacia los archivos de apoyo de tu tienda. Este filtro retorna esa ruta y la agrega como prefijo a la cadena original -- algo así como '/themes/1234/assets/estilos.css'.

    Por último, esa cadena resultante de asset_url es pasada al filtro stylesheet_tag, que inserta la cadena dentro de un <link rel="stylesheet"> de forma de generar el <link> completo.

    ¿Fácil, no?

    Para ponerte a prueba, a ver si logras decifrar cómo construirías el siguiente pedazo de HTML:

      <img src="/themes/1234/assets/imagen.jpg" alt="Una imagen" />
    

    ¿Se te ocurre cómo? Piénsalo bien, guiándote por el ejemplo que vimos recién. Cuando llegues a una solución apreta aquí para ver si tenías razón!

    Más adelante encontrarás una lista con todos los filtros disponibles para jugar.

    {% Etiquetas Liquid %}

    {% if product.available_stock > 10 %}
      Tenemos cachá de este producto.
    {% elsif product.available_stock <= 0 %}
      No tenemos ná.
    {% else %}
      Quedan pocos, así que apúrala oh!
    {% endfor %}
    

    Las etiquetas Liquid por lo general sirven para agregar lógica condicional a tu código, como ves en el súper ejemplo de la derecha. También sirven para poder trabajar con conjuntos de elementos (como el ejemplo de for vendor in shop.vendors arriba), y por último, para llamar a métodos propios de Bootic que retornan un valor producto de un cálculo o lógica específica.

    Es decir, las etiquetas Liquid (que se rodean con {% y %}, a diferencia de las variables y filtros) se usan para todo lo que no sea insertar o escupir el valor de una variable de texto o numérica.

    En la siguiente sección verás qué etiquetas Liquid tienes disponible en tu arsenal. El lenguaje Liquid proporciona la gran mayoría, pero Bootic también incorpora algunas para ayudarte a hacer cosas con menos código. Probablemente la más importante de todas estas etiquetas es {% add_to_cart %}, que la usamos para generar el HTML del botón "Agregar al carro".

    Las etiquetas, a diferencia de las variables, no aceptan el uso de filtros, y si bien todas se encierran con bigotes ({% y %}), cada una acepta opciones específicas que veremos en la próxima sección.

    Variables globales y locales

    <p>Bienvenido a {{ shop.name }}!</p>
    

    En el sistema de plantillas de Bootic, hay ciertas variables que son "globales", es decir, están disponibles para usarse en cualquier plantilla.

    Una variable global, por ejemplo, es shop, que contiene un objeto con la información asociada a la tienda -- como su nombre y URL -- y por lo tanto es muy útil tenerla a mano en cualquier plantilla, ya sea un formulario de contacto (form.html) o bien, la portada del sitio (home.html).

    Sin embargo, existen otras variables que dependen del contexto y que sólo están disponibles en algunas plantillas. A éstas nos referimos como variables locales.

    Por ejemplo, en la plantilla form.html existe una variable local llamada form que corresponde al objeto asociado al formulario desplegado, pero en esa plantilla no existe una variable product ni tampoco collection.

    La razón es simple: al mostrarse el detalle de un producto, Bootic sabe cuál producto es el que está mirando el usuario y por tanto asocia ése producto específico a la variable product. Por el contrario, al visitar un formulario de contacto, al no estar mostrándose un producto específico Bootic no sabría qué producto asociar a la variable product.

    Listado de variables globales

    Generales:

    Menús, links y galerías:

    Productos y sus agrupaciones:

    Contenido estático:

    La variable resource

    resource es una variable que verás mucho en las plantillas Bootic, y la usamos porque está presente en todas las páginas donde hay un recurso principal: en la ficha de un producto sería el producto desplegado, o en el caso de un listado de productos sería la colección (en caso de estar filtrando productos por colección, obviamente).

    Esto la hace una herramienta muy práctica para poder hacer chequeos a nivel global, o simplemente para insertar una variable en común.

    Por ejemplo, como todos los objetos que puede contener resource tienen la variable name, puedes hacer:

    <!-- en layout.html -->
    {% if resource %}
      <h1>Estás viendo nuestra {% resource.name %}</h1>
    {% end %}
    

    Lo cual en algunos casos dirá:

    <h1>Estás viendo nuestra Bicicleta Azul</h1>
    

    Pero también:

    <h1>Estás viendo nuestra Colección Montaña</h1>
    

    slug es otra de las variables que contienen todos los objetos que pueden ser un resource, por lo que puedes puedes hacer chequeos de este tipo:

    {% if resource.slug == 'una-cosa-importante' %}
      Esta es una cosa muy importante!
    {% endif %}
    

    O bien, puedes comparar directamente el objeto asignado a la variable resource con otras variables que puedan estar presentes en una vista:

    {% if resource == type %}
      Estás mirando los productos de tipo {% type.name %}.
    {% elsif resource == collection %}
      Estás mirando la colección {% collection.name %}
    {% endif %}
    

    El listado de variables comunes que poseen todos los posibles resource son:

    El objeto shop

    Disponible a través de la variable global shop.

    El objeto menu

    Disponible a través de la variable global menus, ya sea iterando o usando un handle (ej. menus.sidebar).

    Disponible al iterar sobre el atributo links de un objeto menu.

    También responde a los siguientes métodos, en base al tipo de objeto asociado al link.

    {% for item in galleries.portada.items %}
      <div>
        <img src="{{ item.image | resize:'540x' }}" />
      </div>
    {% endfor %}
    

    El objeto collection

    Disponible en la plantilla collection.html o a través de la variable global collections, ya sea iterando o bien usando una manilla (ej. collections.ofertas.products).

    El objeto product_type

    Disponible iterando sobre la variable global product_types o como el atributo de un producto.

    El objeto vendor

    Disponible al iterar sobre el conjunto global vendors, o como el atributo vendor de un producto.

    El objeto tag

    El objeto product

    Disponible en la plantilla product.html o dentro de un loop de productos.

    Conjuntos o objectos relacionados:

    Variantes:

    Precios:

    Imágenes asociadas:

    Archivos asociados:

    Tipo y atributos:

    Productos similares o relacionados:

    El objeto variant

    Disponible al iterar sobre el conjunto variants un producto.

    Variables relacionadas al stock:

    Variables relacionadas al precio:

    El objeto asset

    Contiene las siguientes variables:

    Variables específicas para imágenes:

    El objeto page

    Disponible en la plantilla page.html. o a través de la variable global pages, ya sea iterando o bien usando un handle específico (ej pages.bienvenida.body).

    El objeto form

    Disponible en la plantilla form.html o a través de la variable global forms, ya sea iterando o bien usando una manilla (ej. forms.landing.body).

    Los campos de un formulario de contacto se despliegan usando la etiqueta especial {% contact_form_fields %}, como aparece en la documentación de la plantilla form.html.

    El objeto blog

    Objeto global. Tiene las siguientes variables:

    El objeto post

    Disponible en la plantilla post.html o al iterar sobre un conjunto de posts (blog.posts). Tiene las siguientes variables:

    Estructura de plantillas

    Plantilla Rutas donde se usa (ejemplo) Variables locales
    layout.html Todas
    home.html /
    products.html /products, /types/mp3s, /collections/ofertas, /vendors/adidas, etc products, resource, y collection, type, vendor y/o tag, en caso que aplique
    product.html /products/ipod-nano product, resource
    page.html /pages/about-us page, resource
    form.html /forms/contacto form, resource
    blog.html /blog blog (global)
    post.html /blog/2014/01/13/hola-mundo post, resource
    cart.html /cart cart, related_products_to_just_added

    layout.html

    Esta es la plantilla principal de tu tienda. Cada página que visitas se despliega dentro de layout.html usando la etiqueta {{ content_for_layout }}.

    Aquí hay un layout.html super hiper simplificado:

    <html>
      <head>
        <title>{% current_title %} - {{ shop.name }}</title>
        <meta name="description" content="{% current_description %}">
      </head>
      <body>
        {{ content_for_layout }}
      </body>
    </html>
    

    Si tuviéramos una plantilla home.html con lo siguiente:

    <h1>¡Bienvenido a nuestro sitio!</h1>
    

    Y visitamos la portada, {{ content_for_layout }} es reemplazada automáticamente por el contenido de home.html. El resultado sería:

    <html>
      <head>
        <title>Calzones rotos a domicilio - Mi tienda</title>
        <meta name="description" content="Calzones rotos a domicilio">
      </head>
      <body>
        <h1>¡Bienvenido a nuestro sitio!</h1>
      </body>
    </html>
    

    Incluyendo otras plantillas

    Para evitar duplicar código, a veces es buena idea poner fragmentos de HTML que se repiten mucho en "sub-plantillas" e incluirlas donde se usen.

    Para esto existe la etiqueta Liquid include, que permite inyectar o meter el código de una plantilla dentro de otra.

    {% include 'mi_plantilla' %}
    

    Por ejemplo, uno de los temas de Bootic usa esta técnica para incluir distintas barras laterales dependiendo de la página que se está desplegando:

    {% if template == 'page' %}
      {% include 'sidebar_pages' %}
    {% elsif template == 'blog' %}
      {% include 'sidebar_blog' %}
    {% else %}
      {% include 'sidebar' %}
    {% endif %}
    

    home.html

    Esta plantilla se carga al visitar la portada de tu tienda Bootic, y su contenido se inserta donde tengas puesta la etiqueta {{ content_for_layout }} de tu plantilla principal, layout.html.

    La portada de tu sitio es el lugar ideal para mostrar productos destacados, ofertas, noticias recientes, "banners" y otros elementos que quieras poner en vitrina.

    Dado que la portada puede contener cosas distintas dependiendo del rubro y estilo de tu tienda, es recomendable que revises la plantilla home.html del diseño defecto de tu tienda Bootic.

    En la parte final de este sitio puedes ver algunos ejemplos de cosas puedes hacer en tu home.html:

    products.html

    {% paginate products by 5 %}
      {% for product in paginated_list %}
        <div ciass="product">
          <a href="{{ product.url }}" class="image">
            {% product.first_image.small | image_tag %}
          </a>
    
          <h3>
            <span class="vendor">{{ product.vendor }}</span>
            <a href="{{ product.url }}">{{ product.model }}</a>
          </h3>
    
          {% if product.price.positive %}
            <span class="price">{{ product.price }}</span>
          {% endif %}
        </div>
      {% endfor %}
    
      {{ paginated_list | pagination }}
    {% endpaginate %}
    

    Esta es la plantilla usada por Bootic para mostrar listas y colecciones de productos. Esta se usa para desplegar listas de productos, por lo que tiene una variable llamada products que contiene el conjunto de productos a mostrar.

    Colecciones, Tipos, Fabricantes y Tags

    Este conjunto de productos se obtiene en forma dinámica, ya que Bootic permite navegar por tu catálogo usando distintos criterios. Estos son:

    Además de esto, Bootic permite combinar dos de cualquiera los cuatro criterios (colección, tipo, fabricante y tag) en caso de que quieras ofrecer niveles de navegación más específicos. Por ejemplo:

    Paginando

    Normalmente querrás usar paginación para mostrar tus productos en varias páginas, ya que esa lista podría tener muchos productos (por ejemplo en el caso de /products, que muestra todos los productos visibles de tu tienda).

    En el ejemplo de la derecha iteramos sobre el conjunto de productos contenidos en la variable products y generamos un bloque div para cada producto, mostrando detalles básicos de cada uno como título, imagen pequeña, precio y fabricante.

    product.html

    Esta plantilla representa a la ficha de un sólo producto en tu tienda. Los datos e imágenes de cada producto los editas en la sección "productos" de la interfaz de administración de tu tienda.

    En la plantilla product.html tienes un objeto product con atributos que puedes usar (ver listado completo de atributos en variables/product).

    También existe la etiqueta especial add_to_cart que genera el html del botón para agregar al carro de compra.

    Mostrar el precio de un producto

    La función format muestra el precio formateado de acuerdo a moneda actual de la tienda.

    Precio: {{ product.price.format }}
    

    Precio y precio de comparación de producto

    Todo producto en lista o página de detalles tiene un atributo price con el precio del producto. Mostrarlo en plantillas es sencillo:

    Precio: {{ product.price }}
    

    Si no quieres mostrar el precio en caso de que sea cero, puedes revisar la variable positive del objeto price de un producto.

    {% if product.price.positive %}
      Precio: {{ product.price }}
    {% endif %}
    

    Esto también sirve en caso de que quieras evitar que un producto se pueda comprar, combinándolo con la etiqueta {% add_to_cart %}:

    {% if product.price.positive %}
      {% add_to_cart %}
    {% endif %}
    

    Además los productos pueden tener un campo opcional de precio de comparación. Muy útil si el producto está en oferta y quieres mostrar el precio anterior. En el panel de administración:

    precio de comparación de productos

    En las plantillas de producto (product.html para el detalle, products.html u otros para las listas) puedes mostrar el precio de comparación como prefieras, si es que está disponible:

    {% if product.has_price_comparison %}
      Precio anterior: {{ product.price_comparison.format }}
    {% endif %}
    

    También puedes mostrar el porcentaje de descuento del precio actual con respecto al an "anterior" o comparación:

    {% if product.has_price_comparison %}
      Descuento: %{{ product.price_comparison_percentage }}
    {% endif %}
    

    Variantes y botón de compra

    Agregar al carro de compras

    La etiqueta {% add_to_cart %} genera un formulario HTML prediseñado con la lista de variantes del producto, un campo para ingresar la cantidad de unidades y un botón para guardar la variante y cantidad elegida en el carro de compras.

    <div id="agregar_al_carro">
      {% add_to_cart %}
    </div>
    

    La etiqueta también revisa el estado de cada variante y deshabilita las que esten fuera de stock. Normalmente esta etiqueta es suficiente para la mayoría de los casos. Con un poco de CSS puedes cambiar el estilo de los elementos generados.

    Colecciones

    Puedes usar product.collections para listar las colecciones a las que el producto pertenece.

    {% if product.has_collections %}
      <h3>Colecciones de {{ product.model }}</h3>
      <ul>
        {% for coll in product.collections %}
        <li>
          <a href="{{ coll.url }}">{{ coll.name }}</a>
        </li>
        {% endfor %}
      </ul>
    {% endif %}
    

    También puedes acceder a una colección en particular usando su "manilla" o título normalizado:

    {% if product.collections.catalogo %}
      Este producto está en la colección {{ product.collections.catalogo.name }}!
    {% endif %}
    

    Etiquetas

    Al igual que con las colecciones, puedes usar product.tags para listar las etiquetas a las que el producto pertenece.

    {% if product.has_tags %}
      <h3>Etiquetas de {{ product.model }}</h3>
      <ul>
        {% for tag in product.tags %}
        <li>
          <a href="{{ tag.url }}">{{ tag.name }}</a>
        </li>
        {% endfor %}
      </ul>
    {% endif %}
    

    Al igual que con las colecciones, también puedes acceder a una etiqueta en particular usando su "manilla"* o nombre normalizado:

    {% if product.tags.hecho_en_chile %}
      Este producto es hecho in Chile!
    {% endif %}
    

    Mostrando imágenes de un producto

    {% if product.has_images %}
      {% for image in product.images limit:2 %}
        <div class="product-image">
          <a href="{{ image.large }}">
            {% image.medium | image_tag %}
          </a>
        </div>
      {% endfor %}
    {% endif %}
    

    La variable product.images contiene un conjunto con las imágenes asociadas a un producto, en el orden definido en el panel de administración. Son objetos de tipo asset.

    Otros archivos

    También puedes subir y asociar otro tipo de archivos a los productos (por ejemplo, una catálogo en formato PDF).

    {% if product.has_files %}
      {% for file in product.files %}
        <a href="{{ file.url }}" class="file-{{ file.extension }}">
          {{ file.file_name }}
        </a>
      {% endfor %}
    {% endif %}
    

    Para mostrarlos, puedes iterar sobre el product.files, que contiene el conjunto de archivos asociados a un producto (no imágenes). Si bien los archivos en sí no son imágenes, los objetos también son de tipo asset, por lo que contienen las mismas variables (url, extension, file_name, etc).

    page.html

    <h2>{{ page.name }}</h2>
    
    <div class="entry">
      {{ page.body }}
    </div>
    

    Esta es una de las plantillas más sencillas de Bootic y su función es mostrar el contenido de una página editable de Bootic. Esta plantilla es usada cuando ves una página en URLs del tipo /pages/sobre-la-empresa o /pages/terminos-y-condiciones

    Los atributos disponibles para la variable page los puedes ver aquí.

    form.html

    <h2>{{ form.name }}</h2>
    
    {% if form.sent %}
    
      <p>¡Recibimos tu mensaje! Gracias.</p>
    
    {% else %}
    
      <div class="entry">
        {{ form.body }}
      </div>
    
      {% contact_form_fields %}
    
    {% endif %}
    

    Esta plantilla despliega los formularios de contacto que puedes crear en tu tienda Bootic.

    blog.html

    Esta plantilla está diseñada para mostrar las noticias que publiques en tu tienda.

    Administración de blog y noticias en Bootic

    Paginando artículos y "leer más"

    {% paginate blog.posts by 10 %}
      {% for post in paginated_list %}
        <div class="post">
          <h3>
            <a href="{{ post.url }}">{{ post.title }}</a>
          </h3>
    
          <div class="entry">
            {{ post.body | split_text }}
          </div>
    
          <span class="date">
            Publicado el {{ post.published_on | date:'%d/%m/%Y' }}
          </span>
        </div>
      {% endfor %}
    
      <!-- no olvidar la paginacion! -->
      {{ paginated_list | pagination }}
    {% endpaginate %}
    

    En el ejemplo de la derecha usamos la etiqueta paginate para generar páginas de 10 artículos cada uno. Además, usamos el filtro split_text para generar un extracto de los artículos, y el filtro date para darle formato a la fecha de cada uno.

    El filtro split_text, aplicado a un artículo, muestra la primera parte del artículo si detecta un símbolo especial insertado en él. En caso de no encontrar el símbolo, se hará un corte arbitrario luego de las primeras 10 líneas de texto.

    El botón para introducir "el corte" en forma manual es el siguiente:

    Dividir artículo

    Y así es cómo se ve el resultado final:

    Leer más

    post.html

    <div class="post">
      <h2>{{ post.title }}</h2>
    
      <div class="entry">
        {{ post.body }}
      </div>
    
      <p class="date" title="{{ post.published_on | date:'%b %d %H:%M:%S %Y' }}">
        Publicado el <strong>{{ post.published_on | date:'%d/%m/%Y' }}</strong> por {{ post.user_name }}
      </p>
    </div>
    

    La plantilla post.html muestra el detalle de cada noticia y tiene su propia URL. por ejemplo /blog/2024/03/18/mi-primera-noticia. En esta plantilla puedes mostrar el artículo completo.

    cart.html

    Ejemplo de una plantilla cart.html:

    {% if cart.units > 0 %}
    
      {% dynamic_cart_table %}
    
    {% else %}
    
      <h2>Carro de compras</h2>
      <p>Tu carro está vacío. ¡Sigue participando!</p>
    
    {% endif %}
    

    La plantilla cart.html contiene el detalle de los productos que el usuario ha ingresado al carro de compra por efecto de cliquear el botón "Agregar al carro".

    Si la cantidad de unidades (cart.units) es mayor a cero mostrará una tabla con 5 columnas - Figura 1:

    1. Foto y nombre del producto
    2. Precio unitario
    3. Texto de ingreso con la cantidad de productos
    4. Subtotal del precio unitario por la cantidad de productos
    5. Enlace para borrar la fila

    Carro de compra

    Además mostrará 3 botones:

    1. Seguir comprando (volverá al portada de la tienda)
    2. Comprar (irá a la página de checkout)

    Si la cantidad de productos es 0 (el carro está sin productos) mostrará lo siguiente:

    Etiquetas Bootic

    Para propósitos de esta documentación, no entraremos en el detalle de las etiquetas Liquid que son parte del lenguaje:

    Si quieres leer más sobre ellas, te recomendamos visitar la documentación oficial de Liquid.

    Etiquetas Bootic generales:

    Etiquetas Bootic para carro y productos:

    Abajo, la descripción y ejemplos de cada una.

    {{ content_for_layout }}

    Inserta el contenido generado por la plantilla correspondiente a la página desplegada (home.html en la portada, cart.html en /cart, etc).

    <!-- layout.html -->
    <html>
    <head>
      <title>{% current_title %}</title>
    </head>
    
    <body>
    {{ content_for_layout }}
    </body>
    </html>
    

    {% current_title %}

    Genera un título para ser usado en la etiqueta <title>, dependiendo de la página desplegada.

    <head>
      <meta charset="utf-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>{% current_title %} - {{ shop.name }}</title>
    

    {% current_description %}

    Genera una descripción corta para usar en el meta description del encabezado. El contenido generado dependerá de la página desplegada.

    <head>
      <meta charset="utf-8" />
      <meta name="description" content="{% current_description %}" />
      (...)
    

    {% navigation_path %}

    Genera la ruta de navegación (también llamados "breadcrumbs") para la página desplegada. Muy práctico, y comúnmente usado en layout.html.

    <div class="breadcrumbs">
      {% navigation_path %}
    </div>
    

    {% bootic_header [version] %}

    Incluye los archivos CSS compartidos por todas las tiendas Bootic (como el carro, los formularios, y el botón agregar al carro), y dependiendo de la página, metainformación asociada: el link RSS en las páginas del blog, y en las fichas de productos datos estructurados (LD+JSON) junto con las etiquetas para el OpenGraph de Facebook.

      {% bootic_header 'v2' %}
    

    Incluye los archivos JS compartidos por todas las tiendas Bootic, y que son requeridos para gran parte de la funcionalidad asociada a la elección de variantes y el carro.

      {% bootic_footer 'v2' %}
    

    {% loop [objects] in 'template' %}

    Permite iterar sobre un conjunto de objetos o variables dentro de una (sub) plantilla. Veamos un caso de uso práctico.

    En la mayoría de los casos, el HTML utilizado para mostrar un producto dentro de un listado (en products.html, o los destacados en home.html o los similares en product.html) es el mismo.

    Para esto es muy conveniente utilizar una misma plantilla e incluirla en cada listado utilizando la etiqueta loop.

    Plantilla reutilizable product_item.html

    Por ejemplo, podríamos crear una plantilla HTML llamada product_item.html con el siguiente código:

    <!-- product_item.html -->
    <div class="product item-{{ product_item_counter }}">
      <a href="{{ product_item.url }}" class="product-image">
        <img src="{{ product_item.first_image.small }}" alt="{{ product_item.title }}" />
      </a>
    
      <h3 class="product-model">
        <a href="{{ product_item.url }}">
          {{ product_item.vendor }}
          {{ product_item.title }}
        </a>
      </h3>
    
      {% unit_price_for 'product_item' %}
    </div>
    

    Ejemplo de uso

    Usamos la etiqueta especial loop para llamar nuestra plantilla product_item.html con cada producto en la lista:

    <!-- products.html -->
    {% paginate products by 20 %}
      {% loop paginated_list in 'product_item' %}
    
      {{ paginated_list | pagination }}
    {% endpaginate %}
    

    De esta manera podemos reutilizar el mismo HTML para productos desde distintas plantillas. Estas plantillas reutilizables a veces son llamadas «parciales», porque muestran sólo una parte de la información de una página.

    Asimismo, ahora podemos incluir esta misma plantilla en el listado de productos similares en product.html:

    <!-- product.html -->
    {% if product.has_similar_products %}
      <div id="similar-products">
        <h2>Productos similares</h2>
        {% loop product.similar_products in 'product_item' limit:3 %}
      </div>
    {% endif %}
    

    {% paginate [list] by [num_per_page] %}

    {% paginate %} sirve para dividir listas de productos (o cualquier cosa iterable) en varias páginas. Dentro de cada bloque {% paginate %} existe la variable paginated_list con el grupo de objetos para la página actual.

    {% paginate products by 5 %}
      {% for product in paginated_list %}
        <p>
          <a href="{{ product.url }}">{{ product.model }}</a>
          <span class="price">{{ product.price }}</span>
        </p>
      {% endfor %}
      {{ paginated_list | pagination }}
    {% endpaginate %}
    

    El ejemplo anterior crea grupos de 5 productos por página.

    También dentro del bloque paginate, el filtro pagination crea HTML para la navegación entre páginas.

    Paginacion de productos en plantillas Bootic

    {% unit_price %} y {% unit_price_for [product] %}

    Muestra el precio de un producto (en caso de que sea mayor a cero), junto con el precio de comparación, en caso de tener uno. También se puede usar en su variación unit_price_for [nombre_variable], en caso de que sea necesario pasar el nombre de la variable asociada al objeto producto.

    <!-- product.html -->
    <h3>{{ product.model }}</h3>
    
    {% unit_price %}
    

    {% stock_status %} y {% stock_status_for [product] %}

    Muestra el nivel de stock de un producto. Opcionalmente se le puede pasar el nombre de la variable asociada al producto, pero para eso hay que usar la etiqueta stock_status_for.

    <!-- product.html -->
    <h3>{{ product.model }}</h3>
    
    <div class="nivel-de-stock">
      {% stock_status %}
    </div>
    

    {% add_to_cart (for [product_variable]) %}

    Genera el HTML del botón 'Agregar al carro' junto a la lista de variantes, en caso de haber más de una.

    <!-- product.html -->
    <h3>{{ product.model }}</h3>
    {% add_to_cart %}
    

    La etiqueta también acepta el nombre de la variable del producto que quieres usar. Esto es necesario cuando el nombre de la variable no sea product, por ejemplo dentro de una plantilla como product_item.html:

    <!-- product_item.html -->
    <h3>{{ product_item.model }}</h3>
    {% add_to_cart for 'product_item' %}
    

    {% add_to_cart_no_variants (for [product_variable]) %}

    Una versión del 'Agregar al carro' que no contiene listas de variantes. Útil en caso de que quieras poner el botón en listas de productos.

    <!-- products.html -->
    {% for product in products %}
      <h3>{{ product.model }}</h3>
      {% add_to_cart_no_variants %}
    {% endfor %}
    

    Al igual que add_to_cart, esta etiqueta también opcionalmente recibe el nombre de la variable asociada al producto.

    {% cart_table_template %}

    Incluye la plantilla Javascript usada en por el carro dinámico. No es necesario que la uses, a menos de que quieras usar el módulo JS CartModal.

    {% dynamic_cart_table %}

    Inyecta el carro dinámico, basándose en la plantilla Javascript entregada por cart_table_template. Requiere del objeto cart, por lo que sólo puede usarse en la plantilla cart.html.

    {% shipping_calculator %}

    Permite mostrar un ventana modal con el costo de envío a la zona geográfica que el comprado seleccione.

    Obviamente, solo mostrará un resultado si la zona geográfica seleccionada tiene costos de envío creada en tu tienda. En caso de que no hayan opciones de envío para la zona elegida, verá un mensaje diciendo "No hay opciones de envío para esa zona."

    Para usar esta funcionalidad ingresamos la etiqueta en la plantilla product.html:

    <!-- product.html -->
    (...)
    
    <h3>{{ product.model }}</h3>
    <div>{% unit_price %}</div>
    
    <div class="costos-de-envio">
      {% shipping_calculator %}
    </div>
    (...)
    

    Archivos e imágenes

    ¿Plantillas o archivos?

    En el editor Bootic, puedes agregar archivos CSS o JS subiendo los archivos desde tu computador, o bien puedes hacerlo creando una nueva plantilla y pegando el contenido original. ¿Cuál es la diferencia?

    La primera y diferencia es que los archivos no se pueden modificar con el editor de código, ya que están pensados como archivos externos y no editables para usarlos en tu plantillas (imágenes, tipografías, etc).

    La segunda diferencia es que las plantillas tienen un límite máximo de tamaño de 64kb, mientras que los archivos pueden pesar hasta 1MB. Esto por la misma razón de antes. Así que si quieres incluir una librería JS que pese más de 64K simplemente no podrás subirla como una plantilla.

    Cómo agregar una nueva plantilla JavaScript o CSS

    <html>
      <head>
        <title>{{ shop.name }}</title>
        {{ 'master.css' | asset_url | stylesheet_tag }}
      </head>
      <body>
        {{ content_for_layout }}
      </body>
    </html>
    

    El HTML generado sería:

    <html>
      <head>
        <title>Mi tienda</title>
        <link href="/themes/2345/master.css" rel="stylesheet" type="text/css">
      </head>
      <body>
        <h1>Hola, estas en la portada de mi sitio!</h1>
      </body>
    </html>
    

    En este caso mostraremos como ejemplo la creación de una plantilla CSS llamada master.css.

    Crear nueva plantilla

    Para insertar una hoja de estilos primero tenemos que crear una plantilla de tipo "css" y darle un nombre.

    Crear nueva plantilla

    Luego la vinculamos desde layout.html usando los filtros asset_url y stylesheet_tag. El primero nos da la ruta absoluta a la hoja de estilos en los servidores Bootic. La segunda crea una etiqueta HTML <style>.

    En el caso que quieras agregar código Javascript de tu tienda, una vez creada la plantilla, tendrías que reemplazar master.css por el nombre de la plantilla JS, y stylesheet_tag por javascript_tag:

    (...)
      <head>
        <title>{{ shop.name }}</title>
        {{ 'theme.js' | asset_url | javascript_tag }}
      </head>
    (...)
    

    ¡Y boom! Listaylor.

    Librerías JavaScript y CSS externas

    Puede que quieras usar librerías externas en tu plantilla. Un ejemplo común es incluír y usar jQuery como complemento a tu propio código Javascript.

    Incluyendo una librería como archivo

    Incluyendo jQuery como archivo

    Si quieres usar una librería externa como jQuery, Velocity.js, Move.js, Vue.js u otras donde no vas a meter mano puede ser recomendable subirla como archivo en la sección "subir archivo" del editor.

    A continuación lo incluyes en layout.html de la misma manera.

    Incluyendo jQuery como archivo

    Incluyendo una librería desde una URL externa.

    Muchas librerías estan alojadas en servidores públicos especializados. Google, por ejemplo, provee versiones actualizadas de las librerías más comunes en esta página: http://code.google.com/apis/libraries/devguide.html#jquery

    En el caso particular de jQuery y cualquier librería alojada en los servidores de Google, recomendamos usar este método. Simplemente copia la dirección del archivo elegido en layout.html.

    Incluyendo jQuery como archivo

    Nótese que estamos usando el filtro javascript_tag del sistema de plantillas de Bootic. Lo anterior es equivalente a escribir el siguiente HTML:

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"
    type="text/javascript"></script>
    

    Trabajando con imágenes

    Subiendo imágenes en el editor

    Subir imágenes

    Abajo a la derecha en el editor de plantillas puedes subir archivos de tipo .gif, .png y .jpg. Bootic te muestra los archivos subidos con su nombre completo.

    Estas imágenes puedes ser usadas tanto en tus plantillas CSS como HTML.

    Insertando imágenes en plantillas HTML

    Abre la plantilla que quieras (por ejemplo layout.html) y agrega una etiqueta de image &lt;img&gt;. En el atributo src debes insertar el nombre del archivo que subiste, tal cual aparece en la lista de archivos subidos, usando el filtro asset_url, así:

    <img src="{{ 'logo.png' | asset_url }}" alt="Logo de mi tienda" />
    

    El filtro asset_url genera la URL al directorio donde Bootic guarda tus archivos. Una vez que guardas la plantilla, Bootic genera dinámicamentte la ruta completa, que se ve más o menos así:

    <img src="http://static.bootic.net/uploads/themes/32/logo.png" alt="Logo de mi tienda" />
    

    Insertando imágenes en plantillas CSS

    En CSS basta con usar el nombre de la imágen directamente. Bootic guarda las plantillas CSS y las imágenes subidas en el mismo directorio, por lo que no es necesario usar el filtro asset_url.

    Este ejemplo situa la imagen "fondo.gif" como imagen de fondo del elemento body (por ejemplo en la plantilla master.css)

    body {
      font-size: 12px;
      background: url(fondo.gif);
    }
    

    Favicon

    El "favicon" es el ícono del sitio que aparece en la barra de título del navegador, y es simplemente una imagen que puedes insertar en la plantilla layout.html. Los favicons normalmente están optimizados y tienen la extensión ".ico", y los puedes generar a partir de una imagen en otro formato (PNG, GIF, JPG) usando un editor de imágenes como Photoshop o incluso herramientas gratuitas online (puedes encontrar muchas en Google: http://www.google.com/search?q=favicon+generator)

    Sube una imágen de 16x16px a la lista de archivos de tu editor de plantillas Bootic e inserta el siguiente código HTML en la sección HEAD de la plantilla layout.html.

    <link rel="shortcut icon" href="{{ 'favicon.ico' | asset_url }}" type="image/x-icon" />
    

    "favicon.ico" es la convención para estos archivos pero en verdad puedes nombrarlo como quieras.

    Enumerando imágenes de productos

    Si quieres listar sólo un subconjunto de las imágenes de un producto, puedes usar el filtro limit:

    {% for image in product.images limit:2 %}
      <div class="product-image">
        {% image.large | image_tag %}
      </div>
    {% endfor %}
    

    En este caso sólo se mostrarán las primeras dos imágenes del producto.

    El fragmento a continuación muestra el resto de las imágenes de un producto (si es que tiene) en un tamaño menor ("thumbnail", de 75x75px).

    {% if product.images.size > 2 %}
      {% for image in product.images offset:2 %}
      <div class="product-image">
        <a href="{{ image.large }}">
          {% image.thumbnail | image_tag %}
        </a>
      </div>
      {% endfor %}
    {% endif %}
    

    Cada imagen de producto tiene los siguientes tamaños predefinidos:

    Además de los tamaños predefinidos, puedes asignar dimensiones personalizadas a imágenes de productos usando el filtro resize, descrito a continuación.

    Control avanzado de imágenes

    Además de los tamaños predefinidos, puedes asignar dimensiones personalizadas a imágenes de productos usando el filtro resize.

    <img src="{{ image | resize: '100x100#c' }}" alt="{{ product.model }}" />
    

    El ejemplo anterior crea un cuadrado de 100x100px, centrado, a partir de la imagen de un producto.

    La lista de geometrías de imagen reconocidas por resize es:

    Imágenes de productos en tono de grises (blanco y negro)

    Puedes usar el filtro greyscale para transformar la imagen a blanco y negro.

    <img src="{{ image | resize: '100x100#c' | greyscale }}" alt="{{ product.model }}" />
    

    El orden no importa:

    <img src="{{ image | greyscale | resize: '100x100#c' }}" alt="{{ product.model }}" />
    

    Si usas greyscale sin el filtro resize, la imagen retornada tiene dimensiones por defecto de '240x180'.

    <img src="{{ image | greyscale }}" alt="{{ product.model }}" />
    

    Bootic.js y los módulos Javascript

    Descripción

    Se dividen en dos grupos:

    Módulos Base

    Módulos Adicionales (dependen de los de arriba)

    ¿Qué son y para qué sirven?

    // product.liquid
    
    {% for image in product.images %}
    <div class="slide" data-related-variant-id="{{ image.related_variant_id }}">
      <a href="{{ image.large }}" title="{{ product.model }}">
        <img src="{{ image.thumbnail }}" alt="{{ product.model }}" />
      </a>
    </div>
    {% endfor %}
    
    <script>
     Bootic.load('VariantImages', {
       imageSelector: '.slide'
     })
    </script>
    

    En general sirven para modificar el comportamiento de la interfaz de usuario. Por ejemplo, el módulo VariantImages se usa en las fichas de producto para cambiar la imagen desplegada en base a la variante elegida por el usuario. El ejemplo que ves a la derecha muestra cómo se usa.

    En este caso, la plantilla genera una lista de divs que contienen las imágenes de un producto. Al cargar VariantImages, le indicamos cuál es el selector que corresponde a las imágenes. Internamente, el módulo "escucha" cuando un usuario cambia la variante seleccionada, y cuando esto ocurre, busca dentro de los elementos con el selector indicado y gatilla un evento click sobre él (para usarlo con librerías de slideshows o galerías de imágenes).

    Este módulo viene incluido por defecto en la plantilla Oxygen y puedes ver este comportamiento en alguno de los productos de la tienda de demostración.

    Pero eso lo puedo hacer por mi cuenta, ¿no?

    Sí, claro que lo puedes hacer a mano por tu cuenta. Los módulos JS los hacemos simplemente para ahorrarte tiempo en cosas chicas para que puedas enfocarte en otras cosas más importantes.

    La gracia, también, es que los módulos los vamos actualizando en el tiempo, entonces en caso de que hayan cambios importantes (por ejemplo en la demarcación del botón "Agregar al carro") no será necesario que actualices tu código para que el truco que hiciste siga funcionando.

    (Tampoco es que estemos cambiando el HTML del "Agregar al carro" todos los días, pero igual. :)

    Cómo usar los módulos

    Paso 1: Cargar dependencias

    <!-- layout.html -->
    
    <!doctype html>
    <html lang="es">
    
    <head>
      <meta charset="utf-8" />
      <meta name="description" content="{% current_description %}" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>{% current_title %} - {{ shop.name }}</title>
    
      {% bootic_header 'v2' %}
      {{ 'styles.css' | asset_url | stylesheet_tag }}
    </head>
    
    <body>
      <header>
        <ul class="menu">
          {% for link in menus.main.links %}
          <li><a href="{{ link.url }}">{{ link.title }}</a></li>
          {% endfor %}
        </ul>
      </header>
    
    {{ content_for_layout }}
    
    <footer>
      {{ pages.footer.body }}
    </footer>
    
    {{ 'theme.js' | asset_url | async_javascript_tag }}
    {% bootic_footer 'v2' %}
    
    </body>
    </html>
    

    Lo primero que necesitas es cargar el código Javascript que incluye los módulos para poder usarlos. Este código viene incluido en el archivo shops.js que es cargado, a su vez, por la etiqueta {% bootic_footer 'v2' %}.

    Esta etiqueta se usa normalmente al final de la plantilla layout.html, y la parte clave es el v2, que le indica a Bootic que deseas cargar la segunda versión del pie de página. Si omites esa parte, Bootic no incluirá la etiqueta <script> hacia shops.js.

    Como complemento a esto, la etiqueta {% bootic_header 'v2' %} agrega en el encabezado un trozo de código que simplifica la carga de módulos y además te permite hacerlo aún cuando shops.js no esté 100% cargado.

    El ejemplo de la derecha muestra una versión simplificada de layout.html con ambas etiquetas en forma correcta.

    Paso 2: Bootic.require() y Bootic.load()

    Una vez que tienes la versión 2 (v2) de bootic_header y bootic_footer en layout.html, ya puedes ponerte a jugar. La manera normal de usar un módulo es, normalmente, requerirlo usando Bootic.require y luego llamar alguno de sus métodos con los parámetros que corresponda.

    Por lo general, los módulos adicionales sólo exponen dos métodos, load() y unload(), y por lo mismo ofrecemos una manera de llamarlos usando Bootic.load() y Bootic.unload() para ahorrarte líneas de código.

    <!-- alguna plantilla, por ejemplo layout.html -->
    
    <script>
      // para usar un módulo base, lo cargamos con Bootic.require()
      Bootic.require('Cart', function(cart) {
        alert('Hay ' + cart.units + ' productos en tu carro!')
      })
    
      // y lo mismo aplica para los módulos adicionales
      Bootic.require('CartModal', function(cartModal) {
        cartModal.load({ cartLinkSelector: '.show-cart' })
      })
    
      // sin embargo, Bootic.load() nos permite saltarnos el paso de require()
      Bootic.load('CartModal', { cartLinkSelector: '.show-cart' })
    </script>
    

    Los módulos base, en cambio, están pensados como herramientas para ser usados de distintas formas, por lo que no responden a los métodos load() y unload(), a diferencia de los módulos adicionales. Más abajo puedes ver los métodos que cada módulo expone para que uses.

    Paso 3: Listo!

    Eso es todo, así es como se usan los módulos Javascript Bootic. A continuación detallamos los distintos módulos y lo que hace cada uno.

    Cart

    <script>
      // requerimos el módulo Cart usando Bootic.require()
      Bootic.require('Cart', function(cart) {
        // Cart es un objeto observable, permitiendo definir
        // funciones que se invocan cuando ocurran ciertos eventos
        cart.on('updated', function() {
          // en este caso, vamos a mantener actualizado un contador con las unidades
          // en el carro cada vez que se produzca alguna actualización.
          $('#cart-count').text(cart.units);
        })
      })
    </script>
    

    Cart es uno de los módulos base y permite realizar modificaciones en el carro del usuario, o simplemente reaccionar a ciertos eventos cuando estos ocurran.

    Métodos

    .isLoading() # => Boolean

    Retorna un booleano indicando si el carro está en proceso de carga o no.

    .isEmpty() # => Boolean

    Retorna un booleano indicando si el carro está vacío o no.

    .add(variantId[, quantity, callback]) # => Cart

    Agrega quantity unidades de la variante con ID variantId al carro (por defecto una unidad). Opcionalmente se puede pasar una función como último argumento, que es llamada luego de que el carro se sincroniza con el backend.

    .find(variantId[, callback]) # => Object/Null

    Busca y retorna el objeto asociado a la variante con el ID variantId que haya dentro del carro. En caso de no haber, retorna null. Opcionalmente se puede pasar una función que es llamada con el mismo resultado retornado.

    .findByProductId(productId[, callback]) # => Object

    Busca y retorna el objeto asociado a la variante perteneciente al producto con ID productId que haya dentro del carro. En caso de no haber, retorna null. Opcionalmente se puede pasar una función que es llamada con el mismo resultado retornado.

    .forEach(callback[, context]) # => Cart

    Itera sobre los productos en el carro, invocando la función callback (requerida), opcionalmente dentro del contexto context, que por defecto corresponde a la instancia propia de Cart.

    .remove(variantId[, callback]) # => Cart

    Remueve la variante con ID variantId del carro. Opcionalmente se puede pasar una función como último argumento, que es llamada luego de que el carro se sincroniza con el backend.

    Eventos

    El objeto Cart es un Observable, así que puedes también escuchar a ciertos eventos y reaccionar a ellos.

    Evento 'updated'

    <script>
    Bootic.require('Cart', function(cart) {
      cart.on('updated', function() {
        console.log('En este momento hay ' + cart.units + ' productos en el carro.');
      })
    
      cart.on('loading', function() {
        document.getElementById('spinner').style.display = 'inline-block';
      })
    
      cart.on('loaded', function() {
        document.getElementById('spinner').style.display = 'none';
      })
    
      cart.on('adding', function(obj) {
        alert('Agregando ' + obj.quantity + ' unidades de la variante ' + obj.variantId)
      })
    
      cart.on('added', function(item) {
        console.log('Item agregado!', item);
      })
    
      cart.on('removing', function(item) {
        console.log('Removiendo item del carro...', item);
      })
    
      cart.on('removed', function(item) {
        console.log('Item removido!', item);
      })
    })
    </script>
    

    Llamado cada vez que se actualiza el carro, ya sea al inicializarse o cuando sus contenidos se actualizan por medio de los métodos .add() o remove().

    Evento 'loading'

    Llamado antes de hacer el llamado al backend para actualizar los datos del carro.

    Evento 'loaded'

    Llamado luego de hacer el llamado al backend para actualizar los datos del carro.

    Evento 'adding'

    Llamado antes de hacer el llamado al backend para agregar un producto al carro. Recibe un objeto con los parámetros variantId y quantity.

    Evento 'added'

    Llamado luego de hacer el llamado al backend para agregar un producto al carro. Recibe un objeto item con los datos del item recién agregado.

    Evento 'removing'

    Llamado antes de hacer el llamado al backend para remover un producto al carro. Recibe un objeto item con los datos del item siendo removido.

    Evento 'removed'

    Llamado luego de hacer el llamado al backend para remover un producto al carro. Recibe un objeto item con los datos del item removido.

    <script>
    Bootic.require('Modal', function(modal) {
      var body  = '<h1>Hola mundo!</h1>';
          body += '<p>Este es un hermoso modal.</p>';
    
      modal.html(body);
    })
    </script>
    

    Módulo que permite mostrar modales en forma rápida y sin ningún tipo de dependencias adicionales.

    Métodos

    <script type="text/html" id="my-modal-template">
      <h1><% title %></h1>
      <p><% message %></p>
      <button class="close-button">Cerrar</button>
    </script>
    
    <script>
    // en este ejemplo requerimos también el módulo Templates, para construir
    // el cuerpo del modal a partir de la plantilla definida aquí arriba.
    Bootic.require('Modal', 'Templates', function(modal, templates) {
      // construimos el HTML usando el módulo Templates
      var templateHTML = document.getElementById('my-modal-template').innerHTML,
          body = templates.renderRaw(templateHTML, { title: 'Hola!', message: 'Un mensaje' });
    
      // mostramos el modal, y guardamos la instancia retornada en la variable `box`
      var box = modal.html(body);
    
      // y agregamos un listener para cerrar el modal si el usuario apreta el botón
      $(box).on('click', '.close-button', function() {
        modal.hide(box);
      })
    })
    </script>
    

    .html(body, opts) # => modal

    Construye y despliega (vía .show()) un nuevo modal a partir del HTML recibido en el primer argumento (body). opts es un objeto que puede contener opciones para la construcción del nodo HTML, como por ejemplo className.

    .iframe(src, opts) # => modal

    Construye un y despliega un modal cuyo contenido estará definido por la ruta recibida en src. El objeto opts puede contener una propiedad height así como las propiedades usadas en la construcción del HTML descritas en el método anterior, .html().

    .show(modal, opts) # => modal

    Despliega un modal ya construido por .html() o .iframe(). Útil para cuando desees reutilizar un mismo modal, sin tener que reconstruirlo cada vez.

    .hide(modal) # => modal

    Esconde un modal ya desplegado. El argumento puede ser tanto un modal como un string con el selector HTML (ID o clase) que corresponda al modal en cuestión.

    Eventos

    Evento: 'hidden'

    Llamado cuando un modal es escondido, ya sea vía .hide() o simplemente porque el usuario hizo click sobre la cruz para cerrarlo.

    Notice

    <script>
    Bootic.require('Notice', function(notice) {
      // esperamos tres segundos y mostramos el aviso
      var message = '<p>Envío <u>gratis a todo Chile</u> por compras sobre <strong>$50.000</strong></p>!';
      setTimeout(function() {
        notice.fromContent('envio-gratis', message);
      }, 3000);
    })
    </script>
    

    Permite mostrar avisos en una franja que se despliega en la parte superior de la ventana del navegador. Utilizado por el módulo PromoNotice para notificar cuando hay una promoción activa en el carro.

    Métodos

    .fromContent(noticeName, content)

    <script type="text/html" id="my-notice-template">
      <% #isEndOfMonth? %>
        <p>Está terminando el mes! <% discountPercentage %> de descuento en todas las compras sobre <% discountMinPurchase %>.</p>
      <% _else %>
        <p>Bienvenido! Si necesitas ayuda en tu compra llámanos al <% phoneNumber %>.</p>
      <% /isEndOfMonth? %>
    </script>
    
    <script>
    Bootic.require('Notice', function(notice) {
      notice.fromTemplate('aviso-del-dia', 'my-notice-template', {
        isEndOfMonth: new Date().getDay() > 25,
        discountMinPurchase: '$35.000',
        discountPercentage: '10%',
        phoneNumber: '+56 (9) 2345 6789'
      })
    })
    </script>
    

    Genera y muestra un aviso con el contenido content. noticeName debería ser un nombre único que identifique el tipo de aviso, ya que se usa para identificar cuando un aviso debiese "tapar" a otro existente y cuando no.

    .fromTemplate(noticeName, templateId, data)

    Genera y muestra un aviso generado a partir de la plantilla HTML con el selector templateId y los datos que vengan dentro del objeto data. noticeName debería ser un nombre único que identifique el tipo de aviso, ya que se usa para identificar cuando un aviso debiese "tapar" a otro existente y cuando no.

    .remove(noticeName)

    Esconde el aviso con el nombre noticeName, en caso de haber uno.

    Templates

    Módulo para construir fragmentos de HTML en base a plantillas (templates) y objetos Javascript. Usamos la librería qiq escrita por uno de los nuestros, que está basada en Mustache pero cuenta con algunos trucos adicionales.

    Para escribir tus propias plantillas te sugerimos que las incluyas dentro de una etiqueta <script>. Un dato importante es que qiq por defecto usa las etiquetas de tipo bigote ({{ }}), sin embargo nosotros usamos la opción de qiq que permite cambiarlas por otras (<% %>). Esto lo hacemos para evitar confusiones con las etiquetas que usa nuestro lenguaje de plantillas, Liquid, que son también los bigotes {{ }} y bigotes con porcentajes {% %}.

    Métodos

    compile(templateName, body)

    Compila una plantilla con cuerpo body llamada templateName. Este último debiese ser un nombre único, ya que este módulo lo usa internamente para construir un caché y evitar compilar una misma plantilla dos veces.

    isCompiled(templateName) # => Boolean

    Retorna un booleano indicando si existe o no una plantilla compilada en el caché con el nombre templateName.

    renderCached(templateName, data) # => String (HTML)

    Renderea una plantilla ya compilada con los datos contenidos en el objeto data. Retorna el HTML generado.

    renderRaw(body, data) # => String (HTML)

    Compila y renderea la plantilla contenida en body con los datos contenidos en el objeto data. Retorna el HTML generado.

    CartModal

    // layout.html
    <header>
      <a href="/cart" class="cart-link">Ver carro</a>
    </header>
    
    {% content_for_layout %}
    
    <!-- la siguiente etiqueta incluye la plantilla HTML del carro
         por defecto de Bootic, usando el ID 'cart-table-template' -->
    {% cart_table_template %}
    
    <script>
      Bootic.load('CartModal', { cartLinkSelector: '.cart-link' });
    </script>
    

    Una buena recomendación es no cargar CartModal en caso de que ya haya una instancia del carro dinámico, que ocurre cuando el usuario está en la ruta /cart. Para eso puedes usar Bootic.loaded(), de esta forma:

    <script>
      if (!Bootic.loaded('DynamicCartTable')) {
        Bootic.load('CartModal', { cartLinkSelector: '.cart-link' });
      }
    </script>
    

    Si quieres usar una plantilla propia para generar el carro, sería algo así:

    // layout.html
    <header>
      <a href="/cart" class="cart-link">Ver carro</a>
    </header>
    
    {% content_for_layout %}
    
    <script type="text/html" id="my-super-cart-template">
      <% #products? %>
        <ul>
        <% #products %>
          <li>
            <a href="/products/<% slug %>"><% model %></a>
            <% custom_variant_title? %>
              <em><% variant_title %></em>
            <% /custom_variant_title? %>
          </li>
        <% /products %>
        </ul>
      <% /products? %>
    </script>
    
    <script type="text/javascript">
      Bootic.load('CartModal', {
        templateId: 'my-super-cart-template',
        cartLinkSelector: '.cart-link'
      });
    </script>
    

    Adicionalmente, puedes también mostrar productos relacionados en el modal para que estos se muestren cuando se agreguen productos al carro (ver módulo DynamicCartButtons, abajo). Para eso debes pasar la opción productsTemplateId:

    <script type="text/html" id="related-products-template">
      <% products? %>
      <div class="product-list">
        <h2>También te puede interesar</h2>
        <ul>
        <% #products %>
          <li>
            <% image? %>
              <a href="/products/<% slug %>">
                <img src="<% image %>" alt="<% model %>" />
              </a>
            <% /image? %>
            <h3><a href="/products/<% slug %>"><% model %></a></h3>
            <strong>$<% price %></strong>
          </li>
        <% /products %>
        </ul>
      </div>
      <% /products? %>
    </script>
    
    <script type="text/javascript">
      if (!Bootic.loaded('DynamicCartTable')) {
        Bootic.load('CartModal', {
          // show cart modal when clicking '.cart-link'
          cartLinkSelector: '.cart-link',
          // and use this template for rendering related products
          productsTemplateId: 'related-products-template'
        });
      }
    </script>
    

    Permite mostrar un modal y desplegar el carro de compras en él, en forma automática cuando el usuario haga click en un elemento de la página, o bien cada vez que se gatille el evento 'updated' del carro.

    Opciones:

    Parámetro Descripción Requerido Valor por defecto Ejemplo
    cartLinkSelector El selector del elemento que abrirá el modal al ser clickeado Ninguno .cart-link
    templateId El ID de la plantilla HTML a usar para generar el carro No cart-table-template
    productsTemplateId El ID de la plantilla HTML a usar para mostrar productos relacionados No Ninguno related-products-template

    DynamicCartButtons

    <script>
      // siempre y cuando no esté cargado DynamicCartTable (que ocurre en /cart)
      if (!Bootic.loaded('DynamicCartTable')) {
        // cargamos el módulo DynamicCartButtons
        Bootic.load('DynamicCartButtons');
        // y su complemento, el módulo CartModal
        Bootic.load('CartModal', { cartLinkSelector: '.cart-link' });
      }
    </script>
    

    "AJAXifica" los botones "Agregar al carro" de tu tienda, para que los ítemes se agreguen al carro sin la necesidad de recargar toda la página. Generalmente se usa en combinación con el módulo CartModal, para que éste muestre un modal con el carro luego de realizado el cambio.

    Opciones:

    Parámetro Descripción Requerido Valor por defecto Ejemplo
    formSelector Selector del formulario que contiene el botón Agregar al carro No .add_to_cart

    DynamicCartTable

    La versión "dinámica" de nuestro carro de compras, y la que se usa hoy por defecto en la plantilla cart.html. Normalmente no deberías tener que usar este módulo directamente, a menos de que quieras hacer algo avanzado.

    Opciones:

    Parámetro Descripción Requerido Valor por defecto Ejemplo
    containerId ID del contenedor No dynamic-cart-table
    templateId ID de la plantilla HTML del carro No dynamic-cart-table-template
    templateName Nombre de la plantilla (para efectos del módulo Templates) No dynamic-cart-table
    productsTemplateId ID de la plantilla para el listado de productos relacionados No Ninguno related-products-template

    DynamicPrices

    Para aquellos productos que tengan variantes con distintos precios, este módulo actualiza el precio desplegado en la ficha de un producto en base al la variante que esté seleccionada.

    Opciones:

    Parámetro Descripción Requerido Valor por defecto Ejemplo
    variantsContainer Contenedor del listado de variantes No .cart_variants
    variantSelector Selector para las variantes, dentro del contenedor No input
    priceSelector Selector que muestra el precio No .bootic-price
    priceComparisonSelector Selector para el precio de comparación No .bootic-price-comparison
    priceComparisonBoxSelector Selector para la caja que contiene precio de comparación No .bootic-price-comparison-box

    DynamicVariants

    Para productos con distintas opciones de variantes (e.g. Color, Tamaño y/o Material), este módulo despliega la matriz de variantes en forma dinámica, permitiendo que el usuario elija entre las alternativas disponibles por opción, en vez de mostrar un listado unidimensional (y largo).

    Opciones:

    Parámetro Descripción Requerido Valor por defecto Ejemplo
    variantsContainer Contenedor del listado de variantes No '.cart_variants
    variantList Objeto Javascript que contiene la matriz de variantes a desplegar Si
    variantOptions Objeto Javascript que contiene la matriz de opciones de variante del producto Si

    FacebookPixel

    Carga el código del Pixel de Facebook y gatilla los eventos correspondientes, dependiendo de la sección del sitio donde esté el usuario.

    Opciones:

    Parámetro Descripción Requerido Valor por defecto Ejemplo
    pixelId Identificador de la cuenta o pixel de Facebook Ninguno 1740478256215512

    GoogleAnalytics

    Carga el código Google Analytics, con las opciones opciones necesarias para el linkeo de eventos entre la tienda y la sección de pagos (checkout).

    Opciones:

    Parámetro Descripción Requerido Valor por defecto Ejemplo
    analyticsId Identificador del perfil de Analytics a cargar Ninguno UA-41958709-1
    cookieDomain Dominio a asociar a la cookie de Analytics Ninguno auto o www.mitienda.com
    legacyCookieDomain Dominio a asociar a la cookie de Analytics Ninguno www.mitienda.com

    ProductFilters

    // product.html
    
    <!-- al cambiar un filtro re-carga toda esta vista, pero dentro de "#search-results"
         por eso sólo desplegamos el tag <section> y el encabezado en forma condicional -->
    {% if view != 'search' %}
      <section class="product-list">
        <h2>Productos</h2>
    
        {% product_filters 'types', 'collections' in "#search-results" %}
        <div id="search-results">
    {% endif %}
    
        {% if products.size == 0 %}
          <p>No hay productos disponibles bajo este criterio.</p>
        {% else %}
          {% paginate products by 20 %}
            <ul>
              {% loop paginated_list in 'product_item' %}
            </ul>
            {{ paginated_list | pagination }}
          {% endpaginate %}
        {% endif %}
    
    <!-- lo mismo que arriba: sólo cerramos los tags si es que los abrimos. :) -->
    {% if view != 'search' %}
      </div>
    </section>
    {% endif %}
    

    Usado internamente por la etiqueta liquid {% product_filters %}. A la derecha puedes ver un ejemplo de cómo se cargan los filtros de productos.

    PromoNotice

    Despliega un aviso en caso de que haya una promoción activa en el carro. Se carga por defecto dentro de bootic_footer 'v2', por lo que no es necesario que lo incluyas.

    VariantImages

    Se usa en las fichas de producto para cambiar la imagen desplegada en base a la variante elegida por el usuario. Depende de que el producto tenga más de una variante disponible, y que las imágenes hayan sido asociadas previamente a ellas.

    Opciones:

    Parámetro Descripción Requerido Valor por defecto Ejemplo
    variantsContainer Contenedor del listado de variantes No .cart_variants
    variantSelector Selector para las variantes, dentro del contenedor No input
    imageSelector Selector para las imágenes No .product-image

    Ejemplos y trucos

    Para desplegar los links de un menú en específico dentro de tu plantilla, debes usar la manilla desde la variable menus e iterar sus links, en la forma menus.MANILLA.links. Ejemplo:

      <ul class="navegacion">
      {% for link in menus.navegacion-footer.links %}
        <li class="{{ link.slug }}{{ ' current' | print_if_equal: resource, link }}">
          <a href="{{ link.url }}">{{ link.title }}</a>
        </li>
      {% endfor %}
      </ul>
    

    El atributo slug en cada link es el valor de su propia manilla. En este caso lo usamos para asignar classes CSS a cada item del menu.

    Además usamos el helper print_if_equal para agregar la clase "current" si un link es igual a la página actual (resource).

    De esta forma puedes crear y mostrar distintos menús de navegación en tus páginas.

    Bootic no soporta la creación de submenús en la interfaz de administración, pero con una combinación de colecciones y etiquetas es fácil construir menús dentro de otros menús.

    Por ejemplo, supongamos que tenemos una colección "catálogo" con 2 productos. Producto 1 tiene las etiquetas ("tags") "etiqueta1" y "etiqueta2". Producto 2 tiene las etiquetas "etiqueta 1" y "etiqueta 3".

    Colección "catálogo"
      - Producto 1
        - tag "Etiqueta 1"
        - tag "Etiqueta 2"
      - Producto 2
        - tag "Etiqueta 1"
        - tag "Etiqueta 3"
    

    Crea un link en un menú apuntando a la colección "catálogo".

    Administración de menus y links de navegación en Bootic

    A continuación construimos el HTML para los links del menú "navegacion-principal" de la misma forma que en el ejemplo anterior, pero dentro de cada link revisamos si hay etiquetas asociadas.

    <ul class="navegacion">
    {% for link in menus.navegacion-principal.links %}
      <li class="{{ link.slug }}{{ ' current' | print_if_equal: resource, link }}">
        <a href="{{ link.url }}">{{ link.title }}</a>
        <!-- este link tiene etiquetas ? -->
        {% if link.has_tags %}
          <ul class="submenu">
          {% for tag in link.tags %}
            <li>
              <a href="{{ link | tagged_collection_path: tag }}">{{ tag.name }}</a>
            </li>
          {% endfor %}
        </ul>
        {% endif %}
        <!-- /etiquetas -->
      </li>
    {% endfor %}
    </ul>
    

    Si el link corresponde a una colección y esta tiene etiquetas asociadas, construimos un elemento UL, recorremos las etiquetas asociadas a la colección y generamos una lista con links usando el filtro tagged_collection_path, pasando el link y cada etiqueta como parámetros. El resultado es un submenú dentro del item "Catálogo", apuntando a las siguientes direcciones:

    - /collections/catalogo/tags/etiqueta-1
    - /collections/catalogo/tags/etiqueta-2
    - /collections/catalogo/tags/etiqueta-3
    

    Como se puede adivinar, estas direcciones sólo muestran productos dentro de la colección "catálogo" que además tengan la etiqueta indicada.

    Con un poco de JavaScript y CSS usar esta técnica para construir submenús desplegables, acordiones y otros.

    Ejemplo de submenú

    Una segunda opción para generar submenús es usar tipos de productos dentro de colecciones en lugar de etiquetas. El código del submenú es similar al ejemplo anterior:

    ...
    <!-- este link tiene tipos ? -->
    {% if link.has_product_types %}
      <ul class="submenu">
      {% for tipo in link.product_types %}
        <li>
          <a href="{{ link | typed_collection_path: tipo }}">{{ tipo.name }}</a>
        </li>
      {% endfor %}
      </ul>
    {% endif %}
    <!-- /tipos -->
    ...
    

    Galería o slideshow de productos

    Los "banners" o imágenes rotativas de productos pueden ser resueltos utilizando las galerías.

    galeria

    En este ejemplo, vamos a construir un slideshow o 'slider' con las imágenes contenidas en una galería Bootic. Para esto usaremos el plugin Owl Carrousel que a su vez depende de jQuery.

    El primer paso es crear una galería llamada "Portada" desde el panel de administración y agregar al menos dos imágenes.

    El código

    Este es el HTML que requiere Owl Carrousel para generar el carrusel. Vamos a alimentarlo de las imágenes que hayan en la galería portada. Inclúyelo en la portada de tu tienda (home.html):

    <div class="owl-carousel owl-theme">
    {% for item in galleries.portada %}
      <div>
        <a href="{{ item.url }}">
          <img src="{{ item.image | resize:'540x' }}" />
        </a>
      </div>
    {% endfor %}
    </div>
    

    A continuación es necesario incluír las librerías JavaScript jQuery y el plugin Cycle. En layout.html, en la sección head:

    (...)
    <!-- Hojas de estilo necesarias para el carrusel de portada (galeria) -->
    <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.0.0-beta.3/assets/owl.carousel.min.css">
    <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.0.0-beta.3/assets/owl.theme.default.css">
    

    Luego agregamos el código JS necesario también en layout.html, pero abajo, justo antes del cierre de la etiqueta </body>.

    <!-- librerías necesarias para el carrusel de portada (galeria) -->
    <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.0.0/jquery.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/jquery-migrate/1.4.0/jquery-migrate.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.0.0-beta.3/owl.carousel.min.js"></script>
    
    <!-- llamada -->
    <script type="text/javascript">
      $(function() {
        $('.owl-carousel').owlCarousel({
          items      : 1,
          margin     : 10,
          autoHeight : true
        });
      })
    </script>
    

    ¡Listo! Visita la portada de tu sitio o recarga la página, y deberías poder ver la galería funcionando.

    Botones de redes sociales en ficha de un producto

    Redes sociales como Twitter y Facebook ofrecen botones en formato HTML que puedes pegar en tu propio sitio. Esta página muestra el procedimiento básico para usar los botones de Twitter y Facebook en las plantillas HTML de tu sitio. Necesitarás conocimientos básicos de HTML y también algo de CSS si quieres ajustar el diseño y posición de los botones.

    En Bootic, puedes pegar estos botones en la plantilla HTML de cada producto. Esta plantilla, llamada product.html, la encuentras en el editor en línea de la interfaz de administración de tu tienda.

    Template de producto

    Botón Twitter

    El código del botón de Twitter lo encuentras en esta dirección: http://twitter.com/about/resources/tweetbutton.

    Ahí puedes personalizar el diseño y texto y generar el código HTML.

    Twitter button

    A continuación debes copiar el código y pegarlo en el lugar apropiado de tu plantilla product.html en el editor Bootic. En este ejemplo, usando la plantilla "base" de Bootic, lo situaré a la derecha del botón para agregar al carro de compra.

    Twitter code in editor

    Salvamos los cambios en el editor y vamos a cualquier página de producto en nuestro sitio.

    Twitter example

    Botón "like" de Facebook

    El botón "Like" de Facebook requiere algo de configuración. Facebook también tiene una página donde puedes cambiar aspectos del botón y generar el código HTML.

    http://developers.facebook.com/docs/reference/plugins/like/

    El único campo necesario es la "URL" que quieres que tus usuarios compartan con sus amigos. En este ejemplo queremos que los usuarios compartan la dirección de cada producto. Para esto tenemos que usar una etiqueta especial de Bootic en la plantilla product.html. Por ahora pondré el texto "URL-PRODUCTO" en Facebook y lo reemplazaré con la etiqueta {{ product.url }} en el editor de Bootic.

    Facebook like button

    Presiona "get the code" y copia el código de tu botón Facebook de la opción "iframe".

    Facebook get the code

    Ahora pegamos el código en la plantilla "product.html", igual que en el ejemplo anterior junto al botón del carro de compra.

    Una vez en el editor reemplazo el texto "URL-PRODUCTO" que puse antes por la etiqueta especial de Bootic que genera la URL de cada producto, {{ product.url }}.

    Facebook editor

    Finalmente guardamos los cambios y nos aseguramos de que las páginas de producto muestran el botón adecuadamente.

    Facebook Like button

    Listo! Ahora, cada vez que alguien apriete el botón "Like" en tus páginas de productos, tus seguidores y sus amigos verán la primera imagen y título del producto en sus "walls".

    Facebook imagen de producto

    Puedes aprender más sobre todas las posibilidades de configuración del botón de Facebook en su documentación.

    Lista de productos destacados

    <ul id="productos_destacados">
      {% for product in collections.destacados.products %}
      <li>
        <!-- 1ra imagen -->
        <a href="{{ product.url }}" class="product-image">
          <img src="{{ product.first_image.small }}" alt="{{ product.model }}" />
        </a>
        <!-- título -->
        <h3 class="product-model">
          <a href="{{ product.url }}">{{ product.model }}</a>
        </h3>
      </li>
      {% endfor %}
    </ul>
    

    Crear colección destacados

    Una forma común de mostrar destacados en la portada es la siguiente:

    Ahora puedes escribir el código (en home.html) que recorra los productos dentro de la colección "detacados" y muestre sus títulos (con link) y primera imagen.

    Mostrando productos similares

    En Bootic, los productos similares (también llamados sustitutos) son aquellos que comparten el mismo Tipo de producto, y la mayor cantidad de tags en común.

    Para mostrar un bloque de productos similares en la ficha de un producto usamos similar_products y has_similar_products:

    <!-- product.html -->
    {% if product.has_similar_products %}
      <h2>Productos similares</h2>
    
      <ul class="products">
        {% loop product.similar_products in 'product_item' limit:3 %}
      </ul>
    {% endif %}
    

    Para el ejemplo anterior limitamos la lista a los primeros tres elementos del conjunto similar_products (aquellos que tengan la mayor similitud con el producto desplegado). Además usamos el bloque de codigo reutilizable product_item.

    Ejemplo

    A continuación te mostramos una página detalle de un producto, con sus similares y relacionados.

    Detalle de producto Bootic, con relacionados y similares

    Mostrando productos relacionados

    En Bootic, los productos relacionados (también llamados complementado) son aquellos que comparten la mayor cantidad de etiquetas con respecto a otro producto, y que no pertenece al mismo Tipo de producto.

    Para mostrar un bloque de productos similares en la ficha de un producto usamos related_products y has_related_products:

    {% if product.has_related_products %}
      <h2>Productos relacionados</h2>
    
      <ul class="products">
        {% loop product.related_products in 'product_item' limit:3 %}
      </ul>
    {% endif %}
    

    Para este ejemplo limitamos la lista a los primeros tres elementos del conjunto related_products (aquellos que tengan la mayor similitud con el producto desplegado). Además usamos el bloque de codigo reutilizable product_item.

    Ejemplo

    A continuación te mostramos una página detalle de un producto, con sus similares y relacionados.

    Detalle de producto Bootic, con relacionados y similares

    Sugiere productos relacionados en el carro de compra

    El siguiente trozo de código sugerirá productos relacionados justo después que el comprador agrega un producto al carro (Figura 2). Un excelente momento para incentivar otra compra.

    <!-- cart.html -->
    {% if related_products_to_just_added %}
      <h2>También te puede interesar</h2>
    
      <ul class="products">
        {% loop related_products_to_just_added in 'product_item' limit:3 %}
      </ul>
    {% endif %}
    

    Usando y mostrando atributos de un producto

    Los atributos son una buena forma de agregarle información personalizada a un producto.

    Por defecto, las plantillas Bootic muestran todos atributos del producto, siempre y cuando estos tengan un valor. Un ejemplo de cómo mostrar todos los atributos (que no estén vacíos) de un producto, sería:

    <ul class="product-attributes">
      {% for field in product.attributes.present %}
      <li class="attribute-{{field.key}}">
        <strong>{{ field.name }}:</strong> <span>{{ field.value }}</span>
      </li>
      {% endfor %}
    </ul>
    

    En caso de que quieras hacer algo especial según la presencia de cierto atributo, puedes hacer algo como esto:

    {% for field in product.attributes %}
      {% if field.key == "color" %}
        <div class="color" style="background-color: {{ field.value }}">&nbsp;</div>
      {% endif %}
    {% endfor %}
    

    Si quieres mostrar un atributo en particular (como por ejemplo el código embebido de un video) el trozo de código liquid sería así:

    {% if product.attributes.video.has_value %}
      <div class="video">
        {{ product.attributes.video.value }}
      </div>
    {% endif %}
    

    El método has_value en cada atributo revisa que el atributo exista y su valor no esté vacío.

    Calendario de noticias

    <ul id="blog-archive">
      {% for date in blog.calendar %}
      <li>
      {% capture localized_month %}datetime.month_names.month_{{date.month_num}}{% endcapture %}
        <a href="{{ date.url }}" title="{{ localized_month | t }}">
          {{ localized_month | t }} {{ date.year}} ({{ date.post_count }})
        </a>
      </li>
      {% endfor %}
    </ul>
    

    Con el objeto blog.calendar y una combinación de trucos Liquid podemos generar una lista de meses, cada uno con la cuenta de artículos para cada més. Por último generamos un link a cada mes para ver el archivo de artículos.

    El método capture es parte de Liquid y permite "capturar" el valor de un bloque de código y asignarlo a una variable, en este caso localized_months. (ver documentación Liquid)