frontend

Drupal json API | Consumiendo API Json en Drupal 10

Video de Youtube
URL de Video remoto
Texto

     Ahora que ya conocemos los principios básicos acerca del proceso de conexión y consumo de datos desde una API externa en Drupal, vamos a poner en práctica lo aprendido, Creando un módulo personalizado con Drush.

   Conexión con API externa en Drupal 10.

      Paso 1 - Generar un módulo personalizado

          El primer paso para lograr la conexión entre Drupal y un API externa, será generar un módulo personalizado, donde iremos añadiendo toda la estructura necesaria. Para ello, abriremos nuestra consola y ejecutaremos el siguiente comando de Drush:

drush gen module

     A continuación, contestaremos a las preguntas básicas que nos irán apareciendo en la consola, hasta finalizar el proceso.

Drush Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

   Paso 2-  Crear página de confirmación

     Para este ejercicio, además de conectarnos con la API JSON, vamos a mostrar al usuario los datos descargados, con esto, podremos hacerno una idea, de cómo ampliar otras funcionalidades, como la creación de todos los registros dentro de la base de datos de Drupal. Con este propósito, a continuación, y utilizando el mismo módulo personalizado que acabamos de generar, crearemos un contrlador con su respectiva página, para ello ejeuctaremos otra opción de Drush gen:

drush gen controller

     En esta ocasión, seleccionaremos todas las opciones por defecto, así podremos activar nuestro módulo y comprobar que todo funciona correctamente, antes de incluir los cambios finales.

Custom Module Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     Ahora es el turno de generar la página donde mostremos la inforamción, una vez realizada la conexión. Esta vez, ejecutaremos el siguiente comando de Drush:

drush gen template

     Seleccionaremos todas las opciones por defecto y sólo añadiremos un nombre de plantilla. (confirmation-data)

Custom Module Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

   Paso 3 - Primeras comprobaciones

     Ya hemos creado nuestro módulo personalizado, así que antes de comenzar a añadir el resto de configuraciones, comprobaremos que todo funciona correctamente. Para ello, activaremos el módulo desde la interfaz de Drupal o mediante consola y a continuación visitaremos la página, cuya url encontraemos dentro del archivo routing.yml.

Custom Module Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

Custom Module Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

Custom Module Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony
Texto

   Conectándonos a la API

     Para este ejemplo, vamos a utilizar la API cat-facts, está muy bien documentada y te servirá para hacer pruebas de conexión entre Drupal y ella.

   Actualizando datos dentro del Controller

     En este ejemplo, la idea es que tengas todas las herramientas necesarias, para que pueda crear tu propio módulo personalizado y conectarte con una API JSON real, por esta razón no entraremos en detalles. No obstante te he añadido comentarios en cada uno de los cambios a realizar, que podrás copiar y pegar, y una vez comprobado y entendido el proceso, sabrás dónde y cómo realizar el resto de cambios, hasta que vayas ganando experiencia.

     El primero de los archivos que actualizaremos será el Controller ApiConnectorController.php, que es dónde realizaremos el trabajo más importante, conectarnos con la API y recuperar los datos para luego pasarlos a la plantilla.

     Así que, lo próximo que deberás hacer, si has seguido todos los pasos anteriores, será COPIAR Y PEGAR el siguiente código:

<?php declare(strict_types = 1);

namespace Drupal\api_connector\Controller;

use Drupal\Component\Serialization\Json;
use Drupal\Core\Controller\ControllerBase;
use GuzzleHttp\Exception\GuzzleException;

/**
 * Returns responses for Api connector routes.
 */
class ApiConnectorController extends ControllerBase {

  /**
   * Builds the response.
   * @throws GuzzleException
   */
  public function getData(): array {

    $client = \Drupal::httpClient();
    $request = $client->get(
      "https://cat-fact.herokuapp.com/facts" // Url de API JSON
    );
    $response = $request->getBody()->getContents();
    $results = Json::decode($response);
    $data = $results;

    //ksm($data);
    // Descomentar para comprobar valores (Debes tener módulo Devel activado)
    //https://drupaladicto.com/curso/programacion-drupal/contenidos-de-prueba-generados-con-el-modulo-devel

    $build['content'] = [
      '#theme' => 'confirmation_data', //Coloca el nombre de tu plantilla declarada en .module
      '#data' => $data, //Esta es la encargada de pasar todos los valores recuperados a la plantilla.
      '#title' => t('Data from External JSON API') //Este es un título adicional que podrás personalizar y mostrar en la plantilla.
    ];

    return $build;
  }

}

   Explicación sobre los cambios en el Controller

      Lo más relevante que deberás tomar en cuenta, dentro del Controller, son las líneas donde se realiza la conexión, que es donde hemos añadido la url a la que nos conectaremos.

 $request = $client->get( "https://cat-fact.herokuapp.com/facts" // Url de API JSON );

     

     Además, hemos añadido el método getData(), para que tenga más coherencia con nuestro ejemplo, sustituyendo al __invoke(), que nos genera Drush automáticamente cuando creamos el módulo mediante el uso de comandos; por esta razón, tendremos que añadirlo dentro de nuestro archivo routing. 

   También encontrarás la línea que te permitirá comprobar los valores recibidos, que está comentada, para que no te muestre nada si no lo necesitas. El objetivo es que una vez sustituidos todos los valores necesarios en cada archivo, si descomentas esta línea, te mostrará en la página, todos los datos con su respectiva estructura. Para habilitarlo, borrar las dos líneas inclidadas a la izquierda de ksm. (También necesitarás haber descargado y activado el módulo Devel)

//ksm($data);

Custom Module Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony
Texto

   Actualizando datos en el .module

     El siguiente archivos que actualizaremos será el api_connector.module, donde comentaremos la parte del código que no vamos a necesitar para este ejemplo y actualizaremos el hook_theme, para poder mostrar en la plantilla el título y los valores recuperados desde la API JSON.

     Si has seguido todos los pasos anteriores, podrás COPIAR Y PEGAR el siguiente código:

<?php declare(strict_types = 1);

/**
 * @file
 * Primary module hooks for API Connector module.
 */

/**
 * Implements hook_theme().
 */
function api_connector_theme(): array {
  return [
    'confirmation_data' => [
      'variables' => ['data' => [], 'title' => '' ] //Hemos sustituido esta línea con los nuevos valores que mostremos en Twig.
    ],
  ];
}

///**
// * Prepares variables for confirmation-data.html.twig template.
// *
// * Default template: confirmation-data.html.twig.
// *
// * @param array $variables
// *   An associative array containing:
// *   - foo: Foo variable description.
// */
//function template_preprocess_confirmation_data(array &$variables): void {
//  $variables['foo'] = 'bar';
//}
Texto

   Actualizando la plantilla

     Ahora que hemos realizado el resto de cambios en .module y en el controlador, es el turno de añadir una pocas líneas que nos permitirán ver en pantalla, los datos extraidos desde la API JSON. Como he dicho al principio del ejemplo, esta es una guía básica, para que puedas comenzar y continuar practicando y perfeccionando, en función de las necesidades de tu proyecto.

     En este caso, los datos no se guardan en Drupal, pero gracias a que estamos mostrándolos dentro de una plantilla Twig, nos permite aplicar algunso filtros como el |upper, que aplica mayúsculas al texto relacionado con el tipo de animal.

     Si has seguido todos los pasos anteriores, podrás COPIAR Y PEGAR el siguiente código dentro de tu plantilla:

{#
/**
 * @file
 * Default theme implementation to display confirmation_data.
 *
 * Available variables:
 * - foo: Foo variable description.
 *
 * @see template_preprocess_confirmation_data()
 *
 * @ingroup themeable
 */
#}
<div class="wrapper-class">
  {# Con esta línea recuparamos el título personalizado #}
  <h2>{{ title }}</h2>
  <ul>
    {#  {{ foo }}#}
    {% for item in data %}
      <li>{{ item.text }} - <strong>{{ item.type|upper }}</strong></li>
    {% endfor %}
  </ul>
</div>

   Explicación de los cambios

     En esta plantilla, podrás imprimir el resto de valores extraidos, que verás en la parte superior, si descomentas la línea //ksm del Controller, añadiendo punto (.), después de la variable item, seguido del nombre del dato que quieres mostrar.

Texto

   Actualizando el routing

     Como hemos mencionado anteriormente, al añadir el método getData(), dentro de nuestro Controller, tendremos que especificar su llamada, en el archivo routing.yml, para que Drupal pueda llamarlo y mostar los datos relacionados dentro de nuestra plantilla.

api_connector.example:
  path: '/api-connector/example'
  defaults:
    _title: 'Example'
    _controller: '\Drupal\api_connector\Controller\ApiConnectorController::getData'
  requirements:
    _permission: 'access content'

     Con este ejemplo, ya cuentas con las herramientas necesarias, para conectarte desde Drupal, hacia una API JSON externa y mostrar los datos recibidos, dentro de una plantilla, que podrás personalizar. En próximos artículos, abordaremos otros temas, como la manera de guardar los datos en Drupal y/o, mostrarlos dentro de una vista.

     Hasta la próxima.

SDC Module | Componentes sin desacoplar

Video de Youtube
URL de Video remoto

     Con la aparición de diversos frameworks basados en javascript, como Node.js, Angular o Vue.js, cuyas ventajas principales, son la muestra de contenidos con mayor velocidad de carga, o agregar efectos visuales a tu web, sin perjudicar su rendimiento; no era extraño esperar, que la comunidad de Drupal, se pusiera manos a la obra, para insertar estas funcionalidades, dentro del ecosistema encargado de la parte gráfica, gracias a su sistema de plantillas Twig. 

sdc module Drupal | Drupaladicto - Consultores especializados en Drupal y Symfony

   Tras varios intentos, finalmente ha salido a la luz en módulo SDC o Single Directory Components, cuyo principal objetivo es el de permitir, la creación de un directorio, dentro de un módulo o theme personalizado , para alojar en su interior, todos los componentes gráficos, de forma individual, incluyendo en cada uno, todas las dependencias para su funcionamiento, como los archivos relacionados con CSS y Javascript. Este enfoque es el punto fuerte, implementado por los frameworks mencionados anteriormente.

   SCD Module - Instalación

     Como el resto de módulos integrados en el núcleo de Drupal, podremos activar el SDC o Single Directory Components, desde el listado de móldulos, accediendo a  la url "/admin/modules".

     Actualmente el módulo sólo tiene una dependencia con Serialization, que también está incluido en el núcleo de Drupal, por lo tanto, podrás activarlo sin sorpresas, al hacer clic en el botón de instalar.

sdc module Drupal | Drupaladicto - Consultores especializados en Drupal y Symfony

   Requerimientos antes de crear componentes

     Para que podamos comenzar a trabajar con nuestros componentes, además de activar el módulo SDC, necesitaremos contar con un Theme personalizado, para modificar la apariencia del proyecto. 

     Podremos realizar modificaciones en los componentes, a través de módulos personalizados, pero en mi caso yo me centraré en explicarte cómo generar tus componentes, para que interactúen con el theme principal de tu proyecto.

     En el siguiente capítulo, comenzaremos a crear nuestro primer componente, pero primero necesitarás tener ya activado tu theme personalizado, así que te dejo el enlace para que puedas ir preparándote y que puedas continuar con el ejercicio. Utilizaré Boostrap Barrio, pero tú puedes elegir el que prefieras.

   Haz clic aquí para crear tu theme personalizado

Gutenberg | Módulo Drupal

Video de Youtube
URL de Video remoto
Texto

      Aunque en mi opinión, una de las cosas que me enamoró de Drupal en cuanto lo conocí, es la posibilidad de manipular, personalizar y saber encontrar, prácticamente dónde y cuando ocurren la mayoría de sus funcionalidades, entiendo que el objetivo principal de cualquier herramienta de desarrollo, debería ser facilitarnos la vida, además de ofrecernos grandes posibilidades a nuestro alcance.

     Como cada proyecto requiere de diferentes requisitos para llevarse a cabo, y por lo general, uno de los más importantes, es el tiempo que tendremos que invertir hasta su puesta en producción, muchos desarrolladores web prefieren apostar por otros CMS o construir desde cero proyectos enteros, para sentir que tienen mayor control sobre sus creaciones.

     No obstante, creo que con un pequeño conocimiento sobre cómo instalar Drupal 9 usando Composer y un breve vistazo a cómo gestionar usuarios y permisos, complementado con la ayuda del Módulo Gutenberg, conocido mayormente por usuarios de Wordpress, podrías llegar a tener lo que haz estado buscando hace tiempo, una plataforma simple de manipular, pero potente, con posibilidad de adaptación a la mayoría de webs sencillas.

     Es por esta razón que a continuación, te voy a mostrar cómo puedes utilizar las opciones que integra este módulo a la interfaz de usuario, facilitándote de forma notable, la creación de nuevos contenidos en Drupal 9.

Descarga y Activación:

Para descargar y activar cualquier módulo de Drupal tienes varias opciones:

     Descarga:

          1.- La forma recomendada a partir de Drupal 8, es utilizando el gestor de paquetes Composer, ejecutando en tu consola el comando:

composer require drupal/gutenberg

          2.- Descargándolo manualmente el módulo desde la página oficial del Módulo Gutenberg y una vez descargado y colocado en carpeta "modules/contrib", si haz descargado todos tus módulos manualmente, deberías crear la carpeta "contrib", para que puedas diferenciar entre tus módulos personalizados y los que están disponibles directamente en la Página oficial de Drupal.
 

     Activación:

          1.- Utilizando la herramienta de consola Drush, la opción "-y" activará todos los sub-modulos automáticamente

drush en gutenberg -y

          2.- Desde la interfaz de usuario de Drupal, en la url "/admin/modules", y luego marcando el check junto al nombre de tu módulo y haciendo clic en el botón guardar que aparecer al final de la página.

 

gutenberg - www.drupaladicto.com - formacion especializada en drupal y symfony

 

Cómo utilizar Gutenberg

     Una vez activado el Módulo Gutenberg, veremos que se ha añadido una nueva opción, en la parte inferior izquierda de todos los contenidos, llamada Gutenberg Experience y que al activarla podremos ver dos listados con todos los nuevos bloques, tanto del propio módulo como de el núcleo de Drupal, que podremos activar o no, para que estén disponibles como parte de las opciones del tipo de contenido en que se han activado, modificando inmediatamente la interfaz de creación de dicho contenido.

 

Gutenberg Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     La idea principal de Gutenberg, es que convierte todos los elementos que podamos añadir, en bloques individuales, con sus propias opciones, disponibles en el momento en que seleccionamos dicho bloque o elemento, haciéndolo mucho más gráfico el método para añadir, modificar o reutilizar dicho elemento.

     Para comenzar a añadir contenidos o "Bloques" en nuestro tipo de contenido, veremos un símbolo de más dentro de un círculo y al hacer clic sobre éste, se desplegarán las diferentes opciones disponibles para agregar y una vez seleccionado el elemento que deseamos añadir y se añade, inmediatamente cambiará el panel de la derecha de la pantalla, adaptándose a las opciones disponibles para él.

 

gutenberg - www.drupaladicto.com - formacion especializada en drupal y symfony

     De entre sus opciones más llamativas, está la posibilidad de arrastrar directamente los elementos hasta la posición deseada desde el escritorio de tu ordenador, la integración con módulos como Media o Imagen, insertar directamente elementos embebidos como vídeos, sonidos, etc, o la posibilidad de crear "Bloques" de contenido reutilizables en cualquier otro lugar de la web.

     El objetivo de utilizar Gutenberg, es que todos tus tipos de contenido, sólo tengan el campo "Body" y dentro de este campo se podrán añadir, editar o eliminar el resto de elementos que se mostrará en tus páginas, incluyendo imágenes o incluso bloques del núcleo de Drupal.

Gutenberg Cloud

     Una de las opciones más novedosas de este módulo, es la posibilidad de añadir "bloques" de contenido, directamente desde su repositorio en la web Gutenbergcloud.org, mediante el sistema de CDN, por lo que dichos bloques, con características, estilos y funcionalidades prediseñados, no se guardan como el resto de contenidos en la base de datos de Drupal. Por el contrario, se añaden como etiquetas dentro del campo "BODY", que añade Drupal por defecto cada vez que creamos un nuevo tipo de contenido.

     Para añadir esta funcionalidad, sólo habría que activarla como cualquier otro módulo y una vez hecho esto, se añadirá como una de las opciones disponibles para agregar en el listado de bloques cuando hagamos clic en el selector.

 

gutenberg - www.drupaladicto.com - formacion especializada en drupal y symfony

     Por desgracia, esta funcionalidad no es compatible para todas las versiones de Drupal 9, por lo menos al momento de escribir este artículo. Pero sí podrás utilizarla en cualquier instalación de Drupal 8 o menor que la 9.1.

 

Gutenberg Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

Breakpoints en Drupal | imágenes y media (Parte 1)

Video de Youtube
URL de Video remoto
Texto

Si no ves el video, puedes refrescar el navegador, presionando (Ctrl+Shift+R | Ctrl+F5 o Shift+F5), o abrirlo directamente desde el Canal de Youtube... HAZ CLIC AQUI

     A medida que vamos creciendo como profesionales, en el desarrollo o maquetación web, nos podremos encontrar con todo tipo de retos, poniendo a prueba nuestros conocimientos, capacidad de análisis, experiencia y sobre todo nuestra paciencia, hasta llegar a encontrar la mejor solución posible.

     Uno de los requerimientos más solicitados, es la optimización de recursos, que permitan acceder fácilmente al contenido publicado en cualquier página web, ya que el tiempo que transcurre, entre la descarga de la información desde un servidor y la presentación de los datos, en la pantalla de cualquier dispositivo, marcará el éxito o fracaso total del proyecto.

     Entre los recursos más valorados están las imágenes, ya que, además de hacer nuestra web más atractiva para los usuarios, también pueden llegar a provocar verdaderos dolores de cabeza, debido al posible incremento en el consumo de memoria, dependiendo de su calidad o tamaño. Por esta razón es importante encontrar el equilibrio entre lo atractivo y funcional.

     Drupal permite cargar imágenes utilizando dos tipos de campo, el campo de imagen simple, o field_image, que podremos encontrar dentro del tipo de contenido Artículo que viene en la instalación por defecto, o el campo de tipo Media, disponible para añadir en cualquier tipo de contenido al activar los módulos Media y Media Library, incluidos en el núcleo de Drupal a partir de la versión 8.

      A diferencia del field_image, el campo de tipo Media, permite subir, además de imágenes, otros formatos de archivos como videos o audio; y con la activación del Media Library, podremos acceder a una librería de archivos con vista previa, para poder elegir reutilizarlos cuando nos haga falta.

     Una de las maneras más efectivas para trabajar con imágenes, es la implementación del Media Query, que en pocas palabras, consiste en definiciones de varios tamaños, correspondientes a diversos dispositivos, que nos permitirán aplicar ciertos cambios en nuestras imágenes, ejecutados cuando se cumplan dichas especificaciones.

     Inicialmente, la Media Query estaba pensada para su aplicación directamente dentro de los archivos relacionados con estilos o CSS de nuestra web, pero todo cambió cuando apareció la etiqueta <picture>, que según su página oficial: "El elemento HTML <picture> es un contenedor usado para especificar múltiples elementos <source> y un elemento <img> contenido en él para proveer versiones de una imagen para diferentes escenarios de dispositivos. "

     Con la implementación de los Breakpoints o puntos de quiebra, Drupal se encargará de añadir la etiqueta <picture> automáticamente en nuestras imágenes, para que se muestren de acuerdo con el tamaño de cada dispositivo y con los estilos que hemos definido previamente, dentro del apartado /admin/config/media/image-styles.

     Cómo crear breakpoints y aplicarlos a imágenes y archivos Media en Drupal 9

          Prerequisitos:

               Activar los módulos MediaMedia Library y Responsive Image, incluidos en el núcleo de Drupal 9.

Drupal 9 frontend  | www.drupaladicto.com - Consultor especializado en drupal y symfony

          Paso 1 Configuración de los campos para trabajar con las imágenes:

               Tal y como mencionamos al principio, existen dos tipos de campos para trabajar con imágenes en Drupal, así que, añadiremos en el tipo de contenido Artículo, que ya nos viene por defecto con el campo field_image, un nuevo campo del tipo Media y cargaremos unas cuantas imágenes para poder realizar los ejemplos.

Drupal 9 frontend  | www.drupaladicto.com - Consultor especializado en drupal y symfony

Drupal 9 frontend  | www.drupaladicto.com - Consultor especializado en drupal y symfony

         Paso 2 Crear el subtheme y definir los breakpoints o puntos de quiebra:

               Como ya habrás imaginado, los breakpoints están relacionados con la apariencia de nuestra web, en Drupal, los responsables de esta tarea son los Themes o Temas, por lo que tienes dos opciones, o creas un Subtheme basándote en los que ya vienen instalados en Drupal, como haremos en este ejemplo o Descargas e instalas un nuevo Subtheme basándote en otro como Bootstrap, Mayo, etc.

Drupal 9 frontend  | www.drupaladicto.com - Consultor especializado en drupal y symfony

               En ambos casos, para definir los Breakpoints tendrás que crear, dentro de la carpeta raíz del subtheme que hayas seleccionado, un archivo llamado "MISUBTEMA.breakpoints.yml" ....

Drupal 9 frontend  | www.drupaladicto.com - Consultor especializado en drupal y symfony

          y dentro de él simplemente tendrás que definir, los diferentes Breakpoints, siguiendo una estructura como la que te muestro a continuación:

drupaladicto.mobile:
  label: 'Mobile'
  mediaQuery: '(min-width: 0px)'
  weight: 0
  multipliers:
    - 1x
    - 2x

drupaladicto.narrow:
  label: 'Narrow'
  mediaQuery: 'all and(min-width: 560px) and (max-width: 850px)'
  weight: 1
  multipliers:
    - 1x
    - 2x

drupaladicto.wide:
  label: 'Wide'
  mediaQuery: 'all and (min-width: 851px)'
  weight: 2
  multipliers:
    - 1x
    - 2x

     Explicación: La estructura del archivo equivale al nombre de cada breakpoint, compuesto por el nombre de nuestro subthema seguido de un punto y el nombre del punto de quiebra o breakpoint equivalente.

     En la línea siguientes a la declaración del Breakpoint, escribimos el Label o nombre que se mostrará en la interfaz, cuando estemos definiendo los estilos de imágenes responsivas o adaptables.

     En la siguiente línea es donde declaramos el o los tamaños correspondientes, para ejecutar nuestras modificaciones.

     En la siguiente línea, especificamos el "peso" u orden de aparición de las diferentes opciones en el listado de Breakpoints que veremos en la interfaz.

     Por últimos, definimos los tamaños, por ejemplo, para el dispositivo en posición vertical y luego en posición horizonal, donde siginficará el doble del tamaño anterior.   

     Paso 3 Activar el subtheme y comprobar que se han añadido los breakpoints:

          Lo siguiente que tendrás que hacer, ahora que ya tienes todos los breakpoints definidos en el archivo de tu subtheme, es activarlo y comprobar que se han añadido al listado correspondiente de estilos.

          Para comprobar si se han añadido los estilos, una vez activado nuestro subtheme, nos dirigiremos a la url /admin/config/media/responsive-image-style, donde haremos clic en el botón 

Drupal 9 frontend  | www.drupaladicto.com - Consultor especializado en drupal y symfony

Drupal 9 frontend  | www.drupaladicto.com - Consultor especializado en drupal y symfony

Slideshow responsive mulitversiones en Drupal

Video de Youtube
URL de Video remoto

     Aunque en la mayoría de las ocasiones, los módulos contribuidos de Drupal podrán resolver el 85% de las necesidades; en algunos casos nos toca realizar desarrollos a medida o añadir ciertos ajustes, para que el resultado cumpla totalmente con nuestro propósito. 

     Otra de las razones por las que nos podemos ver obligados a realizar esta clase de personalizaciones, es para prevenir fallos por incompatibilidad entre versiones de Drupal, una vez actualizados nuestros proyectos.

     Una de las funcionalidades más reclamadas es el uso de un carrusel o slideshow, donde el usuario administrador del sitio pueda promover algunso contenidos de su web, informar sobre promociones concretas o simplemente avisar a los recién llegados, acerca de las ventajas con las que contarán si se suscriben al sitio.

     Por todo lo anterior, hoy te voy a contar los pasos para crear un Carrusel Responsivo, sin la necesidad de utilizar ningún módulo contribuido y con la capacidad añadida de que podrás utilizarlo en cualquier proyecto Drupal, independientemente de la versión.

   Requerimientos

  • Tener instalado un Subtheme o theme personalizado (Para realizar cambios en plantillas)
     
  • Conocimientos básicos sobre Drupal Behaviors HAZ CLIC AQUÍ
     
  • Tener instalado los módulos Media y Media Libraries (Para cargar las imágenes)
     
  • Tener instalado el módulo Paragraphs (Para que el Slideshow sea más flexible) HAZ CLIC AQUI
     
  • Tener habilitado el Modo debug de Drupal HAZ CLIC AQUÍ
     

   Cómo crear un Slideshow Responsivo transversal en Drupal

     Paso 1 - Crear el Subtheme o tema personalizado

       Vamos a comenzar por generar nuestro tema personalizado, para ello utilizaremos el Theme Olivero, que viene instalado en Drupal, a partir de Drupal 9, sustituyendo a Bartik.

Imagen
Subtheme Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

   Arhivos y configuraciones del Subtheme basado en Olivero

     Para poder implementar un tema personalizado en Drupal, serán necesarios varios archivos y carpetas, que nos permitirán conectarlo con Drupal; una vez instalado el subtheme, podremos añadir ciertas modificaciones posteriores, como haremos con los estilos CSS y el código javascript necesario para que funcione nuestro carrusel de imágenes.

     Los archivos y carpetas, que deberás crear antes de poder instalar el Subtheme son:

     Carpetas: olivero_subtheme, css, js, templates

     Archivos: olivero_subtheme.info.yml, global_styling, olivero_subtheme.libraries.yml, style.css, global.js

olivero_subtheme/ olivero_subtheme.info.yml

name: 'Olivero Subtheme'
type: theme
description: 'Subhteme based on Olivero'
core: 8.x
core_version_requirement: ^8 || ^9 || ^10
base theme: olivero

libraries:
  - olivero_subtheme/global-styling

olivero_subtheme/ olivero_subtheme.libraries.yml

global-styling:
  version: 1.x
  css:
    theme:
      css/style.css: {}
  js:
    js/global.js: {}
  dependencies:
    - core/jquery

olivero_subtheme/ style.css

/**
 * @file
 * Subtheme specific CSS.
 */

   Una vez creados todos los archivos necesarios para nuestro subtheme, podremos activarlo como theme por defecto, por medio de la interfaz de usuario de Drupal, desde la url '/admin/appearance', no hemos definido ninguna zona en el archivo olivero_subtheme.info.yml, porque utiliaremos las mismas que trae el theme base Olivero.

Imagen
Subtheme Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

   Paso 2 - Creación de los Paragraphs Carrusel y Diapositiva

     Al igual que explicamos en el curso Landing Page para Drupal 8/9/10, nuestra idea será crear un componente del tipo Paragraphs al que llamaremos Carrusel, que nos permitirá añadirlo y reutilizarlo, en cualquiera de las páginas de nuestro proyecto, por eso lo combinaremos con los módulos Media y Media libraries, y así podremos aprovechar la máximo todo nuestro contenido.

     Primero crearemos un tipo de paragraphs, al que llamaremos "Diapositiva" y le añadiremos cuatro campos:

     - Imagen de fondo: Tipo multimedia, para reutilizar las imágenes.

     - Títular princpal

     - Subtítulo

     - Botón: tipo enlace, para que podamos añadir un botón que lleve al usuario a otros contenidos.

Imagen
Slider multiversion Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony
Imagen
Slider multiversion Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony
Imagen
Slider multiversion Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     Una vez creado el páragraph para las diapositivas, crearemos el segundo paragraphs, con el nombre "Carrusel Promocional", con un único campo del tipo Paragraphs, al que llamaremos "Diapositivas" y dejaremos como ilimitado, permitiéndonos añadir tantas diapositivas como hagan falta.

Imagen
Slider multiversion Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony
Imagen
Slider multiversion Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony
Imagen
Slider multiversion Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     Paso 3 - Añadir el campo Contenidos en Basic Page

     Ahora que ya tenemos creados y configurados los paragraphs, correspodientes a las diapositivas y al mismo carrsuel, es el momento de añadirlo, dentro del contenido "Página básica" o el que prefieras tú, lo llamaremos "Contenidos", y por el momento, sólo añadiremos la referencia hacia nuestro "Carrusel Promocional"

Imagen
Creacion de campos | www.drupaladicto.com - Consultor especializado en Drupal y Symfony
Imagen
Slider multiversion Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony
Imagen
Slider multiversion Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony
Imagen
Slider multiversion Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony
     El resultado final, será un carrusel al que podremos añadir varias diapositivas, con los elementos necesarios para que nuestros usuarios puedan ver la información principal y hacer clic en el botón, para saber los detalles.
Imagen
Slider multiversion Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

   Paso 4 - Configurar las plantillas Twig

     Este paso ya lo hemos explicado ampliamente en varias ocaciones, se trata de facilitar la identificación de las plantillas que necesistaremos, para adapatarlas a los cambios requeridos.

     Si todavía no haz utilizado el Modo Debug de Drupal HAZ CLIC AQUÍ

     Con el modo Debug activado, nos tocará averiguar y elegir el nombre para nuestras plantillas y aplicarles la estructura correspondiente en cada caso.

     Así que, para poder probar nuestro carrusel, primero crearemos una página básica y le añadiremos todos los datos necesarios, que hemos configurado previamente. Como se trata de un carrusel, añadiremos dos diapositivas, para verificar que todo es correcto y se muestra según lo que esperábamos.

Imagen
Slider multiversion Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony
Imagen
Slider multiversion Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony
Imagen
Slider multiversion Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

   Cambiando la plantilla de las diapositivas

     Basándonos en el nombre sugerido para la plantilla que afectará a nuestras diapositivas, copiaremos la plantilla modelo desde el módulo Paragraphs y a continuación copiaremos el siguiente código, cambiando los valores por los que hemos puesto.

{% block paragraph %}
  <div{{ attributes.addClass(classes) }}
    {% block content %}
      {% if content.field_imagen_de_fondo|render is not empty %}
        style=" background-image: url('{{ file_url(content.field_imagen_de_fondo[0]['#media'].field_media_image.entity.uri.value) }}')";
      {% endif %}
      >
      <div id="home-content-box" {{ content_attributes.addClass('node__content', 'clearfix') }}>
        <div id="home-content-box-inner" class="text-center">
          <div id="home-heading">
            {% if content.field_titular_princpal|render is not empty %}
              <h1 class="label-slide">{{ content.field_titular_princpal.0 }}</h1>
            {% endif %}
            {% if content.field_subtitulo|render is not empty %}
              <div id="env-explicacion">
                <p class="explicacion">
                  {{ content.field_subtitulo.0 }}
                </p>
              </div>
            {% endif %}
            {% if content.field_boton_diapositiva|render is not empty %}
              <div id="home-btn" class="animated zoomIn">
                <a class="btn btn-light"
                   href="{{ content.field_boton_diapositiva[0]['#url'] }}" role="button"
                   title="{{ content.field_boton_diapositiva|render|striptags|trim }}">
                  {{ content.field_boton_diapositiva[0]['#title'] }}
                </a>
              </div>
            {% endif %}
          </div>
        </div>
      </div>
    {% endblock %}
  </div>
{% endblock paragraph %}

     Guaradaremos los cambios y deberíamos ver algo parecido a la siguiente pantalla, en caso contrario, puede que necesites borrar la caché de Drupal, o corregir el nombre de alguno de tus campos en la plantilla.

Imagen
Slider multiversion Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

   Aplicando CSS a la plantilla para las Diapositivas

     En esta parte, aplicaremos los primeros cambios para modificar el aspecto de nuestras diapositivas, será desición tuya si colocas los estilos dentro de la misma plantilla, entre las etiquetas <style></style>, lo cual haría de esta plantilla una especie de Compente, como si trabajaras con un proyecto Headless o si lo prefieres, puedes añadirlo a tu hoja de estilos global.

<style>
  /* Telefonos en vertical (portrait phones, less than 576px) */
  @media (max-width: 575.98px) {
    #home-heading {
      margin-top: -166px;
    }

    header#header {
      position: absolute;
      z-index: 99;
      width: 100%;
    }
    #navbar-main {
      background: none;
    }
    #navbar-main .container {
      max-width: 90%;
    }
    .navbar-brand img, span.navbar-toggler-icon {
      filter: invert(1);
    }
    button.navbar-toggler.collapsed {
      border: none;
    }
    .paragraph--type--diapositiva {
      height: 800px;
      margin-bottom: 40px;
    }
    h1.label-slide {
      font-size: 40px;
      color: #fff;
      line-height: 47px;
      max-width: 243px;
      margin: auto;
    }
    #env-explicacion {
      font-size: 18px;
      max-width: 314px;
    }

  }
  /* Ordenadores y Laptops (desktops, 992px and up) */
  @media (min-width: 992px) {

    .paragraph--type--diapositiva {
      height: 800px;
    }
    h1.label-slide {
      font-size: 50px;
      color: #fff;
      line-height: 47px;
      margin-bottom: 25px;
    }

    #env-explicacion {
      font-size: 14px;
    }

    .paragraph--type--diapositiva a.btn.btn-light {
      margin-top: 54px;
    }
    .owl-dots {
      position: relative;
      top: -254px;
    }
  }
  .paragraph--type--diapositiva {
    background-size: cover;
    background-repeat: no-repeat;
  }
  #home-content-box {
    width: 100%;
    height: 100%;
    display: table;
    background: rgba(0,0,0,0.6);
  }
  #home-content-box-inner {
    display: table-cell;
    vertical-align: middle;
    text-align: center;
  }
  #env-explicacion {
    font-size: 21px;
    margin: auto;
    color: #ccc;
    line-height: 29px;
    max-width: 90%;
  }
  #env-explicacion p {
    max-width: 806px;
    margin: 20px auto;
  }
  .paragraph--type--diapositiva a.btn.btn-light {
    border-radius: 25px;
    padding: 10px 30px;
    text-decoration: none;
    background: #ededed;
    color: #000;
  }
</style>
 

   Pado 5 - Añadiendo las librerías de OWL Carousel

     Como hemos prometido, nuestro carrusel no necesitará ningún módulo contribuido de Drupal para su funcionamiento, esto permitirá que podamos emplearlo en mútiples proyectos, sin correr riesgos de compatiblidad.

     Así que utilizaremos los archivos descargados desde la página oficial de Owl Carousel 2, que nos permitirán obtener un carrusel, muy fácil de configurar y personalizar, gracias a varias de las opciones con las que cuenta.

     Tienes la demostración y el código necesario en el apartado Demos, dentro de su misma web.

Imagen
Slider multiversion Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     Por ahora, necesitaremos descarar el archivo ubicado en la página oficial, en el botón Download y a continuación, añadiremos, dentro de las carpetas js y css, de nuestro tema personalizado, los siguientes archivos:

- css / owl.carousel.min.css

css / owl.theme.default.min.css

- js/ owl.carousel.min.js

 

Imagen
Slider multiversion Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     Cuando hayamos colocado cada uno de los archivos, dentro de sus correspondientes carpetas css y js, en nuestro tema personalizado, añadiremos la ruta, dentro de nuestro archivo libraries, para poder ejecutar el código sobre los elementos de nuestro carrusel.

olivero_subtheme.libraries.yml

global-styling:
  version: 1.x
  css:
    theme:
      css/style.css: {}
      css/owl-carousel/owl.carousel.min.css: { }
      css/owl-carousel/owl.theme.default.min.css: { }
  js:
    js/global.js: {}
    js/owl-carousel/owl.carousel.min.js: { }
  dependencies:
    - core/jquery

 

   Añadiendo el identificador para nuestro carrusel

     Para que nuestro carrusel funcione con OWL Carousel 2, tendremos que añadir dos elementos fundamentales, el identificador, con el cual podremos aplicar todas las funcionalidades javascript y la clase owl-carousel owl-theme, que permitirá conectar el contenido con el carrusel.

     En este caso, añadiremos una plantilla más, del tipo campo, porque así nos aseguraremos de que esté justo encima de las diapositivas.

     Como estamos utilizando Olivero, copiaremos la plantilla field.html.twig, ubicada en su carpeta Templates y la renombraremos, colocándola dentro de nuestro tema personalizado.

     Luego añadiremos el identificador y la clase, en la primera línea, tal y como te muestro en la siguiente imagen.

Imagen
Slider multiversion Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

   Paso 6 - Añadiendo el código javascript

     Ya casi hemos terminado todo el trabajo, el último paso será llamar a nuestros elementos, utilizando el identificador que acabamos de agregar y aplicándole los ajustes necesarios de Javascript, que harán funcionar nuestro carrusel.

     En esta parte, añadiremos el código que falta, dentro del archivo global.js.

/**
 * @file
 * Global utilities.
 *
 */

(function (Drupal) {
  Drupal.behaviors.drupalAdicto = {
    attach: function (context, settings) {


      $("#slider-home").owlCarousel({
        autoplay: true,
        loop: true,
        autoplayHoverPause: true,
        nav: false,
        center: true,
        margin: 0,
        responsive: {
          0:{
            items: 1,
            dots: true,
          },
          600:{
            items: 1,
            dots: true,
          },
          1000:{
            items: 1,
            dots: true,
          }

        }
      });

    }
  };
})(Drupal);
Imagen
Slider multiversion Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

Landing Page Drupal | Plantillas Twig (Parte 2) - Bootstrap y Flexbox

Video de Youtube
URL de Video remoto

     Debido a que estamos trabajando con Bootstrap 5, para la creación de nuestra Landing Page personalizable en Drupal 8/9/10, hoy utilizaremos las clases de Bootstrap 5 compatibles con Flexbox; de esta manera, nuestro diseño quedará adaptado a múltiples dispositivos (Responsive), sin la necesidad de manipular nuestra hoja de estilos.

     Si analizamos el comportamiento que esperamos obtener para la visualización de nuestra Landing Page, al acceder desde un ordenador, veremos que en la parte central, los elementos deberían presentarse dentro de tres columnas, las dos primeras para la imagen e información del producto, y la última, a todo el ancho del contenido, donde se muestra el formulario para la realización de los pedidos.

 

Imagen
Landing Page Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     Al acceder a la Página Oficial de Bootstrap, en el apartado de Utilidades, dedicado a FLEX HAZ CLIC AQUI, podremos explorar el listado de clases y sus comportamientos, para facilitarnos la aplicación de casi todas las opciones necesarias en nuestros diseños resposivos, sin demasiados cambios en las hojas de estilos css.

     Si ya conocías Bootstrap, sabrás que, añadiendo una o varias clases dentro de cualquier contenedor o etiqueta html, obtendrás el mismo resultado que si aplicaras varias líneas de código css; esto implica un ahorro considerable dentro de las tareas de diseño, además de ofrecer una amplia documentación y varios ejemplos, que podrás encontrar, tanto dentro de la página oficial, como el muchas otras disponibles en internet.

Imagen
Landing Page Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     Ahora que ya sabemos cómo documentarnos, sobre el uso de las clases de Bootstrap y Flexbox, volvamos a explorar el archivo node--landingpage--full.html.twig, responsable de mostrar nuestra plantilla.

     Recuerda, que hemos creado esta plantilla, gracias a que activamos el modo Debug o Depurador de Drupal, explicado en capítulos anteriores del curso.

     Si prestamos atención en el código que forma, la parte superior de la plantilla, donde hemos añadido ya la imagen de cabera y el texto que aparece justo debajo de ella, encontraremos algunas de las clases de Bootstrap y Flexbox que acabamos de comentar.

{% if content.field_cabecera_landing|render is not empty %}
<div class="d-flex container-fluid" lc-helper="background" style="height:50vh;background:url({{ file_url(content.field_cabecera_landing[0]['#media'].field_media_image.entity.uri.value) }})  center / cover no-repeat;">
  {% endif %}
</div>
<div class="container p-5 bg-light" style="margin-top:-100px">
  <div class="row">
    <div class="col-md-4 text-center align-self-center">
      <div class="lc-block border-end border-2 ">
        <div editable="rich">
          <p class="display-4 text-secondary">WHY?</p>
        </div>
      </div><!-- /lc-block -->
    </div><!-- /col -->
    <div class="col-md-8">
      <div class="lc-block ">
        <div editable="rich">
          <p class="display-4">{{ label.0 }}</p>
        </div>
      </div><!-- /lc-block -->
    </div><!-- /col -->
  </div>

   Explicación

     d-flex: Es la primera de las clases que deberíamos añadir en nuestra etiqueta HTML, para poder emplear la combinación de Flex y Boostrap; añadirla es el equivalente a escribir la propiedad display: flex, dentro de nuestra hoja de estilos.

     container / container-fluid: tiene la misma funcionalidad que ya conoces de Boostrap, y que en este caso, añadirá la propiedad padding, configurada por defecto para Drupal, cuando utilizamos el tema basado en Boostrap.

     p-5: Esta clase es la encargada de modificar la propiedad padding, tienes varios valores disponibles, además de la opción de utilizarla, especificando si quieres aplicar un padding-top pt-5, o padding buttom pb-5, por ejemplo.

     align-self-center: esta clase, como su nombre lo indica, se encargará de centrar los elementos, dentro del contenedor.

     col-md-4: esta es una de las clases que ya deberías conocer, por versiones anteriores de bootstrap, encargada de adaptar el tamaño de la columna, en los dispositivos de tamaño medio (Tablets, Ipads, etc.)

     Si quieres profundizar más sobre las clases disponibles y su implementación, te recomiendo visitar la página oficial de Boostrap. HAZ CLIC AQUI.

   Añadiendo cambios en la plantilla

     Es el momento de continuar con el resto de cambios necesarios, para seguir ajustando nuestra Landing Page, hasta conseguir que se parezca a nuestra propuesta de diseño.

     En esta ocasión, vamos a sustituir en nuestra plantilla, todo el espacio que ocupa el texto central, para dejarle paso, a dos nuevas filas, donde añadiremos los campos correspondientes, encargados de mostrar las imágenes e información de los productos, además del formulario para los peidos.

     He añadido un para de clases adicionales, sólo para que sea más fácil de entender, donde colocaremos cada uno de los elementos.

     El resultado final, con el nuevo cambio, debería ser parecido al siguiente código:

  <div class="row contenido-central">
     <div class="col-md-12">
       <div class="row info-productos">
            LOS PRODUCTOS AQUI
       </div>
       <div class="row formulario-pedidos">
            EL FORMULARIO AQUI
       </div>
     </div>
  </div>
</div>
Imagen
Landing Page Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     Ahora ya tenemos claro, cuál debería ser la estructrura para conseguir el resultado esperado en mi Landing Page, el problema con el que nos encontramos, es que nuestra plantilla sólo tienes dos campos, con los que podamos jugar, field_cabecera_landingfield_contenidos_landing, ya que hemos optado, por el uso de paragraphs, para facilitar la personalización de sus contenidos.

     Si volvemos a la parte del código donde imprimimos nuestra imagen, podremos concluir, que lo que necesitamos para obtener el resto de valores de nuestra página, es añadir la variable que imprime el campo global de los paragraphs y a continuación, añadir las plantillas correspondientes, para cada uno de los elementos contenidos dentro de éste.

     Lo primero que deberíamos hacer será remover la parte del código donde estarán las imágenes, información y el formulario, para añadir dentro sólo el campo global de los paragraphs.

     Por ahora, nuestra plantilla principal, node--landingpage--full.html.twig, debería quedar con el suguiente resultado:

  <div class="row contenido-central">
     <div class="col-md-12 p-5">
        {{ content.field_contenidos_landing }}
     </div>
  </div>
</div>

     Una vez añadido el código anterior, si visitamos nuestra Landing Page, deberíamos ver en pantalla, algo parecido a la siguiente imagen:

Imagen
Landing Page Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

     Si todo ha ido correctamente, y ves en pantalla un resultado parecido al anterior, es el momento de inspeccionar los elementos y crear las plantillas correspondientes a cada paragraphs, para cotinuar con el resto de modificaciones.

Imagen
Landing Page Drupal | www.drupaladicto.com - Consultor especializado en drupal y symfony

   Plantilla principal para la landing page

     El código final de la plantilla general para la landing (node--landingpage--full.html.twig), que incluye además, el campo de selección para el color, gracias al módulo Color Field, será :

{{ attach_library('bootstrap_barrio/node') }}

{%
  set classes = [
    'node',
    'node--type-' ~ node.bundle|clean_class,
    node.isPromoted() ? 'node--promoted',
    node.isSticky() ? 'node--sticky',
    not node.isPublished() ? 'node--unpublished',
    view_mode ? 'node--view-mode-' ~ view_mode|clean_class,
    'clearfix',
  ]
%}
<article{{ attributes.addClass(classes) }}>
  <header>
    {{ title_prefix }}
    {% if label and not page %}
      <h2{{ title_attributes.addClass('node__title') }}>
        <a href="{{ url }}" rel="bookmark">{{ label }}</a>
      </h2>
    {% endif %}
    {{ title_suffix }}
    {% if display_submitted %}
      <div class="node__meta">
        {{ author_picture }}
        {% block submitted %}
          <em{{ author_attributes }}>
            {% trans %}Submitted by {{ author_name }} on {{ date }}{% endtrans %}
          </em>
        {% endblock %}
        {{ metadata }}
      </div>
    {% endif %}
  </header>
  <div{{ content_attributes.addClass('node__content', 'clearfix') }}>

    {% if content.field_cabecera_landing|render is not empty %}
    <div class="d-flex container-fluid" lc-helper="background" style="height:50vh;background:url({{ file_url(content.field_cabecera_landing[0]['#media'].field_media_image.entity.uri.value) }})  center / cover no-repeat;">
      {% endif %}
    </div>
    <div class="container p-lg-5" style="margin-top:-100px;
                                         background-color: {{ content.field_color_fondo_landing.0 }}"
     >
      <div class="row">
        <div class="col-md-4 text-center align-self-center">
          <div class="lc-block border-end border-2 ">
            <div editable="rich">
              <p class="display-4 text-secondary">WHY?</p>
            </div>
          </div><!-- /lc-block -->
        </div><!-- /col -->
        <div class="col-md-8">
          <div class="lc-block ">
            <div editable="rich">
              <p class="display-4">{{ label.0 }}</p>
            </div>
          </div><!-- /lc-block -->
        </div><!-- /col -->
      </div>
      <div class="row contenido-central">
         <div class="col-md-12 p-md-5">
            {{ content.field_contenidos_landing }}
         </div>
      </div>
    </div>

  </div>
</article>

   Plantilla para la imagen y el texto del producto

     El código correspondiente a la parte superior, donde mostramos la imagen del producto, acompañada de un título y un párrafo, (paragraph--bloque-imagen-y-textos.html.twig) será:

{%
  set classes = [
    'paragraph',
    'd-lg-flex',
    'paragraph--type--' ~ paragraph.bundle|clean_class,
    view_mode ? 'paragraph--view-mode--' ~ view_mode|clean_class,
    not paragraph.isPublished() ? 'paragraph--unpublished'
  ]
%}
<style>
  @media (min-width: 992px) {
    .field--name-field-imagen-producto {
      width: 550px;
    }
  }
</style>
{% block paragraph %}
  <div{{ attributes.addClass(classes) }}>
    {% block content %}
      <div class="row no-gutters d-flex">
        <div class="imagen-producto d-sm-column">
          {{ content.field_imagen_producto }}
        </div>
      </div>
      <div class="row no-gutters d-flex">
        <div class="texto-producto d-sm-column">
          <h2>{{ content.field_texto_superior.0 }}</h2>
          <p>{{ content.field_textos_producto.0 }}</p>
        </div>
      </div>
    {% endblock %}
  </div>
{% endblock paragraph %}

   Plantilla para el Bloque formulario

     Para la plantilla, encargada de modificar el aspecto gráfico correspondiente al formulario, que además incluye la etiqueta html <hr />, con algunos estilos en línea, (paragraph--bloque-formulario.html.twig), será:

{%
  set classes = [
    'paragraph',
    'd-flex flex-column',
    'paragraph--type--' ~ paragraph.bundle|clean_class,
    view_mode ? 'paragraph--view-mode--' ~ view_mode|clean_class,
    not paragraph.isPublished() ? 'paragraph--unpublished'
  ]
%}
{% block paragraph %}
  <div{{ attributes.addClass(classes) }}>
    {% block content %}
      <hr style="height: 5px; background-color: #333333;margin-top: 40px; margin-bottom: 40px"/>
      <div class="titular text-align-center flex-row"><h2>{{ content.field_titulo_formulario }}</h2></div>
      <div class="formulario">
        {{ content.field_formulario_bloque }}
      </div>
    {% endblock %}
  </div>
{% endblock paragraph %}