You are hereDrupal

Drupal


#D7CX - Off to strong start

#D7CX is a new movement in Drupal. It stands for Drupal 7 Contrib Experience. 95 module maintainers have pledged that their modules will be released by the time Drupal 7 is released. To join the movement or learn more, see the #D7CX announcement blog post.

I’m so excited about the uptake on #D7CX. 95 modules is is an amazing number. Check out this link which sorts by usage activity. 10 out of the top 20 modules are on board already. #D7CX is all about the minor modules too. Please join the movement even if your module only has a handful of active sites.

We are now just two weeks before code freeze for Drupal 7. It would be great if a few more some more heroic module maintainers did preliminary upgrades right now. That way, we can make significant changes to D7 if its API is found lacking or inconsistent.

Even if you can’t start today, I encourage folks to join a code sprint in order to port your modules in a fun, collaborative atmosphere. Both code sprints at Drupalcon Paris will heavily feature #D7CX upgrading. In addition, NowPublic is hosting a #D7CX sprint on October 17 in Vancouver. I know that I will be hosting sprints at MIT in Cambridge during September/October. I’m looking forward to seeing more such sprints around the world.

Drupal 7 has been 2 years in the making and represents a massive improvement in almost all aspects of Drupal. I really think it will establish Drupal as the default choice for content management. #D7CX is an important part of that goal. We help make the launch story strong. We help assure good reviews in the crucial early months. We help assure a fast, steady stream of new and upgraded sites on Drupal 7. These are fun times.

Ode to the drupalchix ...

I woke up this morning and had to re-watch the Coder Girl music video. It is that good. This post is dedicated to all the Drupalchix out there.

It always leads to an overflow, when it's runtime and we take it slow ...

Praise for Open Atrium

Open Atrium is the finest piece of Drupal art that I have ever seen.

In my 7 years of Drupal, I can’t think of a tighter innovation than this. If Open Atrium is Intranet in a Box, I’ll call this week’s Appollo 11 anniversary 3 men in a beaker.

A few high points ...

Drupal 7 rendering. Roles and responsibilities

I have lots to say about the awesome new page rendering in Drupal 7. For now, I want to clarify the design. The meaning of some familiar features has changed:

  • Regions. Regions are promises made by a theme: “I will print whatever you put into these part of the $page array.”
  • Hook_block(). A modules uses this to make pre-packaged hunks of content available to the CMS
  • Block module. An optional UI where admin populates regions with blocks
  • $page array. See graphic below. $page gets built up during a page request. At the top level of the array we find each region. Within each region we find renderable arrays that often correspond to blocks. After page building is complete, core calls drupal_render($page). We theme each element of the array until we finally get to page.tpl.php
  • Hook_page_alter(). A chance for the site builder to change almost anything about the $page before it is rendered. Populating regions is perfectly reasonable here (e.g. toolbar module). Thats what block.module does.
  • Preprocess layer. A useful place to make minor tweaks to variables before they are printed in templates. Core should not call drupal_render() here. Core should strive to remove all drupal_render() calls from Drupal except drupal_render_page() and render() in templates (e.g. node.tpl.php).

Here is the $page array from current HEAD:

Launching the D7CX movement ... and a Contrib Release Manager

Update: #D7CX pledges are for all, not just top 40 module maintainers. all modules should pledge. non maintainers pledge help w/ docs, QA. there is a pledge for everyone.

Drupal 7 is going to be a phenomenal release. The code is miles ahead of Drupal 6, and the D7UX work is poised to bring us a giant leap forward. I really think we are going to make a major difference in CMS land and in the world in general with this release.

#D7CX

In order to make the biggest possible impact, we need most of the top 40 Contrib modules to have full Drupal7 releases on the day when core Drupal 7 is released. Our failure to accomplish this for Drupal 6 was devastating. So, let's turn our attention toward #D7CX - Drupal 7 Contrib Experience.

I want to collect pledges from maintainers to support the #D7CX effort. A pledge consists of writing a statement like below at the top of your project page on drupal.org. Here are my three pledges ...

Highlights from Design 4 Drupal

I am so happy that I attended much of Design 4 Drupal this past weekend. I think it was a watershed event for Drupal’s design and themer communities.

Markup freaks

There were quite a lot of people who expressed frustration with Drupal’s markup. I got an earful from #danigrrl before I even picked up my badge. She said

My site has a testimonial section. To do that, I create a View called testimonial and configure it to show as a block. I want that block to have an HTML id of #testimonial. I don't want #block-views-testimonial. And I definately don't want a truckload of classes added everywhere.

I decided to take a look. Here markup from a Views block that Organic Groups module offers. The block is a list containing two usernames.

<div class="first block left-region views-block odd clear-block" id="block-views-og_members_block-block_1">
          <h2>Recent members</h2>
          <div class="block-content">
            <div class="view view-og-members-block view-id-og_members_block view-display-id-block_1 view-dom-id-1">
              <div class="view-content">
                <div class="item-list">
                  <ul>
                    <li class="views-row-1 views-row-odd views-row-first">
                      <div class="views-field-picture">
                        <div class="picture"></div>
                      </div>
                      <span class="views-field-name">
                        <span class="field-content"><a href="/pr6og/user/1">weitzman</a></span>
                      </span>
                    </li>
                    <li class="views-row-2 views-row-even views-row-last">
                      <div class="views-field-picture">
                        <div class="picture"></div>
                      </div>
                      <span class="views-field-name">
                        <span class="field-content"><a href="/pr6og/user/3">amy</a></span>
                      </span>
                    </li>
                  </ul>
                </div>
              </div>
            </div>
          </div>;

The traditional answer to this complaint of “classitis” can be summed up as - “tough shit”. That ‘views’ prefix that appears everywhere is a namespacing issue which has solid justification. But I’m slowly, possibly changing my mind on this. The markup freaks greatly value economy in their HTML and CSS. They can’t stand any non-essential bits. Drupal developers are like this too. Code patches get rejected because of extra whitespace for goodness sake. Einstein might have been talking about markup freaks when he said Everything should be made as simple as possible, but no simpler.

Granted, id=block-views-testimonial is only a tiny bit uglier than id=testimonial. But that ugliness gets propogated all over the theme. Your css now references #block-views-testimonial. Multiply that for many blocks and several elements within those blocks and pretty soon you are swimming in block-views prefixes. Furthermore, javascript needs to target these elements so your code becomes less readable too.

Studio theme

Studio is truly innovative base theme. I love how it fully embraces the preprocess layer and base theme inheritance that we added in Drupal6. Studio ships with the usual template files like block, node, page, etc. But the hard coded HTML attributes in the files have been stripped. Compare these two node.tpl.php files.:

STUDIO

<div<?php print $attributes; ?>>

  <?php print $picture ?>

  <?php if (!$page): ?>
<h2 id="_title"><a href="<?php print $node_url ?>" title="<?php print $title ?>"><?php print $title ?></a></h2>
  <?php endif; ?>

  <?php print $submitted ?>

  <?php print $terms ?>

  <?php print $content ?>

  <?php print $links; ?>

</div>

CORE

<div id="node-<?php print $node->nid; ?>" class="node<?php if ($sticky) { print ' sticky'; } ?><?php if (!$status) { print ' node-unpublished'; } ?> clear-block">

<?php print $picture ?>

<?php if (!$page): ?>
<h2 id="_title"><a href="<?php print $node_url ?>" title="<?php print $title ?>"><?php print $title ?></a></h2>
<?php endif; ?>

  <div class="meta">
  <?php if ($submitted): ?>
    <span class="submitted"><?php print $submitted ?></span>
  <?php endif; ?>

  <?php if ($terms): ?>
    <div class="terms terms-inline"><?php print $terms ?></div>
  <?php endif;?>
  </div>

  <div class="content">
    <?php print $content ?>
  </div>

  <?php print $links; ?>
</div>

Instead studio_preprocess() sets them into an $attributes array such as:

<?php
// $Id: preprocess-node.inc,v 1.3 2009/04/20 17:15:17 zarabadoo Exp $

/**
* Implementation of theme_preprocess_HOOK().
* Passes varables to the node templates.
*
* @return $vars
*/
// Prepare the arrays to handle the classes and ids for the node container.
if(!isset($vars['node']->attributes)) {
 
$vars['node_attributes'] = array();
}
else {
 
$vars['node_attributes'] = $vars['node']->attributes;
}

// Add an id to allow the styling of a specific node.
$vars['node_attributes']['id'] = 'node-' . $vars['type'] . '-' . $vars['nid'];

// Add a class to allow styling of nodes of a specific type.
$vars['node_attributes']['class'][] = $vars['type'] . '-ntype';

// Add a class to allow styling based on publish status.
if ($vars['status'] > 0) {
 
$vars['node_attributes']['class'][] = 'published';
}
else {
 
$vars['node_attributes']['class'][] = 'not-published';
}

// Add a class to allow styling based on promotion.
if ($vars['promote'] > 0) {
 
$vars['node_attributes']['class'][] = 'promoted';
}
else {
 
$vars['node_attributes']['class'][] = 'not-promoted';
}

// Add a class to allow styling based on sticky status.
if ($vars['sticky']) {
 
$vars['node_attributes']['class'][] = 'sticky';
}
else {
 
$vars['node_attributes']['class'][] = 'not-sticky';
}

// Add a class to allow styling based on if a node is showing a teaser or the
// whole thing.
if ($vars['teaser']) {
 
$vars['node_attributes']['class'][] = 'teaser-view';
}
else {
 
$vars['node_attributes']['class'][] = 'full-view';
}

// Add a class to allow styling of nodes being viewed by the author of the
// node in question.
if ($vars['uid'] == $vars['user']->uid) {
 
$vars['node_attributes']['class'][] = 'self-posted';
}

// Add a class to allow styling based on the node author.
$vars['node_attributes']['class'][] = 'author-' . strtolower(preg_replace('/[^a-zA-Z0-9-]+/', '-', $vars['node']->name));

// Add a class to allow styling for zebra striping.
$vars['node_attributes']['class'][] = $vars['zebra'];

// Add a class to make the node container self clearing.
$vars['node_attributes']['class'][] = 'clear-block';

// Crunch all the attributes together into a single string to be applied to
// the node container.
$vars['attributes'] = theme('render_attributes', $vars['node_attributes']);
?>

So, if you want a custom id or class, you just set them up in preprocess. The big benefit now is that your hardly ever need to override template files like block.tpl.php. They just emit the attributes which you carefully setup in preprocess. So, we’ve traded proliferation of template files for proliferation of preprocess. I think thats a win, since you likely already deal with preprocess proliferation.

Further, Studio has a great convention for managing preprocess functions. It offers a subdirectory called preprocess where you put small include files. A preprocess function for the theme(‘node’) would is called preprocess-node.inc and it just contains what you would have put in THEMENAME_preprocess_node(). This isolation into small include files helps keeps your template.php nice and small.

Studio can also greatly improve the id and classitis problems I mentioned above. You can simply unset any classes or other HTML attributes in your preprocess function. And its approach to templates is completely compatible with the traditional template files. You can still use the template files from your favorite modules without any changes if you desire. Personally, I’d like to see Studio’s templating philosophy become standard in D7. That might be controversial, so we’ll see if it gets in.

Studio’s authors, Al Steffen and Matt Tucker, have done a terrific job here. For more detail, read their blog post. Thanks for Pingvision for sponsoring this work.

Skinr module

Jacine of Gravitek introduced Skinr module to the world and generated quite some buzz. I missed this session, but have since played with the module on my test site. Skinr’s project description is quite good:

Skinr's main purpose is to allow the theme to define a set of reusable and modular CSS styles, and to make those styles available in Drupal's UI. Skinr was developed for themers to allow them to tap into the power of Drupal's modularity and apply those same principals to theme development. It does not provide any styles of it's own. These styles are defined in the .info file of the theme (or subtheme), by the themer and end up in various places in Drupal's UI, such as:

* Block Configuration
* Node Type (and Comment) Configuration
* Panel Panes
* Views Displays

It also provides a CSS class field, where you can manually add custom classes.

So, all you have to do is add some items to your theme’s .info file and those items appear on the block config form and similar places. Now site admins can choose how to style individual blocks. As their needs vary, the blocks can grow or shrink or change color and so on.

The piece I’m not yet clear on has to do with these modular CSS styles. Perhaps someone could give me some example of css that you might want to make available to block admins. I haven’t done enough style work to instantly see this. Skinr also lets module developers supply these modular CSS styles which sounds quite promising.

Skinr really mixes up the salad bowl. Style selection on the block form really bends my brain. Nice work, Jacine and moonray.

960 theme

960 theme is a Drupal adaptation of 960.gs, a very strong open source project thats getting quick adoption in Drupal circles. It reminds me of the early days of Jquery, where we adopted the upstart library instead of the established players (Prototype, Mootools). That worked out very well, and I have high hopes for 960 and Drupal.

960 helps you lay out your pages. You slice up your page into a grid and 960 does all the math for you. Column based layouts used to be very tricky but I think 960 has finally licked this one. We also heard some about competing grid systems from Blueprint and YUI. Use those if you like them!

Summary

  • The theme community really stepped up this weekend and shared like the open source rock stars that they are.
  • Core developers should be very proud of the enhancements we put into Drupal6. In particular, preprocess, base themes, and rich .info files are in heavy, happy use.
  • A thousand thanks to Susan MacPhee and everyone who organized this great event. Hurrah for the sponsors too.

Update (June 16)

Earl clarifies that the reply to the markup freaks when discussing Views is DON'T USE GENERIC BUILDERS. Hmmm. Is that the final word? Can we add code and documentation that eases the processes of molding generic, verbose markup into terse, personalized output? Lets all think and blog on this topic. Also, it may be news to many that Earl Miles, the author of Views, is also the creator of the preprocess layer and most of the enhancements to themeing in Drupal 6. In other words, he created many of the innovations that we are enjoying.

Cache any element in a drupal_render() array

Below I present a recipe for caching any element within a drupal_render() array. These arrays are even more prevalent in Drupal7 than they were in Drupal6. In fact, the whole page is one big drupal_render() array.

This recipe has huge performance implications. It works for authenticated users. It works when you are running node access modules. It supports custom cache tables and custom expiration rules. I think we can ditch block caching; blocks that want caching will implement this technique (note that blocks can be renderable arrays now in D7). We should probably keep the handy cache key builder that block module has.

The code below is for D7, though it needs minimal changes to run on D6. Surprisingly, this technique is equally valid on D6 as well. The innovation is clever use of #pre_render and #post_render. Drop this code into the root of a drupal site and then visit the page. I am appending some debug text just so it is clear when an element is coming from cache or not.

<?php
define
('DRUPAL_ROOT', getcwd());

include_once
DRUPAL_ROOT . '/includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);


// Imagine that we are building a renderable object like a node or block or page.
$build['bar'] = array('#markup' => 'I am Bar. I don\'t do caching.<br />');
$build['foo'] = array(
 
'#markup' => ' I am Foo.',
 
'#pre_render' => array('drupal_render_cache_get'),
 
'#cache_key' => 'foo:bar:baz', // Think block cache keys. Needs thought.
 
'#cache_table' => 'cache', // Can be a custom cache table.
 
'#cache_expire' => REQUEST_TIME+3600, // Anything that cache_set() supports.
);
print
drupal_render($build);

// Try to retrieve from cache.
function drupal_render_cache_get($elements) {
  if (
$cache = cache_get($elements['#cache_key'], $elements['#cache_table'])) {
   
// Replace everything with what we just successfully retrieved.
   
$elements['#markup'] = $cache->data . ": I was retrieved from cache. <p>To redo this experiment, run DELETE FROM cache WHERE cid='foo:bar:baz';</p>";
  }
  else {
   
// We have a cache miss. Let rendering happen normally. Then cache it.
   
$elements['#post_render'][] = 'drupal_render_cache_set';
  }
  return
$elements;
}

// Cache the rendered HTML. Better luck next time.
function drupal_render_cache_set($children, $elements) {
 
cache_set($elements['#cache_key'], $children, $elements['#cache_table'], $elements['#cache_expire']);
  return
$children . ' I was not retrieved from cache. Next time, I will be.';
}
?>

I was inspired by recent discussions with chx and catch. Kudos also to adrian and eaton and frando who helped drupal_render() rock so much. And many more.

-moshe

Terrific introduction to git

I just finished watching the peepcode screencast on git. It costs US$9, and is worth many times that price. I'm typically not a fan of the screencast format. I find that I can learn the same information faster in text form. Give me a blog post or wiki page and I am happy. But this screencast matched my needs really well. I particularly liked the pace of it. It covered a ton of ground in just 1 hour. I had to pause frequently so I could play around and grok what had been said.

Status of Table Wizard and Migrate modules

Just wanted to give an update on our newly-contributed modules, Table Wizard and Migrate. As I explained at our Drupalcon talk, we have just extracted the source-handling functionality of Migrate as a separate module (Table Wizard), and there's still quite a bit of cleanup to be done. I have just created a dev release for Table Wizard - that is, I think, fairly stable and basically usable as it is now, so those on the bleeding edge can give it a whirl.

Cyrve's big announcement at Drupalcon - Migrate modules go open source

Well, it has been a busy year for Cyrve. I announced the new company just before Drupalcon Boston a year ago. During this year, we took on two big projects worthy of sharing with Drupal Planet. You'll hear more about them soon.

Today, I want to share some exciting news - we are open sourcing the very heart of our business - migrate module and table wizard module. These modules are Mike Ryan's tour de force. The modules are intended to help a site owner or consultant migrate data from an external system into Drupal. The modules are as much about methodology and process as it is about bits and bytes. Our process is big on visualizing client data. We show our clients their tables and columns. And together with clients, we annotate the columns so that everyone understands what they mean. Clients have a UI for marking columns and rows that should be exempted from the migration. They can map their columns to CCK fields.

Migrate module has a major UI for kicking off mini migrations. The thing about migration work is that you have a long re-work phase where you have keep redoing parts of your migration until the kinks are discovered and fixed. Source data might be unclean, or client requirements might need clarification. Migrate module acknowledges this phase and lets you focus on re-migrating just 'editor users' for example.

Our modules feature some of the most interesting Views integration you will find.

We have so much more to say about our migration tools. Attend our Session at Drupalcon on Thursday if you are interested in learning more.

Update: The video of our presentation is now available online.