In the previous post I gave an example of Ctools modal API as being operated with a single form. In this one you'll be given an insight into my web development experiences with another powerful tool, namely Ctools multistep wizard as being used with or without the modal API involvement.
Let's cut the lyrics about all those pretty-looking node, user, registration forms that are done with or without the help of this tool. The popups being used, this process will move to a higher visual level.
So, as usual, we start with hook_menu (). We declare the page which we will be calling a multi-step form and the page of the form itself:
/** * Implements hook_menu(). */ function multi_example_menu() { $items['example/%ctools_js/form'] = array( 'title' => 'Example form', 'page callback' => 'multi_example_form', 'page arguments' => array(1), 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); $items['example-link'] = array( 'title' => 'Example form link', 'page callback' => 'multi_example_link', 'page arguments' => array(1), 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); return $items; }
Functions that generate category:
/** * Page callback: Handles multistep precessing. * * @return string * Multistep wizard output. * * @see multi_example_menu() */ function multi_example_form($js = NULL, $step = NULL) { if ($js) { ctools_include('modal'); ctools_include('ajax'); } // Define array for ctools multistep wizard. $form_info = array( 'id' => 'multi_example', 'path' => "example/" . ($js ? 'ajax' : 'nojs') . "/form/%step", 'show trail' => TRUE, 'show back' => TRUE, 'show cancel' => TRUE, 'show return' => FALSE, 'next callback' => 'multi_example_wizard_next', 'finish callback' => 'multi_example_wizard_finish', 'cancel callback' => 'multi_example_wizard_cancel', // Define forms order. 'order' => array( 'start' => t('Enter your info'), 'second' => t('What do you know?'), 'third' => t('What do think about drupal?'), 'fourth' => t('Do you like cookies?'), ), // Define forms 'forms' => array( 'start' => array( 'form id' => 'multi_example_form_start' ), 'second' => array( 'form id' => 'multi_example_form_second' ), 'third' => array( 'form id' => 'multi_example_form_third' ), 'fourth' => array( 'form id' => 'multi_example_form_fourth' ), ), ); // We're not using any real storage here, so we're going to set our // object_id to 1. When using wizard forms, id management turns // out to be one of the hardest parts. Editing an object with an id // is easy, but new objects don't usually have ids until somewhere // in creation. // // We skip all this here by just using an id of 1. $object_id = 1; if (empty($step)) { // We reset the form when $step is NULL because that means they have // for whatever reason started over. multi_example_cache_clear($object_id); $step = 'start'; } // This automatically gets defaults if there wasn't anything saved. $object = multi_example_cache_get($object_id); // live $form_state changes. $form_state = array( 'ajax' => $js, // Put our object and ID into the form state cache so we can easily find it. 'object_id' => $object_id, 'object' => &$object, ); // Send this all off to our form. This is like drupal_get_form only wizardy. ctools_include('wizard'); $form = ctools_wizard_multistep_form($form_info, $step, $form_state); $output = drupal_render($form); if ($js) { // If javascript is active, we have to use a render array. $commands = array(); if ($output === FALSE || !empty($form_state['complete'])) { // Dismiss the modal. $commands[] = ajax_command_html('#ctools-sample', render(multi_example_get_result($object))); $commands[] = ctools_modal_command_dismiss(); } elseif (!empty($form_state['cancel'])) { // If cancelling, return to the activity. $commands[] = ctools_modal_command_dismiss(); } else { $commands = ctools_modal_form_render($form_state, $output); } print ajax_render($commands); } else { if ($output === FALSE || !empty($form_state['complete'])) { return render(multi_example_get_result($object)) . "\n\r" . l(t('Back'), 'example-link'); } elseif (!empty($form_state['cancel'])) { drupal_goto('example-link'); } else { return $output; } } }