Extra Block Types (EBT) - New Layout Builder experience❗

Extra Block Types (EBT) - styled, customizable block types: Slideshows, Tabs, Cards, Accordions and many others. Built-in settings for background, DOM Box, javascript plugins. Experience the future of layout building today.

Demo EBT modules Download EBT modules

❗Extra Paragraph Types (EPT) - New Paragraphs experience

Extra Paragraph Types (EPT) - analogical paragraph based set of modules.

Demo EPT modules Download EPT modules

Scroll

Создание новых модулей EPT

20/04/2025, by Ivan

Самый простой способ создать новый модуль EPT — это использовать команду Drush (для Drush 12+). Чтобы воспользоваться этой командой, необходимо включить модуль EPT Core Starterkit:

EPT Starterkit

После этого станет доступен генератор модулей EPT:

drush generate ept:module

Начинайте машинное имя с префикса ept_*, это требуется для корректной работы всех модулей EPT.

EPT module generator

Вы также можете использовать EPT Starterkit из папки модулей EPT Core. Просто переименуйте все вхождения ept_starterkit в файлах, заменив их на машинное имя вашего нового модуля EPT.

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

Или скопируйте модуль EPT Text и замените в нём машинное имя.

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

Потому что это самый простой модуль EPT, и он содержит все базовые настройки EPT.

Создание модуля EPT шаг за шагом

(Некоторые скриншоты могут быть для модуля обратного отсчета EBT)

Скопируйте существующий модуль EPT Text или модуль EPT Kickstarter в качестве шаблона, либо используйте команду drush generate ept:module.

Модуль EPT Text содержит следующие папки:
/ept_text/config/install — содержит конфигурации для типа параграфа EPT Text и экземпляров полей. Другие модули EPT могут содержать конфигурации для типов параграфов и хранилищ полей.
/ept_text/templates — здесь находится шаблон paragraph--ept-text--default.html.twig для параграфа.
/ept_text/tests — здесь находятся тесты для модулей EPT, сейчас только один тест на установку модуля.

И другие стандартные файлы модуля Drupal: composer.json, ept_text.info.yml, readme.md. Подробнее о создании пользовательских модулей Drupal можно прочитать в официальной документации:

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

Я создам новый модуль EPT Countdown, который будет использовать следующий JavaScript-плагин — FlipDown:

https://github.com/PButcher/flipdown

FlipCount.js

Сделайте форк репозитория на GitHub и отправьте его в Packagist

Все сторонние библиотеки должны быть форкнуты и размещены на Packagist, например:

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

из:

https://github.com/levmyshkin/flexslider

Затем Composer сможет загружать их как обычные библиотеки с Packagist. Эти сторонние библиотеки должны содержать поле "type": "drupal-library" в composer.json, и тогда они будут загружаться в папку /libraries по умолчанию:
https://github.com/levmyshkin/flexslider/blob/master/composer.json

EBT library

Давайте форкнем репозиторий FlipDown на GitHub.

Обычно не принято форкать репозитории вместо использования оригинальных источников. Однако я считаю, что так проще использовать модули EPT без необходимости ручного редактирования composer.json. Представьте, насколько сложно новичку установить composer, вручную изменить composer.json и правильно указать ссылку на внешний репозиторий. Наличие своей библиотеки на Packagist упрощает установку. Поэтому лучше размещать все сторонние библиотеки на Packagist.

fork git repository

На странице форка репозитория можно переименовать его. Название должно быть простым, без заглавных букв и специальных символов. Допустимы дефисы (-) и подчёркивания (_).

Rename repository

Теперь у нас есть новый репозиторий:

https://github.com/levmyshkin/flipdown

Добавим файл composer.json с типом "drupal-library":

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

Файл composer.json доступен по ссылке:

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

Если проверить текущие теги в репозитории, они будут отсутствовать:

git tag

Git tags

Обычно я ориентируюсь на версию исходной библиотеки. Если последняя версия была 1.4.6, то я увеличиваю минорную версию до 1.4.7. В случае FlipDown не было ни одного тега, поэтому я создал версию 1.0.0:

git tag 1.0.0
git push origin 1.0.0

Тег обязателен, так как он содержит composer.json с типом "library".

Почему нельзя просто скопировать JS-библиотеку внутрь модуля?

Копировать можно только библиотеки с лицензией GPL. Обычно JavaScript-библиотеки используют лицензию MIT. Технически можно, но по правилам Drupal.org это запрещено:
https://www.drupal.org/about/licensing

Теперь опубликуем библиотеку FlipDown на Packagist:

https://packagist.org/packages/submit

Submit new library on packagist.org

Если вы забыли добавить composer.json с "type": "drupal-library" до публикации — не страшно. Просто добавьте файл и создайте новый тег, Packagist автоматически подтянет изменения.

Вот страница библиотеки на Packagist:

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

Packagist library

Убедитесь, что на странице библиотеки указан тип drupal-library.

Теперь вернёмся к нашим Drupal-файлам и скопируем папку ept_text, я назову новый модуль ept_countdown:

EPT Countdown

Нужно выполнить следующие шаги:

  • Удалить конфигурации в /config/install — мы экспортируем новые позже.
  • Заменить все вхождения ept_text на ept_countdown.
  • Переименовать файлы, заменив "text" на "countdown".
  • Обновить описания модуля в файлах ept_countdown.info.yml и README.md.

Я буду фиксировать каждый шаг отдельно в git, чтобы вы могли отслеживать изменения пошагово:

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

Теперь у нас есть шаблон для нашего модуля, и мы можем отправить изменения на Drupal.org.

Создайте проект модуля на Drupal.org

Давайте перейдём на сайт drupal.org на страницу добавления проекта:

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

Drupal.org add content

Нам нужно добавить проект типа Module:

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

Название: Extra Paragraph Types (EPT): Countdown
Тип проекта: Full project
Короткое имя: ept_countdown
Статус поддержки: Активно поддерживается
Статус разработки: В активной разработке
Категории модуля: Content, Content Display
Экосистема: Extra Paragraph Types (EPT): Core

Create new drupal project

В поле Description я обычно вставляю полный список доступных модулей EPT (см. Markdown-пример выше).

Теперь у нас есть страница проекта модуля на Drupal.org:
https://www.drupal.org/project/ept_countdown

На вкладке Version Control вы можете найти инструкции, как добавить удалённый репозиторий в ваш локальный git-проект:

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

Drupal project version control

После начального коммита вам следует создать новую ветку в соответствии с основной версией других модулей EPT — сейчас это 1.4.x.

Теперь мы можем приступить к добавлению новой функциональности в наш модуль. Процесс аналогичен разработке пользовательского модуля: мы создадим тип параграфа, добавим поля, подключим CSS/JS ресурсы.

Начало разработки функциональности EPT Countdown

Шаг 1. Создание типа параграфа EPT Countdown. Просто установите модуль, если вы сгенерировали его с помощью Drush.

Просто установите модуль, если вы сгенерировали его с помощью Drush.

Прежде всего, нужно создать новый тип параграфа EPT Countdown:

/admin/structure/paragraphs_type/add

Add EPT Countdown paragraph type

Обязательно, чтобы машинное имя начиналось с ept_. Обычно я начинаю имя параграфа с EPT — тогда машинное имя будет автоматически сформировано правильно. Нужно ли, чтобы машинное имя соответствовало названию модуля? Да, это желательно для консистентности и исключения конфликтов с другими модулями EPT. Это также важно для переопределения шаблонов в модулях вместо темы — см. функцию ept_core_theme_registry_alter() в модуле ept_core.

Теперь добавим поле EPT Settings: field_ept_settings — оно обязательно для всех EPT модулей:

Add EPT Settings field

EPT Settings — это общее поле из модуля EPT Core, оно предоставляет DOM Box, настройки фона, отступов и ширины.

Так как нам нужно отсчитать время до даты, добавим поле даты/времени:

Add Date field

Я добавил префикс ept_ в машинное имя, но это не обязательно. Можно назвать, например, field_countdown_date. У нас также есть поля body и title по умолчанию — этого достаточно для параграфа countdown.

Обычно для EPT модулей мы используем горизонтальные вкладки на форме редактирования:

Horizontal tabs

Это не обязательно, но удобно разделять контент и настройки, особенно когда настроек много.

Родительская группа должна быть вкладками (Tabs) с направлением Horizontal и параметром Width Breakpoint = 120 (или любым другим маленьким значением):

Tabs settings

Теперь у нас есть тип параграфа, включим модуль EPT Countdown, чтобы применились шаблоны:

/admin/modules

Enable EPT Countdown

Разрешите использование параграфа EPT Countdown для нужного типа материала с полем параграфов:

Create paragraph EPT Countdown

Что мы получаем на странице:

EPT Countdown

Шаг 2. Подключение сторонних библиотек в модули EPT

Теперь мы можем подключить стороннюю библиотеку. У нас уже есть библиотека levmyshkin/flipdown в composer.json, но так как модуль у нас кастомный, необходимо установить библиотеку вручную через Composer:

composer require levmyshkin/flipdown

Библиотека будет автоматически установлена в папку /libraries:

Install flipdown

Теперь создадим файл ept_countdown.libraries.yml и подключим туда CSS/JS библиотеки FlipDown, а также собственный JS-файл ept_flipdown/js/ept_countdown.js, в котором позже будет инициализирован плагин FlipDown:

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

Для файлов в папке /libraries мы используем абсолютные пути с начальным слешем.

js/ept_countdown.js:

(function ($, Drupal) {

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

    }
  };

})(jQuery, Drupal);

Также мы должны подключить библиотеку ept_countdown в шаблонах параграфов. Не забудьте, что у нас два шаблона:

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

Drupal templates

Очистите кэш и проверьте, что JavaScript-файлы загружаются на странице:

Add javascript file

Мы передадим дату из PHP в JavaScript через drupalSettings. Поэтому мы расширили файл ept_countdown.libraries.yml, добавив зависимости:

  dependencies:
    - core/once
    - core/drupalSettings

Шаг 3. Подключение собственного виджета поля для EPT Settings и передача переменных в JavaScript

В модулях EPT настройки по умолчанию не передаются в JavaScript. Чтобы это сделать, нужно переопределить класс виджета поля EptSettingsDefaultWidget:

Файл: 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 implementation of the 'ept_settings_countdown' widget.
 *
 * @FieldWidget(
 *   id = "ept_settings_countdown",
 *   label = @Translation("EPT Countdown settings"),
 *   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('Color theme'),
      '#type' => 'radios',
      '#options' => [
        'dark' => $this->t('Dark'),
        'light' => $this->t('Light'),
      ],
      '#default_value' => $items[$delta]->ept_settings['color_theme'] ?? 'dark',
      '#description' => $this->t('Select color theme for countdown'),
      '#weight' => '3',
    ];

    $element['ept_settings']['styles'] = [
      '#title' => $this->t('Styles'),
      '#type' => 'radios',
      '#options' => [
        'default' => $this->t('Default'),
        'new_year' => $this->t('New Year'),
      ],
      '#default_value' => $items[$delta]->ept_settings['styles'] ?? 'default',
      '#description' => $this->t('Select special style for countdown'),
      '#weight' => '4',
    ];

    $element['ept_settings']['heading_days'] = [
      '#title' => $this->t('Heading Days'),
      '#type' => 'textfield',
      '#default_value' => $items[$delta]->ept_settings['heading_days'] ?? $this->t('Days'),
      '#description' => $this->t('Header for Days counter'),
      '#weight' => '5',
    ];

    $element['ept_settings']['heading_hours'] = [
      '#title' => $this->t('Heading Hours'),
      '#type' => 'textfield',
      '#default_value' => $items[$delta]->ept_settings['heading_hours'] ?? $this->t('Hours'),
      '#description' => $this->t('Header for Hours counter'),
      '#weight' => '6',
    ];

    $element['ept_settings']['heading_minutes'] = [
      '#title' => $this->t('Heading Minutes'),
      '#type' => 'textfield',
      '#default_value' => $items[$delta]->ept_settings['heading_minutes'] ?? $this->t('Minutes'),
      '#description' => $this->t('Header for Minutes counter'),
      '#weight' => '7',
    ];

    $element['ept_settings']['heading_seconds'] = [
      '#title' => $this->t('Heading Seconds'),
      '#type' => 'textfield',
      '#default_value' => $items[$delta]->ept_settings['heading_seconds'] ?? $this->t('Seconds'),
      '#description' => $this->t('Header for Seconds counter'),
      '#weight' => '8',
    ];

    return $element;
  }

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

Теперь мы можем выбрать наш виджет для поля EPT Settings:

Путь: /admin/structure/paragraphs_type/ept_countdown/form-display

EPT Settings

Сохраняем параграф и проверяем переменные JavaScript через drupalSettings. Теперь все параметры из EPT Settings будут передаваться в скрипт:

Drupal EPT

В конце ключа paragraph-id-* — уникальный ID параграфа, по которому можно точно определить, к какому параграфу относятся данные.

У плагина FlipDown есть параметр темы (светлая/тёмная). Мы передаём его с помощью поля color_theme в виджете EptSettingsCountDownWidget:

$element['ept_settings']['color_theme'] = [
  '#title' => $this->t('Color theme'),
  '#type' => 'radios',
  '#options' => [
    'dark' => $this->t('Dark'),
    'light' => $this->t('Light'),
  ],
  '#default_value' => $items[$delta]->ept_settings['color_theme'] ?? 'dark',
  '#description' => $this->t('Select color theme for countdown'),
  '#weight' => '3',
];

EPT Countdown settings

Теперь можно получить значение темы в JavaScript через drupalSettings и отобразить нужный стиль:

Dark theme

Шаг 4. Инициализация плагина FlipDown для параграфа EPT Countdown

Мы уже передали настройки параграфа в JavaScript через drupalSettings, теперь необходимо также передать значение даты из поля Date. Для этого в шаблоне создадим пустой <div> с атрибутом data-date, в котором будет храниться значение даты в формате timestamp. Уникальный ID параграфа задаём через paragraph.id():

Файл: 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

Если вы не уверены, где именно хранится значение даты, используйте модуль Twig Debugger и добавьте {{ dump(content.field_ept_countdown_date) }} в шаблон.

Фильтр date('U') преобразует дату в формат Unix timestamp.

Теперь подключим собственный JavaScript и инициализируем плагин FlipDown:

Файл: /ept_countdown/js/ept_countdown.js

(function ($, Drupal) {

  /**
   * EPT Countdown behavior.
   */
  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);

Не забудьте очистить кэш, чтобы увидеть изменения. После этого плагин FlipDown должен корректно отображаться на странице:

FlipDown

Шаг 5. Стилизация нового параграфа EPT Countdown. Для модуля, сгенерированного через Drush, уже подключён файл Gulp.js.

Как видно, даже стандартные стили FlipDown отображаются неидеально — например, на десктопе числа выводятся в две строки. Но мы легко можем это исправить с помощью кастомных стилей. Просто скопируйте файлы gulpfile.js и package.json из модуля EPT Counter или EPT Core Kickstarter модуля.

gulpfile.js:

// Загрузка плагинов
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": "Run npm install and then 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"
  }
}

Файл package-lock.json будет создан автоматически после команды:

npm install

Затем вы можете запустить задачу Gulp с помощью:

gulp watch

Теперь добавим SCSS файл:

/ept_countdown/scss/flipdown.scss

.flipdown {
  width: 580px;
}

Файл flipdown.css будет автоматически скомпилирован из flipdown.scss. Подключаем его в ept_countdown.libraries.yml:

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

Очистите кэш и проверьте результат:

EBT countdown

Теперь отображение стало заметно лучше!

Можно ли использовать обычный CSS без SCSS-компиляции?

Да, можно. Но большинство разработчиков предпочитает писать SCSS, поскольку это удобнее и масштабируемо.

Шаг 6. Расширение формы настроек дополнительными параметрами плагина FlipDown

Плагин FlipDown поддерживает параметры theme и headings, которые мы можем использовать для настройки отображения. Мы уже создали собственный виджет поля EptSettingsCountDownWidget и теперь добавим туда соответствующие поля.

