Main menu

Secondary menu

Extending Drupal's Context Module: Custom Condition Based on Field Value

Fri, 02/03/2012 - 11:45am -- Andy

We use the context module for Drupal in every site we build. It's a great way to do things like create separate "sections" of a site, with different behaviors and layouts based on an arbitrary set of "conditions" or triggers. For example, we may want Blog posts to have a different layout than other parts of a site.

In a current project, we needed a condition not supplied by context by default. Thankfully, it's pretty painless to extend context with custom conditions. An article from OpenSourcery pointed us in the right direction, and an article from Treehouse Agency gave us a Drupal 7 example, but otherwise we didn't find a ton of documentation out there, so we thought we'd share our technique.

To quote from the context API, adding a new condition (or reaction) is a 4-step process:

Implement `hook_context_registry()` to define your conditions and/or reactions and map them to plugins.

Write your condition or reaction plugin class.

Add in a Drupal integration point for your plugin.

Our example: Add a context condition that checks against a specific field's value

Our site provides a field to content editors for many node types that lets them select a layout for the node. The field is of the "List (text)" type with only a few, known values. We want to add a context condition that checks against the value of the node field, and can then react in many ways.

Step 3: Write the condition plugin class

This code goes in your plugin file. As defined in mymodule_context_plugins above, this file should be in your module's directory, and be named "mymodule_context_condition_myfield.inc".

/**
* Expose the myfield field value as a context condition.
*/class mymodule_context_condition_myfield extends context_condition {function condition_values(){$values=array();// Get the allowed options from our field, and return these to context// as the values for our condition.$field= field_info_field('field_myfield');$field_values= list_allowed_values($field);foreach($field_valuesas$field_key=>$field_value){$values[$field_key]= check_plain($field_value);}return$values;}function execute($node){// Grab the value this node has stored for our field.if($items= field_get_items('node',$node,'field_myfield',$node->language)){// See if any of the field's values satisfy the condition.foreach($itemsas$item){foreach($this->get_contexts($item['value'])as$context){$this->condition_met($context,$item['value']);}}}}}

Step 4: Add a Drupal integration point for the plugin

You might hook into Drupal at any number of different points. We want to check our condition when viewing nodes, so hook_node_view is a good choice.

This is a cool example of how to create a custom condition, but instead of creating a custom field of predefined options and then creating a custom condition to display different contexts based on the selected option in that field, why wouldn't you just use Taxonomy? Using a taxonomy vocabulary to select the layout would be easier, since taxonomy terms are already a built-in condition.

Yep, if taxonomy works for your use case, save yourself the trouble of writing any custom code! But there are any number of ways you could extend context -- hopefully this example gives you some ideas.

In the condition_values function in step 3, you'd want to get the condition values from the session variable. In the execute function in step 3, you'd want to iterate over your variable(s) rather than the field values from our example above.

And in step 4, you'd want to find the right hook to actually check the condition based on whatever you're doing with that information (i.e. when you want your context to fire its reactions based on your custom condition from the session variable).

I hope that helps. Post back here with your results if you get a chance!

As with all of the chaos based solutions, it seems that you must include a hook_ctools_plugin_api declaration. I am not entirely familiar with context, but I believe that it uses the ctools plugin system.

I wonder if it makes sense to start a chaos fork of Drupal so that these things can be integrated into the core.