Jan 13 2019
Jan 13

the Twig file

In the previous section we created the file that defines the widget formatter used to pre-format the data before passing it on to a twig file. In this part we will create the twig file that provides the markup for the viewed content.

name_field_type.html.twig

The file should be placed in the path <my module>/templates and be given the name used for #theme in the previous section with a .twig suffix.


{{ name }}

That's all the pieces. The complete tree for your module should look like this:


name_field_type/
├── name_field_type.info.yml
├── name_field_type.module
├── src
│   └── Plugin
│       └── Field
│           ├── FieldFormatter
│           │   └── NameFormatter.php
│           ├── FieldType
│           │   └── NameItem.php
│           └── FieldWidget
│               └── NameWidget.php
└── templates
    └── name_field_type.html.twig

Enable the module either through the Extensions (/admin/modules) page of the UI or using drush

drush en name_field_type

Select a content type to add the new field type. It should appear in the field type list 

Field type list with the new field type added

When creating a new piece of content for the content type, all of the sub-fields will appear for the new field

sub fields on node form

And finally, the rendering of the parts of our field:

Rendered name

The magic is that this widget can be used on any content type, and is easily moved from site to site, since it's wrapped in a module.

Jan 11 2019
Jan 11

Drupal has everything to do with Community, the embodiment of vibrancy imbuing this Open Source project... so much so that the Community is justly touted as a factor differentiating it within the field of CMSs, and contribution to it is often used to measure a candidate's suitability for employment (a practice that makes sense on the surface but can be inherently biased).

Community is based on volunteerism, and while volunteerism is a great and noble thing with demonstrable successes, especially within the Drupal Community, there is a flip side to it: there is no accountability or surety, and that can be a large issue to the user community.

Let us consider the migration from D7 to D8. On the surface the process has come a long way, with the migration of fairly vanilla sites often being push-button. I posit that the problems, large costly and sometimes insurmountable problems, arise below that surface. One current glaring example is the Rules module, a top favorite in D7. It is still in alpha.

So, what about the multitude of sites that have a heavy investment in Rules, often as a result of their business needs being fulfilled by its use. There seems to be only a few choices for them of what to do, none of them pleasant or defensible, when looking in from the outside:

  • Remain on D7
  • Eliminate the need for the rule(s)
  • Absorb the cost of converting the rules to custom code

Certainly the fact that there is no production D8 rules module, yet, is not a matter of fault. Module migration is like the tripod of any project: it comes down to resources, time and scope. That said, in a volunteer network the availability of resources is indeterminate. 

We are now at the point of scheduling the arrival of D9 and the end-of-life of both D7 and D8, and still, there is a plethora of sites, enterprise sites, that make heavy use of Rules, or some other module not yet migrated, with a brick wall approaching and no brakes on the car.

At a minimum, I feel that mission-critical contributed modules and their migration need to be part of the release planning of a new version, rising to the level of blockers. We owe it to the clients whose use of Drupal means its success. After all, you can have "open source" music, but it means nothing if no one listens to it.

Jan 06 2019
Jan 06

We've all been there, a node form with a number of related fields, such as name or address, again and again... and again. What if you could package those fields into a widget that can be reused just by adding it to a content type. Not only can it be easily be done, but I'm going to show you how.

This tutorial will differ from most other custom field type tutorials, because we won't just be creating a field type, but the field type will be a widget with sub-fields.

Let's first take a cursory look at why you might want to use this type of field type widget, using 'name' as an example, as we will in the tutorial. When working with multiple fields, you typically have two options:

  1. Add discreet fields to the content type, such as 'First name', 'Surname' and so on
  2. Create an entity and field it, then add an entity reference to the content type

Both of these methods will work, but each has at least one drawback. With option 1, you would need to do the same thing with every content type using the same fields. With option 2, adding the entity reference doesn't necessarily provide you the rendering of its fields, nor CRUD (Create/Read/Update/Delete) services.

Fortunately, there's a third option: a custom field type that creates a bundled (compound) field. Let's create one, and I'll leave it to you to decide if it's useful to you!

The Concept

What is a compound/bundled field? It is a field that contains sub-fields. You are probably familiar with this concept if you have ever looked inside the table that contains a node's body field:



+--------------+------------------+------+-----+---------+-------+ 
| Field        | Type             | Null | Key | Default | Extra | 
+--------------+------------------+------+-----+---------+-------+ 
| bundle       | varchar(128)     | NO   | MUL |         |       | 
| deleted      | tinyint(4)       | NO   | PRI | 0       |       | 
| entity_id    | int(10) unsigned | NO   | PRI | NULL    |       | 
| revision_id  | int(10) unsigned | NO   | MUL | NULL    |       | 
| langcode     | varchar(32)      | NO   | PRI |         |       | 
| delta        | int(10) unsigned | NO   | PRI | NULL    |       | 
| body_value   | longtext         | NO   |     | NULL    |       | 
| body_summary | longtext         | YES  |     | NULL    |       | 
| body_format  | varchar(255)     | YES  | MUL | NULL    |       | 
+--------------+------------------+------+-----+---------+-------+ 

Take a look at the last three columns: body_value, body_summary and body_format. These will be familiar to you from the node form. A summary, if provided for the body text, is stored in the body_summary sub-field. The body text is stored in body_value, and the text format selected, such as Basic HTML and Full HTML, is stored in body_format.

That type of structure, in brief, is what we're aiming to create progammatically. We'll look closely at the results in our own table, later. 

Another aspect of the concept of what we'll be doing that is worth knowing, up front: we're not actually creating a field, we're creating a field type. This, too, we'll take a closer look at, later.

So, what will we be creating? A field type widget for a person's name, the sub-fields of which will be, as follows:

  • Title
  • First name
  • Middle name/initial
  • Last name
  • Maternal last name
  • Suffix

The field type is constructed as a widget, which is a technical term for thingy, as in something tangible, but in a somewhat intangible sort of way. Yup, a thingy. The widget has the following components:

  • Module files - the files that define the module scaffolding that wraps the widget plugin
  • Field Type - defines the structure of the field type and how to determine if the field using it should be considered empty 
  • Field Widget - defines the structure of the content form field(s) that will accept values for the field, as well as any custom code needed to process the input
  • Field Formatter - formats the field data to pass to the twig file
  • Twig file - the default rendering of fields using the widget

We will create each of these in this five-part tutorial series. Let's get started!

the Module Files

This widget is made available to Drupal as a plugin wrapped in a module. Let's start by creating the files that are typical for a module.

name_field_type.info.yml


name: 'Name'
description: 'Provides a bundled name field.' 
type: module
core: 8.x
package: 'Field types'
dependencies:
  - field
  - node
  - text

The info.yml file is required for Drupal to pay attention to the rest of the module's files. The contents of this one are vanilla, other than some enumerated core dependencies.

name_field_type.module


/**
 * @file
 * Contains name_field_type.module.
 */
use Drupal\Core\Routing\RouteMatchInterface;
/**
 * Implements hook_theme().
 */
function name_field_type_theme($existing, $type, $theme, $path) {
    $theme = [
        'name_field_widget' => [
            'variables' => [
                'title' => NULL,
                'first_name' => NULL,
                'middle_name' => NULL,
                'last_name' => NULL,
                'maternal_last_name' => NULL,
                'suffix' => NULL,
            ],
        ],
    ];
    return $theme;
}
/**
 * Implements hook_help().
 */
function name_field_type_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    // Main module help for the name_field_type module.
    case 'help.page.name_field_type':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('Field type widget example.') . '</p>';
      return $output;
    default:
  }
}

The .module file contains an implementation of hook_theme. This will pave the way for the variables that will be passed to the twig file, which we'll create later.

That's it for the module files. At this point we could do

drush en name_field_type

and enable the module, though of course the module won't do anything yet. In Part 2 we move on to the file that defines the widget field type.

Part 2

Jan 01 2019
Jan 01

Often a custom module will have configuration settings that can be provided by an administrator. In Drupal 7, the form used for this purpose was provided via form code including a form array, typically encoded in an admin.inc file, and a hook_menu implantation in the .module file. 

In will probably come as no surprise that things are done differently in Drupal 8. So, let's go step-by-step through the creation of a custom module, example, and its settings page.

my_example.info.yml

The .info.yml file is the only file required for a module, and it doesn't need to contain much. Place it in the module root folder, modules/custom/my_example


name: my example
type: module
description: a module to use in my tutorial.
core: '8.x'
configure: my_example.settings

The configure entry uses the routing from the .routing.yml file. This entry results in a configure link being presented when the accordion control for the module is opened on the module admin page.

my_example.routing.yml

The .routing.yml file has a few purposes:

  • Establish the path for the configuration settings page
  • Tie the configuration settings page to its form
  • Declare the permissions necessary to access the page

This file will also be placed in the module root folder.


my_example.settings:
  path: '/admin/config/system/my_example/config'
  defaults:
    _form: '\Drupal\my_example\Form\Settings'
    _title: 'My Example'
  requirements:
    _permission: 'administer site configuration'

In the file, above, note that the prefix to .settings, my_example, matches the module name, and is again used in the _form reference.

my_example.links.menu.yml

Why doesn't my module have a configuration link on the admin configuration page? More often than not, the answer to this and similar questions is that this file wasn't created. The .link.menu.yaml file provides the missing link, so to speak, and like the preceding yaml files should be placed in the module's root folder.


my_example.settings:
  title: 'My Example'
  description: 'A module to use in my tutorial.'
  route_name: my_module.settings
  parent: system.admin_config_system

Note that the first line matches the name used in the .routing.yml file as does the route_name further down in the file. The parent setting determines where on the admin/config page and menu the link will appear, in the System section in this case.

Settings.php

The final file is the one that provides the settings form. Its name matches the last item in the _form setting in the .routing.yml file. It should be placed in the path
/src/Form.


 
namespace Drupal\my_example\Form;
 
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
 
/**
* Configure settings for this site.
*/
class Settings extends ConfigFormBase {
/**
 * {@inheritdoc}
 */
  public function getFormId() {
    return 'my_example_settings';
  }
 
/**
 * {@inheritdoc}
 */
  protected function getEditableConfigNames() {
    return [
      'my_example.settings',
    ];
  }
 
/**
 * {@inheritdoc}
 */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $config = $this----->config('my_example.settings');
 
    $form['sample_setting'] = array(
      '#type' => 'textfield',
      '#title' => $this->t('Sample setting'),
      '#description' => $this->t('A sample setting for our module.'),
      '#default_value' => $config->get('sample_setting'),
    );
 
    return parent::buildForm($form, $form_state);
  }
 
/**
 * {@inheritdoc}
 */
  public function submitForm(array &$form, FormStateInterface $form_state) {
      // Retrieve the configuration
       $this->configFactory->getEditable('my_example.settings')
      // Set the submitted configuration setting
      ->set('sample_setting', $form_state->getValue('sample_setting'))
      ->save();
 
    parent::submitForm($form, $form_state);
  }
}

A few things to note in this file:

  • The class name matches the form name given in _form setting of the .routing.yml file
  • The method names should always be as listed
  • getFormId() returns the ID of the form
  • getEditableConfigNames() returns the name from the first line of the .routing.yml file
  • buildForm() loads the saved config, if any, based on the same routing entry, and creates the config form
  • The #default_value line in the form item retrieves the last saved value, if any, for that field
  • submitForm() uses the same routing entry and saves the values of the enumerated field(s)
Dec 26 2018
Dec 26

Your step by step guide with easy to follow instructions for navigating Drupal 8.

Book cover of Drupal 8 Quick Start Guide

Available from Amazon and Packt.

Drupal is a powerful content management platform, flexible enough to accommodate almost any content requirements. This flexibility comes with a cost: complexity. Drupal 8 Quick Start Guide will clear your path from installation to a building usable site in minutes, and to a customized site in one sitting.

  • Create and customize Drupal structures, such as menus, tags, and content categories
  • Extend Drupal's capabilities with add-on modules
  • Administer site users, their roles, and the actions to which they are granted access
  • Understand user roles and permissions
  • Create, edit, and publish content
  • Use Views for custom content selection and display
  • Expand your audience with custom RSS feeds
  • Configure a home page with meaningful sections for a better UX
Of course, the Drupal Community isn't the only place to give back. It's a complex world, and there are as many worthy causes as their are melodies, with most being served by multiple charitable organizations. Here are a few of those that strike a 7th chord with me. St. Jude Children's Research Hospital logo UNICEF logo
Mar 12 2018
Mar 12

I ran into the usual situation of Composer hair-pulling when updating to Drupal 8.5.

I received errors related to Symfony 3.2.14 not being the release needed. And so it turns out, that Symfony 3.4.5 is the release being used.

The problem was a Catch-22. Composer did not want to update Symfony because someone was requiring 3.2.14. 

I tried updating individually, requiring, even updating both at the same time, but in the end, what worked for me was the following:

  • Edit composer.lock in the Drupal root and search/replace 3.2.14 with 3.4.5
  • composer require drupal/core:~8.5 --with-dependencies

The result is Composer and its components being updated to 3.4.5 and Drupal happily updating to 8.5.

Of course, the Drupal Community isn't the only place to give back. It's a complex world, and there are as many worthy causes as their are melodies, with most being served by multiple charitable organizations. Here are a few of those that strike a 7th chord with me. St. Jude Children's Research Hospital logo UNICEF logo
Apr 27 2017
Apr 27

Thanks to all who took the time to take the poll. The participation was great! Over 350 respondents, which is a number in excess of 10% of the DrupalCon attendance. There were couple comments that I'd like to address:

A few felt that the questions were biased, or that the choices given were biased. I strove to make each of the questions a current topic, without having any imply a leaning in either direction. For example: "How do you feel about Drupal's Leadership" is meant to present a current topic in the community, but is designed to not imply a positive or negative spin. As for the options, it will never be possible in a poll with static response choices to cover all nuances, unless you just give three: positive, negative or neutral. I did try to ensure that each question had a fully positive response, a clearly negative response, and some options in between. I suppose it could have been set up to be a 1-10 scale, but I defy you to qualify the difference between 6 and 7 on such a scale. I also offered to account for comments that included a question number and a custom response when presenting the results, and have done that on questions 1 and 6, for which custom answers were given. 

There was also a concern that question 6 only offered negative or neutral options, and the suggestion was that the question should be removed from the poll as a result. I disagree, feeling that the first option, "The matter was handled properly" is certainly an option that indicates an opinion that is neither negative nor on the fence.

Should I do another poll? Let me know. 

And now, the results:

 The Future of Drupal

 Dries Conflicts

 Drupal Leadership

 Drupal Leadership Structure

 Drupal's Direction

 On the Matter of Crell

 Time Spent with Drupal Hedging your Bet

 Where you work

 What you do

The average time in Drupal for all respondents was 7.1 years.

Of course, the Drupal Community isn't the only place to give back. It's a complex world, and there are as many worthy causes as their are melodies, with most being served by multiple charitable organizations. Here are a few of those that strike a 7th chord with me. St. Jude Children's Research Hospital logo UNICEF logo
Apr 20 2017
Apr 20
The State-of-Drupal Poll ayen Thu, 04/20/2017 - 11:25
Jul 10 2016
Jul 10
Drupal 7 Views Cookbook - Revised cover

Drupal 7 Views Cookbook has been fully revised and painstakingly tested. Those who purchased the original version in electronic or print format from Packt Publishing can obtain this revised edition in electronic form at no cost from your PacktPub.com account.

The original version was drafted while Drupal 7 was still in beta, and Views 3 was still on paper, and was released just prior to tweaks to the Views 3 UI, so from the start, the step-by-step recipes were often at odds with what the reader was experiencing. Every recipe has been recrafted and tested in this revision.

Additionally, the content types and views recipes used in the book are available here as features, for those who want to review the finished views rather than having to create them.

Mar 23 2016
Mar 23

DON'T HACK CORE! It's THE cardinal rule of Drupal. Like another rule, Don't eat yellow snow, it's inviolate...immutable...or is it?
There is one circumstance when hacking core is a good thing. "Really?" you ask. Yes, definitely. Hacking core is a great way to find out how a particular part of Drupal is working, particularly if you can't use something like xdebug. In that case, if you want to see what the world looks like when you get to a certain place in the code, there's nothing better than sticking in some debug code. There are, however, some precautions you should take:

  1. Copy the file you'll be hacking and give it an additional suffix, like .orig 
  2. If you're using git, you'll be reminded looking at git status. If not, you might want to create a directory solely for moving the copies to, so that you can easily check on what you need to move back
  3. Wrap your debug code in some type of active test. I tend to do this:

  if (isset($_GET['debug'])) {
   debug code
  }
