Extra Block Types (EBT) - Nueva experiencia con Layout Builder❗

Extra Block Types (EBT): tipos de bloques con estilo y personalizables: Presentaciones de diapositivas, Pestañas, Tarjetas, Acordeones y muchos más. Configuraciones integradas para fondo, DOM Box y plugins de JavaScript. Experimenta hoy el futuro de la construcción de diseños.

Módulos de demostración EBT Descargar módulos EBT

❗Extra Paragraph Types (EPT) - Nueva experiencia con Paragraphs

Extra Paragraph Types (EPT): conjunto de módulos basado en párrafos de forma análoga.

Módulos de demostración EPT Descargar módulos EPT

Scroll

Creación de nuevos módulos EPT

06/05/2025, by Ivan

La forma más fácil de crear un nuevo módulo EPT es mediante el comando Drush (para Drush 12+). Para usar este comando, necesitas habilitar el módulo EPT Core Starterkit:

EPT Starterkit

Después de eso, estará disponible el generador de módulos EPT:

drush generate ept:module

Comienza el nombre de la máquina con el prefijo ept_*, es obligatorio para que todos los módulos EPT funcionen correctamente.

Generador de módulos EPT

También puedes usar EPT Starterkit en la carpeta de módulos de EPT Core. Solo tienes que renombrar todas las apariciones de ept_starterkit en los archivos con el nombre de máquina de tu nuevo módulo EPT.

https://www.drupal.org/project/ept_core

O copiar el módulo EPT Text y reemplazar allí el nombre de la máquina.

https://www.drupal.org/project/ept_text

Ya que es el módulo EPT más simple y contiene todas las configuraciones básicas de EPT.

Creación del módulo EPT paso a paso

(Algunas capturas de pantalla pueden pertenecer al módulo de cuenta regresiva EBT)

Copia el módulo EPT Text existente o el módulo EPT Kickstarter como plantilla, o utiliza el comando drush generate ept:module.

El módulo EPT Text contiene las siguientes carpetas:
/ept_text/config/install — contiene configuraciones para el tipo de párrafo EPT Text y las instancias de campos. Otros módulos EPT pueden contener configuraciones para tipos de párrafo y almacenamiento de campos.
/ept_text/templates — contiene la plantilla paragraph--ept-text--default.html.twig para el párrafo.
/ept_text/tests — contiene pruebas para los módulos EPT, actualmente solo una prueba de instalación.

Y otros archivos estándar de módulos de Drupal: composer.json, ept_text.info.yml, readme.md. Puedes encontrar más detalles sobre cómo crear módulos personalizados en Drupal en la documentación oficial:

https://www.drupal.org/docs/develop/creating-modules

Crearé un nuevo módulo EPT Countdown que utilizará el siguiente plugin de JavaScript — FlipDown:

https://github.com/PButcher/flipdown

FlipCount.js

Haz un fork del repositorio en GitHub y súbelo a Packagist.

Todas las bibliotecas de terceros deben ser bifurcadas y alojadas en Packagist, por ejemplo:

https://packagist.org/packages/levmyshkin/flexslider

de:

https://github.com/levmyshkin/flexslider

Entonces Composer podrá cargarlas como bibliotecas normales desde Packagist. Estas bibliotecas de terceros deben incluir el campo "type": "drupal-library" en composer.json, y luego se instalarán en la carpeta /libraries por defecto:
https://github.com/levmyshkin/flexslider/blob/master/composer.json

EBT library

Vamos a bifurcar el repositorio FlipDown en GitHub.

Generalmente no se recomienda bifurcar repositorios en lugar de usar las fuentes originales. Sin embargo, creo que esto facilita el uso de los módulos EPT sin tener que editar manualmente composer.json. Imagina lo difícil que es para un principiante instalar Composer, modificar manualmente composer.json y especificar correctamente la URL de un repositorio externo. Tener tu propia biblioteca en Packagist simplifica la instalación. Por lo tanto, es mejor alojar todas las bibliotecas de terceros en Packagist.

fork git repository

En la página del fork en GitHub, puedes renombrar el repositorio. El nombre debe ser simple, sin letras mayúsculas ni caracteres especiales. Se permiten guiones (-) y guiones bajos (_).

Rename repository

Ahora tenemos un nuevo repositorio:

https://github.com/levmyshkin/flipdown

Agreguemos un archivo composer.json con type "drupal-library":

git add composer.json
git commit -m 'Add Composer.json file'
git push origin master

El archivo composer.json está disponible en:

https://github.com/levmyshkin/flipdown/blob/master/composer.json

Si revisas las etiquetas actuales en el repositorio, no habrá ninguna:

git tag

Git tags

Normalmente sigo la versión de la biblioteca original. Si la última versión era 1.4.6, aumento la versión menor a 1.4.7. Como FlipDown no tenía etiquetas, creé la versión 1.0.0:

git tag 1.0.0
git push origin 1.0.0

Se requiere una etiqueta porque contiene el composer.json con type "library".

¿Por qué no simplemente copiar la biblioteca JS en el módulo?

Solo se pueden copiar bibliotecas con licencia GPL. Las bibliotecas JavaScript generalmente usan la licencia MIT. Técnicamente es posible, pero las reglas de Drupal.org lo prohíben:
https://www.drupal.org/about/licensing

Ahora publiquemos la biblioteca FlipDown en Packagist:

https://packagist.org/packages/submit

Submit new library on packagist.org

Si olvidaste agregar composer.json con "type": "drupal-library" antes de publicarlo — no hay problema. Solo agrega el archivo y crea una nueva etiqueta, Packagist obtendrá las actualizaciones automáticamente.

Esta es la página de la biblioteca en Packagist:

https://packagist.org/packages/levmyshkin/flipdown

Packagist library

Asegúrate de que la página de la biblioteca muestre el tipo como drupal-library.

Ahora volvamos a nuestros archivos de Drupal y copiemos la carpeta ept_text; nombraré el nuevo módulo ept_countdown:

EPT Countdown

Los siguientes pasos deben realizarse:

  • Eliminar las configuraciones en /config/install — exportaremos nuevas más adelante.
  • Reemplazar todas las apariciones de ept_text por ept_countdown.
  • Renombrar los archivos, reemplazando "text" por "countdown".
  • Actualizar las descripciones del módulo en ept_countdown.info.yml y README.md.

Realizaré cada paso por separado en Git, para que puedas seguir los cambios paso a paso:

git clone https://git.drupalcode.org/project/ept_countdown.git

Ahora tenemos una plantilla para nuestro módulo, y podemos enviar los cambios a Drupal.org.

Crea un proyecto de módulo en Drupal.org.

Vamos al sitio de drupal.org a la página de creación de proyectos:

https://www.drupal.org/node/add

Drupal.org add content

Necesitamos añadir un proyecto del tipo Módulo:

https://www.drupal.org/node/add/project-module

Título: Extra Paragraph Types (EPT): Countdown
Tipo de proyecto: Proyecto completo
Nombre corto: ept_countdown
Estado de mantenimiento: Mantenido activamente
Estado de desarrollo: En desarrollo activo
Categorías del módulo: Contenido, Visualización de contenido
Ecosistema: Extra Paragraph Types (EPT): Core

Create new drupal project

En el campo Descripción, normalmente inserto la lista completa de módulos EPT disponibles (ver el ejemplo en Markdown arriba).

Ahora tenemos una página de proyecto de módulo en Drupal.org:
https://www.drupal.org/project/ept_countdown

En la pestaña Control de versiones (Version Control), puedes encontrar instrucciones sobre cómo añadir un repositorio remoto a tu proyecto Git local:

https://www.drupal.org/project/ept_countdown/git-instructions

Drupal project version control

Después del primer commit, debes crear una nueva rama consistente con la versión principal de otros módulos EPT — actualmente es 1.4.x.

Ahora podemos comenzar a agregar nueva funcionalidad a nuestro módulo. El proceso es similar al desarrollo de un módulo personalizado: crearemos un tipo de párrafo, añadiremos campos e incluiremos recursos CSS/JS.

Primeros pasos con el desarrollo de la funcionalidad de EPT Countdown

Paso 1. Crea el tipo de párrafo EPT Countdown. Simplemente instala el módulo si lo generaste usando Drush.
 

Primeros pasos con el desarrollo de la funcionalidad EPT Countdown

Paso 1. Crea el tipo de párrafo EPT Countdown. Simplemente instala el módulo si lo generaste usando Drush.
 

Primero, necesitas crear un nuevo tipo de párrafo EPT Countdown:

/admin/structure/paragraphs_type/add

Agregar tipo de párrafo EPT Countdown

