DEV Community

Jim Frenette
Jim Frenette

Posted on • Edited on • Originally published at jimfrenette.com

Drupal 8 Custom Block Module Dev

For those ready to move beyond a simple "Hello World" module, this post documents building a Drupal 8 module with a Giphy search form in a custom block. The form uses jQuery to request data from the Giphy API and display the results.

Drupal 8 module to demonstrate custom block creation with the following features:

  • configuration data that is passed into the modules js library
  • public API search using core jQuery functions
  • twig template for a front end Giphy search form
Source Code

Module Folder

To get started, create a folder for the module in either /modules/custom/ or /sites/all/modules/. The name of the module folder is typically the same as the name given to the module. In the case of this particular module, giphys is an appropriate name. For example:

# context is drupal project root cd modules mkdir custom mkdir custom/giphys 

Module Info File

An info.yml file is needed to store module metadata. Since the module machine name is giphys, the file will be named giphys.info.yml

# create the giphys.info.yml file cd custom/giphys touch giphys.info.yml 

Here are the metadata contents of this file. Included is data to inform Drupal of the core compatibility, module dependencies and a description for the administration portal interface.

giphys.info.yml
name: Giphys type: module description: 'Giphys is a Giphy search block' core: 8.x package: Other dependencies: - block 

After saving giphys.info.yml, in Drupal, select the Extend menu, e.g., http://drupal.docker.localhost:8000/admin/modules. Giphys should be listed under Other:

Extend | Giphys

Module File

The giphys.module file is the entrypoint used to define help and theme hook functions that return respective data and paths. .module files should only contain functions that implement hooks.

# create the giphys.module file touch giphys.module 
giphys.module
<?php /** * @file * Module file for giphys_module. */ use Drupal\Core\Routing\RouteMatchInterface; /** * Implements hook_help(). * * @see https://www.drupal.org/documentation/help-text-standards * * @see hook_help() */ function giphys_help($route_name, RouteMatchInterface $route_match) { switch ($route_name) { case 'help.page.giphys': // Help text for the admin section, using the module name in the path. return t("This is help text created in giphys implementation of hook_help()."); } } function giphys_theme($existing, $type, $theme, $path) { return [ 'giphys' => [ 'variables' => [ 'url' => 'http://example.com', 'secret' => NULL ], ], ]; } 

Twig Template

Note that Drupal 8 currently uses Twig version 1.x, and Drupal 8.4 is slated to use Twig version 2.x. Twig 2 also requires PHP 7.

# create the templates/giphys.html.twig file mkdir templates touch templates/giphys.html.twig 
giphys.html.twig
<div> <form id="giphys-search" accept-charset="UTF-8"> <label for="giphys-search-text" class="visually-hidden">Search</label> <input id="giphys-search-text" class="required" title="Enter the terms you wish to search for." type="search" value="" size="15" maxlength="128" required="required" aria-required="true" /> <input class="search-form__submit button js-form-submit form-submit" type="submit" value="Search" /> </form> <ul class="giphys-list"></ul> </div> 

Module Libraries

CSS and JavaScript for the module is defined in a libraries YAML data file. The CSS and JavaScript assets are loaded in the order they are listed. Additionally, core jQuery is required by the module and is listed as a module dependency to ensure that it gets loaded.

Create the giphys.libraries.yml in the root of the giphys folder together with the other data files.

# create the giphys.libraries.yml file touch giphys.libraries.yml 
giphys.libraries.yml
giphys: version: 1.x css: theme: css/giphys.css: {} js: js/giphys.js: {} dependencies: - core/jquery 

CSS

The CSS for our module is very simple with only a few tweaks to display the giphy API search results list as tiles. Create a new css folder and the giphys.css file as shown.

# create the css/giphys.css file mkdir css touch css/giphys.css 
giphys.css
ul.giphys-list { list-style: none; padding: 0; margin: 0; } ul.giphys-list li { margin-right: 5px; display: inline-block; } 

JavaScript

This file uses the drupalSettings object to get the Giphys module block configuration data. This data is used to make the Giphy API request when a user enters a search term. The results are parsed into html elements and injected into the unordered list element output by the twig template.

# create the js/giphys.js file mkdir js touch js/giphys.js 
giphys.js
console.log(drupalSettings.giphys); (function ($) { var $giphysList, giphysEndpoint, giphysSearchTerm; giphysEndpoint = drupalSettings.giphys.url + '?api_key=' + drupalSettings.giphys.secret; $giphysList = $('ul.giphys-list'); $('#giphys-search').submit( function(e) { e.preventDefault(); $giphysList.empty(); giphysSearchTerm = $('#giphys-search-text').val(); $.getJSON(giphysEndpoint + '&q=' + giphysSearchTerm).done(function(data) { if (data) { var $giphysListItem, giphysData = data.data, len = giphysData.length; for(var i = 0; i < len; i++) { $giphysListItem = '<li><img src="'+ giphysData[i].images.fixed_height_small.url +'" /></li>'; $giphysList.append($giphysListItem); } } }); }); })(jQuery); 

Module PHP

The GiphysBlock.php uses an instance of the block plugin to define a custom block. Also contained in the GiphysBlock class are functions that add a form to the block configuration for setting the API secret, URL and default search term.

The build function attaches the block configuration values to the drupalSettings object for the front end code to use.

# create the src/Plugin/Block/GiphysBlock.php file mkdir src mkdir src/Plugin mkdir src/Plugin/Block touch src/Plugin/Block/GiphysBlock.php 
GiphysBlock.php
<?php namespace Drupal\giphys\Plugin\Block; use Drupal\Core\Block\BlockBase; use Drupal\Core\Form\FormStateInterface; /** * Defines a Giphys block block type. * * @Block( * id = "giphys_block", * admin_label = @Translation("Giphys block"), * category = @Translation("Giphys"), * ) */ class GiphysBlock extends BlockBase { /** * {@inheritdoc} */ public function blockForm($form, FormStateInterface $form_state) { $config = $this->getConfiguration(); $form['url'] = [ '#type' => 'textfield', '#title' => $this->t('url'), '#default_value' => 'http://api.giphy.com/v1/gifs/search', '#required' => TRUE, '#description' => $this->t('api url'), ]; $form['secret'] = [ '#type' => 'textfield', '#title' => $this->t('secret'), '#default_value' => 'dc6zaTOxFJmzC', '#required' => TRUE, '#description' => $this->t('api key'), ]; $form['term'] = [ '#type' => 'textfield', '#title' => $this->t('term'), '#default_value' => 'trump frog', '#required' => FALSE, '#description' => $this->t('default search query term or phrase'), ]; return $form; } /** * {@inheritdoc} */ public function blockSubmit($form, FormStateInterface $form_state) { $this->setConfigurationValue('url', $form_state->getValue('url')); $this->setConfigurationValue('secret', $form_state->getValue('secret')); $this->setConfigurationValue('term', $form_state->getValue('term')); } /** * {@inheritdoc} */ public function build() { $config = $this->getConfiguration(); return array( '#theme' => 'giphys', '#attached' => array( 'drupalSettings' => array( 'giphys' => array( 'url' => $config['url'], 'secret' => $config['secret'], 'term' => $config['term'] ) ), 'library' => array( 'giphys/giphys', ), ), ); } } 

Here is what the Giphys block looks like placed in the content area with search results shown.

Giphys block placed

Source Code

Originally published at jimfrenette.com/2017/08/drupal-8-custom-block-module-dev


Resources

Top comments (0)