Файл: /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('Color theme'),
    '#type' => 'radios',
    '#options' => ['dark' => $this->t('Dark'), 'light' => $this->t('Light')],
    '#default_value' => $items[$delta]->ept_settings['color_theme'] ?? 'dark',
    '#description' => $this->t('Select color theme for countdown'),
    '#weight' => '3',
  ];

  $element['ept_settings']['styles'] = [
    '#title' => $this->t('Styles'),
    '#type' => 'radios',
    '#options' => ['default' => $this->t('Default'), 'new_year' => $this->t('New Year')],
    '#default_value' => $items[$delta]->ept_settings['styles'] ?? 'default',
    '#description' => $this->t('Select special style for countdown'),
    '#weight' => '4',
  ];

  $element['ept_settings']['heading_days'] = [
    '#title' => $this->t('Heading Days'),
    '#type' => 'textfield',
    '#default_value' => $items[$delta]->ept_settings['heading_days'] ?? $this->t('Days'),
    '#description' => $this->t('Header for Days counter'),
    '#weight' => '5',
  ];

  $element['ept_settings']['heading_hours'] = [
    '#title' => $this->t('Heading Hours'),
    '#type' => 'textfield',
    '#default_value' => $items[$delta]->ept_settings['heading_hours'] ?? $this->t('Hours'),
    '#description' => $this->t('Header for Hours counter'),
    '#weight' => '6',
  ];

  $element['ept_settings']['heading_minutes'] = [
    '#title' => $this->t('Heading Minutes'),
    '#type' => 'textfield',
    '#default_value' => $items[$delta]->ept_settings['heading_minutes'] ?? $this->t('Minutes'),
    '#description' => $this->t('Header for Minutes counter'),
    '#weight' => '7',
  ];

  $element['ept_settings']['heading_seconds'] = [
    '#title' => $this->t('Heading Seconds'),
    '#type' => 'textfield',
    '#default_value' => $items[$delta]->ept_settings['heading_seconds'] ?? $this->t('Seconds'),
    '#description' => $this->t('Header for Seconds counter'),
    '#weight' => '8',
  ];

  return $element;
}

Теперь мы можем использовать заголовки и тему в шаблоне. ID элемента имеет шаблон paragraph-id-{{ paragraph.id() }}, и именно по нему можно получить данные из 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();

Дополнительно мы используем значение styles из настроек, чтобы динамически подключать стили в шаблоне:

{%
  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,
  ]
%}

Подключаем стили new_year, если выбран соответствующий стиль:

{% 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;
}

Результат:

New Year EBT block

Вы можете добавить любое количество пользовательских стилей для новых или существующих EPT модулей. Также можно предлагать свои стили, создав issue на Drupal.org:

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

Шаг 7. Экспорт конфигураций для параграфов и полей EPT

Мы завершили добавление функциональности в EPT Countdown, теперь пришло время экспортировать конфигурации и подготовить модуль к выкладке на Drupal.org.

Нужно скопировать все связанные с параграфом EPT Countdown конфигурации в папку /ept_countdown/config/install.

Если модуль был сгенерирован через Drush, необходимо выполнить повторный экспорт конфигураций, чтобы обновить настройки полей и самого типа параграфа.

После этого можно включить модуль на странице Extend/admin/modules. Все конфигурации параграфа EPT Countdown и полей будут установлены автоматически из /config/install:

EBT module configs

Нет необходимости добавлять файлы конфигураций language.*, так как на некоторых сайтах модуль Language может быть отключён.

Обычно я копирую все необходимые YAML-файлы и убеждаюсь, что они попали в config/install:

Copy of configs

Перед коммитом обязательно удалите uuid и hashes из YAML-файлов:

Remove uuid

Если ваш модуль использует другие модули Drupal (например, datetime), обязательно укажите их как зависимости в .info.yml:

Drupal dependencies

/ept_countdown/ept_countdown.info.yml:

dependencies:
  - drupal:datetime

Теперь ваш модуль готов к загрузке и публикации на Drupal.org.

Шаг 8. Развёртывание на Drupal.org и тестирование

Мы уже создали новый проект на Drupal.org:

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

В качестве основной ветки выбрана 1.4.x для соответствия другим модулям из экосистемы EPT:

Drupal EBT module

Все релизы теперь будут начинаться с версии 1.4.0:

git tag 1.4.0
git push origin 1.4.0

Вы также можете создавать промежуточные версии, такие как -alpha или -beta, до выхода стабильного релиза 1.4.0.

Необходимо подождать 10 дней после создания проекта, прежде чем модуль сможет быть включён в программу Security Advisory Coverage (покрытие рекомендациями по безопасности):

EBT Countdown

Теперь можно протестировать новый модуль на разных типах контента, проверить работу FlipDown, настройки темы и заголовков. При необходимости — зафиксировать баги и выпустить патчи.

Шаг 9. Добавление файла README.md

Если вы сгенерировали модуль EPT с помощью Drush, то файл README.md уже должен быть создан автоматически.

В любом случае не забудьте включить README.md в ваш модуль. Это важный файл, содержащий описание, требования, установку и рекомендации. Пример можно посмотреть в другом модуле EPT:

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

Благодарим за использование модулей EPT! Вы всегда можете задать вопрос или предложить идею: