You are here

uc_webform_pane.module in Ubercart Webform Checkout Pane 7.3

uc_webform_pane.module Ubercart Webform Checkout Pane.

@note Ubercart webform data is stored in database during checkout, even when order is not complete.

File

uc_webform_pane.module
View source
<?php

/**
 * @file uc_webform_pane.module
 * Ubercart Webform Checkout Pane.
 *
 * @note Ubercart webform data is stored in database during checkout, even when order is not complete.
 */

/**
 * Implements hook_theme().
 */
function uc_webform_pane_theme() {
  $theme = array(
    'uc_webform_pane_order_view' => array(
      'variables' => array(
        'data' => NULL,
      ),
    ),
  );
  return $theme;
}

/**
 * Implements hook_form_alter().
 */
function uc_webform_pane_form_alter(&$form, &$form_state, $form_id) {
  global $user;

  // Make sure the webform form supports files.
  if ($form_id == 'uc_cart_checkout_form' || $form_id == 'uc_order_edit_form') {
    $form['#attributes']['enctype'] = 'multipart/form-data';
    $form['#process'][] = 'webform_client_form_includes';
  }

  // Support for Webform Validation module
  if ($form_id == 'uc_cart_checkout_form' && function_exists('webform_validation_validate')) {
    $form['#validate'][] = 'uc_webform_pane_wv_validate';
  }

  // Make sure the webform form supports files.
  if ($form_id == 'uc_order_edit_form') {
    $form['#attributes']['enctype'] = 'multipart/form-data';
    $form['#process'][] = 'webform_client_form_includes';
  }

  // Add a config option to webform nodes to enable them as checkout panes.
  if ($form_id == 'webform_configure_form') {
    $form['advanced']['uc_webform_pane'] = array(
      '#type' => 'checkbox',
      '#return_value' => 1,
      '#default_value' => uc_webform_pane_nodestatus($form['nid']['#value']),
      '#title' => t('Generate a checkout pane'),
      '#description' => t('Allow this form to be used as a Ubercart checkout pane.'),
      '#weight' => -15,
      '#access' => user_access('administer store'),
    );
    $form['#submit'][] = 'uc_webform_pane_webform_configure_form_submit';
  }

  // Add access validation to all UC checkout pane webforms.
  if (preg_match('|webform_.*_form|', $form_id)) {
    $nid = arg(1);
    if (uc_webform_pane_nodestatus($nid)) {
      $form['uc_access'] = array(
        '#type' => 'hidden',
        '#value' => user_access('administer store', $user) ? '1' : '0',
      );
      $form['#validate'][] = 'uc_webform_pane_access_validate';
    }
  }
}

/**
 * Send the values of each Webform Pane through to Webform Validation checkers.
 */
function uc_webform_pane_wv_validate($form, &$form_state) {
  $panes = $form_state['values']['panes'];
  if (!$panes) {
    return;
  }
  foreach ($panes as $paneid => $values) {
    if (drupal_substr($paneid, 0, 11) == 'webform_nid') {
      $nid = drupal_substr($paneid, 11);
      $pane_values = array();
      $pane_values['op'] = t('Submit');
      $pane_values['submitted'] = $values;
      $pane_values['details']['nid'] = $nid;
      $pane_state = array();
      $pane_state['values'] = $pane_values;
      webform_validation_validate($form, $pane_state);
    }
  }
}

/**
 * Make sure that the user trying to modify the UC checkout pane enabled webform has adequate Ubercart permissions.
 */
function uc_webform_pane_access_validate($form, &$form_state) {
  if ($form_state['values']['uc_access'] === '0') {
    form_set_error('uc_access', t('This webform is used as an Ubercart checkout pane and cannot be accessed outside of Ubercart and/or without the appropriate Ubercart permissions.'));
  }
}

/**
 * Mark the webform as a potential checkout pane.
 */
function uc_webform_pane_webform_configure_form_submit($form, &$form_state) {
  if ($form_state['values']['uc_webform_pane']) {
    db_merge('uc_webform_pane')
      ->key(array(
      'nid' => $form_state['values']['nid'],
    ))
      ->execute();
  }
  else {
    db_delete('uc_webform_pane')
      ->condition('nid', $form_state['values']['nid'])
      ->execute();
  }
}

