You are here

function commerce_checkout_form in Commerce Core 7

Builds the checkout form for the given order on the specified checkout page.

Parameters

$order: The fully loaded order object being checked out.

$checkout_page: The checkout page object representing the current step in checkout.

1 string reference to 'commerce_checkout_form'
commerce_checkout_forms in modules/checkout/commerce_checkout.module
Implements hook_forms().

File

modules/checkout/includes/commerce_checkout.pages.inc, line 75
The page and form callbacks for use in the checkout form.

Code

function commerce_checkout_form($form, &$form_state, $order, $checkout_page) {
  global $user;

  // Ensure this include file is loaded when the form is rebuilt from the cache.
  $form_state['build_info']['files']['form'] = drupal_get_path('module', 'commerce_checkout') . '/includes/commerce_checkout.pages.inc';
  $form['#attached']['css'][] = drupal_get_path('module', 'commerce_checkout') . '/theme/commerce_checkout.base.css';
  $form['#attached']['css'][] = drupal_get_path('module', 'commerce_checkout') . '/theme/commerce_checkout.theme.css';
  $form['#attached']['js'][] = drupal_get_path('module', 'commerce_checkout') . '/commerce_checkout.js';

  // Refresh the order object in case it has been altered outside the checkout
  // process so cache_form has a stale version.
  $order = commerce_order_load($order->order_id);
  $form_state['order'] = $order;
  $form_state['checkout_page'] = $checkout_page;
  $form_state['account'] = clone $user;

  // Add any help text that has been defined for this checkout page.
  $help = filter_xss($checkout_page['help']);
  if (!empty($help)) {
    $form['help'] = array(
      '#markup' => theme('commerce_checkout_help', array(
        'help' => $help,
      )),
    );
  }

  // Restore form errors.
  if (!empty($form_state['storage']['errors'])) {
    $form_errors =& drupal_static('form_set_error', array());
    $form_errors = $form_state['storage']['errors'];
  }
  $form['#after_build'][] = 'commerce_checkout_form_process_errors';

  // Catch and clear already pushed messages.
  $previous_messages = drupal_get_messages();
  $show_errors_message = FALSE;
  $visible_panes = 0;

  // Add any enabled checkout panes for this page to the form.
  foreach (commerce_checkout_panes(array(
    'enabled' => TRUE,
    'page' => $checkout_page['page_id'],
  )) as $pane_id => $checkout_pane) {
    if ($callback = commerce_checkout_pane_callback($checkout_pane, 'checkout_form')) {

      // Generate the pane form.
      $pane_form = $callback($form, $form_state, $checkout_pane, $order);

      // Refresh the order object in case the checkout pane altered it outside
      // of the passed reference.
      $order = commerce_order_load($order->order_id);
      $form_state['order'] = $order;

      // Combine the messages that were created during this pane's validation or
      // submit process with any that were created during the pane generation
      // and merge them into the session's current messages array.
      if (!empty($form_state['storage']['messages'][$pane_id])) {
        $_SESSION['messages'] = array_merge_recursive($form_state['storage']['messages'][$pane_id], drupal_get_messages());
      }

      // If there are messages in the session right now for this pane, theme
      // them into the form right above the pane itself.
      if (!empty($_SESSION['messages'])) {

        // If there are error messages and this is not the first pane on the
        // form, then indicate we need to show an error message at the top of
        // the page.
        if ($visible_panes > 0 && !empty($_SESSION['messages']['error'])) {
          $show_errors_message = TRUE;
        }

        // Rendering status messages clears the session of messages, so they
        // will not be visible if the user is redirected. We can at least not
        // render here when we detect the global variable added by Rules to
        // handle redirects, though modules implementing redirects will still
        // encounter the same problem of "lost" messages.
        if (!isset($GLOBALS['_rules_action_drupal_goto_do'])) {
          $form_state['storage']['themed_messages'][$pane_id] = theme('status_messages');
          $pane_form[$pane_id . '_messages'] = array(
            '#markup' => $form_state['storage']['themed_messages'][$pane_id],
            '#weight' => -50,
          );
        }
      }

      // Create a fieldset for the pane and add the form data defined in the
      // pane's form callback.
      if ($pane_form) {
        $form[$pane_id] = $pane_form + array(
          '#type' => $checkout_pane['fieldset'] ? 'fieldset' : 'container',
          '#title' => check_plain($checkout_pane['title']),
          '#collapsible' => $checkout_pane['collapsible'],
          '#collapsed' => $checkout_pane['collapsed'],
          '#attributes' => array(
            'class' => array(
              $pane_id,
            ),
          ),
          '#tree' => TRUE,
        );
        $visible_panes++;
      }
    }
  }

  // Restore general messages to the current session's messages array.
  $_SESSION['messages'] = array_merge_recursive(array_filter($previous_messages), drupal_get_messages());

  // If there are errors on the form, add a message to the top of the page.
  if ($show_errors_message) {
    $form['error_message'] = array(
      '#markup' => theme('commerce_checkout_errors_message', array(
        'label' => t('Errors on form'),
        'message' => t('There are errors on the page. Please correct them and resubmit the form.'),
      )),
      '#weight' => -10,
    );
  }

  // Only add buttons to the form if the checkout page hasn't disabled them.
  if ($checkout_page['buttons']) {
    $form['buttons'] = array(
      '#type' => 'fieldset',
      '#attributes' => array(
        'class' => array(
          'checkout-buttons',
        ),
      ),
    );
    $form['buttons']['continue'] = array(
      '#type' => 'submit',
      '#value' => $checkout_page['submit_value'],
      '#attributes' => array(
        'class' => array(
          'checkout-continue',
        ),
      ),
      '#suffix' => '<span class="checkout-processing element-invisible"></span>',
      '#validate' => array(
        'commerce_checkout_form_validate',
      ),
      '#submit' => array(
        'commerce_checkout_form_submit',
      ),
    );

    // Add the cancel or back button where appropriate. We define button level
    // submit handlers because we're using hook_forms() to use this form builder
    // function and to avoid issues if other modules implement button level submit
    // handlers on these or custom checkout buttons.
    $button_operator = '<span class="button-operator">' . t('or') . '</span>';
    if (!$checkout_page['prev_page'] && !empty($checkout_page['back_value'])) {

      // Add an empty "Back" button value to avoid submission errors.
      $form['buttons']['back'] = array(
        '#type' => 'value',
        '#value' => '',
      );

      // Store the cancel redirect in the form so modules can modify it easily.
      $form_state['cancel_redirect'] = '<front>';
      $form['buttons']['cancel'] = array(
        '#type' => 'submit',
        '#value' => t('Cancel'),
        '#attributes' => array(
          'class' => array(
            'checkout-cancel',
          ),
        ),
        '#submit' => array(
          'commerce_checkout_form_cancel_submit',
        ),
        '#limit_validation_errors' => array(),
        '#prefix' => $button_operator,
      );
    }
    elseif ($checkout_page['prev_page'] && !empty($checkout_page['back_value'])) {
      $form['buttons']['back'] = array(
        '#type' => 'submit',
        '#value' => $checkout_page['back_value'],
        '#attributes' => array(
          'class' => array(
            'checkout-back',
          ),
        ),
        '#submit' => array(
          'commerce_checkout_form_back_submit',
        ),
        '#limit_validation_errors' => array(),
        '#prefix' => $button_operator,
      );
    }
  }

  // Remove form level validate and submit handlers.
  $form['#validate'] = array();
  $form['#submit'] = array();
  return $form;
}