Creating new EPT modules
Easiest way to create a new EPT module is Drush command (for Drush 12+). To use this command, you need to enable EPT Core Starterkit module:
After that generator EPT modules will be available:
drush generate ept:module
Start machine name with ept_* prefix, it's required for working all EPT modules.
You can also use EPT Starterkit in EPT Core modules folder. Just rename all ePt_starterkit in files with machine name of your new EPT module.
https://www.drupal.org/project/ept_core
Or copy EPT Text module and replace machine name there.
https://www.drupal.org/project/ept_text
Because, it's simplest EPT module and it contains all basic EPT settings.
Creating EPT module Step by Step
Creating EPT module Step by Step
(Some screenshots can be for EBT Countdown module)
Copy existing EPT Text or EPT kickstarter module as boilerplate or use drush generate ept:module command.
Copy existing EPT Text or EPT kickstarter module as boilerplate or use drush generate ept:module command.
EPT Text module contains next folders:
/ept_text/config/install - with configs for EPT Text paragraph type and field instances. Other EPT modules can contain configs for paragraph types and field storages.
/ept_text/templates - here is paragraph--ept-text--default.html.twig template for the paragraph.
/ept_text/tests - here are tests for EPT modules, now only one test for installation module.
And other regular drupal module files: composer.json, ept_text.info.yml, readme.md. You can read more about creating custom Drupal modules in official documentation:
https://www.drupal.org/docs/develop/creating-modules
I will create a new module EPT Countdown which will use this javascript plugin FlipDown:
Fork Github repository and submit it to Packagist
Fork Github repository and submit it to Packagist
All 3rd party libraries should be forked and placed on Packagist, for example:
https://packagist.org/packages/levmyshkin/flexslider
from:
https://github.com/levmyshkin/flexslider
Then Composer can download them as usual packagist libraries. These 3rd party libraries must have "type": "drupal-library", and they will be download in /libraries folder, by default:
https://github.com/levmyshkin/flexslider/blob/master/composer.json
Let's fork github repository for FlipDown.
It might be unusual to fork git repositories, instead of using source git repositories. But I believe it will be easier to use EPT modules without manipulations with main composer.json file to add external links to repositories in it. Imagine, how it's hard for newbies to install composer, update composer.json file manually and place repository source in right place. With own packagist library the process of installation is getting simple. So let's keep all 3rd party libraries on packagist.
On forking git repo page you can rename repository. You must keep it clean, without Capital letters and special chars, dash - and underscore _ are working fine.
Now we have a new git repo:
https://github.com/levmyshkin/flipdown
Then we need to add composer.json file in this repository with "type": "drupal-library":
git add composer.json
git commit -m 'Add Composer.json file'
git push origin master
Here is composer.json file:
https://github.com/levmyshkin/flipdown/blob/master/composer.json
If you check your current tags in new git repo, it will be empty:
git tag
Usually I follow version from source repo, for example if latest version of library was 1.4.6, I just increment minor version to 1.4.7. FlipDown repo didn't have any tags or releases, so I created 1.0.0 version for new repo:
git tag 1.0.0
git push origin 1.0.0
We need new tag, because it contains our new composer.json with "type": "library"
Why we can't simply copy javascript library inside module?
We can copy only libraries under GPL license, but usually javascipt libraries uses MIT license. It's possible to do technically, but it's prohibited by Drupal.org rules:
Let's submit FlipDown library on packagist.org:
https://packagist.org/packages/submit
If you submitted library and forgot to add composer.json with "type": "drupal-library", don't worry, just add composer.json file and create new tag for your git repository. This tag will be automatically pushed on packagist.
Here is packagist library page for FlipDown:
https://packagist.org/packages/levmyshkin/flipdown
Be sure that you have drupal-library type on packagist page.
Let's go back to our drupal files and copy ept_text folder, I will name new module ept_countdown:
We need to:
- remove configs in /config/install, we will export new configs later
- replace all ept_text mention with ept_countdown
- rename files to have "countdown" instead of "text"
- update texts for module description in ept_countdown.info.yml and README.md files.
I will commit each step separately in git, so you could see updates step by step:
git clone https://git.drupalcode.org/project/ept_countdown.git
Now we have boilerplate for our module and can push changes on Drupal.org.
Create module project on Drupal.org
Create module project on Drupal.org
Let's go on drupal.org site on adding project page:
https://www.drupal.org/node/add
We need to add Module project:
https://www.drupal.org/node/add/project-module
Name: Extra Paragraph Types (EPT): Countdown
Project type: Full project
Short name: ept_countdown
Maintenance status: Actively maintained
Development status: Under active development
Module categories: Content, Content Display
Ecosystem: Extra Paragraph Types (EPT): Core
In Description field I usually insert full list of available EPT modules:
# Extra Paragraph Types (EPT): Countdown
Extra Paragraph Types: Countdown module provides ability to add animated countdown
for specific date.
For a full description of the module, visit the
[project page](https://www.drupal.org/project/ept_countdown).
Submit bug reports and feature suggestions, or track changes in the
[issue queue](https://www.drupal.org/project/issues/ept_countdown).
## Table of contents
- Requirements
- Recommended modules
- Installation
- Configuration
- Troubleshooting
- FAQ
- Maintainers
## Requirements
This project requires the following items:
- [EPT Core](https://www.drupal.org/project/ept_core)
- [Paragraphs](https://www.drupal.org/project/paragraphs)
EPT Modules use Media module with Media Image type for background images.
Check Media Image type exists before install EPT Core module.
## Recommended modules
EPT modules provide ability to add different paragraphs in few clicks.
You can install separate paragraph types from this bunch of EPT modules:
- [EPT Accordion / FAQ](https://www.drupal.org/project/ept_accordion)
- [EPT Basic Button](https://www.drupal.org/project/ept_basic_button)
- [EPT Bootstrap Button](https://www.drupal.org/project/ept_bootstrap_button)
- [EPT Call to Action](https://www.drupal.org/project/ept_cta)
- [EPT Carousel](https://www.drupal.org/project/ept_carousel)
- [EPT Countdown](https://www.drupal.org/project/ept_countdown)
- [EPT Counter](https://www.drupal.org/project/ept_counter)
- [EPT Image](https://www.drupal.org/project/ept_image)
- [EPT Image Gallery](https://www.drupal.org/project/ept_image_gallery)
- [EPT Micromodal](https://www.drupal.org/project/ept_micromodal)
- [EPT Quote](https://www.drupal.org/project/ept_quote)
- [EPT Slick Slider](https://www.drupal.org/project/ept_slick_slider)
- [EPT Slideshow](https://www.drupal.org/project/ept_slideshow)
- [EPT Stats](https://www.drupal.org/project/ept_stats)
- [EPT Tabs](https://www.drupal.org/project/ept_tabs)
- [EPT Text](https://www.drupal.org/project/ept_text)
- [EPT Tiles](https://www.drupal.org/project/ept_tiles)
- [EPT Timeline](https://www.drupal.org/project/ept_timeline)
- [EPT Video](https://www.drupal.org/project/ept_video)
- [EPT Video and Image gallery](https://www.drupal.org/project/ept_video_and_image_gallery)
- [EPT Webform](https://www.drupal.org/project/ept_webform)
- [EPT Webform Popup](https://www.drupal.org/project/ept_webform_popup)
More about EPT paragraphs read on EPT Core module page:
[EPT Core](https://www.drupal.org/project/ept_core)
If you are looking for Extra Block Types, You can check out
this bunch of EBT modules:
- [EBT Accordion / FAQ](https://www.drupal.org/project/ebt_accordion)
- [EBT Basic Button](https://www.drupal.org/project/ebt_basic_button)
- [EBT Bootstrap Button](https://www.drupal.org/project/ebt_bootstrap_button)
- [EBT Call to Action](https://www.drupal.org/project/ebt_cta)
- [EBT Carousel](https://www.drupal.org/project/ebt_carousel)
- [EBT Countdown](https://www.drupal.org/project/ebt_countdown)
- [EBT Counter](https://www.drupal.org/project/ebt_counter)
- [EBT Image](https://www.drupal.org/project/ebt_image)
- [EBT Image Gallery](https://www.drupal.org/project/ebt_image_gallery)
- [EBT Micromodal](https://www.drupal.org/project/ebt_micromodal)
- [EBT Quote](https://www.drupal.org/project/ebt_quote)
- [EBT Slick Slider](https://www.drupal.org/project/ebt_slick_slider)
- [EBT Slideshow](https://www.drupal.org/project/ebt_slideshow)
- [EBT Stats](https://www.drupal.org/project/ebt_stats)
- [EBT Tabs](https://www.drupal.org/project/ebt_tabs)
- [EBT Text](https://www.drupal.org/project/ebt_text)
- [EBT Tiles](https://www.drupal.org/project/ebt_tiles)
- [EBT Timeline](https://www.drupal.org/project/ebt_timeline)
- [EBT Video](https://www.drupal.org/project/ebt_video)
- [EBT Video and Image gallery](https://www.drupal.org/project/ebt_video_and_image_gallery)
- [EBT Webform](https://www.drupal.org/project/ebt_webform)
- [EBT Webform Popup](https://www.drupal.org/project/ebt_webform_popup)
More about EBT blocks read on EBT Core module page:
[EBT Core](https://www.drupal.org/project/ebt_core)
If you want to enhance UI for adding Blocks from Layout builder try this module:
[Layout Builder Modal](https://www.drupal.org/project/layout_builder_modal)
If you want to enhance UI for adding Paragraphs try these modules:
[Paragraphs Edit](https://www.drupal.org/project/paragraphs_edit)
[Paragraphs Modal Edit](https://www.drupal.org/project/paragraphs_modal_edit)
## Installation
Install as you would normally install a contributed Drupal module. For further
information, see
[Installing Drupal Modules](https://www.drupal.org/docs/extending-drupal/installing-drupal-modules).
## Configuration
After enable this project will be available a new paragraph type called `EPT Countdown`
When you're creating this new custom paragraph, you can see that there is a new Tab
called `Settings` and there you can configure the Design options inside of
`Settings` tab
You can configure there:
- Margin;
- Border;
- Padding;
- Border Color;
- Border Style;
- Border Radius;
- Background Color;
- Background Image Style;
- Edge to Edge;
- Container Max Width.
EPT Core has configuration form with Primary/Secondary colors and
Mobile/Tablet/Desktop breakpoints in:
Administration » Configuration » Content authoring » Extra Paragraph Types (EPT)
settings
These configs will be applied to other EPT paragraphs by default.
## Troubleshooting
- If you see the error during EPT modules installation: "The EPT Carousel needs
to be created "Image" media type. (Currently using Media type Image version
Not created)"
Then you need to create Image media type:
Structure » Media types » Add media type
## FAQ
**Q: Can I use only one EPT paragraph type,
for example EPT Slideshow, without other modules?**
**A:** Yes, sure. EPT paragraph types tend to be standalone modules. You can install
only needed paragraph types.
## Maintainers
- Ivan Abramenko - [levmyshkin](https://www.drupal.org/u/levmyshkin)
- Narine Tsaturyan - [Narine_Tsaturyan](https://www.drupal.org/u/narine_tsaturyan)
Now we have Drupal module project page on Drupal.org:
https://www.drupal.org/project/ept_countdown
On Version Control tab you can see instructions how to add remote origin for you local git repository:
https://www.drupal.org/project/ept_countdown/git-instructions
After initial commit you should create a new branch to follow major version of other EPT modules, now it's 1.4.x.
Now we can start to add new functionality for our module. The process is similar with custom module development, we will create paragraph type, add fields, include css/js assets.
Start building EPT Countdown functionality
Step 1. Creating EPT Countdown paragraph type. Just install module if you generated it with Drush.
Start building EPT Countdown functionality
Step 1. Creating EPT Countdown paragraph type. Just install module if you generated it with Drush.
Just install module if you generated it with Drush.
First of all, we need to create a new paragraph type EPT Countdown:
/admin/structure/paragraphs_type/add
It's required that machine name starts from ept_, so usually I name paragraph types starts from EPT, then machine name is automatically being generated in right way. Should paragraph type machine name match to module name? Yes, it's good to have for consistancy and be sure that another EPT module didn't have the same machine name. Paragraph type machine name must start from ept_, becuase it's needed to override templates in modules instead of theme folder, see ept_core_theme_registry_alter() function in ept_core module.
Now we can add EPT settings field, it's needed for all EPT modules. We should add existing field EPT Settings: field_ept_settings:
EPT Settings is common field from EPT Core module, it provides DOM Box, background, spacing and width settings.
As we need countdown to the date, we should have timestamp date field. Let's add it too:
I added ept_ for machine-readable name, but it's not required here. It can be field_countdown_date as well. We also have default body and title field for paragraph, so it will be enough for countdown paragraph.
Usually for EPT modules we have horizontal tabs on Edit form:
It's not required, but it's good to split content and settings, because we have a lot of settings for paragraphs.
Parent field group should be Tabs with settings Direction Horizontal, and Width Breakpoint 120 (or any small number):
Now we have a paragraph type, let's enable EPT Countdown module, so templates for paragraph type will be applied:
/admin/modules
Enable EPT Countdown paragraph for your Content Type with paragraph field.
And what we have on the page:
Step 2. Include 3rd party libraries to EPT modules
Step 2. Include 3rd party libraries to EPT modules
Now we can include our 3rd party library. We have levmyshkin/flipdown library in composer.json, but we have this new module as custom module, so we need to install this library manually with composer:
composer require levmyshkin/flipdown
New library should be placed in libraries folder automatically:
Let's add ept_countdown.libraries.yml file and include there flipdown css/js and javascript file ept_flipdown/js/ept_countdown.js where later we will init flipdown plugin:
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: {}
For files in /libraries folder we use slash at the beginning, so it's absolute path.
js/ept_countdown.js:
(function ($, Drupal) {
/**
* EBT Countdown behavior.
*/
Drupal.behaviors.eptCountDown = {
attach: function (context, settings) {
};
}
})(jQuery, Drupal);
And we should include new ebt_countdown library in temlates, don't forget what we have two templates:
{{ attach_library('ept_countdown/ept_countdown') }}
Clear caches and check that your javascript files on the page:
We will pass date from PHP to javascript in drupalSettings. So we should extend our ebt_countdown.libraries.yml file with dependencies. Also we will use once() function:
dependencies:
- core/once
- core/drupalSettings
Step 3. Include own field widget for EPT Settings, pass variables to javascript
Step 3. Include own field widget for EPT Settings, pass variables to javascript
In EPT modules settings are not being passed to javascript by default. We need to override field widget class 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 {
/**
* {@inheritdoc}
*/
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;
}
/**
* {@inheritdoc}
*/
public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
foreach ($values as &$value) {
$value += ['ept_settings' => []];
}
return $values;
}
}
Now we can select this field widget for EPT Settings field:
/admin/structure/paragraphs_type/ept_countdown/form-display
Let's resave our paragraph and check drupalSettings javascript variable. Now all options from EPT Settings field will be passed in javascript:
At the end of paragraph-id-* we have Paragraph ID, so we have unique keys for all paragraphs.
FlipDown plugin has option for light/dark theme, so let's pass this setting field in our field widget 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',
];
Then we can get theme color value in javascript:
Step 4. Initialize FlipDown plugin for EPT Countdown paragraph
Step 4. Initialize FlipDown plugin for EPT Countdown paragraph
We passed variables from settings to javascript, but we need to pass also Date value from content to javascript. We will create empty div with attribute data-date="", where we will place date and time from Date field. We will use paragraph_id to define unique ID for paragraph:
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>
If you are not sure about where field data is, you can install Twig Debugger module and print content.field_ept_countdown_date on the page {{ dump(content.field_ept_countdown_date) }}:
https://www.drupal.org/project/twig_debugger
And we used date('U') twig filter to transform date to timestamp.
Now we can include custom javascript and initialize 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);
Don't forget to clear caches to see updates. After that FlipDown should be working on the page:
Step 5. Styling new EPT Countdown paragraph. Gulp.js file is included for drush generated EPT module.
Step 5. Styling new EPT Countdown paragraph. Gulp.js file is included for drush generated EPT module.
As you see even default FlipDown styles are not working great. There are two lines of numbers even on desktop. But we can easily fix it with custom styles. You can copy gulpfile.js and package.json files for compiling scss to css from EPT Counter or EPT Core Kickstarter module:
https://www.drupal.org/project/ept_counter
gulpfile.js:
// --------------------------------------------------
// Load 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 = {
// main scss files that import partials
scssSrc: 'scss/*.scss',
// all scss files in the scss directory
allScss: 'scss/**/*.scss',
// the destination directory for our css
cssDest: 'css/',
// all js files the js directory
allJs: 'assets/js/**/*.js',
// all img files
allImgs: 'assets/img/**/*'
};
// Define tasks after requiring dependencies
function style() {
return gulp.src(config.allScss)
.pipe(sass())
.pipe(sassUnicode())
.pipe(postcss([autoprefixer()]))
.pipe(gulp.dest(config.cssDest));
gulp.task('sass:watch', function () {
gulp.watch('./scss/**/*.scss', ['sass']);
});
}
// Expose the task by exporting it
// This allows you to run it from the commandline using
// $ gulp style
exports.style = style;
function watch(){
// gulp.watch takes in the location of the files to watch for changes
// and the name of the function we want to run on change
gulp.watch('scss/**/*.scss', style)
}
// Don't forget to expose the task!
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"
},
"author": "",
"license": "ISC",
"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 file will be generated after you run:
npm install
And you can start gulp task with:
gulp watch
Now we will add scss files:
/ept_countdown/scss/flipdown.scss
.flipdown {
width: 580px;
}
So flipdown.css file will be automatically generated from flipdown.scss. And we can include .css file in .libraries.yml:
ept_countdown:
css:
component:
/libraries/flipdown/dist/flipdown.min.css: { minified: true }
css/flipdown.css: { }
Let's clear cache and see results:
Now it looks better!
Can we use plain css without compiling from scss?
Yes, we can, but writing scss is more convient for the most developers.
Step 6. Extend settings form with FlipDown plugin options
Step 6. Extend settings form with FlipDown plugin options
FlipDown plugin has few options to change display:
https://github.com/PButcher/flipdown
- theme
- headings
We already created new field widget for EPT Settings EptSettingsCountDownWidget, now we will extend this form with new fields:
/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;
}
So we can use Headings for translations:
We have all EPT settings values in javascript, so I just added ID in template for easier getting right unique key.
.setAttribute('id', 'paragraph-countdown-id-' ~ paragraph.id())
Options keys have pattern the same with IDs:
/ept_core/ept_core.module:
$build['#attached']['drupalSettings'][$bundle]['paragraph-id-' . $paragraph_id] = $paragraph_options;
So we could use options from javascript drupalSettings:
/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'],
headings: [
eptOptions['options']['heading_days'],
eptOptions['options']['heading_hours'],
eptOptions['options']['heading_minutes'],
eptOptions['options']['heading_seconds'],
],
}).start();
});
}
}
})(jQuery, Drupal);
I also added $element['ept_settings']['styles'] in field widget, so we will use it in template for adding new class for entire paragraph.
{%
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,
]
%}
{% if content.field_ept_settings['#object'].field_ept_settings.ept_settings.styles == 'new_year' %}
{{ attach_library('ept_countdown/new_year') }}
{% endif %}
It will include new_year library for New Year style, but now we need to create this library.
/ept_countdown/ept_countdown.libraries.yml:
new_year:
css:
component:
css/new-year.css: { }
And here is styles for new-year paragraph:
/ept_countdown/scss/new-year.scss
/ept_countdown/css/new-year.css
.ept-paragraph-countdown.new_year {
background: url(../img/snowflakes.webp) center center repeat;
}
Here is result of adding new style:
You can add any number of styles for new or existing EPT modules. You can also suggest own styles for any EPT module, just create issue on drupal.org for it:
Step 7. Export configs for EPT paragraph types and fields
Step 7. Export configs for EPT paragraph types and fields
I think we finished with adding features to EPT Countdown, it's time to export configs and deploy changes on Drupal.org. We should copy all configs related to EPT Countdown to /ept_countdown/config/install folder.
If you generated EPT module with Drush, you need to update configs for new fields and your EPT paragraph type.
After that enable EPT module on Extend page /admin/modules. New EPT paragraph type and other settings will be installed from /config/install folder from config files:
We don't need to add language.* configs, because some drupal sites have only one language and Language module can be disabled.
Usually I copy all files and checking that I have copy in config/install folder.
Now we need to remove uuid and hashes from configs in config/install folder
As we used another Drupal modules we should include them in .info file as dependencies.
/ept_countdown/ept_countdown.info:
dependencies:
- drupal:datetime
Step 8. Deploy on Drupal.org and testing
Step 8. Deploy on Drupal.org and testing
We created new project on Drupal.org before:
https://www.drupal.org/project/ept_countdown
I will use 1.4.x branch as main branch, for consistancy with other EPT modules:
So all releases will be started from 1.4.0 versions:
git tag 1.4.0
git push origin 1.4.0
You can also create -alpha, -beta version before creating stable 1.4.0 version.
We need to wait 10 days before module can be opted into security advisory coverage.
So we can test our new module and fix bugs.
Step 9. Add README.md file
Step 9. Add README.md file
If you generated EPT module with Drush than Readme file is already there.
Don't forget to add README.md file, you can see example in other EPT modules:
https://www.drupal.org/project/ept_slideshow
Thank you for using EPT modules! Feel free to ask or suggest any ideas: