Feeds

Author

Dec 05 2018
Dec 05

After months of reading, experimenting and a lot of coding, I'm happy that the first release candidate of the Drupal IndieWeb module is out. I guess this makes the perfect time to try it out for yourself, no? There are a lot of concepts within the IndieWeb universe, and many are supported by the module. In fact, there are 8 submodules, so it might be daunting to start figuring out which ones to enable and what they exactly allow you to do. To kick start anyone interested, I'll publish a couple of articles detailing how to set up several concepts using the Drupal module. The first one will explain in a few steps how you can send a webmention to this page. Can you mention me?

Step 1: enabling modules

After you downloaded the module and installed the required composer packages, enable following modules: IndieWeb, Webmention and Microformats2. In case you are not authenticated as user 1, also toggle the following permissions: 'Administer IndieWeb configuration' and 'Send webmention'.

Step 2: expose author information

To discover the author of a website after receiving a webmention, your homepage, or the canonical url of a post needs author information. The module comes with an Author block so you can quickly expose a block where you can configure your name. Your real name or nickname is fine, as long as there's something. The minimal markup should look like something like this:

<p class="h-card">Your <a class="u-url p-name" rel="me" href="https://example.com">name</a></p>


Note: this can be anywhere in your HTML, even hidden.

Step 3: configure webmention module

All configuration exposed by the modules lives under 'Web services' > 'IndieWeb' at /admin/config/services/indieweb. To configure sending webmentions go to /admin/config/services/indieweb/webmention/send. Ignore the ' Syndication targets' fieldset and scroll down to ' Custom URL's for content' and toggle the 'Expose textfield' checkbox.

Scroll down a bit more and configure how you want to send webmentions, either by cron or drush (webmentions are stored in a queue first for performance reasons)

Step 4: configure Microformats module

When sending a webmention to me, it would be nice to be able to figure out what exactly your post is. To achieve this, we need to add markup to the HTML by using CSS classes. Let's configure the minimal markup at /admin/config/services/indieweb/microformats by toggling following checkboxes:

  • h-entry on node wrappers
  • e-content on standard body fields. In case your node type does not use the standard body field, enter the field name in the 'e-content on other textarea fields' textarea.
  • dt-published, p-name, u-author and u-url in a hidden span element on nodes.

Now create a post!

Create a post with a title and body. Your body needs to contain a link with a class so that when I receive your webmention, I know that this page is valid. As an example, we're going to write a reply:

Hi swentel! I just read your <a href="https://realize.be/blog/send-me-webmention-drupal" class="u-in-reply-to">article</a> and it's awesome!

Save the post and verify the markup more or less looks like underneath. Make sure you see following classes: h-entry, u-url, p-name, dt-published, e-content, u-author.

<article role="article" class="h-entry node node--type-article node--promoted node--unpublished node--view-mode-full clearfix">
  <header>
     <div class="node__meta">
        <span>
          Published on <span class=" field--label-hidden">Tue, 04/12/2018 - 22:39</span>
        </span>
        <span class="hidden">
          <a href="https://example.com/canonical-url" class="u-url">
            <span class="p-name">Test send!</span>
            <span class="dt-published">2018-12-04T22:39:57+01:00</span>
          </a>
          <a href="https://realize.be/" class="u-author"></a>
        </span>
      </div>
      </header>
  <div class="node__content clearfix">
  <div class="e-content clearfix ">Hi swentel! I just read your <a href="https://realize.be/blog/send-me-webmention-drupal" class="u-in-reply-to">article</a> and it's awesome!</div>
  </div>
</article>

If everything looks fine, go to the node form again. Open the 'Publish to' fieldset where you can enter 'https://realize.be/blog/send-me-webmention-drupal' in the custom URL textfield. Save again and check the send list at /admin/content/webmention/send-list. It should tell that there is one item in the queue. As a final step, run cron or the 'indieweb-send-webmentions' drush command. After that the queue should be empty and one entry will be in the send list and I should have received your webmention!

Note: You can vary between the 'u-in-reply-to', 'u-like-of' or 'u-repost-of' class. Basically, the class determines your response type. The first class will create a comment on this post. The other two classes will be a mention in the sidebar.

What's next?

Well, a lot of course. But the next step should be receiving webmentions no? If you go to /admin/config/services/indieweb/webmention, you can enable receiving webmentions by using the built-in endpoint. Make sure you expose the link tag so I know where to mention you!

I tried it, and it didn't work!

Maybe I missed something in the tutorial. Or you have found a bug :) Feel free to ping me on irc.freenode.net on #indieweb-dev or #drupal-contribute. You may also open an issue at https://github.com/swentel/indieweb

Send me a webmention with #drupal! 101 setup with the first release candidate of the #indieweb module. Can you mention me? https://realize.be/blog/send-me-webmention-drupal

Nov 20 2018
Nov 20

Lately, Mastodon is getting a lot of attention as an alternative for Twitter. It's a microblogging platform which allows you to setup your own instance, and still interact with users on a totally different domain. They are all part of the Fediverse. It uses open standard protocols and specifications as much as possible, which means that integration from other places should be possible, e.g. why not your own site !

Webmentions

To interact with Mastodon, and most other federated platforms, you need to implement Activitypub and add Webfinger support to your domain, which can be tricky to setup. Enter Bridgy Fed: it acts as a proxy for your domain and does all the heavy lifting for discovery, sending posts to the right instance and sending back interactions to your site. The Drupal IndieWeb module has all the necessary tools for sending and receiving webmentions and the markup needed for your content. In fact, there are only two simple things you need to do. Add "Fediverse|https://fed.brid.gy/" on the 'Sending' settings screen as a syndication target and two lines to .htaccess, and you're done: welcome to the Fediverse. Don't like Drupal ? No problem! Any framework, whether you are using Wordpress or Known, or even wrote yourself, which supports sending webmentions can get on the Fediverse! Read about webmentions and microformats on IndieWeb.org.

Following

If you are on Mastodon, you can follow me by searching for 'swentel' which will give you two results. One is a test account I use for testing the AP protocol. The user that is managed by Bridgy Fed, and which will now get all the notes I syndicate from my site, is @[email protected].

Since I don't have an actual account, how do I follow users? Mastodon exposes an atom and even a Microformats feed of every user. This allows everyone to follow accounts with even a simple RSS reader. In my case, I use Indigenous as my reader, and Aperture as the server (actually, I'm using the built-in server now in the IndieWeb module, but Aperture is a great alternative to get started!). From my client, I can directly interact with anyone on the Fediverse because it knows my micropub endpoint to post to my site which then starts syndicating posts to the right instance: replying, liking, boosting, posting .. it all works! Some tiny details need to be figured out still, like images, but simple content just works fine!

All of this has been tested with Mastodon. There are more federated platforms out there, so this is only the beginning! A big shout out to Ryan Barret, the maintainer of Bridgy Fed (and many other great tools)!

Getting on the Fediverse with your own site using Drupal and Bridgy Fed just became easy! https://realize.be/blog/your-site-fediverse-bridgy-fed #drupal #fediverse #indieweb

Sep 03 2018
Sep 03

For a custom project, we use a taxonomy to tag nodes. Some terms have their own page, while others redirect to a node. The search on the site has one index which contains both nodes and terms, but the terms which are redirecting shouldn't show up when viewing a search results page. While it's possible to use hook_search_api_index_items_alter(), a nicer way to exclude them is by using a processor plugin so you can enable them in the UI per index. The relevant code is underneath. Adjust to your own likings - and maybe inject the service if you want to as well :)

<?php
namespace Drupal\project\Plugin\search_api\processor;

use

Drupal\search_api\IndexInterface;
use
Drupal\search_api\Processor\ProcessorPluginBase;/**
 * Excludes entities which have a redirect.
 *
 * @SearchApiProcessor(
 *   id = "entity_redirect",
 *   label = @Translation("Entity redirect"),
 *   description = @Translation("Exclude entities which have a redirect from being indexed."),
 *   stages = {
 *     "alter_items" = 0,
 *   },
 * )
 */
class EntityRedirect extends ProcessorPluginBase { /**
   * {@inheritdoc}
   */
 
public static function supportsIndex(IndexInterface $index) {
    foreach (
$index->getDatasources() as $datasource) {
     
$entity_type_id = $datasource->getEntityTypeId();
      if (!
$entity_type_id) {
        continue;
      }
      if (
$entity_type_id === 'node' || $entity_type_id == 'taxonomy_term') {
        return
TRUE;
      }
    }
    return
FALSE;
  }
/**
   * {@inheritdoc}
   */
 
public function alterIndexedItems(array &$items) {
   
$repository = \Drupal::service('redirect.repository');
   
$pathAliasmanager = \Drupal::service('path.alias_manager');
   
/** @var \Drupal\search_api\Item\ItemInterface $item */
   
foreach ($items as $item_id => $item) {
     
$object = $item->getOriginalObject()->getValue();
      try {
       
$path = $object->toUrl()->toString();
       
$path = $pathAliasmanager->getPathByAlias($path);
       
$path = ltrim($path, '/');
       
$redirect = $repository->findMatchingRedirect($path);
        if (!empty(
$redirect)) {
          unset(
$items[$item_id]);
        }
      }
      catch (\
Exception $ignored) {}
    }
  }

}

?>

Exclude entities which have a redirect from the search api index: https://realize.be/blog/exclude-entities-which-have-redirect-search-api-...

Feb 27 2018
Feb 27

I've had my site for quite some time now, the internet archive goes way back to 2002 even! To be fair, most of the content until 2007 wasn't that interesting (not sure what makes me think it is nowadays though, but okay ... ), but it was mostly the primary source of well .. me :). Apart from that, I also use Twitter, but I want to turn this around and let my site be the primary source. The IndieWeb movement is something I only recently discovered, but somehow, the philosophy was in my mind for the last few weeks, and I am not the only one that is talking about it.

So, as a first small step, to figure out who links to my content, I created a simple Drupal 8 module that can receive and store webmentions and pingbacks from Webmention.io. The source is available at https://github.com/swentel/webmention_io. I'll move this drupal.org at some point once it gets into a more polished state, but it also depends on further iterations of getting more interaction feedback to my site.

Update: The repository has already moved to https://github.com/swentel/indieweb - sorry in case you were using it already :) The module allows you to receive webmentions, send webmentions to brid.gy which will look for the microformats added by the module on content and images. Micropub and Microsub are on the way too!

https://brid.gy/ is polling Twitter and forwarding those mentions to this site, and currently likes are being exposed and replies are stored as comments, which is very cool! See the sweet magic happening right on note #4.

Nov 28 2016
Nov 28

From the Configuration split project page: "The Drupal 8 configuration management works best when importing and exporting the whole set of the sites configuration. However, sometimes developers like to opt out of the robustness of CMI and have a super-set of configuration active on their development machine and deploy only a subset. The canonical example for this is to have the devel module installed or having a few block placements or views in the development environment and then not export them into the set of configuration to be deployed, yet still being able to share the development configuration with colleagues."

This small utility module for Drupal 8 allows you to exactly achieve this use case (and many others). I will cover two common scenarios, explaining how to configure your site and which commands you need to run:

  1. Have (development/ui) modules installed on your dev environment, uninstalled on production
  2. Have modules installed on your production environment, but not on development

I've also recorded a screencast in which I configure and run all the commands explained underneath. The best way in the end is to play around with the module itself of course.

[embedded content]

Configuration split 101

Configuration split exposes a configuration entity which controls what you want to split off. Currently you can

  • blacklist modules: any configuration that this module owns will automatically be blacklisted too.
  • blacklist configuration: settings or configuration entities. These will be removed from the active sync directory.
  • graylist configuration: settings or configuration entities. These will not be removed if they are in the active sync directory, but also not exported if they are not there yet. I won't cover this functionality in this article post, that will be for another time.

After you configured one or more configurations split entities, you can use the drush commands to export and import configuration, based on one or more of those config entities. When it comes to exporting configuration, you can not use the existing drush core command (config-export / cex). Using drush config-import (cim) or the UI to import may still be used, but this depends on your setup. Drupal Console commands are under revision. Important: since feb 2017, due to https://www.drupal.org/node/2855319 and https://github.com/drush-ops/drush/pull/2471, you can use the standard drush commands without any problems!

Each config split entity defines the directory in which the splitted configuration will live in case there are some. Not all modules define configuration, so there's a possibility that this directory is empty after you do an export.

An important technical aspect is that the module does not interfere with the active configuration but instead filters on the import/export pipeline. What simple happens is this: just before the actual writing, it will check the configuration and remove any entries that you don't want to be there. Then your active configuration is written away. Config that doesn't belong into the active configuration will be moved to separate directory. On import, the opposite happens: it will merge settings back in and set modules to the installed state just before core configuration then starts importing.

Last, but not least: you can swap the config.storage.sync service so that the synchronize screen will use the config split config entities for importing. More information is in the README file and in the video.

Scenario 1: modules installed on dev, not on production

Step 1

After you installed the module, go to 'admin/config/development/configuration/config-split' and click on 'Add configuration split'. Naming is important, so we'll enter 'Dev split' as the name for this configuration. We'll also create a directory called 'sync-dev-split'. Now toggle the modules that you don't want to have installed on production. In this case, we're going to blacklist Devel, Devel Kint, Field UI, Views UI and database logging. Additionally, also toggle system.menu.devel. This configuration is owned by the system module, so there's no dependency on the devel module. There's no problem having this config on your production site though, so it's not required to blacklist it.

Optionally, you can also blacklist the configuration split module because it doesn't necessarily have to be installed on production. We're not doing that here, because in the second scenario, we're building further on this one and we want to have it installed on the production environment as well.

Step 2

Go to your command line interface and run following command:

[email protected]:/home/drupal/drupal-core$ drush csex --split=dev_split

The split option is not required, but when starting to work with the module, it helps you to know which config split will be used for this command. It's possible to override the status of any config split config entity so that eventually, you can omit the split option. Sadly enough, you don't get any feedback (yet), but after the command has run you should see various files in your sync-dev-split directory:

[email protected]:/home/drupal/drupal-core$ ls sync-dev-split/
dblog.settings.yml  devel.settings.yml  field_ui.settings.yml  system.menu.devel.yml

Step 3

You can now commit your active sync and go to production. You don't necessarily have to put the sync-dev-live directory in your version control because production doesn't need to know about these files at all. Once you have pulled on production, go to the synchronize screen to verify what is staged. You will see that the setting files will be removed and core.extension will be changed uninstalling the development modules and installing configuration split. Since we only have one config split configuration, you can hit 'Import all' here or run drush config-import, (which is the drush core command). Note that if you don't use the UI, you can blacklist the configuration manager module as well.

You might wonder why we don't use the 'config-split-import' command from the module itself: this would import the active sync directory and also include the modules and settings again that we have blacklisted. And that's not what we want. This seems confusing at first, but ultimately, if this is your setup, you just keep on using the core / drush commands to import your staged configuration on production.

# This command can be used now, but not anymore further on when we will add scenario 2.
[email protected]:/home/drupal/drupal-core$ drush cim

Scenario 2: modules installed on production, not on dev

Step 1

This scenario builds further on the first one. Config split is now installed on our live website. Create a new config split configuration called 'Live split'. You will need a new directory for this second config split, so make sure it's there. On production we still want to log events and for that we're going to use the syslog module. Install the module, so that we can now blacklist it for the live split configuration.

Step 2

Go to your command line interface and run following commands:

[email protected]:/home/drupal/drupal-core$ drush csex --split=live_split

Again, no feedback here, but after the command has run you should see the syslog settings file in your sync-live-split directory:

[email protected]:/home/drupal/drupal-core$ ls sync-live-split/
syslog.settings.yml

Doing exports and imports on dev or live

From now on, if you want to import new settings whether it's on your dev or live environment, you can not use the drush core commands anymore. Use following commands:

# to export on your dev environment
[email protected]:/home/drupal/drupal-core$ drush csex --split=dev_split
# to import on your dev environment
[email protected]:/home/drupal/drupal-core$ drush csim --split=dev_split

# to export on your live environment
[email protected]:/home/drupal/drupal-core$ drush csex --split=live_split
# to import on your live environment
[email protected]:/home/drupal/drupal-core$ drush csim --split=live_split

The future

Please join us in the issue queue because there's still some work:

  • Optimize the user interface and allow wildcards
  • Add confirmation and feedback in the drush commands

Ultimately, this functionality should live in core. A core issue to discuss this is at https://www.drupal.org/node/2830300.

Aug 05 2016
Aug 05

Every Drupal developer knows the following error message (maybe some by heart): The content has been modified by another user, changes cannot be saved. In Drupal 8 the message is even a bit longer: The content has either been modified by another user, or you have already submitted modifications. As a result, your changes cannot be saved. While this inbuilt mechanism is very useful to preserve data integrity, the only way to get rid of the message is to reload the form and then redo the changes you want to make. This can be (or should I say 'is') very frustrating for users, especially when they have no idea why this is happening. In an environment where multiple users modify the same content, there are solutions like the Content locking module to get overcome this nagging problem. But what if your content changes a lot by backend calls ?

On a big project I'm currently working on, Musescore.com (D6 to D8), members can upload their scores to the website. On save, the file is send to Amazon where it will be processed so you can play and listen to the music in your browser. Depending on the length of a score, the processing might take a couple of minutes before it's available. In the meantime, you can edit the score because the user might want to update the title, body content, or add some new tags. While the edit form is open, the backend might be pinging back to our application notifying the score is now ready for playing and will update field values, thus saving the node. At this very moment, the changed time has been updated to the future, so when the user wants to save new values, Drupal will complain. This is just a simple example, in reality, the backend workers might be pinging a couple of times back on several occasions doing various operations and updating field values. And ironically, the user doesn't even have any permission to update one or more of these properties on the form itself. If you have ever uploaded a video to YouTube, you know that while your video is processing you can happily update your content and tags without any problem at all. That's what we want here too.

In Drupal 8, validating an entity is now decoupled from form validation. More information can be found on the Entity Validation API handbook and how they integrate with Symfony. Now, the validation plugin responsible for that message lives in EntityChangedConstraint and EntityChangedConstraintValidator. Since they are plugins, we can easily swap out the class and depending on our needs only add the violation when we really want to. What we also want is to preserve values of fields that might have been updated by a previous operation, in our case a backend call pinging back to tell us that the score is now ready for playing. Are you ready ? Here goes!

Step 1. Swap the class

All plugin managers in Core (any plugin manager should do that!) allow you to alter the definitions, so let's change the class to our own custom class.

<?php
/**
 * Implements hook_validation_constraint_alter().
 */
function project_validation_constraint_alter(array &$definitions) {
  if (isset(
$definitions['EntityChanged'])) {
   
$definitions['EntityChanged']['class'] = 'Drupal\project\Plugin\Validation\Constraint\CustomEntityChangedConstraint';
  }
}
?>

For the actual class itself, you can copy the original one, but without the annotation. The constraint plugin manager doesn't need to know about an additional new one (unless you want it to of course).

<?php
namespace Drupal\project\Plugin\Validation\Constraint;

use

Symfony\Component\Validator\Constraint;/**
 * Custom implementation of the validation constraint for the entity changed timestamp.
 */
class CustomEntityChangedConstraint extends Constraint {
  public
$message = 'The content has either been modified by another user, or you have already submitted modifications. As a result, your changes cannot be saved. In case you still see this, then you are really unlucky this time!';
}
?>

Step 2: alter the node form

We want to be able to know that a validation of an entity is happening when an actual form is submitted. For this, we're adding a hidden field which stores a token based on the node id which we can then use later.

<?php
/**
 * Implements hook_form_BASE_FORM_ID_alter() for \Drupal\node\NodeForm.
 */
function project_form_node_form_alter(&$form, &$form_state) {
 
/** @var \Drupal\Node\NodeInterface $node */
 
$node = $form_state->getFormObject()->getEntity();
  if (!
$node->isNew() && $node->bundle() == 'your_bundle' && $node->getOwnerId() == \Drupal::currentUser()->id()) {
   
$form['web_submission'] = [
     
'#type' => 'hidden',
     
'#value' => \Drupal::csrfToken()->get($node->id()),
    ];
  }
}
?>

Step 3: Validating the entity and storing an id for later

We're getting to the tricky part. Not adding a violation is easy, but the entity that comes inside the constraint can't be changed. The reason is that ContentEntityForm rebuilts the entity when it comes in the submission phase, which means that if you would make any changes to the entity during validation, they would be lost. And it's a good idea anyway as other constraints might add violations which are necessary. To come around that, our constraint, in case the changed time is in the past, will verify if there is a valid token and call a function to store the id of the node in a static variable which can be picked up later.

<?php
namespace Drupal\project\Plugin\Validation\Constraint;

use

Symfony\Component\Validator\Constraint;
use
Symfony\Component\Validator\ConstraintValidator;/**
 * Validates the EntityChanged constraint.
 */
class CustomEntityChangedConstraintValidator extends ConstraintValidator { /**
   * {@inheritdoc}
   */
 
public function validate($entity, Constraint $constraint) {
    if (isset(
$entity)) {
     
/** @var \Drupal\Core\Entity\EntityInterface $entity */
     
if (!$entity->isNew()) {
       
$saved_entity = \Drupal::entityManager()->getStorage($entity->getEntityTypeId())->loadUnchanged($entity->id());
       
// A change to any other translation must add a violation to the current
        // translation because there might be untranslatable shared fields.
       
if ($saved_entity && $saved_entity->getChangedTimeAcrossTranslations() > $entity->getChangedTimeAcrossTranslations()) {
         
$add_violation = TRUE;
          if (
$entity->getEntityTypeId() == 'node' && $entity->bundle() == 'your_bundle' &&
           
$this->isValidWebsubmission($entity->id())) {
           
$add_violation = FALSE; // Store this id.
           
project_preserve_values_from_original_entity($entity->id(), TRUE);
          }
// Add the violation if necessary.
         
if ($add_violation) {
           
$this->context->addViolation($constraint->message);
          }
        }
      }
    }
  }
/**
   * Validate the web submission.
   *
   * @param $value
   *   The value.
   *
   * @see project_form_node_form_alter().
   *
   * @return bool
   */
 
public function isValidWebsubmission($value) {
    if (!empty(\
Drupal::request()->get('web_submission'))) {
      return \
Drupal::csrfToken()->validate(\Drupal::request()->get('web_submission'), $value);
    }

    return

FALSE;
  }

}

/**
 * Function which holds a static array with ids of entities which need to
 * preserve values from the original entity.
 *
 * @param $id
 *   The entity id.
 * @param bool $set
 *   Whether to store the id or not.
 *
 * @return bool
 *   TRUE if id is set in the $ids array or not.
 */
function project_preserve_values_from_original_entity($id, $set = FALSE) {
  static
$ids = [];

  if (

$set && !isset($ids[$id])) {
   
$ids[$id] = TRUE;
  }

  return isset(

$ids[$id]) ? TRUE : FALSE;
}
?>

Step 4: copy over values from the original entity

So we now passed validation, even if the submitted changed timestamp is in the past of the last saved version of this node. Now we need to copy over values that might have been changed by another process that we want to preserve. In hook_node_presave() we can call project_preserve_values_from_original_entity() to ask if this entity is eligible for this operation. If so, we can just do our thing and happily copy those values, while keeping the fields that the user has changed in tact.

<?php
/**
 * Implements hook_ENTITY_TYPE_presave().
 */
function project_node_presave(NodeInterface $node) {
  if (!
$node->isNew() && isset($node->original) && $node->bundle() == 'your_bundle' && project_preserve_values_from_original_entity($node->id())) {
   
$node->set('your_field', $node->original->get('your_field')->value);
   
// Do many more copies here.
 
}
}
?>

A happy user!

Not only the user is happy: backends can update whenever they want and customer support does not have to explain anymore where this annoying user facing message is coming from.

Apr 11 2016
Apr 11

A native mobile application which can cache the data locally is a way to make content available offline. However, not everyone has the time and/or money to create a dedicated app, and frankly, it's not always an additional asset. What if browsers could work without network connection but still serve content: Application Cache and/or Service Workers to the rescue!

For Frontend United 2016, Mathieu and I experimented to see how far we could take AppCache and make the sessions, speakers and some additional content available offline using data from within the Drupal site. There are a couple of pitfalls when implementing this, of which some are nasty (see the list apart link at the bottom for more information). Comes in Drupal which adds another layer of complexity, with its dynamic nature of content and themes. Javascript and css aggregation is also extremely tricky to get right. So after trial and error and a lot of reading, we came up with the following concept:

  1. Only add the manifest attribute to all "offline" pages which are completely separate from "online pages", even though they might serve the same content. In other words, you create a sandboxed version of some content of your site which can live on its own. Another technique is a hidden iframe which loads a page which contains the html tag with the manifest attribute. You can embed this iframe on any page you like. This gives you the option to create a page where you link to as an opt-in to get a site offline. Both techniques give us full control and no side affects so that when network is available the site works normally.
  2. You define the pages which you want to store in the cache. They are served by Drupal, but on a different route than the original (e.g. node/1 becomes offline/node/1) and use different templates. These are twig templates so you can override the defaults to your own needs. Other information like stylesheet and javascript files can be configured too to be included.
  3. The manifest thus contains everything that we need to create the offline version when your device has no network connection. In our case, it contains the list of speakers and sessions, content pages and some assets like javascript, stylesheet, logo and images.

Note: currently, the website isn't app-cache enabled anymore, preparing for 2017.

Offline in the browser or on the homescreen

Go to the Offline homepage of Frontend United and wait until the 'The content is now available offline!' message appears, which means you just downloaded 672 kb of data - it is really really small, surprising no? Now switch off your network connection and reload the browser: still there! Click around and you'll be able to check the offline version at any time. If you're on a mobile device, the experience can be even sweeter: you can add this page to your homescreen, making it available as an 'app'. On iOS, you need to open the app once while still being connected to the network. We really do hope safari/iOS fixes this behavior since this is not necessary on Android. After that, turn off your network and launch the app again. Oh, and it works on a watch too if you have a browser on it. If that isn't cool, we don't know what else is! We have a little video to show you how it looks like. Watch (pun intended) and enjoy! Oh, in case we make changes to the pages, you will see a different notification telling you that the content has been updated - if your device has network of course.

[embedded content]

Drupal integration

We've created a new project on Drupal.org, called Offline App, available for Drupal 8. The project contains the necessary code and routes for generating the appcache, iframe, pages (nodes and views) and settings to manipulate the manifest content. 3 new regions are exposed in which you can place the content for offline use. Those regions are used in offline-app-page.html.twig - but any region is available if you want to customize. Two additional view modes are created for content types and the read more link can be made available in the 'Offline teaser' mode. Formatters are available for long texts to strip internal links and certain tags (e.g. embed and iframe) and for images that will make sure that 'Link to content' is pointing to the 'Offline path'. Last, but not least, an 'Offline' Views display is available for creating lists. We're still in the process in making everything even more flexible and less error-prone when configuring the application. However, the code that is currently available, is used as is on the Fronted United website right now.

This module does not pretend to be the ultimate solution for offline content, see it as an example to quickly expose a manifest containing URL's from an existing Drupal installation for an offline version of your website. Other Drupal projects are available trying to integrate with AppCache or Service workers, however, some are unsupported or in a very premature state, apart from https://www.drupal.org/project/pwa. Note that I've been in contact with Théodore already and we'll see how we combine our efforts for coming up with one single solution instead of having multiple ones.

What about service workers ?

Not all browsers support the API yet. Even though AppCache is marked deprecated, we wanted to make sure everyone could have the same offline experience. However, we'll start adding support for service workers soon using the same concept.

We're also planning to start experimenting with delivering personal content as well, since that's also possible, yet a little trickier.

Links

Dec 02 2013
Dec 02

This is part 4 of the Drupal 8 Field API series. We skipped part 3 about field types as the dust hasn't settled yet in terms of API changes. Once we get there, we'll make sure we'll talk about the massive changes that have happened in that area.

In this part, we'll talk about new API's which are, strictly speaking, not part anymore of Field API, they now belong to the Entity Field API. However, the reason the changes exist, directly comes out of a big problem in Drupal 7 in Field API: scattered storage.

Entity display

In Drupal 7, parameters controlling how to render the various "parts" of an entity view in a given view mode were scattered in many separate locations:

  • in $instance['display'] for each individual (Field API) field in the bundle
  • in the 'field_bundle_settings_[entity_type]_[bundle]' variable for the 'extra fields' in the bundle
  • in other places for contrib additions that are not one of the two above (most notably field_group module)

In Drupal 8, all those parameters ("options") for all those parts ("components") are centralised in one single EntityViewDisplay configuration object - which means they can be deployed with CMI - for each entity bundle and view mode. You can access these objects with the entity_get_display() function. All available methods can be found in EntityDisplayInterface.

<?php
entity_get_display
('node', 'article', 'default')
 
// Set 'component_1' to be visible, with weight 1.
 
->setComponent('component_1', array(
   
'weight' => 1,
  ))
 
// Set 'component_2' to be hidden.
 
->removeComponent('component_2')
  ->
save();
?>

Also new in D8 is that all entity and field rendering hooks now receive this EntityDisplay object as a parameter. This means you have direct access to the configuration in your functions, instead of having to figure them out by calling functions to get the definition of field instances, extra fields or other configurations. For the full list of all hooks affected, scroll to the resources part at then end of this article for the change record link.

<?php
function hook_node_view(Node $node, EntityDisplay $display, $view_mode, $langcode) {
  if (
$display->getComponent('mymodule_addition')) {
   
$node->content['mymodule_addition'] = array(
     
'#markup' => mymodule_addition($node),
     
'#theme' => 'mymodule_my_additional_field',
    );
  }
}
?>

Note that currently only Field API fields and extra fields are handled by the EntityViewDisplay object. This is going to change when we introduce component type plugins so everyone will be able to store and access configuration. For more information, follow https://drupal.org/node/1875974.

Entity form display

Just like with the display settings, form settings are scattered all over the place:

  • in $instance['widget'] for each individual (Field API) field in the bundle
  • in the 'field_bundle_settings_[entity_type]_[bundle]' variable for the 'extra fields' in the bundle
  • in other places for contrib additions that are not one of the two above (most notably field_group module)

In Drupal 8, all those parameters ("options") for all those parts ("components") are centralised in one single EntityFormDisplay configuration object for each entity bundle and form mode.This object uses the same EntityDisplayInterface as the EntityViewDisplay object. The consequence of this API is the birth of the counterpart of view modes: form modes.

The direct use case for this was the hacky workaround in Drupal 7 for showing Field API fields on the user registration page. In Drupal 8, you can now configure which fields are available on the user registration page or the edit page. However, more interesting possibilities with this new API will certainly pop up when Drupal 8 is released, most notable inline entity forms.

UI impact

In Drupal 7, the place to manage the fields and control the order in forms is done on the 'manage fields' screen. In Drupal 8, this has has been split out in the 'manage fields' and the 'manage form display' screens. Widget settings are now also managed on this new screen, which allows you to have different widget settings depending on the form mode. The form displays screen also have a 'hidden' region, which allows you to hide certain fields on certain form modes.

Display modes

Drupal 7 has the concept of 'view modes', previously build modes in D6. In D8, we now also have form modes and both of them are configuration entities. Drupal 8 also ships with a UI to manage these display modes. You do not have to rely anymore on contributed modules like 'View modes' or 'Display Suite'.

Resources

Sep 19 2013
Sep 19

DrupalCon Prague is approaching fast. In a few days, Drupal folks from all over the world will gather together in Prague to sprint, attend sessions, have fun etc. A few days ago, I was searching to see whether there was a mobile application available and turns out it wasn't. So me and a friend volunteered to create one based on the DrupalCamp app we've created a few weeks ago. They might be basic, but they do the job fine when you quickly want to check the schedule of the whole week.

The apps will be available for Android and iOS. The Android version is available on Play Store, the iOS version is currently in review, so fingers crossed!

Features include:

  • Built with speed in mind: native app
  • Works offline
  • Sessions and speakers
  • Create your schedule
    Note, does not sync with your account.
  • Maps integration when online

Collaborate

The code is available on GitHub, so anyone can easily send in bug reports, interface translations or create pull requests to make the applications even better. You can of course reuse and/or extend the code for future DrupalCons.

Proudly built by @swentel, @TimLeytens and @leenvs.

Aug 07 2013
Aug 07

On september 14 and 15, Leuven will host the annual Belgium DrupalCamp. During those two days, people come together learning and discussing the open-source content management system Drupal. The program will be available on the website, but we decided to also create an application this year. We've tried to make it abstract as possible, so other Drupal events can easily built from the source code which is available online.

The apps will be available for Android and iOS. As soon as the program is ready, we'll publish them, so keep an eye out for the camp website, twitter or, of course, this article. The Android version is available on Play Store.

Features include:

  • Built with speed in mind: native app
  • Works offline
  • Sessions and speakers
  • Mark your favorite sessions
  • Maps integration when online

Collaborate

The code is freely available on GitHub, so anyone can easily send in bug reports, interface translations or create pull requests to make the applications even better.

Proudly built by @swentel, @TimLeytens and @leenvs.

So, who will make the Windows mobile and Firefox version ?

Aug 05 2013
Aug 05

In the first article of the Drupal 8 Field API series, we saw how field formatters are written in Drupal 8. Now it's time for widgets. You might get a déjà vu when reading as a lot resemble to formatters.

Plugins

Creating field widgets in Drupal 7 was done by implementing four hooks. In Drupal 8, widgets are now plugins using the new Plugin API. Hooks are replaced by methods in classes, which means that your module file will be empty if you only provide a widget, unless you also implement one of the (new) widget alter hooks. Being classes, this means that field widgets can now extend on each other. A good example in core is the image field widget extending the file field widget class. Discovery and class instantiation is managed by the new widget plugin manager.

Create a file like '{your_module}/lib/Drupal/{your_module}/Plugin/field/FieldWidget/{NameOfYourWidget}.php. That's a lot of directories right ? Welcome to the world of PSR-0, namespaces and plugins in D8. This is most likely going to change, feel free to read, or even help along in https://drupal.org/node/1971198. Also, plugin managers can control where plugins reside, see https://drupal.org/node/2043379, so we'll probably change this at some point.

In most cases, you will want to extend the WidgetBase class which does most of the heavy lifting for you (holds the code that was in the field_default_*() functions in Drupal 7). Following classes will usually be imported at the top of your file depending on which methods you override:

<?php
// WidgetBase class.
use Drupal\Core\Field\WidgetBase;
// FieldItemListInterface
use Drupal\Core\Field\FieldItemListInterface;
// Symfone violation interface
use Symfony\Component\Validator\ConstraintViolationInterface;
?>

1. hook_field_widget_info() are now annotations

hook_field_widget_info() is replaced by annotation-based plugin discovery, using the \Drupal\field\Annotation\FieldWidget annotation class. As for other plugin types, the accepted properties are documented in the annotation class. Other modules can extend this by implementing hook_field_widget_info_alter(). Note that some property names have changed since Drupal 7 (spaces replaces by underscores). This is how an annotation looks like, which is placed right above the class keyword.

<?php
/**
 * Plugin implementation of the 'foo_widget' widget
 *
 * @FieldWidget(
 *   id = "foo_widget",
 *   label = @Translation("Foo widget"),
 *   field_types = {
 *     "text",
 *     "text_long"
 *   },
 *   settings = {
 *     "size" = "600",
 *   }
 * )
 */
class FooWidget extends WidgetBase { }
?>

2. hook_field_widget_settings_form() becomes WidgetInterface::settingsForm()

Next up is to create a settingsForm() method. If you have an old settings form, you can simply move the code to this method. The calling code (typically Field UI) takes care of saving the settings on form submit. Remember to always start with an empty $elements array and not with the $form argument from the function arguments.

Side note: in all methods in the widget class:

  • the settings values currently configured for the widget can be accessed with $this->getSetting('settings_key'), or $this->getSettings()
  • the settings values currently configured for the field on which the widget is being used can be accessed with $this->getSetting('settings_key'), or $this->getSettings(). Those methods return both field level settings and instance level settings, merged.
  • If access to field properties other than field settings is needed, the field definition can be accessed with $this->getFieldDefinition(). This returns an object implementing \Drupal\Core\Entity\Field\FieldDefinitionInterface, which unifies the separate $field and $instance structures D7 coders are familiar with. More details on this will come in a following post.
<?php
 
/**
   * {@inheritdoc}
   */
 
public function settingsForm(array $form, array &$form_state) {
   
$element = array(); $element['size'] = array(
     
'#type' => 'number',
     
'#title' => t('Size of textfield'),
     
'#default_value' => $this->getSetting('size'),
     
'#required' => TRUE,
     
'#min' => 1,
    );

    return

$element;
  }
?>

3. hook_field_widget_form becomes WidgetInterface::formElement()

This is where you return the widget form. Also, the methods now receive the field values as a \Drupal\Core\Field\FieldItemListInterface object, rather than an $items array in Drupal 7. More information can be found about Drupal 8 Entity API and the syntax around field values in the handbook. Simply put, FieldInterface objects can be accessed and iterated on like an array of items keyed by delta, and properties in each item can be accessed by simple object syntax.

<?php
 
/**
   * {@inheritdoc}
   */
 
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
   
$main_widget = $element + array(
     
'#type' => 'textfield',
     
'#default_value' => isset($items[$delta]->value) ? $items[$delta]->value : NULL,
     
'#size' => $this->getSetting('size'),
     
'#placeholder' => $this->getSetting('placeholder'),
     
'#maxlength' => $this->getSetting('max_length'),
     
'#attributes' => array('class' => array('text-full')),
    );

    if (

$this->getSetting('text_processing')) {
     
$element = $main_widget;
     
$element['#type'] = 'text_format';
     
$element['#format'] = isset($items[$delta]->format) ? $items[$delta]->format : NULL;
     
$element['#base_type'] = $main_widget['#type'];
    }
    else {
     
$element['value'] = $main_widget;
    }

    return

$element;
  }
?>

4. hook_field_widget_error becomes WidgetInterface::errorElement()

The second parameter, $violation, contains the list of constraint violations reported during the validation phase. In Drupal 8, the Sympony contraints class is used to validate objects, whether doing this programmatically or through a form. We won't go deeper into this for now. In the next article, when we'll talk about the field types, this will become much clearer. Just remember for now that validation should not happen in your widgets, but in constraints.

<?php
 
/**
   * {@inheritdoc}
   */
 
public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, array &$form_state) {
    return
$element[$violation->arrayPropertyPath[0]];
  }
?>

5. WidgetInterface::settingsSummary()

This is a new method which resembles FormatterInterface::settingsSummary(). With the introduction of form modes in D8, a given field can be displayed with different widgets in the different form modes used by the entity type. This method is used to output the settings currently configured for the widget in Field UI screens, just like you do with field formatters - try to keep it short :-).

<?php
 
/**
   * {@inheritdoc}
   */
 
public function settingsSummary() {
   
$summary = array(); $summary[] = t('Textfield size: !size', array('!size' => $this->getSetting('size')));
   
$placeholder = $this->getSetting('placeholder');
    if (!empty(
$placeholder)) {
     
$summary[] = t('Placeholder: @placeholder', array('@placeholder' => $placeholder));
    }

    return

$summary;
  }
?>

6. WidgetInterface::massageFormValues()

This is a new method which you should only implement if you need todo complex FAPI tricks when a form is submitted. This lets you turn the raw submitted form values produced by your widget into the "regular" format expected for field values. Examples in core are the taxonomy autocomplete widget and the file widget which need todo additional processing when a form is submitted.

Alter hooks

Besides the existing hook_field_widget_info_alter, two new hooks are introduced allowing you to alter widget settings form or summary on Field UI, which behave almost the same like field formatter alter hooks: hook_field_widget_settings_form and hook_field_widget_settings_summary_alter.

Resources

Conclusion

Like formatters, writing and maintaining field widgets for Drupal 8 is not hard. In most cases, when porting, it's simply moving the contents of your old hooks to the methods in a class. In the next part, we will see how you write field type plugins in Drupal 8.

Jul 22 2013
Jul 22

The Drupal 8 cycle has entered the API freeze since the 1st of July, which means it's time to start porting modules or simply play around with the API. While there are exceptions to change the API, you can safely assume that 95% (or even more) will remain as it is today.

This is the first article which will be part of a series of changes in Field API for Drupal 8: field formatters. In case there are updates to the API, we will update the articles, but also the change records on drupal.org. Watch out for the next couple of weeks and months and hopefully you're prepared for Drupal 8 and Field API.

Plugins

Creating field formatters in Drupal 7 was done by implementing four hooks. In Drupal 8, formatters are now plugins using the new Plugin API. Hooks are replaced by methods in classes, which means that your module file will be empty if you only provide a formatter (unless you also implement one of the field formatter alter hooks). Being classes, this means that field formatters can now extend on each other. A good example in core is the image field formatter extending the file field formatter class. Discovery and class instantiation is managed by the new formatter plugin manager.

Create a file like '{your_module}/lib/Drupal/{your_module}/Plugin/field/FieldFormatter/{NameOfYourFormatter}.php. That's a lot of directories right ? Welcome to the world of PSR-0, namespaces and plugins in D8. This is most likely going to change, feel free to read, or even help along in https://drupal.org/node/1971198. Also, plugin managers can now control where plugins reside, see https://drupal.org/node/2043379, so we'll probably change this at some point.

In most cases, you will want to extend the FormatterBase class which does most of the heavy lifting for you. Following classes will usually be imported at the top of your file:

<?php
// FormatterBase class.
Drupal\Core\Field\FormatterBase;
// FieldItemInterface
use Drupal\Core\Field\FieldItemListInterface;
?>

1. hook_field_formatter_info() are now annotations

hook_field_formatter_info() is replaced by annotation-based plugin discovery, using the \Drupal\field\Annotation\FieldFormatter annotation class. As for other plugin types, the accepted properties are documented in the annotation class. Other modules can extend this by implementing hook_field_formatter_info_alter(). In core, the edit module adds the edit property so it knows which in-place editor it has to use. Note that some property names have changed since Drupal 7 (spaces replaces by underscores). This is how an annotation looks like, which is placed right above the class keyword.

<?php
/**
 * Plugin implementation of the 'foo_formatter' formatter
 *
 * @FieldFormatter(
 *   id = "foo_formatter",
 *   label = @Translation("Foo formatter"),
 *   field_types = {
 *     "text",
 *     "text_long"
 *   },
 *   settings = {
 *     "trim_length" = "600",
 *   },
*    edit = {
*      "editor" = "form"
*    }
 * )
 */
class FooFormatter extends FormatterBase { }
?>

2. hook_field_formatter_settings_form() becomes FormatterInterface::settingsForm()

Next up is to create a settingsForm() method. If you have an old settings form, you can simply move the code to this method. Settings are automatically saved and can be accessed by calling $this->getSetting('settings_key');. Remember to always start with an empty $elements array and not with the $form argument from the function arguments.

<?php
 
/**
   * {@inheritdoc}
   */
 
public function settingsForm(array $form, array &$form_state) {
   
$element = array(); $element['trim_length'] = array(
     
'#title' => t('Trim length'),
     
'#type' => 'number',
     
'#default_value' => $this->getSetting('trim_length'),
     
'#min' => 1,
     
'#required' => TRUE,
    );

    return

$element;
  }
?>

3. hook_field_formatter_settings_summary() becomes FormatterInterface::settingsSummary()

Settings are accessed by calling $this->getSetting('settings_key');. Another change is that the summary now needs to return an array instead of a string.

<?php
 
/**
   * {@inheritdoc}
   */
 
public function settingsSummary() {
   
$summary = array();
   
$summary[] = t('Trim length: @trim_length', array('@trim_length' => $this->getSetting('trim_length')));
    return
$summary;
  }
?>

4. hook_field_formatter_prepare_view becomes FormatterInterface::prepareView() and hook_field_formatter_view() becomes FormatterInterface::viewElements()

The first method allows you to add additional information on the items, the second is where the actual formatting happens. Settings are accessed by calling $this->getSetting('settings_key');. Also, the methods now receive the field values as a \Drupal\Core\Field\FieldItemListInterface object, rather than an $items array in Drupal 7. More information can be found about Drupal 8 Entity API and the syntax around field values in the handbook. Simply put, FieldItemListInterface objects can be accessed and iterated on like an array of items keyed by delta, and properties in each item can be accessed by simple object syntax.

<?php
 
/**
   * {@inheritdoc}
   */
 
public function viewElements(FieldItemListInterface $items) {
   
$elements = array(); $text_processing = $this->getSetting('text_processing');
    foreach (
$items as $delta => $item) {
      if (
$this->getPluginId() == 'text_summary_or_trimmed' && !empty($item->summary)) {
       
$output = $item->summary_processed;
      }
      else {
       
$output = $item->processed;
       
$output = text_summary($output, $text_processing ? $item->format : NULL, $this->getSetting('trim_length'));
      }
     
$elements[$delta] = array('#markup' => $output);
    }

    return

$elements;
  }
?>

Alter hooks

The alter hooks are still the same for Drupal 8, with one small API change in hook_field_formatter_settings_summary_alter() which is invoked by the Field UI module. The summary is now an array of strings instead of a single string. <br/> will be automatically inserted between the strings when the summary is displayed.

<?php
/**
 * Implements hook_field_formatter_settings_summary_alter().
 */
function my_module_field_formatter_settings_summary_alter(&$summary, $context) {
 
// Append a message to the summary when an instance of foo_formatter has
  // mysetting set to TRUE for the current view mode.
 
if ($context['formatter']->getPluginId() == 'foo_formatter') {
    if (
$context['formatter']->getSetting('mysetting')) {
     
$summary[] = t('My setting enabled.');
    }
  }
}
?>

The other two hooks are hook_field_formatter_info_alter() allowing you to make changes to the formatter definitions and hook_field_formatter_settings_form_alter() which is invoked from by the Field UI module when displaying the summary of the formatter settings for a field.

Resources

Conclusion

Writing and maintaining field formatters for Drupal 8 is not hard. In most cases, when porting, it's simply moving the contents of your old hooks to the methods in a class. In the next part, we will see how you write widget plugins in Drupal 8.

Jun 18 2013
Jun 18

First of all: I'm a featured speaker. I'll be hosting a session called 'Drupal 8 for Site Builders'. Come and watch to get an overview of all the wonders and power Drupal 8 has for creating a site. However, there are other reasons to attend DrupalCon Prague, and they are not Drupal related at all.

Kutná Hora

Kutná Hora is a little town, about 80 kilometers away from Prague, world known for its Sedlec ossuary which contains a lot of human bones, used for decorating the inside. While this may sound luguber, a visit to this small chapel is not something you will ever forget. And if you don't go inside, the top of the chapel has a skull, they really thought about everything. The easiest way to get there is by train and even arriving in the small station is worth travelling. I have seen it already, but will be going again, so feel free to join me.

CERN opendays

CERN, the European Organization for Nuclear Research, is opening its doors on 28th and 29th of september for the public for it so called CERN opendays. CERN lies in Geneva, Switserland, about 8 hours driving from Prague, or maybe 1 hour flying by plane. You'll be able to go down 100 meters underground and look at the Large Hadron collider and all other amazingly cool experiments scientists and engineers perform. Unless you are Daniel "dawehner" Wehner, you don't get that many chances to visit this place in your lifetime, especially since they only open it up publicly every 4 years. Tickets are for sale starting August, so keep an eye on the website if you want to go. That means I won't be attending the post-sprints, but honestly, I can live with that.

Apr 14 2013
Apr 14
Live commit of the Field API to CMI patch at Frontend United

At BADCamp 2011 in San Francisco, Yves Chedemois, Greg Dunlap and I sat down to talk how we'd have to convert Field API to the configuration system that is now in Drupal 8.

Fast forward to April 13 2013. After months of hard work, with initial work done at DrupalCon Munich, the patch was finally ready to be committed. The Drupal core maintainers agreed that Alex Pott and I could commit this patch live on stage at Frontend United! And I had the honor of pushing the final button. I'll never be closer than this being a core comitter :)

Graham Taylor (@g_taylor) captured it all on video. 5 minutes of Drupal History.

swentel Sun, 14/04/2013 - 11:49
Dec 19 2012
Dec 19

The Field formatter conditions module for Drupal allows you to add conditions and actions per field on the manage display screens of entities (nodes, users etc). For example: you can hide a field on path x. Or hide it when the current user has role 'Administrator'. The module ships with several built-in conditions and actions for common use cases we encountered during projects at work. And thanks to jpstrikesback a couple of more will be added before we hit a 1.0 release.

It's easy to write your own specific use cases for a project, consult the API or look into the code how to built a form, condition and callback yourself in a few minutes. Field API and Display Suite fields are supported, Field API's extra fields are not, and most likely neither in the future.

Rules support

It gets better though. The API is limited to the fact that a callback is both the condition and the action. But what in case you want more conditions ? That's where Rules comes into play. You can build unlimited rules with fancy conditions and then fire off actions on a specific field. Currently, the module ships with two rules actions which can hide a field or change the image style of an image formatter. The event for these rules always needs to be 'A field is rendered'. Depending on the use cases, more will be added later, but it's easy for developers to write their own actions targeted for a specific project.

See it in action

See how it works in a short screencast. Happy conditioning and a very good new year!

Aug 27 2012
Aug 27

Last week, I attended the Field API pre Drupalcon sprint in Munich. My major motivation was to start working on the conversion of Field API to CMI and little than a week later, we have a patch that is green. While there's still a lot of work on it, it's still a good feeling after one week of hacking and discussions. After driving 8 hours home after a fantastic week, I decided to step up as a co-maintainer of Field API. But me stepping up won't make the big difference, we need more people joining us!

Anyone can help in many different ways

  • Gardening the queue: go through bug reports, ask for more info when something is not clear or close duplicates.
  • You can work on an issue by creating patches. Assign an issue to yourself so we know who's working on it.
  • Help by reviewing and testing patches to see if they actually work as intented.
  • Come bring us coffee and cake :)

Where should I start ?

There's a lot of work, that's for sure: CMI, widget and formatter plugins, Field API vs OO and so on. We have a site which lists the most important issues: http://realize.be/field-api - Bookmark that if you're interested!

We are also available on freenode.net on #drupal-fieldapi in case you have any questions.

How much time should I invest in this ?

That is totally up to you. Remember, this is voluntary work, so we do not expect anybody to work 40 hours a week - although that would be more than fantastic of course :) As an example, this is roughly what I think my weekly schedule will look like:

  1. Continue working further on the CMI patch. I have sponsored time from Wunderkraut so I can focus hard on getting this critical piece of functionality in. Goodbye field_config and field_config_instance tables!
  2. Go through the queue twice a week for about an hour and review existing patches from other people.
  3. Go through the queue twice a week for half an hour and close duplicates or ask for more info.
  4. Pick one 'quick win' issue per week to create a patch from it, either a bug or feature request.
  5. Work on Display Suite issue queue, this usually happens once a week for about 3 hours. Been like that since forever.

So wait, I thought you didn't sleep?

Yes I do, and I do other things as well. It's not worth spending all your nights on coding, you'll get burned out before you know it. But wouldn't it be great to go to sleep and someone else was doing some great work ?

So, who's helping along?

Jul 31 2012
Jul 31

In a previous article", I talked about the possibilities that CTools now exposes through its new powerfull drush commands. With the addition of a new alter hook just before writing out the files to a module, the sky is now the limit when it comes to having configuration of a site in code.

Knapsack

Almost two weeks from now, I created a project called 'Drush CTools Export Bonus' which does 2 basic things: writing a lot of new configuration to files and tons of commands to rebuild this configuration on command line. It finally gave me a reason to use the nice logo which was made a few months ago by Leen Van Severen. It pictures a knapsack which was the codename for a project I worked on at the end of last year, but got hold up by various reasons. Parts of that code ended up as the initial drush export patch for CTools.

So what does it do ? Simple: export or rebuild, via drush, any configuration that isn't supported by CTools' exportables, currently including common objects like content types, fields and instances, variables and many more. Entity exportables are on its way as well. See the project page for a full list. In the end, you should get the state of your site configuration in one single module, controllable by various drush commands. Drush being our Swiss army knife, the module our knapsack. In the end, I chose for a more descriptive project name referencing to its master drush command.

The workflow is extremely easy:

  1. drush dl drush_ctex_bonux into your .drush folder
  2. drush @site_alias ctex module_name to create a new or overwrite an existing export module
  3. drush @site_alias cbum module_name (first time) or drush @site_alias cbrm module_name when updating
  4. Sit back and watch the messages on your screen

For more commands, just type drush --filter=ctools

But hey, this sounds like features!

You're right, both projects (and maybe others out there) try do the same thing: make configuration available in code, but there's a couple of reasons why I chose to go down this road instead of using the features module. In a non-prioritized by importance order, this is why I've been thinking and coding about this the last year (probably even longer, I can't even recall anymore):

  1. Full control: Damian 'damiankloip' Lee and I are the main contributors with access to the CTools project regarding everything related with CTools' drush commands and bulk exporting. That gives us enough flexibility, also because the exportables in CTools just work™. By adding the alter mentioned above, new projects can easily be created and we don't pollute the main ctools project with configuration that it doesn't support out of the box. This new project is mine, but I'm open to any contributors out there, so ping me if you want access to make this rock beyond imagination.
  2. Killing module overhead: with features, you at least need 2 modules enabled. The exported module and features itself. If you want variables, you need strongarm - although that can be disabled and there's other modules out there exposing more configuration on top of that really shouldn't be enabled on your production environment at all. CTools is now slowly becoming a de facto contrib that you install on your Drupal 7 environment - think views and many others out there - which makes the choice very easy. With this project, you only need one drush file and the ctools commands to handle the configuration, including variables.
  3. It's CTools man! I admit, I'm a fan, and not only because of the exportables, which in my opinion everyone should simply implement as it will save you tons of code and maintenance nightmare. Do not try to write your own logic for code vs overridden vs database version of configuration. It's all there. And that's only the top of the iceberg of fine developer tools inside that project.
  4. It's about the state of your site. In its essence, you can export a complete site with both projects to one single module, commit that and update various environments. This is probably the workflow many developers have adopted using features, but there's also the tendency to split up use cases in various pieces. The philosophy of this project is simple: one site, one configuration. There's is absolutely no intention or need to split this up in individual pieces for flexibility. While it's possible, just don't do it, you don't need it.
  5. Dependency on modules: as already mentioned, you need features enabled to run its exported modules. Another key difference in this project is how we handle content types by not implementing hook_node_info(), but simply exporting the content type info to a separate file and a call to node_type_save() when updating. We're still implementing hook_image_default_styles, but that will soon disappear as we'll be adding an option to save every exportable, even ctools', to the database, so you can disable an exported module generated by this project.

Meet us at DrupalCon Munich

We're holding a bof session, currently scheduled on thursday, about all these fine goodies. We'll give you demo on how these commands work, answer your questions and talk about the future.

Will this solve all my problems ?

Maybe. Maybe not. There's no guarantee this approach is better than others, but there's one thing I do now though: typing drush @site_alias cbum module_name on a minimal Drupal install and then looking at the screen is one of the finer things I've seen in months which I wrote myself - but that's not a guarantee either. However, it's getting close to a point I've been dreaming for at least two years, having full control of a D7 configuration in code without any issues - so far. Anyone interested, please test and help along. And be very descriptive in case you post issues.

May 31 2012
May 31

Facet API for Drupal is an amazing module that enables you to easily create and manage faceted search interfaces. The UI is fantastic and easy and it works perfectly together with either Search API or Apache Solr. It also changes the breadcrumb as soon as you start filtering further, which in many (probably most) occasions, is a nice default behavior. But not every project wants these kind of breadcrumbs. In a project we tried first to override the breadcrumb with hook_breadcrumb_alter(), but as we have a lot of search pages, the code was getting ridiculously ugly.

So we looked at where exactly Facet API is changing the breadcrumbs. This happens in a method called setBreadcrumb in a url processor class. So, we need to create our own processor and override the default behavior. First of all, we need to let Facet API know we have our own url processor:

<?php
/**
* Implements hook_facetapi_url_processors().
*/
function yourmodule_facetapi_url_processors() {
  return array(
   
'standard' => array(
     
'handler' => array(
       
'label' => t('Your module URL processor'),
       
'class' => 'FacetApiYourClass',
      ),
    ),
  );
}
?>


We are doing something wrong here: the standard key is also used in facetapi_facetapi_url_processors(), so we should use another name, because we are now overriding the default class. The trick is to extend on that class so the other methods will still do the heavy lifting. Oh module_invoke_all, we sometimes love your merge behavior (although technically here it's a CTools plugin, but the result is the same for both).

<?php
class FacetApiYourClass extends FacetapiUrlProcessorStandard {
  public function
setBreadcrumb() {
   
// Keep default behavior.
 
}
}
?>


If this class is not defined in your .module, make sure you add it to the .info file so the registry picks it up.

That's it. Again, this post should probably also be tagged with '

You're doing it wrong

', but it works perfectly for our current use case.

Mar 24 2012
Mar 24

With the newest release of ctools, a new command was made available for drush to export all objects to code with one simple command to a module. Instead of having to copy and paste all code via the bulk export module to your custom module, a simple drush command now saves you a lot of time. But it doesn't stop there. Damian 'damiankloip' Lee started a sandbox to add more powerful funtionality and this has now been merged in the 7.x branch which will be available in the (soon) next release of ctools. An initial patch to select the exportables by hand has also been committed, but could need some more love on the UX side. Apart from that, the goodies that are in already, should make any developer extremely happy and opens up new possibilities in so many ways. So what commands can you use now and what do they do ?

  • drush ctools-export-disable: disable one or more exportables
  • drush ctools-export-enable: enable one or more exportables
  • drush ctools-export-revert: revert one or more exportables
  • drush ctools-export-info: get an overview of all possible exportables
  • drush ctools-export-view: view one or more exportables
  • drush ctools-export: export all exportables to a module

Excited yet ? We are, so we made a screencast, we're pretty sure you'll love it. Damian and I are planning more things for the future, so anyone who wants to help can post issues to the sandbox. Once they're done, we can commit these easily now Damian has access. Let's make ctools drush extremely powerful!

Mar 19 2012
Mar 19

There are several ways to install XHProf on your mac in a MAMP environment. After a lot fails, the easiest way in my opinion is using Homebrew. The rest of the article assumes you already have this installed, so let's get to the XHProf install.

  1. Fire 'brew install autoconf' to make sure autoconf is installed.
  2. Fire 'brew install xhprof' on the command line. You might get an error downloading the pcre package (depending on your homebrew version):
    Error: Failure while executing: /usr/bin/curl -f#LA Homebrew\ 0.8\ (Ruby\ 1.8.7-249;\ Mac\ OS\ X\ 10.7.3) ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.12.tar.bz2 -o /Users/swentel/Library/Caches/Homebrew/pcre-8.12.tar.bz2
    In that case, go to https://github.com/mxcl/homebrew/blob/master/Library/Formula/pcre.rb and download that file into /usr/local/Library/Formula/ and run the command again from shell.
  3. The extension is now built and can be copied to your MAMP installation:
    cp /usr/local/Cellar/xhprof/0.9.2/xhprof.so /Applications/MAMP/bin/php/php5.3.6/lib/php/extensions/no-debug-non-zts-20090626/ 
  4. Go to your php.ini file in your MAMP installation and paste following code and restart MAMP.
    [xhprof]
    extension=xhprof.so
    ;This is the directory that XHProf stores it's profile runs in.
    xhprof.output_dir=/tmp

That's it. Should take you about 5 minutes. Took me a couple of wasted hours, but it's worth doing. And now you can finally toggle the XHProf option on the devel settings page in case you're working with Drupal.

Other resources about installing XHprof:

Jan 18 2012
Jan 18

I've blogged about this topic almost more than 3 years ago how I used a couple of drupal modules to send mails with images from my iPhone which automatically got posted to my site. But times change. I now own a Nexus One and one of my goals for 2012 is to write at least one decent mobile application. I experimented with Titanium first, but decided to go native for a couple of reasons, performance and size of app being the main reasons.

While I already have an official go for an application I can develop, I started with a simple use case to learn android application development: uploading images to my personal blog saving a new node. Especially the java part is as good as new to me, so starting simple is always the best advice. After 3 hours of Drupal hacking and a lot more Java reading and debugging, my first application is happily working on my own phone and I have cute Druplicon on my desktop.

The code is freely available (see below) consisting of 2 parts.

The Android part

The application is build at SDK version 10, so it should work on any Android 2.3 or higher. It might possibly work on lower versions as well. After installation of the application and the first run on your telephone, you will need to login. The app authenticates with a Drupal user and only stores the endpoint URL and the session cookie. The session cookie is send when uploading an image so we know exactly who's uploading. Besides selecting from the app, you can also go to your Image gallery, select an image and use the Share menu to drop the image to the application.

The layout of the application as the code is relatively simple, it probably doesn't follow the best practices of Java programming, so be gentle in case you start reviewing, I'm still learning :)

The Drupal part

The Drupal module - D7 only - is simple as well, but was less hard to develop. While I could 've used a combination of services and other modules, I decided to write a simple module with a single menu callback that accepts a request that can either authenticate a user or create a node with title, image and other keys. Once enabled, you need to go to 'admin/config/media/drupapp' and start configure following items:

  • The endpoint. Defaults to 'drupapp', but you can change this to your likings.
  • The image field name: this will immediately select the content type that will be used to save the node.
  • Published status: default status, handy if you want to review after upload.
  • Debug option: log the complete $_POST variable through watchdog for testing purposes.

You will need to grant permission on the permissions page as well. Best practice is to create a new role which only has the "upload images via app" permission, and that role does not necessarily need a permission to create nodes.

Combine the 2 technologies and you get Drupoid. What's in name right ? You can browse, fork and/or download the code at http://github.com/swentel/Drupoid. Feel free to modify it to your own needs. The app in its current version will never be made available on the Android market as it's really a personal project. But it might serve as a nice start example for your own adventures in mobile application land.

Jan 05 2012
Jan 05

By default it's not possible to override existing paths with Page manager, the excellent module that is bundled in the CTools project. The Page manager existing pages module now allows you to do that. Technically, this module defines one abstract task and one content type plugin, so menu items can be overridden and the original page callback can be called through the content type plugin. This project comes with one default existing page, which is 'node', the default Drupal frontpage.

Basically, you are now able to override any Drupal path in your installation and create variants for it. The module comes with one default existing page (although new ones might be added in future). Default contexts for entities is possible as well. I've created a screencast so you can see the module in action at http://www.youtube.com/watch?v=W-4g01WjwI4.

Oct 15 2011
Oct 15

Little than a week ago, I committed Renderable elements which enables you to register any piece of build in your Drupal 7 installation and manage that through Field UI. It will make additional fields available of existing entities on the manage forms/display screens or you can for example register the contact form, webform or (let's go crazy) the exposed filter form of a view and rearrange the fields with Field UI. Essentialy, the idea is that you can rip out all elements which are nested, also those inside the vertical tab on the node edit form for instance.

How it works

Currently, only forms are supported, support for any kind of other non entity display is coming soon. Once you enable the module, you can go to admin/config/system/rel/config and enable the registration link on top of forms. Now go to any form in your installation and you'll see a 'Manage form display' link on top. Clicking on the link will make the form available to manage. An overview can be found at admin/config/system/rel. In case you're registering a non entity form, this build will be inserted as a bundle into a new entity that's exposed by the module. This way, we can profit from hook_field_extra_fields to register any kind of element. Tricky ? Sure. Cool, oh yeah!

Any kind of custom registration is exportable thanks to CTools as well.

The power

The idea from the module came after the initial proof of concepts while working on forms support for Display suite. Soon after, an issue appeared as well in the Field group issue queue to make field groups available in other contexts than entities and the ability to rip out the elements that are nested inside vertical tabs. Of course, anything can be done with form alter, but our goal was to make this possible through Field UI. Now, we don't want to force people Field group and/or DS, so we decided to create a separate project, which also means there are no dependencies. If offers a lot benefits and the possibilities you have now are huge:

  1. Install this as a stand alone module and it will make any element on the form available like the Save/Preview/Delete button, vertical tabs etc.
  2. Install Field group and you can take control of existing field groups or add new ones on say the contact form.
  3. Install Display suite and you can now select a template file to manage the layout of registered forms, like webform etc.

Both modules (rel and ds_forms) still need cleanup, but also a lot of testing, so please test as much edge cases as you can and report back into the issue queue!

This might all seem a bit cryptic, so, we've recorded a screencast showing you the power of Renderable elements together with Field group and Display suite on node, contact, webform and views exposed filter forms.

Jul 30 2011
Jul 30

This is probably the number one feature request during the D6 cycle of Display suite: limit the number of items on a multiple value field, usually on images. This involves custom coding in the form of creating new formatters over and over again in code or using the Custom formatters module. The upcoming release of Display Suite for Drupal 7 now puts an end to this annoying limitation. All Field API fields with a cardinality set to unlimited or more than one get an extra textfield on the manage display screens to limit the output per field. I've recorded a short screencast to demonstrate that exciting new suble feature. A new release is scheduled this wednesday, so test and report any errors when found!

There are also 2 issues on d.o to get this feature into other modules:

Jun 18 2011
Jun 18

Ever since Display Suite came out, people always thought it was a competitor for Panels, which really isn't the case. I'm not going into that debate, both me and merlinofchaos know the facts. I've got better news instead. Apart from the fact that Panel layouts are already available through the Field UI, the Panel editor can now be used as well. That's right, if you are a Panels/Page manager user, you can now use that interface to manage the layout of any view mode of any entity in your Drupal 7 installation. Drupal display managemement just got slick!

The code is available in the 7.x-1.x version of Display suite as a submodule called Panel view modes. This is a call for testers to play around with the initial implementation to make sure this works well. Post features, bugs into the issue queue. Make sure you have the latest dev versions installed of CTools, Panels and Display Suite and post as much debug information and/or steps to reproduce for any problem you might find.

In the meantime, you can drool over the screencast, the real magic starts around 1:35 :)

May 23 2011
May 23

Display Suite has the ability to create custom fields, either through code or via the UI. Those fields can hold custom content or even PHP code. It is somewhat limited since one field can only have one type of content, unless your field has some crazy PHP code which is not easy to maintain. Those days are over now. You want to add custom content, a node, the logo or any other type on the Field UI screens? The upcoming release - 7.x-1.2 - comes with a new field called ctools field, which can hold any sort of content that is available through ctools' plugin system and which is configurable on the "Manage display" screens per entity, bundle and view mode. Think as of Panels, but in Field UI. And they are of course all exportable. This may all sound a bit cryptic to you, so I've recorded a screencast showing you how this works. Be amazed and watch out for the upcoming release of Display Suite somewhere next week!

May 09 2011
May 09

The 7.x-1.1 release of Display Suite comes with a couple of new exciting features:

  • Fivestar
  • More hooks and better views extendibility
  • Ability to hide the page title on full node view
  • Custom field templates via the UI

The last feature is better known as the feature for the field system. Or you can also call it semantic fields. The possibilities to theme entities through the Field UI have now become endless. I'll explain those changes with code and screenshots, which should convince you how powerfull and easy Display Suite can be for your website. And best of all, this is all exportable!

Display Suite Extras

The field templates feature is located in the Display suite extras module, so it isn't enabled by default. But once configured to run, all fields, in every entity/bundle/view mode, on the "Manage display" screens get the ability to change following properties of their output:

  • Label: a custom label, wrapper and classes
  • Styles: extra styles on the outer wrapper (except reset or expert)
  • Field template: select the default output function which can be registered with hook_ds_field_theme_functions_info(). 3 options are already available
    1. Default: this is the default Drupal core field output.
    2. Reset: a function which strips all wrappers.
    3. Expert: a function which enables you to have full control over
      • Outer wrapper, element and classes
      • Field items wrapper, element and classes
      • Field item wrapper, element and classes

Fancy pictures usually say more than words, so just take a look at the screenshots underneath to see how this looks in reality.

In case you're not satisfied with those 3 options, you can always create your own output function. It's a simple hook returning an array which keys are the function and values are used for the label in the select box on the Field UI screen. The function takes 2 parameters, namely the $variables from the field the $config variable which holds specific information about the field itself.

<?php
/**
* Implements ds_field_theme_functions_info().
*/
function example_ds_field_theme_functions_info() {
  return array(
'theme_example_field' => t('Example theme field'));
}
/**
* Field theming function.
*/
function theme_example_field($variables, $config) {
 
$output = ''// Render the items without wrappers and label.
 
foreach ($variables['items'] as $delta => $item) {
   
$output .= drupal_render($item);
  }  return
$output;
}
?>

And that's it. Theming your entities has never been so easy in Drupal 7. If you want to try out yourself, go to http://drupal.org/project/ds and download the latest stable release. Happy theming! If you're interested, please support our session at the upcoming DrupalCon London and talk with us maintainers for tips and tricks!

Feb 19 2011
Feb 19

Drupal 7 introduced entities. It's such a great concept, I'm able to easily port Views displays - part of Display suite - to Drupal 7. It is now part of the main package, bundled in a sub module called Display suite Extras, which also includes the 'region to block' and 'switch view mode on a per node basis' features. More goodies, less code, even more power. But back to Views, entities and overriding templates.

For those who don't know exactly what I'm talking about, a quick summary. In the Drupal 6 version of Views displays, you're able to select a single display of a view and rearrange the template variables so you don't have to override the views-view.tpl.php template file. It uses the drag and drop screen that Display suite comes with, but for D7 we decided to use the manage display screens that Field UI provides. This is great because it supports all entities, so any entity that is fieldable use the same forms in which we simply inject our extra regions. However, Views is not an entity, but in comes hook_entity_info to the rescue!

To make sure we can use the Field UI forms, we declare our own entity called 'ds_views', which is not fieldable and only has one default bundle.

<?php
/**
* Implements hook_entity_info().
*/
function ds_extras_entity_info() {  // Register a views entity on behalf of Views.
 
$return = array(
   
'ds_views' => array(
     
'label' => t('Display suite Views'),
     
'bundles' => array(),
    ),
  );
  return
$return;
}
?>

So now that we have an entity, we create our own menu callback function which will ask for the field ui form. Display Suite will call all additional fields and add the layout options too.

<?php
function ds_extras_vd_field_ui() {
 
module_load_include('inc', 'field_ui', 'field_ui.admin');
 
$build = drupal_get_form('field_ui_display_overview_form', 'ds_views', 'views', 'default');
  return
$build;
}
?>

However, when calling the Field UI form, we'll get a message saying this entity does not have not any fields. To solve that problem, we can implement hook_field_extra_fields and return one field. In this case, the title will be overridden later on because we also implement hook_ds_fields() which will return our fields for views. 

<?php
/**
* Implements hook_field_extra_fields().
*/
function ds_extras_field_extra_fields() {  // Register a single field so fields for vd be picked
  // up nicely in the display overview form.
 
$extra['ds_views']['views'] = array(
   
'display' => array(
     
'title' => array(
       
'label' => t('Title'),
       
'description' => t('Title'),
       
'weight' => 10,
      ),
    ),
  );  return
$extra;
}
?>

In the screenshot you see a couple template variables which you can now put into the regions of the chosen layout.

Impressive isn't ? Hacky ? Well .. maybe a little bit. There is even more code, because now the combination of a view and a display is recorded as a bundle within the entity I just created above. I've recorded a short screencast so you can see it in action. If you want to try it yourself, download the second alpha release of Display suite for D7 and have fun!

Jan 26 2011
Jan 26

Drupal 7 is out. Even before the release, the community already started thinking what should happen for Drupal 8, we're just too excited to keep on working! Keeping track of which bugs, tasks and feature requests should be developed is gathered from a lot of sources and eventually - not always - created as an issue in the Drupal Core issue queue. Looking at the size of that queue, we already have a lot of work, most of which are tasks/bugs/follow ups which didn't make into Drupal 7.

New features will obviously come up: proposals and discussions are found on blogs, groups.d.o and Community initiatives. Brainstorm sessions happen at Drupalcons, IRC, local gatherings of Drupal enthousiasts or even surveys. Tracking all this activity and the current work is really hard, probably nearly impossible for every single person on this planet. Also, issues marked as critical give a false sense to me sometimes since the spectrum of things to fix is simply to wide and not focused on making sure a single piece of code is 100% A-OK. You can bookmark several URL's which lists issues based on tags (performance, theme, favorite-of-dries ..), components (node module, etc), priorities (major, critical) and so on. Simply too much to handle for one person.

What's next ?

The biggest personal issue I have, is that I'm not certain by any means what will be in the next release. As an example, take a look at the feature list for Fedora Core 15. It gives me a clear overview what I can expect the next time I'll be updating my development machine(s). I'm able to read a full description, track changes and see the progress of every single feature. That's nice and comforting for me. I would really like to see such an overview for Drupal core too. It would allow me to choose in which areas I want to be involved in and I can rely others to work on area's I'm less familiar with. A nice list like this would finally bring an end to the phrase "when it's ready" on the question when a new Drupal core sees the light.

So what if we started developing Drupal 8 in an agile way, using Scrum or - our favorite at work nowadays - Kanban ? The latter allows us to bend the rules much more in a way that it would fit our situation, in our case, a gigantic community spread all over the world. What do we need and how could we possibly achieve this so we can throw out another kick ass release ?

Roles

In an agile process, several roles are defined each having their responsibilities. Most are known, but we'll define them for our excercise.

  1. Product owner: In some way, everybody owns the product as we all have our ideas. But Dries, at the very end, decides which new features need to be in the next major release and what's left out.
  2. Project managers: Together with Dries, the core committers who test the stories, make sure sprints are delivered on time, discuss and resolve problems towards developers, consulting both the latter as the PO.
  3. Scrum master(s): This is the hardest task. They are responsible to solve problems on the story level, report to PM and PO, guide developers and testers, solve interrelational problems. Experienced people who know how Drupal Core works already, not necessarily on on every level, should be appointed for this role.
  4. Developers: the community. And boy, are we lucky, we have a gigantic pool of resources. But this does not only include hard core coders. People who like design, user experience, information architecture etc. must be involved at all times too. We've seen a lot of good input from a lot of those types, but we need more, a lot more!
  5. Testers: We have a great test bot. But it can't beat every day point and clicking by the average user who will use the product on a daily basis. However, it's ridiculously easy to come up with use cases nobody has never thought of during the process, the clue will be to filter out the critical ones. 

Release planning

Before we all start coding on new things, let's try and find out what the product owner wants to see in the next release. Obviously the PO will have some wishes and as identified above, we already have a big backlog, but priorities are not always clear. In this planning, this should be made clear what is really necessary to be picked up first. Because, the sooner this is done, the better we can focus on the nice to haves. A closing deadline always brings bad advice!

Planning this meeting is not going to be easy for the scrum master. A workable solution is an IRC session on a time it fits for the biggest amount of people, and still, even then some will not get up at night to participate. This can be tackled that already a number of spoke persons stand up voluntarily so they can express the wishes and conceirns from the community. Important is that there can't be a big discussion on technical level, there's just need to be an agreement on a fairly abstract level. Stories are written with a rough estimation, tasks can be assigned, but this not necessary during this meeting. 

Backlog filling

Sprint planning

This meeting should define the primary goal to achieve towards the end of the sprint. It's important that stories in this sprint which do not lead to the success of the sprint are picked up later. This means that a sprint can contain critical, normal and low priority stories! A Drupal core sprint should at least be 2 months, we're still working with volunteers using their free time, and sometimes company time to make things better. At this point, issues can be assigned to a story which make sure we have a deliverable in which the PO, but in the end everyone is comfortable with. Once all is decided, we can start coding and try to make sure we keep up with what is planned. Change requests can occur - read, will happen -  but they should be put in our backlog and be picked up into the following sprint.

Moving stories to a sprint

Adding tasks to the Entity story

Adding tasks to the story

Tools

The screenshots above are taken from the great http://kanbantool.com/ website, which we introduced at Krimson - after a great learning process during my period at One Agency - use on a daily basis for clients, but also for our community work, whether it's maintaining or porting our Drupal modules, organising events etc. The project module already does an amazing job and I think with some really - relatively simple - changes we could make a more visualized and targeted picture of the path Drupal is taking. A board like I mentioned aboved for the Fedora Core release would be the great step. Being able to create meta-issues (stories) and reference other issues (tasks) with eachother is something I would gladly help to write patches for - in an agile fashion of course .. ;)

Will this work ?

To be honest, I think it could. But it won't be easy, but with the right spirit and good leadership, something like this could be achievable. Besides, how extremely cool would it be to tell we're the first community that would work like this - unless there are others, feel free to correct me. But in the end, just knowing what to expect in the next release would make a lot of people feel a lot more at ease.

Dec 21 2010
Dec 21

Let's start with a little Jeoporday quiz!

Answer: There's a module for that, just look it up on d.o.
Question: How can I get this functionality on my website ?

More and more posts on the web are showing up with 'The top x modules you should always install', someone else even created a website for the answer. It's hard to keep up with the new releases everyday, it's sometimes even harder to find out the exact use case why a new module even gets released - although I respect the author because he's contributing, don't get me wrong on that one.

The selection criteria

There are many reasons to pick a module:

  • Deadlines: the functionality is there and the project has to be delivered on time.
  • Workflow: development teams try to work as uniform as possible on every project.
  • Lazyness: why bother writing a functionality yourself (even it you only need one function from a giant module).
  • Strong API: it helps the developer in custom modules or in deployment strategies.
  • PM has found it on the web. I'm dead serious on this one. I've had cases where I had to start on a site where I got the modules picked for me, without even consulting me.

There are other reasons obviously, but what strikes me is that from experience (I'm guilty too) and from a lot of discussions with all kinds of people (developers, project managers, etc), the gap between what the developer needs and the client actually wants has become bigger and bigger. I'm not sure why this is exactly happening, but it can have serious consequences when going live with a project.

The kitten paradox

The Drupal world has this paradigm that you shouldn't hack Drupal core or God kills a kitten. Even worse, Dries too nowadays. This somehow extends to Contrib too, since well, everytime you need to update, you'll have to make sure you have your patches ready. But what about this: every time you're using more than a 100 modules, mankind has killed a lot of kittens by having to install additional load balancers, reverse proxies, web and database servers for keeping the site up if it's a really busy one, especially with authenticated users. Adding hardware because the site is not performing well is - in a lot of cases - not the right answer.

Back to basics

Every project is unique and building a big project should really be evaluated before and - even more important - during the development process, with great care on how the site behaves in a real life situation, investigating the amount of queries, PHP memory, generation time and so on. That's not something you can do at the end. It's simply too late at that point and a lot of kittens have died already. There are great profiling tools in Devel and Xdebug should be your friend all the time. Be sure to use them all the time.

So, depending on the needs, it might be more interesting to write a simple custom module and write PHP yourself again, using either PHP or API functions available in Drupal core. Every developer should've least opened up the includes folder and scanned every file in it. I'm still amazed now and then, even after all those years. Even with Drupal 7 almost out, a lot of people seem scared because Contrib is not entirely ready yet. That's a pity, because there is some amazing stuff under the hood and you'd be pretty surprised how much you can pull off with only Drupal core, PHP and - especially - a lot of developing fun.

Answer: That should be api.drupal.org and php.net.
Question: Which bookmarks should I really have ?

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