/**
 * Implements hook_node_prepare().
 */
function uc_webform_pane_node_prepare($node) {
  if (in_array($node->type, webform_variable_get('webform_node_types'))) {
    $node->webform['uc_webform_pane'] = isset($node->nid) ? uc_webform_pane_nodestatus($node->nid) : FALSE;
  }
}

/**
 * Implements hook_node_delete().
 */
function uc_webform_pane_node_delete($node) {
  if (in_array($node->type, webform_variable_get('webform_node_types'))) {
    db_delete('uc_webform_pane')
      ->condition('nid', $node->nid)
      ->execute();
  }
}

/**
 * Check if a webform node should be selectable as a checkout pane.
 */
function uc_webform_pane_nodestatus($nid) {
  $found = db_select('uc_webform_pane', 'uwp')
    ->fields('uwp', array(
    'nid',
  ))
    ->condition('nid', $nid)
    ->execute()
    ->fetchField();
  return $found ? TRUE : FALSE;
}

/**
 * Implements hook_token_info().
 */
function uc_webform_pane_token_info() {
  $types = array();
  $tokens = array();
  $webforms = _uc_webform_pane_get_nodes();
  foreach ($webforms as $webform) {
    $nid = $webform->nid;
    $node = node_load($nid);
    $type = array(
      'name' => $node->title,
      'description' => t('Webform tokens.'),
      'needs-data' => 'ucwf_' . $nid,
    );
    $info = array();
    foreach ($node->webform['components'] as $field) {
      if ($field['type'] == 'markup' || $field['type'] == 'fieldset') {
        continue;
      }
      $info['uc-webform-' . $nid . '-' . str_replace('_', '-', $field['form_key'])] = array(
        'name' => $field['name'],
        'description' => '',
      );
    }
    $types['ucwf_' . $nid] = $type;
    $tokens['ucwf_' . $nid] = $info;
    $tokens['uc_order']['ucwf_' . $nid] = array(
      'name' => $node->title,
      'description' => t('Webform tokens.'),
      'type' => 'ucwf_' . $nid,
    );
  }
  return array(
    'types' => $types,
    'tokens' => $tokens,
  );
}

/**
 * Implements hook_tokens().
 */
function uc_webform_pane_tokens($type, $tokens, $data = array(), $options = array()) {
  $values = array();
  if ($type == 'uc_order' && !empty($data['uc_order'])) {
    $order = $data['uc_order'];
    $webforms = _uc_webform_pane_get_nodes();
    foreach ($webforms as $webform) {
      $nid = $webform->nid;
      $node = node_load($nid);
      $data = get_object_vars(_uc_webform_pane_get_data($nid, $order->order_id));
      foreach ($node->webform['components'] as $field) {
        if ($field['type'] == 'markup' || $field['type'] == 'fieldset') {
          continue;
        }
        $field_data = isset($data['data'][$field['cid']]['value']) ? $data['data'][$field['cid']]['value'] : NULL;
        $field_element = webform_component_invoke($field['type'], 'display', $field, $field_data);
        $field_element['#webform_component'] = $field;
        $submission_output = theme($field_element['#theme'], array(
          'element' => $field_element,
        ));
        $values['uc-webform-' . $nid . '-' . str_replace('_', '-', $field['form_key'])] = $submission_output;
      }
    }
  }
  return $values;
}

/**
 * Implements hook_uc_checkout_pane().
 */
function uc_webform_pane_uc_checkout_pane() {
  $panes = array();
  $webforms = _uc_webform_pane_get_nodes();
  foreach ($webforms as $webform) {
    $nid = $webform->nid;
    $funcname = '_uc_webform_pane_' . $nid;

    // Dynamically create callback function
    if (!function_exists($funcname)) {
      eval('function ' . $funcname . '($op, $order, $form = NULL, &$form_state = NULL) { return uc_webform_pane_uc_checkout_pane_callback(' . $nid . ', $op, $order, $form, $form_state); } ');
    }
    $node = node_load($nid);
    $body = !empty($node->body) ? $node->body[$node->language][0]['safe_value'] : '';
    $panes['webform_nid' . $nid] = array(
      'callback' => $funcname,
      'title' => check_plain($node->title),
      'desc' => $body,
      'weight' => 0,
    );
  }
  return $panes;
}

/**
 * Checkout Pane callback for dynamic callback function.
 */
function uc_webform_pane_uc_checkout_pane_callback($nid, $op, $order, $form = NULL, &$form_state = NULL) {
  switch ($op) {
    case 'view':
      $form = _uc_webform_pane_edit_form($nid, $order->order_id, 'checkout');
      $node = node_load($nid);
      $body = !empty($node->body) ? $node->body[$node->language][0]['safe_value'] : '';
      return array(
        'contents' => array(
          $form,
        ),
        'description' => $body,
      );
      break;
    case 'process':
      _uc_webform_pane_save($nid, $order->order_id, $form_state['values']['panes']['webform_nid' . $nid][0]);

      // save to database
      return TRUE;
      break;
    case 'review':
      $data = _uc_webform_pane_render($nid, $order->order_id);
      if ($data) {
        return $data;
      }
      break;
    default:
      break;
  }
}

/**
 * Implements of drupal_alter('uc_checkout_pane', $panes).
 */
function uc_webform_pane_uc_checkout_pane_alter(&$panes) {
  global $user;

  // Validate all the webform panes individually during the checkout process
  foreach ($panes as $pid => $pane) {
    if ($pane['enabled'] == 1 && drupal_substr($pane['id'], 0, 11) == 'webform_nid') {

      // Make sure Webform styles/scripts are shown
      drupal_add_css(drupal_get_path('module', 'webform') . '/css/webform.css');
      drupal_add_js(drupal_get_path('module', 'webform') . '/js/webform.js');

      // Load the Webform node
      $nid = drupal_substr($pane['id'], 11);
      $node = node_load($nid);

      // Check if this page is cached or not
      $cached = $user->uid == 0 && (variable_get('cache', 0) || drupal_page_is_cacheable() === FALSE);

      // Check if the webform user submission limit has already been reached
      if ($node->webform['submit_limit'] != -1) {

        // -1: Submissions are never throttled.
        module_load_include('inc', 'webform', 'includes/webform.submissions');

        // Disable the form if the limit is exceeded and page cache is not active
        if (($user_limit_exceeded = _webform_submission_user_limit_check($node)) && !$cached) {
          $panes[$pid]['enabled'] = FALSE;
        }
      }

      // Check if the webform total submission limit has already been reached
      if ($node->webform['total_submit_limit'] != -1) {

        // -1: Submissions are never throttled.
        module_load_include('inc', 'webform', 'includes/webform.submissions');

        // Disable the form if the limit is exceeded and page cache is not active
        if (($total_limit_exceeded = _webform_submission_total_limit_check($node)) && !$cached) {
          $panes[$pid]['enabled'] = FALSE;
        }
      }
    }
  }
}

/**
 * Implements of hook_uc_checkout_complete().
 */
function uc_webform_pane_uc_checkout_complete($order, $account) {

  // Assign the Webform pane submissions to the newly created user
  if (isset($order->data['new_user'])) {
    $webforms = _uc_webform_pane_get_nodes();
    foreach ($webforms as $webform) {
      $nid = $webform->nid;

      // Get the sid for webform submission in the current order
      $sid = _uc_webform_pane_get_sid($nid, $order->order_id);
      if ($sid) {
        db_query("UPDATE {webform_submissions} SET uid = :uid WHERE sid = :sid", array(
          ':uid' => $order->uid,
          ':sid' => $sid,
        ));
      }
    }
  }
}

/**
 * Implements hook_uc_order_pane().
 */
function uc_webform_pane_uc_order_pane() {
  $panes = array();
  $webforms = _uc_webform_pane_get_nodes();
  foreach ($webforms as $webform) {
    $nid = $webform->nid;
    $funcname = '_uc_webform_order_pane_' . $nid;

    // Dynamically create callback function
    if (!function_exists($funcname)) {
      eval('function ' . $funcname . '($op, $order, &$form = NULL, &$form_state = NULL) { return uc_webform_pane_uc_order_pane_callback(' . $nid . ', $op, $order, $form, $form_state); } ');
    }
    $node = node_load($nid);
    $body = !empty($node->body) ? $node->body[$node->language][0]['safe_value'] : '';
    $panes['webform_nid' . $nid] = array(
      'callback' => $funcname,
      'title' => $node->title,
      'desc' => $body,
      'class' => 'abs-left',
      'weight' => 7,
      'show' => array(
        'view',
        'customer',
        'edit',
      ),
    );
  }
  return $panes;
}

/**
 * Order Pane callback for dynamic order callback function.
 */
function uc_webform_pane_uc_order_pane_callback($nid, $op, $order, &$form = NULL, &$form_state = NULL) {
  switch ($op) {
    case 'view':
    case 'customer':
      $data = _uc_webform_pane_render($nid, $order->order_id);
      if ($data) {
        $build = array(
          '#markup' => theme('uc_webform_pane_order_view', array(
            'data' => $data,
          )),
        );
        return $build;
      }
      break;
    case 'edit-form':
      $webform = _uc_webform_pane_edit_form($nid, $order->order_id, 'order');
      $node = node_load($nid);
      $form['webform_nid' . $nid] = array(
        '#type' => 'fieldset',
        '#title' => t('Modify @title information', array(
          '@title' => $node->title,
        )),
        '#collapsible' => TRUE,
        '#collapsed' => FALSE,
      );
      foreach ($webform as $field_id => $field_settings) {
        $form['webform_nid' . $nid][$field_id] = $field_settings;
      }
      return $form;
    case 'edit-theme':
      drupal_add_css(drupal_get_path('module', 'uc_webform_pane') . '/uc_webform_pane.css');
      $output = '<div id="webform-' . $nid . '-select"></div><table class="uc-webform-edit-table">';
      foreach (element_children($form['webform_nid' . $nid]) as $field) {
        if (isset($form['webform_nid' . $nid][$field]['#type']) && in_array($form['webform_nid' . $nid][$field]['#type'], array(
          'value',
          'markup',
        ))) {
          continue;
        }
        elseif (isset($form['webform_nid' . $nid][$field]['#type']) && $form['webform_nid' . $nid][$field]['#type'] == 'hidden') {
          $output .= drupal_render($form['webform_nid' . $nid][$field]);
        }
        else {
          $title = $form['webform_nid' . $nid][$field]['#title'];

          // Process select_or_other widgets
          if (isset($form['webform_nid' . $nid][$field]['select'])) {
            $title = $form['webform_nid' . $nid][$field]['select']['#title'];
            $form['webform_nid' . $nid][$field]['select']['#title'] = NULL;
          }
          $form['webform_nid' . $nid][$field]['#title'] = NULL;
          $output .= '<tr><td class="uwet-label">' . check_plain($title) . ':</td><td>' . drupal_render($form['webform_nid' . $nid][$field]) . '</td></tr>';
        }
      }
      $output .= '</table>';
      return $output;
    case 'edit-process':
      _uc_webform_pane_save($nid, $order->order_id, $form_state['input']['webform_nid' . $nid]);
      break;
  }
}

/**
 * Implements hook_uc_order().
 */
function uc_webform_pane_uc_order($op, &$order, $arg2) {
  switch ($op) {

    // Delete from the database.
    case 'delete':
      include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'webform') . "/includes/webform.submissions.inc";
      $uc_wf_subs = db_select('uc_webform_pane_submissions', 'uwps')
        ->fields('uwps', array(
        'nid',
        'sid',
      ))
        ->condition('order_id', $order->order_id)
        ->execute();
      foreach ($uc_wf_subs as $uc_wf_sub) {
        $node = node_load($uc_wf_sub->nid);
        $submission = webform_get_submission($uc_wf_sub->nid, $uc_wf_sub->sid);
        webform_submission_delete($node, $submission);
      }
      db_delete('uc_webform_pane_submissions')
        ->condition('order_id', $order->order_id)
        ->execute();
      break;
  }
}

/**
 * Save pane values as webform submission through Webform submit handler.
 */
function _uc_webform_pane_save($nid, $order_id, $submitted) {
  global $user;
  $node = node_load($nid);
  $sid = _uc_webform_pane_get_sid($nid, $order_id);
  $values['op'] = t('Submit');
  $values['submitted'] = $submitted;
  $values['details']['uid'] = $user->uid;
  $values['details']['nid'] = $nid;
  $values['details']['sid'] = $sid;
  $values['details']['finished'] = FALSE;
  $form_state = array();
  $form_state['values'] = $values;

  // Perform post processing by components.
  _webform_client_form_submit_process($node, $form_state['values']['submitted']);

  // Flatten trees within the submission.
  $form_state['values']['submitted_tree'] = $form_state['values']['submitted'];
  $form_state['values']['submitted'] = _webform_client_form_submit_flatten($node, $form_state['values']['submitted']);

  // Do some cleaning up before our fake submit
  foreach ($form_state['values']['submitted'] as $key => $value) {

    // Clean up anything that is not a Webform component
    if (!is_numeric($key)) {
      unset($form_state['values']['submitted'][$key]);
    }

    // Clean up empty values as these won't be saved anyway
    if (is_array($value) && sizeof($value) == 0) {
      unset($form_state['values']['submitted'][$key]);
    }
  }

  // If the values list ends up empty, all required fields must be empty - get out
  if (!$form_state['values']['submitted']) {
    return;
  }

  // Set a flag indicating processing should continue and be saved.
  $form_state['webform_completed'] = TRUE;
  webform_client_form_submit(array(
    '#node' => $node,
  ), $form_state);
  if (!$sid) {
    $sid = $form_state['values']['details']['sid'];
    db_insert('uc_webform_pane_submissions')
      ->fields(array(
      'nid' => $nid,
      'sid' => $sid,
      'order_id' => $order_id,
    ))
      ->execute();
  }
}

/**
 * Return webform submission id.
 */
function _uc_webform_pane_get_sid($nid, $order_id) {
  return db_select('uc_webform_pane_submissions', 'uwps')
    ->fields('uwps', array(
    'sid',
  ))
    ->condition('nid', $nid)
    ->condition('order_id', $order_id)
    ->execute()
    ->fetchField();
}

/**
 * Return webform submission data.
 */
function _uc_webform_pane_get_data($nid, $order_id) {
  if ($sid = _uc_webform_pane_get_sid($nid, $order_id)) {
    include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'webform') . "/includes/webform.submissions.inc";
    return webform_get_submission($nid, $sid);
  }
  $empty = new stdClass();
  return $empty;
}

/**
 * Return list of webform nodes.
 */
function _uc_webform_pane_get_nodes() {
  $query = db_select('node', 'n')
    ->fields('n', array(
    'nid',
  ))
    ->condition('type', webform_variable_get('webform_node_types'))
    ->condition('status', 1)
    ->orderBy('title', 'DESC');
  $query
    ->join('uc_webform_pane', 'uwp', 'n.nid = uwp.nid');
  $rs = $query
    ->execute();
  $webforms = array();
  foreach ($rs as $webform) {
    $webforms[] = $webform;
  }
  return $webforms;
}

/**
 * Render webform submission data.
 */
function _uc_webform_pane_render($nid, $order_id) {
  $data = get_object_vars(_uc_webform_pane_get_data($nid, $order_id));
  $output = array();
  if ($data) {
    $node = node_load($nid);
    foreach ($node->webform['components'] as $field) {
      if (!in_array($field['type'], array(
        'hidden',
        'markup',
        'fieldset',
      ))) {
        $field_data = isset($data['data'][$field['cid']]['value']) ? $data['data'][$field['cid']]['value'] : NULL;
        $field_element = webform_component_invoke($field['type'], 'display', $field, $field_data);
        $field_element['#webform_component'] = $field;
        $submission_output = theme($field_element['#theme'], array(
          'element' => $field_element,
        ));
        if ($submission_output !== NULL && trim($submission_output)) {
          $output[] = array(
            'title' => check_plain($field['name']),
            'data' => $submission_output,
          );
        }
      }
    }
  }
  return $output;
}

/**
 * Theme webform submission data on the order view page.
 */
function theme_uc_webform_pane_order_view($variables) {
  $data = $variables['data'];
  $output = '<table>';
  foreach ($data as $row) {
    $border = '';
    if (isset($row['border'])) {
      $border = ' class="row-border-' . $row['border'] . '"';
    }
    $output .= '<tr valign="top"' . $border . '><td class="title-col" ' . 'nowrap>' . $row['title'] . ':</td><td class="data-col">' . $row['data'] . '</td></tr>';
  }
  $output .= '</table>';
  return $output;
}

