Upgrade Your Drupal Skills

We trained 1,000+ Drupal Developers over the last decade.

See Advanced Courses NAH, I know Enough
Nov 11 2021
Nov 11

A few weeks ago, DrupalCon Europe took place - for the second time as a purely digital conference. The whole undpaul team had "time off" from their daily tasks, so we had time to learn new things, to share our knowledge and to contribute to the community. From last year (link to blog post), we already knew the digital approach and plunged directly into the large number of talks and sessions.

Jun 30 2021
Jun 30

Personal expectations exceeded

Regarding my three days working in the Tiny House office, I have to say: the actual experience exceeded even my wildest expectations. After a short settling-in period, during which I felt a bit like a fish in an aquarium, the special atmosphere of the Tiny House completely absorbed me. Even with the high temperatures (well over 30° Celsius), a pleasant breeze came inside through the large doors and I was able to work in a relaxed and concentrated manner. Of the many possibilities offered by the house, I could only use a limited amount, but what I was able to experience definitely left an impression.

I believe that Tiny Houses can definitely be an alternative to fixed offices and also the classic home office in the future. After all, they are very variable, can be used almost anywhere and can offer different professional groups a comfortable workplace. At the beautiful location in the heart of Rosenheim, directly in front of the city library, the Tiny House 35 Kubik Heimat is definitely worth a visit and for me a view of how cities should be in the future.

Certainly there will be further opportunities to use the Tiny House again as a workplace for me, but also for smaller events of undpaul. The very good conversations with the people in charge of the library made me want to do more.

Jun 02 2021
Jun 02

For a great number of use cases

There is a whole range of use cases for a Site Assistant. For what purpose and with what goal they are used depends very much on the context. To help you understand what Site Assistant can do for you, we show three different use cases here:

Variant 1 - Product information

The Site Assistant is displayed on the product detail pages of a technology company. There it contains for example:

  • A link to the online store where the products can be purchased.
  • The contact details to the sales department for bulk orders
  • The contact details for technical customer support for queries about products that have already been purchased
  • Information and forwarding to the current product innovation of the company

Variant 2 - Events

The Site Assistant is displayed on the trade fair pages of a venue. There it contains for example:

  • A link to the exhibitor registration page
  • A link to the ticket store for visitors
  • The contact details of the project management for further inquiries

Variant 3 - Press area

The Site Assistant is displayed in the press and news area of an international company. There it contains for example:

  • A link to the media library to download additional media
  • A subscription to the press newsletter
  • The contact details of the press spokesperson
  • The opening hours of the company

Unrestricted design for editorial teams

The Site Assistant module is built in such a way that editors or other authorized roles can use it to quickly and easily add content, reuse it, as well as display the assistant on any page.

A huge advantage of our module (especially compared to other solutions) is that any number of assistants can be used for different purposes on one Drupal site. For example, pages on product topics can contain an online store and the contact of the person responsible for the product, whereas news pages can display press contacts and downloads in the assistant.

All in all, the module offers four enormous advantages for editorial teams and page operators from our point of view:

  1. It offers editorial teams themselves a simple tool to provide site visitors with up-to-date and relevant information and to provide them with customized navigation options.
  2. Furthermore, assistants can be used as a marketing tool to better reach customers and direct them to specific (marketing relevant) content.
  3. Since the module is shared with the Drupal community, it is available for all for download. So there are no costs for extending the Drupal site and using the Site Assistant module.
  4. The complete design of the assistants can be customized. This requires site builder skills to customize the Drupal templates and CSS if necessary.

What exactly is in the Site Assistant module? We already wrote a post about this a few weeks ago titled "New Drupal module for contextual assistants".

May 21 2021
May 21

1) Flexibility

Drupal is extremely flexible and versatile. Due to the modular structure, content and layout are separated from each other. Both can be edited or exchanged independently without affecting the site as a whole.

The page can be changed or extended at any time. For example, it is possible to add language variants, redesign the layout, add further user interaction, integrate new data sources, etc.

2) Tailored solutions

Drupal is very well customizable and adaptable to the actual goals and requirements of the web project. There are (almost) no limits to the ideas and possibilities.

As a CMS, Drupal offers a very good basis, which can be extended and customized via thousands of extensions (modules). The already large selection is also constantly being expanded with new modules. Thus, there is already a pre-built solution for an enormous number of use cases. The Drupal site is then assembled only from the building blocks that are needed for the particular use case. And of course, these can be extended at any time.

3) Usability & Accessibility

Drupal has a strong focus on usability for users and accessibility for visitors.

The backend for Drupal users is kept clear and focused. Users can work from anywhere via the browser and do not need any additional software. Via the integrated role and rights system, the view and editing options are adapted for the user groups. Thus, all users (e.g. marketing, editors, developers, etc.) can work clearly and efficiently in their work environment.

Accessibility standards are a basic requirement in Drupal. Drupal ensures that all features and content comply with the World Wide Web Consortium guidelines WCAG, WAI-ARIA and ADA guidelines. This supports a low barrier website to allow easy access to information for all users.

4) Open interfaces

Drupal integrates really well with existing tools and software in the existing business environment. Through robust APIs, the Drupal site can communicate and interoperate with many other interfaces. For example, your own CRM software, external media databases, marketing tools, etc. can be shared with Drupal.

5) Community & Security

Drupal is an open source solution and is (further) developed by an extremely dedicated community. Worldwide, many web professionals invest their time in documentation, testing, code review, further development and networking. Thus, they are constantly working on the improvement of Drupal, which becomes visible in the form of ever new features and modules.

An important role is played by the security team within the community. The experts continuously analyze and eliminate potential risks. Thus, every new module undergoes a strict quality test by the security team before release.

Apr 08 2021
Apr 08

Within the product lifecycle, individual software versions repeatedly reach their end-of-life (EOL). After this point, the previous version is no longer supported in favor of a newer version - this is quite normal and usual for a technical product.

Drupal is also due for an end-of-life this year: Support for Drupal 8 will be discontinued on Nov. 2, 2021. Now, many Drupal 8 site owners are under pressure to upgrade to Drupal 9 in time to ensure a risk-free and secure Drupal environment. Since Drupal 8 will not be further supported after the EOL, we can therefore only strongly advise all Drupal 8 site owners to upgrade the system to Drupal 9 in time.

Ending Signage

From Drupal 8 to 9 - The upgrade has to be done

That Drupal 8 is hitting its EOL so soon is due to the following: Drupal 8 uses Symfony 3, which will no longer be developed as of November this year. The newer Drupal 9 only uses the successor Symfony 4 as PHP framework, library and its modules.

With the EOL, no more security updates will be made available for websites that use Drupal 8. So, in essence, there is no viable alternative for these sites other than to upgrade to Drupal 9.

What Drupal 9 brings with it

Upgrading from Drupal 8 to Drupal 9 is a much smaller jump than the previous upgrade from Drupal 7 to Drupal 8. For the first time in Drupal's history, the new Drupal version builds directly on a previous version. The upgrade from Drupal 8 to Drupal 9 is therefore much more comparable to an update from, say, Drupal 8.6 to Drupal 8.7.

Drupal 9 is a further developed and improved version of Drupal 8. The new version offers a whole range of advantages. In general, the most relevant advantages can be summarized in the following three points:

  • Long Term Support
    Drupal 9 is supported until at least the end of 2023, which provides site owners with long-term security.

  • "Cleaned up" Drupal version
    The program code has been cleaned up and tidied up in many places to make the Drupal core clearer.

  • Many modules and new features
    Many existing modules are already available for Drupal 9 and new modules / features are developed only for Drupal 9.

How we upgrade our customer projects

For the upcoming upgrades to Drupal 9 in the coming weeks and months, we have worked out a simple process by which we proceed:

  1. In the first step, we analyze the current instance. Installed modules, themes and project-specific code are checked for compatibility with Drupal 9.

  2. In the second step we perform the update of modules, Drupal core, theme files and project specific code. If necessary, we create patches for "old" modules so that they continue to work on the upgraded Drupal 9 site if they are not (yet) officially ready for Drupal 9.

  3. In the third step, our customers can test the functionality of the site in a staging environment before everything is rolled out to the production environment.

Also important and good to know: From an editorial point of view, there is no effort involved in upgrading to Drupal 9 and everything remains as it was. For example, the familiar workflows remain in place and no existing content needs to be migrated.

Apr 07 2021
Apr 07

Switch view modes for all entity types editorially with our new Drupal module!

Interaction with the View Mode Switch Field Modul 

Separating content from layout, ensuring high flexibility for the editorial team when creating content, as well as a simple and consistent CMS - this all sounds absolutely reasonable and can also be implemented very well in Drupal. With its modular structure and the ability to extend its functions through various contrib modules, this is already possible in Drupal. Nevertheless, in our projects we have noticed over and over again that editors need even more predefined layouts (e.g. for different arrangements in text-image elements, teaser variants, etc.) from which they can select individually and thus determine the output.

Different view modesLayout variants of the configured view modes in the output

This idea is not a new one. There are and have been different approaches within the Drupal world for managing output options:

  • In Drupal 7, there were two major players Display Suite (ds) and Panels (panels) for layouting content. Both had their advantages and disadvantages, but both have lost their relevance in Drupal 8/9 due to the Layout Builder.
  • With the Layout Builder in Drupal 8/9, the editorial team can be extremely flexible in customizing the layout of content. Even too flexible, so that it is also up to them to take care of the consistency in the layout of the page.
  • For Drupal 8/9 there is a contrib module called "View Mode Selector", which provides a similar functionality as our new module. This gives the editors a choice of (only) one defined view mode, which in practice is usually not enough.

So why yet another new module?

Quite simple: We were missing versatility and flexibility for site builders as well as editorial teams. Especially for larger projects, when the Drupal site is extensive and many people are involved in the editorial team, this becomes more and more important.

This is when it is extremely helpful to be able to select different predefined view modes with different layouts/templates for all relevant entities and still maintain the layout consistency of the site. This is how the View Mode Switch Field module was born.

In a nutshell, the View Mode Switch Field module does the following: It allows site builders to provide different defined view modes for fieldable entities. This allows editors to choose between predefined view modes and thus control entity output more flexibly. For example, editors can highlight article teasers in a listing or change the arrangement of image text paragraphs.

Layout Builder View Mode Switch FieldConfiguration of the layout variants as view modes with the help of the layout builder

The simple magic behind the View Mode Switch Field module

Site builders can include any number of view mode switch fields per entity bundle, so that editors can independently switch one or more view modes per field. Of course, the created view modes can be subsequently adjusted, changed or even deleted - without affecting the content of the Drupal page itself. Any configuration change to the corresponding view modes will also be applied to existing content. In case of missing view modes the layout jumps back to the defined default setting.

To use the module, there are only a few simple steps for site builders:

  • Create and design the view modes.
  • Add and configure one or more view mode switch fields via the Field UI - here it is possible to allow any number of view modes to be switched per field and to define which view modes can be switched to.
Settings View Mode Switch Field ModulField configurations of the View Mode Switch field

A wide range of benefits

As mentioned before, the View Mode Switch Field module mainly improves versatility and flexibility for site builders and editors. This is still quite general and applies to many Drupal modules. So here we want to give you very specific points where the module will help you:

  • Content and layout are still considered separately. This means that both can be adjusted independently of each other.
  • The module strikes a good balance between freedom and flexibility for the editorial team and compliance with CI guidelines. The editorial team is only given really necessary options, so that a consist look and feel of the design is automatically preserved.
  • Data structures (e.g. the field set of a paragraph) only have to be defined once and can still use different output options. Instead of creating a new paragraph type for another display, e.g. an inverted text-image combination, this can be controlled by selecting the view modes.
  • By avoiding duplications in the data structure, the editing interface becomes and remains lean and clear.
  • The way the module works avoids possibly unperforming preprocesses and templates for the actual layout switching. In addition, the use of view modes ensures very good cache behavior and thus high performance.
  • Subsequent global layout changes affect all (new and existing) entities. For comparison: e.g. with Layout Builder, the layouts overwritten per entity are decoupled from updates.
  • The implementation based on the Drupal Core Field API enables site builders to perform all the functions already known for entity fields - for example, generating entity listings based on specific View Mode Switch field values (whether for editorial overviews or administrative information).

Last but not least

As an agency, we handle a wide variety of projects and like to use the View Mode Switch Field module for them. The module is particularly useful in Drupal projects that use a component-based layout/design approach. Editors can use it to select individual building blocks (entity bundles) from a ready-made construction kit (content types, paragraph types, etc.) and display or "paint" them differently (view modes with defined layouts).

Since it is extremely important to us that our projects run smoothly at all times, we equip them with automated tests by default. The View Mode Switch Field module also comes with extensive test classes that ensure the runability of the module code for various scenarios.

The View Mode Switch Field module is shared in the Drupal community and is available for anyone to download. Try it out and feel free to give us feedback in the Drupal issue queue!

Mar 09 2021
Mar 09
Meer mit Tunnel

When a new project is started, everyone is usually full of anticipation and motivated to get started right away in order to "really get things done" and be successful. This enthusiasm is absolutely good and important, but above all it is important to maintain it throughout the entire project.

As an agency, we accompany many projects in parallel, some of them even from the very beginning. Again and again we notice: One of the biggest sticking points is the preparation and work prior to the actual start of the project. If there is a lack of understanding, coordination and information here, this can be felt for a long time during the project and can make the work more difficult. Therefore, we at undpaul have developed a method with our Discovery Workshop, which helps to ensure a good and coordinated start to every new project.

Discovery vs. Discovery

There are a lot of meanings and definitions for the term "Discovery". In our understanding, we divide Discovery into the Discovery Workshop and the Discovery Phase. Both have in common that they take place prior to the actual development and project work. The main difference is the time frame and therefore the depth and scope in which the content is elaborated.

During the Discovery Workshop as the first step into a project, the focus is on getting to know the participants and the project, a common understanding of the goals and framework conditions as well as the general basis for the upcoming collaboration. In the second step (depending on the size of the project), the requirements are formulated more concretely in a Discovery Phase and the user experience of the site as well as the target group (analysis) are taken into consideration.

What do I get out of a Discovery Workshop?

Especially at the beginning of new partnerships, we often have to convince our customers to do a Discovery Workshop. Again and again we hear arguments like:

  • "We already have our requirements written down."
  • "This costs a lot of money and we don't have a website (or a product) in the end."
  • "Our project manager is already doing this / has all the information available."
  • "Our requirements are described by us down to the smallest detail."

So why is a Discovery Workshop so useful and important? Simply put, to reduce risk, build trust, and develop a common goal or understanding of goals.

Let's make it a little more specific with some examples:

  • Only a reasonable solution will be successful and also make the project successful. But this requires a project team that fully understands the goals and requirements. This means on the one hand to have the same understanding of the goals and on the other hand to see the requirements in context in order to bring in the best solutions and alternatives at any time.
  • If the goals are clear and unambiguous for the entire project team, the team has "Purpose & Direction", so to speak, then decisions can be made much faster and also better in everyday work.
  • In addition, we like to recommend our clients to see the Discovery Workshop as a way of getting to know the agency. With the smaller own project, the cooperation and sympathy can already be tested in the real "working world".

Hands-On: Content and tools

For a Discovery Workshop, we have come up with a question collection that applies well in most projects. Basically, we divide the question collection into three areas:

  1. The area from the client's point of view mainly deals with the overall goals.
  2. The project area includes everything that concerns the project or product itself. From this the requirements result later.
  3. The framework area covers the basic framework, e.g. technical requirements but also time and budget plan.
Fragen für eine DiscoveryQuestions for a Discovery Workshop (German only)

Most of our Discovery Workshops take place remotely - also totally unrelated to the current Corona situation. We use a video conference in combination with a collaborative meeting tool. Where we have found no relevant difference between the different videoconferencing tools for our Discovery Workshop, we currently prefer to use Miro for the collaborative creative process and documentation.

Miro Board für eine DiscoveryExample agenda of a Discovery Workshop in Miro (German only)

The main thing is to do it!

There is something new to learn in every Discovery Workshop. However, as with many workshops and preparatory work, there is no "right or wrong" in methods and execution. The very most important point is: do a Discovery when starting a new project! The time you put into preparation so often makes the work go more smoothly and successfully as the project progresses.

Feb 09 2021
Feb 09

To enable visitors to the site to navigate more effectively via individual assistants that inform and direct them to the relevant topics depending on the context - that's what we wanted to realize for one of our projects. The goal behind this is to give end users the information they need quickly and easily at the time they need it.

In the World Wide Web such assistants can be found more and more. However, for our Drupal project we did not find the right thing for our needs - neither an existing Drupal module nor a service provider offering such a solution. So it was clear: A new module was needed. And this module should be available as a contribution for the whole Drupal community. Voilá, a few days later we developed the Site Assistant module.

View of a site assistant in action.View of a site assistant in action.

Requirements for the assistant

The overall requirement for the assistant is: It must be easy to use and well adaptable. Editorial teams should be able to create their own assistants with customized content for different areas. In addition, we defined the following requirements for the new module:

  • The content is created and maintained editorially.
  • There can be multiple assistants with different content.
  • The assistants are displayed depending on conditions (condition plugins).
  • The design of the assistants is customizable.
  • The assistants are sticky and usable in the different viewports.
  • Editors create assistants themselves, without a site builder and without the need for deployment.

This is inside the new Drupal module

From a technical perspective, the condition handling for the context-dependent display of the assistant is certainly the most exciting part. The Site Assistant module uses the existing condition plugin system and builds on it.

The display of our assistants is controlled by the conditions. A big advantage of the condition plugin system is that the Drupal community continuously provides new condition plugins and expands the selection more and more. For example, there are already condition plugins for the Drupal Commerce module for online stores. So if your Drupal site already has a store that uses this module and its condition plugin(s), you only need to activate the Site Assistant module and you can directly use the existing conditions from the store for the assistant as well.

The Site Assistant module itself is divided into three sets: the assistants, the assistant list items, and the assistant library content.

  • The assistants themselves are composed of a content field and a display options field. In the content field, the content to be displayed is placed and arranged using multiple list entries as needed. The display field is used to configure the conditions (condition plugins) on the basis of which the assistant is to be displayed.
  • The assistant list items are the contents that are displayed in the assistant. The module already brings a set of predefined list item types: headline, link, link list, subpage, library content, free text (wysiwyg). Site builders can create their own list item types, giving editors more choices in content design.
  • Assistant library items are content stored separately for reuse, and can be used in different assistants. An assistant library item consists of any number of list items. For example, for recurring contact opportunities, an assistant library item can be created with the heading "Contact" and a wysiwyg field with address, phone number and email, which is then used in different assistants.

The design of the assistant can be customized at different levels. Since each item in the assistant is a separate entity, they can be customized and formatted as usual via Drupal templates. The general design of the assistant can be customized via CSS.

Entry form for the fields of a site assistantEntry form for the fields of a site assistant.

And what's more?

With our new module there is now also the possibility to easily and quickly introduce context-dependent assistants in Drupal in order to better support the end user. The Site Assistant module brings a good base, but of course there is still a lot of potential for extensions and customizations. With a little development effort, you can create your own custom conditions (a tutorial can be found on Drupal.org) and customize the functionality exactly to your needs.

We would like to see more assistant list item types shared by and for the Drupal community so that the possibilities with the assistant grow. For example, I can very well imagine chat bots (possibly directly via service providers) being integrated into an assistant.

Jan 15 2021
Jan 15

Today, just 20 years ago, the first version of Drupal, Drupal 1, was released. We come together with a loud (and somewhat off-key) "Happy Birthday" for its 20th birthday. Great that Drupal and its wonderful community have been part of the world wide web for so long!

20 years Drupal around the world

20 years, yes that is right TWENTY, is a really long lifetime for a content management system. Many technologies have emerged in these 20 years, became relevant, lost their relevance again and disappeared. But not Drupal. The open source technology has been continuously enhanced by the large community, and is still state of the art and will continue to shape the future of the web.

Drupal was there

“We were blogging before blogging was cool.” This is how Dries started his technology review at the last DrupalCon. And it's true - vividly illustrating the ambition and development history of Drupal. 

Who remembers the days before everyone could use the Internet? It feels like an eternity ago, it was even a previous millennium. For a large part of the development within and around the Internet, Drupal was there:

  • Drupal witnessed the birth of the browsers Safari and Firefox.
  • Drupal accompanied the emergence of the social web and with it, among others, Myspace, Facebook. YouTube, and others.
  • When the iPhone became the first device with mobile browsers, responsive designs were implemented in Drupal. Thus, Drupal played an important role in the mobile web from the very beginning.
  • Drupal was the first CMS to adopt jQuery, validating it and significantly promoted the spread of JavaScript.
  • Drupal is also developing new approaches to current developments, specifically in the area of “digital experiences”, through new channels and approaches such as voice interaction, digital machine learning and integrated solutions.

A wonderful community

We know that Drupal is great. And more and more people are agreeing with us. The Drupal supporters and community is growing. 

For more than 10 years, we as undpaul have been part of the Drupal community. Some of us have been part of it for even longer. And here is a personal thank you to Drupal: Thank you because undpaul owes its presence to the lovely and hardworking people in our community. Even though everything was a bit different last year, DrupalCon is one of our annual highlights. We are looking forward even more to the next live event with the community - with our friends and colleagues!

I will always remember my first DrupalCon, back in 2006 in Brussels. It was great to be welcomed into the community so easily. And of course remember enjoying the currywurst with Dries and a few other Drupal veterans in the restaurant of a sports club.


Dec 16 2020
Dec 16

As a developer I tend to be lazy. I'm always searching for tools or shortcuts to make my live more comfortable.

Recently I stumbled across a giving an example on how to use migrate instead of a custom update script to update existing entities. Having no use for it at this time I saved it in my "maybe useful later"-part of my brain ... and forgot about it.

However, last week I had to add an existing field to the form display of all Paragraphs types in a project. Additionally a new field should be added and configured. Because I didn't want to configure the fields manually (remember? I'm a lazy developer!) for all Paragraphs types (there are about 80 of them in this project) I normally would have written an update hook for this task. But then I remembered the tweet and thought "wouldn't it be also possible to update the configuration using migrate?".

What do we need?

The first part of the task is easy: to display an existing field in the form of an entity you simply drag it from the "hidden" section to the content section.

Paragraphs form displayForm display of a simple Paragraphs type.

After moving the field "Published" into the content section, I exported the configuration changes to see what happened and got the following result for core.entity_form_display.paragraph.text.default.yml:

Configuration changes in Paragraphs form displayConfiguration changes in Paragraphs form display

So in my migration I have to replicate exactly this configuration change for all Paragraphs types.

Migrating form display settings

In the migration I need a source plugin for all available Paragraphs types first. Because I already made the necessary changes to the form display of Paragraphs type "Text" the source plugin also needs the possibility to exclude certain items (well, I eventually could have reverted the previous configuration changes and start over with a recent database backup, but ...).

  1. namespace Drupal\up_migrate\Plugin\migrate\source;

  2. use ArrayObject;

  3. use Drupal\Core\StringTranslation\StringTranslationTrait;

  4. use Drupal\migrate\Plugin\migrate\source\SourcePluginBase;

  5. use Drupal\migrate\Plugin\MigrationInterface;

  6. use Drupal\paragraphs\Entity\ParagraphsType;

  7. /**

  8.  * Source plugin for ParagraphsType.

  9.  *

  10.  * @MigrateSource(

  11.  *   id = "up_paragraphs_type",

  12.  *   source_module = "up_migrate"

  13.  * )

  14.  */

  15. class UpParagraphsType extends SourcePluginBase {

  16.   use StringTranslationTrait {

  17.     t as t_original;

  18.   }

  19.   /**

  20.    * List of paragraphs types to exclude.

  21.    *

  22.    * @var array

  23.    */

  24.   protected $exclude = [];

  25.   /**

  26.    * List of paragraph types.

  27.    *

  28.    * @var array

  29.    */

  30.   protected $items = [];

  31.   /**

  32.    * {@inheritdoc}

  33.    */

  34.   protected function t($string, array $args = [], array $options = []) {
  35.     if (empty($options['context'])) {
  36.       $options['context'] = 'up_migrate';

  37.     }

  38.     return $this->t_original($string, $args, $options);

  39.   }

  40.   /**

  41.    * {@inheritdoc}

  42.    */

  43.   public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration) {
  44.     parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);

  45.     if (isset($configuration['exclude'])) {
  46.       $this->exclude = $configuration['exclude'];

  47.     }

  48.   }

  49.   /**

  50.    * {@inheritdoc}

  51.    */

  52.   public function fields() {

  53.     return [

  54.       'id' => $this->t('ID'),

  55.       'label' => $this->t('Label'),

  56.     ];

  57.   }

  58.   /**

  59.    * {@inheritdoc}

  60.    */

  61.   public function getIds() {

  62.     $ids['id']['type'] = 'string';

  63.     return $ids;

  64.   }

  65.   /**

  66.    * Return a comma-separated list of paragraph type ids.

  67.    */

  68.   public function __toString() {

  69.     return implode(', ', array_column($this->items, 'id'));
  70.   }

  71.   /**

  72.    * {@inheritdoc}

  73.    */

  74.   protected function initializeIterator() {

  75.     $this->items = [];

  76.     $paragraphs_types = ParagraphsType::loadMultiple();

  77.     /** @var \Drupal\paragraphs\ParagraphsTypeInterface $paragraphs_type */

  78.     foreach ($paragraphs_types as $paragraphs_type) {

  79.       $this->items[$paragraphs_type->id()] = [

  80.         'id' => $paragraphs_type->id(),

  81.         'label' => $paragraphs_type->label(),

  82.       ];

  83.     }

  84.     if (!empty($this->exclude)) {
  85.     }

  86.     return (new ArrayObject($this->items))->getIterator();

  87.   }

  88.   /**

  89.    * {@inheritdoc}

  90.    */

  91.   public function count($refresh = FALSE) {
  92.     parent::count($this->items);
  93.   }

  94. }

As you can see in the gist above, the source plugin is very simple. It grabs a list of all available Paragraphs types and removes the types you would like to exclude.

The next step is to write a migration that updates the configuration for the form display.

  1. id: paragraphtypes_form_display__status

  2. label: Add status field to paragraph form display.

  3. source:

  4.   plugin: up_paragraphs_type

  5.   exclude:

  6.    - text

  7.   constants:

  8.     entity_type: paragraph

  9.     field_name: status

  10.     form_mode: default

  11.     options:

  12.       region: content

  13.       settings:

  14.         display_label: true

  15.       third_party_settings: {  }

  16.       type: boolean_checkbox

  17.       weight: 5

  18. process:

  19.   bundle: id

  20.   entity_type: constants/entity_type

  21.   field_name: constants/field_name

  22.   form_mode: constants/form_mode

  23.   options: constants/options

  24. destination:

  25.   plugin: component_entity_form_display

  26. migration_tags:

  27.  - up_paragraphstype

