background image

Content tagged with: hook_form_alter

Eric's picture

In this snippet, I'll show you how you can submit a webform programmatically using drupal_execute(). The first thing you'll need to do is figure out what the $form_state data looks like when the webform is submitted, so you can recreate that structure and pass it into drupal_execute().

One way to accomplish this is to add a validation/submit handler to the form using hook_form_alter() and then output the contents of the submitted data (using krumo, print_r, etc).

The following code will prepend a validation handler to the webform $form, so we can dump the submitted data to the screen:

<?php
function MYMODULE_form_alter(&$form, $form_state, $form_id) {
 
 
// define node id of webform
 
$webform_node_id = 146;
 
 
// check for form id of webform
 
if ($form_id == 'webform_client_form_' . $webform_node_id) {
 
   
// prepend a validation callback to the form
   
array_unshift($form['#validate'],
     
'_MYMODULE_form_alter_webform_' . $webform_node_id . '_validate');
 
  }
 
}
?>

And here is the validation handler which will dump the submitted data to the screen. NOTE: krumo() is available from the devel module; you could use print_r() as well:

<?php
function _MYMODULE_form_alter_webform_146_validate($form, &$form_state) {
 
// debug
 
krumo($form_state);
  die;
}
?>

Now, if I populate the webform with some data:

And submit the form, I will get the following debug output:

You'll need to mirror the structure of the submitted data when creating your $form_state variable, which will be passed into drupal_execute().

In the following function, I show how you can submit a webform programmatically. There is even additional code in there which loads a user's previously submitted data, if you care.

<?php
function MYMODULE_some_function() {

 
// define webform node id
 
$webform_node_id = 146;

 
// define user submitting the webform
 
$user_id = 2;

 
// load webform node
 
if ($node = node_load($webform_node_id)) {

   
// load module include file, per loading previously submitted webform data
   
module_load_include('inc', 'webform', 'webform_report');

   
// get submissions for user
   
$submissions = webform_get_submissions($node->nid, NULL, $user_id);

   
// get submission data ($submission) and submission id ($sid)
   
if (FALSE !== ($sid = key($submissions))) {
     
$submission = $submissions[$sid];
    }
    else {
     
$submission = NULL;
     
$sid = NULL;
    }

   
// create array of $form_state data
    // NOTE: be sure to use the debug output as a guide to make this array match!
   
$form_state = array(
     
'submitted' => true,
     
'values' => array(
       
'submission' => $submission,
       
'submitted' => array(
         
'test_field_1' => 'abc',
         
'test_field_2' => '123',
         
'test_field_3' => 'def',
        ),
       
'details' => array(
         
'email_subject' => $node->webform['email_subject'],
         
'email_from_name' => $node->webform['email_from_name'],
         
'email_from_address' => $node->webform['email_from_address'],
         
'nid' => $webform_node_id,
         
'sid' => $sid,
        ),
       
'op' => t('Submit'),
       
'submit' => t('Submit'),
       
'form_id' => 'webform_client_form_'. $webform_node_id,
      ),
    );

   
// Saves the webform data submited prior to login.
   
drupal_execute('webform_client_form_'. $webform_node_id, $form_state, $node, $submission, TRUE, FALSE);
   
  }

}
?>

Eric's picture

In this tutorial, I'll show you how you can expose your search form on another site using jQuery. At first, I thought about scraping the form's html using AJAX.. and quickly remembered you cannot easily do that. Which lead me to review the AJAX functionality included in jQuery. Bingo, one of my favorites: jQuery.getJSON. To summarize this code, I create a callback function to display the form's json-ified html which can then be easily embedded on another site.

First I defined the menu hook:

<?php
function MYMODULE_menu() {

 
$items = array();

 
// add a page callback for the url: "external-search.js"
 
$items['external-search.js'] = array(
   
'page callback' => '_MYMODULE_external_search',
   
'type' => MENU_CALLBACK,
   
'access arguments' => array('search content'),
  );
   
  return
$items;
   
}
?>

Then I created the callback function for the menu callback:

<?php
function _MYMODULE_external_search() {

 
// create a json string of the search form html
 
$json = drupal_to_js(drupal_get_form('search_form'));
   
 
// format the json as a callback function
  // see: http://docs.jquery.com/Ajax/jQuery.getJSON for more information
 
if ($_GET['jsoncallback']) {
   
$json = $_GET['jsoncallback'] . "(" . $json . ");";
  }
   
 
// output the json
 
print $json;

 
// stop the script, so the theme layer is not applied
 
die;
}
?>

One problem though, the form submits locally. That can be fixed using a form_alter function:

<?php
function MYMODULE_form_alter(&$form, $form_state, $form_id) {
   
 
// check for external search form and set form action to be full path
 
if ($form_id == 'search_form' && arg(0)=='external-search.js') {
   
// change the form action to be the full path
   
$form['#action'] = 'http://' . $_SERVER['HTTP_HOST'] . $form['#action'];
  }
}
?>

Now, if you clear your cache and go to http://YOURSITE/external-search.js, you should see the JSON (and nothing else).

Lastly, you can embed the code on another site using a few lines of jQuery. You can even pull the jQuery from your site if the external site does not have jQuery included.

<!-- Include jQuery (as necessary) -->
<script type='text/javascript' src='http://YOURSITE/misc/jquery.js' ></script>

<!-- create a div container to contain the search form -->
<div id='embedded_search'></div>

<!-- add the jQuery to embed the form -->
<script type='text/javascript'>
$(document).ready(function(){
  // make the ajax request
  $.getJSON("http://YOURSITE/external-search.js?jsoncallback=?",
    function(data){
      // append the form to the container
      $('#embedded_search').append(data);           
    }
  );
});
</script>

Now people should be able to access your site's search form from another site!

Eric's picture

At some point, you might want to restrict sections of a form to certain users and roles. That can be accomplished relatively easy by creating a module that implements 2 Drupal hooks: hook_form_alter and hook_perm.

First, I start by adding the hook_perm():

<?php
function MYMODULE_perm() {
 
// return an array of permissions,
  // they can be named whatever you'd like.
  // NOTE: avoid redeclaring permissions that are already set
 
return array('access secret section of my form');
}
?>

Next, add a form_alter hook:

<?php
function MYMODULE_form_alter(&$form, $form_state, $form_id) {

 
// test for the form id you'd like to alter.
  // if you are unsure of the it's exact name,
  // you could add this: echo $form_id . "<BR>";
 
if ($form_id =='SOME_FORM_ID') {
   
// check if the user has access to the permission you defined
   
if (!user_access('access secret section of my form')) {
     
// deny access to the form element
      // if you don't what what it's called,
      // output the $form object:
      // echo "<pre>" . print_r($form, true) . "</pre>";
     
$form['SOME_FORM_ELEMENT']['#access'] = false;
    }
  }
}
?>

Now, if you enable you module you can restrict permissions by going here: /admin/user/permissions