Apr 18 2016
Apr 18

In our last post we talked about how the Drupal Community is supporting Drupal 6 after its end-of-life and what that means for your Drupal 6 site.  In this post we’ll get a bit more technical and talk about what exactly you need to do to keep your website up to date.

Step #1: Getting an accurate report of your site’s modules and themes

Ever since the Drupal 6 sunset date, your website’s report of Available Updates at /admin/reports/updates has been telling you that everything is unsupported and should be uninstalled.  That’s not very helpful :-)

Drupal 6 Update module report

So the first step is to get the myDropWizard module.  This is provided free (libre) to the Drupal Community by one of the Drupal LTS vendors. The main purpose of this module is to show whether a module is supported by the Drupal 6 Long-Term Support (LTS) vendors, so you’ll know if it’ll be getting security updates going forward.

Drupal 6 MyDropWizard report

Ahhh, that’s better.

Now you can continue to manage security updates for modules and themes just like you always have.  But there are some significant gotchas.

How problems are found and fixed

When vulnerabilities are found they will be posted as issues in the Drupal 6 LTS project.  Once the issue is  fixed, and if the module maintainer is still maintaining the D6 version, then the maintainer will simply release a new version, just like normal.  But if the maintainer is no longer maintaining it, then new releases are made on Github.  Drupal Core is no longer receiving any new commits on the 6.x branch,  so new releases will be made to the Pressflow project, also on Github.

How to obtain new versions

If new releases are scattered across Drupal.org and Github, the question becomes: How do we easily obtain new versions?  Assuming that you run security updates with Drush, then you can use the --update-backend=mydropwizard flag when calling any of Drush’s Project Management commands (pm-download, pm-refresh, pm-updatedstatus).  The MyDropWizard backend will automatically obtain the project from Github or Drupal.org.

New Drush

But this brings a new problem: The --update-backend flag only works with Drush 7 or later.  On a server that’s running Drupal 6, chances are high that it’s using Drush 6, and chances are also high that it’s using an old version of PHP (like 5.3.3 that is bundled with Debian/Ubuntu).  The old version of PHP means that you can’t upgrade to the latest Drush 7 (7.2.0).  But there’s a fix on the way for that.

Switching to Pressflow?

Since new releases are no longer made to Drupal Core, and only to Pressflow, this creates a bit of a dilemma for sites that are not running Pressflow.  In those cases it’s probably more cost effective to manually apply patches rather than move to Pressflow.  There’s a couple ways to be notified of these commits:

Add-on modules

The final tricky area that we’ve found is with modules that extend Update Status module. There’s two in particular that we use often: Update Exclude Unsupported, and Update Status Advanced Settings — neither of these will work anymore.  Instead you’ll need to implement hook_mydropwizard_status_alter().

/**
 * Implements hook_mydropwizard_status_alter().
 */
function mymodule_security_mydropwizard_status_alter($projects) {

  // Projects determined to be okay for this particular site.
  $projects_deemed_okay = array(
    // This is okay because of the finglewabble.
    'foo', 
    // This is okay because of hard-coded site configuration. 
    'bar',
  );
  foreach ($projects_deemed_okay as $module) {
    if (isset($projects[$module])) {
      $projects[$module]['status'] = 'deemed-okay';
      $projects[$module]['extra'][] = array(
        'class' => 'deemed-okay',
        'label' => t('Deemed okay'),
        'data' => t('This project was analyzed and determined to be acceptable to run on your site.'
      );
    }
  }
}

Conclusion

I’m sure there will be a few more hiccups along the way, but this should get you started.

Image by: Henri Bergius

Apr 08 2016
Apr 08

Those of you who still have a Drupal 6 site are by now aware that you need to do something with it since this version is no longer supported.  Your options in short are:

  • Upgrade to Drupal 7
  • Upgrade to Drupal 8
  • Choose one of several options to limit your vulnerability (e.g. convert the site into a static HTML website, or close logins to all but a handful of trusted people and harden the security of the login form)

But that’s a big decision.  What do you do until you’ve decided which path to choose?  Now that Drupal 6 is past its sunset date, is your site suddenly vulnerable to having its data stolen and being turned into a spam factory?

The short answer

As long as you have someone keeping an eye on the security of your site, you’re just fine.  Take some time to make your decision — just don’t wait too long.

Interested in our Drupal security services?  Contact us to find out more.

The long answer

The long answer is a bit more nuanced.  When the Drupal 6 end-of-life was approaching, the Drupal Security Team asked for vendors to apply to become recognized as official Drupal 6 Long Term Service Vendors.  These LTS vendors have clients running Drupal 6 websites.  As security vulnerabilities are found and fixed in Drupal 7 (and Drupal 7 modules) the vendors are committing to make those same fixes to the Drupal 6 versions, but only for the modules that their clients are using.  

That exception has significance for other Drupal 6 sites and it all boils down to the question of:

How much security is enough?  

Low risk websites

Many (most?) websites only need to be worried about automated security attacks: Villains and mischief makers will try to attack every website on the Internet using every known vulnerability.  A tiny fraction  of the time they’ll be successful and turn a website into a spam factory, or virus spreader.  If they do their work well the site owner won’t even notice.  There’s a very low success rate, but there’s a billion websites out there.  You do the math.

High risk websites

Other websites have to worry about someone trying to actively hack their website.  There’s usually three possible reasons for this:

  • Your website has information worth stealing — Maybe your site has an e-commerce component, or a database of hundreds of thousands of membership records (with full names and e-mail addresses).
  • Your website has a lot of visitors — This is really just a subset of the first point.  If someone could infect all those visitors with a virus they could make a lot of money.
  • Someone wants to shut your website down — Maybe your organization has a political bent that some people strongly disagree with.

So what does this mean for my Drupal 6 site?

If your site is in the low risk category, then nefarious individuals will be using the vulnerabilities fixed by the LTS vendors in their automated attacks.  As long as your site continues to be updated with these fixes you are probably fine.  

There is still some risk if:

  • your site runs a module that the LTS vendors do not support,
  • and a vulnerability is found in the Drupal 7 version of that module,
  • and that vulnerability exists identically on the Drupal 6 version.

That’s possibly enough “ifs” to keep the risk at an acceptable level.

Also be aware that this support won’t last forever.  As more sites get off of Drupal 6, the LTS Vendors will have fewer clients paying for those services, and the number of supported modules will diminish.  Eventually your Drupal 6 site could be the last one standing with no one looking out for it.  How long this support is “good enough” is impossible to say.

If your site is in the high risk category, then you need to take a more active role in preventing successful attacks.  You could:

  • Move the information worth stealing somewhere else.
  • Move your site off of Drupal 6 faster.
  • Become a client of a Drupal 6 LTS Vendor to ensure that all of your modules are supported (not just the ones that other LTS Vendor clients happen to be using).

If you need help figuring out what you need, just contact us.

Photo by Billie Grace Ward

Jan 05 2016
Jan 05

We’ve been thinking about code reviews lately here at Advomatic.  Fellow Advo-teammate Oliver’s previous post covered the whys of our code review process, and Sarah covered the hows when she did a overview of some tools we use regularly.  This post focuses on the front-end side, and deals more with the whats of front-end code review… as in:

  • what are our main overall goals of the code we write?
  • what are the common standards we follow?
  • and what quick-and-easy changes can we make to improve our front-end code?

Guiding Front-end Coding Principles

In the world of front-end development, it seems like there is an intimidating, constantly expanding/changing set of tools and techniques to consider.  The good news is that there is a pretty dependable set of widely accepted working guidelines that aren’t tool-specific.  We really try to consider those guidelines first when we are reviewing a peer’s code (and the technical approach they have taken):

  • Write valid, semantic HTML5 markup – and as little markup as needed
  • Enforce separation of content, functionality/behavior, and presentation
  • The site should function without the use of JavaScript, which when added, is only used to progressively enhance the site. Visitors without JavaScript should not be crippled from using the site.

Best Practices

Sometimes there are a million ways to solve a single problem, but I think we do a good job of not pushing a particular tool or way of dealing any of those problems.  Instead, we’ll see if the code is efficient and if it can stand up to questions about its implementation, as far as best practices go.  For example:

  • Is there logic-related PHP in templates that should be moved to template.php?
  • Can JS be loaded conditionally from a custom module or the theme’s template.php via
    $render['#attached']['js']
    

    so it doesn’t load on pages that don’t need it?

  • Is the project already using a DRY CSS methodology elsewhere?  BEM or SMACSS maybe?  Should it be used here?
  • Are we generally following coding standards?
  • Are we coding with web accessibility guidelines in mind?

Minimal Effort Refactoring or “Grabbing the Low Hanging Fruit”

Refactoring code as an afterthought (or as a reaction to some problem down the road), is never fun – it pays to be proactive.  Ideally, we should always be retooling and improving our code as we go along as we get more information about the scope of a project and if the project budget and/or timeline allows for it.  When we look at a peer’s code changes, what kinds of things can we suggest as a quick and easy “upgrade” to their code?

  • Markup:
    • Instead of that ugly Drupal-default markup we’re working with, can it be swapped out with an appropriate HTML5 replacement element?
    • Is that inline JS or CSS I see in the markup?  Crikey, what’s that doing here?!?
    • Do we really need all these wrapper divs?
    • Is this the bare minimum markup we need?
  • CSS/Sass:
    • Can we use an already-established Sass mixin or extend instead of duplicating styles?
    • Is this element styling worthy of a new mixin or extend that can be reused on other elements, either now or in the future?
    • Should this mixin actually be an extend (or vice versa)?
    • If the code is deeply nested, can we utilize our CSS methodology to make the selector shorter, more general, or more concise?
    • Is this selector too unique and specific?  Can it be generalized?
  • JS:
    • Does this work without JS?
    • Is there a chance this could adversely affect something unrelated?
    • Does it need to be more specific, or be within a Drupal behavior?
    • In Drupal behaviors, do selected portions of the DOM use the “context” variable when they should? For example:
      $('#menu', context)
      
    • Is jQuery Once being used to make sure that code is only run once?
    • Should this code only run when we are within a certain viewport size range (a breakpoint)?
    • Does it need to be killed/destroyed when the breakpoint changes?
    • Would this functionality benefit from being fired via feature detection, especially if our target browsers are old-ish?

Quick Browser QA

I know, I know.  Browser QA is not really “code review”.  However, it does go hand in hand, and makes sense to deal with when you’re reviewing someone’s code.  It is at that point that you, the code reviewer, are most familiar with your peer’s work and specific goals.

While we do a more thorough and complete test and review of work in target browsers and devices at the end of an iteration (generally every two weeks), we also do a shorter burst of quick QA during an individual ticket’s code review.  We’ll quickly check it in the latest version of major target browsers/devices – this helps us find bugs and issues that are big, visible and easy to fix.  It also ensures that they don’t pile up on us to deal with during our final iteration… which can be really demoralizing.

Back to Basics

Code reviews are great for brushing up on the basics when other parts of your work can seem very complicated.  None of this is particularly revolutionary – it helps to revisit the basics of why you do what you do from time to time. Aside from reviewing the technical aspect of the work, you can act as an outsider that can see the big picture of how this work affects the user experience… easier than someone in the trenches.  This is an important and valuable role to play as things come together on the front-end of your project.

Dec 18 2015
Dec 18

Code reviews are a regular part of our project process and give us the opportunity to catch bugs and standardize code before work is tested by our project leads or clients. You can read more about our code review philosophy in our last post.

This post aims to give an overview of some of the code review tools we use for PHP code reviews.

Tool Time

Git history

For smaller reviews, using Git history to look at a code change is all you need. We use a post-commit Git hook that posts commit hashes to their related tickets in our project management software, so when you’re assigned a ticket to review, you can easily see the commit IDs and run “git show [the hash]” to see the change. With some other ticket management tools you may even be able to see the code changes right along with the ticket comments.

Git diff showing a code change.

Looks good, Oliver! ????


CodeSniffer

The PHP CodeSniffer (PHPCS) utility reviews PHP code for adherence to a given code standard. For Drupal projects, we can check code against Drupal’s standards. There are a few ways to run this, but first, you’ll need to install a few things.

How to install PHP CodeSniffer

  1. Download the PHPCS package using Composer.
    • For Drupal 7 projects:
      composer global require squizlabs/PHP_CodeSniffer:\<2
    • For Drupal 8 projects:
      composer global require squizlabs/PHP_CodeSniffer:\>=2
    • Or, you can install PHPCS with Drush.
  2. Download the Drupal Coder module (7.x-2.x branch – this part is important, don’t choose the 1.x branch). Move this to your central Drush directory ($HOME/.drush) – that allows it to be used on all your Drupal projects.
  3. Configure PHPCS to use Drupal standards:
    phpcs --config-set installed_paths $HOME/.drush/coder/coder_sniffer
    phpcs --config-set default_standard Drupal

Run PHP CodeSniffer in phpStorm IDE

If you use an IDE, there’s probably a plugin for running PHPCS. I set it up in phpStorm like this:

  1. Follow the directions above to install CodeSniffer with the Drupal standards.
  2. Set the path to your CodeSniffer installation in phpStorm (Preferences > Languages & Frameworks > PHP > CodeSniffer). Click the Validate button there to make sure it works.
  3. Enable CodeSniffer (Preferences > Editor > Inspections): Select “PHP CodeSniffer validation”, then select Drupal as the standard to use.
PHPCS settings in phpStorm

PHPCS settings in phpStorm.

Once that’s hooked up, you’ll start to see inline alerts of your rule breaking. You can also run PHPCS against a whole file, directory or project (Code > Run inspection by name > PHPCS). This will give you a list of all the issues PHPCS finds, with a synopsis of the problem and how to fix it.

PHPCS error in phpStorm.

Oooh, busted! ????

There are a lot more Drupal-specific features in phpStorm that are worth trying out, especially in Drupal 8 – check out the JetBrains site for more information.

Run CodeSniffer on the command line

If you don’t use an IDE or just prefer a CLI, you can run PHPCS with terminal commands. You can do this with Drush, like this: drush drupalcs path/to/your/file

Or, without Drush, like this: phpcs --standard=Drupal path/to/your/file

PHPCS command line output.

PHPCS command line output.

The command will return a list of errors and the line numbers where they occur.

Drupal Coder Review module

If you prefer a UI, you can still make use of the Coder module by way of the accompanying Coder Review module.

Coder Review module UI.

Coder Review module provides user interface.

  1. Download the Coder module to your site’s module directory and enable coder and coder_review.
  2. Browse to admin/config/development/coder/settings.
  3. Choose which modules or themes to review.
  4. Review your results, and if needed, make the suggested changes to your code.

Further Reading

Best practices for Drupal code are well-documented on Drupal.org:

These are some other blog posts on the topic:

Do you use any other code review tools?
How do you use code review tools in your project process?

Dec 15 2015
Dec 15

Code reviews, or the practice of going over another’s code, have become an integral part of our team’s development workflow. There are several types of code reviews, but this article will focus on a few key scenarios where code reviews have served to significantly enhance our process and the quality of our work.

At Advomatic, we’ve been using code reviews for several years, but we’re always looking to change things up, try out new ideas, and learn from our strategic experimentation. Over the past year, we’ve been thinking hard about the purpose and value of code reviews, and how we can improve our process.  This is what we’ve come up with.

Quality Control

Quality control is the most common way we use code reviews. Every ticket that involves substantial* commits is code reviewed by a different developer on the team. Usually, we divide the reviews between the front-end and back-end teams, so developers are only responsible for their area of expertise. Sometimes, on small teams, we bring in developers from another team, just to provide reviews. These reviews regularly focus on a set of common standards, including:

  • Is this the right approach for the problem?  Maybe you know some trick that the author doesn’t.
  • Coding conventions/standards: Honestly, we don’t put too much weight on this.  Yes, we adopt Drupal coding conventions, but there’s no value to our clients in spending the time to add a missing space in if( or fix a comment line that went longer than 80 characters.
  • Proper documentation: are functions well commented? Is the purpose of the code explained or easily understandable, particularly for complex solutions or unique requirements? Can we understand why a bit of unusual code is doing what it’s doing?
  • Efficiency: is the code as concise as it can be? Is there any unnecessary duplication? Is it sufficiently modular?
  • Clean-up: has all experimental and debug code been removed?
  • Security: Is all output of user-generated-content properly checked/escaped? Are all potential breakage points properly handled?
  • Organization: is the code located in the proper module or directory? Does it leverage existing functionality?
  • Bugs: Are there edge-case bugs that you can see aren’t handled by the code?

Knowledge Sharing

One of the challenges of organizing a team is that our work can become siloed. If each person is working on a separate feature, they alone are familiar with the specifics when it comes time to make a change. By having team members review one another’s code before delivering it to the client, we help ensure that critical details are passed around to everyone.

Often, there is a team member with a particular skill or expertise and it makes sense to have them take on tasks in that area. With code reviews, junior developers can learn from their more experienced teammates and be ready to tackle a particular challenge on a future project.

The Hiring Process

We’ve recently incorporated code reviews into the interview process. We’ve long required that candidates give us a sample of their work and then perform internal reviews to evaluate their potential strengths and weaknesses. However, after flipping that process on its head, we’ve found we learn even more by having the job seeker review a flawed (usually in multiple ways) code sample. Not only does this help to reveal what the candidate knows, but it also illuminates how they communicate and what they might be like as a team member.

Best Practices

As you can imagine, who does the review and how they do it are essential ingredients for a successful outcome. It is crucial that everyone comes into the process with the proper attitude and communicates using an effective tone. For a senior team member, there’s a difficult balance between providing enough information to home in on a problem, while at the same time encouraging self-sufficient problem solving. In these cases, it helps to frame suggestions in terms of the desired outcome, rather than describing a specific solution. For example, instead of saying, “Make the database call happen outside of the foreach loop,” the reviewer might propose, “Could we improve performance by altering where the database call happens?”

On the topic of tone, it’s best to keep things friendly, provide lots of encouragement around the criticism, and focus on critiquing the code – not the coder. It is also important to consider how much to say and when to say it. If a junior developer is struggling with a solution, it can be discouraging to hear multiple comments about where the comment lines are wrapping and missing punctuation (not that those comments don’t sometimes have their place).

When the process is handled with careful intent, the code review process can be an effective tool for team building and knowledge sharing. Our tickets are regularly filled with responses like, “Great catch! I can’t believe I missed that,” and “Good suggestion, I’m on it!”

One thing to remember is that while this arrangement is working well for us, your team might need something different.  A two-person team building a website for a small non-profit has different needs from an 80-person team working on an online banking website. Find the balance that works for you.

What are the key ways you use code reviews in your process? Are there any important principles or best practices you’d add to the ones listed here?

Thanks to Dave Hansen-Lange for reviewing (and improving) this post.

* That’s right, we don’t code review everything. If there’s no value (particularly to the client) in having someone review the code (maybe only a few lines were changed, maybe the new code is self-evident), then we skip it.

Nov 17 2015
Nov 17

We just launched our first Drupal 8 website for the Northwest Atlantic Marine Alliance (NAMA). During our project retrospective, a few of us brought up how nice it was that so many contrib modules that were part of the D6 site weren’t necessary in Drupal 8 – this was a major factor in making it possible to launch this project before the actual D8 release.

The graphic below compares contrib modules that were running on NAMA’s Drupal 6 site compared to the modules needed to achieve the same functionality in Drupal 8.

Having so many of the modules that we always install built into core gave us more time to focus on ways to optimize the site for NAMA’s specific needs, and it should also save us time down the road when it’s time to handle maintenance tasks (like security updates) or add on new features.

What are you most excited about having in core?

Which modules are you waiting to see in D8 before upgrading?

Nov 06 2015
Nov 06

The Northwest Atlantic Marine Alliance (NAMA) advocates for healthy marine ecosystems. Through their site, namanet.org, they organize and promote a movement toward a thriving ocean and a just seafood system.

Having helped create the original Drupal 6 site for NAMA in 2008, it’s been a rewarding experience re-architecting it in Drupal 8 (beta). The main purpose of the project, at least initially, was to help NAMA plan for how to deal with their soon-to-be-end-of-lifed D6 site by upgrading it to D7. As a fully matured platform, this upgrade (or migration) path has long been the recommended approach, even since talk of a release candidate began in the summer of ’15, when the number of critical issues neared zero.

Choosing an upgrade path – Drupal 7 vs Drupal 8

NAMA was the perfect client to test out a Drupal 8 upgrade. They were flexible about their design and functional requirements, and the original site was straightforward in its architecture. As the betas ticked up in number, it became feasible to consider skipping over D7 to go straight to D8 instead. Once the D6->D8 migration path appeared ready to use, we discussed the pros and cons with NAMA and, together, decided to go for it.

By structuring the project to partially include “internal” and “personal development” time, we were able to deliver the new site on a tight budget while allowing the entire team to gain crucial experience with the upcoming version of our CMS/framework of choice.

The Drupal 8 advantage

While NAMA will enjoy many secondary benefits to having a D8 site, like a responsive front-end and in-place WYSIWYG editing, the most meaningful advantage of NAMA skipping D7 for D8 is the significantly extended lifespan of their redeveloped site. For Advomatic, apart from getting to work with a shiny new Drupal toy, we’re now prepared to hit the ground running when the full release of D8 is ready, and to support the sea of Drupal 6 sites that will soon be in need of migration help.

NAMA's coordinating director, Niaz Dorry.

NAMA’s coordinating director, Niaz Dorry.

As we wrapped up our final tickets and NAMA began working with their new site, I asked Coordinating Director Niaz Dorry to chat with me about their experience with Drupal 8 so far.

When asked about her favorite features of the new site, Niaz noted that it was, “clean, open, uncluttered, more modern, and (so far) appears to be easier to edit.” She also detailed some of the new configurable components we added to the homepage, which leverage the fieldability of D8’s upgraded Block module.

Niaz added that the move to the new site has been fairly seamless from an administrator’s perspective. The ease of this process is largely due to content creation and usability improvements that have been incorporated into D8 core: 

“The transition seems smooth so far. Generally speaking, the two sites feel similar. What is different is not THAT different, and we seem to be learning it pretty quickly.”

And what about the tradeoffs of working with not-quite-ready software, when a robust ecosystem has been developing around its predecessor for years? At the outset of the project, we’d discussed – in theory – what sacrifices might need to be made. But in practice, what diminished functionality did they end up having to live with?

“Not much, really. Some of the things that are not ready yet – like a better date module – don’t appear to be showstoppers. We knew what we were going into, and that there would be some adjustments to things as Drupal 8 goes from Beta to fully operational. So nothing has been a surprise.”

Niaz eloquently summarizes how this project has been a big win for everyone involved:

“We’re glad to have had this opportunity to work with Advomatic. The results – an updated website for us, experience with Drupal 8 for Advomatic, and contributing to the broader cyber community as we learn – are truly a win-win-win, and that’s the kind of effort we like to engage with, whether it’s our program work, our policy work, the way we run our organization, and now even the way we build our website.”

Have you had a chance to work with a client on a D8 project yet? What do they think so far?

Oct 16 2015
Oct 16

We recently finished building our first Drupal 8 site for a client. So I wanted to ask our team, “What did you like about working in Drupal 8?” These were some of the topics they touched on.

Content editing

Amanda: The UI for editing content is very good, with contextual links much more useful and usable than they were in Drupal 7. Node edit pages are also improved—with a sidebar and collapsed options, making them easily accessible, and the options are neither in the way nor create really long edit pages. And the WYSIWYG is in there by default now, which is a bonus for site owners.

Dave: The newly streamlined content editing form is going to make the lives of content creators much easier. It’s amazing how little things like that can have a big impact. For those smaller organizations that are resource constrained, they don’t want to be spending their time doing menial tasks to manage their content, they need to spend their energies on what’s important—crafting content that engages their constituents. Drupal 8 will help them do that.

Responsive Design

Amanda: While there are many contrib modules that are not ready yet, I’ve been impressed by what is now included in core and considered necessary—like breakpoints and responsive images.

Sarah: Also HTML5 markup out-of-the-box makes for a better experience on mobile and easier responsive theming.

Jack: Having Responsive Images in core is a no-brainer; every serious project these days deals with that aspect of site building. In the past, it could get quite complicated mashing a few contrib & custom solutions together to handle dynamic image resizing and resolution. After giving things a spin in D8 and working out the kinks of our first approach, it feels very intuitive and less of an afterthought.

The Developer Experience

Sarah: A fun thing about using Drupal 8 has been having something new to learn. We’ve been working with Drupal 7 for about five years now, and it’s exciting to get a push towards getting up-to-speed with more modern PHP practices.

And long-term maintenance will be made easier by having fewer contributed modules. Having better translation capabilities in core should make it easier to add multilingual support to a site, and result in a better experience for translators.

Amanda: So far I like how core, custom themes and modules, etc, have been restructured; putting core in it’s own folder discourages hacking and having a developer’s custom files easier to access makes sense.

Jack: For clients who will be taking our work and building off of it internally post-launch, it will be easier to continue development using the clear implementation examples we’ve set up initially for them. Trying to dig around in the admin side of D7 to figure out where responsive images were handled was understandably frustrating (for devs and clients alike) and I think things seem much more clear now.

Everyone on the team enjoyed working in Drupal 8, and we are really looking forward to our next D8 build. Have you started working in Drupal 8? Let us know in the comments!

Oct 13 2015
Oct 13

Cowritten by Jack Haas and Amanda Luker

Celebrating the first release candidate for Drupal 8, the Advomatic team has been testing things out, diving into not-so-well documented (yet!) waters. Here’s a little tutorial for doing something that had us scratching our heads for a bit: adding responsive images in Drupal 8.

Here’s what you will need:

  • A Drupal 8 install (Breakpoint and Responsive Image modules are already in core)
  • Make sure Breakpoint module is enabled (already enabled by default in core)
  • Turn on the Responsive Image module

Setting up your breakpoints

Since Breakpoint module was added to D8 core, you can now define your theme’s breakpoints in code (and categorize them into breakpoint groups – for example, one group for image-sizing breakpoints and one for layout-related breakpoints). There is no UI for doing this, but Breakpoint module gives us an API that allows modules and themes to define breakpoints and breakpoint groups, as well as resolution modifiers that come in handy when targeting devices with HD/Retina displays.

To do this from your theme, simply create a yourthemename.breakpoints.yml file in the root of your theme directory. For the purposes of simplifying this tutorial, we will be creating two, simple, device-agnostic breakpoints: “small” and “large.” Under normal circumstances we would be using more.

yourthemename.small:
  label: small
  mediaQuery: '(min-width: 0px)'
  weight: 0
  multipliers:
    - 1x
    - 2x
yourthemename.large:
  label: large
  mediaQuery: 'all and (min-width: 960px)'
  weight: 1
  multipliers:
    - 1x
    - 2x

The weight of these is crucial so that the proper image styles get swapped in depending on viewport size and screen resolution. Here, a breakpoint’s weight should be listed from smallest min-width to largest min-width. Modules, however, can reverse that order if needed, as the Responsive Images module does.

Also, note the “multipliers” section. Breakpoint allows for different pixel density multipliers for displaying crisper images on HD/Retina displays: 1x, 1.5x and 2x. More on that below.

Determine what image styles you will be using for each breakpoint

Depending on how many breakpoints you have, you will need to plot out what your image sizes will be for each breakpoint range. In our case, we’ll do a simplified version with just two image styles, one for each of our breakpoints.

As an aside, here’s an interesting presentation on doing the math for your responsive images before you even get to Drupal. The presenter, Marc Drummond from Lullabot, uses a rule of 25% to choose his image styles. For a hero image, for example, he starts with 320px (generally, your starting maximum width). Then he picks his next breakpoint at 320 x 1.25 — 400px, then 400 x 1.25 — 500px … on up through 1600px (tidying up the numbers a bit to make more sense later).

Add your image styles at /admin/config/media/image-styles

Below is what I’ve chosen for my image styles, basing each on the largest width and height it will need to be before the next breakpoint snaps into place. I’m using a 16:9 aspect ratio across the board here to make crops, but yours may vary, based on the layout changes among breakpoints. These all use the “Scale and Crop” effect.

  • feature-small (0-959px): 738px x 415px
  • feature-large (960px & up): 938px x 528px
Screen Shot 2015-10-08 at 11.24.33 AM

 

HD (and Retina) screens

At this point, you should seriously consider making a twice-as-large version of images for your high definition display users. For this step, you’ll need to make sure you have your breakpoints set up to accept 2x options (via the “multipliers” you set up in yourthemename.breakpoints.yml), and then add doubled-up image styles:

  • feature-small-2x (0-959px): 1476px x 830px
  • feature-large-2x (960px & up): 1876px x 1056px
Screen Shot 2015-10-08 at 11.21.51 AM

Now I’ve got a slew of image styles all ready to go!

Screen Shot 2015-10-09 at 2.04.35 PM

Intro to the Picture HTML element

Drupal 8 makes the big leap and uses the HTML5’s Picture element to display all our different image styles and pick the right one. It’s essentially a container that allows for multiple sources for a single image tag. Let’s see how it works.

Here’s a basic example of the picture element markup:

<picture>
  <source
    media="(min-width: 960px)"
    srcset="images/kitten-big.png,
      images/[email protected] 2x">
  <source 
    media="(min-width: 768px)"
    srcset="images/kitten-med.png,
      images/[email protected] 2x">
  <img 
    src="https://www.advomatic.com/blog/adding-responsive-images-to-your-drupal-8-site/images/kitten-sm.png,
      images/[email protected] 2x">
      alt="a cute kitten">
</picture>

The source tag allows you to state your breakpoints and the image source to use in that case (with a regular and a 2x version). The img tag provides your fallback image — it will show when the others don’t apply. So the work we’ve done so far is basically providing all the parameters for the picture element that we’re building. Note that the source rules are listed from largest to smallest.

Next, create your responsive image style using those image styles at /admin/config/media/responsive-image-style

Now let’s put it all together in Drupal. Add a new responsive style, selecting the breakpoint group you are going to use here — in my case, I’m using my theme’s breakpoint group.

Screen Shot 2015-10-09 at 3.02.21 PM

For each breakpoint, I’m choosing a single image style — but you can also choose to ignore that breakpoint, or even load multiple images styles based on different size criteria you specify.

Apply your responsive image style

In my case, I added a field to the Basic Page content type for the Feature Image. Set the Format Settings to “Responsive image” and select your new Responsive image style.

Screen Shot 2015-10-08 at 1.50.07 PM

Now check your work. One thing that makes it a little more difficult is that the web inspector won’t tell you which version of the image is loading just by looking at the DOM; the picture element markup looks the same no matter what breakpoint you are in. Instead, you will need to peek at the browser’s web dev tools (such as the Network tab in Chrome) to see which version of the image has downloaded.

Here’s the wide version on a non-HD screen:

Test Responsive Image Styles | Drupal 8 Test-2

And a small version on a HD screen:

Test Responsive Image Styles | Drupal 8 Test-3

As you can see, this method can be as simple or complex as you need it to be. But I think Drupal 8’s new system allows for the flexibility for the range of devices and breakpoints we have now.

Oct 09 2015
Oct 09

When migrating a site from Drupal 6 to Drupal 8, we had to write some very basic Plugins. Since plugins and some of their related pieces are new to Drupal 8, here is a walk-through of how we put it together:

Use case

In Drupal 6, the contrib Date module provided a date field that had both a start and end date. So, the beginning of Crazy Dan’s Hot Air Balloon Weekend Extravaganza might be July 12, with an end date of July 14. However, the datetime module in Drupal 8 core does not allow for end dates. So, we had to use two distinct date fields on the new site: one for the start date, and one for the end date.

Fields in D6:
1.  field_date: has start and end date

Fields in D8:
1.  field_date_start: holds the start date
2.  field_date_end: holds the end date

Migration overview

A little background information before we move along: migrations use a series of sequential plugins to move your data: builder, source, process, and finally, destination.

Since we are moving data from one field into two, we had to write a custom migration process plugin. Process plugins are where you can manipulate the data that is being migrated.

Writing the process plugin (general structure)

The file system in Drupal 8 is organized very differently than in Drupal 7. Within your custom module, plugins will always go in [yourmoduledir]/src/Plugin. In this case, our migrate process plugin goes in [yourmodulename]/src/Plugin/migrate/process/CustomDate.php.

Here is the entire file, which we’ll break down below.

<?php
/**
 * @file
 * Contains \Drupal\custom_migrate\Plugin\migrate\process\CustomDate.
 */

Standard code comments.

namespace Drupal\custom_migrate\Plugin\migrate\process;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Row;

Instead of using functions like include(); or include_once(); to add various PHP files, now we “include” them by referencing their namespaces. Or rather Drupal knows which files to autoload based on the namespace.  This way, if a class is ever moved to a new directory, we won’t have to change code elsewhere, as long as the namespace stays the same. We will allow our code to be used the same way, by defining its namespace.

/**
* This plugin converts Drupal 6 Date fields to Drupal 8.
*
* @MigrateProcessPlugin(
*   id = "custom_date"
* )
*/

This class comment includes an annotation. When the Migrate module is looking for all available migration plugins, it scans the file system, looking for annotations like this. By including it, you let the migration module discover your migrate process plugin with the unique id ‘custom_date’.

Our new class will inherit from the ProcessPluginBase class, which is provided by the Migrate module in core. Let’s step back and look at that class. This is it’s definition:

abstract class ProcessPluginBase extends PluginBase implements MigrateProcessInterface { ... }

Since this is an abstract class, it can never be instantiated by itself. So, you never call new ProcessPluginBase(). Instead we create our own class that inherits it, by using the keyword extends:

class CustomDate extends ProcessPluginBase { ... }

The ProcessPluginBase class has two public methods, which will be available in child classes, unless the child class overrides the methods. In our case, we will override transform(), but leave multiple() alone, inheriting the default implementation of that one.

(A note about abstract classes: If there were any methods defined as abstract, our child class would be required to implement them. But we don’t have to worry about that in this case!) To override transform() and create our own logic, we just copy the method signature from the parent class:

public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property)

Writing the process plugin (our specific data manipulation)

In order to write custom code, let’s review our use case of dates again. Since this is our mapping:

OLD D6 field_date (from component) -> NEW D8 field_date_from
OLD D6 field_date (to component) -> NEW D8 field_date_to

We will migrate field_date twice per node. The first time, we will pull the from date. The second time, we will pull the to date. Since our process plugin needs to be aware of which piece we’re looking for in that particular run, we will allow the process plugin to have additional configuration. In our case, we will call this configuration date_part, which can be either from or to, and defaults to from:

$date_part = isset($this->configuration['date_part']) ? $this->configuration['date_part'] : 'from';

Depending on which date part we’re looking for, we’ll grab the appropriate date from the D6 source field, which is stored in the array $value.

$value = ($date_part == 'from') ? $value['value'] : $value['value2'];

And we’ll return the string, which will populate the new field:

return $value;

That’s it for writing our process plugin! Now we just have to use it.

Using the process plugin

In our migration definition, we need to call this plugin and feed it the correct information. So back in [yourmodulename]/config/install/migrate.migration.d6_node.yml, we map the new and old fields:

field_date_start:
  plugin: custom_date
  source: field_date
  date_part: from
field_date_end:
  plugin: custom_date
  source: field_date
  date_part: to

Which reads like this: For field_date_start on the new site, pass the old field_date to the custom_date process plugin, with the configuration date_part = ‘from’. Do this all again for field_date_end, but with the configuration date_part = ‘to’. Both of our D8 fields get filled out, each getting its data from a single field on the old D6 site.

migration

Time to fly! (Image courtesy of Wikimedia)


Feedback

Hopefully this helps. If you have any corrections, improvements, questions, or links to how you use plugins, leave them in the comments!

Aug 26 2015
Aug 26

We’re working on our first Drupal 8 project here at Advomatic, and Jim and I have been tasked with implementing a content migration from the client’s existing Drupal 6 site.

My first assignment was to write a plugin which rewrites image assist tags in node body fields as regular HTML image tags. Fortunately, lots of smart people had already solved this problem for Drupal 6 to Drupal 7 migrations (I adapted my plugin from Olle Jonsson’s script on Github), so the biggest hurdle was learning how to implement this thing in Drupal 8.

This is the true story of how we made it work.

Note: You’ll need to use Drush 8 for working with Drupal 8. I’d recommend following Karen Stevenson’s great tutorial from the Lullabot blog to help set up multiple versions of Drush on your system.

Initial setup

As of this writing, you’ll need some very specific Git checkouts of Drupal core and the migration helper modules, or you’re going to immediately encounter a pile of fatal errors. These are working for us:

Enable those modules and their dependencies, then set up your own custom module for your plugin code. The very cool Drupal Console module is a quick way to generate the boilerplate files you’ll need.

Write some code

Migration template

Your migration is likely going to need to provide migration templates for various node types, as well as one that handles all nodes. This plugin for handling image assist tags needs to run on all imported nodes, so we start by copying /core/modules/node/migration_templates/d6_node.yml over to our module and adjusting it a little to instruct it to run the ImgAssist plugin (see line 36 here).

Migrate plugin

There are example process plugins in “process” folders around the installation, and looking at those was a great way to figure out how to write ours. Jim made note of these commands to use for finding example code:

find ./ -type d -name 'migration_templates'
find ./ -type d -name 'process'

Our ImgAssist migrate process plugin starts with the Drupal 6 node body and teaser values, and then it runs through a few steps to create their Drupal 8 counterparts:

Running a node migration, step-by-step

  • 1. Get the D6 site running locally.
  • 2. Install Drupal 8 dev at the commit noted above.
  • 3. Install migrate_plus and migrate_upgrade at the commits noted above, and enable your custom module.
  • 4. Add your D6 database connection information to settings.php (you can follow the Drupal 7 directions here).
  • 5. Run these Drush commands:
    • drush8 migrate-upgrade --legacy-db-url=mysql://dbusername:[email protected]/D6databasename --legacy-root=http://d6site.local --configure-only
    • drush8 migrate-status (just to make sure your custom migration template is registering)
    • drush8 migrate-import yourmodule_d6_node

You’ll probably get an error the first time running migrate-import since the node migration depends on a few others to run first, such as d6_user. Run the dependency migrations as needed, then try the custom node import again.

If you have a lot of nodes, the import process will take a few minutes. I actually wrote this entire blog post while waiting for imports to run. Go do something fun for a minute, you’ve earned it.

Eventually, migrate-import will finish running, and you’ll be all set! You can compare the node on your D8 site against the node on the D6 site and see that the tag has been replaced. Hooray!

If it didn’t work: read on. It’s totally fine, you’ve got this.

So what if you have to roll it back?

drush migrate-rollback hasn’t been implemented in D8 just yet (but it is getting close). A workaround is to use drush scr to run a script which deletes your newly-imported nodes. We’ve been using this: https://gist.github.com/sarahg/993b97d6733003814fda

Then, you’ll need to uninstall your custom module, remove all of its config entities from the database, and drop its database tables. You can do that with queries like these:

DELETE from config where name=“migrate.migration.yourmodule_d6_node”;
DROP table migrate_map_yourmodule_d6_node;
DROP table migrate_message_yourmodule_d6_node;

To make this a little easier, you could add these queries to a hook_uninstall function in your module. I’m not one for making things easy (I’m working on this migration before there’s even a Drupal 8 release candidate, after all), so I’ve just been using drush sql-cli.

Now you can adjust your code as needed, re-enable your module and give it another shot (you can just skip ahead to the “drush8 migrate-import yourmodule_d6_node” step at this point).

Further reading

It took a lot of research to figure out how to get migrate working in Drupal 8 this early in the game. These articles were immensely helpful (thanks bloggers and documenters!).

Aug 26 2015
Aug 26

We’re wrapping up our first Drupal 8 project here at Advomatic, and Jim and I have been tasked with implementing a content migration from the client’s existing Drupal 6 site.

My first migration job was to write a plugin which rewrites image assist tags in node body fields as regular HTML image tags. Fortunately, lots of smart people had already solved this problem for Drupal 6 to Drupal 7 migrations (I adapted my plugin from Olle Jonsson’s script on Github), so the biggest hurdle was learning how to implement this thing in Drupal 8.

This is the true story of how we made it work.

Note: You’ll need to use Drush 8 for working with Drupal 8. I’d recommend following Karen Stevenson’s great tutorial from the Lullabot blog to help set up multiple versions of Drush on your system.

Initial setup

When we first ran our migrations, a few months ago, we needed specific checkouts from dev branches of core and migrate modules. However, as of our final migration run yesterday (10/6/15), we were able to use:

Enable those modules and their dependencies, then set up your own custom module for your plugin code. The very cool Drupal Console module is a quick way to generate the boilerplate files you’ll need.

Write some code

Migration template

Your migration is likely going to need to provide migration templates for various node types, as well as one that handles all nodes. This plugin for handling image assist tags needs to run on all imported nodes, so we start by copying /core/modules/node/migration_templates/d6_node.yml over to our module and adjusting it a little to instruct it to run the ImgAssist plugin (see line 36 here).

Migrate plugin

There are example process plugins in “process” folders around the installation, and looking at those was a great way to figure out how to write ours. Jim made note of these commands to use for finding example code:

find ./ -type d -name 'migration_templates'
find ./ -type d -name 'process'

Our ImgAssist migrate process plugin starts with the Drupal 6 node body and teaser values, and then it runs through a few steps to create their Drupal 8 counterparts:

  • 1. Read through the body value and pick out [img_assist] tags.
  • 2. Split those tags into usable pieces.
  • 3. Build the HTML image tag.
  • 4. Replace the original content containing img_assist tags with the rewritten version, using the built-in transform function.

Running a node migration, step-by-step

  • 1. Get the D6 site and your D8 site running locally.
  • 3. Enable migrate_plus, migrate_upgrade and your custom module.
  • 4. Add your D6 database connection information to settings.php (you can follow the Drupal 7 directions here).
  • 5. Run these Drush commands:
    • drush8 migrate-upgrade --legacy-db-url=mysql://dbusername:[email protected]/D6databasename --legacy-root=http://d6site.local --configure-only
    • drush8 migrate-status (just to make sure your custom migration template is registering)
    • drush8 migrate-import yourmodule_d6_node

You’ll get a notice the first time running migrate-import since the node migration depends on a few others to run first, such as d6_user. Run the dependency migrations as needed, then try the custom node import again.

If you have a lot of nodes, the import process will take a few minutes. I actually wrote this entire blog post while waiting for imports to run. Go do something fun for a minute, you’ve earned it.

Eventually, migrate-import will finish running, and you’ll be all set! You can compare the node on your D8 site against the node on the D6 site and see that the tag has been replaced. Hooray!

If it didn’t work: read on. It’s totally fine, you’ve got this.

So what if you have to roll it back?

drush migrate-rollback hasn’t been implemented in D8 just yet (but it is getting close). A workaround is to use drush scr to run a script which deletes your newly-imported nodes. We’ve been using this: https://gist.github.com/sarahg/993b97d6733003814fda

Then, you’ll need to uninstall your custom module, remove all of its config entities from the database, and drop its database tables. You can do that with queries like these:

DELETE from config where name=“migrate.migration.yourmodule_d6_node”;
DROP table migrate_map_yourmodule_d6_node;
DROP table migrate_message_yourmodule_d6_node;

To make this a little easier, you could add these queries to a hook_uninstall function in your module. I’m not one for making things easy (I’m working on this migration before there’s even a Drupal 8 release candidate, after all), so I’ve just been using drush sql-cli.

Now you can adjust your code as needed, re-enable your module and give it another shot (you can just skip ahead to the “drush8 migrate-import yourmodule_d6_node” step at this point).

Further reading

It took a lot of research to figure out how to get migrate working in Drupal 8 this early in the game. These articles were immensely helpful (thanks bloggers and documenters!).

Aug 12 2015
Aug 12

In the first article in our series we talked about how styleguide-driven development (SDD) and decoupling both serve many of the same goals, and SDD can do so in a way that avoids the many challenges of decoupling.  Now we’ll get deeper into the details of SDD and how we use it to build a website.

This post will walk you through the process from planning to prototyping to developing, theming, and QAing the final product. 

First, plan the work

During a project’s discovery (planning) phase, we break the project down into bite-sized pieces; pieces small enough to build. Part of that includes isolating components. I’m not sure if components is yet a standard word, but it’s a logically and functionally independent piece of the page. One or more components will be placed into a region of the page.  A component can be a menu, a “block”, a “module”, a list, a field, etc..  Below is an example from a full-page comp, showing a single component that we called Image — with rollover.

Comp showing the isolated Image — with rollover component

This is a bit more complicated than it first appears because there’s a complex hover effect.

We’ll start by breaking this down into three user stories:

 

1. Admins see Image — with rollover components after creating them (prototype)

Acceptance Criteria

  • HTML/CSS prototype of component described in the development ticket should appear as comped (across multiple breakpoints).
  • If I hover over the component with my mouse (or tap on a touch device)
  • Then the teal overlay fades in
  • And the title and arrow slide up to the centre
  • And the summary slides into the component from the bottom

Technical notes

See .PSD for hover elements

2. Admins see Image — with rollover components after creating them (develop)

Acceptance Criteria

  • Given that I’m an admin on any customizable page
  • If I click Customize Page
  • And click the + icon to add a new component to the page
  • Then I can add the Image — with rollover component
  • from the Two Thirds width category
  • And I see fields for:
    • Title (built-in)
    • Image (Media browser, req’d)
    • Summary (long text, no WYSIWYG, max 200 chars, req’d)
    • Destination URL (link, URL only, req’d)
  • If I view a page with this component
  • Then I see it (with the markup described in the prototype).

Technical Notes

This should be a Fieldable Panels Pane

3. Admins see Image — with rollover components after creating them (theme)

Acceptance Criteria

Functionality described in the development ticket is styled to match the corresponding prototype and comp.

Why three user stories for one component?

This is ultimately part of how we’re able to resource our projects well in advance and keep things consistent through the life of the project. By splitting tickets this way, we can determine and plan for how many hours we need for each, e.g. Project X will run from Aug 1 – Oct 31. It’s estimated at 600 hours back-end work and 400 hours front-end work. We then go even deeper: Gertrude is working 15 hrs per week on project X and 10 hrs per week on project Y.

There’s a second benefit where this split allows us to do the prototype in an earlier iteration than the dev and theming. This means that right from the start of the project, while back-end developers are working on the foundation, front-end devs (we call them The FEDs) can be working on the first set of prototypes.

Prototype

After looking at the series of design comps (maybe some are “mobile” and some are “desktop”), there are generally three things we’re trying to accomplish when we get into the process of responsive prototyping within our living style guide. The goal here is to provide the cleanest model of how the component should be structured, and it will be used as a guide during actual development.

We advocate creating a prototype horse before just diving in and building one.

First, we try to determine how to build it with the absolute least markup possible. This means first looking at the component at the smallest possible width. We then add required markup only as necessary to fulfill the needs of the component’s layout as things change visually for increased browser widths. The same approach applies when writing Javascript for the prototype.

Second, we try to anticipate and prevent bloated CSS by using our own brand of DRY methodology (Don’t Repeat Yourself) in assigning class attributes to our markup. The idea is to create reusable classes that describe the component as a whole on its container markup, as well as grouping and identifying the inner parts of the component. We try to adhere to the naming conventions used in BEM methodology (Block, Element, Modifier) for writing scalable and modular styles, as demonstrated in the “flower” example by John Albin Wilkins. By doing this, we can really reduce the amount of long, overly specific CSS selectors (perhaps via Sass code nesting), which leads to faster compile times and leaner final CSS. Here’s an example of ideal rollover component prototype source code, as seen within this case study’s living styleguide:

<div class="component image-rollover">
 <img class="image-rollover__image" src="https://placeimg.com/654/476/animals" />
 <div class="image-rollover__overlay">
   <h2 class="image-rollover__title">Living on campus<a class="arrow" href="#"></a></h2>
   <p class="image-rollover__content intro">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent posuere tincidunt nisl et eleifend.</p>
 </div>
</div>

Lastly, sometimes we’ll fake things with CSS in the prototypes that will eventually be provided via backend functionality. For example, “responsive” images used in banner/hero image type components. In the prototype it’s usually good enough to use an image and stretch it fluidly, as big or small as it needs to be, using “width: 100%” and/or the common “max-width: 100%” approach. At some point that will be done using a proper solution, like Drupal’s image styles and the Picture or Client-side Adaptive Image modules.

Develop

The back-end developer’s job is to build the prototyped component in Drupal and hook it up to an admin interface for managing its content. Depending on the project and the context, it could be a fieldable panels pane (FPP), a CTools plugin, a BEAN, a block, a theme function, a field formatter, a View… there are all sorts of ways to accomplish the same thing, and picking the right one could be a blog post itself!

In our example, though, we’re working with an FPP, as specified in the technical notes of the ticket. Looking at the prototype, we determine which pieces need to be editable, and we build fields for those pieces. Here, we were able to use the Fields UI for this (but sometimes we’ll need a custom form).

More often than not, we write some hook_form_alter functions to make the admin experience as smooth as possible – things like conditional fields, or programmatic default values. This one is simple enough already, though. Thanks Drupal!

Fieldable Panels Pane: field configuration and content form

Now, we can input the data required for an instance of this component, and we can make a few samples to work with. Next, we need to override the default markup and get it close to the lean markup provided in the prototype. Since our FPP will be rendered in a panel pane, we implement hook_panels_pane_content_alter, hook_theme and a custom theme function:

/**
 * Themes an image with rollover FPP.
 */
function theme_edusa_media_image_rollover($variables) {
 $output[] = '<div class="image-rollover">';
 $output[] = render($variables['image']);
 $output[] = '<div class="image-rollover__overlay">';
 $output[] = '<h2 class="image-rollover__title">';
 $output[] = $variables['title'] . l('', $variables['url'], array('attributes' => array('class' => array('arrow'))));
 $output[] = '</h2>';
 $output[] = '<p class="image-rollover__content intro">';
 $output[] = $variables['summary'];
 $output[] = '</p>';
 $output[] = '</div>';
 $output[] = '</div>';

 return implode(PHP_EOL, $output);
}

Theme

It’s possible there’s not much left to do during the theming phase if the prototype markup could be faithfully reproduced during development without any snags. However, sometimes it’s easier to make a quick change to the prototype to accommodate something that would have otherwise taken a while to do on the back end. The theming phase serves as a moment for us to tie up any loose ends on the front end, including using the Fences module to set proper wrapper HTML elements (or removing them altogether) for any field content used in the component to match what was used in the initial prototype.

This is where we work in-browser with the fully developed version of the component, and fix any issues on the front-end due to how it appears when real-world variables come into play: the size of the viewport, the existence and length of content, or other edge case scenarios. Occasionally, we’ll need to go back to the style guide and adjust the prototype’s markup, CSS, or JS to keep it in sync with the completed, functional, and responsive version of the component. This is the frustrating part of the process, when the styleguide breaks for seemingly random reasons.  We’ve got some ideas for how to fix this problem.  We’ll explore these ideas in part 3 of this series.

At this point, we’ll do a little mini-QA session to check things against the current versions of our target browsers and a few popular mobile devices. This allows us to catch the majority of browser or device-based issues early while the component is still fresh, before a more thorough QA process at end of the iteration.

The Final Product

And here’s the component in action:
https://educationusa.state.gov/experience-studying-usa/experience-studying-usa

Finished Image — with rollover

The Only Thing You Can Count On Is Change

Regardless of whether you’re doing decoupled Drupal, or styleguide-driven development, you need to have interdependence between the front-end and back-end team. If there’s one thing that we can count on, it’s that partway through the project priorities will change. Maybe now that we see the site in action we realize that it needs to be reworked a bit; maybe someone forgot about feature X that is going to end up taking 25% of the project budget; maybe the client organization needs to pivot. Whatever the reason, we need to have a process that can account for change. And keeping the front-end and back-end teams in sync, neither getting too far ahead of the other, is crucial. If we have to start dropping features, our options become limited if we have many things half-built.

Conclusion

Style-guide driven development is not without its challenges (what is?), but we hope you have a good idea of what you’ll need to make it happen. In part three of this series we’ll explore how we might deal with the problems of styleguides getting out-of-sync with reality and styleguides that randomly break.

This article was a team collaboration by Amanda, Andy, Dave, Jack, Kim, Oliver, & Sarah.

You should also check out:

Jul 21 2015
Jul 21

What exactly are we trying to do here? And is there another way to do it?

Headless/decoupled Drupal has received a lot of buzz in the last year. But the rise of decoupled Drupal has also been met with due skepticism, as there are significant challenges. We’re not here to further that flame war; you can find the details elsewhere. In some specific cases, taking the decoupled approach can be worth the cost of dealing with those challenges. But in many — if not most — cases, that list of challenges trumps the novelty of decapitation.

At Advomatic, we’ve been exploring how to achieve the same goals of decoupling, while avoiding that hefty list of challenges.

The direction that we’ve been heading is to use styleguide-driven development (SDD).

First, what do people typically mean by decoupled/headless Drupal?

In this approach, Drupal is used only as a place for administrators to manage content. The Drupal site does not actually display the content (at least, not to anonymous visitors). Instead the Drupal site makes the content available via an API. That API is used by the public-facing website, which is typically powered by a JavaScript framework like Angular.js, Ember.js, or Backbone.js. This has many advantages, which we’ll discuss below, but this approach also comes with significant drawbacks, like problems with SEO and accessibility, lack of contextual tools for administrators, fad JS frameworks, trouble finding skilled developers, little role for the “site builder,” and more.

Let’s also define what we mean by styleguide-driven development.

We’ll go into more details in the next article in this series, but for now, when we talk about styleguides, we are talking about a set of fully functional, reusable elements and components, built and themed outside of Drupal, using idealized markup. This includes all generic HTML elements, (headers, lists, blockquotes, etc.), native Drupal components (pagers, menus, alerts, etc.), and site-specific components (carousels, listings, features, etc.)

So what are the goals of decoupling? And can SDD accomplish them just as well?

Recently our colleagues over at Lullabot published an article describing the underlying goals of the decoupled approach. Some items on their list are related to APIs. Styleguide-driven development does nothing for your APIs. If you know that one of the primary content delivery methods for your project will be through an API, maybe decoupled Drupal is for you. If you don’t need to have an API, or if the API is going to be a second-class citizen, then decoupling could be a case of YAGNI.

I would argue that one of the goals in the Lullabot article — abstraction and constraints reduce individual responsibilities while promoting content reuse — while an important topic, actually has nothing to do with decoupling. 

I’m adding another of my own, so that leaves us with this list of goals and how decoupling and SDD address each:

  • Less reliance on Drupal specialists  

    Drupal has long been a market where it is difficult to attract top talent;  many people are already happy where they are. Because styleguides are built using the more broadly used tools of HTML/JavaScript/SASS (and maybe a styleguide tool like KSS), we can leverage the skills of a broader variety of web professionals.  In contrast, headless/decoupled Drupal only replaces Drupal specialists with specialists of another type.

  • More self-contained upgrades

    Want to upgrade to Drupal 8 without a redesign, and only a minimal theme upgrade?  Want to revamp the look and feel with minimal changes to the back end? That’s now easier with both decoupling or styleguide-driven-development. Because the front end and back end are less tightly coupled, you can make a major overhaul to one with less impact on the other (compared to if both are a single system). We should note that at this point this is entirely theoretical. The movement is still too new¹ to see many (any?) examples of this in practice.  I anticipate that in reality stakeholders will almost always want to make changes to both at the same time.

  • Allowing front-end and back-end teams to work simultaneously 

    This is where both decoupling and styleguide-driven development really shine.  In the olden days the back-end team would start building the website while the front-end team would be sitting on their hands waiting until there was something to work with.  Similarly at the end of a project the back-end team would finish up while the front-end team frantically pulled all-nighters to fix all the cross-browser bugs. In our next article of this series we’ll delve deeper into how a parallel workflow with styleguide-driven-development can look.

Ultimately, we believe that the styleguide-driven approach has the potential to meet the same goals as decoupled/headless CMS development, but it does so in a way that bypasses many of the challenges.  In the next post in this series we’ll get into the details of what exactly this looks like for a typical project.

In closing, let’s back up for a second and talk about how we should go about making decisions about which tools to use when building websites. 

“Right tool for the job” – another abused one. The intention here is reasonable: who wants to use a tool that isn’t appropriate? But a rare perspective is that this can be detrimental when taken to the extreme. A carpenter doesn’t arm himself with every variation and size of hammer that is available, even though he may encounter hammering tasks that could be ideally handled by each one. Why? Because lugging around (and maintaining) a gazillion hammers incurs a cost. As such, decisions on this axis have trade-offs.
John Allspaw

It’s both too expensive to try and build everything with the same tool, or to learn a new tool for every project.  At the same time, some tools only work for a very narrow use-case, while some tools can be used for a broad range.  Are we hitting the limits of what we can do with small chunks of HTML, CSS, and (minimal) JS?  How far can we take the styleguide approach?  We see the future looking very bright, both in terms of where the web community at large is headed with ideas like Web Components, and at Advomatic we have some ideas for how we can make components more reusable across Drupal projects (look for a future series of articles on this topic).

1. The idea of a decoupled website had some degree of popularity way back in the late 90s, but the flavour that we see now is different enough that it’s difficult to draw many meaningful comparisons.

Thanks to Amanda, Jack, Oliver, and Kim for collaborating with me on this.

Other posts you should check out

Jul 01 2015
Jul 01

Earlier this year, we launched a new site for the ACLU. The project required a migration from Drupal 6, building a library of interchangeable page components, complex responsive theming, and serious attention to accessibility, security and privacy. In this post, I’ll highlight some of the security and privacy-related features we implemented.

Privacy

As an organization, the ACLU has a strong commitment to protecting individual privacy, and we needed to translate their passion to this issue to their own website. This meant meeting their high standards at a technical level.

The ACLU ensures that technical innovation doesn’t compromise individual privacy, and most of our work around user privacy involved ensuring that third-party services like Facebook and YouTube weren’t accessing user data without their consent.

Social sharing

Facebook “Like” buttons on the site offer a quick way for visitors to follow ACLU content on their Facebook feed. But even if you don’t click to “Like” a page, the tracking scripts behind them – coming straight from Facebook – log your behavior and make note of your visit there. That data can be used for targeted advertising, and the data itself is also a sellable product. Because these buttons are all over the web, Facebook can piece together quite a bit of your browsing history, without your knowledge.

To prevent this from happening to ACLU site visitors, we hooked up a jQuery plugin called Social Share Privacy to make sure that visitors who want to “Like” ACLU can do so while others can avoid Facebook’s data tracking. The plugin initially loads a disabled (greyed-out) button for the Facebook “Like”. If the visitor wants to use the button, they click once to enable it, which then loads Facebook’s iframe, and then a second time to “Like” the page.

ACLU.org Facebook button

The Social Share Privacy jQuery plugin keeps Facebook from tracking you without your consent.

A nice side effect is a faster page load for everyone since we don’t have to load content from Facebook on the initial page render.

Video playback

YouTube and other video sharing sites present a similar privacy problem – the scripts used to embed videos can also dig into visitor data without their consent.

MyTube video embed

A MyTube video embed on ACLU.org.

MyTube is a script that was written by the Electronic Frontier Foundation as a Drupal 5 module, then updated as a Drupal 6 module by students in the Ohio State University Open Source Club. For the ACLU site, we worked on porting the module to Drupal 7 and updating various parts of the code to work with updated APIs (both on the Drupal end and the video host end).

Similar to the Social Share Privacy plugin, MyTube initially loads a static thumbnail image from the embedded video, and to play the video, the visitor gives it an extra click, opting-in to run code from the third-party site.

If you’re interested in helping complete Drupal 7 version of the module, take a look at some of the patches our team submitted, and test them out!

Security

Due to the ACLU’s high profile and involvement with controversial topics, security was a major concern throughout the development process. While we can’t go into too much detail here (because, well, security), here are a few steps we took to keep the site safe.

  1. Scrubbed database back-ups. When developers copy down database instances for local development, sensitive information – such as user emails and passwords – are removed. This is made pretty easy using Drush sql-sync-pipe.
  2. Secure hosting on Pantheon with controlled development environments. In addition, though our development team can make code changes, only a handful of authorized ACLU web managers can actually deploy change to their live site. 
  3. The site runs entirely over SSL via HSTS headers
  4. The previous version of the site had various “action” tools where visitors could log in to sign petitions and send letters to their elected representatives. During the redesign this functionality was moved to a separate site, on a separate codebase, running on separate infrastructure. Any site that allows anonymous visitors to create accounts is, by definition, more susceptible to attack. By splitting into two sites, a successful exploit of one web property will not affect the other.
  5. All custom code was reviewed by multiple members of the Advomatic team, and Tag1 Consulting performed an additional security review, in which our codebase received excellent marks and a glowing recommendation.

When your organization champions a cause, all your activities should embody it, including your website. The ACLU takes these standards very seriously, and so do we. Take a look at some of our other projects to see how we worked with nonprofits on sites that reflect their values. 

You should also check out

Apr 27 2015
Apr 27

Over the past year or so here, we’ve tried to make front-end development less painful by creating living style guides in our Drupal themes that we can use internally as a valuable resource during development, as well as externally as a client deliverable. They allow us to write consistent, reusable and efficient code that is easy to maintain over the lifespan of a project. In addition, they show our design standards and prototypes that we can play with in a browser, at different sizes and in mobile devices, before things are truly functional and placed on an actual page of the site.

Though it takes more work at the beginning to set up, it definitely pays off in the long run. Ready to make an automated, living style guide work within your Drupal theme? Here’s how:

 waynes_world_conveyor

Using KSS and Grunt together to build a living style guide

Knyle Style Sheets (KSS) allows us to add special code comments to our Sass/CSS to specify the site’s repeated patterns, branding, color palette, typography, components and Drupal blocks/panel panes. When the Sass is saved and compiled it gets generated into a nice and clean style guide via kss-node (the NodeJS implementation of KSS), immediately viewable in your web browser. If you don’t like how the default style guide looks, you can customize things with KSS Node Template or just customize the default, vanilla style guide template. (However, recent improvements in kss-node – like being able to specify markup or a template file for everything that gets compiled into the style guide – have made KSS Node Template less useful for us.)

Grunt tasks have been great for us, helping automate some of the stuff we regularly do manually.  For example, updating the style guide files the moment that there’s a saved change to the Sass files we’re working on:

watch: {
 css: {
  // Here we'll config grunt-contrib-watch to keep an eye on any .scss file, in any directory in the theme.
  files: ['**/*.scss'],
  // When one is changed and saved, let's run the sass task to compile CSS.
  tasks: ['sass:dev']
 }
},

things get turned into CSS

sass: {
 dev: {
  options: {
   // Since we're compiling a "dev" version of the CSS here, let's make it expanded output style so we get all the little helpful references to where the CSS originates from in the Sass.
   outputStyle: 'expanded',
  },
  files: {
   // Advomatic standard practice is to have one single manifest file (styles.scss) where we import various partial Sass files in the order we want them compiled. We'll specify Sass to compile CSS exactly where we want it, in this case... css/styles.css.
   'css/styles.css': 'sass/styles.scss'
  },
 },
},

and then the style guide gets regenerated on the fly.

kss: {
 options: {
  // Link to previously compiled CSS.
  css: '/sites/all/themes/custom/mythemename/css/styles.css',
  // Link to theme JS.
  js: '/sites/all/themes/custom/mythemename/js/script.js',
  // Set our custom template to build styleguide from.
  template: 'mythemename-styleguide-template'
 },
 dist: {
  files: {
   // "styleguide" is the destination directory, the source directory is "sass"
   'styleguide': ['sass']
   }
  }
}

With this setup in the Gruntfile.js in your theme directory, you can view your style guide directly in your browser by viewing http://mydomainname.com/sites/all/themes/custom/mythemename/styleguide. That’s kind of a long URL, but we can make it more digestible by setting up a redirect to point that long path to a shorter path, like http://mydomainname.com/styleguide.

Drupal markup examples

You know them, you love them! Drupal has a bunch of “pieces” that you usually have to style on every site you work on; tabs, error messages, pagers – that kind of thing.  A great way to see all the different stuff that could appear in your Drupal site is to download and install the styleguide module (check out this demo site to see it in action).  You might not want all of that stuff in your KSS style guide, so just pick and choose the stuff you do want to use.  For adding more standard, non-Drupal-specific HTML elements and design patterns to your style guide, Brett Jankford’s Style Guide Boilerplate is an excellent source of markup chunks.

Let’s say you want to add the Drupal pager to your style guide.  

The latest version of kss-node allows you to specify a file containing a markup example template file (either .html or .hbs) for each section of your style guide.  You can then copy the default pager markup that gets rendered from the styleguide module’s page for your theme at at http://mydomainname.com/admin/appearance/styleguide, and stick it into a pager.html file in your theme and tell KSS where to find it via the KSS comments in your Sass, like so:

// Pager
//
// Markup: pager.html
//
// Styleguide: pager

After you compile your style guide, you will find a “Pager” section that has a prototype (non-functional) pager example using the markup in the pager.html file you added.  You can then style that example as you wish.  Note: the filename should be relative to the .scss file you’re specifying it from.

Pager example

Pager example within the KSS styleguide, as well as a background grid (via Susy)

 

In conclusion

This is just a brief overview of how to make an automated KSS/Grunt living style guide work within your Drupal theme, and there are even more ways to make your it more organized and comprehensive.  We have definitely found that a little work setting up a living style guide during your initial theme setup goes a long way during the project. The result is a constantly updated library of default styles, patterns and prototypes (with markup examples) that serves as a valuable team and client resource.

For an excellent overview on the resources for building (as well as the benefits of) living style guides, you must read my fellow Advomatic front-ender Amanda Luker‘s excellent recent post.

You should also check out:

Mar 31 2015
Mar 31

Heading into Chicago’s Midcamp, my coworker Andy and I were excited to talk to other front end developers about using style guides with Drupal. We decided to put the word out and organize a BOF (birds of a feather talk) to find our kindred front end spirits. Indeed, we found a small group of folks who have started using them and had a great conversation: tools, workflow and pain points galore! So if you have already been using them or if you are brand new to the idea, read on.

Andy on a Divvy bike.

We looked pretty cool riding Chicago’s Divvy bikes to and from the conference!

So what is a style guide?

It can mean different things in different contexts, but for front end development, it means a fully-realized library of elements and components, using clean HTML/CSS/Javascript. I’ve heard them described as “tiny Bootstraps for every client” (Dave Rupert) — a client with a style guide has all the classes and/or markup they need to properly add new elements and components. A living style guide asserts that the style guide is maintained throughout the life cycle of a project.

At Advomatic, we’ve been integrating style guides into our workflow for about a year. We’ve had a few discussions about when it makes sense to have one, and when not. In the past, I’ve even argued against them, in the case of small projects. But at this point, we’ve come to the conclusion that it ALWAYS makes sense to use one. Smaller sites might have smaller styleguides — perhaps just with the the baseline elements included — but with a boilerplate style guide and a compiler in place, the style guide will, in fact, build itself.

So what can you use to build a style guide?

I heard many static markup generators and/or prototyping software mentioned at Midcamp: Jekyll, Pattern Lab, Prontotype, and Sculpin.

At Advomatic, we’ve been using KSS (Knyle Style Sheets), which is more specific to just generating style guides. It uses a Grunt task to compile a style guide from markup (commented out in your Sass files) and the corresponding CSS. This section documents setting up KSS to auto-generate your style guide using KSS. We use the NodeJS implementation of KSS, which, coincidentally, JohnAlbin (the brains behind Zen base theme and Drupal theming in general) has taken the reins on.

If you still haven’t found one you like, here’s a handy list of styleguide generators!

Scared? I hear you. It SOUNDS like an extra layer of work.

Here were my fears moving to style guides:

  • It might add another layer of complexity and chance to break things.
  • If the markup differs significantly in the style guide and Drupal, we’d have to do the work twice.
  • The style guide is not within Drupal, so you cannot write javascript with the Drupal.behaviors convention.
  • If your style guide includes components that are layout-dependent, you’ll need to set up your grid system within KSS.
  • If the style guide rots on the vine or gets out of sync, it could be a pain to fix.

But let’s look at the pros:

  • Clients love to see the style guide, it can be an early, easy win.
  • Keeps the front-end decision-making at the beginning of the process, and agnostic of the back end.
  • Front end work can happen alongside back end work.
  • A HTML/CSS style guide can be a fully responsive document, unlike a PDF.
  • A style guide can be a stand-alone deliverable, if the client needs to pause or implement it themselves.
  • The modularity of a style guide helps clients think about the site as a system rather than individual pages. The result is flexible when the client wants to add more pages down the line.
  • A style guide helps onboard new people coming onto a project or keep consistency among more than one front end dev. A FED can see if a similar component has already been built or if certain styles can be reused or expanded on.
  • Helpful for QA testers — something that they can refer back to if something “in the wild” doesn’t look quite right.
  • Having the markup embedded in the style guide helps multiple developers produce consistent markup for the front end.

We have found that components that we chose to not prototype in a style guide often ended up taking more time than expected. When the back end devs could see what our preferred markup was, they built our components very closely to what we prototyped. In the end, the pros outweigh the cons.

So what is the holy grail style guide workflow?

We’re still looking for it, but here’s some tips:

  • Automate your workflow — style guides should compile every time you make a change to the site. We use Grunt for this.
  • Use a boilerplate style guide — you won’t forget to theme anything that way.
  • Use Drupal-specific markup in your boilerplate to make the transition easier. Use the Drupal style guide module for boilerplate markup.
  • Try not to put too many components on the same page to reduce endless scrolling, ease testing for accessibility by tabbing through components, reduce the amount of javascript and images loading on the page.
  • I haven’t yet, but I’d love to incorporate something like Ish to make each component responsive without having to resize the whole browser window when testing responsiveness.

What else would you suggest? Any pain points that you are feeling when using style guides with Drupal?

Or if you are just dipping your toes in, check out these resources for more good information:

Website Style Guides Resources
http://styleguides.io/

Style Guide podcast, Anna Debenham and Brad Frost
http://styleguides.io/podcast/

Front End Styleguides by Anna Debenham
http://24ways.org/2011/front-end-style-guides/

Design Components presentation from JohnAlbin:
http://www.slideshare.net/JohnAlbin/managing-design

Example style guides
http://ux.mailchimp.com/patterns
http://rizzo.lonelyplanet.com/styleguide
http://www.starbucks.com/static/reference/styleguide
http://www.bbc.co.uk/gel
http://primercss.io (Github’s style documentation)

Style guide comparison chart (google doc)

Responsive Deliverables
http://daverupert.com/2013/04/responsive-deliverables

Modularity and Style Guides
http://dbushell.com/2012/04/23/modularity-and-style-guides

You should also check out:

Jan 16 2015
Jan 16

Now that Drupal 8 is in beta, I’ve been trying to spend some more time with it. Reading articles and watching presentations are good ways to keep up with where things are (or are going), but nothing beats actually using it. Simplytest.me, Pantheon, and Acquia Cloud all now provide free ways to spin up an instance of the latest version (beta 4 as of this writing), so there’s no excuse not to try it out, even if a local setup seems daunting.

After clicking around a bit and admiring some of the administration interface improvements, I set to work on putting a test site together.

Arguably the most essential site building tool, Views in now part of Drupal 8 core. In being integrated, the module has also been leveraged to power most of the default lists and blocks (think content admin page, front page, taxonomy term pages, user admin page, recent content block, etc.). You can use your Views knowledge to modify these site elements or use them as starting points for your own creations.

Credit goes to the VDC (Views in Drupal Core) team for doing an excellent job of porting the module and converting to the new core plugin system. Although VDC wasn’t one of the original initiatives, it was one of the first ones ready, and the team was then able to use what it learned in the process to help out on other initiatives too.

The Views refactoring has brought many improvements, but in this post I’m going to focus on some new Displays functionality. A common task when putting a new site together is to customize the out-of-the-box pages (particularly the home page and content admin page), so I headed to Structure -> Views to copy a default view and get started.

After realizing that everything was mostly the same, one of the first differences I spotted was that you can now clone a display as a different type, so the block you’ve been working on can easily be turned into a page. Each display has its own “View” button, that now also allows you to “duplicate as”, which is slightly different from the old way of doing things. Technically, Views still uses the concept of a “Master” display that can be overridden. You can see it if you create a view with no display type, but it goes away after you create your first display. It pretty much disappears into the UI and is only present in the various settings’ “Apply” buttons — where you can save your changes by display or universally (“this display” vs “all displays”).

d8-views-display-optionsExamining the “duplicate as” options in my test view, I noticed three new display types:

Embed

In the Views module settings, you can choose to “Allow embedded displays”, and they can be used in code via views_embed_view().

Entity Reference

In your Entity Reference field settings, you can choose to “filter by an entity reference view” and use a view with this display type to determine what’s referenceable.

REST export (with RESTful Web Services enabled)

You can convert the output of a view into whatever format is requested, such as JSON or XML, and easily create a REST API for an application.

These Views improvements represent a few differences coming in D8, but are just a small taste of some of the exciting new functionality we have to look forward to in the near future. What Drupal 8 updates interest you the most?

Resources:

Nov 07 2014
Nov 07

This week, a couple of us are at BADcamp! We love the Bay Area Drupal community and this event, and we’re proud sponsors this year. 

This year, BADCamp moved from the hallowed halls of UC, Berkeley to the Palace of Fine Arts in San Francisco, once the home of the Exploratorium (which we also highly recommend). That puts BADCamp 2014 in one of the most scenic areas of the city with views of the Golden Gate Bridge, Alcatraz, and Angel Island just a stone’s throw away.

I spent the day at the Nonprofit Summit attending presentations from local organizations on their big Drupal developments this year. 

Adrian Cotter, from the Sierra Club did a great job of describing how their redesign project was as much a reworking of the structure and processes they used to manage their sites as it was a redesign of the sites themselves. 

Sam Mankiewicz talked about Kiva’s crowdsourcing platform and their upgrade from Drupal 5 to 7. They also talked about it at Austin’s DrupalCon, and you can watch the presentation here

And Mark Burdett from the Electronic Frontier Foundation talked about all the different ways you can put your site, your data, and your visitors at risk and what you can do to protect yourself and your users, including penetration testing, regularly applying security updates and using encrypted connections for your entire site. Mark also talked about HTTPS Everywhere a browser extension that forces encrypted connections for you even if the site doesn’t. 

We absolutely love seeing advocacy organizations using open source solutions to tackle big strategic problems, and it’s always amazing to be surrounded by other people and organizations using technology to make the world a better place. 

Nov 14 2013
Nov 14
Project: Global Zero
Responsive Iframes — yes it is possible

The Web has always had a love-hate relationship with 3rd-party content.  Whether that external content is self-contained functionality brought into a website via SaaS, or to add a donation form to your website in a way that reduces your PCI Requirements, or to possibly connect your disparate web properties together.  Back in the prehistoric days before responsive web development (a.k.a. two years ago) a common way to insert 3rd-party content was with an iframe. Something like:
<iframe src="http://example.com/widget" width="300" height="500" /></iframe>

The challenge with responsive design is the hard-coded width and height.  You might be able to choose reasonable settings for a desktop viewport, but a smaller mobile viewport may require something narrower and longer (or sometimes even wider and shorter).  And as the user interacts with the iframe (e.g. submits a form) the content may shrink and grow. Iframes quickly become untenable in a responsive world.  But often there is no alternative (Salsa, Blackbaud NetCommunity, Wufoo and many other CRM/donation/form platforms do not have adequate JavaScript APIs).

However there is a solution. We can use JavaScript to communicate between the iframe and the top-level page. With one slight problem — due to the same-origin policy an iframe at a different domain can't use JavaScript to directly communicate with the parent page.  Instead we have to use the postMessage() method to do cross-window messaging. This is a bit awkward, but there's good news at the end of this blog post.

postMessage()

Let's start with a quick tutorial on how postMessage() works. We'll set up a line of communication from the parent to the iframe and then send CSS and JavaScript links that can be used to style and otherwise manipulate the content.

// Parent
var iframe = document.getElementById('the-iframe');
var tags = '<script type="text/javascript" src="https://example.com/script.js"></script>';
tags += '<link type="text/css" rel="stylesheet" href="https://example.com/styles.css" />';
// Send a message to the iframe only if it contains content from
// https://frame.example.net.
iframe.contentWindow.postMessage(tags, 'https://frame.example.net');

Before we get too far there is one caveat: You must be able to have a small snippet of JavaScript in the iframe (e.g. If your donation form's configuration tool allows you to insert JavaScript). Unfortunately many 3rd-party tools don't allow this. Other JavaScript we can send over to the iframe via postMessage(), but we need to start with something.

// Iframe
function listener(event) {
  // Only listen to events from the top-level page.
  if (event.origin !== "http://example.com" &&
      event.origin !== "https://example.com" &&
      event.origin !== "http://dev.example.com" &&
      event.origin !== "https://dev.example.com"
  ) {
    return;
  }
  jQuery('head').append(event.data);
}
// We attach this differently for older versions of IE.
if (window.addEventListener) {
  addEventListener("message", listener, false);
}
else {
  attachEvent("onmessage", listener);
}

The cross-window messaging security model can be two-sided. The sender ensures that the data is only sent to trusted domains and the receiver checks that the message came from trusted domains.

Resizing the iframe

To resize the iframe we need to communicate in the other direction — the iframe needs to tell the parent how big it is.

// Iframe.
/**
* Send a message to the parent frame to resize this iframe.
*/
var resizeParentFrame = function() {
  var docHeight = jQuery('body').height();
  if (docHeight != parentDocHeight) {
    parentDocHeight = docHeight;
    // There is no need to filter this to specific domains, since the data is
    // not sensitive, so just send it everywhere.
    window.parent.postMessage(parentDocHeight, "*");
  }
};

// Check frequently to see if we need to resize again.
setInterval(resizeParentFrame, 250);

// Parent.
var listener = function (event, iframe) {
  // Ignore messages from other iframes or windows.
  if (event.origin !== 'https://frames.example.net') {
    return;
  }
  // If we get an integer, that is a request to resize the window
  var intRegex = /^\d+$/;
  if (intRegex.test(event.data)) {
    // Math.round() is important to make sure Internet Explorer
    // treats this as an integer rather than a string (especially
    // important if the code below were to add a value to the
    // event.data, although currently we aren't doing that).
    iframe.object.height(Math.round(event.data));
  }
}
// Setup the listener.
if (window.addEventListener) {
  addEventListener("message", listener, false);
}
else {
  attachEvent("onmessage", listener);
}

You can see these concepts in action on the Global Zero donate page. On a soon-to-be-launched project we're also taking it one step further to pass other information to/from the iframe.

If you do get this far, you'll note how this is a big pain in the arse; It will take several hours to get this all setup and QAed.  The good news is that at some point in the future we won't have to do this.  HTML5 has a new attribute for iframes called seamless. A seamless iframe will inherit the parent's CSS and adapt in size to fit the contents.  The bad news is that it has yet to be implemented by any browser, so it's still a long way off.

Photo by Bruce Denis


Thanks to Ben Vinegar for confirming that I'm not crazy to think this is the best way to do this.

Some browsers currently have very superficial support — they only remove the default iframe border. But that's just simple CSS that your browser-reset CSS is likely dealing with anyway.

Oct 21 2013
Oct 21
Automating new dev sites for new branches

Over the past few years we've moved away from using Subversion (SVN) for version control and we're now using Git for all of our projects.  Git brings us a lot more power, but because of its different approach there are some challenges as well. 

Git has powerful branching and this opens up new opportunities to start a new branch for each new ticket/feature/client-request/bug-fix. There are several different branching strategies: Git Flow is common for large ongoing projects, or we use a more streamlined workflow.  This is great for client flexibility — a new feature can be released to production immediately after it's been approved, or you can choose to bundle several features together in an effort to reduce the time spent running deployments.  Regardless of what branching model you choose you will run into the issue where stakeholders need to review and approve a branch (and maybe send it back to developers for refinement) before it gets merged in.  If you've got several branches open at once that means you need several different dev sites for this review process to happen.  For simple tasks on simple sites you might be able to get away with just one dev site and manually check out different branches at different times, but for any new feature that requires database additions or changes that won't work. 

Another trend in web development over the past few years has been to automate as many of the boring and repetitive tasks as possible. So we've created a Drush command called Site Clone that can do it all with just a few keystrokes:

  1. Copies the codebase (excluding the files directory) with rsync to a new location.
  2. Creates a new git branch (optional).
  3. Creates a new /sites directory and settings.php file.
  4. Creates a new files directory.
  5. Copies the database.
  6. Writes database connection info to a global config file.

It also does thorough validation on the input parameters (about 20 different validations for everything from checking that the destination directory is writable, to ensuring that the name of the new database is valid, to ensuring that the new domain can be resolved).

Here's an example of how it's run:

drush advo-site-clone --destination-domain=test.cf.local --destination-db-name=test --git-branch=test
---VALIDATION---
no errors

---SUMMARY---
Source path         : /Users/dave/Sites/cf
Source site         : sites/cf.local
Source DB name      : cf
Destination path    : /Users/dave/Sites/test.cf.local
Destination site    : sites/test.cf.local
Destination DB name : test
New Git branch      : test

Do you really want to continue? (y/n): y
Starting rsync...                                             [status]
Rsync was successful.                                         [success]
Creating Git branch...                                        [status]
Switched to a new branch 'test'
Git branch created.                                           [success]
Created sites directory.                                      [success]
Updated settings.php.                                         [success]
Created files directory.                                      [success]
Starting DB copy...                                           [status]
Copied DB.                                                    [success]
Complete                                                      [success]

There are a few other things that we needed to put in place in order to get this working smoothly. We've set up DNS wildcards so that requests to a third-level subdomain end up where we want them to.  We've configured Apache with a VirtualDocumentRoot so that requests to new subdomains get routed to the appropriate webroot.  Finally we've also made some changes to our project management tool so that everyone knows which dev site to look at for each ticket.

Once you've got all the pieces of the puzzle you'll be able to have a workflow something like:

  1. Stakeholder requests a new feature (let's call it foo) for their site (let's call it bar.com).
  2. Developer clones an existing dev site (bar.advomatic.com) into a new dev site (foo.bar.advomatic.com) and creates a new branch (foo).
  3. Developer implements the request.
  4. Stakeholder reviews on the branch dev site (foo.bar.advomatic.com). Return to #3 if necessary.
  5. Merge branch foo + deploy.
  6. @todo decommission the branch site (foo.bar.advomatic.com).

Currently that last step has to be done manually.  But we should create a corresponding script to clean-up the codebase/files/database/branches.

Automate all the things!

May 14 2013
May 14

Jack, my co-themer here at Advomatic, and I will be doing a series of articles about how we use SASS and Compass on our projects. There are plenty of articles out there on what it is and how to get started, so we wanted to dig a little deeper, and share a few tips and ideas.

is that IE7 I smell?

Today I'll talk about Modernizr, which is a javascript library that will check to see if your browser supports HTML5 and CSS3 features. We use it on every project now to make sure we aren't serving unsupported stuff to browsers that can't handle it. One thing Modernizr does is add classes to your HTML tag, like "cssgradients" or "no-cssgradients," or "textshadow" or "no-textshadow" as the case may be. Combined with SASS, this can be a very simple way to limit your CSS3 work. Here's an example of how we now apply any of our css3 theming, using the way SASS allows you to check for parent classes, and the nice CSS3 includes of Compass.

h1.title {  // A double border, for browsers that support box shadows; single border for those that don't.
  border-bottom: 1px solid #c3c3bf;
  .boxshadow & {
    @include box-shadow($white 0 1px);
  }
}

Here's a slightly more elaborate example:

#footer {
  background-color #114163: // a baseline background color
  .lt-ie10 & { // dirty proprietary filter for IE9 and below
    filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#2074b1', endColorstr='#114163');
  }
  .cssgradients & { // gradient for CSS3-supporting browsers
    @include background-image(linear-gradient(#2074b1, #114163));
  }
}

By the way, that handy ".lt-ie10" class on the html tag is standard now in Drupal's Zen base theme. It's very handy. While we try to avoid it, we also will add in classes for .mac, .pc, .chrome, .firefox and .safari, if we have some extremely browser-specific problems, which is rare. If you are curious, here's the javascript we use to add that information to the html tag.

Drupal.behaviors.targetBrowsersOS = {
  attach: function (context, settings) {
    // Check to see which operating system we're using.
    if (navigator.appVersion.indexOf("Mac")!=-1) {
      $('html').addClass('mac');
    }
    else {
      $('html').addClass('pc');
    }
    // Check to see if the browser is Safari and doublecheck that it is not Chrome.
    if (navigator.userAgent.indexOf('Chrome') > -1) {
      $('html').addClass('chrome');
    }
    if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) {
      $('html').addClass('safari');
    }
    if (navigator.userAgent.indexOf('Firefox') > -1) {
      $('html').addClass('firefox');
    }
    if (navigator.userAgent.indexOf('MSIE') > -1) {
      $('html').addClass('ie');
    }
  }
}

So, as you can imagine, this gives you the ability to customize what css various browsers are served, and leaner, cleaner experience all around. Stay tuned for more SASS/Compass tips and tricks!

May 10 2013
May 10
Responsive & adaptive grids with Susy, Sass & Compass in Drupal 7

Here at Advomatic we've experimented with several approaches to responsive design over the past few years. I think the "mobile first" philosophy became popular right in the nick of time. There was a point when we'd detect if the user was on a mobile device and then deliver a separate mobile theme. This meant two instances of a site to develop for and maintain. I can't imagine doing that now, given the amount of device width/height possibilities and device-specific bugs that exist out there. So, now we work on layout with the goal of accommodating the content rather than the device. To accommodate a responsive and flexible layout, it's best to get your site on a grid. There are tons of options out there, but we've found one in particular helps you quickly get rolling and set up with a column layout that can adjust to whatever device you need your site to display on (and is fun to work with, too). Lately, it's been part of our holy trinity for responsive theming: Sass, Compass and Susy.

First things first: ditch pixels

One big first step to responsiveness in your site is to stop using pixel units for measurements. We use em units because they are proportional to any parent measurement, and therefore flexible and responsive. If we have a base font-size set on the body element of 16px, and our #footer is set to 1.6em, that #footer font-size will automatically scale up or down accordingly if the body's (or any parent element to #footer, for that matter) font-size changes. To manually figure out exactly what em value you should be using for an element, you can use a commonly used formula: target ÷ context = result... or you could do it the easy way with a Sass function:

// Create em() for setting font-sizes in pixels.
@function em($target, $context: $base-font-size) {
   @if $target == 0 { @return 0 }
   @return $target / $context + 0em;
}

// Example usage: font-size: em(21px);
// This will set the font-size to 21px in relation to the browser's base font size if it has not been established in any parent element, or in relation to $base-font-size which is a variable you can set in your Sass.

// Example usage 2: font-size: em(12px, 10px);
// This will set the font-size to 12px in relation to a parent element's font-size of 10px.

Get on the grid

If you're doing front end development these days, you're probably familiar with the concept of grid-based design and translating a comp into a fully fluid or adaptive layout via HTML/CSS. We frequently use Zen 5 as a base theme and have been big fans over the years because it comes loaded with many of the best tools for front end/theme development, while also pretty lean as far as bloat goes. While it's important to be able to build themes for browsers that can handle fancy bells and whistles, we also need to support older browsers that don't. Zen 5 already has Sass and Compass integrated. As far as a grid framework goes, we use Susy instead of Zen Grids... this has just come down to personal preference. Zen Grids is also a great system. Susy is a responsive grid framework/plugin for Compass, and it allows you to build on top of either a "magic", static or completely fluid grid.

  • "Magic" grids are the default - they have an elastic container that responds to font sizes when set with em units, and is fluid on the inside. It's container size gets calculated according to the widths of your columns and gutters.
  • Static grids are just that - all containers and column widths are not flexible and this is the traditional grid style. As such, it does not collapse when the viewport is smaller than the grid is wide. Even though you may specify pixel values for the column sizes, Susy converts to a percentage of the container size. The container size, like the magic grid, gets calculated according to the widths of your columns and gutters.
  • Fluid grids are truly flexible layouts that respond to the width of the viewport. By default the container width is 100%. However, as with any grid type you choose, you can specify this with the $container-width variable (such as "$container-width: 70%").

Set it all up

To add Susy to your theme, there are a few things you'll need to do.

  1. If you haven't already, install Sass and Compass.

    sudo apt-get install rubygems
    sudo gem update
    sudo gem install sass

    sudo gem install compass

  2. Set up a Compass project in your theme directory.

    This is already done for you with Zen 5. If you're not using Zen 5 or a contrib theme that has this done already (look for a config.rb file in the theme directory), then set up your Compass project by going to your theme directory in your favorite command line interface and run:

    compass create nameofyourtheme

    This will add a "config.rb" file to your theme, and is where the Compass project settings are located.

  3. Then, install Susy.

    sudo gem install susy

  4. Require Susy in your Compass project.

    Open up the config.rb file and add the following (wherever "requires" are located):

    require "susy"

  5. @include susy and add grid settings to your _base.scss (or equivalent "global" Sass file).

    We usually stick any of our grid settings in the _base.scss file that comes with Zen so that the grid variables set there are available to any other Sass stylesheet in the theme (because Zen's base gets @imported in them all). You'll also want to place them in whatever Sass file you're using that gets imported into any file where you'll be doing responsive styling/layout. For example:

    @import "susy";
    $total-columns: 12;             // a 12-column grid
    $column-width: 4em;            // each column is 4em wide
    $gutter-width: 1em;            // 1em gutters between columns
    $grid-padding: $gutter-width;  // grid-padding equal to gutters

After installing Susy, and getting your Compass project set up properly for the theme, you'll want to tweak those default grid settings that you just added (total columns, column width, grid padding, etc...) for the purpose of your own design. Using those settings, Susy will automatically figure out the math and put percentage widths on internal grid elements, as well as a max-width on the container (should you use a non-fluid grid). By default, all Susy grids are "magic." If you want to use one of the other types of grids, you would do that by setting the $container-style variable. For example, to build a 5 column-wide mobile first "magic" layout, we can do something like this:

$total-columns: 5;
$column-width: 3em;
$gutter-width: .75em;
$grid-padding: $gutter-width;

Making things happen at different viewport sizes

Another handy part of Susy is its at-breakpoint() mixin. This can be used in replacement of a long and drawn out media query that targets specific pixel-based min-width or max-width values of the viewport. Something we do frequently for adaptive/responsive layouts (where there are established, comp-determined breakpoints for mobile, tablet, desktop), is set variables for different numbers of grid columns.

$mobile   : 5;
$tablet   : 11;
$desktop  : 16;

So if you're building in a mobile first manner like this, and you want something to happen at a certain breakpoint in your Sass, you can use at-breakpoint() with your column count variables as an argument.

#content {
  @include span-columns(5);
  @include at-breakpoint($desktop) {
    @include span-columns(13, $desktop);
    @include prefix(3, $desktop);
  }
}

In this situation, #content normally spans 5 columns wide, which is the default/mobile width of the grid in this example. When the viewport is at the desktop breakpoint (16 columns can fit in the viewport), the width of #content will change. span-columns(13, $desktop) means "make this 13 columns wide, out of 16 total columns". prefix(3, $desktop) means "add 3 columns of empty space beforehand." So #content becomes 16 columns wide in total, however only 13 columns of space are usable and contain content, since we added 3 columns of padding to the start. A different, non-layout related way of using at-breakpoint() is to maybe change some kind of style at a given breakpoint.

padding-bottom: em(15px);
@include at-breakpoint($desktop) {
  padding-bottom: em(85px);
  background: url("bg-content.png") 162px 100% no-repeat;
}

Having at-breakpoint() at the ready is a great way of releasing yourself of the mindset and clutter of maintaining several pixel-based breakpoints in your site, and helps future-proof things since device sizes are fluctuating so wildly as time goes on. Since Sass supports code nesting, it has become standard operating procedure for us to use at-breakpoint() at the end of things in a selector's nested styles, so that they override any established defaults (which are usually the mobile version styles if we are building mobile-first).

Alternatively, Aurora

While we normally use Zen and add Susy in manually (replacing Zen Grids), some themes have Susy, Sass and Compass (and other front end goodies) baked in already. Aurora is also a Sass & Compass-powered minimalist theme with a focus on best practices for HTML5 and front end development within Drupal. It has a number of cool features like Google Chrome Frame and Typekit integration. Aurora encourages the use of Panels' HTML5 Sections layout instead of using the standard Drupal left/right sidebar block regions for sidebars. Aurora also suggests you use the Blockify module to turn all the little things on the page that normally get rendered in a page template variable into blocks that you can assign to regions via Drupal's block admin page. There are a number of features in Aurora which have been pulled out and put into a separate module, so that any theme can make use of them. That module is called Magic and some of it's best features are the ability to exclude certain CSS/JS from being included, exporting of theme settings, enhancement of CSS aggregation and adding a viewport width indicator - which is very helpful when developing a responsive site to check all your breakpoints and everything in between.

Conclusion

Susy provides a great way of quickly getting your site layout blocked out and can produce any kind of grid you need. What has your experience been like using Susy in Drupal?

Dec 11 2012
Dec 11

Drupal 8, originally scheduled for an August 2013 release, will from all appearances not just be another version upgrade. There will be extensive improvements on issues that matter to all types of Drupal users. That last sentence doesn't do it justice. Really Drupal 8 will be a quantum leap among Content Management Systems and Web-Application Frameworks.

Who will Drupal 8 benefit the most, users or developers? This is hard to quantify, but so far it seems that the end user will feel the biggest shift. The most dramatic changes for end users will be a simplified interface for content modification, and improved mobile compatibility. But these are not the only enhancements that are underway for what is undoubtedly the most ambitious Drupal version to date.


If you can post to Facebook, You can post to Drupal 8

Posting content will be as easy as it is on popular social networking sites. If you can post to Facebook, you will be able to post to Drupal without any additional training. The usability for site managers is also markedly improved. This is all due mainly to the Spark distribution work which allows in-place editing, see http://drupal.org/project/spark. The goal is that content creators, site managers and end users will have the option to just click what they want to edit on a page, like the title, text, or images and change them directly without having to switch to an administrative editing interface. I know that end users have instinctively tried to edit content just by clicking on blocks of text when given Drupal without any training. This update will make the process of seeing what your changes look like as you compose feel entirely natural.


Mobile

Drupal 8 is setup for mobile in multiple ways. The new Drupal is being built so that from the moment of first use, you will be able to interact with your site on both traditional and mobile displays. Additionally, work is underway towards “responsive layouts” which allow site creators to place regions of text, graphics and other elements so that everything appears readable on mobile devices and your laptop, auto adjusting size and orientation to whatever you are using at the time. Mobile apps will also be able to tie into Drupal 8.

Say you feel like logging into your Drupal site and checking on new comment activity, but you only have your mobile phone. With Drupal 8 you'll be able to do that with an interface that works well with your mobile device; no scrolling around and trying to enlarge text. While much of this is possible with Drupal 7 with extra setup beforehand, we're going to see this become the standard on Drupal 8.


HTML5 and High-Performance

Drupal 8 does HTML5, the shiny new version of Hyper Text Markup Language that supports video, audio, better forms, 2D/3D graphics and animation. That's just the start of the great things HTML5 offers and it's with Drupal 8 it's already built in, link: http://www.switched.com/2010/05/11/what-is-html5-and-why-should-you-care.

Major work is going towards performance improvements in Drupal 8, we'll be blogging later to explain how. To generate pages suitable for a variety of devices it is important for Drupal 8 to be quick, and major progress is already underway to enhance speed, mainly on the “front-end,” and that means on your end-user device.

Lastly, efforts are being made to include back-end wizardry which allows custom apps to connect to the Drupal database in standardized ways using new and improved Web-Services. Web Services are how different computer devices communicate with each other over the Internet. When you visit somewhere else in the world it is good to speak the language, in this case the computer's language. Improved Web Services allow your Drupal 8 site to communicate better with the world, that is other applications, be they mobile or most anything else which speaks these standardized data languages.


Other Initiatives

The other main initiatives, overlooking all the many tweaks and interface improvements are: multilingual, design, and configuration management (and the Views module group is in core).

If you have a multilingual site, or more to the point, want a multilingual site, Drupal 8 now includes the language systems in core. So adding languages and translations is more like installing or updating modules.

Designers will also see big changes with the way themes are made using Drupal 8, and given the mobile initiatives this is imperative. The goal here is to make design (theming) work better. The end result is cleaner and more elegant web design.

There will also be improvements in configuration management. When creating sites, most developers have multiple installations of the site, development, staging and production, or minimally development and production. In Drupal 8 configuration management makes it easier and methodical to maintain these separate installations while simplifying deployment of new code, updates and alterations. Besides the time saved for developers, these procedural improvements will benefit site owners because their site can be better maintained, more stable, and more secure.

Recently the Views module has been added to core. If you don't know what Views is in Drupal, suffice it to say that now, with a default Drupal 8 installation, site-builders will be able to make complex web applications, similar to many of the popular ones we know and love, like Twitter for instance, without adding additional external modules (of course you may end up adding just a few of the thousands of available modules to add some cool functionality). Yep, it's excellent.

That's a long list so far and that's just the beginning. Drupal 8 has even more in store for all of us due the large and growing community of ambitious and hard working contributors.


This blog entry is based on an informal presentation and post-discussions about Drupal 8 given by Darrell Ulm at Drupal Camp Ohio 2012.

Apr 17 2012
Apr 17

A lot of very interesting things are happening to make Drupal's caching system a bit smarter. One of my favorite recent (albeit smaller) developments is a patch (http://drupal.org/node/1471200) for the Views module that allows for cached views to have no expiration date. This means that the view will remain in the cache until it is explicitly removed.

Before this patch landed, developers were forced to set an arbitrary time limit for how long Views would store the cached content. So even if your view's content only changed every six months, you had to choose a time limit from a list of those predefined by Views, the maximum of which was 6 days. Every six days, the view content would be flushed and regenerated, regardless of whether its contents had actually changed or not.

The functionality provided by this patch opens the door for some really powerful behavior. Say, for instance, that I have a fairly standard blog view. Since I publish blog posts somewhat infrequently, I would only like to clear this view's cache when a new blog post is created, updated, or deleted.

To set up the view to cache indefinitely, click on the "Caching" settings in your view and select "Time-based" from the pop-up.

Then, in the Caching settings form that follows, set the length of time to "Custom" and enter "0" in the "Seconds" field. You can do the same for the "Rendered output" settings if you'd like to also cache the rendered output of the view.

Once you save your view, you should be all set.

Next, we need to manually invalidate the cached view whenever its content changes. There are a couple different ways to do this depending on what sort of content is included in the view (including both of the modules linked to above). In this case, I'll keep it lightweight and act on hooks in a custom module:

/**
* Implements hook_node_insert().
*/
function MY_MODULE_node_insert($node) {
  if ($node->type == 'blog') {
    cache_clear_all('blog:', 'cache_views', TRUE); 
  }
}...Same for hook_node_update() and hook_node_delete()...

And just like that, my view is only regenerated when it needs to be, and should be blazing fast in between.

The patch was committed to the 7.x-3.x branch of Views on March 31, 2012, so for now you will have to manually apply the patch until it is released in the next point release.

Happy caching!

Apr 11 2012
Apr 11

Ah, Drupalcon. Three days of panels and BOFs, one Advomatic code sprint, and some very late nights with the Advoteam. Now I'm thrust back into the land of overflowing diaper pails and spaghetti bits everywhere that is work-from-home motherhood. But I promised myself I'd put my DrupalCon notes into a fancy blog post in the hope that others will find them useful (and so I can find them later). Two weeks later, here goes.

This year's DrupalCon was particularly fruitful for us theme developers. In years past, there hasn't been much new and shiny for us beyond CSS3 goodies we couldn't touch because of legacy browsers. But technology is changing, as it is wont to do. We're seeing a revolution in how we plan, design, theme and QA our sites, thanks mostly to responsive design (and SASS/Compass, but I'll save that for a later blog post.)

If you need any convincing that the mobile revolution is mandating a change in the way we design and build sites, check out Luke Wroblewski's super engaging keynote. LukeW coined the term (and wrote the book) "Mobile First" to redirect planning sites for handheld devices first -- then for computers -- because of the clear trend in how people are accessing sites. A collateral benefit is that by designing mobile first you are forced to prioritize your site's content -- maybe the main thing people need when they go to your organization's website is how they can help the cause, not a letter from the Board. There were a few "future is now" moments in there too, for better or worse. Do check out his Future Friendly manifesto.

At Advomatic, responsive sites are rapidly becoming the norm, and we're figuring out best practices as we go. So these DrupalCon sessions were a top priority:

There was a bit of buzz around the idea of doing "design in browser" versus in a design program like Fireworks or Photoshop, which inevitably mean a fixed width conceptualization of a site (even if the designer creates versions for a variety of browser widths.) SASS and Compass would give you a leg up to design something quickly directly from your browser, and I hope to address that in future blog posts. However, I tend to camp with those that say that starting from the browser will inevitably stunt a designer's creativity:

The browser was intended as a delivery mechanism with HTML and CSS a means of describing content rather than defining it (a subtle distinction I know, but an important one). As such the browser lacks even the most rudimentary tools, such as the ability to draw lines or irregular objects through direct manipulation. Instead this process is heavily abstracted through code. As the best design tools are the ones that put the smallest barrier between the creator and their creation (the pencil is a good example of this) designing in the browser adds an unnecessary level of craft to the process. - Andy Budd, Clearleft

I'm not sure whether Photoshop and Fireworks will soon have built-in flexibility, or if browsers will have built-in design tools, but currently neither is a perfect tool for responsive design.

Another interesting approach to the the problem of graphic design for responsive environments is Style Tiles, which was mentioned in at least four of the sessions I saw. It's a method for designing for a client without creating full comps, somewhere between a "mood board" and a comp. I like that it allows for some flexibility, and look forward to an opportunity to try it out. Another suggestion was designing a few comps for different breakpoints in Photoshop/Fireworks and a style guide -- and then move to designing in the browser.

One Drupal module that would help with in-browser design (and makes testing for different displays easier) is the Style Guide module, which generates a page where you can test all common HTML elements for a site, so you don't miss anything.

There is still a lot of debate on how to handle images in responsive design. While the img {max-width: 100%;} goes a long way, it still means you are potentially downloading a unnecessarily large image on your phone. And unlike CSS background images, img tags have a single, immutable source. The Adaptive Image module for Drupal is suggested, as is Borealis Responsive Images, for creating smaller images on the fly depending on the browser size. It's a complex issue, and you can dive deeper here and here. For video FitVids was suggested (and FitText for flexible font sizes.)

What about content? While there is this mantra of "mobile first" -- designing the site around the smallest of devices first, keeping content super streamlined -- there's another thread that content available to larger screens shouldn't necessarily be hidden on smaller screens. Mobile users may in fact be looking for a more rich experience, not just the bare bones. So think twice before plunking in a display:none on an entire region. However, I imagine that will probably be a site-by-site decision.

Responsive Design Testing

So testing for all these various devices inevitably will be tedious. I collected a little list of some tools to help.

  • Responsive Design Testing Tool - See how your site will look in four different device widths together on a single page.
  • Adobe Shadow - plug in devices to a desktop, pull up your site on one, and view it in all devices (no need to surf to it on all devices.)
  • The Browser Stack, a cross browser testing tool, just added mobile support

And, finally, here's a collection of fun responsive examples to check out for inspiration.

There you have it. Hopefully something in my extended brain dump will be of use to you!

Watch all Drupalcon sessions here, and fill me in on anything I missed below.

Jan 12 2012
Jan 12

This month the Senate is scheduled to vote on a bill that could end the internet as we know it. If the so-called “Stop Online Piracy Act” (SOPA), currently making its way through the House, or the “Protect Intellectual Property Act” (PIPA), awaiting a vote in the Senate, become law, corporations will have the ability to “disappear” your website without any due process. Internet innovators like Google, Twitter, Wikipedia, Al Gore and YouTube have come out against the bill because it will be disastrous to free speech, business and yes, to nonprofits.

Web innovators are taking the threat of SOPA and PIPA very seriously. One of the most popular sites on the internet, Reddit, is going to go dark for 12 hours on January 18th to protest against the bill. That will be a small sample of what the world would be like if these bills became law. No more satirical content that uses pop-culture to make a point. No more Fair Use. Nonprofits could be held accountable for what their members post. And nonprofits won’t have the financial ability to protect themselves.

So if the people who built the internet and the most important sites on the internet are telling Congress not to pass this bill, who is telling them to support it? Here’s the list. And until a few days back, the regressive domain name registration and web hosting company GoDaddy was championing SOPA as well.

Hard to say why GoDaddy was supporting it. Maybe it’s because there were amendments in the works that would exempt operators of commercial sub-domains such as GoDaddy from the law. But maybe it’s just because GoDaddy is an ideologically bad company. Their ads are sexist and their president shoots elephants. (Seriously who does that? Montgomery Burns?) When activists at Reddit learned about GoDaddy’s support of SOPA they named December 29th Dump GoDaddy Day and started organizing.

What happened next is a great case of consumer activism and online organizing making a difference. TheDomains.com reports that GoDaddy lost 37,000 domains between Dec 22 and 24 alone! GoDaddy changed their stance VERY publicly as a result of the public outcry. Advomatic was moving one last domain away from GoDaddy and as we clicked the button on their site to receive the final authorization key we needed to leave, GoDaddy displayed a message saying that they no longer support SOPA-- a final pathetic plea as if to say, “We stopped being evil! We promise!”

Guess what? Even though GoDaddy relented, their President still killed an elephant and their ads are still sexist. They don’t deserve our support.

Thankfully, there are many domain name registration companies you can move to for better service AND that have policies that match our progressive values. Advomatic transferred all of the domains we manage away from GoDaddy to the domain registrar Gandi.net. They are against SOPA and even donate money to the Electronic Frontier Foundation! Other good options include DreamHost, which provide free hosting for 501c3s and NameCheap (which had an anti-SOPA discount).

To help you out LifeHacker posted a handy guide on how to switch web domain companies. If you’re a client and need a hand moving your domain names let us know! And don’t forget that we offer web hosting with free migration help through our hosting service line, Cadre.

So join Advomatic and all of the other business and nonprofits that care about the future of the internet and don’t like sexist jerks and change your domain company and keep those emails going to Congress.

Maybe we should start a petition asking Google and Facebook to post anti SOPA messages on their sites so they can educate their users....

Sep 19 2011
Sep 19

Columns. While it may seem like a good idea to a graphic designer, the idea of newspaper-style columns strikes fear in the hearts of themers everywhere. In particular, you may run into an instance where you need a list view to be A-L in the first column, then M-Z in the second column. I'll walk you through a method for doing just that, using a little PHP. Note that this is for Drupal 7, but is easily adaptable for Drupal 6.

I will note first that there are a couple other quickie options that might work for your situation.

1. There are several javascript solutions available, which finds a midpoint in the text and wraps the chunks in divs. This works, but if a user has a plugin like NoScript enabled, this solution does not degrade gracefully.

2. There IS a CSS3 multicolumn solution, but it is largely unsupported. Currently it is only supported by Firefox 1.5+ and Safari 3.

So, eventually, there will be a simple CSS solution, but, for the time being, the cleanest option is server-side, using PHP.

In my example here, we'll look at theming a list view to have multiple columns.

Say you have a view with a some items that we want to display in two columns. Views generates HTML that looks something like this:

<div class="view-columns">
  <div class="view-content">
    <div class="views-row views-row-1 views-row-odd views-row-first"> ... </div>
    <div class="views-row views-row-2 views-row-even"> ... </div>
    <div class="views-row views-row-3 views-row-odd"> ... </div>
    <div class="views-row views-row-4 views-row-even views-row-last"> ... </div>
  </div>
</div>

Here's what that looks like just floating each row to the left. Looks like columns, but they are not in the order we want.

floated rows

Instead, we want something that looks like this:

newspaper style columns

To make this themable with CSS, we need the markup to look like this instead:

<div class="view-columns">
  <div class="view-content" id="leftcol">
    <div class="views-row views-row-1 views-row-odd views-row-first"> ... </div>
    <div class="views-row views-row-2 views-row-even"> ... </div>
  </div>
  <div class="view-content" id="rightcol">
    <div class="views-row views-row-3 views-row-odd"> ... </div>
    <div class="views-row views-row-4 views-row-even views-row-last"> ... </div>
  </div>
</div>

The solution to building this markup is with PHP in a views template. The next trick is to choose the right one! Editing your view, click on the Advanced tab, then on Theme: Information. We want to use the Display output template. So, for example, mine is called: views-view--columns--page.tpl.php.

First, we'll make a preprocess function in our template.php file specific to that views template file that finds the number of view results and the halfway point.

This first function here is a helper function for Drupal 7 so you can add preprocess functions to specific views on the fly:

<?php
 
function THEME_preprocess_views_view(&$vars) {
    if (isset(
$vars['view']->name)) {
     
$function = 'THEME_preprocess_views_view__'.$vars['view']->name;
      if (
function_exists($function)) {
      
$function($vars);
      }
    }
  }
?>

And here's the preprocess function:

<?php
 
function THEME_preprocess_views_view__columns(&$variables) {
   
$view = $variables['view'];
   
// Create a variable that divides number of results in half and add one.
   
$variables['half'] = ceil((count($view->result) / 2) + 1);
  }
?>

Once you have determined the $half variable, which is row number that starts the second column.

So let's add the markup to the views tpl file.

Replace the lines:

<div class="view-content">
  <?php print $rows; ?>
</div>

with:

<?php
 
// remove white space in html
 
$rows = preg_replace('~>\s+<~', '><', $rows);
 
// add the </div><div> in at the halfway point to separate the columns
 
$search = '<div class="views-row views-row-' . $half;
 
$replace = '</div><div id="rightcol" class="view-content"><div class="views-row views-row-' . $half;
 
$rows = str_replace($search, $replace, $rows); //
?>

<div class="view-content" id="leftcol">
  <?php print $rows; ?>
</div>

This will wrap the first half of your results in a leftcol div and the second half in a rightcol div. From there, float your columns and add the necessary padding. Enjoy!

Jul 06 2011
Jul 06

Here's a beginner-level Drupal CCK/Views site building recipe for creating a nicely filterable Staff page. After making one like this for a recent project in Drupal 6, I was both pleased and annoyed to discover how easy it is to build in Drupal 7, now that fields are in core. I'll show you both ways in case you are still on Drupal 6 and need to accomplish this task.

Our goal is to make a grid of user profile pictures, and have filters in the sidebar to help find someone. Something similar to Yahoo Research's staff page.

yahoo staff list screenshot

The Drupal 7 Way

Let's do the easy way first.

  1. Make sure you have installed and enabled Views (and Chaos Tools).
  2. Configure your user form with any additional fields you want by going to admin/config/people/accounts/fields. In my example here, I used Job Title, Location and a field for Full Name, so you can use that instead of the Username in the view, since usernames are often abbreviations. Thinking ahead, consider if you would like any of these fields to be exposed filters on your staff view. Because I want people to be able to find staff based on their job title or location, I made those fields select lists instead of plain text fields.
  3. Add your users at admin/people/create. Once created, edit the user to add a photo and fill in the additional information. (You can expose the additional fields to the User Create form too. Depending on your site, you may not want all those fields on the initial registration page so as to not overwhelm new users, if they are the ones filling out the form.)
  4. Now let's create the View: admin/structure/views/add. Show Users, create a Page, and give it a path so you can find it.
  5. Set the Format to Grid* and Show Fields. Select the fields you would like to expose. I've selected User: Picture, User: Full Name, User: Job Title, User: Location, in that order.
  6. Choose your Sort Criteria. If you want to sort by last name, you may need to create another field for just the last name, or redo your fields to include first and last names as separate fields.
  7. In the Advanced area, I have enabled "Exposed form in a block", so one can place the filters in the sidebar, as opposed to at the top of the view.
  8. Save your View, and visit the blocks page to position your Exposed filters block in the desired region. Also, edit your block so it only appears on that View (and perhaps on user pages).

drupal 7 staff list

And that's basically it; it's ready for theming. The one tricky part is that Drupal 7 still uses an odd image field for the user picture that is not configurable with Image Styles (although it seems to default to the thumbnail Image Style), the core replacement of ImageCache for Drupal 7 (both for the User page and for Views.) In that case, we'll need to theme them manually with theme_image_style()** in your user-picture.tpl.php file. If you want the staff view to have a different size, find the Field User: Picture tpl information under Theme: Information in the views configuration and theme it from there.

The Drupal 6 Way

Now you will see how awesome Drupal 7 is! Obviously this is just one example, but this one test case shows me that some annoying problems have been solved in the latest version. (I made it extra hard for myself by first trying to do this with core Profiles and the Profile Checkboxes module, which has a frustrating known issue with exposed filters in Views. Yeah, don't do that.) Let's get to it!

  1. First, install the Content Profiles module. This module allows user profiles to be treated like nodes with CCK. Also make sure you have installed and enabled Views and CCK (with Text and Option Widgets).
  2. Now you will see a new content type for Content Profiles. First configure it by going to admin/content/node-type/profile. Under "Submission form settings," you will probably want to change "Title" to "Name," and hide the Body field, and disable Comments. Under the last section, Content Profiles, there's a checkbox for using that content type as a content profile for users. Check it.
  3. Click "Manage Fields" next to the Profile content type to add the additional fields you want. In my example here, I used Job Title, Location and Full Name, so you can use that instead of the Username in the view, since usernames are often abbreviations. Thinking ahead, consider if you would like any of these fields to be exposed filters on your staff view. Because I want people to be able to find staff based on their job title or location, I made those fields checkboxes instead of plain text fields.
  4. Make sure you have enabled Picture Support in your User Settings (admin/user/settings).
  5. Add your users at admin/user/user/create. Once created, edit the user to add a photo and click the "Profile" tab to fill in the additional information. (You can expose the additional fields to the User Create form too. Depending on your site, you may not want all those fields on the initial registration page so as to not overwhelm new users, if your site has open registration.)
  6. Now let's create the View: admin/build/views/add. Give it a name and choose User as the View type.
  7. Set the Style to Grid* and make sure the Row style is set to Fields.
  8. To be able to access Profile fields for a User view in Drupal 6, you will need to create a Relationship from Users to the Profile table in the database. (If you tried to add Content Profile fields to the Fields in the View now, you'd see that they are not available.) To make them available, add a new Relationship of Node: Content Profile. Choose "Profile" as the content type and check "Require this relationship."
  9. Now you should see your custom profile fields under Fields (in the Content group.) In my view, I've added User: Picture, Content: Full Name, Content: Job Title, Content: Location, in that order.
  10. Choose your Sort Criteria. If you want to sort by last name, you may need to create another field for just the last name, or redo your fields to include first and last names as separate fields.
  11. Under Basic Settings, enable "Exposed form in a block", so one can place the filters in the sidebar, as opposed to at the top of the view.
  12. In the Filters area, add the fields you will filter by: Content: Full Name, Content: Job Title (allowed values), Content: Location (allowed values). Expose all of them, and adjust each of their labels. For the Full Name, change the operator to "Contains."
  13. Save your View, and visit admin/build/block to position your Exposed filters block in the desired region. Also, edit your block so it only appears on that View (and perhaps on user pages).

drupal 6 staff list

Now you are ready for theming!

This tutorial was both meant to ease a new user into building a common type of view, and also to highlight some of the improvements we are now enjoying with Drupal 7.

*If you don't like tables in your markup, see my post about creating a tableless grid for a Drupal view.

** This function works a bit differently than theme_imagecache() did in Drupal 6. Mine looks like: <?php print theme_image_style(array( 'path' => $account->picture->uri, 'style_name' => 'medium')); ?>, but check the API to make sure you using the proper method.

Jun 28 2011
Jun 28

Cadre Web Hosting is sending someone to Drupalcon London 2011. Will it be you?

That's right, Cadre is sending one lucky winner to London to attend Drupalcon all on our dime. Since we are Silver Sponsors this year we decided that we'd give away a conference registration along with airfare and lodging for the week of Drupalcon. All you have to do is be from the US, Canada or Europe and gain the most points during the contest, simple right?

Here's how it works:

Step two: Activate your contest page by following the activation link we'll send you after submitting the entry form

Step three: Run your contest! Send your contest page around to everyone you know. For each tweet or facebook post someone does through your page you get one point. Folks can do this once per day, so be sure to get your crew to come back so you can stay in the lead. We'll be sending out additional updates with other ways to win points as the contest continues, so stay tuned for those announcements!

Step four: The contestant with the most points wins!

In addition to the grand prize, we will also be giving runner-up prizes including a year's worth of web hosting and fancy Cadre t-shirts, how about that? Are you so excited you just can't stand it? We are too, so get over there, sign up and start rallying your supporters!

We'll see one of you in London, good luck!

The Cadre Web Hosting Team

Jun 07 2011
Jun 07
Notable changes to theming in Drupal 7

There are 50+ changes to the theme system in the move to Drupal 7 - that's a lot to consider when upgrading your theme from Drupal 6 to Drupal 7. As expected, some of the changes make theming more complex... but those changes can also free things up for you to do complex things in a simpler way. Some things have been broken down into smaller pieces so you can do more with them, and some tasks you did repetitively across different themes are now automated.

Node Jenga

So far, you've come to grips with two common ways of getting fields to print in the node template (in the order you want):

  1. Drag and drop fields into the order you want them via the "Manage Fields" page for a given content type in that content type's Manage Fields page.
    This is only a global solution for your site, and you don't really have a way to sort fields in different contexts. Your node template gives you $content which prints out all the fields associated with that node. While this works just fine for simple sites, what happens when you want the fields to display in different orders when seen in different situations? In Drupal 6, if you want your node to display its fields in a certain order for the "full" node version, but in a different order for its teaser version, then you're out of luck (without writing custom code or perhaps using a contrib module for that functionality).
  2. Print fields out directly.
    If you want to print out certain fields, you've been able to search the $node object for the particular field you want and print it directly, getting around having to use $content altogether. An example of that would be <?php print $node->content['field_myfieldname']['#value']; ?>

In Drupal 7, you can sort fields for both the "default" and "teaser" formats, among others, from the content type's "Manage Display" page. However, be aware that if you rearrange your fields in the manner, it also affects the order of the fields shown on your node's "edit" form (a tip of the hat to commenter Matthias for making this point). If you want to order your fields in a way that the "Manage Display" page won't allow you to... or if you don't want your node edit form mangled, you can take your node's $content and print things however you want (or conversely, NOT print things) from within the template, so you never have to mess with the content's "Manage Display" page, or break apart $node. For this approach, we have two new functions available to us:

  • hide()
    Now you can use, for example, <?php hide($content['links']); ?> at any point before the content gets printed and those parts of the $content will not be rendered with everything else.
  • render()
    So you've decided which fields/parts of $content you don't want in the big old chunk of $content, and now you use <?php print render($content); ?> to print the rest. Everything that wasn't first hidden with hide() will now be printed out. You can then use <?php print render($content['links']); ?> to print what you originally hid in $content.

Of course, if you can sort your fields the way you want them using the admin pages for your content type, you should probably do that before adding unnecessary code to your node templates or preprocess functions.

Say goodbye to .clear-block

The Drupally way of clearing floats within container elements was the .clear-block class. In Drupal 7, this class has been renamed to .clearfix. This seems to be a little more descriptive of the point of the fix in the first place, and does less to confuse beginners with Drupal's "block" system which is unrelated.

Hiding stuff

Special standard classes to identify elements as hidden have been added to core CSS:

.element-hidden is for hiding things on page load, and it can be used in junction with jQuery's .show() and .hide() to toggle something as hidden or not. An example of usage of this class attribute would be to put it on a dropdown menu (<div> or <ul>, or whatever floats your boat) that only displays when its parent main menu item has been hovered on.

.element-invisible is for elements you want permanently hidden (but still viewed on screen readers for accessibility reasons). If you ever do any image/text replacement work, you can probably see how this will be useful.

Form overrides

When I first got started with Drupal, I found it particularly difficult as a themer with beginner's PHP skills trying to figure out how to take a form and make modifications: re-order fields, change labels, remove fields, add markup... that kind of thing. Eventually you learn that form overrides can be done in a custom module using hook_form_alter(), or by using hook_theme() in template.php to establish a form override function and do your magic there. As a themer, in most cases, your form changes don't fundamentally change how the form's functionality works, and you usually do your form override in template.php.

Well, now hook_form_alter() is available for use in the theme layer. This means you don't have to go through hook_theme() anymore and you can just jump in and modify whatever for you want using the $form_id that comes in as an argument via hook_form_alter() and hook_form_FORM_ID_alter():

For example, to add a new "search-field" class to your search block's text field, you would simply drop the following into your theme's template.php:

function yourtheme_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'search_block_form') {
      $form['search_block_form']['#attributes']['class'][] = 'search-field';
  }
}

As you can see, we're checking for $form_id to do these overrides on a case-by-case basis. You can add more IF statements to this function to other overrides for different forms. Alternatively, you can use hook_form_FORM_ID_alter() to break your forms into separate functions, like this:

function yourtheme_form_search_block_form_alter(&$form, &$form_state, $form_id) {
      $form['search_block_form']['#attributes']['class'][] = 'search-field';
}

So, form overrides are a little bit easier and simpler in Drupal 7.

In related news, fellow Advomatic developer Aaron Winborn discovered today that ALL _alter functions are now available to the theme layer in D7 (currently happening in the middle of drupal_alter() if you're curious). This allows for things like hook_js_alter() or hook_css_alter() in themes, which some of you may find useful.

Thanks for reading, and stay tuned for part two.

May 03 2011
May 03
Webcam Magic!

Here is a recipe for the holy grail of video handling on your server: recording a video with a webcam from the browser, upload it to YouTube, and embed it on your site, all with one magic click. This technique is currently only possible with Drupal 6, although support for Drupal 7 should be ready soon, and should be even easier with the tools available there.

Here are some shortcuts to the relevant sections of this post:

Besides Media: Webcam, which will interface the browser with users’ webcams, the modules we’ll use for this functionality include CCK for attaching fields to content types and FileField, which can be used to store image snapshots (along with ImageField), as well as the recorded videos if you want to serve them locally and skip the YouTube options. We’ll also need Media Mover to pass our recorded files around, if we’re not serving them locally. This module will work in conjunction with Embedded Media Field and Media: YouTube to send and receive the video for storage with YouTube.

Next up, we’ll need to install Red5 on our server, which is an Open Source package that we’ll use for streaming video in conjunction with Flash. It’s a free alternative to Adobe’s Flash Media Server, and is capable of much more than the simple job we’re tasking it with. Unfortunately, installation of Red5 is not easy or intuitive, and might be a hurdle if your hosting provider doesn’t offer it or allow you shell access to install it yourself. More on that later.

Let’s do the easy steps first. You won’t need Red5 for this first example, which will allow users to create snapshots with their webcam. After installing the contributed modules on your local Drupal 6 installation (see the handbook if you need help setting this up), go to admin/build/modules and enable Content (CCK), FileField, ImageField, and Media: Webcam.

Now we’ll set up a field to gather and store our snapshots. You can either set up a new content type, or use the default Story type. For the second option, simply navigate to admin/content/node-types/story/fields and add a new field, which we’ll call Webcam for this example. The type will be File, and in the last selector for the form element, we’ll choose Webcam Image & Video Capture.

Add snapshot field

On the resultant page, check the Allow snapshot box and submit, and you’re set! Now add a node, at node/add/story, and watch the magic happen...

Flash permission

Note that you’ll likely want to change the display settings for the field. As it’s an ImageField at heart, you’ll have access to all the usual display formatters, including for ImageCache if installed. Simply navigate to admin/content/types/story/display and select the format to display for Teasers and Full nodes.

Webcam node

Before we can add video capability, we need to set up our Red5 server.

Once you’ve gotten Red5 installed, you’ll need to copy the application file at /sites/all/modules/media_webcam/src/red5/media_webcam/dist/media_webcam.war to the webapps folder of your Red5 installation, for instance at C:\Program Files\Red5\webapps. Then you’ll either restart Red5 (from the Services window of the Administrative Tools of Windows Control Panel) or wait about 10 minutes, and it will automatically deploy.

Now we’ll configure Drupal to interface with Red5, by going to admin/settings/media_webcam. Here you can set the global width and height for the recorder on this page as well.

Settings

The Connect URL will be the address to access the Red5 server application, in our case at rtmp://localhost/media_webcam. Note that by default Drupal uses rtmp://localhost/oflaDemo, which is a demo application packaged with Red5. That would work, but you most likely will want to use the application packaged with the module above rather than leaving a demo on your production server.

You can leave the Base filename alone; this simply determines how final files will be named. You can change it if desired -- the final names will have a randomly timestamp-derived numbers appended, with a .flv extension.

Next you’ll want to set the folder where videos will be uploaded, in the Upload folder textfield. Note again that the default is set to the oflaDemo folder; you’ll want to change this to the location where you’ll find the media_webcam Red5 server application. For Windows, that will likely be at C:\Program Files\Red5\webapps\media_webcam\streams.

You can leave the File directory alone, unless you want to change the location in Drupal’s file system where the final video will be moved to.

Finally, you can set the Maximum duration allowed for webcam uploads. By default, it’s set to 10 minutes, or 600 seconds.

Field settings

After submitting your settings changes, you’ll need to go back to the field settings at admin/content/types/story/fields/field_webcam and check the Allow video box. After submitting that, it should be good to test, by adding another Story node.

If you want to host your videos locally, then you’re all set! All you would need to do would be to set up a Flash player for display. There are many ways to do this; for a quick set-up, I suggest using jQuery Media with Longtail.

For integration with YouTube, we’re going to have to do some more setup. Firstly, you’ll need an account to accept uploads from YouTube. You’ll also need to apply for a developer API key.

On the Drupal side, you’ll need to install Media Mover, Embedded Media Field (with its included Embedded Video Field), and Media: YouTube. You’ll also need to enable the Media Mover CCK and Media Mover Emfield modules, which are packaged with Media Mover. Finally, you’ll need to install the latest release of the Zend Framework library at /sites/all/libraries.

Browse to the Media: YouTube Administration screen at admin/settings/media_youtube, where you’ll need to set the developer key. You’ll also need to add your YouTube username and password, which the module will need to send video uploads.

We’ll also need to add an Embedded Video field to the Story content type, with default settings. You can do that at admin/content/node-types/story/fields like you did with the Webcam field.

YouTube field

Next, you’ll add a new Media Mover configuration at admin/build/media_mover/add. Media Mover configurations allow you to harvest, process, and store files. For the Harvest Configuration, we’ll select the Webcam field of the Story content type. Additionally, we’ll need to set the file type from its default to flv, which is the format created by the Flash.

Harvest

For processing, we’ll simply set it to upload the video to YouTube. You’ll also need to select a YouTube category.

Process

Finally, we’ll configure the Storage to save the resultant video in the Embedded Video field we set up.

Storage

That’s it. When you next record a video from the webcam in the browser when you add a new story, it will work automatically. Note that we’ve currently set things up to run on cron, so you might need to hit cron.php to get your video working. If you want, you can enable the Media Mover Auto Run module (packaged with Media Mover), and configure your process to run when you submit the node, rather than waiting for cron. You would do this at admin/build/media_mover/settings/mm_auto_run.

That’s it! Here are a short list of potential gotchas:

  • Make sure to use a version of Media Mover later than 6.x-1.0-beta9 if available, or at least 6.x-1.x-dev, due to a known issue that will block things.
  • If you get an error like Cannot authenticate. Error: Unable to Connect to ssl://www.google.com:443. Error #76170016: Unable to find the socket transport "ssl" - did you forget to enable it when you configured PHP? then you need to enable SSL on Apache and PHP. For WAMP, you can do this by clicking on the WAMP Server tray icon and enabling the SSL modules for each service (Apache > Apache Modules > ssl_module, and PHP > PHP Extensions > php_openssl).
  • If you get an error like Upload failed. Error: Expected response code 200, got 400 yt:validationinvalid_valuemedia:group/media:category[@scheme='http://gdata.youtube.com/schemas/2007/categories.cat']/text(), then make sure that you’re using a valid YouTube category. You can see those categories if you open up the reference file (at http://gdata.youtube.com/schemas/2007/categories.cat); they’re like atom:category term='Music' and usually capitalized.

Also note that the buttons on the recorder are built with CSS, so you can replace them with your own images.

Aaron is currently writing Drupal 7 Media, to be published by Packt Publishing later this year!

Mar 25 2011
Mar 25

"Drupal sites can look any way you want!" Heard this before? While technically true, it doesn’t mean it’s always the best option. If you are a graphic designer creating comps (compositions) for a Drupal site, here are a few DOs and DON'Ts to follow. Not only can they make theme developers happy, but also they can speed production, saving the client money in the long run. Of course, some of these tips will apply to web design in general, not just for Drupal sites.

Note that there are a few key words that keep popping up throughout: reuse, flexibility and standardization. These are great guides for the design process.

sprite exampleDO Use reusable graphical elements. This may seem like common sense, but sometimes designers will resize design elements (buttons, icons, arrows, custom bullets, etc.) depending on the page, or use different colors depending on the section. Standardize them as much as possible. Themers appreciate being able to gang small, repeatable elements on a sprite and reusing them when needed. If an element appears on a variety of backgrounds, make sure the element is on a separate layer so it can be used on a sprite with transparency. Check out Jack’s post on sprites for more information about why they are useful for shrinking website load time.

DON'T use Photoshop tricks that won’t work on the web. Just because Adobe can do it, it doesn’t mean you can do it on the web. For example, dynamic color overlays with special filters (multiply, color burn, etc.) can’t be reproduced accurately on the web – one can only apply opacity with a transparent PNG or --in some browsers -- with a percentage in CSS.

There are some things you can do in Photoshop that are certainly possible with CSS, but may take a lot of time to implement properly. If you are using a fancy menu with background images and hover states, consider what might create problems when the menu is sliced.

For instance, in the example below, the length of menu item names are not flexible (it is possible – but would require some special techniques with several background images and extra divs.) Also, the hover state is problematic because of the overlap at the top and bottom on the neighboring button. Same principle: it can always be done, but it will take some time.
menu example

DO consider using a grid. In the interest of full disclosure, I don’t always use a grid to design. Sometimes it isn’t necessary on a small site. However, using a standard grid dovetails nicely with the principles of Drupal: reusability, flexibility and standardization. Choosing a grid and sticking with it can help make your site visually appealing to users and give a uniformity to the layout that can save time. That means the template can be set up quickly, and won’t need to be fussed with later – no need for lots of variations.
grid example
Grid example from Chapter Three's Fireworks Drupal design template

If you have a grid as the bottom layer of your PSD, AI or PNG file, you can toggle it on and off as needed, and then pass it along to your theme developer who can use the dimensions to build out the theme, perhaps using a grid base theme, like Zen nineSixty or Blueprint.

DON’T forget to configure your color settings properly in Photoshop or Illustrator. Sometimes when saving out slices for the web, there will be a slight – or dramatic – color shift if your settings are not correct. Photoshop and Illustrator are "color-managed" software, which means you can set apply different setting for different uses: for print, for photos, for the web, etc. There are a few schools of thought on ensuring that colors don’t shift when you save for web, but otherwise, my preferred choice is to simply build comps with non-color managed software: Fireworks.

DO familiarize yourself with Drupal forms. Out of the box, Drupal comes with several forms that a designer might be tempted to redesign: the log-in form, node add forms, contact form, comments forms, etc. While it can be done, sometimes overriding how a Drupal form is structured can be tedious and time-consuming. For time sensitive projects, limit design changes to Drupal forms to CSS only. Consider keeping the language, the order of fields, and markup needed. Of course, this can be hard to anticipate, but familiarizing yourself with how to forms are structured can help.

Also, some forms elements can be notoriously hard to manipulate. Often, the image upload field and dropdown selects require using javascript to style. While there are some good options out there (like Uniform), choosing to leave them as-is will save time and money. See my blog post on 10 Tips for Theming Drupal 6 Forms.

DON’T ignore elements that ALWAYS need theming in Drupal. Sometimes it is easy to design for what you need, but ignore what Drupal automatically gives you. Here’s a nice checklist that was compiled by Chapter Three of elements that are present in 90% of Drupal sites:

• Header
• Footer
• H1 - H5
• Body
• Link
• Unordered List
• Blockquote
• Code
• Admin Tabs (secondary tabs)
• Collapsable Field Sets
• Block Headers
• Block Typography
• More button
• Submit Button or general button style
• Input Field
• Tags
• Pagination
• Basic Node Style
• Table Style
• Error Message
• Status Message
• Warning Message
• Help Message
• Default Profile Layout
• Blog title and Byline
• Breadcrumbs
• Error Message
• Status Message
• Warning Message
• Help Message
• Secondary tabs

This list is from an incredibly useful blog post for using their customized Drupal templates to begin the design process. This can help you remember all the out-of-the-box elements. It is worth downloading the templates and reviewing them before your designs are set in stone.

DO think about how content is displayed by default in Drupal. There are certain things that are harder to do with content than others. For example, one thing that can be tough is splitting one node’s content into different regions – like putting the author’s name in the sidebar, for example. Of course, it CAN be done – but it takes some work.

DON'T use styles that vary wildly page to page. This is a similar idea to some other points above. But it may help (if your project is on a budget) to remember that Drupal is built with a series of templates, and the more continuity you build in to page elements, the faster it can be themed. For instance, if you create a bunch of sidebar blocks that all look completely unique, each one could take an hour or more to style. However, if they all have common styles, development time will drastically be reduced.

One nice Drupal tool for allowing content creators choose from a set selection of styles for blocks, nodes and other content areas is the Skinr module. Check out what it does and think about how it could be used with your design.

DO look at jQuery. Even if you are on a budget, there are some pretty tricks that can be easily added to a Drupal site. For instance, a Views Slideshow or jCarousel is requested on many website front pages – and it isn’t very hard to implement and style (usually!) Accordions, tabs and sliders are other things that may add something special without too much time and money spent. Check out jQuery UI or the jQuery plugins page for more ideas.
jquery example

fireworks exampleDON’T dismiss Adobe Fireworks! I’ve hinted at this in other tips, but the oft-overlooked Fireworks is the best tool I’ve found for creating web design comps. Fireworks creates vector based, multipage documents perfect for storing and duplicating elements and templates. Not only can you have a document that contains all of your comps, but a panel for "states" on each page (instead of the dreaded hidden layers) is very useful, as is the library for reused elements and symbols. (You can save an element as a symbol, and whenever you edit the symbol, it will change wherever it is used, just like in Flash.) Obviously, you may choose a different application for making a logo or other graphics for the site, or preparing photos. Master pages (much beloved in print layout programs like InDesign) is also a huge time saver.

Jun 02 2010
Jun 02

A common question I get for theming Drupal sites is how to apply css to specific pages. For example, you might want your background image for your header to change on specific pages. Out of the box, Drupal doesn't give you any class in the HTML that's unique to your node to grab onto. This is where $body_classes come in.

Drupal 6 introduced the $body_classes variable to dynamically include certain information about the page you are on as a class of your body tag. These include:

- .no-sidebar/.one-sidebar/.two-sidebars
- .sidebar-left/.sidebar-right
- .front/.not-front
- .logged-in/.not-logged-in
- .page-[PAGE TYPE]
- .node-type-[CONTENT TYPE]

Some starter themes, like Zen, come with the $body_classes variable already in place. If you are building your theme from scratch or using a theme that doesn't have it, you'll need to add it in.

To add $body_classes to your theme, open your page.tpl.php file, and find your body tag. Edit it to be: <body class="<?php print $body_classes ?>">. Now, when you check your HTML, your body tag should look something like this:

<body class="not-front logged-in page-node node-type-forum one-sidebar sidebar-right">

You can probably see how these will give someone building a theme good stuff to work with. However, sometimes this isn't enough; sometimes you need node-specific classes. With Drupal 6, you can use a preprocess_page function to add on to your $body_classes variable.

First, you will need to create a function that properly takes your URL and converts it to a class (you don't want any space, capitals or irregular characters). Open your template.php file and add the following function:

<?php
/**
* Converts a string to a suitable html ID attribute.
*
* <a href="http://www.w3.org/TR/html4/struct/global.html#h-7.5.2" title="http://www.w3.org/TR/html4/struct/global.html#h-7.5.2" rel="nofollow">http://www.w3.org/TR/html4/struct/global.html#h-7.5.2</a> specifies what makes a
* valid ID attribute in HTML. This function:
*
* - Ensure an ID starts with an alpha character by optionally adding an 'id'.
* - Replaces any character except A-Z, numbers, and underscores with dashes.
* - Converts entire string to lowercase.
*
* @param $string
*   The string
* @return
*   The converted string
*/
function YOURTHEME_id_safe($string) {
 
// Replace with dashes anything that isn't A-Z, numbers, dashes, or underscores.
 
$string = strtolower(preg_replace('/[^a-zA-Z0-9_-]+/', '-', $string));
 
// If the first character is not a-z, add 'n' in front.
 
if (!ctype_lower($string{0})) { // Don't use ctype_alpha since its locale aware.
   
$string = 'id' . $string;
  }
  return
$string;
}
?>

This is reusable code - use it anywhere you need to convert a string into an id.

Next, search for a section that starts with YOURTHEME_preprocess_page. If you don't have one, just add in this code anywhere in the file:

<?php
/**
* Intercept page template variables
*
* @param $vars
*   A sequential array of variables passed to the theme function.
*/
function YOURTHEME_preprocess_page(&$vars) {

  if (!

$vars['is_front']) {
   
// Add unique classes for each page and website section
   
$path = drupal_get_path_alias($_GET['q']);
    list(
$section, ) = explode('/', $path, 2);
   
$vars['body_classes'] .= ' ' . YOURTHEME_id_safe('page-' . $path) . ' ';
   
$vars['body_classes'] .= ' ' . YOURTHEME_id_safe('section-' . $section) . ' ';
  }
}
?>

Otherwise, you will need to merge this code into the preprocess_page function.

This code gives you two new classes: page-PATH and section-SECTION. It might look something like: <body class="not-front logged-in page-node node-type-forum one-sidebar sidebar-right page-about-history section-about">. The page-PATH class displays the full url path, and the section is just the first arg in the path - enabling you to do some section-based theming, if your URLs are all segmented properly.

The final trick is to add your taxonomy terms to $body_classes. After the new section in your preprocess_page function where you turn urls into your $body_classes, add this snippet:

<?php
if (isset($vars['node']->taxonomy)) {
 
// Add unique classes based on taxonomy terms
 
$taxonomy_classes = array();
  foreach(
$vars['node']->taxonomy as $term_info) {
   
$taxonomy_classes[] = 'taxonomy-'.YOURTHEME_id_safe($term_info->name);
  }
 
$vars['body_classes'] .= " ".implode(' ', $taxonomy_classes); // Concatenate with spaces
}
?>

This will add a class to your body tag that looks like taxonomy-YOURTAG. All together, your preprocess_page function might look like this:

<?php
/**
* Intercept page template variables
*
* @param $vars
*   A sequential array of variables passed to the theme function.
*/
function YOURTHEME_preprocess_page(&$vars) {

  if (!

$vars['is_front']) {
   
// Add unique classes for each page and website section
   
$path = drupal_get_path_alias($_GET['q']);
    list(
$section, ) = explode('/', $path, 2);
   
$vars['body_classes'] .= ' ' . YOURTHEME_id_safe('page-' . $path) . ' ';
   
$vars['body_classes'] .= ' ' . YOURTHEME_id_safe('section-' . $section) . ' ';
  }
 
  if (isset(
$vars['node']->taxonomy)) {
   
// Add unique classes based on taxonomy terms
   
$taxonomy_classes = array();
    foreach(
$vars['node']->taxonomy as $term_info) {
     
$taxonomy_classes[] = 'taxonomy-'.YOURTHEME_id_safe($term_info->name);
    }
   
$vars['body_classes'] .= " ".implode(' ', $taxonomy_classes); // Concatenate with spaces
 
}
}
?>

Armed with those $body_classes, there is very little page- and section-specific CSS targeting you can't do!

May 18 2010
May 18

     In the last few years, the term “cloud computing” has become the ubiquitous new buzz-word to toss around when talking about flexible, scalable hosting solutions. Unfortunately, as often happens when a new concept is introduced to a large market, it is often misunderstood; the benefits and drawbacks are misrepresented (intentionally or not).

A recent schematic of 'The Cloud'     The original concept of cloud computing was a utility-like service that would provide a pool of shared resources for clients to use on-demand – thereby allowing customers to leverage a large pool of resources without having to bear the burden of the capital cost of building or maintaining the entire infrastructure themselves. In the web hosting world what we refer to as “cloud computing” sometimes aligns with this original concept, sometimes not so much, depending on the service in question.

     In this post, we hope to remove some of the mystery around cloud computing as it relates to web hosting services; pull back the curtain a bit and explain what is actually happening inside that misty and illusory “cloud”.

Virtualization and The Cloud
     All cloud products that are offered as a web hosting service have one thing in common: they are virtualized. "Virtualized" means that your “server” (whether called an “instance”, “slice” or something else by your service provider) is actually a virtualized operating system (kernel) that is referred to as a “virtual machine”, or VM. The VM is running inside a “container” system, which is in charge of managing the resources of multiple VMs running alongside yours. There are several products that do this, some of which you may be familiar with – some of the more well known products out there are VmWare, VirtualBox, and XEN.

Although all cloud products are virtualized, not all virtualized hosting services are cloud services. What distinguishes the two is:

  • the ability to scale dynamically
  • adding or removing resources can be controlled by the customer through an API
  • have the utilized resources billed out by some small increment, such as by the hour or day (although some providers do have larger billable increments, such as week or months)

This flexibility is generally considered to be the largest advantage of a cloud product over your more standard virtualized private server, it allows you to dial up and down resources, on-demand and as-needed, without having to commit to a lot of hardware that comes with a bunch of unused overhead during non-peak hours.

The team said my post needed more pictures, so, eh, here is a guy 'Virtualizing'     Once you are on a virtualized platform, your “server" becomes platform agnostic. It is now a VM. This means that it will run anywhere the “container” will run. It doesn't matter what the hardware is. This means that (compared to an operating system installed directly on some hardware) its trivially easy to move your VM from one container to another – from server to server, or even from datacenter to datacenter. The various virtualization technologies have different ways to do this, with different requirements, but they almost all have some way to “migrate” a VM from one host to another. Here is where an important distinction between virtualized private server (or “VPS”) services and cloud services comes into play.

Under the Hood
     In order for cloud services to be able to scale in an elastic fashion, they must use some sort of network attached storage. Network attached storage is pretty much what it sounds like - a physical disk storage system that connects to a server over a network. In the case of the cloud, your VM runs on a server which provides the "brain", the RAM/CPUs and other hardware necessary for the operating system to run and connect to the Internet. But instead of having hard drives inside that same server, the storage is on a networked storage solution that is connected to the server running your VM (in many cases just using your standard Ethernet interface and switching gear).

     Having network based storage is generally a requirement for any type of “hot migration”, that is, moving a VM from one server to another very seamlessly. In this configuration, using XEN for instance, you can migrate a running VM from one server to another without even a reboot. This is useful when you need to allocate more ram or CPU cores to a VM that is on a server that is fully utilized (by migrating to a server with more resources available), or if a server has some hardware failure and needs maintenance all the VMs on it can be migrated with minimal interruption.

More Ins and Outs

Image of an actual I/O bottleneck in the cloud, taken by electron microscope and artificially colorized by photoshop.     There are several drawbacks to using network attached storage, the primary one being I/O. I/O, very simply, is the rate at which data can be transferred “In” and “Out” of a device. There are various kinds of I/O that affect performance in various ways, but in this case we are talking about disc I/O. There are several types of network attached storage products out there, but the most popular is iSCSI, which is basically SCSI over Ethernet. This means that if you are running Gigabit Ethernet, you have 1,000 Mbit/s of I/O. Serial attached SCSI (SAS) drives put you at 4,800 Mbit/s - in a RAID configuration, you can get much more than that. If you are running 10 Gigabit Ethernet, you have 10,000 Mbit/s.

     Comparing I/O rates between devices and standards is never an apples to apples comparison, because it completely depends on the hardware and network configuration - for example it doesn't matter if you've spent all your money on a 10GbE network if you have connected an 8 servers with 8 CPU cores to one 10GbE network connection - you are now sharing that connection with potentially 64 CPU cores - that many cores could easily saturate your expensive 10GbE network several times over. Now, of course, even if each server had a dedicated direct attached SCSI array you could still saturate your disk I/O, but you would have much more overhead to play with, and you could more easily dedicate resources to a specific VM or set of VMs.

     As always, there are some exceptions to the rule, but as of right now, most cloud products will not give you as much I/O as you can get out of dedicated direct attached storage. I/O is not everything, but this is one potential bottleneck.

Keep it down over there! - or - Noisy Neighbors
These crazy kids up all night saturating my network     Perhaps more important than raw I/O, is the fact that cloud products (and shared VPS services for that matter), are based on shared resources. This is great when you don't want to pay for all the resources you have access to all the time, but what happens when someone sharing the same resources as you maxes them out? Your service suffers. If they saturate the network your storage is on, your service can suffer *a lot*. For disk I/O intensive applications (like Drupal) this can mean slow, frustrating death. This is true not only for shared network resources, but for shared CPU cores (you can't share RAM for technical reasons, so at least you are safe there). If you have someone sharing the same resources as you, and they use more than their "fair share", your service will be impacted. This is called having “Noisy Neighbors”. Some people mitigate this by rebooting their VM, hoping they boot back up on a less resource-bound server. Some just wait it out. Many just watch the low load numbers on their VM, and puzzle over the lackluster performance.

What should I do?!?
     Decisions about what type of hosting service to use depends on your particular situation. In most cases, we always say “proof is in the pudding” - if the service you are on is making you happy, and the price is sustainable, then stay there for goodness sake! But if you experience performance problems on a budget hosting or cloud service that are causing you to lose money or traffic, maybe its time to look at a dedicated server environment.

     Drupal, especially with the default database-based cache enabled, can be particularly I/O heavy on the database. Many cloud providers offer a hybrid model, where you can have virtualized cloud servers that connect to external non-virtualized hardware with direct attached storage. This is a great solution if you can afford it – it allows you to put your database server on dedicated hardware, but keep your web servers on a more flexible solution.

     If you can't afford that, then look at Drupal performance solutions like Pressflow or Mercury. If thats not an option, then the next stop may be a VPS with direct attached disks and dedicated resources.

     If you feel like you are having I/O or “Noisy Neighbor” issues, check if you are on a “shared” resource plan, ask your provider what type of infrastructure they are using and if its saturated. If they won't tell you, and you continue to have problems, its probably time to start looking for another provider.

Next up: Caching and Drupal – examining apc, varnish, boost, memcache, and content delivery networks, and how they work together.

Related resources

May 10 2010
May 10

In environments where there are many databases running on the same machine (ex. shared hosting), or in high traffic environments (ex. enterprise sites) it is a common problem that unterminated connections to the database linger around indefinitely until MySQL starts spitting out the "Too many connections" error. The fix for this is decrease the wait_timeout from the default 8hrs to something more in the range of 1-3 minutes. Make this change in your my.cnf file. This means that the MySQL server will terminate any connections that have been sitting around doing nothing for 1-3 minutes.

But this can lead to problems on the other side where now MySQL is terminating connections that are just idle, but will be called on to do something. This results in the "MySQL has gone away" error. This problem is unlikely to happen with stock Drupal, but is much more frequent with CiviCRM (or any other time where you connect to more than one database). The issue being that sometimes an intensive process will happen in one database, then action needs to return to the other database, but oops MySQL has terminated that connection. This is most likely to happen on anything that takes a long time like cron, contact imports, deduping, etc.

There's a little known trick with changing wait_timeout on the fly. You can do this because wait_timeout is both a global and per-session variable. Meaning each connection uses the global wait_timeout value, but can be changed at any time affecting only the current connection. You can use this little function to do this:

<?php
/**
* Increase the MySQL wait_timeout.
*
* Use this if you are running into "MySQL has gone away" errors.  These can happen especially
* during cron and anything else that takes more than 90 seconds.
*/
function my_module_wait_timeout() {
  global
$db_type, $db_url;
 
 
watchdog('my_module', 'Increasing MySQL wait timeout.', array(), WATCHDOG_INFO);
  if (
is_array($db_url)) {
   
$current_db = db_set_active();
    foreach (
$db_url as $db => $connection_string) {
     
db_set_active($db);
     
db_query('SET SESSION wait_timeout = 900');
    }
    if (
$current_db) {
     
db_set_active($current_db);
    }
  }
  else {
   
db_query('SET SESSION wait_timeout = 900');
  }
 
  if (
module_exists('civicrm')) {
   
civicrm_initialize();
    require_once(
'CRM/Core/DAO.php');
   
CRM_Core_DAO::executeQuery('SET SESSION wait_timeout = 900', CRM_Core_DAO::$_nullArray);
  }

}

?>

Then call this function before anything that might take a long time begins.

There's also an issue in the CiviCRM issue queue to make CiviCRM do this before any of it's long internal operations.

About Drupal Sun

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

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

See the blog post at Evolving Web

Evolving Web