How to Build a Popup in Drupal for Login or Register Form

How to Build a Popup in Drupal for Login or Register Form

FFW Marketing
Thought byFFW Marketing
July 09, 2013
Drupal How to Build Login or Register Form

Recently we have launched two commerce projects at our Drupal Agency, that have the same functionality: For an anonymous user, when he clicks on “Checkout” on the card, he gets a pop-up that asks to login or to register.

In this article I would like to share the way how this functionality can be implemented in Drupal.

In order to have this popup flexible to customize we will display a mini panel. We will make the popup by using ctool modal.

First we should ajaxify the “Checkout” button to display popup, as we want all values of the cart form to be saved before we display the popup.

/** * Alter for form 'views_form_commerce_cart_form_default'. */ function mymodule_form_views_form_commerce_cart_form_default_alter(&$form, &$form_alter) { if (user_is_logged_in()) { return; } $order = commerce_cart_order_load(); if (isset($order->data['mymodule_popup_showed'])) { return; } $form['#prefix'] = '<div id="commerce-checkout-dialog">'; $form['#suffix'] = '</div>'; $form['actions']['checkout']['#ajax'] = array( 'callback' => 'mymodule_checkout_ajax_callback', ); }

We will ajaxify the form only for the anonymous users and only in case the user hasn't made the decision yet. This means that in case the visitor has already chosen to register, to login or simply close the dialog we do not want him to see the dialog again.

Our ajax callback will look like this:

function mymodule_checkout_ajax_callback($form, $form_state) { // Put a flag in order that user has already seen the popup and has done decision // so he doesn't need to see it again. $order = commerce_cart_order_load(); $order->data['mymodule_popup_showed'] = TRUE; commerce_order_save($order); ctools_include('ajax'); ctools_include('modal'); ctools_modal_add_js(); $commands = array(); $commands[] = ajax_command_replace('#commerce-checkout-dialog', drupal_render($form)); $commands[] = ajax_command_prepend(NULL, theme('status_messages')); $dialog_minipanel = _mymodule_render_login_register_minipanel(); $commands[] = ctools_modal_command_display('Login', $dialog_minipanel); return array('#type' => 'ajax', '#commands' => $commands); }

To display dialog popup we need to return ctools_modal_command_display() command. Function _mymodule_render_login_register_minipanel() simply renders our custom minipanel. The minipanel will consist of two panes – one with login form, another with user register form.

The biggest pitfall we have faced during the implementation of this drupal task was that ctools ajaxifies all form buttons displayed in the popup (this happens in ZZCToolsModal behavior of modal.js), so we need to make sure that all forms do have ajax callbacks.

In order to achieve this we create custom panes that will display forms. Here is an example of the pane render callback:

function mymodule_pane_login_pane_render($subtype, $conf, $args, $contexts) { $block = new stdClass(); $block->title = t('Login'); $form_state['mymodule_alter'] = TRUE; $form = drupal_build_form('user_login_block', $form_state); $block->content = '<div id="mymodule-user-login-block">' . drupal_render($form) . '</div>'; return $block; }

We set a property 'mymodule_alter' in $form_state so in form_alter we can add ajax callback for submit button. We do this as we do not want to add this effect to all user_login_block forms. For example if somebody will place a login block on the page it should not be ajaxified.

Form alter looks in following way:

function mymodule_form_user_login_block_alter(&$form, &$form_state) { _mymodule_alter_ajax_form($form, $form_state, 'mymodule_user_login_block_ajax_callback'); } function _mymodule_alter_ajax_form(&$form, &$form_state, $ajax_callback) { if (!isset($form_state['mymodule_alter'])) { return; } $form_state['cache'] = TRUE; $form['actions']['submit']['#ajax'] = array( 'callback' => $ajax_callback, ); }

Helper function _mymodule_alter_ajax_form has been introduced as Register form uses exactly same logic so we can reuse the same code (the only difference is the name of the ajax callback).

Now lets take a look at ajax callback of the submit button from the Login form.

function mymodule_user_login_block_ajax_callback($form, $form_state) { return _mymodule_form_ajax_callback($form, 'mymodule-user-login-block'); } function _mymodule_form_ajax_callback($form, $wrapper_id) { $commands = array(); $commands[] = ajax_command_replace('#' . $wrapper_id, theme('status_messages') . drupal_render($form)); $form_errors = form_get_errors(); if (empty($form_errors)) { ctools_include('ajax'); $commands[] = ctools_ajax_command_redirect('checkout'); } return array('#type' => 'ajax', '#commands' => $commands); }

As ajax callback in case of Login and Register forms has the same logic, again, we have separated it to the helper function. The idea is that if we have no validation errors on the form we redirect the user to the checkout page.

And this is it. Now we have dialog popup with two forms. In case of successful submission of one of them we got redirected to checkout.