The migration uses the new source plugin "up_paragraphs_type" and excludes the Paragraphs type "text" from the list to process. In line 11..17 we set exactly the same display settings as in the screenshot showing the configuration changes made for the "Text" Paragraphs type.

In the "process" section the migration loops over the results from the source plugin, using only the returned ID from each Paragraphs type and otherwise the constants defined earlier. Since we would like to update the form display configuration, we choose the "component_entity_form_display" plugin as destination, which is kindly provided directly by Drupal Core.

After running the migration all Paragraphs types available on the site are configured to display the "Published" checkbox. Yeah!

What about new fields?

But what about the new field I needed to create? Basically the migration doesn't really differ from the one above. The only thing we need to add is an additional migration creating the field configuration for each Paragraphs type.

Let's say, we would like to create a text field named "Comment" for all Paragraphs types. Then you will need to create the field storage for this field using something like this:

Note: if you have created the field manually (like me for Paragraphs type "Text") you can skip this migration because the field storage is already existent.

To add the newly created field we need to create a field instance for each Paragraphs type. This can be done by using the migration destination "entity:field_config":

Simple, isn't it?

What's up next?

After seeing how simple it is to create and update field configuration some new ideas came to our mind. It should also be possible to create entity types containing all required fields and display configuration using migrate. This could be a great option to enable some additional features on a site simply by clicking on a button (disclaimer: of course you need to export the configuration and eventually do some more stuff).

But this is stuff for another blogpost ...

Dec 14 2020
Dec 14

Since we have been working in a remote setup for more than ten years, we always look forward to the yearly DrupalCon so we can finally see each other again as one team. This year, despite everything going on with Covid-19, we wanted to keep up the tradition and bought tickets for the whole team. Unlike in previous years, DrupalCon Europe 2020 took place as a digital-only conference.

For this virtual DrupalCon, we decided to not fall into the work-trap but fully focus on the event and the sessions. We created a Miro board with frames for each team member to document sessions while they happened. We also created a DrupalCon Slack channel within which people would start threads for a session they were in, so we could chat about what we found interesting. Personally, I found reading this very helpful because if I was in another session, I would still immediately know if there is a session I would want to watch later.

DrupalCon Europe 2020

Advantages Of A Virtual DrupalCon

Being able to meet the Drupal community in person is a highlight for us each year. However, in this year's virtual setup, we found quite a few advantages:

  • One of the major advantages for me personally was that sitting at the computer while watching sessions allowed us to take better notes than usual and made it possible to chat within our team in Slack as well as with other attendees in the sessions' discussion chats
  • The coffee was better and there was no line to get it
  • No chance for Drupal Flu
  • Bluetooth headphones allowed us to do stuff while still listening
  • Better networking during sessions: In a single room you can't really talk to someone sitting next to you or on the other side of the room. But in this virtual setting, you can
  • More sleep, less commuting
  • Saved money and CO2 for transportation and accommodation
  • People who are shy to speak in public can ask questions


Of course there were some challenges with this years setup:

  • No great networking opportunities between sessions. The discussion chat was disabled as soon as the session ended. If you wanted to contact a person via Meeting Hub, you were out of luck if they didn't see your connection request.
  • Not being able to collect giveaways or play fun games at sponsor booths
  • Not being able to do sightseeing in an exciting city
  • With family being around, you are more likely to not attend evening events with your team
  • Documenting in Miro and Slack prevented me from using Twitter for sharing more about the event into the world outside of DrupalCon

Tips For Your Next Virtual Conference

We did block our team for DrupalCon but there was the occasional private appointment that we should have planned for another week.

  • Block the conference days to be able to focus on sessions instead of work
  • No work or private appointments during DrupalCon session hours you wouldn't have made while in another city
  • If you have anything planned for the evening with other attendees, be able to take part as if you were in a room together. Get a babysitter, let your partner know you are not available etc.

Our Team's Favorite Sessions

Almost all sessions were recorded and will be publicly available in about a month after the conference. If you bought a ticket, you may log back in to the EventsAir platform and find the session video there. The videos of our favorite sessions are available by the Drupal Association for the public on youtube.












The main topics I took from this DrupalCon were personalization/DXP (Apache Unomi, Mautic, Smart Content Paragraphs), the Gin Admin Theme and Digital Signage.

The following sessions are on my to-watch list after hearing good feedback from others:

We would like to thank all volunteers, the Drupal Association and Kuoni for making this an unforgettable event. 

Dec 03 2020
Dec 03
Lebkuchenherz undpaul

We really already reached a two digit anniversary. undpaul had its 10th birthday yesterday - and that was celebrated! With hot wine, delicious food, party hats, and memories of one or the other highlight with the undpaul team - of course all compliant with the current Corona situation using a remote meeting.

Ten years it is already... It feels a little bit as if it was only a few moments ago that undpaul was founded on a bitterly cold December day 2010 in Hannover. We have experienced and learned a lot during this time, worked on exciting projects and got together with wonderful colleagues.

"The most wonderful Drupal agency in Germany" - says Stefan about undpaul.

That is true so far, we agree. But not only that is what makes undpaul. Of course there are keywords like Drupal, experience, quality and remote work / new work. But above all, our team, collegiality, flexibility, fun, commitment and integration make us who we are.

Karte 10 Jahre undpaul

We are happy that we have come so far together and wish for another 10 wonderful years with you!

Thanks to all of you who have accompanied us so far - to you our business partners with the new challenging projects, to you undpaul friends, to the Drupal community with whom we spent so many hours and of course to the whole undpaul team for the daily fun.

Danke mit Signaturen

P.S. If you want to know something about our beginnings, you can find more information in our blog post for our 3rd birthday. There you will also find answers to the often asked question "Where does the name undpaul come from and who is Paul?".

Nov 10 2020
Nov 10

What the craftsmen use for their workshops is the local development environment for our development team. And we want it to be nice and simple and cosy. After all, we have enough other things to think and puzzle about.

From MAMP/LAMP and Docker to DDEV

In the past, each of our developers had an own MAMP/LAMP setup on his machine. This was easy to set up, worked rather uncomplicated and was also fast. However, over time, more and more problems arose. Among other things, some projects required newer php versions or special server settings that were difficult to reproduce on the local computers. In addition, it became more and more difficult to switch quickly between projects, because you always had to adjust the local configuration of your system.

For this reason we switched to a Docker-based setup for local development. This made it quite easy for us to reproduce the specifics of the servers on which the websites we were responsible for were located. This way we were better protected against unpleasant surprises after deployments - after all, the local development environment was now almost identical to the live server.

Over time, however, disadvantages of our docker setup became more apparent. It was still quite complicated to set up a new project (you had to copy various files to the right places, overwrite settings, ...). There was also a big weakness compared to the old MAMP/LAMP setup: It was not possible to run multiple projects locally at the same time; at least not without manually overwriting some settings. This finally made us rethink our setup and look for better alternatives. This is how we finally came up with DDEV.

What is DDEV?

DDEV-Local - so the complete name - is an open source based tool for software development. It builds up a local web server with the corresponding software packages, through which code can be easily built, tested and deployed. DDEV is based on Docker, but simplifies the work for the development team enormously and offers additional extensions.

Albert Einstein Zitat

Everything for a simple working environment

With DDEV, the initial setup is easy and done in no time. With only three commands in the command line (git clone, composer install, ddev start) a project is now usually set up locally. Two arguments in particular have convinced us to switch to DDEV:

  1. Setting up a local project is wonderfully simple and fast.
  2. We can easily run multiple instances in parallel in the local environment.

As a Drupal agency we work with various customer sites and not every developer has always set up all projects on his machine. With DDEV we now have a significant time saving especially with the changing sprints and security updates. The actual killer feature for us, however, is the parallel operation. During the weekly update evenings we install the latest updates in all our (SLA) customer projects. If every project were to be processed sequentially, our team would hardly be able to manage the updates in one single evening. Thanks to DDEV, we can now easily work on these projects in parallel and don't have to start complex workarounds with Docker. This saves us an enormous amount of time and hopefully long night shifts in the future.

There are other pre-built things for DDEV that simplify the work. For example the command ddev share, which makes the local instance of the page available via a public URL. This is a great way to test local sites on other devices (like the smartphone, tablet).

At https://github.com/drud/ddev-contrib there are a lot of useful examples and templates to extend DDEV. So you can easily add Solr or Varnish to your project setup to be as close as possible to the production environment.

Our summary

DDEV is already simplifying our daily work enormously now that we are using it in the first projects. The development teams can use Docker functions quickly and easily. And another plus: DDEV is not limited to Drupal. So we can recommend it to anyone who works with php projects and also wants to set up different CMS locally.

Oct 15 2020
Oct 15
Serpentinen im Wald

An agency is selected, the goals are agreed upon and the work on the website is commissioned - then it's time to work on the many to-dos. But how do we as a project team always keep an overview and can plan the next steps together? There are task management tools for this purpose. As an issue tracking system, they manage requirements and upcoming tasks for collaborative work.

At undpaul we like to use Jira Software from Atlassian for requirements management. Jira is very comprehensive and thus offers many possibilities for individualization, but is still intuitive to use. With Jira complex processes can be mapped, but also in easy steps an already very helpful tool for joint project work can be created.

Jira configuration in our web projects

Every project and every customer is different. This means that the configuration in Jira is also individual and different in each of our projects. However, a certain basic framework (basic configuration) has proven itself for our Drupal projects.

Manage different requirements with Issues

All requirements are collected in Jira as so-called Issues. We use different issue types to structure the different requirements.

  • A story describes a new feature or function for the website. Since we work according to Scrum, the story (in Scrum "User Story") focuses on the end-user perspective and mainly includes the functional acceptance criteria.
  • A task describes a rather technical task that is necessary for the project but has no direct visibility to the end users.
  • A bug describes an unexpected, incorrect behavior on the website, especially for functions that have already been implemented correctly in previous requirements.
  • An epic basically represents a large user story and collects stories and tasks that belong to one topic.

Each issue passes through different statuses during editing. In our Jira projects, we use the statuses mainly to differentiate the degree of completion and the different areas of responsibility. An issue usually passes through the following statuses: In planning - To Do - Needs Info - In progress - Testing - Customer acceptance - Done. The workflow in Jira allows us to control the order in which the issues pass through these statuses.

Views for different purposes

The Jira backlog contains all issues of the project that still need to be worked on and do not have the status "done". It gives us an overview of all tasks still to be done. In the backlog our customers sort the requirements by priority and together as a project team we plan upcoming sprints.

Furthermore, we use two different boards, i.e. different views on the issues. 

The Sprint Board is our working tool in the active development phase, the Sprint. During the sprint period, the development team works its way through all issues on the Sprint Board and pushes them from left to right through the statuses until they are completed. Our customers are directly involved in the development work with the Sprint Board. This is how all communication runs through the Jira comments and issues in the status Customer Acceptance is a work package for the customers.

We use the SLA Board for customers with an active maintenance contract. It is an ongoing collection of issues that are errors on the website or hinder the website. Our customers create these issues themselves in their Jira project, we receive a push notification and can start working on them.

Setting up a free Jira instance

Some of our customers already use Jira within their own company and can add us to their instance for the web project. For other customers, we set up a new Jira instance for our web project. This is easier and (up to a certain point) cheaper than expected: the cloud version is available for up to 10 users for free. In most of our projects these 10 users are sufficient.

Setting up a free Jira project is quite simple. Follow the steps below and in 5 minutes the new project will be ready.

  1. Log in to the Atlassian website with a user account.
  2. Enter a name for the instance.
  3. Invite other users. This is optional and can be done later.
  4. The next step is to create the actual Jira project. Several different Jira projects can be created in one Jira instance.
  5. As a basis for a project we choose the Scrum template. Within the project different boards can be created later.
  6. Enter the name and key for the project and then it is already created.

You can read more about this in the more detailed instructions of Atlassian

Multiple Jira instances at a glance

As an agency, we manage various customer projects in parallel - usually each with its own Jira instance. Not losing the overview can be quite a challenge. 

We found the best solution for us in the Jira Watchtower App. It visualizes issues from different Jira instances in one view. Thus, we have clearly arranged all our project tasks in one undpaul internal board.

Sep 29 2020
Sep 29

"The path is the goal". Heard so often and quoted even more often. However, there is also an important essence in it for our everyday work.

Overall goal of our projects is to create or enhance websites that exactly meet the specific requirements and expectations of our customers. More and more the path determines the success of the results. So we at undpaul decided some years ago to apply agile project management and now follow the Scrum framework.

You do not know Scrum yet? Then have a look at the introduction from scrum.org.

Hikers at Sunset

What does Scrum mean for project work?

Scrum is a framework and provides a foundation. But how do we at undpaul use it for us? How does Scrum affect the projects? We have put together the most important questions here.

How does a web project run with undpaul?

First we agree with our customers on a cooperation and an overall goal, then it really gets started. A very important point is that not all details are determined and defined at the beginning. Instead, we realize the website step by step, in sprints of two weeks each. Each sprint expands the website with new functions and lays the foundation for further sprints. Depending on time and budget on the client side, we process a varying number of sprints per year.