/**
 * Generate a form to edit webform submission data.
 */
function _uc_webform_pane_edit_form($nid, $order_id, $pane_type) {

  // Load the node and make sure it's a Webform
  $node = node_load($nid);
  if (!$node->webform['components']) {
    return array();
  }
  $submission = _uc_webform_pane_get_data($nid, $order_id);

  // Mark the node as a checkout pane
  $node->in_checkout = TRUE;

  // Load the Webform
  $form_state = array(
    'method' => 'post',
  );
  $form_state['build_info']['args'] = array(
    $node,
    $submission,
  );
  $form = drupal_retrieve_form('webform_client_form_' . $node->nid, $form_state);
  drupal_prepare_form('webform_client_form_' . $node->nid, $form, $form_state);

  // Remove some things that get in the way
  foreach (array(
    'details',
    'form_id',
    'form_token',
    'form_build_id',
    'actions',
    '#parents',
    '#theme',
    '#tree',
    '#id',
    '#type',
    '#theme_wrappers',
  ) as $key) {
    unset($form[$key]);
  }

  // Wrap the form in same id's as it would be as a real Webform
  $form['#prefix'] = '<div id="webform-client-form-' . $nid . '">';
  $form['#suffix'] = '</div>';
  foreach ($form['submitted'] as $key => $field) {
    $form[$key] = $field;
  }
  unset($form['submitted']);

  // Prepare form fields for processing using UCWP
  _uc_webform_pane_edit_form_prepare($form, $pane_type);
  return $form;
}

/**
 * Prepare form fields for processing using UCWP.
 */
function _uc_webform_pane_edit_form_prepare(&$form, $pane_type) {
  foreach (element_children($form) as $k) {
    $form[$k]["#validated"] = FALSE;
    if ($pane_type == 'order') {
      $form[$k]["#required"] = FALSE;
    }
    if (isset($form[$k]["#type"]) && $form[$k]["#type"] == 'fieldset') {
      _uc_webform_pane_edit_form_prepare($form[$k], $pane_type);
    }
  }
}

Functions

Namesort descending Description
theme_uc_webform_pane_order_view Theme webform submission data on the order view page.
uc_webform_pane_access_validate Make sure that the user trying to modify the UC checkout pane enabled webform has adequate Ubercart permissions.
uc_webform_pane_form_alter Implements hook_form_alter().
uc_webform_pane_nodestatus Check if a webform node should be selectable as a checkout pane.
uc_webform_pane_node_delete Implements hook_node_delete().
uc_webform_pane_node_prepare Implements hook_node_prepare().
uc_webform_pane_theme Implements hook_theme().
uc_webform_pane_tokens Implements hook_tokens().
uc_webform_pane_token_info Implements hook_token_info().
uc_webform_pane_uc_checkout_complete Implements of hook_uc_checkout_complete().
uc_webform_pane_uc_checkout_pane Implements hook_uc_checkout_pane().
uc_webform_pane_uc_checkout_pane_alter Implements of drupal_alter('uc_checkout_pane', $panes).
uc_webform_pane_uc_checkout_pane_callback Checkout Pane callback for dynamic callback function.
uc_webform_pane_uc_order Implements hook_uc_order().
uc_webform_pane_uc_order_pane Implements hook_uc_order_pane().
uc_webform_pane_uc_order_pane_callback Order Pane callback for dynamic order callback function.
uc_webform_pane_webform_configure_form_submit Mark the webform as a potential checkout pane.
uc_webform_pane_wv_validate Send the values of each Webform Pane through to Webform Validation checkers.
_uc_webform_pane_edit_form Generate a form to edit webform submission data.
_uc_webform_pane_edit_form_prepare Prepare form fields for processing using UCWP.
_uc_webform_pane_get_data Return webform submission data.
_uc_webform_pane_get_nodes Return list of webform nodes.
_uc_webform_pane_get_sid Return webform submission id.
_uc_webform_pane_render Render webform submission data.
_uc_webform_pane_save Save pane values as webform submission through Webform submit handler.