Drupal 7 – Dynamic select options for Webform

Webform is a great module in Drupal which help collecting user data. Recently i am working on a new website which needs a webform and one of the field is a selection list contains the node titles of a specific content type. I found a blog post about this dynamic select options feature in Drupal 6 by creating a custom module.
xebee – Drupal Webform : Add a dynamic select option list

Here is a similar approach for Drupal 7.

1. Create a new directory named as webform_options with the following 2 files inside.
webform_options.info

; $Id$
name = Webform options
description = Preset options for webform field
package = "Eureka"
core = 7.x
version = 7.x-1.0

 

webform_options.module

<?php

/**
 * Reference: http://xebee.xebia.in/2011/06/14/drupal-webform-add-a-dynamic-select-option-list/
 * The following piece of code is based on the blog post above written by Anubhav
 */

function webform_options_webform_select_options_info() {
  $items = array();
  if (function_exists('_get_node_titles')) {
    $items['node_titles'] = array(
      'title' => t('Node titles'),
      'options callback' => '_get_node_titles',
    );
  }
  return $items;
}

function _get_node_titles() {
  $options = array();
  $sql = "SELECT nid, title FROM {node}";
  
  $result = db_query($sql);
  foreach ($result as $row) {
    $options[$row->nid] = $row->title;
  }
  return $options;
}

 

2. Enable the module and add a new webform field.

 

3. In the webform field setting page, pick Node titles for Load a pre-built option list. In addition, check the Listbox checkbox under Display as we want to have a selection list instead of radio button.

 

4. Save the form and you now have selection list which contains all node titles. If you want limit the options to a specific content type, just modify the SQL in webform_options.module.

 

Done =)

Reference: xebee – Drupal Webform : Add a dynamic select option list

About these ads

60 thoughts on “Drupal 7 – Dynamic select options for Webform”

  1. Hi,
    this tip works great but does not fit an additonal effort I have:

    I have an event with multiple dates (date field, with multiple dates allowed).
    Now I want to display each date with its eventname in options list.

    E.g.: event 1 is on two dates, event 2 on 4.

    23|event 1 – 1.1.2012
    23|event 1 – 1.3.2012
    24|event 2 – 1.1.2012
    24|event 2 – 3.1.2012
    24|event 2 – 15.1.2012
    24|event 2 – 22.1.2012

    By the way, can I change the safe_key to something else then the nodes id?

    Like

    1. This can be done. But instead of querying the data by SQL, it is better to use the EntityFieldQuery to query the node data.

      Here is an example

      function _get_activity_codes() {
        // Get all published activity nodes
        $query = new EntityFieldQuery();
        $query->entityCondition('entity_type', 'node')
          ->entityCondition('bundle', 'activity')
          ->propertyCondition('status', 1);
        $result = $query->execute();
      
        $options = array();
        if (isset($result['node'])) {
          // Load all activity nodes into $activities
          $activity_nids = array_keys($result['node']);
          $activities = entity_load('node', $activity_nids);
      
          foreach ($activities as $activity) {
            // For each activity, set a key value pair for selection list options
            // where $activity->nid is the option key and
            // the first value of field_activity_code is the option value.
            $options[$activity->nid] = $activity->field_activity_code['und'][0]['value'];
          }
        }
        return $options;
      }
      

       

      In you case, you need to add one more for loop for retrieving multiple date values for each event.

      Hope this help.

      Like

      1. Hi, this sound great. Just to be sure: if I use this way, will I get one Row for each event with all the dates in this single row, or is it possible to get one row for each pair of event and date? This is what I need.

        Thanx again!

        Like

  2. OK, got it ;-)
    In my case (as I just need the start date) I need something like

    function _webform_options_get_story_nodes() {
    
      // Get all published activity nodes
      $query = new EntityFieldQuery();
      $query->entityCondition('entity_type', 'node')
        ->entityCondition('bundle', 'seminare')
        ->propertyCondition('status', 1);
      $result = $query->execute();
    
      $options = array();
      if (isset($result['node'])) {
        // Load all activity nodes into $activities
        $activity_nids = array_keys($result['node']);
        $activities = entity_load('node', $activity_nids);
    
        foreach ($activities as $activity) {
          $var_countings = count($activity->field_myfield['und']);
          for($count = 0; $count nid . '-' . $count] = $activity->nid . '-' . $activity->field_myfield['und'][$count]['value'];
          }
        }
    
      }
      return $options;
    }
    

    Like

  3. Thanks a lot for this posting, really nice and understandable, but nonetheless I got stuck with a similar problem like Kaion:

    I’ve got an event-node-type with date-field and want the dates to appear on the webform select list. But all I am able to get are the node-titles of the according nodes to be displayed on the webform-dynamic-select-list (and all other information, which are stored in the (mysql-)node-table like language, node creation-date etc.). I have been searching for a solution on the internet for hours, but can’t find any solution :(.

    I guess I need to load the date-data from my (mysql-)_field_termim_datum-table for each node, but can’t figure out how. Do you know how? Thanks a lot in advantage!

    Like

    1. Hi John, you dun’t need to load the data from the database. Just make use of the EntityFieldQuery and you retrieve all fields data of your selected nodes. In your case, the code should be sth like

      function _get_event_termin_datum() {
        // Get all published event nodes
        $query = new EntityFieldQuery();
        $query->entityCondition('entity_type', 'node')
          ->entityCondition('bundle', 'event')
          ->propertyCondition('status', 1);
        $result = $query->execute();
      
        $options = array();
        if (isset($result['node'])) {
          // Load all event nodes into $events
          $event_nids = array_keys($result['node']);
          $events = entity_load('node', $event_nids);
      
          // Check all field data of $events for debug
          // print_r($events)
      
          foreach ($events as $event) {
            // For each event, set a key value pair for selection list options
            // where $event->nid is the option key and
            // the first value of field_termim_datum is the option value.
            $options[$event->nid] = $event->field_termim_datum['und'][0]['value'];
          }
        }
        return $options;
      }
      

       

      Does it work for you?

      And you can find more details about EntityFieldQuery in the following post
      Drupal 7 – Get specific nodes using EntityFieldQuery

      Hope this help. =)

      Like

  4. Has anyone had problems getting the list to display in the Load pre-built option list? After installing the custom module and following the steps, I still have not yet been able to display the custom pre-built list in the “Load pre-built option list” dropdown. Any suggestions?

    Like

      1. Hey ykyuen,

        No luck when printing a string inside the _get_node_titles() function. But the module is appearing and enabled in the modules list. Any idea why it would not be running?

        Like

      2. Hey ykyen,
        My module is in the folder: webviewssel
        which contains: webviewssel.info webviewssel.module
        This is what I have for my .module file which is named webviewssel.module:

        function webform_options_webform_select_options_info() {
          $items = array();
          if (function_exists('_get_node_titles')) {
            $items['node_titles'] = array(
              'title' => t('Custom Countries'),
              'options callback' => '_get_node_titles',
            );
          }
          return $items;
        }
        
        function _get_node_titles() {
         $countries = array(
            t('Europe') => array (
              'nl' =>  t('The Netherlands'),
              'be' =>  t('Belgium'),
              'fr' =>  t('France'),
            ),
            t('Africa') => array (
              'tu'  =>  t('Tunisia'),
              'sa'  =>  t('South Africe'),
            ),
            t('Asia') => array (
              'ru'  =>  t('Russia'),
              'cn'  =>  t('China'),
            ),
            'key' => t('some country that is in no group'),
          );
          return $countries;
        }
        

        My webviewssel.info just has:

        name = Webform Views Select
        description = This module will be used to create selection options from a view.
        package = “Webform”
        core = 7.x
        version = 7.x-1.0

        Like

      3. Rename the function webform_options_webform_select_options_info() to webviewsse_webform_select_options_info()

        Drupal makes use of the hook mechanism which is a kind of Inversion control. The above function is based on the hook_webform_select_options_info(). When you implement the hook, you have to replace the hook_xxx with <module name>_xxx.

        Like

  5. Hi ykyuen, thanks for your explication.
    i have done everything you listed.

    i’ve created in (..sites/all/modules/) a new directory named as webform_options.

    and i’ve created the 2 files inside, even with the same name,

    but when i go to the admin->modules->
    i cant find my new module to activate it, what im doing wrong?
    thanks again.

    Like

    1. Replace the webform_options.module by the following one.

      <?php
      
      /**
       * Reference: http://xebee.xebia.in/2011/06/14/drupal-webform-add-a-dynamic-select-option-list/
       * The following piece of code is based on the blog post above written by Anubhav
       */
      
      function webform_options_webform_select_options_info() {
        $items = array();
        if (function_exists('_get_node_titles')) {
          $items['node_titles'] = array(
            'title' => t('Node titles'),
            'options callback' => '_get_node_titles',
          );
        }
        if (function_exists('_get_timezones')) {
          $items['timezones'] = array(
            'title' => t('System timezones'),
            'options callback' => '_get_timezones',
          );
        }
        return $items;
      }
      
      function _get_node_titles() {
        $options = array();
        $sql = "SELECT nid, title FROM {node}";
        
        $result = db_query($sql);
        foreach ($result as $row) {
          $options[$row->nid] = $row->title;
        }
        return $options;
      }
      
      function _get_timezones() {
        $zones = system_time_zones();
        return $zones;
      }
      

      You could find the System timezones in the pre-built option list

      Like

  6. Hi I’m not that savvy with code…could you let me know how to just select a specific content type. I know your mentioned that one would just modify the code in the module, but I just dont know what to ‘modify’!…thank you.

    Like

    1. Replace the <content type machine name> with your content type machine name.

      <?php
      
      /**
       * Reference: http://xebee.xebia.in/2011/06/14/drupal-webform-add-a-dynamic-select-option-list/
       * The following piece of code is based on the blog post above written by Anubhav
       */
      
      function webform_options_webform_select_options_info() {
        $items = array();
        if (function_exists('_get_node_titles')) {
          $items['node_titles'] = array(
            'title' => t('Node titles'),
            'options callback' => '_get_node_titles',
          );
        }
        return $items;
      }
      
      function _get_node_titles() {
        $options = array();
        $sql = "SELECT nid, title FROM {node} WHERE type = '<content type machine name>'";
        
        $result = db_query($sql);
        foreach ($result as $row) {
          $options[$row->nid] = $row->title;
        }
        return $options;
      }
      

       

      See if it works for u.

      Like

  7. Thank you for the tutorial! The instructions for how to do this in the official Webform documentation failed me, but this worked great!

    Like

  8. Thank you so much for the tutorial! Very helpfull!! Now I already managed to have a dropdown of the titles of a certain content type. But now i’m struggling with the multilanguages… Is there a way to show only the node titles of the language that is active for the user (and hide the titles of the other 2 languages)

    I already used the code you suggested to Collin and works great! I’m trying to add a line with something like global $language; or $lang_name = $language->language; but I don’t seem to manage to get it right…

    All suggestions / help are very welcome!

    Thanks in advance!

    Like

    1. OK tried to make it work but no succes untill now. The following code gives me the least errors for now, but still pretty massiv… testsite crashed…

      I’m pretty new to coding like this. Anybody an idea what is going wrong?

      <?php
       
      /**
       * Reference: <a href="http://xebee.xebia.in/2011/06/14/drupal-webform-add-a-dynamic-select-option-list/" rel="nofollow">http://xebee.xebia.in/2011/06/14/drupal-webform-add-a-dynamic-select-option-list/</a>
       * The following piece of code is based on the blog post above written by Anubhav
       */
       
      function webform_options_webform_select_options_info() {
        $items = array();
        if (function_exists('_get_node_titles')) {
          $items['node_titles'] = array(
            'title' => t('Node titles'),
            'options callback' => '_get_node_titles',
          );
        }
        return $items;
      }
       
      function _get_node_titles() {
        $options = array();
        $sql = "SELECT nid, title FROM {node} WHERE type = 'seminaries' ';";
         
        $result = db_query($sql);
        foreach ($result as $row) {
       	global $language;
      	$lang_name = $language->language; 
          $options[$row->nid] = $row->title;
        }
        return $options;
      }
       

      Like

      1. Forgot to mention: I have a content type ‘seminaries’ and a multilingual site (3 languages)… What I’m trying to do is generate a list of the node titles, but only thos from the user’s active language must be shown, the rest will be hidden (whereas now everything was shown)

        Like

      2. Allright!! I’m very sorry for all the spamming, but finally found the way. Here’s the code that did the trick for me

        <?php
         
        /**
         * Reference: <a href="http://xebee.xebia.in/2011/06/14/drupal-webform-add-a-dynamic-select-option-list/" rel="nofollow">http://xebee.xebia.in/2011/06/14/drupal-webform-add-a-dynamic-select-option-list/</a>
         * The following piece of code is based on the blog post above written by Anubhav
         */
         
        function webform_options_webform_select_options_info() {
          $items = array();
          if (function_exists('_get_node_titles')) {
            $items['node_titles'] = array(
              'title' => t('Node titles'),
              'options callback' => '_get_node_titles',
            );
          }
          return $items;
        }
         
        function _get_node_titles() {
        	global $language;
        	$lang_name = $language->language;
        	
        	$options = array();
        	$sql = "SELECT nid, title FROM {node} WHERE type = 'seminaries' AND language = '" . $lang_name . "';";
        	$result = db_query($sql);
        	foreach ($result as $row) {
        		$options[$row->nid] = $row->title;
        		}
        		return $options;
        		}
         

        Thanks again ykyuen for the code!

        Like

  9. This has been immensely helpful after many hours of painful attempts at getting webforms to work for my needs. That said, I’m still stuck. Perhaps you can help?

    Here’s my situation:
    I have three webforms for three class sign-ups. At this point I’ve given up on using a single view output to work for all three, so I have three class content types (one for each class). I need to add all three types to my webform options as a select list in each form.

    This code works wonderfully for adding one type of node to the select list options, but when I try to duplicate the initial module to use for the second two lists, it breaks.

    I’m extremely ignorant with regards to PHP so I’ve no idea how to change the code to work for me. Does any of this make sense?

    Like

    1. Can you follow the syntax highlight and post your code here?

      Can you you give me more details on the logic you want to have?

      Is that you want to have 3 webforms and each on the want to have a preset select option list of different values?

      Like

  10. hi, it is possible if there are 2 date field, once the first date field are selected, the second date field will auto select a date which is 2 years/month later of the first date field, thx.

    Like

  11. Hi, great post, very helpful. I’ve got an immediate problem needing a solution, sorry off topic a bit from your original, wondering if you could give a heads up.

    I have a webform with a picklist that specifies dept. Rather than the user having to set which dept this form originates, i’d like that set via a passed parameter on the menu URL. So for example, in Dept X webpage, the menu URL for the webform has a parameter that is used to set the value of the dept pick list on the form (ie from Dept X). That way i can hide the list and each form has its orginating dept set based on where on the website it originates.

    Like

  12. Hi, I’m really grateful to find this article. I’m wondering if you could help me set default values for the node titles from the URL. somewhat similar to nodereference.

    thank you

    Like

  13. I am trying to add configurable options to this module. The API for hook_webform_select_options_info() says that you can provide an “options arguments: Any additional arguments to send to the callback.”

    How do you set values of options arguments – as an array or a string? Also, whichever way I set the arguments, I am not able to access them in the callback function. How should the arguments be accessed inside the callback function?

    Thanks for the gr8 post.

    Like

    1. The options argument could be set in this way.

      function webform_options_webform_select_options_info() {
        $items = array();
        if (function_exists('_get_node_titles')) {
          $items['node_titles'] = array(
            'title' => t('Node titles'),
            'options callback' => '_get_node_titles',
            'options arguments' => array('hello', 'world'),
          );
        }
        return $items;
      }
      

      And your call back function should look like this

      function _get_node_titles($arg1, $arg2) {
        // Your code
      }
      

      Like

      1. I tried that out. I set up ‘options arguments’ with array(‘hello’, ‘world’) and then I write the _get_node_titles() as:

        function _get_node_titles($arg1, $arg2) {
          $options = array();
          $options[$arg1] = $arg2;
          return $options;
        }
        

        Now I get the error “Warning: Illegal offset type in _get_node_titles()”.

        Trying to print $arg1 in _get_no_titles() returns something like: Array ( [nid] => 2 [cid] => 1 [pid] => 0 [form_key] => select [name] => select [type] => select [value] => [extra] => Array ( [items] => 2|Get a Quote 3|test 1|Welcome to Base D7 [options_source] => node_titles [multiple] => 0 [title_display] => before [private] => 0 [aslist] => 0 [optrand] => 0 [conditional_operator] => = [other_option] => [other_text] => Other… [description] => [custom_keys] => [conditional_component] => [conditional_values] => ) [mandatory] => 0 [weight] => 0 [page_num] => 1 )

        And trying to print $arg2 returns 1.

        I am running on Drupal 7.22 & webform 7.x-3.19.
        Could that be a bug with webform?

        Regards.

        Like

  14. I tried it out. Doesn’t seem to be working. This is what I did – in hook_webform_select_options_info() I pass the arguments with the key ‘callback arguments’ (& not ‘options arguments’) and then set it to array(‘hello’ => ‘world’). In the callback function, I add four arguments to the signature (as per the post you mentioned) and the last one should contain the passed arguments. But, the fourth argument is nothing but an empty array. Also, nothing is returned when I set the key in the hook to ‘options arguments’, not even an empty array. The first argument returns the webform component information only, the second & third arguments return 1.

    However, I got a work around which is working. Since, in hook_webform_select_options_info() the ‘options callback’ can be set to the name of the callback function (as string) only and the ‘options arguments’ is not working as desired, create as many items as you require and then for each of the ‘options callback’ pass a lambda function using the create_function, which essentially returns the name of the function created and executes when called.

    My code looks something like this:

    <?php
    function webform_options_webform_select_options_info() {
    
      // get all content types
      $node_types = array_keys(node_type_get_names());
    
      $items = array();
      // for each of the content types, create an item
      foreach($node_types as $ntype){
        // returns function names as lambda_1, lambda_2, ...
        $callback_func = create_function('', 'return _get_node_titles("'.$ntype.'");');
        $items[$ntype] = array(
          'title' => t('Node: ' . $ntype),
          'options callback' => $callback_func,
        );
      } // foreach
      return $items;
     
    } // webform_options_webform_select_options_info()
     
    function _get_node_titles($node_type) {
     
      $options = array();
      $sql = "SELECT nid, title FROM {node} WHERE type = '$node_type'";
      $result = db_query($sql);
      foreach ($result as $row) {
        $options[$row->nid] = $row->title;
      }
      return $options;
      
    } // _get_node_titles()
    

    Like

      1. Hi KN,

        I have fixed your code snippet in the above comment. good to know that you have solved the problem and thanks for your code. =D

        Like

  15. If I want to appear directly in the webform each page, without requiring the user to specify option list
    How to write code

    Like

  16. I want use to different webform nid, load a different Dynamic select options
    -How get to different webform nid
    -How use to?

    Like

    1. You can add different select options list in the return $items inside the hook_webform_select_options_info() function. Then you can edit different webforms and bind different select options list.

      Like

  17. The tutorial is fantastic! but i have a problem that doesn’t get solve…I need that VALUE is the title and the KEY is the email

    I need help please!! :(

    Like

    1. You could write your own function in the “options callback” which returns the key value pair.

      function webform_options_webform_select_options_info() {
        $items = array();
        if (function_exists('_get_node_titles')) {
          $items['node_titles'] = array(
            'title' => t('Node titles'),
            'options callback' => '_get_node_titles', // write your own call back
          );
        }
        return $items;
      }
      

      Like

  18. Hi,

    I have added this code and module and have it working as designed. However, the content type I am trying to display contains items that need to be displayed based on permissions. That is, I would like my “Programs” select list to only include items that the current user has permissions to view. Right now, every “program” is shown to all users. For my case, I am designing a registration form and I’d only like Anonymous users to be able to sign up to Programs that they have been given permission to sign up for.

    My current code is this:

    function _get_node_titles() {
     
      $options = array();
      $sql = "SELECT nid, title FROM {node} WHERE type= 'programs'";
       
      $result = db_query($sql);
      foreach ($result as $row) {
        $options[$row->nid] = $row->title;
      }
      return $options;
    }
    

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s