Video nativo para un producto

En este tutorial vamos a ver como implementar videos nativos en tu tienda.

Para lograrlo vamos a realizar ajustes sobre la implementación actual de videos (YouTube/Vimeo), permitiendo la reproducción de videos nativos y manteniendo la compatibilidad con Swiper y Fancybox.

HTML

1. Vamos a renombrar el archivo product-image-thumb.tpl con el nombre product-image-thumbs.tpl y vamos a realizar los siguientes ajustes:


Adicionamos a condição para verificar se o elemento é um vídeo, para que seja armazenado o ID do vídeo:

<a href="#" {% if media.isVideo %}data-video_id="{{ media.id }}"{% endif %}...>

Vamos agregar la condición {% if media.isImage %} antes del elemento img para luego mostrar el contenido según tipo de media:

{% if media.isImage %}
   ...//Aqui traer todo el código de image teniendo en cuenta el reemplazo de image por media.
{# Low quality img until final img is lazyloaded #}
<img src="{{ media | product_image_url('tiny') }}" class= "img-absolute img-absolute-centered blur-up visible-xs" 
  {% if media.alt %}alt="{{media.alt}}"{% endif %}/>
{% else %}
<div class="video-player-icon video-player-icon-small">
  <svg class="icon-inline icon-xs svg-icon-invert"><use xlink:href="#play"/></svg>
</div>

2. Dentro de product-image.tpl vamos a reemplazar product.images_count por product.media_count y dentro del elemento con la clase swiper-wrapper vamos agregar:

{% for media in product.media %}
  {% if media.isImage %}
   ...// Aqui el código igual pero teniedo en cuenta el reemplazo de image por media
{% else %}
  {% include 'snipplets/product/product-video.tpl' with {video_id:media.next_video, product_native_video: true} %}
{% endif %}

3. En product-video.tpl, vamos actualizar la condición inicial {% if product.video_url %} por:

{% if product.video_url or product_native_video %}

Luego vamos a cambiar las variables product.images_count por product.media_count.

En el div con clase product-video vamos a incluir las versiones donde por un lado muestra el video en el carrusel y por otro lado prepara una copia oculta para el modal.

<div class="js-product-slide js-product-video-slide swiper-slide slider-slide {% if product_native_video %}
product-native-video-slide{% endif %} {% if home_main_product %}w-100{% endif %}"data-image-position="{{ video_index }}">
 ...
   <div class="product-video"
    {# Visible video inside slider #}
    {% include 'snipplets/video-item.tpl' with {video_id: video_id, product_modal_trigger: true,product_video: true, 
      product_native_video: product_native_video} %}
    {# Hidden video inside modal #}
    {% include 'snipplets/video-item.tpl' with {video_id: video_id, product_modal: true, product_video: true, 
      product_native_video: product_native_video} %}
   </div>

4. En video-item.tpl, vamos a cambiar el id del modal y las condiciones para mostrarse en la página de inicio, en el primer elemento <a>:

<a id="trigger-video-modal-{{ media.id }}" href="#product-video-modal-{{ media.id }}" data-fancybox="product-gallery" class="js-play-button video-player {% if not home_main_product %}d-block  d-md-none{% endif %} {% if home_main_product %}d-none{% endif %}">

Agregamos las clases condicionales según si es video nativo:

<div class="{% if not thumb and not product_native_video %}js-video{% endif %} {% if product_video and not product_modal %}
js-video-product{% endif %} embed-responsive embed-responsive-16by9 visible-when-content-ready {% if product_native_video %}
product-native-video-container{% endif %}">

Vamos a realizar el siguiente ajuste en el elemento <a> para manejar video nativo:

<a href="javascript:void(0)" {% if product_native_video %}data-video_uid="{{ media.next_video }}"{% endif %} class="{% if product_native_video %}js-play-native-button{% else %}js-play-button{% endif %} video-player {% if product_modal_trigger and not home_main_product %}d-none d-md-block{% endif %}">

En la miniatura de video (thumbnail) vamos a tener:

{# Video thumbnail #}
  {% if product_native_video %}
  <div class="js-video-native-image w-100">
   <div data-video_uid="{{ media.uid }}"  class="js-external-video-iframe-container embed-responsive" data-video-color="{{ settings.primary_color | trim('#') }}" style="display:none;">
    {{ media.render | raw }}
   </div>
  <img data-video_uid="{{ media.uid }}" src="{{ 'images/empty-placeholder.png' | static_url }}" data-src="{{ media.thumbnail }}" class="video-image lazyload" alt="{{ 'Video de' | translate }} {% if template == 'product' %}{{ product.name }}{% else %}{{ store.name }}{% endif %}">
</div>
  {% else %}
  <div class="js-video-image">
      <img src="{{ 'images/empty-placeholder.png' | static_url }}" data-src="" class="lazyload video-image fade-in" alt="{{ 'Video de' | translate }} {% if template == 'product' %}{{ product.name }}{% else %}{{ store.name }}{% endif %}" style="display: none;">
      <div class="placeholder-fade">
      </div>
 </div>
{% endif %}

CSS

Requisito:

Tener agregados en tu diseño las clases helpers. Podés seguir este este pequeño tutorial para hacerlo (simplemente es copiar y pegar algunas clases, no toma más de 1 minuto).

Como en este ejemplo usamos un slider con Swiper, necesitamos agregar el plugin. Para ver cómo hacerlo podés leer este corto artículo y luego continuar con este tutorial.

En el sass style-critical.scss, vamos agregar los siguientes estilos para contenedores y elementos de video nativo:
.icon-inline {
 z-index: 1;
}

.video-player-icon-small {
  z-index: 10;
 }

.product-native-video-slide{
  height: auto;
}
.product-native-video-container {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  overflow: visible;
}

@media (min-width: 768px) {
...
/* //// Product detail */
.product-native-video-slide {
    height: 100%;
  }
}

JS

Dentro de store.js.tpl, vamos a realizar los cambios donde vamos a definir la lógica de inicialización y control de los videos nativos.

Para esto vamos a reemplazar referencias de product.images_count por product.media_count.

Luego vamos agregar las funciones initAllVideos() y pauseAllVideos():

{% set native_videos_enabled = false %}
    {% if template == 'product' and product.hasNativeVideos %}
        {% set native_videos_enabled = true %}
    {% endif %}
    {% if home_product_main %}
        {# on the home, if there is at least one featured product with native videos, we enable them #}
        {% for product in sections.featured.products %}
            {% if product.hasNativeVideos %}
                {% set native_videos_enabled = true %}
            {% endif %}
        {% endfor %}
    {% endif %}


{% if template == 'product' or home_product_main %} 

{% if native_videos_enabled %}
       var stream_videos = [];
            function initAllVideos(){
                jQueryNuvem(".js-external-video-iframe").each(function($el){
                    const player = Stream(document.getElementById($el.id));
                    stream_videos.push(player);
                });
            }
            initAllVideos();
            function pauseAllVideos(){
                stream_videos.forEach(function(player){
                    player.pause();
                });
            }
            jQueryNuvem(".js-play-native-button").on("click", function($el){
                pauseAllVideos();
                const link = jQueryNuvem(this);
                const id = jQueryNuvem(this).data("video_uid");
                const iframe = jQueryNuvem("#video-" + id);
                const image = jQueryNuvem("img[data-video_uid='" + id + "']");
                const parent = jQueryNuvem(this).parent(".embed-responsive-16by9");
                const container = jQueryNuvem("div[data-video_uid='" + id + "']");
                iframe.attr("src", iframe.data("src"));
                container.show();
                image.hide();
                link.hide().removeClass("d-md-block");
                parent.removeClass("embed-responsive-16by9");
            });
        {% endif %}


  var has_multiple_slides = false;
        {% if template == 'product' and (product.media_count > 1 or video_url) %}

Dentro la configuración de Swiper (Product-slider o dentro de createSwiper).

Vamos agregar la función pauseAllVideos() en el evento slideChange, para evitar que un video siga reproduciéndose al cambiar de slide.

{% if native_videos_enabled %}
     slideChange : function () {
     pauseAllVideos();
    },
{% endif %}

Luego vamos a cambiar en LS.registerOnChangeVariant, dentro del bloque {% if has_multiple_slides %}, vamos agregar la condición para detectar y abrir el video correspondiente:

var video_id = jQueryNuvem(e.currentTarget).data("video_id");
         if(video_id){
            jQueryNuvem('#trigger-video-modal-' + video_id).trigger('click');
            return;
         }

También vamos ajustar la condición dentro del bloque “on”:

// Antes:
},
{% if product.video_url and template == 'product' %}
    on: {
        init: function () {
            if (window.innerWidth < 768) {
                ...
            }
        }
    }
{% endif %}

Anteriormente, la condición que controlaba la inicialización del video ({% if product.video_url and template == 'product' %}) se encontraba por fuera del bloque on: dentro de la configuración del Swiper.

//Ahora:
},
on: {
    {% if product.video_url and template == 'product' %}
        init: function () {
            if (window.innerWidth < 768) {
                ...
            }
        },
    {% endif %}

Ahora se movió dentro del bloque on:, lo que permite definir correctamente los eventos del carrusel y agregar nuevos comportamientos, como pausar los videos nativos cuando el usuario navega entre slides.

En external.js.tpl vamos agregar el código del servicio interno que permite reproducir y controlar los videos nativos dentro del sitio.

{% set home_product_main = template == 'home' and sections.featured.products %}


{% set native_videos_enabled = false %}
{% if template == 'product' and product.hasNativeVideos %}
    {% set native_videos_enabled = true %}
{% endif %}
{% if home_product_main %}
    {# on the home, if there is at least one featured product with native videos, we enable them #}
    {% for product in sections.featured.products %}
        {% if product.hasNativeVideos %}
            {% set native_videos_enabled = true %}
        {% endif %}
    {% endfor %}
{% endif %}


{% if native_videos_enabled %}
    {% raw %}
     // Pegar aquí código del siguiente repositorio
      {% endraw %}
{% endif %}

Activación

Desde el administrador, en el formulario del producto en la sección de Fotos y videos podemos subir el video teniendo en cuenta el tamaño máximo y formato especificado.

Una vez subido y guardado el video en el admin, se puede ver el video en la tienda.