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. 

Categories

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.2017 Quelle: 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 27 2017
Mar 27
ImpactHub MünchenCredits: Axel Öland

 

We are used to successfully work with our clients all over Germany. It is not important for us in what part of the country the next project awaits us. We are eager to prepare a great environment for our team, so it can provide quality for the project to lead to success. We always focus on supporting our clients to reach their goals and exceed them. On this way it does not matter if we are working for our clients from our Head office in Hannover, at a co-working space or in home office. Up until now our main office was totally sufficient as a place-to-go. Since 2016 we have employees working from south of Germany. And our award winning collaboration with Hubert Burda Media also showed to us that other cities do have their charm too. So we decided to settle down in Munich too.

At the beginning of the year, we found our place to stay in the Impact Hub Munich. There you can meet our team (Johannes and Dennis) now on a regular basis in a pleasant and innovative environment.

We are also engaged in the local Drupal user group. We are celebrating this occasion with hosting the upcoming meetup. Any people interested in Drupal may join us at March 29th 2017 at 19h. You can find the registration and details to the event via the website of the user group.

We are looking forward to meeting you and to an exciting and successful time in Munich.

 

Foto-Credits: Axel Öland

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.scss

// 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:

// <!-- Default button: -->

// <button type="submit" class="btn {$modifiers}"> // Label

 

// <!-- Link button: -->

// <a href="#" class="btn {$modifiers}">

// Label

// </a>

//

// 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.

Dec 11 2013
Dec 11

Submitted by Dennis Hoyer on Wed, 11/12/2013 - 14:22

The template engine Twig will be a component of the Drupal 8 core and is replacing PHPTemplate. The new syntax brings a lot of changes and a simpler system. The function access is restricted, which results in a more secure system. The consistent use of the syntax improves the readability of template files extremely.

Motivation

I am going to show you the Basics of Twig in this short eight minute long screencast. You can see how to print variables or how to access objects or arrays via the punctual syntax. I will also demonstrate the use of control structures like if or for loops. After this video, you will be able to use Twig without the trouble of looking up the simple Twig syntax.

Further information

If that wasn't enough you can additionally read Steffen’s posts for the Twig basics [1] [2] or Luca’s about converting Drupal themes to Twig.

Since this is my first screencast, I would enjoy some constructive feedback.

 

[embedded content]

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.

Installation

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.

Configuration

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. <?php

  2. /**

  3.  * Implements hook_form_FORM_ID_alter().

  4.  *

  5.  * Alter views exposed forms for collapsible filters.

  6.  */

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

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

  10.     // not the expected view.

  11.     return;

  12.   }

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

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

  16.     );

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

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

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

  21.       // to "All").

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

  23.     }

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

  25.   }

  26.   // Alter multi-value dropdowns.

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

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

  33.     }

  34.   }

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

  40.     // Attach custom javascript to the form.

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

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

  46.         ),

  47.       ),

  48.       'type' => 'setting',

  49.     );

  50.   }

  51. }

  52. ?>

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. <?php

  2. /**

  3.  * Implements hook_views_pre_view().

  4.  */

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

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

  8.   }

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

  12.       // unknown to Views.

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

  15.   }

  16. }

  17. ?>

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 = $('<a>')

  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);

Result

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.

name: Busy
type: theme
description: 'The ultimate Drupal business theme.'
core: 8.x
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:

<div id="comments" <?php print $attributes; ?>>
  <?php print render($content['comments']); ?>
  <?php if ($content['comment_form']): ?>
  <h2 class="title"><?php print t('Post new comment'); ?></h2>
  <div>
    <?php print render($content['comment_form']); ?>
  </div>
  <?php endif; ?>
</div>

<div id="comments"{{ attributes }}>
  {{ comments }}
  {% if form %}
    <h2 class="title">{{ 'Post new comment'|t }}</h2>
    <div>
      {{ form }}
    </div>
  {% endif %}
</div>

Similar conversions have to be applied to arrays and loops.

  {% set users = ['Paul', 'Guenther', 'Max'] %}
  {% for user in users %}
    {{ user }}  
  {% endfor %}

$users = array('Paul', 'Guenther', 'Max');
foreach ($users as $user) {
  echo $user;
}

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.

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.

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:

040_modules.sh

################################################################################ # 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 26 2013
Jun 26

We would like to share a tool with you that has helped speed up our development process as a team.

If you work on Drupal sites with a team of other developers you will know the problem: You pulled code and all of a sudden you get strange errors. Eventually you find out you need to run update.php or revert a certain Feature or clear the cache. Maybe you even got into the habit of just doing all of that after each pull and it takes up some valuable time that you need elsewhere. To avoid these problems we introduced shell scripts a while ago. Within just a few months they have evolved into a multi-file system with subscripts, but I want to share them in their simplest form.

Here's a few examples of what you can do in a script, combined with the powers of Drush:

  • Enable and disable modules or themes
  • Revert your Features
  • Clear your caches
  • Run database updates
  • Delete content types and fields
  • Index content for solr
  • Whatever else Drush can do
  • Output some audio when the script is finished!

Our scripts live in sites/all/scripts. Drupal by default disallows access to .sh files so there's nothing we need to do there to keep our files private.

################################################################################
# Shell and drush commands to update the given installation
#
# Go to sites/all/scripts (e.g. cd sites/all/scripts) and type "sh update.sh"
# in your console/shell/Terminal.
#
# The commands have to be functional for any case after the initial installation
# installation. So on any set up after calling that script, the configuration
# must be the same.
#
# For example:
# ------------
# When the script enabled a module in an earlier revision and that module shall
# not be enabled in the current revision, we have to add a "drush dis" and a
# "drush pm-uninstall" command for that module to this script.
#
################################################################################

# Change directory to drupal root
cd ../../..
# pwd

# Check drupal status
drush status

# Disable these themes to make sure they are never enabled.
drush --yes pm-disable seven
drush --yes pm-disable bartik

# Enable some modules that must be enabled.
drush --yes pm-enable features
drush --yes pm-enable strongarm

# Enable project features.
drush --yes pm-enable ok_base
drush --yes pm-enable ok_event
drush --yes pm-enable ok_i18n
drush --yes pm-enable ok_menus
drush --yes pm-enable ok_news
drush --yes pm-enable ok_page
drush --yes pm-enable ok_search
drush --yes pm-enable ok_slideshow
drush --yes pm-enable ok_sidebar
drush --yes pm-enable ok_theme
drush --yes pm-enable ok_user
drush --yes pm-enable ok_wysiwyg

# Enable project theme.
drush --yes pm-enable ourprettytheme

# Update
drush --yes updb

# Disable unused modules and features.
drush --yes pm-disable features_override
drush --yes pm-uninstall features_override

# Remove an old content type and some fields.
drush --yes php-eval "node_type_delete('page');"
drush field-delete field_news_tags --bundle=news
drush field-delete field_news_link --bundle=news

# Index content for solr
drush sapi-i ok_sitewide_index 10000 25
drush sapi-s

# Revert all features and clear cache.
drush --yes features-revert-all
drush cache-clear all

# Display list of features to check status manually.
drush features

# Check for available notification system
# Checks in preferred order and only uses one: Notification Center, Growl, Audio
# For OS X 10.8 use terminal notifier "sudo gem install terminal-notifier" http://rubygems.org/gems/terminal-notifier
# For Growl, download and install growlnotifier http://growl.info/downloads#generaldownloads
if [ $( find /Library/Ruby/Gems/ -name 'terminal-notifier*' -type d | wc -l) -ge 1 ]; then
    # Notification center output for finished update.sh
    terminal-notifier -message "$USER, the update script run is complete" -title "undpaul Update Script"
elif [ -f /usr/local/bin/growlnotify ]; then
    # Growl notification
    growlnotify -n "undpaul Update Script" -m "$USER, the update script run is complete"
elif [ $(command -v say) ]; then
    # Vocal output for finished update.sh
    say "$USER, the update script run is complete"
fi

Because the script tells us when it's finished, we can just go do something else while it runs.

We also use an installation script so everyone on the team can get started quickly. Basically, we expect to be able to set up the project from scratch at any time by just running install.sh and update.sh:

################################################################################
# Shell and drush commands to set up (or some part of it) the new site.
#
# Go to sites/all/scripts (e.g. cd sites/all/scripts) and type "sh install.sh"
# in your console/shell/Terminal.
#
# The commands are built to run once, e.g. to set some symlinks, but shall be
# designed to not break other commands on the second run.
#
################################################################################

# Change directory to drupal root
cd ../../..

# Build symlinks for local environment.
echo "Create symlinks:"
ln -s .htaccess.local .htaccess
ln -s settings.local.php sites/default/settings.php

# Install Drupal
drush site-install minimal -y

# Check drupal status
drush status

# Create Login
echo "Use the following link to log in"
drush uli

This is really helpful if anyone wants to test their development with a fresh database, but using the current code base. It helps avoid problems that occur if someone forgot to export some setting in a Feature.

What do you think about our scripts? Does your team use something like this during development?

Jun 17 2013
Jun 17

Submitted by Stefan Borchert on Mon, 17/06/2013 - 18:44

While working on a project for a customer we had the requirement to display different parts of an exposed form of a view in different regions of the page. Additionally not all parts of the form should be visible on all pages of the site (i.e. the search box should be visible on all pages whereas other exposed filters or sort options should be visible on the result pate only).
Normally we would manage this by using some hook_form_alter()-magic and/or create a custom block with a coded form in it. But a hint of Daniel Wehner (dawehner) pointed me to a different solution:

Multiple Views Displays

In Views you are able to clone an existing display, which means nothing else but creating a plain copy of it. In our case I cloned the page display containing the exposed form to split and modified some filter settings only. 

Other options (especially the page path) were not changed.

If you now look into the list of blocks, there is one block for both Views displays containing the corresponding exposed form. These blocks may be displayed on different pages and in different regions.

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).

Assumptions

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

  1. <?php

  2. /**

  3.   * Implements hook__wysiwyg_editor_settings_alter().

  4.   */

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

  6.  global $base_url;

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

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

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

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

  11.    // Set custom skin.

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

  14. }

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:

[gist:5690836]

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

  1. <?php print render($main_menu); ?>

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.

Preparations

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: 

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. <?php

  2.  /**

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

  4.    */

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

  6.   }

  7.   /**

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

  9.    */

  10.   function option_definition() {

  11.   }

  12.   /**

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

  14.    */

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

  17.   /**

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

  19.    */

  20.   function get_argument() {

  21.   }

  22.   /**

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

  24.    */

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

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

  27.   }

  28. ?>

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. <?php

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

  3. ?>

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.

[gist:5264086]

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. <?php

  2.   /**

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

  4.    */

  5.   function get_argument() {

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

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

  8.     // Get all User flags.

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

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

  11.     // Get the vocab foreach flag.

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

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

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

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

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

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

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

  23.           }

  24.         }

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

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

  27.       }

  28.     }

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

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

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

  33.     }

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

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

  36.     else {

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

  39.   }

The helper function for the .module file:

  1. <?php

  2. /**

  3.  * Helper to filter tids on given vocabularies.

  4.  *

  5.  * @param array $tids

  6.  *   array of term ids

  7.  * @param array $vocabularies

  8.  *   array of vocabulary machine names

  9.  *

  10.  * @return array

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

  12.  */

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

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

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

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

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

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

  20. }

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.

Summary

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. <?php

  2. /**

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

  4.  *

  5.  * @param string $location

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

  7.  * @param string $country

  8.  *   Name of the country to use.

  9.  *

  10.  * @return string

  11.  *   The rendered map.

  12.  */

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

  14.   $map = '';

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

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

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

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

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

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

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

  23.     // Set initial zoom level.

  24.     $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 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 function and the with its Twig counterpart.

Translation in templates

Example for translations in PHPTemplate:

Example for translations in Twig:

As already known from the  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  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 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:

[gist:5011792:taxonomy-term.tpl.php]

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

[gist:5011792:taxonomy-term.html.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:
[gist:5011792:syntax.php]

Example of a Views exposed filter in Twig:
[gist:5011792:syntax.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:
[gist:5011792:book-all-books-block.tpl.php]

for loop example in Twig:
[gist:5011792:book-all-books-block.html.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):
[gist:5011792:comments.php]

Example for comments in Twig:
[gist:5011792:comments.html.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.
[gist:5011792:image-formatter.html.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:
[
gist:5011792:node-admin-overview.html.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:
[gist:5011792:checkplain.php]

Example in Twig:
[gist:5011792:checkplain.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.

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.

<?php
db_query
('DROP TABLE {users}');
unlink('sites/default/files/myfilename.pdf')
?>

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)
  • 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.

Disadvantages

  • 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.

Twig TemplatesThe 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 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.

<?php db_query('DROP TABLE {users}'); unlink('sites/default/files/myfilename.pdf') ?>

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.

Disadvantages

  • 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.

Image Style Watermark

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 Configuration

  • 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.

Image styles per Domain

  • 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

Content Type Display

  • 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))

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))

Oct 01 2012
Oct 01

In August 2012 the Federal Ministry of the Interior published a press release with the title "Federal Ministry of the Interior publishes survey about "Open Government Data Germany"". Of course this is very exciting and interesting, because Germany also wants to join the idea of making all public documents freely accessible for general public. This can have, among others, several advantages as follows:

  • the support of organizations in achieving ther goals,
  • access to all relevant information as basis of participating in political decisions and processes and
  • complement and improve scentific results.

On the other side concerns were expressed that citizens could be overwhelmed by their limited motivation and time through informations overloads. The quality of information also has to be controlled permanently, what is associated with additional time and financial outlays. But why should the idea of "Open Government Data" be realized in Germany? First of all, because the participation through transparancy is possible, as well as better traceablility of information and facilitations of tasks can take place in each target group. Many countries have already shown how the idea of "Open Data" could be realized in the US, United Kingdom or Australia.

What Drupal has to do with it

And now, what does Drupal have to do with this topic? In the full paper (German only) of the Federal Ministry of the Interior Drupal was named as one of the recommended platform technologies among Java-based frameworks, with which a user-friendly realization of "Open Government Data" is possible. It is assumed that Java-based content management systems are better suited for major projects than PHP based CMS. This is the reason why Liferay was recommended. Liferay, like Drupal, is Open Source Software. The Java Specification is also a reason for recommending Liferay. It is able to support the JSR-168/286-Specification, while PHP based CMS like Drupal are not (However, we have found a module which apparently supports this specification. So a junction seems to be possible.) In addition to that Liferay guarantees the compability of the Java Portal System.

The consequences for Drupal

Even though in the summary of this study Liferay is preferred over Drupal, it is still a really good sign that they mention and suggest Drupal for building Open Government systems. Also, Liferay Portal Community Edition is Open Source but Liferay Portal Enterprise Edition comes under a non-free commercial licence, which guarantees long-term support as well as a support package. Also the importance of the study should not be underestimated, because it is a big and far-reaching concept. Drupal is therefore on its best way to be one of the most siginificant CMS for German Government websites.

Oct 01 2012
Oct 01

In August 2012 the Federal Ministry of the Interior published a press release with the title "Federal Ministry of the Interior publishes survey about "Open Government Data Germany"". Of course this is very exciting and interesting, because Germany also wants to join the idea of making all public documents freely accessible for general public. This can have, among others, several advantages as follows:

  • the support of organizations in achieving ther goals,
  • access to all relevant information as basis of participating in political decisions and processes and
  • complement and improve scentific results.

On the other side concerns were expressed that citizens could be overwhelmed by their limited motivation and time through informations overloads. The quality of information also has to be controlled permanently, what is associated with additional time and financial outlays. But why should the idea of "Open Government Data" be realized in Germany? First of all, because the participation through transparancy is possible, as well as better traceablility of information and facilitations of tasks can take place in each target group. Many countries have already shown how the idea of "Open Data" could be realized in the US, United Kingdom or Australia.

What Drupal has to do with it

And now, what does Drupal have to do with this topic? In the full paper (German only) of the Federal Ministry of the Interior Drupal was named as one of the recommended platform technologies among Java-based frameworks, with which a user-friendly realization of "Open Government Data" is possible. It is assumed that Java-based content management systems are better suited for major projects than PHP based CMS. This is the reason why Liferay was recommended. Liferay, like Drupal, is Open Source Software. The Java Specification is also a reason for recommending Liferay. It is able to support the JSR-168/286-Specification, while PHP based CMS like Drupal are not (However, we have found a module which apparently supports this specification. So a junction seems to be possible.) In addition to that Liferay guarantees the compability of the Java Portal System.

The consequences for Drupal

Even though in the summary of this study Liferay is preferred over Drupal, it is still a really good sign that they mention and suggest Drupal for building Open Government systems. Also, Liferay Portal Community Edition is Open Source but Liferay Portal Enterprise Edition comes under a non-free commercial licence, which guarantees long-term support as well as a support package. Also the importance of the study should not be underestimated, because it is a big and far-reaching concept. Drupal is therefore on its best way to be one of the most siginificant CMS for German Government websites.

Jan 10 2012
Jan 10

Setting up HTTPS configuration is easy ...

To build additional security on special pages on a website (e.g. a user form), the module Secure Pages has proved its worth. With it, you simply configure a domain within Drupal to be used for the secure connection, (provided that the server is configured correctly). With additional settings, you can specify several pages to be secured.

... and a mobile domain too, ...

To provide your page with a special theme for mobile devices, the module Mobile Tools is a good solution. You simply enter your mobile domain in the configuration and mobile devices are redirected to that page, with the theme switched to the selected one.

... but they don't want to work together!

But now, if you want to benefit from both modules, it comes to a small desaster, because we also have to care about mobile secure pages. Especially if a module like GlobalRedirect is activated, trouble occurs.

In such a situation, it will hapen that - on a mobile device - you get redirected from the desktop url to the mobile domain. But there securepages recognizes that the given page shall be delivered via https. So it redirects you to the configured https domain, which is a desktop url. But there mobile_tools wants us to go to the mobile domain. With all these redirects we end up with an error message like: Error 310 (net::ERR_TOO_MANY_REDIRECTS): There were too many redirects.. The settings caused a circular reference on the redirects.

In an example, we have the domain http://www.example.com and its secure page https://www.example.com, the domain configured in securepages. In the moment we set up the mobile site http://m.example.com, in most cases we also need the mobile https equivalent https://m.example.com. But neither Mobile Tools nor SecurePages offer us these settings - at least not in the configration forms.

We need a tamer!

This tamer we find  inside settings.php. Because as long as the configuration variables aren't stored in the database (more precisely: in the table {variable}), we simply can set them up within settings.php.

To avoid storing these values in the database I wrote a little sandbox and published it on http://drupal.org/sandbox/derhasi/1399172 (currently only for Drupal 6). It will delete the special variables from the database, after the Mobile Tools or SecurePages configuration form was sent.

But now let's take a look at the snippet for settings.php, with which we avoid the circular reference:

// Let mobile tools work with secure pages.

// We have to set the base_url too, so e.g. globalredirect

// will not force a wrong redirect.

$desktop_url = 'www.example.com';

$mobile_url = 'm.example.com';

$secure = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on');

// On mobile requests, mobile path provide the secure settings.

if ($_SERVER['HTTP_HOST'] == $mobile_url) {

  $conf['securepages_basepath'] = "http://$mobile_url";

  $conf['securepages_basepath_ssl'] = "https://$mobile_url";

  $base_url = ($secure) ? "https://$mobile_url" : "http://$mobile_url";

}

else {

  $conf['securepages_basepath'] = "http://$desktop_url";

  $conf['securepages_basepath_ssl'] = "https://$desktop_url";

  $base_url = ($secure) ? "https://$desktop_url" : "http://$desktop_url";

}

// On secure pages, mobile and desktop urls are https urls.

if ($secure) {

  $conf['mobile_tools_mobile_url'] = "https://$mobile_url";

  $conf['mobile_tools_desktop_url'] = "https://$desktop_url";

}

else {

  $conf['mobile_tools_mobile_url'] = "http://$mobile_url";

  $conf['mobile_tools_desktop_url'] = "http://$desktop_url";

}

With this configuration, SecurePages and Mobile Tools now react on the given circumstances (https or mobile) on each request, and set the correct base and configuration domains.

The snippet is available in default.settings.inc of the repository.

Extra hint

In addition to the MobileTools and SecurePages configuration, you also need to keep an eye on your custom redirects and rewrites. For example, if you let .htaccess redirect www.example.com to example.com, this will lead to a circular reference of redirects too (with the above settings).

Jan 10 2012
Jan 10

Setting up HTTPS configuration is easy ...

To build additional security on special pages on a website (e.g. a user form), the module Secure Pages has proved its worth. With it, you simply configure a domain within Drupal to be used for the secure connection, (provided that the server is configured correctly). With additional settings, you can specify several pages to be secured.

... and a mobile domain too, ...

To provide your page with a special theme for mobile devices, the module Mobile Tools is a good solution. You simply enter your mobile domain in the configuration and mobile devices are redirected to that page, with the theme switched to the selected one.

... but they don't want to work together!

But now, if you want to benefit from both modules, it comes to a small desaster, because we also have to care about mobile secure pages. Especially if a module like GlobalRedirect is activated, trouble occurs.

In such a situation, it will hapen that - on a mobile device - you get redirected from the desktop url to the mobile domain. But there securepages recognizes that the given page shall be delivered via https. So it redirects you to the configured https domain, which is a desktop url. But there mobile_tools wants us to go to the mobile domain. With all these redirects we end up with an error message like: Error 310 (net::ERR_TOO_MANY_REDIRECTS): There were too many redirects.. The settings caused a circular reference on the redirects.

In an example, we have the domain http://www.example.com and its secure page https://www.example.com, the domain configured in securepages. In the moment we set up the mobile site http://m.example.com, in most cases we also need the mobile https equivalent https://m.example.com. But neither Mobile Tools nor SecurePages offer us these settings - at least not in the configration forms.

We need a tamer!

This tamer we find  inside settings.php. Because as long as the configuration variables aren't stored in the database (more precisely: in the table {variable}), we simply can set them up within settings.php.

To avoid storing these values in the database I wrote a little sandbox and published it on http://drupal.org/sandbox/derhasi/1399172 (currently only for Drupal 6). It will delete the special variables from the database, after the Mobile Tools or SecurePages configuration form was sent.

But now let's take a look at the snippet for settings.php, with which we avoid the circular reference:

// Let mobile tools work with secure pages.

// We have to set the base_url too, so e.g. globalredirect

// will not force a wrong redirect.

$desktop_url = 'www.example.com';

$mobile_url = 'm.example.com';

$secure = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on');

// On mobile requests, mobile path provide the secure settings.

if ($_SERVER['HTTP_HOST'] == $mobile_url) {

  $conf['securepages_basepath'] = "http://$mobile_url";

  $conf['securepages_basepath_ssl'] = "https://$mobile_url";

  $base_url = ($secure) ? "https://$mobile_url" : "http://$mobile_url";

}

else {

  $conf['securepages_basepath'] = "http://$desktop_url";

  $conf['securepages_basepath_ssl'] = "https://$desktop_url";

  $base_url = ($secure) ? "https://$desktop_url" : "http://$desktop_url";

}

// On secure pages, mobile and desktop urls are https urls.

if ($secure) {

  $conf['mobile_tools_mobile_url'] = "https://$mobile_url";

  $conf['mobile_tools_desktop_url'] = "https://$desktop_url";

}

else {

  $conf['mobile_tools_mobile_url'] = "http://$mobile_url";

  $conf['mobile_tools_desktop_url'] = "http://$desktop_url";

}

With this configuration, SecurePages and Mobile Tools now react on the given circumstances (https or mobile) on each request, and set the correct base and configuration domains.

The snippet is available in default.settings.inc of the repository.

Extra hint

In addition to the MobileTools and SecurePages configuration, you also need to keep an eye on your custom redirects and rewrites. For example, if you let .htaccess redirect www.example.com to example.com, this will lead to a circular reference of redirects too (with the above settings).

Dec 21 2011
Dec 21

Foto von kryczka (istockphoto) - http://www.istockphoto.com/user_view.php?id=1405619Who doesn't know the following scenario: one is on vacation, maybe on a farm. Letting it all go easy, the sun is shining on your head, cowbells are ringing all around, everything feels just wonderful.
And then ... there comes the inevitable call from a colleague. "Johannes, could you have a look at this thing on site xy and just fix it. We need it till tomorrow." I won't go into if that is a healthy idea on a vacation, but normally I'll dive headlong into the problem. Of course I took my laptop with me just in case something would come up ...

Creating a local development copy "in a minute"

With Git code is set up quickly. In many cases the problem is better testable with actual content of the site, so I also want that. For that task a database dump with Backup-Migrate is handy (configuration is of course bundled into features). Pulling the database is a quick job, as it normally makes up for a file size of a few megabytes. Now we basically got all the content, as far as it consists of text.

But our site also has a lot of images and preview images in views. To get that, the traditional way would be copying the entire sites/default/files-directory from the server (e.g. using FTP). With some projects this can amount to several gigabytes - so this can take long. But we only wanted to perform a quick fix on the site.

Stage File Proxy - in a minute, for real!

To do the sitebuilding work, we only need a few images that are in the subset of content we are working on locally. So it's a mess do really download all the files. This is where Stage File Proxy comes in.

The module saves the work of pulling all the images manually. Instead, with each request the local dev copy checks if it already has the desired file in the local file system. If not, it looks it up on the remote server and downloads it. For that, the module only needs to be installed on your local machine, not the remote one.

Setup is easy:

  1. Download the module and put it into the modules folder (drush dl stage_file_proxy)
  2. Activate the module (drush en stage_file_proxy)
  3. in settings.php enter the remote url: $conf['stage_file_proxy_origin'] = 'http://my-great-domain.com';

Of course the process is also documented in the INSTALL.txt of the module.

Not much to do after that - given the write permissions in the local installation for the files-directory are set correctly.

Stage File Proxy is also taking care of the Imagecache styles. Instead of downloading the derivates created by imagecache, it downloads the respective source iamge. So the derivates can be created locally. If you do not want that, switch off this behaviour by writing into settings.php $conf["stage_file_proxy_use_imagecache_root"] = FALSE;

By setting $conf['stage_file_proxy_hotlink'] = TRUE; you even can avoid downloading files completely. Instead the file requested will be served as a redirect 301 to the fle on the (remote) server.

If you placed your origin installation behind an access authentication (via .htaccess/.htpasswd), you simply have to add your authentication data as domain prefix like that: $conf['stage_file_proxy_origin'] = 'http://username:[email protected] my-great-domain.com';.

Wrap-up

Okay, the scenario above won't hit you that often on vacation, but almost every day at work if you are a developer. Since the Drupal 7 version of Stage File Proxy is out, I use it on almost every local site. Especially for working in a team it is great. You do not have to pass around big file dumps or tell everyone to get the files via FTP - the module does it by itself, nice and quickly. On a staging site before the go live, it also saves you a lot of time of tedious file copying.

So far I have only had one case where it did not work. We had a site with a lot of videos that were just too big to be downloaded by PHP. But maybe one of you readers already has a solution for that in mind.

You find the module - of course - on drupal.org http://drupal.org/project/stage_file_proxy, there is a dev version for Drupal 6 and Drupal 7. A big thanks to netaustin and robw for their great work!

Dec 21 2011
Dec 21

Who doesn't know the following scenario: one is on vacation, maybe on a farm. Letting it all go easy, the sun is shining on your head, cowbells are ringing all around, everything feels just wonderful.
And then ... there comes the inevitable call from a colleague. "Johannes, could you have a look at this thing on site xy and just fix it. We need it till tomorrow." I won't go into if that is a healthy idea on a vacation, but normally I'll dive headlong into the problem. Of course I took my laptop with me just in case something would come up ...

Creating a local development copy "in a minute"

With Git code is set up quickly. In many cases the problem is better testable with actual content of the site, so I also want that. For that task a database dump with Backup-Migrate is handy (configuration is of course bundled into features). Pulling the database is a quick job, as it normally makes up for a file size of a few megabytes. Now we basically got all the content, as far as it consists of text.

But our site also has a lot of images and preview images in views. To get that, the traditional way would be copying the entire sites/default/files-directory from the server (e.g. using FTP). With some projects this can amount to several gigabytes - so this can take long. But we only wanted to perform a quick fix on the site.

Stage File Proxy - in a minute, for real!

To do the sitebuilding work, we only need a few images that are in the subset of content we are working on locally. So it's a mess do really download all the files. This is where Stage File Proxy comes in.

The module saves the work of pulling all the images manually. Instead, with each request the local dev copy checks if it already has the desired file in the local file system. If not, it looks it up on the remote server and downloads it. For that, the module only needs to be installed on your local machine, not the remote one.

Setup is easy:

  1. Download the module and put it into the modules folder (drush dl stage_file_proxy)
  2. Activate the module (drush en stage_file_proxy)
  3. in settings.php enter the remote url: $conf['stage_file_proxy_origin'] = 'http://my-great-domain.com';

Of course the process is also documented in the INSTALL.txt of the module.

Not much to do after that - given the write permissions in the local installation for the files-directory are set correctly.

Stage File Proxy is also taking care of the Imagecache styles. Instead of downloading the derivates created by imagecache, it downloads the respective source iamge. So the derivates can be created locally. If you do not want that, switch off this behaviour by writing into settings.php $conf["stage_file_proxy_use_imagecache_root"] = FALSE;

By setting $conf['stage_file_proxy_hotlink'] = TRUE; you even can avoid downloading files completely. Instead the file requested will be served as a redirect 301 to the fle on the (remote) server.

If you placed your origin installation behind an access authentication (via .htaccess/.htpasswd), you simply have to add your authentication data as domain prefix like that: $conf['stage_file_proxy_origin'] = 'http://username:[email protected] my-great-domain.com';.

Wrap-up

Okay, the scenario above won't hit you that often on vacation, but almost every day at work if you are a developer. Since the Drupal 7 version of Stage File Proxy is out, I use it on almost every local site. Especially for working in a team it is great. You do not have to pass around big file dumps or tell everyone to get the files via FTP - the module does it by itself, nice and quickly. On a staging site before the go live, it also saves you a lot of time of tedious file copying.

So far I have only had one case where it did not work. We had a site with a lot of videos that were just too big to be downloaded by PHP. But maybe one of you readers already has a solution for that in mind.

You find the module - of course - on drupal.org http://drupal.org/project/stage_file_proxy, there is a dev version for Drupal 6 and Drupal 7. A big thanks to netaustin and robw for their great work!

Dec 12 2011
Dec 12

I guess a lot of people that have to deal with integrating videos on a website for iPhone and iPad, will  - at some point - run into the problem that some videos simply won't play. In most cases embedding the video is the simple part: either we use the fantastic HTML5 specifcation or use some weird snippet for loading a Flash Video Player. But I don't want to look at that in this post, I want to dig a little deeper into the encoding problematics. But this is not about dealing with whether to use OGG TheoraVP8 or h264, or how to use them all at once. In this case I stumbled upon an iOS specific problem. So h264 would be the codec to look at, as this is the favourite on Apple devices.

Differences for iOS devices

iPhone Video Fehler

One might think it would be enough to simply convert any video to h264 format for it to run on iPhone and iPad. But it isn't that easy: when a video plays on an iPad, this does not mean it will play on an iPhone (in my case it was an iPhone 3GS). Instead of playing the video Safari would instead show a crossed out play button, with the Safari Debug Console displaying a "very helpful" message:

Quicktime:
Movie could not be played.

The iPad played the same video just fine.

After some research on the web I came to the conclusion that it's not enough to choose the right codec. To a greater degree, you have to keep an eye on different parameters (as bitrate for audio and video). Sure, on other devices (not just Apple's) you have to deal with that too. A blog entry at Zencoder tries to summarize the settings for different devices.

Sure, you now could try to find the correct settings by trial and error. The iOS Simulator of XCode might help in that situation, as there the same problem occurs on the simulated iPhone, but not on the iPad. So you can debug on your local machine.

Use the Handbrake to quickly stop

With the hints from the zencode post I tried may way on the road, but of course the first attempt failed. The video conversion tool of my choice "Handbrake" (alternatives) luckily had a preset that would just fit the needs for Apple devices. So I tried it again with that preset - named "Apple - Universal", and, lo and behold, it worked. The video just played on both devices. I finally found the right conversion tool and settings.

Impacts your site

For site adminstrators this would mean to convert all videos they ever uploaded to the new format. This really only might be a viable solution for smaller sites, but in the current case it was fair enough to make the most important videos compliant for the iPhone.

Other solutions

Sure, converting the videos on your local machine is not feasible for every website. But it saves the need for server side processing (like ffmpeg) or implementing a third part tool (like Zencode). If you want to provide different sizes for different devices, the local conversion is no pragmatic solution. You should definitively grab an ffmpeg module or use a SaaS for video conversion for that use case.

Pages

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