A Drupal 7 example of using this is when you want to see what permissions are being tested for on a page. At the start of the user_access function in the user module, inserting
  if (isset($_GET['debug'])) {
    dpm($string);
  }
if you have the devel module installed, or 
  if (isset($_GET['debug'])) {
    drupal_set_message($string);
  }
if you don't, will answer the question for you, if you load the page with the query string ?debug=1
Oh, and regarding yellow snow...even That has an exception: yellow snow cones!

Of course, the Drupal Community isn't the only place to give back. It's a complex world, and there are as many worthy causes as their are melodies, with most being served by multiple charitable organizations. Here are a few of those that strike a 7th chord with me. St. Jude Children's Research Hospital logo UNICEF logo
Mar 21 2016
Mar 21

I was listening to Webchick's presentation on Upgrading YOUR Module to Drupal 8 (https://www.youtube.com/watch?v=wKdU2Q1NIZQ), following along with my own contributed module (https://drupal.org/project/node_theme) and when she reached a seemingly innocuous step

  • Installation:
    • drush dl drupalmoduleupgrader
    • cd drupalmoduleupgrader
    • composer install

I received the following response in my Mac terminal window

-bash: composer: command not found

Well, hell. I checked a few things, and yup, no composer to be found. I figure I'm not the only one running into this (although I'm late to the D8 upgrade game, so maybe so!).

If you are on a Mac, you're probably using Vbox, MAMP, or Macports. I'm going to describe installing composer in an environment using Macports. First, be aware that 

sudo port install composer

yields nothing. It's quite possible that there's some jinky package name that would have resulted in composer being installed, but I was feeling particularly ornery and impatient tonight, so I moved on without checking.

curl -sS https://getcomposer.org/installer | php

had better results, for a moment, and then this

Some settings on your machine make Composer unable to work properly.
Make sure that you fix the issues listed below and run this script again:
The openssl extension is missing, which means that secure HTTPS transfers are impossible.
If possible you should enable it or recompile php with --with-openssl

Fair enough. I'm running php 5.5 (yup, 5.6 upgrade next), and this was easily taken care of with the following

sudo port install php55-openssl
--->  Computing dependencies for php55-openssl
--->  Fetching archive for php55-openssl
--->  Attempting to fetch php55-openssl-5.5.33_0.darwin_15.x86_64.tbz2 from http://packages.macports.org/php55-openssl
--->  Attempting to fetch php55-openssl-5.5.33_0.darwin_15.x86_64.tbz2 from http://lil.fr.packages.macports.org/php55-openssl
--->  Attempting to fetch php55-openssl-5.5.33_0.darwin_15.x86_64.tbz2 from http://mse.uk.packages.macports.org/sites/packages.macports.org/php55-openssl
--->  Fetching distfiles for php55-openssl
--->  Verifying checksums for php55-openssl
--->  Extracting php55-openssl
--->  Configuring php55-openssl
--->  Building php55-openssl
--->  Staging php55-openssl into destroot
--->  Installing php55-openssl @5.5.33_0
--->  Activating php55-openssl @5.5.33_0
--->  Cleaning php55-openssl
--->  Updating database of binaries
--->  Scanning binaries for linking errors
--->  No broken files found.

Let's try it again

curl -sS https://getcomposer.org/installer | php

All settings correct for using Composer
Downloading...
Composer successfully installed to: /Users/jag/temp/composer.phar
Use it: php composer.phar

Much better! Ok, now

sudo mv composer.phar /usr/local/bin/composer

And a test just to make sure

composer --version
Composer version 1.0-dev (a8e9df55dc62d8806360be2f79ad112b8678d397) 2016-03-17 11:42:19
Mar 12 2016
Mar 12

It took far too long, but I've finally posted a 7.x update for project Node Theme at https://drupal.org/project/node_theme
Node Theme is used to control which theme a given path will use. "Node Theme" is a bit of a misnomer, a holdover from 6.x. It can be used to record the theme choice for any path on the site, and will seamlessly switch the rendering to that theme when the page is requested. 

Of course, the Drupal Community isn't the only place to give back. It's a complex world, and there are as many worthy causes as their are melodies, with most being served by multiple charitable organizations. Here are a few of those that strike a 7th chord with me. St. Jude Children's Research Hospital logo UNICEF logo

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web