Asegúrate de que el nombre de máquina comience con ept_. Normalmente comienzo el nombre del párrafo con EPT — de esta manera el nombre de máquina se forma automáticamente de forma correcta. ¿Debe coincidir el nombre de máquina con el nombre del módulo? Sí, se recomienda por coherencia y para evitar conflictos con otros módulos EPT. Esto también es importante para anular plantillas desde los módulos en lugar de los temas — consulta la función ept_core_theme_registry_alter() en el módulo ept_core.

Ahora añade el campo EPT Settings: field_ept_settings — este campo es obligatorio para todos los módulos EPT:

Agregar campo EPT Settings

EPT Settings es un campo compartido del módulo EPT Core; proporciona configuraciones para DOM Box, fondo, espaciado y ancho.

Como necesitamos contar hacia una fecha, añade un campo de fecha y hora:

Agregar campo de fecha

Agregué el prefijo ept_ al nombre de máquina, pero no es obligatorio. Puedes nombrarlo, por ejemplo, field_countdown_date. También tenemos los campos predeterminados body y title — esto es suficiente para el párrafo de cuenta regresiva.

Para los módulos EPT, normalmente usamos pestañas horizontales en el formulario de edición:

Pestañas horizontales

Esto no es obligatorio, pero es conveniente separar el contenido y las configuraciones, especialmente cuando hay muchas configuraciones.

El grupo padre debe configurarse como Tabs con la dirección Horizontal y el parámetro Width Breakpoint establecido en 120 (u otro valor pequeño):

Configuraciones de pestañas

Ahora que tenemos el tipo de párrafo, habilita el módulo EPT Countdown para aplicar las plantillas:

/admin/modules

Habilitar EPT Countdown

Habilita el párrafo EPT Countdown para el tipo de contenido deseado con un campo de párrafos:

Crear párrafo EPT Countdown

Esto es lo que obtenemos en la página:

EPT Countdown

Paso 2. Conexión de bibliotecas de terceros en módulos EPT

Ahora podemos conectar una biblioteca de terceros. Ya tenemos la biblioteca levmyshkin/flipdown listada en composer.json, pero como se trata de un módulo personalizado, necesitamos instalar la biblioteca manualmente mediante Composer:

composer require levmyshkin/flipdown

La biblioteca se instalará automáticamente en la carpeta /libraries:

Instalar flipdown

Ahora crea el archivo ept_countdown.libraries.yml y registra las bibliotecas CSS/JS de FlipDown, así como un archivo JS personalizado ept_flipdown/js/ept_countdown.js, donde se inicializará el plugin FlipDown más adelante:

ept_countdown.libraries.yml:

ept_countdown:
  css:
    component:
      /libraries/flipdown/dist/flipdown.min.css: { minified: true }
  js:
    /libraries/flipdown/dist/flipdown.min.js: { minified: true }
    js/ept_countdown.js: {}
  dependencies:
    - core/once
    - core/drupalSettings

Para los archivos en la carpeta /libraries, usamos rutas absolutas que comienzan con una barra diagonal.

js/ept_countdown.js:

(function ($, Drupal) {

  /**
   * Comportamiento de EBT Countdown.
   */
  Drupal.behaviors.eptCountDown = {
    attach: function (context, settings) {

    }
  };

})(jQuery, Drupal);

También necesitamos adjuntar la biblioteca ept_countdown en las plantillas de párrafo. No olvides que tenemos dos plantillas:

{{ attach_library('ept_countdown/ept_countdown') }}

Plantillas de Drupal

Limpia la caché y verifica que los archivos JavaScript se cargan en la página:

Agregar archivo javascript

Pasaremos la fecha de PHP a JavaScript mediante drupalSettings. Por eso ampliamos el archivo ept_countdown.libraries.yml agregando las siguientes dependencias:

  dependencies:
    - core/once
    - core/drupalSettings

Paso 3. Conexión de un widget de campo personalizado para EPT Settings y paso de variables a JavaScript

En los módulos EPT, los valores por defecto de configuración no se pasan a JavaScript. Para habilitar esto, necesitamos sobrescribir la clase del widget de campo EptSettingsDefaultWidget:

Archivo: ept_countdown/src/Plugin/Field/FieldWidget/EptSettingsCountDownWidget.php

<?php

namespace Drupal\ept_countdown\Plugin\Field\FieldWidget;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\ept_core\Plugin\Field\FieldWidget\EptSettingsDefaultWidget;

/**
 * Plugin implementación del widget 'ept_settings_countdown'.
 *
 * @FieldWidget(
 *   id = "ept_settings_countdown",
 *   label = @Translation("Configuración EPT Countdown"),
 *   field_types = {
 *     "ept_settings"
 *   }
 * )
 */
class EptSettingsCountDownWidget extends EptSettingsDefaultWidget {

  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
    $element = parent::formElement($items, $delta, $element, $form, $form_state);

    $element['ept_settings']['pass_options_to_javascript'] = [
      '#type' => 'hidden',
      '#value' => TRUE,
    ];

    $element['ept_settings']['color_theme'] = [
      '#title' => $this->t('Tema de color'),
      '#type' => 'radios',
      '#options' => [
        'dark' => $this->t('Oscuro'),
        'light' => $this->t('Claro'),
      ],
      '#default_value' => $items[$delta]->ept_settings['color_theme'] ?? 'dark',
      '#description' => $this->t('Selecciona el tema de color para la cuenta regresiva'),
      '#weight' => '3',
    ];

    $element['ept_settings']['styles'] = [
      '#title' => $this->t('Estilos'),
      '#type' => 'radios',
      '#options' => [
        'default' => $this->t('Por defecto'),
        'new_year' => $this->t('Año nuevo'),
      ],
      '#default_value' => $items[$delta]->ept_settings['styles'] ?? 'default',
      '#description' => $this->t('Selecciona un estilo especial para la cuenta regresiva'),
      '#weight' => '4',
    ];

    $element['ept_settings']['heading_days'] = [
      '#title' => $this->t('Encabezado Días'),
      '#type' => 'textfield',
      '#default_value' => $items[$delta]->ept_settings['heading_days'] ?? $this->t('Días'),
      '#description' => $this->t('Encabezado para el contador de días'),
      '#weight' => '5',
    ];

    $element['ept_settings']['heading_hours'] = [
      '#title' => $this->t('Encabezado Horas'),
      '#type' => 'textfield',
      '#default_value' => $items[$delta]->ept_settings['heading_hours'] ?? $this->t('Horas'),
      '#description' => $this->t('Encabezado para el contador de horas'),
      '#weight' => '6',
    ];

    $element['ept_settings']['heading_minutes'] = [
      '#title' => $this->t('Encabezado Minutos'),
      '#type' => 'textfield',
      '#default_value' => $items[$delta]->ept_settings['heading_minutes'] ?? $this->t('Minutos'),
      '#description' => $this->t('Encabezado para el contador de minutos'),
      '#weight' => '7',
    ];

    $element['ept_settings']['heading_seconds'] = [
      '#title' => $this->t('Encabezado Segundos'),
      '#type' => 'textfield',
      '#default_value' => $items[$delta]->ept_settings['heading_seconds'] ?? $this->t('Segundos'),
      '#description' => $this->t('Encabezado para el contador de segundos'),
      '#weight' => '8',
    ];

    return $element;
  }

  public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
    foreach ($values as &$value) {
      $value += ['ept_settings' => []];
    }
    return $values;
  }
}

Ahora podemos seleccionar nuestro widget para el campo EPT Settings:

Ruta: /admin/structure/paragraphs_type/ept_countdown/form-display

Configuración EPT

Guarda el párrafo y revisa las variables de JavaScript mediante drupalSettings. Ahora todos los parámetros desde EPT Settings se pasan al script:

Drupal EPT

Al final de la clave paragraph-id-* está el ID único del párrafo, que ayuda a identificar el párrafo correspondiente.

El plugin FlipDown tiene un parámetro de tema (claro/oscuro). Lo pasamos usando el campo color_theme en el widget EptSettingsCountDownWidget:

$element['ept_settings']['color_theme'] = [
  '#title' => $this->t('Tema de color'),
  '#type' => 'radios',
  '#options' => [
    'dark' => $this->t('Oscuro'),
    'light' => $this->t('Claro'),
  ],
  '#default_value' => $items[$delta]->ept_settings['color_theme'] ?? 'dark',
  '#description' => $this->t('Selecciona el tema de color para la cuenta regresiva'),
  '#weight' => '3',
];

Configuración EPT Countdown

Ahora el valor del tema puede ser recuperado en JavaScript mediante drupalSettings y usado para aplicar el estilo correspondiente:

Tema oscuro

Paso 4. Inicialización del plugin FlipDown para el párrafo EPT Countdown

Ya hemos pasado las configuraciones del párrafo a JavaScript mediante drupalSettings. Ahora también necesitamos pasar el valor de la fecha desde el campo de fecha. Para ello, crea un <div> vacío en la plantilla con un atributo data-date que almacene el valor de la marca de tiempo. Usa paragraph.id() para asignar un ID único al párrafo:

Archivo: paragraph--ept-countdown--default.html.twig

  <div
    class="ept-countdown-date ept-countdown-inline-block flipdown"
    id="paragraph-id-{{ paragraph.id() }}"
    data-date="{{ content.field_ept_countdown_date[0]['#attributes']['datetime']|date('U') }}">
  </div>

EPT HTML

Si no estás seguro de dónde se almacena el valor de la fecha, usa el módulo Twig Debugger e inserta {{ dump(content.field_ept_countdown_date) }} en la plantilla.

El filtro date('U') convierte la fecha al formato de marca de tiempo Unix.

Ahora incluye el JavaScript personalizado e inicializa el plugin FlipDown:

Archivo: /ept_countdown/js/ept_countdown.js

(function ($, Drupal) {

  /**
   * Comportamiento EPT Countdown.
   */
  Drupal.behaviors.eptCountDown = {
    attach: function (context, settings) {
      var countdowns = once('ept-countdown-paragraph', '.ept-countdown-date', context);
      countdowns.forEach(function(countdown) {
        var eptOptions = drupalSettings['eptCountdown'][countdown.getAttribute('id')];
        var countdownTimestamp = parseInt(countdown.getAttribute('data-date'));
        var countdownId = countdown.getAttribute('id');

        new FlipDown(countdownTimestamp, countdownId, {
          theme: eptOptions['options']['color_theme'],
        }).start();
      });
    }
  };

})(jQuery, Drupal);

No olvides limpiar la caché para aplicar los cambios. Después de eso, el plugin FlipDown debería renderizarse correctamente en la página:

FlipDown

Paso 5. Estilización del nuevo párrafo EPT Countdown. Para un módulo generado mediante Drush, el archivo Gulp.js ya está incluido.

Como podemos ver, incluso los estilos predeterminados de FlipDown no se renderizan perfectamente—por ejemplo, en escritorio, los números aparecen en dos líneas. Pero esto se puede corregir fácilmente con estilos personalizados. Simplemente copia los archivos gulpfile.js y package.json desde el módulo EPT Counter o desde el módulo EPT Core Kickstarter.

gulpfile.js:

// Cargar plugins
var gulp = require('gulp'),
    sass = require('gulp-dart-scss'),
    postcss = require("gulp-postcss"),
    autoprefixer = require("autoprefixer"),
    cssnano = require("cssnano"),
    notify = require('gulp-notify'),
    sassUnicode = require('gulp-sass-unicode');

var config = {
  scssSrc: 'scss/*.scss',
  allScss: 'scss/**/*.scss',
  cssDest: 'css/',
  allJs: 'assets/js/**/*.js',
  allImgs: 'assets/img/**/*'
};

function style() {
  return gulp.src(config.allScss)
    .pipe(sass())
    .pipe(sassUnicode())
    .pipe(postcss([autoprefixer()]))
    .pipe(gulp.dest(config.cssDest));
}

exports.style = style;

function watch(){
  gulp.watch('scss/**/*.scss', style)
}

exports.watch = watch;

package.json:

{
  "name": "ept_styles",
  "version": "1.0.0",
  "description": "Ejecuta npm install y luego gulp watch",
  "main": "gulpfile.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "devDependencies": {
    "autoprefixer": "^10.2.5",
    "cssnano": "^5.0.2",
    "gulp": "^4.0.2",
    "gulp-dart-scss": "^1.1.0",
    "gulp-notify": "^4.0.0",
    "gulp-postcss": "^9.0.0",
    "gulp-sass-unicode": "^1.0.5",
    "gulp-sourcemaps": "^3.0.0"
  },
  "dependencies": {
    "cucumber": "*",
    "postcss": "^8.2.13"
  }
}

El archivo package-lock.json se generará automáticamente después de ejecutar:

npm install

Luego puedes iniciar la tarea de Gulp con:

gulp watch

Ahora, añade un archivo SCSS:

/ept_countdown/scss/flipdown.scss

.flipdown {
  width: 580px;
}

El archivo flipdown.css se compilará automáticamente a partir de flipdown.scss. Inclúyelo en ept_countdown.libraries.yml:

ept_countdown:
  css:
    component:
      /libraries/flipdown/dist/flipdown.min.css: { minified: true }
      css/flipdown.css: {}

Limpia la caché y verifica el resultado:

EBT countdown

¡La visualización ha mejorado significativamente!

¿Puedo usar CSS plano en lugar de compilación SCSS?

Sí, puedes. Pero la mayoría de los desarrolladores prefieren escribir SCSS porque es más conveniente y escalable.

Paso 6. Ampliación del formulario de configuración con parámetros adicionales del plugin FlipDown

El plugin FlipDown admite los parámetros theme y headings, que podemos utilizar para personalizar la visualización. Ya hemos creado un widget de campo personalizado EptSettingsCountDownWidget, y ahora añadiremos los campos correspondientes.

Archivo: /ept_countdown/src/Plugin/Field/FieldWidget/EptSettingsCountDownWidget.php

public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
  $element = parent::formElement($items, $delta, $element, $form, $form_state);

  $element['ept_settings']['pass_options_to_javascript'] = [
    '#type' => 'hidden',
    '#value' => TRUE,
  ];

  $element['ept_settings']['color_theme'] = [
    '#title' => $this->t('Tema de color'),
    '#type' => 'radios',
    '#options' => ['dark' => $this->t('Oscuro'), 'light' => $this->t('Claro')],
    '#default_value' => $items[$delta]->ept_settings['color_theme'] ?? 'dark',
    '#description' => $this->t('Selecciona el tema de color para la cuenta regresiva'),
    '#weight' => '3',
  ];

  $element['ept_settings']['styles'] = [
    '#title' => $this->t('Estilos'),
    '#type' => 'radios',
    '#options' => ['default' => $this->t('Por defecto'), 'new_year' => $this->t('Año nuevo')],
    '#default_value' => $items[$delta]->ept_settings['styles'] ?? 'default',
    '#description' => $this->t('Selecciona un estilo especial para la cuenta regresiva'),
    '#weight' => '4',
  ];

  $element['ept_settings']['heading_days'] = [
    '#title' => $this->t('Encabezado Días'),
    '#type' => 'textfield',
    '#default_value' => $items[$delta]->ept_settings['heading_days'] ?? $this->t('Días'),
    '#description' => $this->t('Encabezado para el contador de días'),
    '#weight' => '5',
  ];

  $element['ept_settings']['heading_hours'] = [
    '#title' => $this->t('Encabezado Horas'),
    '#type' => 'textfield',
    '#default_value' => $items[$delta]->ept_settings['heading_hours'] ?? $this->t('Horas'),
    '#description' => $this->t('Encabezado para el contador de horas'),
    '#weight' => '6',
  ];

  $element['ept_settings']['heading_minutes'] = [
    '#title' => $this->t('Encabezado Minutos'),
    '#type' => 'textfield',
    '#default_value' => $items[$delta]->ept_settings['heading_minutes'] ?? $this->t('Minutos'),
    '#description' => $this->t('Encabezado para el contador de minutos'),
    '#weight' => '7',
  ];

  $element['ept_settings']['heading_seconds'] = [
    '#title' => $this->t('Encabezado Segundos'),
    '#type' => 'textfield',
    '#default_value' => $items[$delta]->ept_settings['heading_seconds'] ?? $this->t('Segundos'),
    '#description' => $this->t('Encabezado para el contador de segundos'),
    '#weight' => '8',
  ];

  return $element;
}

Ahora podemos usar los encabezados y el tema en la plantilla. El ID del elemento sigue el patrón paragraph-id-{{ paragraph.id() }}, lo que nos permite obtener datos desde drupalSettings:

new FlipDown(countdownTimestamp, countdownId, {
  theme: eptOptions['options']['color_theme'],
  headings: [
    eptOptions['options']['heading_days'],
    eptOptions['options']['heading_hours'],
    eptOptions['options']['heading_minutes'],
    eptOptions['options']['heading_seconds'],
  ],
}).start();

Adicionalmente, usamos el valor de styles de la configuración para asignar estilos dinámicamente en la plantilla:

{%
  set classes = [
    'paragraph',
    'ept-paragraph',
    'ept-paragraph-countdown',
    'paragraph--type--' ~ paragraph.bundle|clean_class,
    'ept-paragraph--type--' ~ paragraph.bundle|clean_class,
    view_mode ? 'paragraph--view-mode--' ~ view_mode|clean_class,
    not paragraph.isPublished() ? 'paragraph--unpublished',
    'paragraph-id-' ~ paragraph.id(),
    content.field_ept_settings['#object'].field_ept_settings.ept_settings.styles,
    content.field_ept_settings['#object'].field_ept_settings.ept_settings.color_theme,
  ]
%}

Adjunta los estilos new_year condicionalmente si se seleccionó el estilo correspondiente:

{% if content.field_ept_settings['#object'].field_ept_settings.ept_settings.styles == 'new_year' %}
  {{ attach_library('ept_countdown/new_year') }}
{% endif %}

ept_countdown.libraries.yml:

new_year:
  css:
    component:
      css/new-year.css: {}

/ept_countdown/scss/new-year.scss:

.ept-paragraph-countdown.new_year {
  background: url(../img/snowflakes.webp) center center repeat;
}

Resultado:

Bloque EBT Año Nuevo

Puedes añadir cualquier número de estilos personalizados para módulos EPT nuevos o existentes. También puedes proponer tus estilos creando una incidencia en Drupal.org:

https://www.drupal.org/project/issues/ept_core

Paso 7. Exportación de configuraciones para párrafos y campos EPT

Hemos finalizado la incorporación de funcionalidades a EPT Countdown. Ahora es momento de exportar las configuraciones y preparar el módulo para su publicación en Drupal.org.

Todas las configuraciones relacionadas con el párrafo EPT Countdown deben copiarse a la carpeta /ept_countdown/config/install.

Si el módulo fue generado usando Drush, deberías volver a exportar las configuraciones para asegurar que todas las configuraciones del tipo de párrafo y campos estén actualizadas.

Después de esto, puedes habilitar el módulo en la página Extender/admin/modules. Todas las configuraciones de párrafo y campos de EPT Countdown se instalarán automáticamente desde /config/install:

Configuraciones del módulo EBT

No es necesario incluir archivos de configuración language.*, ya que el módulo Language puede estar desactivado en algunos sitios.

Normalmente copio todos los archivos YAML necesarios y me aseguro de colocarlos bajo config/install:

Copia de configuraciones

Antes de hacer commit, asegúrate de eliminar los campos uuid y hashes de los archivos YAML:

Eliminar uuid

Si tu módulo depende de otros módulos de Drupal (por ejemplo, datetime), asegúrate de declararlos como dependencias en el archivo .info.yml:

Dependencias en Drupal

/ept_countdown/ept_countdown.info.yml:

dependencies:
  - drupal:datetime

Tu módulo ahora está listo para ser subido y publicado en Drupal.org.

Paso 8. Despliegue en Drupal.org y pruebas

Ya hemos creado un nuevo proyecto en Drupal.org:

https://www.drupal.org/project/ept_countdown

La rama principal seleccionada es 1.4.x, para mantener coherencia con otros módulos del ecosistema EPT:

Módulo Drupal EBT

Todos los lanzamientos comenzarán ahora desde la versión 1.4.0:

git tag 1.4.0
git push origin 1.4.0

También puedes crear versiones preliminares como -alpha o -beta antes de publicar la versión estable 1.4.0.

Debes esperar 10 días después de crear el proyecto para que el módulo pueda ser incluido en el programa de Cobertura de Avisos de Seguridad (Security Advisory Coverage):

EBT Countdown

Ahora puedes probar el nuevo módulo en diferentes tipos de contenido, verificar el comportamiento de FlipDown, configuraciones de tema y encabezados. Si es necesario, reporta errores y publica parches.

Paso 9. Adición del archivo README.md

Si generaste el módulo EPT usando Drush, el archivo README.md ya debería haberse creado automáticamente.

En cualquier caso, no olvides incluir un archivo README.md en tu módulo. Este es un archivo importante que contiene la descripción del módulo, los requisitos, los pasos de instalación y las instrucciones de uso. Puedes ver un ejemplo en otro módulo EPT:

https://www.drupal.org/project/ept_slideshow

¡Gracias por usar los módulos EPT! Siempre puedes hacer preguntas o compartir ideas: