Sep 05 2015
Sep 05

Drupal 8 hit the single digits for critical issues this week, so we have officially started in on the RC1 Release Checklist! :D Two of the items on there are:

In an effort to get as much testing in front of RC1 as possible, today with the help of numerous awesome people such as hussainweb, DuaelFr, tarekdj, klausi, dawehner, Wim Leers, cilefen, and many more, we were able to get all of the external libraries in Drupal 8 updated! :D

While we have a green board as far as automated tests go, nevertheless these changes could use additional eyeballs, so please be on the lookout for any weirdness, esp. in front-end functionality, for which we lack automated test coverage.

Sep 04 2015
Sep 04

So after several months' of work last week I finally got new releases out for the Twitter module. And then this morning released more updates because a few bugs had snook their way in. Sorry about that. I do hope the new versions will keep people content for a while - if you, your client or your employer's site(s) use the module, please consider giving some back (on company/client time!) through helping with the issue queue as there are still a good many feature requests and patches that need some TLC.

Last week also saw a security release for Fieldable Panels Panes. With that out the door the next step for that module is to work through the issue queue and work on plans for the next release.

However, before that happens I do really need to get back to the Panelizer module that has definitely languished from my absence of the past several months. This module is very important to me and I'm ready to fix all the things and get a stable release out. Oh, and to write more tests. A lot more tests. Because tests are the one thing that help avoid the regressions that keep coming up.

PS, I'll be at NERDSummit next Saturday, September 12th, giving a talk on why open source is not just free software - I hope to see you there.

Oh... I almost forgot. This weekend I'll be getting the D8 port of Metatag onto d.o and plotting out my hopes and dreams to take it to v1.0 and beyond - we'll see how that goes.

Sep 04 2015
Sep 04

Image of computer boardAs far as how to install and maintain Drupal, there is no need to dig further. Installing Drupal in any hosting provider is simply a matter of decompressing a tarball; Drush on the command line gives the seasoned sysadmin a wealth of administrative aids. However, when considering integration with the system as a whole, there is ample room for improvement. Drupal cannot exist outside of a given environment: the PHP version used, the way it is integrated into its host operating system, the modules for connecting to the database, and the database engine itself. Ideally, they will all make up a coherent entity, with a single, unified administrative logic. Looking at each component individually would quickly lead to madness, especially for the sysadmin, who has to keep the whole stack secure and updated.

Debian

Debian is one of the earliest free­software distributions built around Linux. By the time this article is printed, Debian 8 (code­named Jessie) should have been released, with over 35,000 binary packages (that is, independent programs), and lives according to the distribution's motto, the universal operating system. It runs from the smallest embedded devices to the largest workstations, across many different hardware architectures.

System-wide Integration

One of Debian's strongest merits – what has made it a lively, energetic community with a sound technological platform and projection into the future – is its policy. Despite the amount of available packages, they are all standardized: They are all configured in the same location, follow the same layout logic, and are guaranteed not to clash with one another. But where this policy shines most brightly is when it is applied to keeping things
optimally administered. Debian provides security support throughout the stable release cycle, not just easing the system’s installation. As was already stated, our Drupal installs involve quite a bit beyond just Drupal itself. So, on a freshly ­installed system, the task of installing

Drupal is just a matter of running:

# apt­get install drupal7

And all of the necessary software (that is, an HTTP server, the PHP programming language and execution environment, a relational database engine, and the needed glue between them) will be installed. To apply all of the pending security and reliability fixes across the entire system, run the command:

# apt­get update && apt­get upgrade

That’s all that's needed to get every component in the system up to date.

The Debian Drupal installation is multisite­aware. This means that all of the sites Drupal will respond to should be configured from the same location. If your host will serve both example.com and anotherexample.org, you only need to create the /etc/drupal/7/sites/example.com and /etc/drupal/7/sites/anotherexample.org directories and put the sites’ configuration files there. All of the codebase will be shared, installed only once in the /usr/share/drupal7 directory.

This has an interesting advantage security­wise when compared with what I have seen at most shared hosting providers. As all the Drupal code belongs to root, any attacker that manages to subvert Drupal's security – or any of the installed modules’ security – will not have enough privileges to modify your site’s code, and will thus have a harder time leaving a backdoor or modifying your site's behavior for their interests. Even if they got a local rivilege escalation exploit, finding their misdeed will be easier: Debian ships cryptographic signatures for all of its files. By simply running the following command, any file that was modified will be reported:

$ debsums drupal7

Handling Modules

The Drupal ecosystem is very rich in third­party code: almost 30,000 modules and over 2,000 themes. Packaging them all for Debian is plainly unfeasible, but we have a tool – dh­make­drupal – that not only packages modules and themes pointed to it, but processes dependency handling as well. This way, even having a complex, multi­site and multi­server deployment, it’s easy to deliver code with all of the characteristics mentioned in the previous section.

Version Stability

Just as, within Drupal, all of the related PHP and Javascript libraries are frozen prior to a release and not hanged at that point (to avoid breaking internal stability throughout the life cycle of a stable release), packages in Debian are frozen and do not get updated when new versions come out. But in order to keep security tracking at the level required by our users, all important fixes get backported to the corresponding release. For example, Debian 7 (frozen gradually since June 2012 until its release in May 2013) shipped with Drupal 7.14. But that does not mean that Debian’s Drupal package went on for its three years of life unpatched: While feature releases were not incorporated, as you can see in our public Git repository, all bugfix releases were.

What About Drupal 8?

Now... With all the hype set in the future, it might seem striking that throughout this article I only talked about Drupal 7. This is because Debian seeks to ship only production­ ready software: as of this writing, Drupal 8 is still in beta. Not too long ago, we still saw internal reorganizations of its directory structure.

Once Drupal 8 is released, of course, we will take care to package it. And although Drupal 8 will not be a part of Debian 8, it will be offered through the Backports archive, following all of Debian's security and stability requirements.

Wrapping Up

Of course, I understand the workflow and tools mentioned here are not for every person and situation. Drupal developing is clearly served better by the “traditional” way of installing Drupal. However, for administering a large­ scale Drupal installation, operating­ system integration through Debian might be just what you need!

Image: " X-ray of computer motherboard" by tpmartins is licensed under CC BY 2.0

Sep 04 2015
Sep 04

Photo of network cablesWhen faced with the task of managing videos in Drupal, the number of available solutions might seem overwhelming. Where should you store the videos? What is the difference between CDNs (content delivery networks), cloud storage services, and hosted video solutions? Which Drupal modules should you use with which service?

Drupal Modules

By using some of the most popular modules for video handling, you can quickly set up a reliable video solution:

  • Media module Although not specialized for video, this widely used module can be combined with others; some cloud services have their own modules integrated with the Media module, too.
  • MediaElement module The MediaElement module provides an HTML5 (or Flash fallback) player. With the MediaElement module you can stream video to mobile devices as well. The player can integrate with your responsive theme.
  • Video module The Video module can handle video upload, transcoding, and playing; generates thumbnails; and can deliver videos from cloud systems.

Content Delivery Networks

CDNs are largely distributed systems optimized for delivering content to end-users, over the Internet, with high availability and performance. For video content, they are often coupled with a transcoding server.
They can be expensive, but are a good choice for improving performance and delivering content for high-traffic websites. As the data centers are distributed, they will be faster than the usual hosting providers for most visitors to your site. Also, contemplate using a CDN if you already have a transcoding server.

The CDN module provides easy Content Delivery Network integration for Drupal sites. It alters file URLs so that files are downloaded from a CDN instead of your web server.

Cloud Storage Services

Cloud storage services aren’t optimized for delivering rich media content on high traffic sites, but can be a cheaper alternative to CDNs – if you don’t have a huge number of videos and your site traffic isn’t very high.

The Media module alone doesn't provide full cloud storing services (like Amazon S3, Rackspace Cloud, and Google Cloud Platform), but together with the Remote Stream Wrapper module, you can reach external files from Drupal.

Some modules for full cloud storage service integration:

  • Storage API is a low-level framework that can be extended to work with any storage service.
  • Google Cloud Storage allows you to replace the local file system with Google Storage. Files will still be managed by Drupal, but instead of being stored on the local server, they will be stored on the Google Cloud Platform.

Cloud-hosted Video Solutions

Hosted video platforms are specialized for video storage, transcoding, and playback. They already include the transcoding software, and additional features like players (for different devices), playlists, ads, live streaming or DRM (Digital Rights Management).

DRM is a robust content protection program that enables publishers to enforce policies and rules for usage of their content.

  • Brightcove offers a highly-scalable secure video hosting platform for delivering and monetizing video across connected devices.

    The Brightcove integration module adds Brightcove videos or playlists to your content, and accesses information from the Video Cloud from within your site. Brightcove actively maintains their Drupal module by paying a company from the community – Pronovix (where I work) – for development and support.

  • The Platform offers different online video packages from an enterprise-class video management system to businesses with smaller video libraries. They also provide a transcoding engine. Their Drupal module, Media: thePlatform mpx, integrates with the Media module.
  • Wistia is a professional video hosting solution with analytics and video marketing tools. In Drupal, you can either use it with the Media:Wistia module or the Video Filter module that has extended Wistia support.
  • Vzaar is a video hosting solution offering quick, secure, and reliable services with much-praised support. Use it with the Media:vzaar module for Drupal integration.
  • Viddler offers Overture, a video hosting platform for enterprise corporations, and Arpeggio, a responsive HTML5 video player that enables you to create interactive video content and timeline commenting. Use the Viddler module for Drupal integration. (Note: The Drupal 7 version is in development, currently for testing only with limited functionality.)

Self-hosted Video Solutions

For an open source solution, you can opt for Kaltura – the world's first open source online video platform – or set up your own hosted video platform with OctopusVideo.

  • Kaltura provides enterprise level commercial software and services, as well as free open-source community-supported solutions for video publishing, management, syndication, and monetization. You can use it as a one-stop solution for all your Rich Media, including images, audio, and documents.
    Using the Kaltura module, you can either leverage the Kaltura hosted platform or grab the free source code and self-host the entire platform.
  • For your own hosted video platform, try OctopusVideo, an open source video transcoding and delivery platform built on Drupal.

Video Sharing Sites

If simply embedding YouTube or Vimeo videos in your Drupal site is enough for your project, you have more options to choose from:

  • Use the Embedded Media Field module and the YouTube integration for the Media module in both Drupal 6 and 7.
  • Use the Media module to embed videos from YouTube or Vimeo, by adding the URL to a field or through an editor.
  • In Drupal 7, use the Video Embed Field module to create a simple field type that allows you to embed videos from YouTube and Vimeo or show their thumbnail previews by entering the video's URL.
  • Use the Media Embed plugin for CKEditor that opens a Dialog where you can paste an embed code from YouTube or Vimeo.

Conclusion

As you see, there is a wide variety of available solutions, which vary widely in price and performance: choose the approach that best suits your needs. This overview should help you get started!

Image:"Networking" by npobre is licensed under CC BY 2.0

Other articles from this issue:

Columns

Jonathan Hedstrom

There are lots of new features for testing Drupal sites, making the process simpler and more efficient. Herein, some examples and explanations.

Coming Soon

Jeff Sheltren

NYC tourist: “How do I get to Carnegie Hall?” Musician: “Practice, man, practice.” The same is true for achieving expertise as a barista – or a Drupalista.

Coming Soon

Articles

Emma Jane Westby

In Drupal, there’s no single enforced path into content; there’s more than one way to skin the cat. Taxonomies, vocabularies, and other options abound. Take a look.

Coming Soon

Sep 04 2015
Sep 04

We met again today to discuss critical issues blocking Drupal 8's release (candidate). (See all prior recordings). Here is the recording of the meeting video and chat from today in the hope that it helps more than just those who were on the meeting:

[embedded content]

If you also have significant time to work on critical issues in Drupal 8 and we did not include you, let me know as soon as possible.

The meeting log is as follows (all times are CEST real time at the meeting):


[11:09am] alexpott: https://www.drupal.org/node/2545972
[11:09am] Druplicon: https://www.drupal.org/node/2545972 => Remove all usages SafeMarkup::checkPlain() and rely more on Twig autoescaping [#2545972] => 157 comments, 29 IRC mentions
[11:09am] catch: https://www.drupal.org/node/2563023
[11:09am] Druplicon: https://www.drupal.org/node/2563023 => drupal 8.0.0-beta15 => 0 comments, 1 IRC mention
[11:09am] GaborHojtsy: catch: woot :)
[11:10am] alexpott: https://www.drupal.org/node/2560863
[11:10am] Druplicon: https://www.drupal.org/node/2560863 => #options often is escaped by the code that creates the render array, the render element should do this itself [#2560863] => 19 comments, 6 IRC mentions
[11:11am] alexpott: https://www.drupal.org/node/1031122
[11:11am] Druplicon: https://www.drupal.org/node/1031122 => postgres changeField() is unable to convert to bytea column type correctly [#1031122] => 98 comments, 6 IRC mentions
[11:12am] dawehner: https://www.drupal.org/node/2538108
[11:12am] Druplicon: https://www.drupal.org/node/2538108 => Add an API for data value updates to reliably run after data format updates [#2538108] => 37 comments, 11 IRC mentions
[11:15am] plach: https://www.drupal.org/node/2561129
[11:15am] Druplicon: https://www.drupal.org/node/2561129 => Composite indexes are not correctly deleted/re-created when updating a field storage definition [#2561129] => 38 comments, 9 IRC mentions
[11:16am] plach: https://www.drupal.org/node/2504139
[11:16am] Druplicon: https://www.drupal.org/node/2504139 => Blocks containing a form include the form action in the cache, so they always submit to the first URL the form was viewed at [#2504139] => 113 comments, 20 IRC mentions
[11:18am] plach: https://www.drupal.org/node/2341575
[11:18am] Druplicon: https://www.drupal.org/node/2341575 => [meta] Provide a beta to beta/rc upgrade path [#2341575] => 69 comments, 32 IRC mentions
[11:22am] GaborHojtsy: https://www.drupal.org/node/2506445
[11:22am] Druplicon: https://www.drupal.org/node/2506445 => Replace remaining !placeholder with @placeholder [#2506445] => 97 comments, 16 IRC mentions
[11:23am] GaborHojtsy: https://www.drupal.org/node/2562903
[11:23am] Druplicon: https://www.drupal.org/node/2562903 => Drupal 8's APIs Defined => 0 comments, 1 IRC mention
[11:23am] GaborHojtsy: https://www.drupal.org/node/2560783
[11:23am] Druplicon: https://www.drupal.org/node/2560783 => Replace !placeholder with @placeholder in hook_help() text [#2560783] => 38 comments, 5 IRC mentions
[11:32am] dawehner: https://www.drupal.org/node/2538108
[11:32am] Druplicon: https://www.drupal.org/node/2538108 => Add an API for data value updates to reliably run after data format updates [#2538108] => 37 comments, 12 IRC mentions
[11:49am] Fabianx-screen: hook_post_update()
[11:55am] Fabianx-screen: node.post_update.php

Sep 04 2015
Sep 04

It’s popular, free, flexible, powerful. It’s just Drupal! This content management system (CMS) has had 7 official major releases, and the 8th is almost there.

With each release, Drupal becomes more improved and up-to-date.

It offers:

  • new functionality
  • better architecture
  • improved security
  • and many other benefits

We’re after the latest trends, so let’s discuss two freshest Drupal versions (7 and 8).

  • Drupal 7 has deservedly gained lots of supporters across the globe.
  • Drupal 8 promises to be an amazing discovery with lots of new features.

Drupal 7 vs Drupal 8: which to choose for your website?

  • Drupal 7: proven, mature, reliable.
  • Drupal 8: advanced, cutting-edge, innovational.

Drupal 7: The interface of Drupal 7 is really user-friendly, allowing many options to customize your website. If offers a lot of improvements compared to older Drupal versions, in terms of user experience, flexibility, scalability, security.

Drupal 8: It has some enhancements like multilingual add-ons, better mobile-friendliness for all kinds of devices, an improved version of HTML5 for better website management, higher file uploading and storing speed.

If you want to upgrade your website, should you choose Drupal 7 or Drupal 8?

Question 1: How complex is your website?

If your website is relatively simple, an upgrade to Drupal 8 can be your best choice. If it’s more complex with lots of custom modules, it could be rather challenging to move it all to Drupal 8.

Question 2: Do you plan a complete overhaul?

If you want a complete overhaul or redesign, moving to the Drupal 8 is a justified decision. Give yourself website a brand-new start!

How to make the right decision? Let us carefully analyze your website to say if Drupal 8 can be recommended for you or you should rely on the proven Drupal 7.

Let the right decision make your life happy! ;)

Sep 04 2015
Sep 04
Steve Furley's picture Sep 4th 2015Front-end Developer

Installing Drupal on a *local development environment, for the first time, can be a baffling process!
Place this file here, change that setting, connect to some server, something to do with lamp stack etc?

Luckily, with the emergence of cloud based IDEs (integrated development environments) like Cloud 9 and Codio, we can now make this process much simpler, accessible and efficient. For more on Cloud based IDEs, see Martin's post Coding In The Cloud.

In this post I'm going to guide you through a few steps, specific to getting Drupal up and running on Codio in minutes.

*This tutorial assumes that you are comfortable with using a terminal based interface and have a working knowledge of Drupal using the LAMP server stack.

Install Drupal on Codio in minutes

Step 1 - Register with Codio it's FREE!

Before anything else you need to visit codio and sign up to a free account.

Step 2 - Create a project

Once you have a Codio account, visit the dashboard page and choose New Project in the top right corner.

For the available starting point options, choose LAMP.  
This will setup a new Codio 'box' - A unique server instance for use with our project, which contains it's own LAMP stack, a new blank MySQL database and an integrated text/code editor.

Add a name and a description for our project, then select the visibility (private projects are a premium feature in Codio so leave it set to public unless you fancy paying for a subscription). Once you're happy, click create.

Step 3 - Install Server Utilities And Software

Just like Blue Peter, here's a script we made earlier

To complete your 'stack' you will need to add various add-on utilities 'to get all the bits talking to each other', these include: php5, php5-apache2, php5-pdo-mysql, php5-gd, mysql and composer.
Also before installing Drupal itself, we need to install drush, - an invaluable Drupal developer's shell/utility app which is full of useful commands for interacting with Drupal via the terminal, giving you the ability to install and enable modules/themes/profiles etc, clear site caches and various other tasks. (you can learn more about drush here).

