2

I'm trying to create a webform on my node programmatically so that I can set it up to be used as for a specific scenario. What I wanted to do is have all of the components my client want to appear automatically, but also default to specific settings for user entry, email specific users and validation rules etc, because they are going to have the same setup for each one, and they aren't going to want to write their setup out every single time.

I was using the Webform Default Fields module, but I know that this only works with the components, and not the setup. So I got rid of it and started writing my own version, with big help from this answer to get me as far as I am right now. But I'm struggling to find the correct format of how to write in a conditional statement, or how you would set the settings for the webform.

My current code is as follows:

function mymodule_node_insert($node) {
  if ($node->type == 'event') {
    _abstract_webform_components($node);
  }
}

function _abstract_webform_components($node) {
  $components = array(
      0 => array(
        'name' => 'First name',
        'form_key' => 'first_name',
        'type' => 'textfield',
        'mandatory' => 1,
        'weight' => 1,
        'pid' => 0,
        'extra' => array(
          'private' => 0,
        ),
      ),
      1 => array(
        'name' => 'Last name',
        'form_key' => 'name',
        'type' => 'textfield',
        'mandatory' => 1,
        'weight' => 2,
        'pid' => 0,
        'extra' => array(
          'private' => 0,
        ),
      ),
    );
      // etc etc

  webform_ensure_record($node);
  foreach($components as $component) {
    $component['nid'] = $node->nid;
    $component['extra']['title_display'] = 'inline';
    $component['extra']['locked'] = 1;
    $node->webform['components'][] = $component;
    webform_component_insert($component);
  }

  // Retrieves information about the author
  $author = user_load($node->uid);
  // Adds the author of the node as the default email recipient
  $email = array(
    'nid' => $node->nid,
    'email' => $author->mail,
    'subject' => 'default',
    'from_name' => 'default',
    'from_address' => 'default',
    'template' => 'default',
    'excluded_components' => array(),
  );
  webform_email_insert($email);

  $validation = array(
   'validator' => 'max_words',
   'action' => 'add',
   'nid' => $node->nid,
   'rulename' => 'Maximum Abstract Length',
   'rule_components' => array(
     1 => '1',
   ),
   'data' => 300,
  );
  webform_validation_rule_save($validation);

  }

Basically I'm missing the correct notation for how you add a condition to the webform but I have the right command to insert it. Also, I have the notation for how I want to setup my webform settings, but I don't know how to apply it

Many Thanks

EDIT

I've got one half of it, I've managed to add the conditional statement into the code, I was actually using the wrong code, but I managed to find a proper example of how the array needs to be written, edited the code above

3 Answers 3

1

I had a similar requirement :

The site will have some landing page contents and the site owner can add those contents at different times, and once a content of type landing_pages will be created some blocks (already created) will get enabled on that node details page and a new webform node with some predefined fields will get created and get enabled as a block on that page in particular places.

I did it in D6.

My approach for the dynamic webform block :

  1. I created a webform node with all the default & predefined fields, say with nid = 100

  2. Enabled 'Available as block' option by visiting 'Form settings' tab in the path 'node/100/webform/configure'

  3. Created a custom module 'landing_pages'

  4. I cloned the nid = 100, each time a new landing_pages content is created

  5. In hook_init() used this code :

    
    /**
     *Implementation of hook_init(). 
     */
    function landing_pages_init() {
    // Update the 'blocks' DB table with the blocks currently exported by modules.
    _block_rehash( $theme = NULL );
    }
    
  6. In hook_node_api() used this code :

    
    /**
     *Implementation of hook_node_api().
     */
    function landing_pages_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
     switch ($op) {
       case 'insert' :
         if ($node->type == 'landing_pages') {
           $node_id = 100;
           // function to create & save the clone node              
           $new_nid = clone_node_save_custom( $node_id, $node->title );
         }
       break;
       case 'load' :
         if ($node->type == 'landing_pages') {
           /*updating webform block*/
           $result2 = db_fetch_object( db_query( "SELECT n.nid , n.title FROM {node} n WHERE n.type = 'webform' ORDER BY n.nid DESC LIMIT 1" ) );
           $var_result2 = 'client-block-' . $result2->nid;
           $result3 = db_result( db_query( "SELECT b.bid FROM {blocks} b WHERE b.module = 'webform' ORDER BY b.bid DESC LIMIT 1" ) );
           $nid = $node->nid; // Can avoide this step & directly use $node->nid
           $var_result1 = 'node/' . $nid;
           $check1 = db_query( "SELECT bl.bid FROM {blocks} bl WHERE bl.pages LIKE '$nid' AND bl.module = 'webform'" );
           /*if blocks table doesn't have any entry for 'pages' like this 'nid'*/
           if (db_affected_rows() == 0) {
             $check2 = db_fetch_object( db_query( "SELECT b.bid, b.region, b.status, b.visibility, b.pages FROM {blocks} b WHERE b.delta LIKE '$var_result2'" ) );
             /*if blocks table doesn'thave any entry for 'delta' like '$var_result2'*/
             if (db_affected_rows() != 0) {
               /*if blocks table doesn't have any entry for 'region' & pages,0 as entry for 'status' & visibility*/
               if ($check2->region == '' && $check2->status == 0 && $check2->visibility == 0 && $check2->pages == '') {
                 $exp = explode( '-#-', $result2->title );
                 if ($exp[0] != '')
                   $title = $exp[1];
                   db_query( "UPDATE {blocks} b SET b.module = 'webform', b.delta = '%s', b.theme = 'YOUR_THEME_NAME', b.status = 1, b.region = 'sidebar_second', b.visibility = 1, b.pages = '%s', b.title = '%s' WHERE b.bid = %d", $var_result2, $var_result1, $title, $result3 );
                 }
               }
             }
           }
        break;
        case 'delete' :
          if ($node->type == 'landing_pages') {
            $res = db_query( "SELECT b.bid, b.delta FROM {blocks} b WHERE b.module IN ('webform' , 'block') AND b.theme = 'YOUR_THEME_NAME' AND b.pages LIKE 'node/$node->nid'" );
            while ( $row = db_fetch_object( $res ) ) {
              if (! is_numeric( $row->delta )) {
                $exp = explode( 'client-block-', $row->delta );
                if ($exp[0] == '' && is_numeric( $exp[1] )) {
                //This validation can be skipped
                  $type = db_result( db_query( "SELECT n.type FROM {node} n WHERE n.nid = %d", $exp[1] ) );
                  if ($type == 'webform') {
                    node_delete( $exp[1] );
                }
              }
            }
            else {
              db_query( "DELETE FROM {blocks} WHERE bid = %d", $row->bid );
              db_query( "DELETE FROM {boxes} WHERE bid = %d", $row->delta );
            }
          }
        }
        break;
     }
    }
    
  7. Supporting functions :

      
    /**
     *Definition of clone_node_save_custom(). 
     */
    function clone_node_save_custom($nid, $nodetitle) {
     if (is_numeric( $nid )) {
       global $user;
       $node = node_load( $nid );
       if (isset( $node->nid ) && clone_is_permitted( $node->type )) {
         $original_node = drupal_clone( $node );
         $node->nid = NULL;
         $node->vid = NULL;
         $node->tnid = NULL;
         $node->name = $user->name;
         $node->uid = $user->uid;
         $node->created = NULL;
         $node->menu = clone_node_clone_menu_link( $original_node );
         $node->book['mlid'] = NULL;
         $node->path = NULL;
         $node->files = array();
         $node->title = t( '!tit -#- !title', array('!tit' => $nodetitle, '!title' => $node->title ) );
         $node->clone_from_original_nid = $original_node->nid;
    
    
     if (variable_get( 'clone_reset_' . $node->type, FALSE )) {
       $node_options = variable_get( 'node_options_' . $node->type, array('status', 'promote' ) );
       foreach ( array('status', 'moderate', 'promote', 'sticky', 'revision' ) as $key ) {
         $node->$key = in_array( $key, $node_options );
       }
     }
     drupal_alter( "clone_node", $node, $original_node, "save-edit" );
     node_save( $node );
     return $node->nid;
    
    } } }
    
    /**
    *Defines clone_node_clone_menu_link()
    *@param $node
    */
    function clone_node_clone_menu_link($node) {
    if (variable_get( 'clone_menu_links', FALSE )) {
      // This will fetch the existing menu link if the node had one.
      node_invoke_nodeapi( $node, 'prepare' );
      if (! empty( $node->menu['mlid'] )) {
        $old_link = $node->menu;
        $link['link_title'] = t( 'Clone of !title', array('!title' => $old_link['link_title'] ) );
        $link['plid'] = $old_link['plid'];
        $link['menu_name'] = $old_link['menu_name'];
        $link['weight'] = $old_link['weight'];
        return $link;
      }
    }
    return NULL;
    }
    
  8. Theme used is ZEN

  9. Region I needed the webform be enabled is 'sidebar_second'

  10. We shall have control over the settings of each webform for each Landing Page

Hope it helps.

1
  • I appreciate the time you've taken to write this response but I think it's a little too far from my original question, in my scenario, I create a content type of 'Event', I then want to apply specific settings to this webform (ie, only 1 entry per user, unlimited entries overall, reload page on submit etc) but the default automatically sets it to unlimited entries for everyone, I want to know how I can change the default setup for my webform in the code Jul 10, 2013 at 11:04
1

I suggest you to create the Webform normally via the GUI and use the webform share module to export your settings to code. This module produces an configuration array with all your settings, which you can use in your module then.

An example (hide field2, when field value of field1 equals the value "male") for conditions exported via webform share is:

$conditions = array (
  0 => 
  array (
    'nid' => '3',
    'rgid' => '0',
    'andor' => NULL,
    'action' => 'hide',
    'target_type' => 'component',
    'target' => '2',
    'weight' => '-1',
    'rules' => 
    array (
      0 => 
      array (
        'nid' => '3',
        'rgid' => '0',
        'rid' => '0',
        'source_type' => 'component',
        'source' => '1',
        'operator' => 'equal',
        'value' => 'male',
      ),
    ),
  ),
4
  • This is a good idea, it's helped me write out my array in the notation that I needed to, I've looked at the code for the import function and it seems to import all the settings by declaring the node objects webform property and then invoking node_save on it. Because I am calling my code from hook_node_submit, it won't allow me to invoke node_save without throwing an error, but this is a step in the right direction Jul 10, 2013 at 11:39
  • Oh... Now I see what you are doing here :) Is it really necessary to create a webform for each node or would it be adequate to have the same webform for every event-node, sending the webform to the author's mail address?
    – Nebel54
    Jul 10, 2013 at 11:53
  • At the moment the code only makes this webform if the 'event' content type is created, and attaches my components and the author to it, the reason I wanted it to set up a default is because these will be used for submitting 'abstracts' for approval to the event, but each form can change slightly event to event (in this instance all but 1 field will be set by default except the client might want to add some custom categories to a dropdown) Jul 10, 2013 at 12:08
  • Ok... if the form can change from event to event, this approach totally makes sense... otherwise i would recommend to use the same webform with invisble fields for event-data and the author-infos.
    – Nebel54
    Jul 10, 2013 at 12:16
1

I actually managed to get there in the end by re-tracing how it is written in the first place looking through the Drupal Contrib API documentation

I thought I would answer this question as a decent guide for anyone wanting to do the same again, even if I can only give them answer in my specific example

My code is as follows

/**
 * Implements hook_node_insert().
 */
function mymodule_node_insert($node) {
  // Examines the node type of that being created
  if ($node->type == 'event') {

    // The declaration for how setting up the webform defaults
    // is done at this stage rather than after invoking the
    // function below
    $node->webform = abstract_webform_node_defaults();

    // Adds the default settings for the abstract submission
    _abstract_webform_components($node);
  }
}

// Custom function to overwrite the normal defaults for webform
// This notation was taken from link 1 - provided under answer
function abstract_webform_node_defaults() {
  $defaults = array(
    'confirmation' => '', 
    'confirmation_format' => NULL, 
    'redirect_url' => '<none>', 
    'teaser' => '0', 
    'block' => '0', 
    'allow_draft' => '1', 
    'auto_save' => '0', 
    'submit_notice' => '1', 
    'submit_text' => '', 
    'submit_limit' => '1', 
    'submit_interval' => '-1', 
    'total_submit_limit' => '-1', 
    'total_submit_interval' => '-1', 
    'status' => '1', 
    'record_exists' => FALSE, 
    'roles' => array_keys(user_roles(TRUE)), // Roles are normally written as array keys for users, I wanted everyone except anonymous users to be able to enter mine
    'emails' => array(), 
    'components' => array(), 
    'conditionals' => array(),
  );
  return $defaults;
}

/* Custom function to setup webform as specific default */
function _abstract_webform_components($node) {
  $components = array(
      0 => array(
        'name' => 'First name',
        'form_key' => 'first_name',
        'type' => 'textfield',
        'mandatory' => 1,
        'weight' => 1,
        'pid' => 0,
        'extra' => array(
          'private' => 0,
        ),
      ),
      1 => array(
        'name' => 'Body',
        'form_key' => 'name',
        'type' => 'textfield',
        'mandatory' => 1,
        'weight' => 2,
        'pid' => 0,
        'extra' => array(
          'private' => 0,
        ),
      ),
      2 => array(
        'name' => 'Email address',
        'form_key' => 'email_address',
        'type' => 'email',
        'mandatory' => 1,
        'weight' => 3,
        'pid' => 0,
        'extra' => array(
          'private' => 0,
        ),
      ),
      3 => array(
        'name' => 'Message',
        'form_key' => 'message',
        'type' => 'textarea',
        'mandatory' => 1,
        'weight' => 4,
        'pid' => 0,
        'extra' => array(
          'private' => 0,
        ),
      ),
    );

  // Iterate through each $component record and pass into node
  // Information on how to do this taken from link 2
  webform_ensure_record($node);
  foreach($components as $component) {
    $component['nid'] = $node->nid;
    $component['extra']['title_display'] = 'inline';
    $component['extra']['locked'] = 1;
    $node->webform['components'][] = $component;
    webform_component_insert($component);
  }

  // Retrieves information about the author
  $author = user_load($node->uid);
  // Adds the author of the node as a 'reviewer'
  $email = array(
    'nid' => $node->nid,
    'email' => $author->mail,
    'subject' => 'default',
    'from_name' => 'default',
    'from_address' => 'default',
    'template' => 'default',
    'excluded_components' => array(),
  );
  webform_email_insert($email);

  // This function returns the value of which component is called 'Body' so 
  // that I can use its key for my validation rule, just so that if I re-arranged
  // my order at a later date, it would still keep the right key value
  for ($i = 0; $i < count($components); $i++) {
    if ($components[$i]['name'] == 'Body') {
      $body_component = $i+1;
      break;
    }
  }

  // If there is a 'Body' component
  if ($body_component) {
    // Validation formatting was taken from link 3
    $validation = array(
      'validator' => 'max_words',
      'action' => 'add',
      'nid' => $node->nid,
      'rulename' => 'Maximum Abstract Length',
      'rule_components' => array(
        $body_component => 'Body',
      ),
      'data' => 300,
    );
    webform_validation_rule_save($validation);
  }

  drupal_set_message(t('Abstract Submission created, Author set to reviewer by default.'));
}

Credit goes to all the authors of commenters from the original questions and links provided

Link 1

Link 2

Link 3

Also I would like to credit @Nebel54, for the suggestion about using the Webform Share to get a print out of exactly how your webform is written.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.