In a digital ticket system (we usually use Atlassian Jira) we manage the backlog. Every member of the project team enters new requirements, change requests or errors into this living collection. Prior to each sprint, priorities and scope of the backlog entries are adjusted, if necessary, to meet the most relevant requirements in the upcoming sprint.

When the scope for a go-live is reached, the site goes live. From that point on, it belongs to the support/maintenance scope for us. If further adjustments or enhancements are pending, we plan these bundled in further sprints.

How does a sprint at undpaul work?

Together with the customer we define a time frame for the sprint. After all, everyone on the project team has to be available for the short sprint period and close cooperation.

With the preparation phase (grooming), we ensure that the requirements are defined in a clear and comprehensive way and that they are understood by the project team. What is possible and reasonable? What is unnecessarily complex? In most cases, a lot of discussion, additions or changes are made to ensure that the feature offers real added value for the end user.

In the planning meeting, the official start of the sprint, the development team estimates how many of the requirements can be realized during the sprint period. During the sprint, the requirements pass through various states: from implementation through internal developer QA to customer approval and deployment on the website. The dailies are the daily status update for the entire project team. Here we often clarify queries that have arisen during development.

With the end of the sprint period the sprint ends. The sprint board shows the result. At best, all issues are listed in the state "done" on the far right, i.e. they have been accepted by the customer and deployed on the website.

How do you involve the customers?

Regardless of the project management method, we see the collaboration as an equal give and take. We (from undpaul side and customer side) have a common goal and each member accomplishes important tasks and responsibilities. Through the Scrum process we involve our customers in the complete development phase and see the foundation in communication and transparency.

In the project teams we gladly hand over the role of the Product Owner to employees from the customer side, because they know the end users and their use patterns best. This means that a lot of responsibility for requirements, priorities and the release of new features is with our customers. Much of the preparatory work is done by the Product Owner with the support of the developers in grooming and planning. This determines the direction of the sprint. In the dailies, the Product Owner is welcome to get a daily overview of the current development status or to help with further questions.

What advantages do I have as a customer with the agile approach?

By now we have taken over many externally developed projects, as customers have requested more prompt communication and transparency. Our Scrum process helps enormously with these two points in particular, since the customers are involved in the entire development process: Among other things, they manage the backlog, communicate directly with the developers in the sprints, have access to the sprint board and can give immediate feedback at any time. The daily updates in the Daily allow for early coordination if a requirement exceeds the time frame.

Another advantage of Scrum is the focus on user-oriented and timely usable solutions. By working out the requirements together, an early exchange on usability, technical implementation or further development possibilities is created. Looking at things from different angles has often brought the project teams to good, new ideas.

New requirements are developed as a completed user story in a sprint. Thus, they are fully executable at the end of the sprint and the progress of the website is quickly visible.

Mann auf dem Gipfel
Apr 12 2019
Apr 12

For us, the Paragraphs module is the holy grail of structured content creation.

With Paragraphs it is relatively uncomplicated to define prefabricated content elements that define the structure of the corresponding content. These can then simply be placed in the desired content by editors.

Paragraphs default display

This allows editors to create clearly structured content without a lot of effort and to fall back on recurring content structures. The editors simply select the desired element from the list of available content elements, fill in the corresponding fields and the content is output in the specified structure. This is extremely helpful when creating more complicated page layouts where you want to use the same structures over and over again.

Is there a better way?

We have asked ourselves and our clients' editors how to further simplify and improve the input using Paragraphs, or what might interfere with the editorial process when using Paragraphs.

It has often been mentioned here that it is quite annoying to have to drag the content elements to the desired position after adding them. This is especially cumbersome for content with many content elements. It would be much better to be able to insert the element right at the corresponding position.

Paragraphs with add_in_between

Fortunately, there is the Paragraphs Features module from the Thunder Core team. This module extends Paragraphs by inserting a button between each content element to open the modal dialog for adding more elements. 

Using these buttons, editors can insert the elements in the correct position as desired and do not have to move them first.


Beautiful. But is there an even better way?

Editors always add the same elements to certain content. The question arose whether these content elements could not be inserted preferentially, i.e. without first having to open the dialog.

In addition, some editors were disturbed by the large number of buttons: after each single content element a button for adding further elements appears. *sigh*

So we thought about how to make the buttons less annoying. 

Buttons you don't see don't interfere. Accordingly, with our new module Paragraphs Editor Enhancements, we have simply hidden the buttons. 

With some applications and tools (e.g. Apple Mail or Slack) the buttons for certain actions only become visible when you point the mouse over a certain area. Exactly this function has also been implemented for the buttons: only when you point the mouse over an existing content element, the buttons for adding become visible above and below the element.

new styling for Paragraphs add_in_between

In addition, the most important content elements should also be able to be inserted directly with a click. 

So we had to add two new buttons for the most important content elements to the button to open the dialog.

Editors are no longer disturbed by the large number of buttons and can simultaneously insert the most important content elements with just one click.

Great! But can you make it even much better?

Another often mentioned improvement suggestion concerned the dialog for adding content elements themselves.

Paragraphs dialog

If you have many elements to choose from, the dialog quickly becomes confusing. In addition, editors often find it difficult to find the right elements. On the basis of the title of a content element one cannot always immediately conclude on the actual purpose of the element and cannot imagine how the element is represented in the content.

With Paragraphs Editor Enhancements we have completely redesigned the dialog. We've added the ability to filter the list of content elements so editors can quickly find the desired elements through the title and description of the element.

redesigned Paragraphs dialog

In addition, the representation of the elements in the dialog has been revised. Each element shows the title and the description as well as an image (if uploaded in the element's configuration).
As an alternative to displaying the elements as tiles, you can also display the elements as a list.

As a bonus, you can create categories for content elements and assign the individual elements to one or more categories. 

This gives editors a faster and better overview of the available content elements and allows them to find the desired element more quickly and easily.

Whew. Do you have any more?

We wouldn't be undpaul if that was all.

Some time ago, one of our clients was faced with the problem of having to add the same elements in the same order over and over again. 

As a simple example, one can imagine this as follows: an introductory text followed by an image, then a two-column text and finally a text with an image.

For the editors, this meant that the corresponding content elements had to be inserted in the correct order for each individual content item. 

Wouldn't it be great if you could add the desired elements with just one click, so that the editorial staff could concentrate on entering the actual content?

redesigned Paragraphs dialog with Paragraphs Sets

The solution to this problem was the Paragraphs Sets module.

Paragraphs Sets are used to define groups of content elements. These groups can be added to the content just like the usual elements.

This saves editorial members the hassle of searching out and inserting individual elements and allows them to start entering the corresponding content directly.

Of course, Paragraphs Editor Enhancements and Paragraphs Sets also work together. The element groups of Paragraphs Sets are displayed in a separate category in the dialog and can also be found using the filter function. 

Jul 31 2018
Jul 31
Day Orange 04.08.2018Quelle: Facebook

On August 4th 2018 the so-called Day Orange took place. The day was organized by Seebrücke, an organization that expresses solidarity with all people seeking refuge and demands safe escape routes, as well as a decriminalization of sea rescue and a humane welcome of people who had to flee or are still on the run.

We wanted to show our support and transformed our usual green logo icon into an orange heart for Day Orange.

On Day Orange, all people who wish to support the organisation and its goals were invited to show solidarity with the refugees and the many volunteer rescue workers. It is not even necessary to go to a demonstration, but rather to stand up for something together, whereby the colour orange can be used in different ways to show solidarity.

Unser Seebrücke-Logo

We very much welcome this commitment and show our support with our logo. We show our colours, we are orange.

Mar 09 2018
Mar 09
Gruppenfoto Splash AwardLars Stauder Photography Drupal Business Deutschland e.V.

On the 8th of March 2018 it was time again, in Frankfurt the Drupal Splash Awards 2018 were awarded in the Brotfabrik. The aim of the award is to show special Drupal projects and give them a stage. Jeffrey A. "jam" McGuire, Marcus Maihoff, Robert Douglas, Meike Jung, Rouven Volk and Marc Dinse were among the international jury this year.

The nominees

In total, 27 German projects were nominated this year. There have been various great projects, etc. filed in the fields of e-learning, e-commerce, non-profit, government or publishing/media. All nominees you can find here. We entered the race this year with our project ispo.com in the category publishers/media. Other contenders for the coveted award in this category were the SUPERillu (by UEBERBIT), Der Nordschleswiger (by Comm-Press) and Das Haus (by Galani Projects).

The Splash Award was international

New this year: for the first time there were also ten Austrian nominations. The Austrian Drupal community actually had the goal also to host a national competition for Drupal projects. However, there were not enough applicants, that’s why the German Splash Awards organizing team assigned the austrian colleagues an extra category. In the specially established categories "Austria", "E-Commerce", "Enterprise" and "Publishing / Media", all Austrian projects competed against each other.

The award

As in the previous year, Jeffrey A. "guided" McGuire through his presentation in a charming manner, presenting the nominated projects in each category. Compared to the previous year, significantly more spectators appeared for the award and so there were in addition to the awards also a lot of new contacts to win. All nominees received certificates and the agencies with the winning projects also took a nice, blue award back to the office.

The winners

We are pleased to have been nominated for this year with our project ispo.com in the category publishers / media. We congratulate our colleagues from Galani Projects, who won the Splash Award in the category publishers / media with their project Das Haus. More winners of this year will be available soon here.

Review Splash Awards 2017

Jan 24 2018
Jan 24
Splash AwardsSplash Awards Deutschland

For the second time, the Splash Awards Germany will take place on March 08, 2018. The awarding of the coveted prize for successful Drupal projects takes place in the Brotfabrik in Frankfurt am Main.

About the Splash Awards

Originally, the award ceremony for the Splash Award comes from the Netherlands. Since 2014, Drupal service providers have been awarded who realize extraordinary projects. Various interesting projects from different areas are presented and judged by a jury. 


Nominations are available in the categories Education, E-Commerce, Enterprise, Healthcare, Solutions, Non-Profit, Government, Social / Community and Publishing / Media. Agencies and freelancers will be able to submit their projects to the Splash Awards 2018 upto 31th January 2018. The only requirement for participation is a company headquarters in Germany. Sponsors are still accepted. 

This year, we submitted our project ISPO.com in the category publishers/media and we are curious to see who will win the race this year. We look forward to lots of interesting Drupal projects and old/new faces from the Drupal community.

Nov 06 2017
Nov 06
Thunder Day am 20.11.2017Quelle: thunder.org

The first Thunder Day will take place on 20th November 2017 in Hamburg at the Wälderhaus. The free event starts at 10:00 am and serves the exchange of experiences in working with Thunder. The day should also show users the benefits of Thunder with showcases.

The Guests

The event's guests include not only publishers, but also agencies that have successfully implemented projects with the help of Thunder. Therefore, members of the undpaul team will also be present and share their experiences at the event with others. Johannes Haseitl will present a case study on our most recent project ISPO.com together with Peter Bilz-Wohlgemuth (CTO of Deutsche Telekom subsidiary The Digitale). A customer representative will share her view of the project with the participants: Saskia Rettenbacher, Senior Manager Messe München GmbH.

Get together

The day will be aligned by Hubert Burda Media, who developed the content management system Thunder for publishers. Starting at 6 pm, a casual get together is planned, where further networking is on the agenda.

We are happy to meet old and new faces on the Thunder Day. Come and get your ticket here

Apr 11 2017
Apr 11

The European Drupal Business Days 2017 take place in Frankfurt from 18.05.-20.05.2017. We are a Platinum sponsor and support the event. In addition, we would like to share our expertise in major publishing projects with Thunder.

[embedded content]

At the European Drupal Business Days, not only decision-makers, marketing managers or CXOs meet, but also customers for Drupal services. The event takes place at the Radisson Blu in Frankfurt am Main. Through the input of the various speakers from very different areas, each participant of the event can learn something new.

Subjects of the sessions are for example: issues such as brand communication or content management topics that help Drupal projects to success. In addition, social media strategies play a role as well as project management in Drupal projects. Total should be taught how Drupal projects become successful.

The keynote speakers

Here are some of the great speakers this year:

  • Collin Müller, Business Development, from Hubert Burda Media
  • Zach Chandler, Web Strategist at Stanford University

Anja from undpaul will give a lecture as part of Collin Müller's keynote session on "Our experience with Thunder in the real world". Another keynote speaker from Vodafone is planned, but not fixed yet. More information about all the entries submitted so far, you find here: Sessions.

Get in Touch in Frankfurt

Do we meet in Frankfurt? Now secure tickets under www.drupalbusiness.org

Mar 16 2017
Mar 16
undpaul Team bei der Entgegennahme des Splash Awards 2017 in der Kategorie Verlage/Medien

The Splash Awards 2017

We were there: at the first German Splash Awards 2017 in Hamburg. The award show with Dutch roots took place for the first time in Germany.

Above all, the Splash Awards are designed to honor those who make remarkable use of Drupal. Not only Drupal agencies, but also individual Drupal developers are taken into account with their submitted projects. In addition to eight awards, a Drupalista of the Year was also selected. The Drupalista award is designed to highlight the people who have made a significant contribution to the Drupal community and have been specially dedicated to the Drupal community last year.

The nominees, the categories and the jury

27 projects were nominated in nine categories. The submitted projects were diverse and came from different fields such as the food, health, e-learning, chemical and publishing industries. undpaul was nominated in the category publishers/media with the project "Mein Schöner Garten". The jury of the Splash Awards 2017 included Jeffrey A. "jam" McGuire, Robert Douglass, Meike Jung, Rouven Volk and Marc Dinse.

The location

In the heart of St. Pauli, the award ceremony took place in two locations in the clubhouse. The reception as well as the after show party were arranged at kukuun, while the actual awarding took place at Häkken. The exceptional location, the professional service staff and the successful aftershow party put the awards uniquely in the scene.

The winners

All winners in the respective categories can be found here.

undpaul wins Award

We are proud to have received the award for best project in the category publishing & media. A big thank you to everyone involved!

Feb 17 2017
Feb 17
Screenshots des Zeitungsartikels über undpauls neuen iranischen Kollegen Siavash Torkzaban in der Hannoverschen Allgemeinen Zeitung

Recently the German newspaper HAZ visited us to talk about our new Junior Drupal Developer Siavash. A positive example for the integration of a refugee on the German labor market should be presented and brought to the public. In the article, Siavash recounts the bureaucratic hurdles he had to overcome until he could finally work at undpaul. He still has to wait, be patient and hope his asylum application is successful.

Originally Siavash did not want to go to Germany but to Canada. Now he is learning both German and Drupal and is not afraid of the complexity of the task.

View the newspaper article on haz.de.

Sep 23 2015
Sep 23

We folks at undpaul love Drupal swag. At DrupalCon Amsterdam, we gave away over 500 shirts for free, which was a huge success. 

This year, we wanted to create something more unique. Since we all love festivals and DrupalCon, we merged both worlds and created a very special poster for you guys. We made a poster with every speaker who is presenting at DrupalCon Barcelona. If you are holding a session, you received a poster from the lovely people at the Drupal Association when they gave you your registration goodie bag. If you are not a speaker, you can still download the poster and print it out yourself and make your office a little bit more beautiful.

Mar 23 2015
Mar 23

In December 2013, Packt Publishing asked us to write a book about the upcoming Drupal 8. They had seen the Drupal Association survey that showed the new feature Configuration Management was the most popular topic they wanted to learn about in Drupal 8. Since we are long-time evangelists of tracking configuration changes in code, we were excited about having the opportunity to write this book, which is expected to be published in March 2015 (like this week!). It's even more exciting because Packt actually donates a portion of sales of Drupal-related books to the Drupal Association. For this to work, you need to order or pre-order directly at Packt.

Since we did so much testing with and writing about Drupal 8, we also wanted to build something with it. So we built a microsite for the book and we were surprised about how smooth this worked. It took 9 hours on a Sunday to find an appropriate HTML template, install and configure Drupal and make it look the way it does now. After the book is published, the site will get some more functionality so we can publish questions and answers as well as errata. Since it will be quite a while until Drupal 8 is actually released, we are expecting there will be a few changes and some of our code might become outdated.

You can read a sample chapter in an article on Packt's website.

What will be in the book?

Chapter 1, Understanding Configuration Management, will give you a quick overview of Configuration Management. You will learn what types of configuration exist, why managing configuration is a good idea, and how to get started with it. It will provide a look at the several ways in which configuration was managed in Drupal 7 and then show how Drupal 8 approaches the problem.

Chapter 2, Configuration Management for Administrators, provides an introduction on how to use Configuration Management for users who are not developers, but administrators of a Drupal website who want to make use of the advantages of this new feature. We will show you how to use the Configuration Management interface and how to create a copy of your website, and you will learn how to move a configuration made on one site to another site.

Chapter 3, Drupal 8's Take on Configuration Management, will show you the inner workings of the Configuration Management system in Drupal 8. You will learn about config and schema files, and read about the difference between simple configuration and configuration entities.

Oct 21 2014
Oct 21

Don't you know that, too? You or your team is building a site and during this process all implemented parts are styled through templates and CSS. The CSS files (at best you are using a CSS preprocessor like SASS are getting bigger, more sophisticated and even more confusing - not to mention that these files are getting almost unmaintainable and more and more error-prone. Of course you can reduce risks a little by sticking to standards like SMACSS, but you will reach a point where it is almost impossible to keep track of all changes - especially when a team of several members is involved.

By now at the latest, you should have a styleguide that provides an overview of all styled components of the site... But where will you find the time to create one now? And who takes care of it to ensure that all future components will be included? There is a simple solution - the Living Styleguide!

At DrupalCon Amsterdam 2014 there was an interesting session by John Albin Wilkins, which covered this topic. Apart from an introduction about agile development, he explained in detail how team members may automatically create a styleguide during the development process by using the Knyle Style Sheets (KSS) tool or more specifically by its Node.js implementation kss-node. This automated styleguide allows to examine and review every component of the site on its own - even without the context of the actual site itself.

Sounds complicated, but it isn't!

kss-node is easily installed by the help of Node Packaged Modules with a one-line command (`$ npm install -g kss`). Now you only need to place a `styleguide.md` file in the source directory of your style files (the directory containing e.g. CSS, SASS or LESS files), which is used as the entry page for your styleguide and may be filled with any generic information about your project at will.

The following command then generates the styleguide:

$ kss-node "path/to/styles-directory" "destination/of/styleguide-files" 

Visit the kss-node project page for a full reference of the `$ kss-node` command.

The styleguide directory now contains all generated styleguide files. But wait... apart from the entry page, which was generated from the `styleguide.md` file, it is completely empty?!

This happens, because we do not provide any real data for the parser yet. But this is also done in a breath: With the help of simple annotations in the comments of your style files, you may provide information about the expected markup and its corresponding styles. It is even possible to provide Modifiers for different states of a component (e.g. `:hover`- and `:active` state of a button). Here is a basic SASS example:


// Buttons


// Just add your descriptive text about buttons here //

// Styleguide 1

// General styles


// Add even more descriptive text...


// :hover - State: Hovered

// :active - State: Active

// .btn-medium - Size: Medium

// .btn-large - Size: Large


// Markup:


// // Label




// Label



// Styleguide 1.1

.btn {

background: #83B81B; border: 2px solid #83B81B; color: #fff; font-family: sans-serif; font-size: 0.75em; padding: 1em; text-decoration: none;

&:hover {

background: #fff;

color: #83B81B;

} &:active {

background: #fff; border-color: #000; color: #000; } &.btn-medium { font-size: 1.25em; } &.btn-large { font-size: 2em; } }

Visit the KSS projct page for a full annotation syntax reference.

Et voilá: After running the `$ kss-node` command explained above again, the styleguide now contains a new Buttons section, which provides previews for all Modifier variants of the button component.

More styleguide examples

And there is even more...

  • As Markdown is supported, all annotations may contain any Markdown syntax
  • Use `$ kss-node --init "your-template"` to initialize a custom styleguide template, which then may be adjusted to all your special needs. Add the `--template "your-template"` option when running `$ kss-node` to use this template for generating the styleguide
  • Generation/updates of a styleguide may be automated with a task manager like Gulp
  • ... Everything else is up to you!

It will be interesting to see how this tool will mature in the future and if there will even be a Drupal integration for the automated generation of all the source code snippe

May 26 2014
May 26

We are always on the lookout for new clients. And there are many clients looking for services like ours. Some clients know they want Drupal. Others still have to be convinced. Especially here in Germany, we have to compete against TYPO3, because it's an established content management system for the enterprise. We believe Drupal is similar or superior to what TYPO3 and others can accomplish, but it's not easy to convince others about it.

In order to win a client, you might list some advantages of Drupal and show some of the sites you've built with the system. However, you can't show the backends of most sites you've built for clients and a plain install of Drupal is not very convincing.

A demo system is a great way to show the potential of Drupal, but creating your own is time-consuming to build and maintain.

Gladly, Acquia provides a free demo distribution called Demo Framework. The demo is a personalized, multilingual platform with modern responsive capabilities including previews for different devices. With its beautiful interface and sample commerce and multimedia integration, it's perfect to show just what our favorite content management framework Drupal is capable of.

Acquia also created 6 short videos to present the Demo Framework distribution. It's worth taking a look!

You should also check out jam's (virtual) Drupal Camp session with Brant Wynn who talks about the Demo Framework in a Google Hangout.

Download the distribution at drupal.org or join the discussions at groups.drupal.org.

We are also very excited that Acquia announced hiring Tim Plunkett last Friday, who will be a great addition to the Demo Framework team.

Check out some screenshots of the system:

Very modern and minimal presentation with responsive images.

Information and travel guides about tours can be viewed here. For more details and discussions you can join a tour group. Once you're convinced, you can purchase the tour, which will be added to your cart.

Overview of products in the backend. Existing products can be edited here and new ones can be added.

The view an editor has when editing content. Content can be saved as drafts, moderated and translated to other languages.

The Demo Framework supports a responsive layout and includes an ability to define different breakpoints and have the resulting look in several devices displayed right in the browser.

Feb 13 2014
Feb 13

This year Google celebrates the 10th birthday of their global program „Google Summer of Code“. The open source program offers student developers over the age of 18 the possibility for a scholarship. Mentoring organizations' application deadline is February 14th.

Google Summer of Code (GSoC) is very popular amongst projects of the open source scene, because students can take on tasks that otherwise wouldn't get done. Participants earn scholarship funds of 5.500 USD, of which 500 USD go to the specific project and their mentors. This concept has a very high success rate and the participator list shows almost all popular open source projects.

We at undpaul love Drupal and the open source idea, which is why we decided to provide mentors to support the development of the Drupal modules FluxPocket, Leaflet and Paragraphs. You can view our proposals in the Task Organization Wiki at groups.drupal.org.

Also make sure to check out these links if you're interested in mentoring or applying for a scholarship.

"Google Summer of Code" Logo from Google is licensed under "CC BY-NC-ND 3.0".

Jan 17 2014
Jan 17

In every Drupal project, it is crucial for your application to be fully defined in code at every time and every state. When working with a configuration management based upon Git (www.git-scm.com/), Features (www.drupal.org/project/features), Drush based shell scripts (www.undpaul.de/en/blog/2013/06/26/simplify-your-development-workflow-dr…) and Master (https://www.undpaul.de/en/blog/2013/06/28/introducing-master-drupal), it is possible to represent your whole Drupal 7 application's configuration state in a traceable and reproducible way.

Watch your Drupal modules

This way your team has a good tool to manage the development of the application and even manage the state of the Drupal modules in your application. Especially in large Drupal projects it is always important to know the modules you are dealing with, what modules to enable and to know what modules you can disable. Even already disabled Drupal modules influence your system and the overall development experience of your team.

For example, if you provide a large set of modules in your project, there will be a lot of noise for the developers when working on the sprint issues (e.g. a developer might find search results in the IDE for a code snippet in modules that are not meant to be enabled anymore). Therefore it is important all modules that should not be enabled are really disabled and uninstalled from the Drupal project. And, if possible, after that the modules should be removed from the file disk. As we are (hopefully) always dealing with a version control system like Git, we are safe to remove those modules without losing any information of the project's evolution.

Remove modules with Master

In projects that have grown for several months and no-one had a look at the modules directory, it will be very painful and time intense to remove those obsolete modules. To ease such tasks in the development workflow, we created the Master module some time ago. With the latest release of Master  (www.drupal.org/project/master), we have also introduced a new command to assist you in finding the modules you really don't need anymore in your directory.

With drush master-removables you will get a list of Drupal module directories that can be removed from the project's file system. When combining the command with the remove command, you can delete those modules from the file system:

rm -rf $(drush master-removables --absolute --pipe)

Make sure you checked the output of drush master-removables, especially when dealing with multiple environments (like develop, testing, live), you have to make sure all modules you are about to remove from the filesystem have been properly uninstalled before. For example, in Sprint 11, when your team decides they will not work with the Context module anymore, but it already has been rolled out and enabled in a previous sprint, they cannot simply remove Context from the Git repository in Sprint 11. That's because the module will be needed to successfully fire the uninstall procedure on the production-installation for that module in the next roll-out. So you may only fully delete the module after the roll-out was successful and make that change in the next sprint.

Tip: When you stumble upon such a situation, simply remind yourself for this task in the next sprint by creating a new related issue in the backlog for that upcoming sprint.

Absent modules

In some cases, e.g. when carelessly updating or removing modules, there might be modules missing, although the Drupal installation needs them to be enabled. For example some module was removed although the module was still enabled. This might be a heavy performance impact, as Drupal will scan the module directories several times each Drupal bootstrap. This would be not good. To make sure we do not run into this scenario, the newest Master release also contains a command to list those modules that are not in the installation but should be present. With `drush master-absent` you will get a list of those modules and can fix the problems.

The command will also list those modules that are part of the master configuration or an unmet dependency of the master modules and are not present in the module directory.

Master development

We are curious about your experience with Master or other approaches of managing your modules' state. As we are currently working on a stable release for Drupal 7 your feedback is very welcome in the Master issue queue on www.drupal.org/project/issues/master.

If you need any help in your Drupal development workflow, we will be happy to help with our professional Drupal service.

Oct 16 2013
Oct 16

In a recent project, we had to provide a way to easily limit the amount of menu items for several menus separately. Drupal does not provide this functionality out of the box so we had to hit the keyboard and take care of this functionality on our own. The result is our newest contrib module Menu Item Limit.


Installing the module is easy and does not require any magic. Just drop it in your sites/all/modules/contrib/ folder with the rest of your contributed modules and activate it on the modules page.


Per default, every menu has the ability to hold unlimited amount of menu items. You can set a custom limit by editing a menu on /admin/structure/menu, i.e. the main menu. Enter any number you want greater than 0 to set a limit. Entering 0 will remove the limit.

That's pretty much it. Now you have a nice and easy way to control your menus.

Jul 17 2013
Jul 17

When building sites for our customers we usually create some administrative views (like for content or user administration) to make it easier for editors to work with the site. For a little more user experience we modify these views (especially the exposed form providing the filters). One of these modifications is to create a "collapsible" filter dropdown.

The Mission

Think of a content administration view with filters for content type, status, author and so on. Normally the filter for the content type allows multiple selections and would look similar to the one in the image.

But we want the filter to act as a single dropdown that could be expanded to a multi-select list if the user wants to filter for several types.

The Solution

To achieve this we need a small custom module and alter the exposed form:

  1. /**

  2.  * Implements hook_form_FORM_ID_alter().

  3.  *

  4.  * Alter views exposed forms for collapsible filters.

  5.  */

  6. function MYMODULE_form_views_exposed_form_alter(&$form, &$form_state) {

  7.   if (empty($form_state['view']) || !in_array($form_state['view']->name, array('NAME_OF_VIEW', 'NAME_OF_VIEWS_DISPLAY'))) {
  8.     // We alter the exposed form of a single views display, so return if this is

  9.     // not the expected view.

  10.     return;

  11.   }

  12.   if (isset($form['type'])) {
  13.     // Add option to select all items (equals to resetting the filter).

  14.       'All' => variable_get('views_exposed_filter_any_label', 'new_any') == 'old_any' ? t('') : t('- Any -'),
  15.     );

  16.     $options += $form['type']['#options'];

  17.     // Change size of field based on number of options (max: 5 items).

  18.     if (count($options) <= 2) {
  19.       // Hide filter if there is only one option available (additional

  20.       // to "All").

  21.       $form['type']['#access'] = FALSE;

  22.     }

  23.     $form['type']['#options'] = $options;

  24.   }

  25.   // Alter multi-value dropdowns.

  26.   $form_multiple_selects = array();
  27.   foreach (element_children($form) as $element_name) {

  28.     if (isset($form[$element_name]['#type']) && $form[$element_name]['#type'] == 'select' && !empty($form[$element_name]['#multiple'])) {
  29.       $form_multiple_selects[$element_name] = array(
  30.         'size' => isset($form[$element_name]['#size']) ? $form[$element_name]['#size'] : 5,
  31.       );

  32.     }

  33.   }

  34.   if (count($form_multiple_selects)) {
  35.     $form['#attached'] += array(
  36.       'js' => array(),
  37.       'css' => array(),
  38.     );

  39.     // Attach custom javascript to the form.

  40.     $form['#attached']['js'][] = drupal_get_path('module', 'MYMODULE') . '/js/MYMODULE.admin.js';

  41.     $form['#attached']['js'][] = array(
  42.       'data' => array(
  43.         'collapsibleFilter' => array(
  44.           'multiple_selects' => $form_multiple_selects,

  45.         ),

  46.       ),

  47.       'type' => 'setting',

  48.     );

  49.   }

  50. }

  51. ?>

Unfortunately we have to do some more magic to avoid errors after selecting the new option "All". Because we manually added the option in the form-alter, Views does not know about it and would throw an error after selecting it. The simplest way to avoid it, is to remove the filter value before displaying the results:

  1. /**

  2.  * Implements hook_views_pre_view().

  3.  */

  4. function MYMODULE_views_pre_view(&$view, &$display_id, &$args) {

  5.   if (!in_array($view->name, array('NAME_OF_VIEW', 'NAME_OF_VIEWS_DISPLAY'))) {
  6.     return;

  7.   }

  8.   foreach (array('type') as $filter) {
  9.     if (!empty($_GET[$filter]) && (is_array($_GET[$filter])) && reset($_GET[$filter]) == 'All') {
  10.       // Remove the filter value because it is manually added and thus

  11.       // unknown to Views.

  12.       unset($_GET[$filter]);
  13.     }

  14.   }

  15. }

  16. ?>

Finally we add our JavaScript to append the "plus sign" to the dropdown and add the "collapse" functionality:

  1. (function($) {

  2.   /**

  3.    * Change multi-value dropdown to single-value dropdown and back (visually).

  4.    */

  5.   Drupal.behaviors.collapsibleFilterRewriteMultipleSelect = {

  6.     attach: function(context, settings) {

  7.       $.each(Drupal.settings.collapsibleFilter.multiple_selects, function(name, settings) {

  8.         $('select#edit-' + name)

  9.               .once('collapsible-filter-multiple-rewrite')

  10.               .each(function() {

  11.           var selectionCount = $('option:selected', $(this)).length;

  12.           if (selectionCount <= 1) {

  13.             // Set size of select to 1 if there is not more than 1 selected.

  14.             $(this).attr('size', 1);

  15.             // Remove attribute "multiple".

  16.             $(this).removeAttr('multiple');

  17.             // Set default option.

  18.             if (selectionCount === 0 || $(this).val() === 'All') {

  19.               $(this).val('All');

  20.             }

  21.             // Add link to expand the dropdown.

  22.             $expand = $('')
  23.                     .addClass('select-expander')

  24.                     .attr('href', '#')

  25.                     .attr('title', Drupal.t('Expand selection'))

  26.                     .html('[+]')

  27.                     .click(function() {

  28.                       // Get corresponding select element.

  29.                       $select = $(this)

  30.                               .parent('.form-type-select')

  31.                               .find('.collapsible-filter-multiple-rewrite-processed');

  32.                       // Expand element.

  33.                       $select.attr('size', settings.size)

  34.                               .attr('multiple', 'multiple');

  35.                       $(this).remove();

  36.                     })

  37.                     .appendTo($(this).parent());

  38.           }

  39.         });

  40.       });

  41.     }

  42.   };

  43. })(jQuery);


After you have all this together, users will be able to choose whether to select a single type from a dropdown or multiple values from a list. If a user selected multiple values the filter automatically displays as select list. 

Jul 04 2013
Jul 04

This post adds to the successful and popular "Theming in Drupal 8 with Twig?" (Part 1, Part 2) series from Steffen. It deals with converting Drupal phptemplate themes to use the new Twig template engine, like we recently did with our Busy theme. This is all for Drupal 8, so this might not be helpful to you just yet, but if you wanna get a headstart on converting your phptemplate theme to Twig, nothing's holding you back from starting right now! If you don't know how to get your Drupal 7 theme to Drupal 8, there's an older write-up on how to convert a Drupal 7 theme to Drupal 8 in our blog (keep in mind that things in Drupal 8 change rapidly so some of that text might already be outdated).

First of all, Drupal 8 has Twig as its default template engine. That means if you don't write any other setting into the THEME_NAME.info.yml, Drupal will use Twig as its template engine. So, if the current theme is based on phptemplate, you must delete the line "engine: phptemplate" from your THEME_NAME.info.yml. In the following example it's line #5.   

  1. name: Busy

  2. type: theme

  3. description: 'The ultimate Drupal business theme.'

  4. core: 8.x

  5. engine: phptemplate

After that you can start with the "real" rebuilding. Make sure you know the basic syntax and features of Twig.

Copy the template file and rename it from TEMPLATE_NAME.tpl.php to TEMPLATE_NAME.html.twig. Then you have to look at each line and replace PHP commands with Twig commands. The following example shows you such a conversion of a template file:

Similar conversions have to be applied to arrays and loops.

  1.   {% set users = ['Paul', 'Guenther', 'Max'] %}
  2.   {% for user in users %}
  3.     {{ user }}  

  1. $users = array('Paul', 'Guenther', 'Max');
  2. foreach ($users as $user) {

  3.   echo $user;

  4. }

If you like to save some time, there is a nice Drupal 7 module called Twigify (sandbox-project). It tries to convert your theme automatically from a phptemplate theme to a new Drupal 8 Twig based theme. But keep in mind: complex code still needs to be edited manually.

So, don't be afraid of converting your themes to use the Twig template engine, it isn't that hard.

Jun 28 2013
Jun 28

Whenever working in a Drupal project you have to deal with a bunch of modules - core, contrib, custom and features. In the lifetime of a project you enable new ones and disable and uninstall modules you don't need anymore or replaced with a better one. But how do you track that, and how do you make sure that those modules that should not be active really are not?

I did not find any existing solution in the Drupal contrib modules that deals with this issue, so I wrote a small helper module: Master.

Master Yoda icon designed by Artua

Drupal module whitelists with master

You really should know and should define what modules have to be enabled to fulfill the project's functionality. Those modules that are meant to be active should be defined to be active in a way. With master you got a tool to whitelist those modules that have to be active. We call those modules master modules.

Configuration in settings.php

This is done by simply defining $conf['master_modules'] in your settings.php:

$conf['master_modules'] = array( 'myworld_news', 'myworld_contact', );

Module dependencies

Modules that are not in this whitelist may also be required by those modules. Therefore master also takes care of module dependencies. So if your module myworld_news needs node, features, strongarm and views enabled, you do not have to write those modules in your $conf['master_modules'], you simply place those as dependencies in your myworld_news.info.

name = "MyWorld News" description = "News section for my world" core = "7.x" dependencies[] = features dependencies[] = node dependencies[] = strongarm dependencies[] = views

As you might know, Views has a dependency to the Chaos Tools Suite - it is not listed in myworld_news.info as the dependency is already declared in the Views module. Master is aware of that. Modules that are a direct or indirect dependency of a master module are required modules.

Redundant modules

Modules that are no master modules and have no dependency to one of those master modules are meant to be redundant. They shall not be active in the given site. If you want a redundant module to be meant to be active, you have to define it as master module (add it to settings.php configuration) or add it as a direct or indirect dependency of one of the master modules.

Using master

So how can you use that? After you defined your modules in your settings.php, you can use drush commands to check the status of the module whitelist and to ensure the intended module status.


drush master-status [--status=…] [--pipe] [--sort] [--scope=…] [--skip-scope-validation]

With the master-status command you will get an output of the current state of your master modules and their dependencies. So you can make sure certain modules are active or disabled.

The command lists all modules in specific categories:

  • Master modules: those defined in $conf['master_modules']
  • Required modules: dependencies of the master modules
  • Missing modules: modules that are either master or required, but are not enabled
  • Redundant modules: modules that are not master and not required, but are enabled
  • Uninstall modules: modules that are disabled, not master and not required, but not completely uninstalled

By default the list is printed to the shell in a human readable table with additional information. You can limit the output to specific groups of modules by using --status: e.g. drush master-status --status="master,required" for only master modules and their dependencies. You can use the --pipe option to only return a whitespace delimited list of module names or use the --sort option to sort the modules by name.

The --scope option is for using different sets for different environments. This functionality is described in detail below. By default a scope has to be given, unless you use the --skip-scope-validation option.

Ensure modules

drush master-ensure-modules [--no-disable] [--no-uninstall] [--scope=…] [--skip-scope-validation]

This is the heart of Master. With drush master-ensure-modules you can make sure all modules are enabled, disabled and uninstalled as they are meant to be - in one single command. The command retrieves the information from your master modules configuration. It enables all master and required modules. Additionally it disables and uninstalls all redundant modules.

Especially when using Master the first time, you first should check the status of your modules using drush master-status, because maybe you forgot to put some modules in your configuration or module dependencies. Without any additional option, Master would disable and uninstall all modules that are not defined to be active.

Master will make sure of the order modules are enabled, disabled and uninstalled. Dependency will be enabled first and disabled last. When modules are disabled they are uninstalled before the next module will be disabled (and uninstalled). This way we make sure dependent modules may still be active - just for a reason it might be needed.

Master also makes sure already disabled modules are really uninstalled: in most cases, uninstalling a module means removing tables and variables from the database - this is managed by hook_uninstall() and/or hook_schema().

By using the options --no-disable and --no-uninstall you can avoid disabling and uninstalling modules when using the master-ensure-modules command.

--scope and --skip-scope-validation fulfill the same purpose as in drush master-status.

Different modules on different environments

When you work with different staging environments or even different production environments you may have the need to enable an additional set of modules on these sites. For example you might have a language specific feature for the German website that is not part of the international one, or you simply want to make sure your developers have fieldui_ and devel enabled on the local development environment.

For that use case you can define scope specific additions to the global master module configuration. You will also do that by defining a variable in your settings.php. The variable is called $conf['master_modules:SCOPE'], where SCOPE is the name of the scope (e.g. local or live-de).

$conf['master_modules:local'] = array( 'devel', 'field_ui', 'stage_file_proxy', 'views_ui', ); $conf['master_modules:live-de'] = array( 'myworld_de', );

The listed modules will be merged with the modules defined in $conf['master_modules'] and therefore build a bigger set of master modules.

Note: Instead of listing additional separate modules it might be better to add a "dev-Feature", so you can provide additional configuration too (e.g. for devel).

When using the drush commands, you simply append a --scope=local to the command and the given set will be used:

drush master-status --scope=local drush master-ensure-modules --scope=local

Scope validation

As any accidental deactivation or uninstallation of a module might solve data loss, I implemented "scope validation" for any command. This means that a scope has to be defined for the command being executed.

You define a scope by simple setting an array (at least an empty one) for the scope specific module list:

$conf['master_modules:live'] = array();

When you do enter a scope that is not defined that way or enter no scope, the command will fail with an error The given scope "" is not valid!. This might happen if you accidentally type in drush master-ensure-modules --scope=locla or drush master-status. As said, the error is also triggered, when you enter no scope, so you do not accidently forget to enter your scope name.

You can disable scope-validation by using the --skip-scope-validation option in your drush commands. That way we make sure the user decides to do so.

Do not uninstall

In some cases it might be necessary to not completely uninstall the modules that shall be disabled. That might be the case when you only want to temporarily disable a module and leave content intact for the moment - e.g. you disabled the forum or just want to disable the migrate module for now but keep the migrate mapping tables.

For that case, you can fill your master_uninstall_blacklist in the settings.php with modules that shall not be uninstalled by Master when they are about to be.

$conf['master_uninstall_blacklist'] = array( 'myworld_module', ); $conf['master_uninstall_blacklist:live] = array( 'migrate', );

As you see, there is also a scope specific setting, using master_uninstall_blacklist:SCOPE.

Note: This functionality is no replacement for doing a database backups before changing your code. Be sure to make a backup before you use Master!

How we use it.

We at undpaul simply put the drush commands in one of our update.sh files:


################################################################################ # Enable our modules and features. ################################################################################ # We use the master module for controlling the module status. # @see http://drupal.org/project/master drush $DRUSH_PARAMS --yes pm-enable master # And finally execute master. drush $DRUSH_PARAMS --yes master-ensure-modules --scope=$STAGE_INDICATOR

This is located right before reverting features, so we do not revert old features.

What it (currently) does not do.

Currently Master does not have any UI for the admin backend. Everyone is welcome to contribute to a master_ui, but in our workflow with automated drush deployment scripts, we simply did not need it by now.

Master does not manage any dependencies by downloading missing components from drupal.org or any third party site. I guess this would be some part drush make might be good at.

Additionally I had in mind to provide a command that will delete all of the module projects, that are not in use in the current site, so we do not clutter up our modules directory - especially when we use a VCS.

I'm curious about your comments and maybe some contributions. The project is available on d.o. You're invited to p

Jun 14 2013
Jun 14

CKEditor 4.x has been out for a while now. Something I really enjoy about the new release is the new skin, for which the people at CKEditor ran a contest. The winner of the contest was Moono, but I also really like the silver skin. So today I want to show you how you can change the skin when using CKEditor 4.x in Drupal. There is an overview of skins on ckeditor.com, but there's not much there yet. Moonocolor is worth a look, but we are going to focus on silver, which you can find on Github.

I'm going to show you how it's done by writing just a few lines of code (which stBorchert wrote for me :)) and I'm also including a feature module which you can just throw into your site to get going (make sure to grab a database dump first, just in case).


Here's the code that goes in your custom module's .module file:

  1. /**

  2.   * Implements hook__wysiwyg_editor_settings_alter().

  3.   */

  4. function MODULENAME_wysiwyg_editor_settings_alter(&$settings, $context) {

  5.  global $base_url;

  6.   if ($context['profile']->editor == 'ckeditor') {

  7.    $skins_path = drupal_get_path('module', 'MODULENAME') . '/ckeditor/skins';

  8.    // For flexibility we use a variable to get the active skin name.

  9.    $active_skin = variable_get('MODULENAME_skin', 'silver');

  10.    // Set custom skin.

  11.     $settings['skin'] = sprintf('%s,' . '%s/%s/%s/', $active_skin, $base_url, $skins_path, $active_skin);
  12.   }

  13. }

I created a WYSIWYG feature that serves as my custom module and contains my text format, its wysiwyg settings and the silver skin. If you have WYSIWYG module and CKEditor where they belong (as stated under Assumptions) then you can just download this feature and activate it like you would any other module. I created my own text format so it doesn't interfere with the text formats you might already have on your site. The settings are identical to the Filtered HTML format. Check the .module file of the feature to see above code in action. I have included a README.txt in the feature. You have to switch to text format undpaul WYSIWYG to see the editor in the silver skin.

Download the feature

Get the feature and try it out!

Have fun and let me know what you think.

Jun 02 2013
Jun 02

Back when Drupal 7 was being developed, there was a big inititiative about getting new pretty themes into Drupal core. There were three really good suggestions, one of them being Bartik, which the most people got behind, so it could be finished in time to get into Drupal 7 core. One really good suggestion that couldn't be finished in time was Corolla by Jeff Burnz, which is now a contrib theme. The third suggestion was our theme Busy by eigentor, a theme targeted at corporate websites. Just like Corolla, there wasn't enough time to finish it up for Drupal 7 core. Busy has been a contributed theme ever since, because we didn't want it to get lost only because it didn't make it into Drupal core.

After DrupalCon Portland we got really excited about Drupal 8 so we decided to see how porting Busy would go. Work had to be done to exchange some template variables and rename some files, but it was pretty straightforward and only took a little more than an hour to finish. After twig was moved to core as the new default template engine, some more work had to be done (see "Upgrading a phptemplate theme from Drupal 7 to Drupal 8").

Busy will stay minimally maintained for now, though we might port it to use twig in the future.

If you want a new look for your Drupal 8 site, check out Busy and let us know what you think!

Upgrading a phptemplate theme from Drupal 7 to Drupal 8

So now that twig is in core as the default template engine, how do you port your theme to Drupal 8? We considered converting the theme to twig, but that would take up too much time for now. We just wanted to publish the theme for Drupal 8 as soon as possible. At first of course, we ported the theme to the new structure. These are just a few changes, like renaming the THEME.info file to THEME.info.yml and changing its contents to yml, which is simple. You can check core's bartik.info.yml to see how this needs to be done. Your template.php file is renamed to THEME.theme, the contents of this file didn't have to be changed for Busy. We did have to change some variable names in some of our template files (like the comment template) by referring to core's templates, which are nicely documented within each file. For example, in our comment.tpl.php, we had to replace $picture with $user_picture.

THEME.info.yml file

If you have a phptemplate theme, simply add this line to the theme's .info.yml file:

  1. engine: phptemplate

Without this line you will not even be able to activate the theme.

Menus, breadcrumbs, messages

After adding this line, you might still have problems seeing the theme you're used to. In Busy we got fatal errors due to the way we printed the menus in our page.tpl.php. This is what it looks like in Drupal 7:


And this is what we need to do now to print menus like the main menu in your page.tpl.php:

If you want to add classes or ids to the menu, you can do the following in your THEME.theme file (In Drupal 7 this file is called template.php):

  1. /**

  2.  * Implements hook_preprocess_HOOK() for page.tpl.php

  3.  */

  4. function busy_preprocess_page(&$variables) {

  5.   // Pass the main menu and secondary menu to the template as render arrays.

  6.   if (!empty($variables['main_menu'])) {

  7.     $variables['main_menu']['#attributes']['id'] = 'main-menu';

  8.     $variables['main_menu']['#attributes']['class'] = array('links', 'clearfix');

  9.   }

  10.   if (!empty($variables['secondary_menu'])) {

  11.     $variables['secondary_menu']['#attributes']['id'] = 'secondary-menu';

  12.   }

  13. }

Now if you print variables like $messages just using print $messages, you will not get any output. Look through the code in your page.tpl.php for any print $VARIABLE and make it print render($VARIABLE). We had to do this for $breadcrumb and $messages.

Drupal 8's theming system is still under heavy construction and I'm sure there will be more stuff we'll have to change in our template files very soon, but this way works well for now if you are just interested in porting your phptemplate theme to Drupal 8.

Apr 04 2013
Apr 04

The Views module is the most installed Drupal module and gives great power to developers for building websites. Because of its rich feature set, Views will be integrated in core as part of Drupal 8. Developers may extend the Views functionality by writing custom plugins using the complex plugin system. This helps implementing functionality for special use cases in Views.

In this blog post I would like to explain how to write a custom "Default Argument Handler" for Views and how to develop a simple context system using the Flag module by providing a sample use case as example.

Hint: The complete code of the module can be accessed for testing purposes at github.

The Use Case

Our client produces organic pet food as a family business and wants to increase sales using e-commerce. Furthermore, the daughter of our client will publish a monthly magazine with tips and tricks for each dogs and cats. The magazine should be advertised on the new website of the customer. Older magazine arcticles will be published on the website later on.

A key feature of the new website will be a context system which delivers products and articles to the user based on his favorite pet. We use the Flag module to flag the pets for each user.

Hint: To keep it simple we flag the pets by hand.


Creating flags

First of all we create a vocabulary "flag context" with some terms which will be flagged later.

Afterwards we create a new flag at admin/structure/flags with the flag type "taxonomy term" choosing "flag context" as bundle. 

Extending the content type

By adding an "Entity Reference" field to a content type (i.e. article of the standard profile) we make sure that we can link content to the terms which will be flagged by the user. After adding the field we create at least one node for each term. For this use case we would also need to add this field to our products but this will be sufficient for our example.

Next, we have to flag a term for testing the functionality later. Just visit a term page and flag the term using the link on the page.

Creating Views

The user should see what their favorite pet is. We make this happen by creating a View.

The View filters terms by our created vocabulary "flag context" and has a relationship "Flags: Taxonomy Term flag" on "Flag Context" and  "Current User".  We use "block" as a display for easy embedding.

In addition to the title we also add a flag link allowing the user to unflag the term in the block.  

For testing purposes, we add the new block to the "sidebar first" region. 

At last, we create the basics for our final test. We create a page View showing only "article" nodes. We add "Content:has taxonomy term ID" as "Contextual Filter". This filter will be extended later with our context functionality.

Coding the handler

A views handler has to been included in a module to be recognized by the plugin system of Views. It is not a lot of work but despite that there are some lines where we could struggle. 

1. The .info file

A common pratice is to put views handlers and plugins in their own subdirectorys. Drupal needs to know where those files are located so we include the path into the info file.

  1. name = Views Flag Context

  2. description = Provides a flag context.

  3. core = 7.x

  4. package = Flags

  5. version = 7.x-0.1

  6. dependencies[] = flag

  7. files[] = handlers/views_argument_default_flag.inc

2. The .module file

We need to implement hook_views_api to tell Views that our module is of interest: 

  1. /**

  2.  * Implements hook_views_api().

  3.  */

  4. function views_flag_context_views_api() {

  5.   return array(

  6.     'api' => '3',

  7.   );

  8. }

Now, Views looks for a file with relevant code. Best practice is to create a modulename.views.inc file.

3. The .views.inc file

By implementing hook_views_plugin we return an array in which we define the kind of plugin we like to create and the place where to find it.

  1.  /**

  2.   * Implements hook_views_plugins().

  3.   */

  4. function views_flag_context_views_plugins() {

  5.     'argument default' => array(
  6.       'views_argument_default_flag' => array(
  7.         'title' => t('Default Flags'),

  8.         'handler' => 'views_argument_default_flag',

  9.         'path' => drupal_get_path('module', 'views_flag_context') . '/handlers',

  10.       ),

  11.     ),

  12.   );

  13.   return $plugin;

  14. }

  15. ?>

With these 3 steps we prepared our handler. Now it is time to add functionality to the handler.

4. The views_argument_default_flag.inc file

In this file we define the handler as class by inheriting and overriding methods from the views_plugin_argument_default.

The tree:

  1.  /**

  2.    * Define the options form to enable selection of flags.

  3.    */

  4.   function options_form(&$form, &$form_state) {

  5.   }

  6.   /**

  7.    * Return all possible options for the view and provide default values.

  8.    */

  9.   function option_definition() {

  10.   }

  11.   /**

  12.    * Provide the default form form for submitting options.

  13.    */

  14.   function options_submit(&$form, &$form_state, &$options = array()) {
  15.   }

  16.   /**

  17.    * This function controls what to return to the contextual filter.

  18.    */

  19.   function get_argument() {

  20.   }

  21.   /**

  22.    * Initialize this plugin with the view and the argument is is linked to.

  23.    */

  24.   function init(&$view, &$argument, $options) {

  25.     parent::init($view, $argument, $options);

  26.   }

  27. ?>

First of all, we define the option form of the handler. We want to configure which flags or vocabularys we want to use later. This makes it possible to add other flags or vocabularies very easily. Furthermore, it should be possible to add multiple terms and also to define a fallback if there is no content available. 

To achieve this we get all flags from the system and create a checkboxes form item. It is important to implement the "default value" of the options correctly. The options are available in the views object:

  1. '#default_value' => $this->options['flags'],

  2. ?>

The complete function:


As with all forms we also can add a validate and a submit function. We only add a submit function for now.

  1.   /**

  2.    * Provide the default form form for submitting options.

  3.    */

  4.   function options_submit(&$form, &$form_state, &$options = array()) {
  5.     // We filter the options on only selected ones.

  6.     $options['vocabularies'] = array_filter($options['vocabularies']);
  7.   }

Now we have to override the get_argument() function. This function will return values to the filter in the view.

We compare the flagged content with the values from the options. We filter all term ids by their vocabularies using a helper function. It is important to return the value as a string just as we would call the argument by hand.

  1.   /**

  2.    * This function controls what to return to the contextual filter.

  3.    */

  4.   function get_argument() {

  5.     // Get available flag types from the system.

  6.     $flags = flag_get_flags('taxonomy_term');

  7.     // Get all User flags.

  8.     $user_flags = flag_get_user_flags('taxonomy_term');


  10.     // This array will collect all Term IDs which will be filtered.


  12.     // Get the vocab foreach flag.

  13.     foreach ($flags as $flagname => $flag) {

  14.       // We only proceed with this flag, if it has been selected and the current

  15.       // user has flagged terms with that flag.

  16.       if (!empty($this->options['flags'][$flagname]) && !empty($user_flags[$flagname])) {
  17.         // Get all tids from the user flags.

  18.         $user_tids = array_keys($user_flags[$flagname]);
  19.         $vocabs = array();
  20.         // Check  which vocabularies are valid for this handler.

  21.         foreach ($flag->types as $vocab) {

  22.           if (!empty($this->options['vocabularies'][$vocab])) {
  23.             $vocabs[] = $vocab;

  24.           }

  25.         }

  26.         // We add the valid terms of the flag set to our default argument list.

  27.         $valid_tids = _views_flag_context_filter_tids_on_vocabularies($user_tids, $vocabs);

  28.       }

  29.     }

  30.     // If no tids are valid, we can fallback to a given value.

  31.     if (empty($tids)) {
  32.       // Fall back to the exception value (by default this is 'all')

  33.       return $this->options['fallback'];

  34.     }

  35.     // If there are term ids available we return them by concating the terms

  36.     // with the multiple operator (AND or OR).

  37.     else {

  38.       return implode($this->options['multiple_operator'], $tids);
  39.     }

  40.   }

The helper function for the .module file:

  1. /**

  2.  * Helper to filter tids on given vocabularies.

  3.  *

  4.  * @param array $tids

  5.  *   array of term ids

  6.  * @param array $vocabularies

  7.  *   array of vocabulary machine names

  8.  *

  9.  * @return array

  10.  *   array of terms that live in one of the given vocabularies.

  11.  */

  12. function _views_flag_context_filter_tids_on_vocabularies($tids, $vocabularies) {

  13.   $query = db_select('taxonomy_term_data', 't')

  14.     ->fields('t', array('tid'))
  15.     ->condition('t.tid', $tids);

  16.   $query->innerJoin('taxonomy_vocabulary', 'v', 't.vid = v.vid');

  17.   $query->condition('v.machine_name', $vocabularies);

  18.   return $query->execute()->fetchCol();

  19. }

This is all for the handler.

Next, we add the handler to the contextual filter we recently created.

After applying the changes there should be the article which matches our favorite pet in the preview.


The Flag modules makes it easy to handle user preferences. Page elements can react to different flags and return relevant content to the user by using the handler we created. With a few tricks we can extend the functionality, i.e. adding automatic flagging with rules reacting on content views.

Github: https://github.com/Cyberschorsch/views_flag_context

Mar 26 2013
Mar 26

Sometimes you would like to add a map to a node or block without the need for detailled configuration options. You simply want to display a map and be done with it.
Fortunately this is an easy task using Leaflet.

Say you have a value for the location and one for the country and would like to print this "address" in a map.
So you need to first install Leaflet and Geocoder and then use this function to generate the map:

  1. /**

  2.  * Generate a simple map with a location pointer.

  3.  *

  4.  * @param string $location

  5.  *   Location to use (for example the address).

  6.  * @param string $country

  7.  *   Name of the country to use.

  8.  *

  9.  * @return string

  10.  *   The rendered map.

  11.  */

  12. function mysimplemap_map_create($location, $country) {

  13.   $map = '';

  14.   // Join the address parts to something geocoder / google maps understands.

  15.   $address = sprintf('%s, %s', $location, $country);
  16.   // Try to create a geographic point out of the given location values.

  17.   if ($geo_point = geocoder('google', $address)) {

  18.     // Create a JSON equivalent to the point.

  19.     $geo_json = $geo_point->out('json');

  20.     // Get map implementation provided by http://drupal.org/project/leaflet_googlemaps.

  21.     $map = leaflet_map_get_info('google-maps-roadmap');

  22.     // Set initial zoom level.

  23.     $map['settings']['zoom'] = 16;


  25.     // Decode the JSON string.

  26.     // Create settings for the map.

  27.     $map_features = array(
  28.         'type' => 'point',

  29.         'lon' => $geo_data->coordinates[0],

  30.         'lat' => $geo_data->coordinates[1],

  31.       ),

  32.     );

  33.     // Render the map with a fixed height of 250 pixels.

  34.     $map = leaflet_render_map($map, $features, '250px');

  35.   }

  36.   return $map;

  37. }

  38. ?>

Easy, isn't it?

Feb 26 2013
Feb 26

Following up on the first blog post on Theming in Drupal 8 with Twig, this second part will cover Twig's syntax.

In order to explain these changes more clearly I want to compare the known PHPTemplate syntax with the new Twig template syntax. All examples mentioned in this blog post are based on the latest development state of the Drupal 8 Twig Sandbox.

Usually themers only have to care about the output of predefined variables or simple control structures (if conditions or for loops that output lists of content). Complex logic or further processing of variables should not be placed in the template files - I think everybody can remember a situation in which they inserted a view programmatically in a template or placed custom field on theme layer. In most cases the ability to use custom PHP in template files lead to more complexity and a lack of clarity.

Using variables in templates:

Example for the usage of variables and simple if condition in PHPTemplate:


Example for the usage of variables and simple if condition in Twig:


In the example shown above you can clearly see the differences. Instead of using the PHP'S print function or Drupal's render() function, Twig offers the {{ }} syntax for outputting variables. Twig also improved the output of array and object elements on the theme layer. In the future we will be using the following consistent "point-syntax". Here it does not matter if we want to access array or object elements.

Example of a Views exposed filter in PHPTemplate:

Example of a Views exposed filter in Twig:

Control Structures

In addition to the already mentioned if conditions there is the possibility to use for loops with the {% %} syntax.

for loop example in PHPTemplate:

for loop example in Twig:

As in earlier versions of Drupal you should avoid putting too much logic in template files. For this purpose you should use the known preprocess function provided by Drupal. Besides the new {% %} syntax in the templates the example also shows the usage of the new nav elements of HTML5 standard, which also has been introduced in other Twig templates.

Comments in templates

For documentation in templates, Twig provides the {# #} syntax.

Example for comments in PHPTemplate (phpdoc style):

Example for comments in Twig:

Reusability of templates via includes

Even though it was possible to use the PHP include or include_once function for re-using existing parts of a template, it was rarely used in the previous versions of Drupal. In Twig these includes will be used much more often. A good example for the use of includes is the image module - based on the imagestyle another template file will inlcuded by the include function of Twig.

With the help of the paramater "with" you can specify variables that are available in the scope of the included template.

Usage of filters in templates

Twig filters offer the possibility to influence the output of variables on the theme level. The following examples show a common use case for filters in Twig - they replace the check_plain function and the t-function with its Twig counterpart.

Translation in templates

Example for translations in PHPTemplate:

Example for translations in Twig:

As already known from the  t-function you can use placeholders in Twig to make the translatable strings more dynamic. In the example above the variable $votes and type are replaced in the strings.

Escaping special chars in templates

In previous Drupal versions you were able to convert special chars to HTML with the help of the check_plain function.

Example in PHPTemplate:

Example in Twig:

The escape filter can also be used via the alias e and supports parameters for different escape strategies.

  • html: escape a string for HTML body context
  • js: escapes a string for JavaScript context
  • css: escapes a string for CSS context
  • url: escapes a string for URI or parameter context
  • html_attr: escapes a string for HTML attribute context

Further information on Twig filters can be found in the Twig's documentation.

Feb 18 2013
Feb 18

Besides fundamental changes in the backend of Drupal 8 (i.e usage of several Symfony 2 components) a new theme engine called Twig is also introduced to Drupal.

In the course of further development of Drupal it is necessary to look beyond our community boundaries and to be open to new ideas and technologies. This is the only way to ensure a sustained and stable growth of the community. With the introduction of the Symfony 2 components Drupal took a major step forward to the PHP community.

In addition to PHPTemplate themers can use Twig as a new theme engine in Drupal 8. This helps lowering the entry barrier for new developers since learning PHP for theming Drupal is no longer necessary.

In our multi-part blog post on Twig we want to explain the fundamental changes of the new theme engine and show new possibilities in theming introduced by its implementation in Drupal Core.

Why Twig?

Twig has its origin in the world of Django and was developed by Armin Ronacher as an alternative theme engine for writing templates directly in PHP. Since 2009 Twig has been an integral part of the Symfony framework and has proven to be a reliable and fast theme engine. Since then the further development of Twig is promoted by Fabien Potencier, the leader of the Symfony project. Further information on his thoughts about templating engines in PHP can be found in his blog post Templating Engines in PHP.

The following list provides an overview on PHP frameworks that also support Twig:

Drupal & Twig

Apart from an easier tag-based syntax, Twig offers a lot more security on theming level. The fact can be described very briefly by a quote of John Albin at DrupalCon Denver.

We hand themers a loaded gun and tell them to hammer in a nail with it. Oh and be careful!

For instance, it would be possible to access the Drupal database via PHPTemplate and delete individual tables or access the file system of your server.

Advantages using Twig

  • more security on theme level due to limited possibilities given by tag-based syntax
  • no more PHP/HTML mix in template files
  • simplification of theming system due to the reduction of preprocess functions
  • consistent and easy-to-learn tag-based syntax, that is limited to the most common use cases in template 'development'
  • Reusability of template files (via Twig includes)
  • IDE integration (Netbeans, vim, PHPStorm, Eclipse, Textmate, Sublime)
  • good documentation - Twig documentation
  • will bring Symfony and Drupal community closer, because more components can be shared

Unfortunately there is not so much documentation on drupal.org yet but the latest coding standards can be found here: Twig Coding Standards.


  • learning a new template syntax
  • performance and memory issues caused by an extra theme engine
  • differing update cycles of Drupal Core and Twig regarding to the code freeze of Drupal 8

In my opinion only the first issue should be considered as a real disadvantage - in addition to the fundamentely changed backend in Drupal 8, Drupalistas also have to get used to a new template syntax. But if you have a look at other Content Management Systems or Frameworks you'll also find custom syntax for templating, unless they are using PHP as their main language for templating.
The performance issue will be adressed in one of our following blog posts on Twig. The already mentioned update cycles are a well-known problem in the Drupal community (jQuery is a good example in Drupal 7) - but I don't think that Twig will change dramatically in future releases.

Twig is part of Drupal Core

In the latest Drupal 8 release Twig is available as an additional theme engine and is ready to use in custom themes (Integrate Twig into core: Implementation issue). Currently the built-in themes are still using PHPTemplate as their theme engine - but you can try the Drupal 8 Twig Sandbox instead. The goal should be to reduce all Drupal Core templates and their related theme functions to just one Twig template and to simplify the theming system. The Stark theme located in the sandbox is a good example for the new approach - besides the module templates all parts of administrational pages are provided as Twig templates and can be easily overriden.

We won't get rid of the big "render array" (of doom) in Drupal 8, but the usage of Twig as our new templating engine will be much easier.

In the second part of our blog post series we want to talk about the syntax of Twig and show some simple examples to explain how we can benefit from these changes.

The Twig logo is © 2010-2012 Sensio Labs

Feb 14 2013
Feb 14

Image Style Basics

Drupal offers the possibility to easily process images via image styles (formerly known as imagecache presets). In our current case of a photo heavy website we had to integrate a watermark image on all images supplied by the site. For this purpose we used the image style action Overlay (watermark).

The configuration of the style is really simple - but could be enriched with scaling and all other available actions.

A major advantage of using Drupal's built in image style is the fact that all images are only processed once and cached in Drupal's file system for later usage. In case of our image gallery the first call of the page would take a long time, because all thumbnails would be rendered for the first time. But on second call all images would be available immediately.

Domain Access Basics

With the help of the Domain Access module you are able to share configuration, content and users between different domains. Compared to the known Drupal multisite approach, which uses a single database per site, Domain Access shares all data in a single database.

In one of our latest projects we used the module for a German city website called ROW-People (row-people.de / hb-people.de). Besides sharing content and configuration between these two sites we had to ensure that all images get a unique watermark rendered via Drupal's image styles. For further information on using the Domain Access module we will write an extra blog post explaining the setup process and usage.

Our Domain Access configuration for testing:

  • Domain 1 (machine_name: domain1) Default Domain
  • Domain 2 (machine_name: domain2)

If you want to test the setup on your local machine, you will have to set up two virtual hosts pointing to the Drupal installation.

Problem and our solution

Due to the fact that image styles are only rendered once, all images on both domains would get the same watermark image. But as mentioned before, we want a unique watermark per domain.

In order to achieve this goal we had to create our own image style per domain (the original style name suffixed by the domains machine_name) that contained the desired watermark image.

  • watermark (default-watermark)
  • watermark_domain2 (suffix matches the machine_name of the domain)

For testing purposes we created a simple content type with the following fields

  • Title (Standard)
  • Body
  • Image (Style watermark)

All further processing had to be done via a preprocess function supplied by the theming layer of drupal.

While configuring our domains we needed to set up a unique machine_name per domain that could be used in our template_preprocess_node().

Provide appropriate watermark image via preprocess functions

With the help of the template_preprocess_node() function you are able to rewrite the output of fields on node level. Whenever the page is called the preprocess function will rewrite the name of the image style name based on the machine_name of the actual domain.

In case of the city-portal site (row-people.de/ hb-people.de) we also had to add some preprocess functions to overwrite the output of the image fields used in several views ( e.g. (Image gallery))


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