You could install all of these parts manually, but as we are just trying to get to a stage where you can see and use Drupal quickly, I have provided a script below which automate the entire process for us. 

So...  Open the Codio terminal by going to 'Tools > Terminal' in the main menu and paste the following snippet of code and hit enter:

wget -O - https://raw.githubusercontent.com/sfurley1/codiosetup/master/codiosetup | bash

*To understand what processes exactly are being automated, by  the above script, below is a long-hand version of what is happening in the background.

#A bash script is a text file that contains a sequence of commands for a UNIX-based operating system.
#! /bin/bash

#This installs all the parts you need for Drupal to work
parts install php5 php5-apache2 php5-pdo-mysql php5-gd mysql composer

#Installing drush 
composer global require drush/drush:6.*

#Start up the apache server
echo "parts stop apache2 mysql ; parts start apache2 mysql" > ~/startup.sh
chmod +x ~/startup.sh
~/startup.sh

#Create a random database password and grant user permissions to the database
pass=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 10 | head -n 1)
mysql -u root -e"create database codio; create user codio@localhost identified by '$pass'; grant usage on *.* to codio@localhost; grant all privileges on codio.* to codio@localhost"

#Print out the new username and password so a user can view it and use it
echo "user: codio"
echo "pass: $pass"
echo "db: codio"

IMPORTANT!

When the script above has stopped running, look for the database username and password entries in the code. COPY THE PASSWORD! and paste into a text file or similar, we'll need it later.

Step 4 - Download Drupal Core

Close the terminal and reopen it again. - This will refresh our Codio box cache and let it know drush exists.

Let's install Drupal which will be easy with drush.

  1. Still in the terminal, move up a folder to the root of our box by using the following command:

    cd../
    
  2. Now in the root we can install Drupal. The following command downloads the latest version of Drupal core and renames the parent folder from 'Drupal' to match our Codio environment's 'workspace' folder. Don't worry, this has no baring on you Drupal site name, it just prevents all our Codio urls being appended with /drupal.

    drush dl drupal --drupal-project-rename=workspace
    
  3. CD back into our workspace folder (the folder which now contains our Drupal files and the root of our running Codio box):

    cd workspace
    

Step 5 - Giving Drupal Access To Our Codio Database

Nearly there.

You now have our Drupal files all downloaded and ready to go. The only small bit left to do is update the database file.

  1. In the folder tree on the left of the Codio interface, go to workspace > sites > default.
  2. Make and in-place copy of the file default-settings.php and rename the new copy to settings.php.
  3. Our default folder should now containing both default-settings.php and the new settings.php. We do this so that we always have an unedited copy as back-up, should we mess up our custom copy.
  4. Open the new settings.php file.
  5. We're going to tell Drupal which database to use and which login credentials to use when accessing it. These settings are for our local environment only. When moving our site to a production environment (or to any other environment for that matter) we will need to update to reflect the database which we want the site to access. Here we're on our Codio box, so we're using our 'codio' database.
  6. Copy the code below and paste it in, below line 216.
  7. Replace the password for the one you copied earlier in step 3, then save the file (Ctrl + S). The database name and username will always be 'codio'. It's fine to leave these as they are, as on Codio there is a completely unique LAMP stack per project, therefore no chance of conflicting database names.
$databases['default']['default'] = array(
   'driver' => 'mysql',
   'database' => 'codio',
   'username' => 'codio',
   'password' => 'your_password_here',
   'host' => 'localhost',
   'prefix' => 'main_',
   'collation' => 'utf8_general_ci',
);

Step 6 - Install Our Drupal Site

Now to tie all the bits together and actually install the Drupal site from the file downloaded earlier. 

  1. From the top Codio menu, click the dropdown next to project index (static) and select box URL. 
  2. The browser will open a new tab with the new box setup and running.
  3. Notice the unique server alias url in the address bar (Codio will auto-generate one at random so it could be called literally anything).
  4. In the address bar, after the url add 'install.php' - for example http://spain-boxer.codio.io:3000/install.php
  5. Hit enter.

That's it, now just run through Drupal's normal installation process and you are good to go!

Conclusion

Installing Drupal can now be a (relatively) straight forward process without any faff. Plus the joy of Codio and many other cloud based IDE's is you can access them, wherever you have an Internet connection.

Super Charged Install Option

Its important to understand the steps above, but if you are in a real rush and need Drupal set up on Codio as quickly as possible, I'm also including the below automation script, which will automatically (duh!) take care most of these steps for you, including creating and editing our settings.php:

wget -O - https://raw.githubusercontent.com/sfurley1/codiosetup/master/codiosetupmore | bash

To use this speedy set-up script do the following:

  1. Create a new Codio project only this time select default rather then LAMP.
  2. Open terminal and run the code above
  3. Skip to Installing our site like in step 6 - 'Install our Drupal Site'

* Foot Note
Although of course technically cloud based IDEs aren't 'local' to your specific machine (a possible advantage actually, as you can access them from any machine with an internet connection and the correct login), but here were are using Codio as 'local' development environment as opposed to a live production server.

Ashley George's picture

You may also like...

Git Basic Principles & Concepts (for new developers)

As a new developer, learning all the Git commands and theories is pretty intimidating along with all of the other new knowledge. So I wrote the following guide, which is the document I would've like to have been given when I started.

Sep 04 2015
Sep 04

By default, Page Manager has the User Profile Page (/user/user-id) and the User Edit Page (/user/user-id/edit), but there are a few user pages that are missing, most obvious will be the login page.

The Drupal User Pages module is a simple module that is not that commonly used that adds in the important missing pieces by adding these four options to Page Manager:

  • User Login Page (/user/login)
  • User Password Page (/user/password)
  • User Page (/user)
  • User Register Page (/user/register)

Page Manager User Pages

Install and Configure

I've found that I almost always seem to set User Page (/user) and User Login Page (/user/login) to be exactly the same using the User Login Form.

Also, you also only need to set the User Register Page (/user/register) if you allow registration.  If you don't allow for user registration, leave that page disabled.

Sep 04 2015
Sep 04

With the imminent release of a Drupal 8 Release Candidate, which could potentially be announced as soon as the end of September at Drupalcon Barcelona, the clock has just started ticking a lot louder for those sites still on Drupal 6 with the looming Drupal.org support transition policy about to kick in:

Drupal 6 core and modules will transition to unsupported status three months after Drupal 8 is released. "Unsupported status" means the community will not be providing support or patches in the same way we do now.

- drupal.org

If a similar timeline is followed, as Drupal 7 had from Release Candidate through to Full Release, then this realistically means that Drupal 6 (and Pressflow 6) will be lucky to be considered supported by the time that we are shaking off our New Year's hangovers. Not an ideal situation for Drupal 6 site owners to find themselves in.

So what can you do if you're sitting on a Drupal 6 site?

  • Stay on Drupal 6 - The latest usage statistics suggest that you're in the same boat as nearly 130,000 other site owners, so it is probable that security patches and bug fixes will still surface on drupal.org in one way or another beyond the official support period, while there are parties interested in prolonging the life of Drupal 6.
  • Upgrade to Drupal 7 - The safe bet would be to start planning how you are going to take advantage of the continued support from drupal.org by upgrading your site to Drupal 7 now -- but how? via the standard upgrade path, or by a re-build?
  • Upgrade to Drupal 8 - If you've stuck with Drupal 6 for this long, the opportunity to bypass any talk of a Drupal 7 to Drupal 8 in a few years time would probably appeal to you, so why not leap on to the bleeding-edge of technology, and go with Drupal 8 now and then stick with it for the next decade! There are even tools in the works to help you make the jump directly!

All three options have their merits, it just all depends on how much your are prepared to invest, wait, or how much risk you are prepared to take.

Knowing that nothing paints a picture quite like a graph with a subjective hyperbolic axis; here's our attempt at conveying the options that are on the table for Drupal 6 site owners:

Investment required for Drupal version number selectionRisk associated with Drupal version number selection

Obviously staying put on your existing Drupal 6 implementation is going to be the cheapest option, with Drupal 8 being the most expensive as it will be a learning experience for any developer that works on it in the early days, with no small amount of time battling against a more limited set of module options that are likely to be littered with bugs initially. The risk graph above, was trying to illustrate that the risk of staying on Drupal 6 is high as it slips out of the official support period, while moving on to Drupal 8 before it is deemed a robust platform comes with its own set of risks (e.g. stability of platform, limited set of available modules etc.). If a time factor could be applied to the risk graph, then the risk of moving to Drupal 8 would obviously degrade as time passes by, and Drupal 8 matures.

What it boils down to, is that if you are risk averse, and are prepared to invest, the safe option is for you to upgrade your site to Drupal 7 as soon as you can. For those of you that are more gung-ho, you could sweat your existing Drupal 6 platform for a while longer, riding the risk of being on an unsupported release, and hang on long enough until Drupal 8 is considered robust enough before going ahead with the upgrade.

The Zoocha approach for upgrading from Drupal 6 to Drupal 7

If after weighing up your options you decide that upgrading to Drupal 7 is the prudent thing to do, then we have a straightforward, sensible approach that we have developed over the years that we would like to share, that will hopefully put you on the right path and save you time and money during the upgrade process. Depending on the complexity of your Drupal 6 site, there may even be time to upgrade to Drupal 7 before the official support period expires.

In our approach, the first thing we would recommend doing before a line of code is written, or an upgrade path is launched into, is to perform a Drupal audit and evaluation of the existing Drupal 6 site. We suggest doing this as it tells you if:

  • There are any contrib modules without a clear upgrade path to a D7 version.
  • The volume of custom code, technical debt, and level of re-factoring, that will be necessary to upgrade the code to be compatible with D7 will be a problem or not. This goes for both the theming layer and custom modules.
  • Drupal core, or any contrib modules have been patched, or modified in any way beyond their original versions. If they have, then this is another problem to contend with.
  • The information / data / content-type structure is sound, and how / where it is stored.
  • There are any integrations worth paying heed to, and giving special consideration.
  • The code is locked to an older version of PHP, through use of functions that have been deprecated in recent versions of PHP.
  • How the content is surfaced to render the pages (through Views, Panels, Blocks etc.).
  • The theming layer is locked to an old version of a front-end framework without a clear upgrade path.

With this information known, along with any planned roadmap functionality considered, a balanced assessment can then be made as to whether it will be more cost-effective, with reduced risk and a better end result, to perform a re-build of the site in Drupal 7, rather than perform a standard upgrade. What you can also think about at this stage, is to see if there are any possibilities of compromise in terms of functionality, or improved module selections that can be made, such as calling upon some of the newer Drupal 7 only modules like Paragraphs and WorkBench, so that budgets and timelines can be met. At this point we would generally recommend producing an options appraisal that lays out in plain language what are the pro’s and con’s of each approach are, so that business owners can make an informed decision about where they want to take their platform / site.

Drupal 6 Upgrade - make sure that you script it!

If after performing the evaluation it appears that an upgrade will be possible, and is the more attractive option to the site owner, then we would generally advise that the upgrade approach as detailed on drupal.org is followed. However, for non-trivial sites, we would advise against performing these steps manually, and instead encourage you to try to capture the upgrade process in code, via a bash script making use of Drush, and php where necessary. The reason why we suggest this is so that when you are developing locally, you can at any point bin your current attempt at an upgrade, and start again at any previous step, or alter the order in which you do things simply by re-running the script. On non-trivial sites, this can save you a great deal of time, and also makes it much easier for other developers to pick up where another left off, let alone the efficiencies gained when it comes to dealing with content-freezes and pushing the changes live. When the upgrade script is ready to go, it's an undeniably satisfying experience watching your terminal shell hammering through the script, with a shiny new Drupal 7 site coming out the other side!

One type of requirement that can often tip the balance in favour of the re-build approach, is that of a new mobile compatible, responsively designed theme. If your site is of any level of complexity, trying to upgrade a Drupal 6 non-responsive theme, whilst maintaining the site branding and design, to become a Drupal 7 responsive version is something that should not to be approached lightly. In cases like this we would always recommend using a new Drupal 7 starter theme (such as Bootstrap), and then using that as a basis for a refreshed design -- a Drupal themer experienced with Bootstrap would be able to create a new theme for a site using this method in about half the time (typically) compared to upgrading an existing Drupal 6 theme to the same responsive standard.

Re-build of a Drupal 6 site in Drupal 7

If a re-build in Drupal 7 is decided upon, then I'm sure we all have a favoured development process that we go with in the construction of a new site. If however you are inexperienced with Drupal 7, then it would make sense to engage a Drupal 7 specialist to help validate your architecture, approach and plan, and act as a sound board throughout development.

The final step that we would recommend undertaking in any upgrade or re-build, would be to verify that no content has been lost/corrupted, and all key user journeys and functionality operate correctly. There are quick ways of doing this, and not so quick, but we'll save the 'how' on this for another post.

What can you do to protect your site, come Drupal 6 support retirement day?

If you decide to stay on Drupal 6 (and hang on until Drupal 8 matures enough before trading up), it's time to batten down the hatches folks! Maybe that is being a bit dramatic, as if you look hard enough you'll find sites running Drupal 5 out there still doing a job. If a Drupal upgrade is out of the question, then now would be a good a time as ever to make sure that you are doing all that you can to protect your site via other means from the dark forces at work online.

The main thing that you can do to protect your site is to review your Drupal configuration against best practices, evaluate your current hosting / infrastructure and make sure that it is as secure as can be, and be vigilant in terms of monitoring, with a plan to revert to backup should something go wrong. In the unlikely event that another SQL injection compromise in Drupal core is discovered akin to the recent 'Drupalgeddon' vulnerability, then there is very little you can do to counter this, short of wait for a fix to surface on drupal.org and to apply it as quickly as you can.

At the server level there are several mitigations that can be made (hat tip to mig5 for some of the suggestions that follow), along with Drupal practices that you can employ that will collectively go a long way to protecting you in the post Drupal 6 support era, even if your site is running modules that are technically deemed insecure. The following list is by no means exhaustive, applies to any version of Drupal, and would be a good starting point for you to measure your infrastructure and Drupal configuration against:

1) Maintain regular backups

The most important thing you can do is to maintain regular backups of both the Drupal codebase, user files and database. If something then goes bad, or a compromise occurs, then you can revert to the last known safe backup (on entirely new infrastructure if needs be). Just make sure that you keep your back-ups on a different server to your production box.

2) IP Restriction

If practical, restricting access to your Drupal administration area (/admin) by IP address (or range) is a highly effective way of cutting off external access to the admin UI. This wouldn't stop a privilege escalation exploit in Drupal, but it could still protect access to those admin areas, which would be re-assuring to have in place in the event of an admin password leak for instance.

3) Update core and contrib modules

Make sure that you keep your Drupal core and contrib modules up to date, until drupal.org turns off the taps. When they finally do, then you will want to make sure that you are on the latest version of everything where possible, libraries included.

4) Stay on top of your server updates

It's all too easy to fall behind with your server software updates if you are managing them yourself / in-house. Try to at least once a week run the operating system software updates, and immediately upon a 'Heartbleed' esque threat.

5) Add a security certificate

If nothing else, it demonstrates to your users that you take security seriously, and prevents credentials any other potentially sensitive information being sent in plain text. Security certificates are cheap and easy to install, so there is no reason not to have one.

6) Ensure that you are not running an any standalone app's, or other sites within the Drupal codebase

It's more common than you think seeing a WordPress install or some such, nestled in the Drupal codebase (think drupal.xyz/wordpress/) that perhaps arrived there as a standalone marketing campaign and not touched again since it was hastily deposited there. This obviously leaves a potential security hole that you'll want sew up, so think about moving such invaders elsewhere, and configuring your web-server to handle their new locations.

7) Replace Apache/PHP with Nginx/PHP-­FPM

Replacing Apache/PHP with Nginx/PHP-­FPM, and using a 'hardened' Nginx config will provide several improvements to security, and even potentially increase the performance of a site. One of the ways it does this is by restricting the ability of the server to execute php files, so that you can give execute permission to specific named files only, such as index.php and cron.php. What this particular measure would do is protect you in the event that someone managed to get a malicious php file on to your server, and prevent them from ever been able to execute it. The other thing you should do here is turn off the core PHP module.

8) Information disclosure

The default Drupal codebase contains a number of innocuous files that give information away about the version of Drupal you are on, such as drupal.xyz/CHANGELOG.txt. Preventing access to these, or removing them altogether can make it more challenging for attackers to determine your configuration via automated tools. Also hiding information such as the version of PHP and other server side software / extensions that you are running will help too.

9) Install php5­suhosin

Suhosin (pronounced 'su-ho-shin') is an advanced protection system for PHP installations. It was designed to protect servers and users from known and unknown flaws in PHP applications and the PHP core. Suhosin comes in two independent parts, that can be used separately or in combination. The first part is a small patch against the PHP core, that implements a few low-level protections against buffer overflows or format string vulnerabilities and the second part is a powerful PHP extension that implements numerous other protections.

- suhosin.org

Installing php5­suhosin with the default settings will improve the overall security of your platform, but watch out for any undesired consequences of it being in place, such as POST request limits.

10) Install OSSEC + Anti-Virus

Installing OSSEC, even in standalone mode ­ to monitor for intrusion attempts and unexpected changes to files, and potentially block them. OSSEC will then trigger alerts when it detects something amiss, such as:

  • rootkit and trojans (viruses)

  • alerting to poorly configured files e.g. files with insecure permissions

  • attempted brute force logins to any administration area

  • other anomalies in the system (unexpected change in network services, logs generated by the applications that might indicate a problem e.g. syntax errors, resource issues).

We would also recommend implementing other rootkit and virus scanning software on Linux servers (such as RKhunter and ClamAV) to further augment the detection of malicious software.

11) Update the admin username

If you set the site administrator role to have a username other than admin, you will thwart the bulk of brute force attacks that assume this user exists.

Putting it all to the test

Once you are confident that you have made all the security improvements you are able to on your platform, then you should put it to the test -- one such tool that can help you here goes by the suitably scary name of Zed Attack Proxy which is an Open Source penetration testing tool:

The Zed Attack Proxy (ZAP) is an easy to use integrated penetration testing tool for finding vulnerabilities in web applications.

It is designed to be used by people with a wide range of security experience and as such is ideal for developers and functional testers who are new to penetration testing.

ZAP provides automated scanners as well as a set of tools that allow you to find security vulnerabilities manually.

- owasp.org

Running ZAP over your site on a scheduled basis, analysing the results (including what your monitoring says) and taking any remedial action should give you confidence that you've done everything you can to secure your platform.

Hope you found this article useful, and please let us know in the comments if you spot any errors, or have any advice for Drupal 6 site owners that is pertinent right now, along with any recommendations about how such folk can protect their sites come the time when Drupal 6 is no longer supported!

Sep 04 2015
Sep 04

September 4, 2015 | 0 Comments | Submitted by narendran

I'm running a multisite Drupal installation, Drupal's multisite allows me to run different websites off the same set of PHP files, but with different databases (so different content). Like example.com, example1.com, and example2.com. All of them point to single folder in my server.

What should be added to .htaccess file to use http authentication only for example2.com without affecting others (example.com and example1.com).

I have used below code to achieve what i want..

  1. set the "require_auth" var if Host ends with "example2.com"

  2. SetEnvIfNoCase Host example2\.com$ require_auth=true

  3. # Auth stuff

  4. AuthUserFile /var/www/htpasswd

  5. AuthName "Password Protected"

  6. AuthType Basic

  7. # Setup a deny/allow

  8. Order Deny,Allow

  9. # Deny from everyone

  10. Deny from all

  11. # except if either of these are satisfied

  12. Satisfy any

  13. 1. a valid authenticated user

  14. Require user valid-user-name

  15. or 2the "require_auth" var is NOT set

  16. Allow from env=!require_auth

This will make it so authentication is not required unless the host ends with example2.com (e.g. www.example2.com, dev.example2.com, etc). The expression can be tweaked if needed. Any other host will cause the require_auth var not to get set so authentication is not required. If this needs to be the other way around, the last line could be changed to: Allow from env=require_auth, removing the !.

0 Comments
Sep 04 2015
Sep 04

When I was first starting to dive deep into the Drupal theming layer (beyond making a subtheme and changes the styles with CSS), I found the documentation to be rather scattered. Since I'm also impatient, I wanted one place where I could go to get a quick overarching picture of what the different files in a Drupal theme do, and how a themer can use those files to bend the theme to the designer's will. 

First, basic theme anatomy

Many people subtheme Drupal's contributed themes since there are already so many great starter themes that are highly functional. Why build from scratch when others have already done much of the work for you? If you've subthemed before (read about how to create a subtheme here) you'll already be familiar with the basic anatomy of a subtheme. You have your .info file where you name your subtheme and tell your subtheme what you're using for your base theme. You can get pretty far by just doing this and then going in and tweaking the CSS/LESS/SASS.

To take theming to the next level, you'll want to understand how the template.php and template files (page.tpl.php, node.tpl.php etc) work. I've tried to break this down into a simple table that highlights the differences between template.php and template files (confusing nomenclature, yes).

  template.php Template files (*.tpl.php) When is it run? Contains code that is run every time the template engine is run. Only runs when needed/appropriate What is it for? template.php is a collection of functions that assist in the theming of the site. It’s for all the conditional logic and data processing of the output - the place to redefine or override theme functions, or add variables that will be made available to the theme engine. Template file(s) defines the framework of a page or region. They provide templates for various components that are made available to the page.tpl.php file, such as blocks, boxes, etc. What are the basics of the code? PHP: This file must start with a PHP opening tag and typically does not end with a PHP closing tag. HTML only with some basic PHP to use variables, but shouldn’t have complex logic. What does Drupal Core provide? There are default baseline variables available to all template files. Core template files. How is the file used in the theme? There will be one template.php file for a theme, and this one file will define any needed variables. There can be none or many template files for a theme, including (but not exclusively) page.tpl.php, block.tpl.php, node.tpl.php... What can you add or customize through this? You can add new variables and template suggestions. The layout of the specified page/node/region.

I'll walk you through template files and template.php in more detail here. We'll first start with template files (*.tpl.php) since these are the easiest to read if you're not too familiar with PHP since they are mostly HTML. 

Template Files (*.tpl.php) - More DETAILS

So now we understand that template.php and template files play distinct roles in our theme. We use the template.php for all of our conditional logic, so we keep the template files clean and looking (for the most part) like HTML. Template files, like page.tpl.php, node.tpl.php, block.tpl.php, comment.tpl.php, define the HTML for different parts of the website, and are named pretty logically. Node.tpl.php will apply to all nodes, block.tpl.php applies to all blocks, comment.tpl.php applies to all comments - you get the picture.  One thing to not get confused about here - page.tpl.php is the template file that is applied to all pages for Drupal - it's not a specific template file for nodes of the content type 'page'. 

Template Suggestions

If you want to customize the HTML for any of these regions or pages, you place the appropriate template file in the templates directory of your theme, and then customize. If you want a custom template file for the home page only (a common use case) you can create a page--front.tpl.php file. This is called a template suggestion. This will override the page.tpl.php layout only for the front page. Likewise, if you want to customize the layout of articles nodes, but no other content types, you create a node--article.tpl.php file and this will override node.tpl.php. You can get more and more specific, all based on how you name the template files. Read more on Drupal.org about template (theme hook) suggestions

Variables

Drupal core already provides a some baseline variables that are available to our template files. In addition, each core template files provides additional variables that are available within that template file. You can see what variables are available to the template file by looking in the comments in the /** @file **/  at the top of the template file. Often the core template file only uses a small subset of available variables, so it's worth looking to see what else you can print out. For example, the node.tpl.php file provided by Bartik is pretty simple. I know, I said template files were mostly HTML, but this sure looks like a lot of PHP. If we break it down though, there isn't any complex logic or functions here. We mainly are using the PHP opening and closing tags to print out variables. 

For example, let's print out the number of comments on a node above the comment form. We see that the variable $comment_count is "the number of comments attached to the node".? Perfect. If we want to make the comment count an H2 to make it more noticeable, we will add the following to our node.tpl.php file:

<h2>Comments: <?php print $comment_count; ?></h2>

Refresh any page that displays a node and we'll see the following. (You may need to clear cache.)

drupal template file customization

What if we want something in a template file that isn't available as a variable? That's where template.php comes in - we can use template.php to create new variables and make them available to our template files. 

Template.php - More Details

Most themers can work with template files without much understanding of PHP. To work with template.php, some more PHP knowledge is useful, but again it's pretty basic. We put all of our functions in template.php, such as preprocess and process functions, and here we can add new variables and template suggestions. Let's break down what each of these terms means. 

Preprocess functions and variables

There are two kinds of preprocess functions you can create, theme_preprocess(), and theme_preprocess_hook().  To print out a list of available hooks on a given page, we create the simplest preprocess function (using the dpm() function requires the Devel module):

function mytheme_preprocess(&$variables, $hook) {
  dpm($hook, 'hooks');
}

Clear cache, refresh page and you'll get a long lists of hooks that are available. Here are just two:

drupal theme hooks

These hooks are giving us a list of all of the possible template files we could use to customize this page or region. So now, if we want our preprocess function to be only called when the page hook is called, so it will only be called once on a page load, we modify our preprocess function as follows. We'll also print out the variables that are available.

function mytheme_preprocess_page(&$variables) {
  dpm($variables, 'variables');
}

Now if we refresh the page, we will get a nicely formatted array of variables that are available for us to work with in our template.php. 

drupal template.php variables

Why do we care? Well, preprocess functions are great for doing things like creating new variables that we can pass to the variables array, and therefore make that variable available to our template files. Say we want to print the day of the week on our page. There currently isn't a variable for the day of the week, so we'll create one using the PHP date function. We'll then add that variable to the variables array (which we passed by reference in our function, so we can make changes). 

function mytheme_preprocess_page(&$variables) {
  $day_of_week = date('l');
  $variables['day_of_week'] = $day_of_week;
  dpm($variables, 'variables');
}

Refresh the page and we'll see at the bottom of the variables array we have a new variable, day_of_week. 

drupal template.php add variable

Now we can use that variable in our page.tpl.php as follows:

<h2>Today is <?php print $day_of_week; ?></h2>

I've added this just above the title. Refresh any page and you should see:

drupal page.tpl.php add variable

In case my comment above about the hooks giving us a list of all of the possible template files didn't make sense, I'll clarify here. We used a preprocess_page function, calling the page theme hook. This means this new variable will only be available to the page.tpl.php template file. If we took the same code that we placed in the page.tpl.php to add the day of the week, and placed it in our node.tpl.php, our variable would not print out and we would get an error like:

Notice: Undefined variable: day_of_week in include() (line 82 of /projects/drupal-7.38/themes/mytheme/templates/node.tpl.php).

If we want to get even fancier and print the day of the week only to logged in users, we place the logic in our template.php, and keep the page.tpl.php simple. We know we have access to the logged_in variable by inspecting our variables array that we have dpm'd out on the page

drupal template.php logged_in variable

And then we add the following code. If you refresh you'll see that logged in users can see the day of the week, but anonymous users get a snarky message. 

function mytheme_preprocess_page(&$variables) {
  $day_of_week = date('l');
  if ($variables['logged_in']) {
    $variables['day_of_week'] = 'Today is ' . $day_of_week;
  } else {
    $variables['day_of_week'] = 'You are not privy to that information';
  }
}

Theme function overrides

We override theme functions if we want to change something in the layout of our theme that doesn't have a template file. There are lots of parts of the theme that don't have template files, if they are smaller bits of HTML, like breadcrumbs or the username. Here is another place the Devel and Theme developer modules comes in handy. In combo they are great for figuring out candidate template files and theme functions if we want to change something. For example let's say we want our breadcrumbs to be H3 elements, and we want to change the divider between the breadcrumb elements from '>>' to '++'. Using Theme Developer, click on the breadcrumbs to get the theme function. It's named something logical - theme_breadcrumb().

drupal devel themer If you click on theme_breadcrumb() it will send you to the code for this function on Drupal.org:

function theme_breadcrumb($variables) {
  $breadcrumb = $variables ['breadcrumb'];

  if (!empty($breadcrumb)) {
    // Provide a navigational heading to give context for breadcrumb links to
    // screen-reader users. Make the heading invisible with .element-invisible.
    $output = '<h2 class="element-invisible">' . t('You are here') . '</h2>';

    $output .= '<div class="breadcrumb">' . implode(' » ', $breadcrumb) . '</div>';
    return $output;
  }
}

To make our changes, we put this function in our theme, rename it according to our theme name, and make the desired changes. 

function mytheme_breadcrumb($variables) {
  $breadcrumb = $variables ['breadcrumb'];

  if (!empty($breadcrumb)) {
    // Provide a navigational heading to give context for breadcrumb links to
    // screen-reader users. Make the heading invisible with .element-invisible.
    $output = '<h2 class="element-invisible">' . t('You are here') . '</h2>';

    $output .= '<h2>' . implode(' ++ ', $breadcrumb) . '</h2>';
    return $output;
  }
}

Template suggestions

Another thing you can do in your template.php file is add template suggestions that aren't automatically available. There are already a lot of template suggestions available - let's take node.tpl.php as an example. If we wanted to change the layout of nodes of content type article, we would make a node--article.tpl.php file. If we wanted to change the layout of a specific node, we would make a node--[nid].tpl.php file. We can access the list of available template suggestions by dpm'ing out the variables in a hook_preprocess_node() function in our template.php as follows: 

function mytheme_preprocess_node(&$variables) {

  dpm($variables, 'variables');

}

Inspect the variables array for theme hook suggestions and we'll see two. Note that in the array they are listed with underscores, but when we make the template files, the underscores are replaced with dashes. Also, the order matters here - Drupal will look for the most specific template first, (at the bottom of the list), and then keep working its way up. It doesn't necessarily mean that these templates exist, but that Drupal will check to see if they do. 

drupal theme hook suggestions

But say we didn't want to use either of these template files, and wanted to make a new template suggestion. For example, let's say we wanted to add a template file that would only display on the weekends, reminding people they shouldn't be inside on the interwebs, but outside doing something involving fresh air. We would add a template suggestion to the theme_hook_suggestions array as follows - note since we're adding to an array, we include an additional empty []. Also, we don't need to include '.tpl.php' in the name of our suggestion, and we're using underscores. For the actual template file itself, we will call it node--weekend.tpl.php. 

function mytheme_preprocess_node(&$variables) {
  $variables['theme_hook_suggestions'][] = 'node__weekend';?
  dpm($variables, 'variables');
}

Refresh, and check out your variables array - you'll see our new template suggestion is now listed. Also, since it is at the bottom of the list, it is the most specific file, so if that template suggestion and file exists, Drupal will use it.  

adding a new theme hook suggestion drupal

Great, now we can make our node--weekend.tpl.php and put in an obnoxious message like this. Note that this will replace all content that would normally be displayed by node.tpl.php and only this message will be displayed. 

custom node template file

The last thing we have to do is make sure that this template suggestion only exists on the weekends. Right now as our code was written, that template suggestion will always be there. We'll just do a quick check of the day of the week before we make the template suggestion. 

function mytheme_preprocess_node(&$variables) {
  $day_of_week = date('l');
  $variables['day_of_week'] = $day_of_week;
  if (($day_of_week == 'Saturday') || ($day_of_week == 'Sunday')) {
    $variables['theme_hook_suggestions'][] = 'node__weekend';
  }
  dpm($variables, 'variables');
}

Now (as long as it's a weekend) if someone tries to view a node they will just get this - pretty annoying, huh?

using custom node template

Well, that should be a good start on your journey to becoming a Drupal theming expert. Hope you found it helpful!

MORE great resources

Sep 03 2015
Sep 03

Do you add content to Drupal websites? Have you ever found yourself in the process of uploading an image, with no clue what size to upload? Or whether Drupal will scale or crop the image? If so, you’re not alone.

Drupal sites get built a million different ways because of scope, budget and time. Because of this, sites behave differently. One site may automatically crop and scale an uploaded image to fit within a template. Another may require you to do that work before hand. This behavioral inconsistency can leave admins guessing as to how the site behaves.

You might be thinking “But we account for this during training.” Many teams train clients how to use their sites during a hand off. They account for any lack of help text with verbal explanations. While that trained client maintains the site, everything may go fine. But what happens when that person leaves and another person takes over? Do they get trained? Is there documentation?

Even the in the best case scenarios when there is documentation residing outside the CMS, few read the manual. Most of us muddle through. We do this because we’re busy and don’t want to look for instructions and can’t remember where Frank put that file anyway. Where is Frank? Frank!

So what’s the fix?

Meaningful help text. We want to provide help text in the image field that maps to the possible questions an admin may have when faced with uploading an image. These questions are:

  • Does the image gets cropped?
  • Does the image get scaled?
  • Does the image get scaled proportionally?
  • What size do I need to prep my image at?
  • What file format is best?
  • Do I need to compress my image before upload or will Drupal do it for me?
  • Do I get to pick the thumbnail crop or is it generated automatically?

Here are some examples of well written help text to address these never-ending quandaries:

Example for when admin has to crop, scale & compress an image

  • Image dimensions: 1500px x 450px (must be exact or design will break)
  • Best file format: jpeg
  • Image file size should be less than 100K
  • Drupal will not compress your image. Upload as small as possible (without compromising quality) for performance.

Example for when Drupal crops, scales & compresses an image

  • Image dimensions: any
  • Drupal will crop and scale your image to 1500x450. You will be shown a crop interface to pick where the image gets cropped after you press the “upload” button.
  • Best file format: jpeg
  • Image file size: Drupal will compress your image for you.

Example for when image can be any size, so long as it adheres to an aspect ratio & Drupal compresses

  • Image dimension: 4:3 aspect ratio
  • NOTE: Make sure width is at least 800px wide (at at least 72 ppi)
  • Best file format: jpeg
  • Image size: Any. Drupal will compress for you

For extra credit you can add image guidelines reflecting your brand such as:

  • Do not upload images with a text overlay
  • Use imagery that is architectural, scenic or inspiring
  • Do not use images with a person as the subject. Keep it abstract

Go forth and make great help text! Share any other text you’ve found to be helpful in your sites. This small improvement can help all Drupal sites maintain their visual integrity through multiple site owners.

868
Sep 03 2015
Sep 03

The White House released an open source map that harnesses data from community initiatives around the United States.

omb_map.jpg

Obama's presidency has been marked by a number of technological firsts: Obama's been unofficially dubbed the "social media President" as he was the first sitting US president to have a twitter account, his campaigns embraced methods such as email marketing and by all accounts he's the first president to use a selfie stick. Yup.

But the latest data-driven project from the White House should have Drupal and open source enthusiasts particularly excited.

The White House created an open source map that offers a visualization of the Obama administration’s community-based initiatives across the United States. 

The code is in GitHub and it contains this brief description of the project:

"This map is a snapshot view of the Obama Administration’s work in partnership with local communities. The map is made up of data sets from initiatives across more than 15 Federal agencies. We are adding datasets and features to the map as we build it, so check back for updates (or help us add them!)." 

The map is built primarily with the Leaflet web mapping library and JQuery with data contributed from a number of open source projects, including OpenStreetMap.  Whitehouse.gov is inviting front-end developers to fix bugs or add new features to the map, which is pretty cool!

Related blog post: Open Source’s Impact on Government

Do you have a favorite example that harnesses the power of open source in your community? Drop a comment below and let us know!

Sep 03 2015
Sep 03
drupal flexslider

Flexslider is a jQuery plugin by WooThemes and it makes it very easy to create slideshows.

You can integrate it into Drupal easily, using the FlexSlider module which has full Views integration.

The FlexSlider page on WooThemes.com, shown below, gives you an idea of the slideshows you can build with FlexSlider.

Drupal Slideshows with FlexSlider from WooThemes
  • Install the FlexSlider module, plus any module dependencies that you need.
  • I'm also going to recommend that you enable "FlexSlider Example" for this tutorial.

Next we need to download FlexSlider itself.

  • Extract the FlexSlider files to /sites/all/libraries/. Your files should be located here: sites/all/libraries/flexslider/jquery.flexslider-min.js
  • Go to Content > Create FlexSlider Example.
  • Upload an image and save the content.
  • Repeat by creating more content items and uploading more images.
  • Go to Structure > Block.
  • Publish the "View: FlexSlider Views Example: Thumbnail Controls" block.
  • Your slider will look like the image below:
  • Go to Structure > Views > FlexSlider Views Example.
  • Click "Settings" next to "FlexSlider".
  • Inside the settings, you'll see a variety of different options for your slideshow. These are similar to some of the examples on the WooThemes page.

The sample View also has automatically created Views, using some of these options:

View the discussion thread.

blog comments powered by DISQUS back to top
Sep 03 2015
Sep 03

If you have deja vu when we say DrupalCon Barcelona, you could be one of the people who attended DrupalCon Barcelona back in 2007! In true Throwback Thursday fashion, we are going to break down the tried and true things that have been the same for the past eight years, and what you can expect to be different at our upcoming DrupalCon.

Changing with the times

To start with, there are many more Drupalers

In 2007, 450 attendees showed up to celebrate Drupal in Barcelona. For this coming September we are expecting four times more attendees to come together to learn, share and get social in the city all over again. Everything is going to be correspondingly larger as a result.

More sharing on more topics

In 2007, the Con offered 84 sessions. As our attendance has grown, so has our demand for broader content, which is why for our 2015 Con we will be offering 120 sessions with quite a few tracks that didn’t appear 8 years prior. The increased contend doesn’t stop with sessions: we will also offer:

  • 3 plenary sessions highlighting four keynote speakers, a bit more than the 1 we had in 2007
  • we will hold a Business Summit along with 8 trainings on Monday
  • Even more opportunities to sprint beginning at 9:00 on the Saturday before the Con until midnight the Sunday after. Of course, there are also tons of evening social events where you can get your Drupal on, 2015-style.

First-Timer Fun

Over the years, we have heard a lot of feedback that although the Drupal community is welcoming and friendly, the sheer scale of it can make it a bit intimidating and overwhelming to go to your first DrupalCon. We tested out a First Time Attendees Social in Los Angeles, and it went so well that we’re replicating it in Barcelona. Join us Monday evening for the First Time Attendee Social, where new Con attendees can make friends and talk with DrupalCon veterans full of tips and great advice.

Tickets Cost More

In 2007, the price of the Con was a mere 50€ which was amazing! As the Cons have gotten bigger, it’s become increasingly difficult to find space in popular cities such as Barcelona that have space for keynotes, exhibit halls, lots of sessions and BoFs, 24/7 sprinting, lunch and well-priced nearby hotels. While the price for DrupalCon Barcelona 2015 will be higher, we have done our best to keep the price as low as possible while continuing to provide all the elements that are now expected of Cons. We are looking forward to releasing more information about what it costs to run a Con with the Los Angeles wrap blog post next month.

Tech Updates

Thanks to the amazing work from the various Con teams throughout the years, we have enjoyed some great technological advances at each DrupalCon. In Barcelona in 2007, not all rooms had microphones, presenters were requested to upload their own presentations and slides to slideshare, and the main keynotes were not streamed live. This time around, we are happy to offer a typical AV set-up in each session room (mic, podium, screen), live streaming for the keynotes and closing session, and YouTube archiving that is almost instantaneous. Throwback bonus: in 2007 there was talk about offering session recordings on a DVD for conference attendees to watch at home after the Con, and we are sorry to say we will not be offering this ;).

Keeping it the Same

Dries’ Welcome

A Con is not a Con without a welcome from Dries! On Tuesday, 22 September, we will hear from Dries about the ‘State of Drupal’ but instead of highlighting the Drupal 6.0 beta which was released four days before the 2007 Con, we are hoping to hear some grEIGHT announcements from Dries about the what’s happening for Drupal in 2015.

Speakers

Besides Dries, there are many speakers who shared their knowledge in 2007 and will be sharing new content this time around. agentrickard won’t be highlighting Enterprise Drupal this time around, but instead will talk about reimagining content management; eaton won’t be telling us about the exciting future of nodes like he did in 2007 but will share his knowledge on how to build a (billable) content strategy practice; although crell won’t be speaking about PHP, he has become the PHP Track Chair this time around… and, of course, Gábor Hojtsy will speak about multi-lingual, just like he did eight years ago.

Drupal CAT is still helping organize

The people at Drupal CAT (the Catalan Drupal group) along with many other volunteers were instrumental in putting on the Con in 2007. The Drupal Association was a wee baby at only 1 year old, and we have now grown up and have taken on the Cons. While the DA has taken the reins, the faces of Drupal CAT are still playing a huge role and the goal to provide a great Con still lives on in the local community.

People will always want more/better coffee

Even back in 2007, when the organizers requested feedback on the Con, there were people that wanted better and more coffee. It seems that even with the changing times, large venues just don’t provide amazing coffee during a conference. While we are working our best to provide a lot (we know you want it!) of coffee for Barcelona 2.0, we also understand that there will be people who provide the same feedback as they did in 2007. Happily, one thing that will change in regards to coffee is that Neil Drumm will now partake in the beverage: he told the Events team he ‘was not drinking coffee’ back then. Hopefully he isn’t disappointed by what the convention center has to offer.

We’re looking forward to hearing from you about what you are planning on repeating from DrupalCon Barcelona 2007 and what you are excited that will be different. We’re sure that all our attendees are going to have a great time, and that DrupalCon Barcelona is going to be fantastic. After all, it’s the attendees that make a Con great, and we couldn’t be happier to work with the best community in the world. Make sure to get your ticket and bring a friend to make new memories with.

Flickr photo by André Ellis
Group photo by Dries Buytaert

Sep 03 2015
Sep 03

On October 15th, 2014, the highly critical SA-CORE-2014-005 - Drupal core - SQL injection vulnerability was announced. Shortly afterwards, research showed that sites not patched that same day could very well be compromised. Two weeks later, a public service announcement was released explaining the gravity of the situation. There was also a FAQ, a flowchart for dealing with it and a module that could potentially confirm a compromised site. Needless to say, it was a challenging time for the community.

At the time, I was asked by a client of mine to analyze a site to determine risk.

Some common attack vectors associated with the vulnerability were:

  • Changing the superuser's (user ID 1) username, password or e-mail address.
  • Adding new users to the user table with the administrator role (usually ID 3).
  • Adding entries to the menu_router table.
  • Adding PHP files to the code base or in the sites/all/files directory.
  • Adding nodes (pages) or blocks with executable PHP.
  • Downloading the list of user passwords
  • Determining hackability through the version listed in CHANGELOG.txt
  • Spawned processes run by the Web server
  • Adding new roles
  • Permission changes

So based on the above, and some other sources, it was possible to produce a list of things one could look for to determine if a site had been compromised. As has been discussed elsewhere, failure to confirm any of these did not mean the site was not compromised, but it did provide some indication of risk.

  1. Rerun the Security Review module.
  2. Perform checks with the Drupalgeddon & Site Audit modules.
  3. Check for changes to user 1's username, password or e-mail address.
  4. Check all users in roles other than "anonymous" and "authenticated".
  5. Check for strange entries in the menu_router table.
  6. Check for code files outside of version control.
  7. Check for code files inside sites/all/files.
  8. Check for new nodes or blocks in the DB.
  9. Check for strange processes spawned by the Web server user.
  10. Check for any new roles.
  11. Check for any permission changes.
  12. Check the mail logs for anything suspicious being sent out.
  13. Scan site with the Sucuri tools Free Website Malware and Security Scanner and Unmask Parasites.
There are some worthwhile things to note with respect to the checklist above:
  1. Some of the clues (such as 5 and 6 above) would have been long gone as they're rebuilt during cache clears and deployments.
  2. It's theoretically possible that malicious processes could have been spawned by the Web servers. The names could have been renamed to look non-malicious, but unless something was set up to make these persist across power cycles, they would be wiped on a system reboot.
  3. It's also theoretically possible that user passwords could have been compromised. In Drupal 7, hashed passwords are salted, but the random string used for the salt could have been read as it's in sites/default/settings.php. With that in mind, the site would be susceptible to brute force, dictionary and rainbow table attacks. If the site isn't going to be rebuilt, it would be a good idea to expire all passwords and forcing users to reset them. If another system is handling authentication, this isn't an issue.

And of course there could be any number of other things. The best course of action would be to rebuild the site. If that's a challenge, always consider the level of risk before deciding not to. Hopefully we won't have to make too many of these determinations in the future.

References

This article, Responding to Drupal's highly critical SQL injection vulnerability, appeared first on the Colan Schwartz Consulting Services blog.

Sep 03 2015
Sep 03

After working with both Chinese customers and global customers with a Chinese user base, we at Acquia have developed an understanding not only of the sometimes difficult requirements faced, but also the existing state of both sites and platforms.

From well-known challenges like the Great Firewall of China (GFW), to the lesser known problems of ICP licenses (for Internet Content Provider, a permit issued by the Chinese Ministry of Industry and Information Technology to permit China-based websites to operate in China), to hosting availability, the Acquia APJ (Asia, Pacific & Japan region) team has seen and dealt with most of these difficult requirements.

Currently the relevant Amazon Web Services region in Beijing (AWS cn-north-1), which I've circled below, contains just one availability zone (AZ), making the standard High Availability Architecture (HA) setup Acquia utilises in all other regions impossible.

This means the majority of Acquia customers requiring a Chinese presence manage their sites out of either Tokyo (ap-northeast-1) or Singapore (ap-southeast-1).

To ensure our customers’ sites remain online, the Acquia Cloud utilises a high availability (HA) architecture, removing single points of failure. To do this, we use multiple AZs within a hosting region and split web servers, database servers, load balancers and all other components between them. Using separate power and network grids in each AZ allows us to have confidence that even in the worst of circumstances, sites remain online.

Elsewhere in China, some of the largest companies in the world by revenue are moving into the hosting business. The two largest providers are Baidu Cloud (???), a hosting offering from online services company Baidu, and Ali Cloud (???), a cloud computing offshoot from giant Alibaba.

Baidu hosts its own services, provides online storage and a developer centric execution environment. Ali Cloud provides an elastic distributed environment and hosts both Taobao and Zhifubao, the Chinese equivalents of eBay and Paypal respectively. The final option, Tencent, the company behind the Chinese messenger service QQ, has started their own cloud endeavours although at a smaller scale.

Despite a flourishing cloud industry, hosting in China hasn’t yet stretched into the realms of fully managed platforms yet. Whether it’s a shared server, a dedicated box with access to the root user, or a cPanel enabled server without command line access; the result is just a box to put a site on without configuration, guarantees or support.

While hosting providers are moving towards Xen as a standard practice, much of the existing shared hosting in the country utilises Windows as both the hypervisor and operating system. The effect of this is that more modern web languages and frameworks, designed with Linux in mind, may not be fully supported.

(from http://www.cioage.com/)

The prevalence of Windows as the operating system is reflected by some of the choices in CMS used by Chinese organisations. A scan of websites hosted within the country shows that open source is by far prefered to proprietary but with a number of home grown solutions developed for IIS/PHP taking the largest share. Discuz, DedeCMS and Z-Blog are all used widely but for narrow scoped applications of forums and blogs rather than the wider variety of possible uses Drupal has the potential for.

 

Finally, with mobile users in China accounting for 85.8% of online users and a mobile-to-desktop online ratio of roughly 6:5 (from the China Internet Network Information Center), the idea of responsive design and a mobile first online strategy should be paramount. However, the move away from sites based around <table> tags is a slow and drawn-out process, with many popular sites continuing to exhibit a more traditional theme (http://www.sina.com.cn/ and http://www.sohu.com/).

The result of the above leads us into a situation where a large proportion of online activity in China is reliant on outdated second class hosting platforms unable to offer a best-in-class experience for site visitors.

A disruptive transformation brought about by increased adoption of Drupal and Acquia in China would lead to fully-supported sites with faster page loads, better UX, greater control for site editors, and an assurance that the sites remain online. This in turn would ultimately lead to more conversions and increased revenue, desirable for everyone.

Next: I’ll take a look behind China’s Great Firewall (GFW), and what it means for organizations that are operating outside, and inside, China.

Sep 03 2015
Sep 03

28 pages of unmarred perfection. This book is pure unadulterated genius

- Chris Arlidge

Never Be Shocked Again! - Budgeting your Web Project

Are you having trouble figuring out an appropriate budget for your next web project? Our whitepaper can help!

Download your FREE COPY, to learn the different types of website projects, understand the factors that play a role in the budgeting process, and determine where your web plans will fit when it comes to costs!

Don’t ever be shocked by web costs again! A clear guide to help you plan the budget for your next web project.

In depth, but not too deep

Okay, so you want to use RequireJS to manage and organize your JS and all the dependencies, in a modular way. You also don’t want deal with RequireJS caching the heck out of your JS changes during development, otherwise...Derpal..  but, you do if you’re ready for production.

Also...  Compiling with Grunt (compass), component package management with Bower, and having it not interfere with Drupal. (.info files… we’ll get to that).

And finally, I’m not a fan of installing ruby gems and all that globally on your machine. We want this specific to the project, and keeping the versions in sync, with that Gemlock file that gets generated after the “bundle install”, which installs those ruby gems.

What we’re gonna do:

  1. Set up our files and structure for front-end development, and having it work with foundation, but not interfere with other theme related stuff.
  2. Set Up some PHP to have drupal differentiate between a ‘dev’ environment and production, as well as getting a form of cache busting in there for Require.
  3. Setup RequireJS, and make use of that cache busting.
  4. Get a sample Require JS module running, that will only load the needed JS files related to the homepage.

First thing’s first.

From what I’ve seen, it’s been common practice to have all your FE (front-end) related files in the theme folder, including your gruntfile.js, package.json, Gemfile.. etc.. Problems can arise from this.  Some bower or node packages contain .info files that aren’t Drupal standard .info files.

Drupal unfortunately recursively scans all your sub folders, and if it finds additional .info files (which would be installed along with node or bower packages) it will read them and derp out.  You can expect to find very weird problems, like not being able to install drupal or the theme properly, or unexplainable php errors.

Below is a link to a thread where people are proposing solutions.. But we’re doing things differently, so we won’t run into the issue at all.

https://www.drupal.org/node/2329453

Our Solution.  -- Don’t use the theme folder for all your setup and compiling related files.

Instead, I simply like to use a custom subfolder off of Drupal’s root folder.  Since everything is “user interface” related, it makes sense to call the folder “UI”.

So we have: [drupal-root-folder]/UI

Alright, now we can begin to put all of our front-end compiling related files in there.

Let’s start with our Node Modules, we’ll need a bunch, to get all this working.  We first need a ‘package.json’ file that will contain a list of all the node modules and their version.

File: [drupal-root-folder]/UI/package.json

{
  "name": "cmmdrupalboiler",
  "version": "0.1.0",
  "private": true,
  "config": {
        "unsafe-perm": true
  },
  "scripts": {
        "install": "bundle install --path ruby_gems && bower install"
  },
  "devDependencies": {
        "load-grunt-tasks": "~0.3.0",
        "grunt": "~0.4.5",
        "grunt-contrib-watch": "~0.6.1",
        "grunt-contrib-compass": "~1.0.3",
        "grunt-contrib-cssmin": "~0.8.0",
        "grunt-contrib-jshint": "~0.8.0",
        "grunt-contrib-clean": "~0.5.0",
        "grunt-contrib-requirejs": "~0.4.4",
        "grunt-contrib-uglify": "~0.3.3",
        "grunt-contrib-copy": "~0.8.0",
        "node-bourbon": "~1.2.3"
  }
}

Looks like a pretty standard package file. You may have noticed the ‘scripts’ section.  It just allows us to simply only run “npm install” and it will also install all the required bower modules and ruby gems, we’ll talk about those later in the grunt file.

I’ve also included ‘node-bourbon’ since that comes from foundation. So we’ll need it. (Unless you don’t plan on using it of course).

Okay, so we got node packages listed out, now lets do some bower stuff.  We’ll need the ‘bower.json’ file for this.

File: [drupal-root-folder]/UI/bower.json

{
  "name": "cmmdrupalboiler",
  "private": "true",
  "dependencies": {
        "intentionjs": "0.9.9",
        "underscore": "1.7.0",
        "viewportsize": "latest",
        "requirejs": "latest"
  }
}

Just some bower components, so we can use them.. talk to them, tease them, snuggle them. We’re including requireJS through bower here as well.

Next up, your Gems. (Gemfile)

File: [drupal-root-folder]/UI/Gemfile

source 'http://rubygems.org'
gem 'sass', '3.4.5'
gem 'compass', '~> 1.0.3'

Okay now that we’ve got all our resources setup, we need to install them. So, do:

npm install

And then magical unicorns will install all those packages for ya.

Grunt!

Well, now that we’ve got our packages installed, we can setup our gruntfile.  This one is a bit of a doozy, but bare with me.. we can snuggle later.

Im going to go through the file bit by bit. Follow along with the downloaded code.

File: [drupal-root-folder]/UI/Gruntfile.js

/*
 * Base Gruntfile Module
 */
module.exports = function (grunt) {
  'use strict';
  return this.registerTask('default', ['build']);
};

First part is just standard syntax for starting a grunt file. And we just register the default task, which is our ‘build’ task. -- We’ll add that actual task later. This is just the opening and closing of the function, obviously there’s a lot more in it, I’m just being syntactically correct.

Next:

  /*
   * load grunt tasks automatically
   */
  require('load-grunt-tasks')(grunt);

  var bourbon = require('node-bourbon').includePaths;

  /*
   * setup paths
   */
  var path_vars = {
        theme_path: '../sites/all/themes/cmmdrupalboiler',
        foundation_path: '../sites/all/themes/zurb_foundation',
        compile_path: '../UI',
        bower_path: '<%= path_vars.compile_path %>/bower_components',
        gem_path: '<%= path_vars.compile_path %>/ruby_gems',
        js_base_path: '<%= path_vars.theme_path %>/js',
        js_src_path: '<%= path_vars.theme_path %>/js/src',
        js_bld_path: '<%= path_vars.theme_path %>/js/dist'
  };

  /*
   * foundation - additional libraries
   */
  var foundation_libs = [
        '<%= path_vars.foundation_path %>/js/vendor/placeholder.js',
        '<%= path_vars.foundation_path %>/js/vendor/fastclick.js'
  ];

  /*
   * foundation - core JS
   */
  var foundation_js = [
        '<%= path_vars.foundation_path %>/js/foundation/foundation.js',
        '<%= path_vars.foundation_path %>/js/foundation/foundation.abide.js',
        '<%= path_vars.foundation_path %>/js/foundation/foundation.accordion.js',
        '<%= path_vars.foundation_path %>/js/foundation/foundation.alert.js',
        '<%= path_vars.foundation_path %>/js/foundation/foundation.clearing.js',
        '<%= path_vars.foundation_path %>/js/foundation/foundation.dropdown.js',
        '<%= path_vars.foundation_path %>/js/foundation/foundation.equalizer.js',
        '<%= path_vars.foundation_path %>/js/foundation/foundation.interchange.js',
        '<%= path_vars.foundation_path %>/js/foundation/foundation.joyride.js',
        '<%= path_vars.foundation_path %>/js/foundation/foundation.magellan.js',
        '<%= path_vars.foundation_path %>/js/foundation/foundation.offcanvas.js',
        '<%= path_vars.foundation_path %>/js/foundation/foundation.orbit.js',
        '<%= path_vars.foundation_path %>/js/foundation/foundation.reveal.js',
        '<%= path_vars.foundation_path %>/js/foundation/foundation.slider.js',
        '<%= path_vars.foundation_path %>/js/foundation/foundation.tab.js',
        '<%= path_vars.foundation_path %>/js/foundation/foundation.tooltip.js',
        '<%= path_vars.foundation_path %>/js/foundation/foundation.topbar.js'
  ];

So here we just setup all the variables, and paths to everything. We also include all the paths to the JS files that are needed by foundation. The foundation stuff was taken right out of the gruntfile, from it’s “zurb_foundation” theme folder.

So now for the tasks.

  /*
   * grunt tasks config
   */
  grunt.initConfig({
        path_vars: path_vars,
        pkg: this.file.readJSON('package.json'),

        /*
        * grunt clean
        */
        clean: {
        css: ['<%= path_vars.theme_path %>/css'],
        js: ['<%= path_vars.theme_path %>/js/dist'],
        options: {
        force: true
                }
        },

...

We need a ‘clean’ task that will clear out all the old CSS files, and the all old JS files, so we don’t run into problems with old versions, or orphaned files making things messy.

/*
 * grunt copy
 */
copy: {
  main: {
    files: [{
      expand: true,
      src: [
                '<%= path_vars.bower_path %>/underscore/underscore-min.js',
                '<%= path_vars.bower_path %>/intentionjs/intention.js',
                '<%= path_vars.bower_path %>/viewportsize/viewportSize-min.js',
                '<%= path_vars.bower_path %>/requirejs/require.js',
      ],
      dest: '<%= path_vars.js_src_path %>/vendor',
      filter: 'isFile',
      flatten: true
     }]
    }
  },


...

Okay, so here’s some more interesting stuff.  I like bower, but I don’t like having all the files that come with each bower component. It makes things messy, and you don’t need all that on your server, or say your GIT repo.

I’ve setup a ‘copy’ task, that will copy all the desired JS files, from their specific locations (from the bower install), to the one specified location, to where they will actually be used, by either drupal, or in this case RequireJS.  We’ll get to that. Let’s keep moving on through the Gruntfile.js

/*
 * grunt compass
 */
compass: {
  clean: {
        options: {
                clean: true
        }
  },
  dev: {
        options: {
                basePath: '<%= path_vars.theme_path %>',
        sassDir: 'scss',
        cssDir: 'css',
        imagesDir: 'images',
        importPath: [
        '<%= path_vars.foundation_path %>/scss/'
        ].concat(bourbon),
        bundleExec: true
        },
  },
  build: {
        options: {
                basePath: '<%= path_vars.theme_path %>',
        sassDir: 'scss',
        cssDir: 'css',
        imagesDir: 'images',
        importPath: [
        '<%= path_vars.foundation_path %>/scss/'
        ].concat(bourbon),
        outputStyle: 'compressed',
        noLineComments: true,
        environment: 'production',
        bundleExec: true,
        }
  }
},

We now have two different build options for compass. A ‘dev’ version that compiles all your sass (or scss), leaving in comments and line comments and all that good stuff.  Then a build version, where all that is striped out, and the css is compressed.

Right, compass, not sass.  I like the way compass outputs it’s line comments for debugging and some of the other options it has.  The gruntfile that comes with foundation is using a compiled version of sass, which is fast, but.. doesn’t have all the nice options. At this point, it’s your choice what ya like to use.

MOAR!

/*
 * grunt jshint
 */
jshint: {
  options: {
        jshintrc: '.jshintrc'
  },
  all: [
        'Gruntfile.js',
        '<%= path_vars.js_src_path %>/main.js',
        '<%= path_vars.js_src_path %>/modules/*.js',
        '!<%= path_vars.js_src_path %>/vendor/**/*.js'
  ]
},

A little hint hurt no body. This will just help us keep our JS clean.  The .jshintrc file is included in the code, but that’s beyond the scope of this.  For now, you can see that we are just keeping the gruntfile, main.js file (requirejs main file), everything in our custom modules folder, but nothing in the vendor folder.. since that’s all 3rd party js code.

/*
 * grunt uglify
 */
uglify: {
  options: {
        sourceMap: false
  },
  dist: {
        files: {
                '<%= path_vars.js_base_path %>/libs.min.js': [foundation_libs],
        '<%= path_vars.js_base_path %>/foundation.min.js': [foundation_js]
        }
  }
},

We’re just using uglify manually here, to uglify foundation’s JS code.  This is also pulled from foundations default gruntfile.  So, keeping foundation in mind, whispering sweet little nothings and giving snuggles here and there. Making sure it feels the love.   Onto the homestretch for our little gruntfile.

/*
 * grunt requirejs
 */
requirejs: {
  compile: {
        options: {
        baseUrl: '.',
        appDir: '<%= path_vars.js_src_path %>',
        dir: '<%= path_vars.js_bld_path %>',
        mainConfigFile: '<%= path_vars.theme_path %>/js/src/main.js',
        optimize: 'uglify',
        preserveLicenseComments: false,
        useStrict: true,
        wrap: true,
        removeCombined: true
        }
  }
},

There’s our friend require.  We’re telling require to move all our require related JS code into the ‘dist’ folder, and then uglifying it there for compression.  This task only runs when we do a ‘grunt build’, and not on “grunt dev”.  WHY?, cause you’ll see, stop whining. *arnold voice*

  /*
   * grunt watch
   */
  watch: {
        grunt: { files: ['Gruntfile.js'] },
        compass: {
        files: ['<%= path_vars.theme_path %>/scss/**/*.scss'],
        tasks: ['compass:dev']
        },
        js: {
        files: ['<%= jshint.all %>'],
        tasks: ['jshint', 'uglify']
        }
  }

And last but not least our watch task.  We’re wanting to watch for any changes to the gruntfile itself, the scss source files, or any of the JS files, which are defined in the jshint task.

Okay, last part.

/*
 * register 'dev' task
 * : for development compilation
 */
grunt.registerTask('dev', [
  'copy',
  'clean',
  'compass:dev',
  'uglify',
  'watch'
]);

/*
 * register 'build' task
 * : for production compilation
 */
grunt.registerTask('build', [
  'copy',
  'clean',
  'compass:build',
  'uglify',
  'requirejs'
]);

We’ve got two different running tasks.  The dev one being for when we want to work on the project. It first runs ‘copy’ to copy over all the bower related files we need to use. Then ‘clean’ to clean up our files. Then “compass:dev” to get some freshly compiled css out there and ready for development/debugging. Then ‘uglify’ (for foundation JS), Then ‘watch’ to watch for any changes.

The other task is reserved for production use.  When we’re happy with our code, and got everything figured out, we’ll run the ‘grunt build’ task. (Or just ‘grunt’ since that’s our default). The same ‘copy’, ‘clean’ tasks run.  But now we’re running compass:build, that will compress everything and remove needless comments and such.  Then ‘uglify’ (for foundation JS), Then require task will run, and move all the JS to the dist folder, and uglify it all. 

So at this point, you might be wondering what’s the point of the dist folder, how are we going to tell require to use everything in the ‘dist’ folder, and not ‘src’ for production.  This is where we do some PHP fun.  But before we do that, we do that snuggling we were talking about, and grab a coffee.

Part 2 is on the Way!

Download the code from GitHub

Sep 03 2015
Sep 03

Hey Drupalists! Any news – fine or great? Because we cannot restrain our emotions for longer: American researcher of world’s IT industry Clutch ranged us as one of 12 Top Web and Software Developers in Ukraine. Not bad, yes? Especially if to take into account that we are the only Drupal developer on the list.

Actually, the process of achieving such honorable positions was not so simple as resting on laurels. We have been working really hard in order to meet the most demanding client’s expectations – the main indicator for Clutch. And hurray – mark “Excellent” in the category “Market presence” (9,6 points) and “Very good” in “References” (8,83) and “Clients and experience” (8,05).

We suspect that it is due to the combination of the experience of our developers and designers and respectable client’s approach. In order to maintain it, we realised such project as DruDesk, and shared our love to Drupal and web development among other people through DrupalTour, DrupalCamps and IT School (you always can take a look on our blog for inspecting them).

By the way, guys from Clutch are very respectable in the world. The company operates in the area of web and software analytics, working up with a huge amount of data and determining the leaders in IT business all over the world. This is Washington based company with strong reputation and qualitative approach to the researches. The reports on IT leaders in different countries the company establishes annually.

Therefore, we are twice more pleased to be recognized as one of the best web and software companies in Ukraine and will be working even more insistently in order to deliver the best service to our dear clients.

Sep 03 2015
Sep 03

Reason #1: Drupal is Technology Ready

For the past 15 years Velir has been customizing and implementing top-tier content management systems. Given our focus on creating digital solutions, content management is at the core of almost every project we take on.

We’re veterans in the CMS space, but up until recently we exclusively worked with commercial CMS platforms. As the CTO of my agency, I wanted to explain why we’ve now decided to take the leap with Drupal.  

This post focuses on one reason we like Drupal: because it offers a solid technical foundation to build upon.  This foundation has been created by a large and passionate community, has shown an ability to evolve intelligently over time, and is being guided by strong leadership which is positioning the platform for the future.

The Strength of Open Source

Even a casual follower of the CMS space will have noticed how the “proprietary vs open source” conversation plays out regularly each year.  We have never bought into the FUD spread by both sides of this debate, as it’s usually a philosophical argument rather than a capability-based comparison of each platform.

But it is undisputable that open source software excels at providing tools and platforms for well understood problems.  As a result, over the past 20 years, there have been a number of problems that could be considered solved in the CMS space:  structured data, versioned content, workflow, accessible content APIs, and rich text editing (well, maybe not this one, yet). Drupal has a strong community with thousands of developers who have contributed to making sure these problems are solved well. Going forward we are excited to contribute to this community by supporting our team to contribute their own projects and solutions for Drupal.

Big Changes, Big Progress

As Drupal 8 has taken shape over the past few years, it has become clear that the project is evolving in intelligent ways.

The Drupal project was arguably growing too large to stay nimble - most everything had been built from the ground up. The continued growth of custom built sub-systems were demanding time and attention from the core team.  

In 2012, the collaboration between the Drupal and Symfony project teams signaled an important shift: a willingness to shed custom built pieces of the Drupal framework and partner with other proven projects for large pieces of functionality.  

This introduces a critical dependency on an outside project, but in exchange it provides a great deal of freedom for the Drupal community.  It allows them to apply more focus on solving the unique problems of web content management, rather than working on a series of problems that have been elegantly solved elsewhere.

Another key evolution we’re excited about is the embracing of an Object-Oriented Programming (OOP) approach in Drupal 8.  OOP offers a long history of promoting design patterns for solutions, which once learned, can easily be adopted to build well-architected systems.  Our experience tells us that these OOP principles and techniques will promote reuse, extensibility, testability -- and lead to solutions that are more efficiently maintained.  

Built with the Future in Mind

Accessible digital content is vital for modern organizations.  Content may be repurposed for display on the desktop or mobile web, pushed to native devices, or pulled into content aggregators like Flipboard or Prismatic.  

Dries Buytaert, founder of Drupal and co-founder of Acquia, has been cultivating a strong vision for how Drupal fits into the future of web content management. With core support for RESTful content APIs, schema.org support for boosting semantic tagging, and the rising buzz around Headless Drupal implementations, it’s clear that Drupal is being positioned to serve future content management needs.  

As an agency, Velir has remained focused on building deep expertise with the best platforms in the market.  We’ve been doing this long enough to know that no technology platform offers a panacea to a company’s digital needs.  

To sum up: We feel Drupal’s technical foundation is solid and we are reassured that the project is evolving intelligently to meet future needs.  In the next post, I’ll share some of the non-technical motivations behind why we have decided to invest in a Drupal practice.

Sep 03 2015
Sep 03

Pane Field is a new Drupal module by VDMi.
Most of the time we will give our users 3 Paragraphs types:

  • Text (just a simple WYSIWYG and a title field)
  • Text with image (simple WYSIWYG, title field, image field (media/scald/image), image position)
  • Image (media/scald/image)

Over time we learned that when content editors discover such flexible content, they immediately start thinking about exceptions. You’ll probably get some questions about “special” content like animations, videos and call-to-actions. That's where Pane Field comes in!

While most of these exceptions can be implemented in Paragraphs, it’ll become a problem when you have 10 different animations, or 10 different call to actions and the list keeps growing. That’s why we thought of another way to keep the ease of content editing, but have the flexibility of ctools panes. Which gives you - the developer - an very easy way to quickly create new pieces of content that the editor can use.

Ctools panes (also known as content types) are simple ctools plugins that basically define what they are, how they are configured and how they should be rendered. A definition is placed inside the same file that takes care of configuration/rendering. The definition will look something like this:

<?php
/**
 * Plugins are described by creating a $plugin array which will be used
 * by the system that includes this file.
 */

$plugin = array(
  'title' => t('Buy our product'),
  'description' => t('Buy our product and get another one for free call to action.'),
  'category' => t('Call to Actions'),
  'edit form' => 'shop_cta_buy_our_product_edit_form',
  'render callback' => 'shop_cta_buy_our_product_render',
  'admin info' => 'shop_cta_buy_our_product_admin_info',
  'required context' => new ctools_context_required(t('Node'), 'node'),
  'defaults' => array(
    'title' => 'Improve your daily workflow with our turboblender',
    'subtitle' => 'Buy now and get one free!',
    'button' => 'Buy now!',
    'button_link' => 'order',
  )
);

The callbacks will look like this for a simple pane, they are in the same file as the definition:

/**
 * 'Edit form' callback for the content type.
 */
function shop_cta_buy_our_product_edit_form($form, &$form_state) {
  $conf = $form_state['conf'];

  $form['title'] = array(
    '#title' => t('Title'),
    '#type' => 'textfield',
    '#default_value' => $conf['title'],
  );

  $form['subtitle'] = array(
    '#title' => t('Subtitle'),
    '#type' => 'textfield',
    '#default_value' => $conf['subtitle'],
    '#maxlength' => 2048,
  );

  $form['button'] = array(
    '#title' => t('Button'),
    '#type' => 'textfield',
    '#default_value' => $conf['button'],
  );

  $form['button_link'] = array(
    '#title' => t('Button Link'),
    '#type' => 'textfield',
    '#default_value' => $conf['button_link'],
  );

  return $form;

}

function shop_cta_buy_our_product_admin_info($subtype, $conf, $context) {
  $output = new stdClass();
  $output->title = '';
  $output->content = '<strong>'. t('Title') . ':</strong> ' . check_plain($conf['title']) . '</br>';
  $output->content .= '<strong>'. t('Subtitle') . ':</strong> ' . check_plain($conf['subtitle']) . '</br>';
  $output->content .= '<strong>'. t('Button') . ':</strong> ' . check_plain($conf['button']) . '</br>';
  $output->content .= '<strong>'. t('Button Link') . ':</strong> ' . check_plain($conf['button_link']) . '</br>';
  return $output;
}

function shop_cta_buy_our_product_render($subtype, $conf, $panel_args, $context) {
  $node = $context->data;
  $block = new stdClass();
  $block->title = '';

  $content = array(
    '#theme' => 'shop_cta_buy_our_product',
    '#path' => drupal_get_path('module', 'shop_cta'),
    '#title' => $conf['title'],
    '#subtitle' => $conf['subtitle'],
    '#button' => $conf['button'],
    '#button_link' => $conf['button_link'],
  );

  $block->content = $content;

  return $block;
}

And there you go, you created a new piece of custom content for your website. In the theme function you can use a template that has some custom HTML. Now you can enable the pane in the instance settings of the pane field:

As you can see, your new pane is available, all default ctools panes are also available.

When you edit content, you can now add a new Paragraph, select the paragraph type with the pane field and then select the new ctools pane:

You’re probably wondering “WHY?” at this moment

Pane Field causes extreme flexibility in your content without the hassle of creating a new paragraphs type, adding fields to them, adding preprocess functions, creating a bundle template. It allowes you to create exceptions to your base types much faster. It also is faster (in CPU time) compared to using a new Paragraphs type because it’s not a new entity, it’s just a field value with a reference to the ctools pane and some configuration values.

One big note: because the pane configuration is simply stored serialized in the field value, you can’t use them in stuff like Views or Search API (you can render the field and index that though).

Here is a more comprehensive article about how to write content panes.

Sep 02 2015
Sep 02

Upgrading Drupal distributions, technically referred to as installation profiles, can be tricky. If you aren't using Drupal Core, but rather a distribution of it, it's not possible to follow standard processes for upgrading Drupal core and contributed modules. You must upgrade the distribution as a whole.

In this article, we'll be working with the Web Experience Toolkit (wetkit) as the example distribution.

Assumptions

Steps

  1. Switch to your Web directory and make sure your working tree is clean.
    1. cd $(drush dd @site); git status
  2. Note any commits made to the distro since it was last upgraded. These will have to be reapplied (cherry-picked in git-speak) after the upgrade unless they were explicitly added to the distro in the latest release. Find them with this command.
    • git log profiles/wetkit/
  3. Make sure that you read and understand any distro-specific information on upgrading it. In this example, the documentation is available over at Release Cycle / Updates.
  4. This is a workaround until Drush up should update contrib profiles as well is fixed. Download the distro with the following command. For the version number, use the version that was released immediately after the version that you currently have installed. For example, if you have 7.x-1.4, you need to download 7.x-1.5. If you're multiple versions behind, you'll need to repeat these instructions multiple times. Jumping more than one release ahead could cause problems.
  5. Unpack it.
    1. tar zxvf /tmp/wetkit-7.x-Y.Z-core.tar.gz --directory /tmp
  6. Move your sites folder out of the way so that it won't be overwritten. It's necessary to do this as the administrator to maintain permissions on the files directory.
    1. sudo mv sites /tmp
  7. Copy the new release's files into your Web dir. Don't copy core's Git ignore file; keep ours. This is a workaround for Rename core .gitignore file to example.gitignore and add explanatory comments.
    1. cp -r /tmp/wetkit-7.x-Y.Z/.htaccess /tmp/wetkit-7.x-Y.Z/* .
  8. Replace the new default sites dir with our own.
    1. rm -rf sites
    2. sudo mv /tmp/sites .
  9. Remove the distro-specific Git ignore files, as they'll cause us to ignore files we shouldn't.
    1. rm $(find profiles/wetkit -name ".gitignore")
  10. Stage all of the changed files.
    1. git add --all
  11. Commit the upgrade with a comment like, "Issue #123: Upgraded the WxT distro from release 7.x-A.B to 7.x-A.C."
    1. git commit
  12. Cherry-pick each of the commits that you noted in the first step. Ideally, these are upstream patches that you either found or posted yourself while working on the distro. For each commit message, use something like "Issue #567: Applied patch from https://www.drupal.org/node/1417630#comment-6810906." so you'll know if you'll be need to re-apply it again, or if it's been committed (and you no longer need to worry about it).

    1. git --edit cherry-pick COMMIT_ID_1
    2. git --edit cherry pick COMMIT_ID_2
    3. ...
  13. Update the database schema.
    1. drush updb
  14. Clear all of the application caches.
    1. drush cc all
  15. Test the local site to ensure everything is working.

Notes

  • Whenever we override the distro's module versions in sites/all/modules/contrib (this should be an extremely rare occurence, if ever), we should set up Profile Status Check. In fact, it probably wouldn't hurt to include this module in all of the official distributions.
Sep 02 2015
Sep 02

There has been a radical shift in how enterprises want to use Drupal. Their focus is moving from sites to integrated services., and this change is typically accompanied with a set of new technologies, such as MongoDB and Node.js. Still, the role of Drupal has become more central than ever. How?

Nowadays, success on the Internet depends more on your content than your platforms. Writing and producing content is a surprisingly expensive and tedious process. When you have produced excellent content, you want to maximise its effectiveness and usage in various channels.Managing, combining and transforming content flexibly and effectively has always been one of the key strengths of Drupal - and content output has not.

Many Drupal users address this dillemma by installing Exove's MongoDB Indexer module that automatically copies all nodes and entities from Drupal to MongoDB in real time. The users are served using Node.js + Express or Koa that uses Twig.js, React, or Angular as user interface rendering layer. All the content changes are available in real time, shown with the latest, coolest, and greatest of front-end libraries available today, and blazingly fast with no caching whatsoever needed.

If you are interested in hearing more about this solution, check out Exove's Technology Director Kalle Varisvirta’s sessions in DrupalCon Amsterdam and DrupalCamp London.

As we in the Exove team realized, content is just another kind of data, and Drupal’s content model can be used to manage, combine and transform that data flexibly and effectively. While the amount of data will explode with Internet of Things / Everything, most connected devices will have either proprietary or bad - or both - managing applications, and combining data will be a huge dilemma.

But we don't think this will be the case for Drupal. It has all required input and output mechanisms to become a central point for IoT networks, connecting the sensors, devices, and people - using the same set of tools as in managing content. Need a web interface? Use Drupal as is or as a headless content source. Mobile app? Drupal REST APIs to rescue. Et cetera, et cetera.

Kalle Varisvirta has spoken about this in DrupalCamp Baltics in Tallinn and will also have a session at DrupalCon Barcelona.

And all of these great solutions have been achieved using Drupal 7. Think of the possibilities that the new architecture and component based approach of Drupal 8 will bring! The future sure looks bright.

Innovate to win with Drupal

In the celebration of the upcoming Drupal 8, we made a little game. Can you get all the way to Drupal 8? Have a try at www.drupalbird.com! You will, of course, find us at DrupalCon Barcelona too. Come and meet us at booth #300.

Finally, we are also hiring more excellent people to work with Drupal and other open technologies. Check out our open positions at exove.com/careers and join our happy gang.

Exove is a leading open technology web design and development company in the Nordic countries, the Baltic states and UK.

We help our customers to grow their digital business. We provide beautiful, functional, and business driven web and mobile sites and applications.

Sep 02 2015
Sep 02
147 - Using Drupal Console with Drupal 8 with Jesus Manuel Olivas - Modules Unraveled Podcast | Modules Unraveled

Skip to main content

Drupal Console

  • What is Drupal Console?
    • It is a suite of tools that you run on a command line interface (CLI) to generate boilerplate code and interact with a Drupal 8 installation.
  • How is it different from Drush? And are there overlapping features?
    • There are many similarities between these two tools, but the main difference is how it was built, using an object-oriented architecture and Symfony components.
  • Will we continue to use both? Or will Drupal Console replace Drush?
    • I think we will keep using both at least for now and maybe at some point we can merge both tools.
  • What are some of the things that you will keep using Drush for in Drupal 8?
    • Site alias (sync, backup), download modules, installing the site.
  • Are you planning to introduce those features into Drupal Console?
    • Yes we are actually working on site alias.
  • What are some things that Drupal Console can do that Drush can’t?
  • Who is the intended audience of Drupal Console?
    • You can use Drupal Console to help you developing faster and smarter with Drupal 8
    • Developers and SiteBuilders since you can Generate code and files required by a Drupal 8 module and Interacting with your Drupal installation (debugging services, routes) you can put your site in Maintenance mode or Switch system performance configuration.
    • But you can use this tool to Learn Drupal 8.
    • We are also working on a GUI so if you are afraid of CLIs we will provide a web site you will be able to use and select what you want to generate (module, controller, services, blocks, entities, etc…) and generate and download the generated code.
  • Would it be fair to say that right now, it’s most useful to developers who are actually writing code, while later, it will also be useful for sitebuilders who are used to using Drush to create site, install modules and themes, and perform routine tasks?

Use Cases

  • What are some things you can do with DrupalConsole?
    • Drupal Console help you developing faster and smarter with Drupal 8.
    • Generating the code and files required by a Drupal 8 module.
    • Interacting with your Drupal installation.
    • Learning Drupal 8.

Updates and Future

  • You were on the Drupalize.me podcast back in February talking about Drupal Console, what are some of the improvements that have been made since then? (Especially with Drupal 8 progressing the way it is.)
Sep 02 2015
Sep 02

Drupal: Add new operators to views filters (such as contained in CSV) or how to override default view's handlers

Today I'm going to show you how to turbo boost Drupal's default views filters with an example on how to add  a "Conatained in CSV" operator for Numeric and String filters.

Imagine a user wants to perform a batch operation on entities with ID's X, Y and Z. Unless they all appear on the same page, or you set the page size to inifinte this is impossible because Views Bulk Operations won't let you manually pick items between searches and/or pages.

We want something like this to happen:

It is very important:

  • Not to modify core.
  • Not to introduce new handlers, so that currently configured views will have this new features available without having to reconfigure them.

The first thing we need is a handler class that extends from views_handler:

<?php

/**
 * @file
 * Definition of ViewsHandlerFilterNumeric.
 */

namespace Drupal\fdf\Views\Handlers;

/**
 * Simple filter to handle greater than/less than filters
 *
 * @ingroup views_filter_handlers
 */
class ViewsHandlerFilterNumeric extends \views_handler_filter_numeric {
  
  /**
   * {@inheritdoc}
   */
  function operators() {

    $operators = parent::operators();

    $operators += array('containedin' => array(
        'title' => t('Is contained in (csv)'),
        'short' => t('contained in'),
        'method' => 'op_contained',
        'values' => 1,
      ),);

    return $operators;
  }

  /**
   * {@inheritdoc}
   */
  function value_form(&$form, &$form_state) {
    parent::value_form($form, $form_state);
    if (isset($form['value']['value']['#type'])) {
      $form['value']['value']['#maxlength'] = NULL;
    }
    if (isset($form['value']['#type'])) {
      $form['value']['#maxlength'] = NULL;
    }
  }

  /**
   * {@inheritdoc}
   */
  function op_contained($field) {
    //dejamos solo valores numéricos
    $arr = explode(',',$this->value['value']);
    foreach($arr as $key => &$item) {
      $item  = preg_replace('#[^0-9]#', '', $item);
      if(!is_numeric($item)) {
        unset($arr[$key]);
      }
      else {
        $arr[$key] = (int) $arr[$key];
      }
    }
    $this->query->add_where($this->options['group'], $field, $arr);
  }
}

And now override the default handlers by consuming hook_views_data_alter:

/**
 * Implements hook_views_data_alter().
 */
function fdf_views_data_alter(&$data) {
  // Cambiar algunos handlers por otros customizados.
  foreach ($data as &$item) {
    foreach ($item as &$subitem) {
      if (isset($subitem['filter']['handler']) && $subitem['filter']['handler'] == \views_handler_filter_string::class) {
        $subitem['filter']['override handler'] = \Drupal\fdf\Views\Handlers\ViewsHandlerFilterString::class;
      }
      elseif (isset($subitem['filter']['handler']) && $subitem['filter']['handler'] == \views_handler_filter_numeric::class) {
        $subitem['filter']['override handler'] = \Drupal\fdf\Views\Handlers\ViewsHandlerFilterNumeric::class;
      }
    }
  }
}

Piece of cake! For this to work you will of course need the amazing XAutoload module.

xjm
Sep 02 2015
Sep 02

Start: 

2015-09-04 00:00 - 23:30 UTC

Organizers: 

catch xjm

The next beta release for Drupal 8 will be beta 15! (Read more about beta releases.) The beta is scheduled for Friday, September 4, 2015. To ensure a reliable release window for the beta, there will be a Drupal 8 commit freeze from 00:00 to 23:30 UTC on September 4.

Beta 15 will include a couple of important API changes. See SafeMarkup::set(), SafeMarkup::checkPlain(), and other methods are removed from Drupal 8 core for details.

xjm
Sep 02 2015
Sep 02

Before the release of the first Drupal 8 beta, Twig's autoescape functionality was enabled in Drupal 8 core. At the time, the SafeMarkup class was added in order to integrate Drupal core's own filtering and escaping APIs with Twig's.

Following extensive critical work on Drupal 8's sanitization APIs, most of the public API for the SafeMarkup class has been removed. Of particular note: for the next beta (beta 15), SafeMarkup::set() will be removed and SafeMarkup::checkPlain() will be deprecated for removal before 8.0.0.

SafeMarkup::set() will be removed

The SafeMarkup::set() method was documented for internal use when it was originally added. However, Drupal 8 core (as well as some contrib and custom modules) used it incorrectly to avoid unwanted escaping, because at the time there were not good examples for all usecases, particularly for code that assembled together multiple different strings of markup. Now, all core usages have been removed, and the change record has been updated to include recommended strategies for concatenating markup strings. Refer to this change record to replace any remaining usages of SafeMarkup::set().

SafeMarkup::checkPlain() is deprecated and will be removed

In Drupal 7 and earlier, check_plain() was important for sanitizing untrusted input for output to the page. In Drupal 8, Twig's autoescape provides this functionality for any variables passed to a Twig template, and other APIs are used in other circumstances.

When explicit escaping is needed, the most direct replacement for check_plain() or SafeMarkup::checkPlain() is Html::escape(). See the change record section on escaping text in Drupal 8 for details.

The correct use of t() and SafeMarkup::format() is not affected and these functions will still automatically escape input passed in the second parameter for a @variable or %variable placeholder. See the SafeMarkup::format() documentation for details.

Sep 02 2015
Sep 02

Jen Lampton and Nate Haug (co-founders, BackDrop CMS) explain their fork of Drupal 7: why they felt the move was necessary; who benefits from it; and the Drupal community’s reaction.
There’s also a blatant plug for Drupal Watchdog. (Which you should subscribe to, right now, before you forget: https://drupalwatchdog.com/subscribe/2015)

Sep 02 2015
Sep 02

Watching the Drupal release cycle ebb and flow reminds me of sitting on the beach as the waves roll in. There is Drupal 5! It’s getting closer and closer! Finally it crashes on the beach in a splash of glory. But immediately, and initially imperceptibly, it starts to recede, making way for Drupal 6. And so the cycle goes, Drupal 5 recedes and Drupal 6 rushes in. Drupal 6 is overcome by Drupal 7. And now, as I write this, we’re watching as Drupal 7 washes back and Drupal 8 towers over the beach.

Each new version of Drupal is a huge improvement on the one before. But each version also introduces uncertainties. Is all that new functionality necessary? Has Drupal core become ‘bloated’? Does it do too much (or too little)? Will it be performant? How much work will it take to implement? Is it still buggy? And, arguably, the most important question of all, when will the contributed modules we need catch up?

So when is Drupal “ready” for our clients? If clients want a new site in this between-releases period, do we build it on the solid, safe, predictable older release? Or jump in with the shiny, new, improved release that is just over the horizon, or just released? Or do we wait for the new version to mature further and delay building a new site until it’s ready?

We’ve dealt with these questions over and over through the years. Knowing when to embrace and build on a new major release requires careful consideration along several axis, and making the right decision can be the difference between success and failure.Here are the guidelines I use.

How Complex is the Site?

If the site is simple and can be built primarily with Drupal Core, than the shiny new version is likely a safe bet. Contributed modules may add nice features, but creating the site without many (or any) of them will mitigate your risk.

Each new Drupal release pulls into core some functionality that was previously only possible using contributed modules. Drupal 5 allowed you to create custom content types in the UI. Drupal 7 added custom fields to core. Drupal 8 brings Views into core. And every Drupal release makes some contributed modules obsolete. If the new core functionality is a good match for what the site needs, we’ll be able to build a new site without using (and waiting for) those contributed modules, which would be a good reason to build out on the frontier.

Correspondingly, if the site requires many contributed modules that are not included in core, we’ll have to wait for, and perhaps help port, those modules before we can use the new version. If we can’t wait or can’t help we may have no choice but to use the older version, or wait until contributed modules catch up.

How Tight is the Deadline?

It will probably take longer to build a site on a new version of Drupal that everyone is still getting familiar with than an older version that is well understood. It always takes a little longer to do things when using new processes as when repeating patterns you’ve used many times before.

Delays will also be introduced while waiting for related functionality to be ready. Perhaps there is a contributed module that solves a problem, but it hasn’t been ported yet, so we have to stop and help port it. Or there may not be any contributed module that does anything close to what we need, requiring us to plan and write custom code to solve the problem. Latent bugs in the code may emerge only when real world sites start to use the platform, and we might have to take time to help fix them.

In contrast, if we’re using the mature version of Drupal, odds are good that the bugs have been uncovered and there is code somewhere to do pretty much anything that needs to be done. It might be a contributed module, or a post with examples of how others solved the problem, or a gist or sandbox somewhere. Whatever the problem, someone somewhere probably has already run into it. And that code will either solve the problem, or at least provide a foundation for a custom solution, meaning less custom code.

Basically, if the deadline is a key consideration, stick with the tried and true, mature version of Drupal. There just may not be enough time to fix bugs and create custom code or port contributed modules.

How Flexible is the Budget?

This is a corollary to the previous question. For all the same reasons that a deadline might be missed, the budget may be affected. It takes more time (and money) to write custom code (or stop and port related contributed modules). So again, if budget is tight and inflexible, it might be a bad decision to roll out a site on a shiny new version of Drupal.

How Flexible is the Scope?

If we use the latest, greatest, version of Drupal, is the scope flexible enough to allow us to leverage the way the new code works out of the box? If not, if the requirements of the new site force us to bend Drupal to our will, no matter what, it will require custom code. If we build on a more mature version of Drupal we may have more existing modules and code examples to rely on for that custom functionality. If we build on the bleeding edge, we’ll be much more on our own.

Where is the Data Coming From?

If this is a new, from-scratch site, and there’s no need to migrate old data in, that would be a good use case for building this shiny new site with the latest, greatest version of Drupal.

But if there is an existing site, and we need to not only create a new site, but also migrate data from the old site to the new, the question of which version to use gets more complicated. If the source is another, older Drupal site, there will (eventually) be a supported method to get data from the old site to the new site. Even so, that may not be fully ready when the new version of Drupal is released. Drupal 8 uses Migrate module for data migration, but only the Drupal 6 to Drupal 8 migration path is complete, and that migration process will likely improve in future point releases. The upgrade path in previous versions of Drupal was often fraught with problems early on. It's something that never gets fully baked until the new version is in use and the upgrade process is tested over and over with complex, real-world sites. So the need to migrate data is another reason to use the older, more mature version of Drupal (or to wait until the new release is more mature).

How Important Is the New Hotness?

Every version of Drupal has a few things that just weren’t possible in previous versions. CMI (Configuration Management) in Drupal 8 provides a much more rational process for deploying code and configuration changes than Drupal 7 does. Drupal 7 requires banging your head against the limitations of the Features module, which in turn is hampered by the fact that Drupal 7 core just isn’t architected in a way that makes this easy. And Drupal 8 core has built-in support for functionality previously only possible by using one or more additional Services modules in Drupal 7.

If these new features are critical features, and if struggling to solve them in older versions has been a time sink or requires complex contributed modules, it makes sense to dive into the latest greatest version that has this new functionality built in.

How Long Should It Last?

A final question is how often the site gets re-built. If it is likely to be redesigned and re-architected every two or three years to keep it fresh, there should be little concern about rolling out on the older, mature version of Drupal. Drupal 7 will be supported until Drupal 9 is released, and that is likely to be a long time in the future. If it will be many years before there will be budget to re-build this site that might be a reason to build it on the latest version, delaying the project if necessary until the latest version is fully supported by contributed modules and potential problems have been worked out.

It’s Complicated!

The ideas above are just part of the thought process we go through in evaluating when to use which version of Drupal. It’s often a complex question with no black and white answers. But I take pride in our ability to use our long experience with Drupal to help clients determine the best path forward in these between-release periods.

Sep 02 2015
Sep 02

By Steve Burge 02 September 2015

bolt module drupal

Views Bulk Operations (VBO) is one of those modules whose name and Drupal.org description doesn't indicate how useful it is.

Here's the short version of what VBO does it:

  • Allows you quickly select all the items displayed in a View.
  • Allows you to perform advanced operations on all the items you selected.

So, VBO enables you to greatly speed up your site administration, particularly if you have a lot of data:

  • Want to quickly delete 1000's of user or comments? VBO can do that.
  • Want to update 100's of content items at once? VBO can do that.

Let Robert Ring introduce you to VBO in this video:

This video is part of our Better Drupal Administration class, which is full of useful tips like this.

Sep 02 2015
Sep 02

By Steve Burge 02 September 2015

bolt module drupal

Drupal has strong default caching systems, but the Boost module significant improvements.

Boost creates a cache in the file system rather than the database, so Drupal never needs to commuicate with the database. This provides major a performance and scalability boost for sites that receiving mostly anonymous traffic (it doesn't help so much with logged-in users). 

Boost will cache and compress your site's HTML, XML, Ajax, CSS and Javascript. There's also a built-in that will regenerate pages once they are marked as expired.

Boost isn't always this easiest module to set-up, but this video will help you get started.

This video is part of our "Speeding Up Your Drupal Site" class.

Sep 02 2015
Sep 02

The biggest risk for any website is security. Research has shown that the average cost of a data breach is several million dollars. The last two years have seen a number of high-profile security breaches affecting millions of people, including:

  • 145 million eBay users
  • 70 million Target customers
  • over 20 million U.S. government job applicants.

That’s why it’s important to ask yourself: Does your company have the expertise and resources to manage your websites’ security?

Acquia Cloud engineering and operations teams are constantly responding to security threats and updating hundreds of mission-critical software packages behind the scenes. Do your engineers know how to manage the complexity of the hundreds of mission-critical software packages required to run modern websites? Do they have the processes in place to get notified of vulnerabilities and roll out changes before attackers can exploit them?

It can easily cost millions of dollars for the expertise and development required to manage your websites’ security in-house. If you’re managing your own security and not spending that money, you may be making trade-offs that put your business and your reputation at risk.

Many companies can’t afford that kind of investment in security expertise, and that’s why many of them choose Acquia Cloud. Acquia Cloud removes a number of risks and challenges of building and running websites, including security risks. We have invested those millions of dollars in expertise, processes, and hardened security architecture so that our customers stay safe without having to think about it. And we are evaluated annually by independent third party auditors to validate our practices and alignment with standards.

Our security practices extend beyond our platform and infrastructure. Our Remote Administration team can update user applications when Drupal core or contributed modules are out of date. Password strength and multi-factor authentication requirements can be enforced to log into the Cloud administration dashboard, and actions on that dashboard are managed via granular access controls (complete with an activity stream to audit changes). We also offer protection at the network level with Acquia Cloud Edge to deny malicious web requests and Acquia Cloud Shield for keeping especially sensitive information inaccessible from the public internet.

One other way we make sure our customers stay safe is to disable software that has reached its end-of-life and is no longer receiving security updates. For that reason, we recently disabled PHP 5.3 on our platform (the lowest version we now support is PHP 5.5). As we do whenever we deprecate functionality, we provided our customers an extended notice period and worked with them to make sure their applications work on newer, secure versions of PHP. If you’re using a vendor that continues to run insecure versions of such mission-critical software, you should think twice about their security practices. When you use Acquia Cloud, we stay on top of those risks so that you don’t have to.

One example of our commitment is our response to security events, like when we were the only Drupal platform-as-a-service company to protect all customer sites against the critical Drupalgeddon vulnerability without any loss of site functionality or availability. Similarly, when vulnerabilities like Heartbleed, POODLE, Shellshock, and others (from the past year alone) shook the foundations upon which websites rely, Acquia was able to rapidly update our entire fleet of affected servers while keeping our customers’ sites online.

If you’re unsure about your security situation or requirements, talk to us and we can help you figure out what you need. One option is our security workshop where we work with you to analyze your situation and offer recommendations.

It’s better to find out your requirements - especially legal ones like PCI compliance - as early as possible, before you commit to a vendor that puts the cost burden on you.

Sep 02 2015
Sep 02

For my Drupal 7 development I always use an include file to override settings from the settings.php file. Other developers use this trick too. In Drupal 8 you can find some (disabled) code in the settings.php file to support this. To give you a kick start, I want to share the settings.local.php that I use for my Drupal 8 development.

Copy the below code into a settings.local.php file and place it in the settings directory. Uncomment the code settings.php (below) to activate the include function.

<?php

$config

['system.site']['name'] = 'Drupal 8 DEVELOPMENT';
$config['system.logging']['error_level'] = 'all';             // hide|some|all|verbose
$config['system.performance']['cache.page.max_age'] = 0;      // Time in seconds, 0 = no caching
$config['dblog.settings']['row_limit'] = 1000;                // Max. entries in log, 0 = all entries
$config['system.performance']['css.preprocess'] = true;       // true|false
$config['system.performance']['js.preprocess'] = true;        // true|false
$config['system.performance']['css.gzip'] = true;             // true|false
$config['system.performance']['js.gzip'] = true;              // true|false
$config['system.performance']['response.gzip'] = true;        // true|false
$config['system.cron']['threshold.autorun'] = 0;              // Time in seconds, 0 = never run
$settings['file_public_path'] = 'sites/default/files';
$settings['file_private_path'] = '';
$config['system.file']['path.temporary'] = '/tmp';
$config['system.file']['temporary_maximum_age'] = 21600;      // Time in seconds, 0 = never delete
?>
This is how the code in settings.php should look now:

<?php
/**
 * Load local development override configuration, if available.
 *
 * Use settings.local.php to override variables on secondary (staging,
 * development, etc) installations of this site. Typically used to disable
 * caching, JavaScript/CSS compression, re-routing of outgoing emails, and
 * other things that should not happen on development and testing sites.
 *
 * Keep this code block at the end of this file to take full effect.
 */
if (file_exists(__DIR__ '/settings.local.php')) {
 include 
__DIR__ '/settings.local.php';
}
?>

Do note that, different from Drupal 7, these overrides are not visible in the admin interface. For that purpose I have added an overridden site name to give you some visible proof that the configuration is overridden.
Sep 02 2015
Sep 02

In a post last week I discussed versioning in Drupal and briefly touched on version numbers in info files. A lot of my focus over the last few months has been around composer and Drupal, one issue for Drupal when using composer for contrib modules is that the info file is pulled from git and therefore doesn’t have the version number, project name or datestamp in the info.yml file that is added by the drupal.org packager.

I am currently working on a patch for the update module which will get the project name from the module’s composer.json. This is just the first step because the project name is what’s needed for the module to show on the update status page.

The patch adds a composer parser service, which like the info parser service that parses the info.yml file of a module, this parses the composer.json file of a module. From here we can get the project name such as “drupal/devel”, then by exploding that we can get the project name from the second element in the array.

Composer.json files sometimes include a version number so we could use that too, but this is vary rare. The only real option for the version number is the git branch or git tag, this is how the git deploy module works.

Please enable JavaScript to view the comments powered by Disqus.

blog comments powered by
Sep 02 2015
Sep 02

In a previous article about using AdvAgg to inline critical path CSS, I briefly mentioned an optional step to reducing the number of bundles produced by the aggregator. I’d like to walk through that process now, using the Fourword as an example.

If you’re not familiar with the Advanced CSS/JS Aggregation module for Drupal (called AdvAgg for short), it is the go-to solution for frontend performance optimization in Drupal. This article describes the process for AdvAgg 7.x-2.14. Older or newer versions might have slightly different configuration options.

Use-case: removing files from an aggregate

In my situation, I had an issue where using the AdvAgg Bundler was producing more than one aggregate for the public visitors to the site. The extra aggregates were coming from sources that, upon inspection, were found to be completely unused by visitors to the site. I decided the simplest solution was to suppress them for anonymous users, completely eliminating the aggregates that were composed of these files.

First, I went to /admin/config/development/performance/advagg/info to load the Information tab. This page has lots of options but we’ll focus on one section for our use-case: the last section which is labeled “Get detailed info about an aggregate file.”


Screenshot of AdvAgg Detailed Information section
Screenshot of AdvAgg’s detailed info tool.

Identify files within aggregates

The interface is simple: there’s a text field for you to enter a file name. You can enter a specific file that might be used on your site (e.g. modules/system/system.base.css) or you can enter an aggregate filename. Assuming you’ve already got AdvAgg enabled, entering aggregate filenames will be the most useful. Go ahead and enter the filename of the unwanted aggregate. It will be a lengthy filename made up of random letters and numbers.

I’d suggest loading your site in incognito (in Chrome) or Private Browsing mode (in Firefox) if you want a quick method of looking at the site as an anonymous visitor. This will be more reliable than looking at the aggregates generated for a logged-in admin, which might be quite different.

Once you’ve pasted the aggregate filename and clicked the Lookup Details button, AdvAgg will return all the information it has about this aggregate: the AdvAgg settings associated with it, the hooks which caused it to be created or altered into its current state, and the files which were combined to create it. Let’s focus on the files, which are labeled [files] in the Array that AdvAgg returns. Here’s a sample of the output you’re looking for:

[files] => Array
  (
    [sites/all/modules/contrib/fences/field.css] => Array
      (
        [filesize] => 457
        [mtime] => 1407138086
        [filename_hash] => RMBNT_K3MAIy2ar1d8XH5YHHoHuiA6hpuYF_vFaZJxM
        [content_hash] => GMyvgHJxaIu9_qs6iF6TOcu_cN4fb3wb5TI3C_020iE
        [linecount] => 6
        [data] => sites/all/modules/contrib/fences/field.css
        [fileext] => css
        [cache_id] => advagg:file:RMBNT_K3MAIy2ar1d8XH5YHHoHuiA6hpuYF_vFaZJxM
        [group_hash] => 00000003 ypA6vopnjoro5_v18jPM_NMJh2Xy9NfpYXkIqcv8_TI
      )
  )

Each item in the array has a filename as an index. That’s the information we’re interested in at the moment. Scanning the list, I noticed that my unwanted aggregate contained CSS from a few familiar modules: ctools, views, the date and date_popup module, and a few others. Since I’m familiar with the internals of the Fourword, I know that a normal visitor will never see any of these styles; there are no date popups, no auto-complete boxes, or ajax requests which use that characteristic Drupal throbber. They are safe to completely remove for anonymous users.

Note: AdvAgg can’t tell you if a visitor needs the files it finds; you must determine its relevance based on knowledge of your specific Drupal implementation. Be sure to test your work thoroughly to make sure it’s not causing problems for your users!

Removing CSS files within Drupal

Once I determined which files to remove for my visitors, I went back to fourword_theme where I previously inlined our critical CSS. In this case the changes are all related to a particular theme, but if you prefer to use a custom module that’s a good home for this code too:

<?php

/**
 * Implements hook_css_alter().
 *
 * Alter CSS to optimize our theme.
 */
function fourword_theme_css_alter(&$css) {
  global $user;

  $exclude = array(
    // Contrib CSS
    'sites/all/modules/contrib/date/date_api/date.css' => FALSE,
    'sites/all/modules/contrib/date/date_popup/themes/datepicker.1.7.css' => FALSE,
    'sites/all/modules/contrib/views/css/views.css' => FALSE,
    'sites/all/modules/contrib/ctools/css/ctools.css' => FALSE,
    'sites/all/modules/contrib/panels/css/panels.css' => FALSE,
  );

  // Exclude unnecessary CSS for anonymous users.
  if ($user->uid == 0) {
    $css = array_diff_key($css, $exclude);
  }
}

My logic is luckily quite simple: exclude the files for anonymous users. Our content editors and other logged-in users still need these styles, since we make use of them for authoring posts and other Drupal admin tasks.

Since the $css variable is passed by reference into all alter hooks within Drupal, there’s no need to return anything; the CSS is now permanently altered for this page load.

Debugging gotchas

During the course of debugging, you’ll find yourself clearing the cache often in order to see the new aggregates. Don’t forget to supply the new filename to AdvAgg once you’ve done so. If you check the same filename again, it will show you the same list of files and it might seem like your changes didn’t take.

When you’re satisfied, clear that cache one more time to be sure that visitors are getting the latest and greatest.. your page should load with one less aggregate! High five!

Learn more at DrupalCon Barcelona

If you liked this article and are attending DrupalCon Barcelona in a few weeks, consider taking our frontend performance training, led by myself and web chef Taylor Smith. We’ll cover all aspects of frontend performance in Drupal, from workflow to performance budgeting.

Register for Frontend Performance training

Sep 02 2015
Sep 02

Post date: 

September 2 2015

Category: 

Announcements

Tags: 

drupal planet

The Realityloop team have been contributing at DrupalCon sprints since 2010, mentoring at sprints since 2013, and I've personally been a lead mentor at sprints since DrupalCon Austin last year. To Realityloop the best way to help an open source project thrive is to contribute back and this is one of the ways that we do that.  The whole Realityloop whole team we be mentoring at DrupalCon Barcelona so we'd love to see you attending.

What is a Sprint?

A sprint is simply a get-together of people involved in a project to further a focused development of the project. In the DrupalCon context it's where we all get to sit in a room together and make Drupal better.

Come join us at the DrupalCon sprints

DrupalCon Barcelona is only a few weeks away, and as usual there will be a lot of sprinting happening around and during the event! 

If you are interested in contributing - and we'd love you to get involved - there are a lot of resources available. If you've never contributed in the past you shouldn't assume you don't have the skills to contribute. Many of the things being worked on need people with experience in things other than coding, such as; design, project management, writing documentation, dev ops, testing, user experience, marketing, or just helping hands. 

If you will be mentoring at the First Time Sprinters Workshop we really appreciate you giving your time to help get new people involved.

To all who contribute, open source projects thrive with contribution from their communities so by contributing you are changing the world and directly helping Drupal grow. For that we thank-you!

On the Internet

Check the Barcelona website for the sprint schedule and location information. Sprinting is generally happening all the time and at multiple locations, if you will be mentoring keep an eye on the BoF schedule for the mentoring and triaging sessions.

On the Drupal website you can also find a lot of information on ways to get involved in the Drupal project and core mentoring or how to set up a local Drupal development environment for the First Time Sprinters workshop, how to use the issue queue and tasks for new contributors.

During the conference

At the conference there will be a Core Mentoring booth in the Exhibit Hall (booth 100), It is staffed by mentor volunteers and if you have questions about getting involved, being mentored.. or becoming a mentor, or anything else related to contributing please pay us a visit we'll be happy to answer your questions.

On the Friday after a DrupalCon there is always an all-day sprint. The attendees of this sprint will typically be working on any one of Drupal core, contributed modules and themes, Drupal related project, and even Drupal.org itself.

  • First-Time Sprinter Workshop
    If this will be your first Drupal sprint or you need help setting up your computer, then the First-Time Sprinter Workshop in room 116 is especially for you. It is hed in the morning of the Friday sprint, and mentors will be on hand to help you get setup and learn about the various tools used for contributing. If you do not have a working Drupal 8 environment on your machine installed from the git repositry, please attend this workshop. The mentors at this workshop will be focused on getting you ready to contribute so you can spend the afternoon at the..
     
     
  • Mentored Core Sprint
    This is all day session is where new contributors can come to get mentored help. Mentors at the Mentored Core Sprint in room 115 will help you pair up with another new contributor or several contributors, find an issue or issues that you are interested in to work on together, and work through the process of contributing. All skill levels and roles are welcome. This is not a developer only event. If you don't yet have a Drupal 8 development environment installed via git then for your benefit it is suggested to attend the First-Time Sprinter workshop before coming to this room.
     
     
  • General Sprints
    Experienced contributors are encouraged to attend the all-day General Sprints in room 114. Typically contributors in this area form groups to work on key initiatives, or you can form your own.
     


A reminder to sprint leads, mentors and experienced contributors

Make some time before the conference begins to update your issues. If you have easier issues tag them as "Novice", and review your issues for missing tags, especially ones that less experienced contributors or non-developers can assist with. some of these might be; rerolls, manual testing, change notice updates, or documentation

The mentoring team will be triaging the issue queue throughout the week. If you are interested in helping please attend the related BoF to discuss and pick issues appropriate for the Friday sprint.

Also, remember that extended sprints actually start on the 19th September, so it would be great if you can find time to update things before then.

Moral of the story

If your attending a DrupalCon and not attending the Sprints, your really missing out on a quite large part of the DrupalCon experience just one of the reasons I would urge anyone interested to get involved and contribute.

You'll get to make a lot of new friends and help make Drupal a better project, learn to be a better coder if that is your interest, find smart people to collaborate with, grow your karma quotient, have a lot of fun and maybe even get on stage for a live code commit!

Even if you're not a coder, you can be confirming bug reports, testing patches, writing documentation, creating marketing or training materials, planning event logistics, or even organizing your own local code sprint or camp... and this is just a small selection of the stuff that you'll be able to do as a contributor. Come change the world!

Sep 01 2015
Sep 01

Adapted from a post by the Nerdary  that basically deals with the problem of having .htaccess files that are different on your local and other environments.

This example deals with the headache of https and not wanting your local environment to automatically redirect to HTTPS. I am only posting the relevant code that sets up the environment variable.

<IfModule mod_rewrite.c>
  RewriteEngine on

  ### SET UP ENVIORNMENTS ###

  # Default environment is master ###
  RewriteRule .* - [E=ENVIRONMENT:master]

  # Environment is set to develop if the server names ends in local.com
  RewriteCond %{SERVER_NAME} .local.com$
  RewriteRule .* - [E=ENVIRONMENT:develop]
  ## END SET UP ENVIRONMENTS ###

  # Redirect HTTP to HTTPS only if environment is master
  RewriteCond %{ENV:ENVIRONMENT} master
  RewriteCond %{HTTPS} off
  RewriteCond %{HTTP:X-Forwarded-Proto} !https
  RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

</IfModule>

Another cool thing about this is that we've also created a new $_SERVER['ENVIRONMENT'] variable that we can access in php. 

Sep 01 2015
Sep 01

If you are starting to learn about Drupal 8, you must have come across a term called "Dependency Injection". If you are wondering what it means, then this is the post you should read. Through examples, you will learn why dependency injection is useful for decoupling the code as well as unit testing effectively.

In the post on PHP Inheritance, we created HondaAccord and ChevyRam classes, both of which extend the Vehicle class. Vehicle has getWarrantyLeft(), drive() and getMilesDriven() methods. getWarrantyLeft() method is being overridden by ChevyRam while HondaAccord has a trunk and implements putInTrunk() and takeFromTrunk() methods. Vehicle also has color, warranty and milesDriven properties.

Let's also assume that there is a Person class and each person owns a vehicle. We are initializing this vehicle in the constructor of the Person class. Person has methods travel() and getDistanceTraveled(). travel() method uses Vehicle's drive() method and getDistanceTraveled() method uses the Vehicle's getMilesDriven() method. Here is how Vehicle.php and Person.php files look:

<?php

/**
 * Vehicle class.
 */
class Vehicle {

  // Color of the vehicle.
  public $color;

  // Miles driven.
  private $milesDriven;

  // Warranty available.
  public $warranty;

  /**
   * Default constructor.
   *
   * @param string $color
   *  Color of the vehicle.
   * @param int $milesDriven
   *  Number of miles driven already.
   * @param int $warrantyProvided
   *   Number of miles of warranty provided with the vehicle.
   */
  function __construct($color, $milesDriven = 0, $warranty = 100000) {
    $this->color = $color;
    $this->milesDriven = $milesDriven;
    $this->warranty = $warranty;
  }

  /**
   * Returns miles of warranty left on the vehicle.
   *
   * @return int
   *   Miles of warrnty left on the vehicle.
   */
  public function getWarrantyLeft() {
    if ($this->warranty - $this->getMilesDriven() > 0) {
      return ($this->warranty - $this->getMilesDriven());
    }

    return 0;
  }

  /**
   * Drive the vehicle. This will add to miles driven.
   *
   * @param int $miles
   *   Number of miles driven in the current trip.
   */
  public function drive($miles) {
    if ($miles > 0) {
      $this->milesDriven += $miles;
    }
  }

  /**
   * Returns the number of miles driven in total.
   *
   * @param int
   *   Total number of miles driven.
   */
  public function getMilesDriven() {
    return $this->milesDriven;
  }
}

/**
 * HondaAccord class.
 */
class HondaAccord extends Vehicle {

  // Stuff in the trunk.
  public $stuff;

  /**
   * Put stuff in trunk.
   *
   * @param mixed $stuff
   *   Stuff to be put in the trunk.
   */
  public function putInTrunk($stuff) {
    $this->stuff = $stuff;
  }

  /**
   * Take stuff out from the trunk.
   *
   * @return mixed
   *   Stuff returned from the trunk.
   */
  public function TakeFromTrunk() {
    $stuff = $this->stuff;
    unset($this->stuff);
    return $stuff;
  }
}

/**
 * ChevyRam class.
 */
class ChevyRam extends Vehicle {

  /**
   * Returns miles of warranty left on the vehicle.
   *
   * @return int
   *   Miles of warrnty left on the vehicle.
   */
  public function getWarrantyLeft() {
    if ($this->warranty - $this->getMilesDriven() > 0) {
      return (2 * ($this->warranty - $this->getMilesDriven()));
    }

    return 0;
  }

}

?>
<?php

require_once 'Vehicle.php';

/**
 * Person class.
 */
class Person {

  // Vehicle
  public $vehicle;

  /**
   * Default constructor.
   */
  function __construct() {
    $this->vehicle = new HondaAccord('red');
  }

  /**
   * Let the person travel in his vehicle.
   *
   * param int $miles
   *   Number of miles that the person travels.
   */
  public function travel($miles) {
    $this->vehicle->drive($miles);
  }

  /**
   * Returns the number of miles that the person has traveled.
   *
   * @return int
   *   Number of miles that the person has traveled.
   */
  public function getDistanceTraveled() {
    return $this->vehicle->getMilesDriven();
  }
}

$you = new Person();
$you->travel(2000);
echo 'Distance traveled: ' . $you->getDistanceTraveled() . "\n";

?>

Following is the output when executing Person.php file:

$ php Person.php
Distance traveled: 2000

You will notice that in the constructor of Person class, we are initializing the vehicle he owns to be a red Honda Accord. So this code works fine as long as we expect all the people to own a red Honda Accord. But obviously this is not the case in real life. In Inheritance in PHP post, we had a case where I owned a red Chevy Ram truck while you owned a white Honda Accord. So how do we initialize two people, you and me, such that we both own different vehicles? The easiest way is to remove the initialization of the vehicle from the Person class. Instead initialize it outside and pass the initialized Vehicle class to the Person class in the constructor. This is how the file Person.php will look after this change:

<?php

require_once 'Vehicle.php';

/**
 * Person class.
 */
class Person {

  // Vehicle
  public $vehicle;

  /**
   * Default constructor.
   *
   * @param Vehicle
   *   Vehciel object.
   */
  function __construct($vehicle) {
    $this->vehicle = $vehicle;
  }

  /**
   * Let the person travel in his vehicle.
   *
   * param int $miles
   *   Number of miles that the person travels.
   */
  public function travel($miles) {
    $this->vehicle->drive($miles);
  }

  /**
   * Returns the number of miles that the person has traveled.
   *
   * @return int
   *   Number of miles that the person has traveled.
   */
  public function getDistanceTraveled() {
    return $this->vehicle->getMilesDriven();
  }
}

$hondaAccord = new HondaAccord('white');
$you = new Person($hondaAccord);
$you->travel(2000);
echo 'Distance traveled by you: ' . $you->getDistanceTraveled() . "\n";

$chevyRam = new ChevyRam('red');
$me = new Person($chevyRam);
$me->travel(5000);
echo 'Distance traveled by me: ' . $me->getDistanceTraveled() . "\n";

?>

Following is the output when executing Person.php file:

$ php Person.php
Distance traveled by you: 2000
Distance travaled by me: 5000

What we did above is that we initialized the Vehicle object outside the Person class and passed the Vehicle object to the Person class when initializing a person. Earlier since Vehicle object was initialized within the Person class, Person class had a hard dependency on the Vehicle object. Now that we are passing an initialized Vehicle object to the Person class, the dependency has been decoupled to an extent. We can initialize any type of Vehicle and pass it to the Person being initialized. The Person class doesn't really care what type of Vehicle object is being passed as long as it implements drive() and getMilesDriven() methods. This is dependency injection. Earlier Person class was dependent on the Vehicle class but now we are initializing the Vehicle object elsewhere and injecting it into the Person object. If you understood what we did here, you understand what dependency injection is. Now let's understand the benefits of dependency injection.

Benefits

Decoupled code, which leads to more flexible architecture

The reason we used dependency injection in the above example is to increase the flexibility. Before using dependency injection, every person was initialized to own a red Honda Accord. After using dependency injection, every person will get initialized to own any vehicle that you initialize, and not necessary a red Honda Accord. In the example above, $me was initialized with a red Chevy Ram and $you were initialized with a white Honda Accord. Now let's take it one step further and instead of defining the argument in the constructor to be an object of the type Vehicle, define it to be an object that implements VehicleInterface. Since a person is using only two methods, drive() and getMilesDriven(), of the Vehicle object, we will define these methods to be in the interface and let the person be initialized with any object that implements this interface. An example of such an object could be a bullock cart. It has drive() and getMilesDriven() methods but doesn't have any other method, such as getWarrantyLeft(). Here's how VehicleInterface.php, BullockCart.php and Person.php will look in such a case:

<?php

/**
 * VehicleInterface interface.
 */
interface VehicleInterface {

  /**
   * Drive the vehicle.
   *
   * @param int $miles
   *   Miles driven.
   */
  public function drive($miles);

  /**
   * Returns the total number of miles driven.
   *
   * @return int
   *   Total miles driven.
   */
  public function getMilesDriven();
}

?>
<?php

require_once 'VehicleInterface.php';

/**
 * BullockCart class.
 */
class BullockCart implements VehicleInterface {

  // Miles driven.
  private $miles;

  /**
   * Default constructor.
   */
  function __construct() {
    $this->miles = 0;
  }

  /**
   * Drive the bullock cart.
   *
   * @param int $miles
   *   Miles driven.
   */
  public function drive($miles) {
    $this->miles += $miles;
  }

  /**
   * Returns the total miles driven.
   *
   * @return int
   *   Total miles driven.
   */
  public function getMilesDriven() {
    return $this->miles;
  }
}

?>

<?php

require_once 'Vehicle.php';
require_once 'BullockCart.php';

/**
 * Person class.
 */
class Person {

  // Vehicle
  public $vehicle;

  /**
   * Default constructor.
   *
   * @param Vehicle
   *   Vehciel object.
   */
  function __construct(Vehicle $vehicle) {
    $this->vehicle = $vehicle;
  }

  /**
   * Let the person travel in his vehicle.
   *
   * param int $miles
   *   Number of miles that the person travels.
   */
  public function travel($miles) {
    $this->vehicle->drive($miles);
  }

  /**
   * Returns the number of miles that the person has traveled.
   *
   * @return int
   *   Number of miles that the person has traveled.
   */
  public function getDistanceTraveled() {
    return $this->vehicle->getMilesDriven();
  }
}

$hondaAccord = new HondaAccord('white');
$you = new Person($hondaAccord);
$you->travel(2000);
echo 'Distance traveled by you: ' . $you->getDistanceTraveled() . "\n";

$bullockCart = new BullockCart();
$me = new Person($bullockCart);
$me->travel(5000);
echo 'Distance traveled by me in a bullock cart: ' . $me->getDistanceTraveled() . "\n";

?>

As seen in the code above, Person object is no longer dependent on the Vehicle object. In fact, we can even initialize it using the BullockCart object, which is not related to the Vehicle object in any way, as long as BullockCart object implements VehicleInterface, which in turn requires only two methods: drive() and getMilesDriven(). We have truly made Person and Vehicle classes decoupled and increased the flexibility of the code.

Easier Unit Testing

The second advantage of dependency injection is the ability to unit test the classes Vehicle and Person independent of each other. Consider the initial code when Person was initializing the Vehicle object in its constructor. This is how a PHPUnit test for Person will look:

<?php

/**
 * PersonTest class.
 */
class PersonTest extends \PHPUnit_Framework_TestCase {

  /**
   * Make sure that distance traveled is correct.
   */
  public function testDistanceTraveled() {
    $person = new Person();
    $person->travel(1000);
    $this->assertEquals(1000, $person->getDistanceTraveled(), 'Distance traveled does not match.');
  }
}

?>

The above test will pass. Let's assume that in future, there is a mistake in the implementation of getMilesDriven() in the Vehicle class. Suppose getMilesDriven() function in Vehicle class starts returning 0 irrespective of the miles actually driven. Now the above test will fail since getDistanceTraveled() method, which in turn calls Vehicle's getMilesDriven() method, returns 0 and does not match 1000. This is undesirable. Why should a test testing Person class fail if there is a mistake in Vehicle class? Agreed that in the above code, it's very easy to debug what's going on but when the project grows, just figuring the root cause of a failing test can become time-consuming. What we want is that a unit test testing the Person class should fail if and only if there is a problem in the Person class and not anywhere else. This is where dependency injection is useful. Now that we are creating an object implementing VehicleInterface and passing it in the Person's constructor, we can use mocks in PHPUnit to isolate the tests for Person class from any other class. Here is how the PHPUnit test for Person class will look after implementing dependency injection using VehicleInterface:

<?php

/**
 * PersonTest class.
 */
class PersonTest extends \PHPUnit_Framework_TestCase {

  /**
   * Make sure that distance traveled is correct.
   */
  public function testDistanceTraveled() {
    // Create a stub for VehicleInterface.
    $stub = $this->getMockBuilder('VehicleInterface')->getMock();

    // Configure the stub to return 1000 whenever getMilesDriven() method is called.
    $stub->method('getMilesDriven')->willReturn(1000);

    $person = new Person($stub);
    $person->travel(1000);
    $this->assertEquals(1000, $this->getDistanceTraveled(), 'Distance traveled does not match.');
  }
}

?>

The test code above is slightly more complicated that the one earlier. First we are creating a mock for VehicleInterface and instructing the mock to return 1000 whenever its method getMilesDriven() is called. Next we pass this mock to the Person object during initialization. As a result, In the assertEquals() statement, $this->getDistanceTraveled() will invoke getMilesDriven() method of the mock and will return 1000 as programmed. You will notice that even in the unit test, we have eliminated the dependency on any external class. Even if the implementation of getMilesDriven() method in the Vehicle or BullockCart class has bugs, the above test will pass since we are using a mock that gets passed to the Person object. So in future, if the above test fails, then we know for sure that there is a problem in the Person class and nowhere else. It becomes much easier to debug.

In this post, you learned about dependency injection and its benefits. In the next post, you'll learn about dependency injection container. In the meantime, please comment below if you can think of any other advantages of using dependency injection. If you found some part of this post difficult to understand, please let me know in a comment below so that I can make it easier to understand.

Sep 01 2015
Sep 01

In a large website with many nodes, stop using the node_load_multiple function. It potentially limits the site growing.

According to the document: "This function should be used whenever you need to load more than one node from the database." But, I want to say that we should avoid using this function as this open the door to system crash in the future.

I had written a blog before Design a Drupal website with a million nodes in mind. I had used this function as an example. It is true that node_load_multiple function enhance the performance. But, it comes with a price. When we load thousands of node into the memory, it exhausts the web server memory instantly. Then we get this infamous message: "Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to allocate XYZ bytes) in ...".

This issue brought me to an attention when I am reading the code done by one of the well-known Drupal shops. In one of the recently launched high-profile project, the function is used to load all the show nodes in the system. It sounds to be troublesome to me at the beginning. We can not load all nodes if we are not sure how many it will be? Where there are a small amount of node in the system, that is fine. But if it is for a system there are over hundred thousand nodes, that is a big problem. As time goes by, we add more shows into the system; The utility function needs more memory to handle it. The physical memory limits the ability to add infinity show nodes into the system.

What is the best way to handle this situation? Avoid using the node_load_multiple function. If we have to use the node_load_multiple, limit the number of the node for node_load_multiple to load.

Sep 01 2015
Sep 01

Discover the post on social shopping projects in Drupal with some of the best secrets
of ecommerce website development for you ;)

The World Wide Web has given people 2 unquestionable pleasures. The first one is the convenience of viewing and buying products online, sitting in a comfortable chair with a cup of your favourite coffee. The other (since we are all social creatures!) is the joy of chatting to your friends on social media every minute you want. For example, to discuss the new awesome parcel from an online shop that has just been delivered to you doors.

A perfect combination of social media and ecommerce

Indeed, social media and ecommerce are great powers that rule the Internet. What do we get if we combine them? We get a super power! ;) It has a name — it’s called social shopping. This is one of the newest but already very popular ecommerce website development phenomena.

Social shopping is like taking your Facebook friends to a store with you. Just about the same fun, discussions, comments on the products you choose. Need your friends’ opinions about a product? Here you go! Want to boast your new purchase? :) Feel free! Social shopping includes these and many more options, while the comfort of your room is always with you.

Social shopping: much more than just social buttons

A few years ago, having social media buttons on your website was a sign of your up-to-dateness and respectability. Today, it’s no longer enough. Social shopping involves much deeper users’ interaction with your website. They should be guided through the whole shopping process on its every step.

Drupal’s the perfect companion to go social shopping with

Thinking to build your social shopping project, which platform to choose? It should:

  • be flexible enough to meet all your needs and implement all your ideas;
  • be powerful enough to handle lots of products and users quickly and without delay;
  • allow effective payment system integration.

Here, Drupal is a perfect fit just like a suit tailored specially for you. Obvious choice — let’s see in more detail why.

A “chic” example of a Drupal social shopping project

The best proof is a closer examination of an amazing social shopping website built with Drupal. You will see something that is really “chic” — and it’s not only about the design, but also about the functionality. Welcome to chiq.com, the “incarnation of chic” in Drupal ecommerce development! ;) This is our social shopping project that was build with Drupal to enjoy all its benefits. Today, the website is not using Drupal anymore, but this link will lead you exactly to the version we developed so that you can see how it was built. It’s a powerful aggregator of stylish and fashionable clothes. Our virtual journey to it will be both visually pleasing, useful and interesting, we promise. Let’s go!

As close to Facebook as possible: real integration

We’ll begin with the most important feature of a social shopping project, i.e. social media integration. We developed Drupal custom modules and algorithms to provide full Integration with Facebook. Users see items on their dashboard according to their Facebook likes, create FB photo albums and more. The position of each item depends on its likes calculated in real-time mode. People come to the website from the Facebook page and are redirected to vendors’ websites to actually make purchases.

Quick and “chic”! Really high website performance

When a website has over 1 million items, lots of Facebook fans, high traffic and a big amount of published content, it should be powerful enough to handle it proudly :) We made this social shopping Drupal site work really quickly, with an average page generation speed of less than 60 msec. Sometimes we got about 50.000 unique visitors in a few minutes after a new post on the Facebook page.

Just some Drupal secrets of how we made it. We didn’t use “heavy” Drupal modules like Views, Panels, CTools on dashboards. We used only one dedicated server with our custom configuration for all of this stuff. Of course, we achieved such results with no Drupal core hacks, just using a standard database, session and cache layers for Drupal. A custom caching algorithm was implemented for the website. CDN was used to store content. Some pages used only partial DRUPAL_BOOTSTRAP capability.

Integration with http://www.authorize.net payment system

When it’s convenient, easy and safe to pay, people are willing to make purchases on a website. Drupal allows effective payment system integration. So the integration with http://www.authorize.net payment system enabled easy payment process on chiq.com, right on the purchase page.

Store feed: an automatic item aggregator

It really made the life of content managers easier. They used to pick and add items from various sites before, but our aggregator enabled the display of all items in a convenient way and made it easy to add them with just a few clicks. This information is stored in a separate database table created specially for temporary storage. Only after a content manager clicks the “Add item” button, a separate node for the specific product is created on the site. The store feed is updated once a day.

Let’s sort out the necessary things: specific item sorting algorithms

How to show the items that deserve it most? We use logarithmic sorting and custom algorithm (depending on how popular the item is and how recently it’s been uploaded). The combination of these two factors is the best way to sort items. Those algorithms provide showing most popular and most recent items on top of the feed.

Rewards for active users: a flexible system of badges

Active users’ actions on social shopping websites should be encouraged, if you want them to show even more activity. Chiq.com users received special badges like:

  • Newbie: Welcome to the CHIQ Community;
  • Blue Ribbons are awarded to users with 5 Chiq points;
  • Fashion Leader: Where fashion followers become fashion leaders.

Chiq is always with you: special browser apps & bookmarks

No matter where users go, chiq.com is always with them. We developed special chiq button for Chrome and Firefox browser so everyone is welcome to “chiq” everything they like on any site to add it to chiq.com.

Briefly about other features

We have listed just a few important Drupal features, but there are more of them. For example, a flexible automatic discount system depending on the product’s votes, subscription to the product’s price change, a gift system, an advertising system, a “page refreshing to help circulate items” function and many more.

We hope you have enjoyed this virtual Drupal journey to chiq.com. Choose what suits you best and make people enjoy staying on your social shopping website!

Pages