background image
HomeRecent PostsDrupalSearchTagsRSSContactAboutAccount
Eric.London'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!

The purpose of this code snippet is to show you how you can use the lightmodal functionality in the Lightbox2 module to embed a form in a fancy css popup window. But why would you want to do this? Because it looks great and it improves usability.

The first thing you'll need to do is register a menu item for the page callback that you'd like to appear in the lightbox window.

<?php
function MYMODULE_menu() {
 
$items[] = array();

 
$items['MY/URL'] = array(
   
'page callback' => 'drupal_get_form',
   
'page arguments' => array('MYCALLBACK_form'),
   
'type' => MENU_CALLBACK,
   
'title' => t('MY TITLE')
  );

  return
$items;
}
?>

Next, define a function to create the form

<?php
function MYCALLBACK_form($form_state) {
 
$form = array();

 
// add your form elements here. for example:
 
$form['MYTEXTFIELD'] = array(
   
'#type' => 'textfield',
   
'#title' => t('MY TEXT FIELD'),
  );

 
// add submit button
 
$form['submit'] = array(
   
'#value' => 'Submit',
   
'#type' => 'button'
 
);

 
// add cancel button
  // NOTE: the cancel button simply closes the lightbox window
 
$form['cancel'] = array(
   
'#value' => 'Cancel',
   
'#type' => 'button',
   
'#attributes' => array(
     
'onClick' => "Lightbox.end('forceClose'); return false;"
   
)
  );

  return
$form;
}
?>

Next, add a link to your page content to open up the lightbox window with your new form in it. By adding the rel=lightmodal property onto an A tag, you'll automatically load the contents of the href in a fancy lightbox window.

<?php
// NOTE: you should use the l() function here to properly generate your A tag
$page_contents .= '<a href="/MY/URL" rel="lightmodal">MY LINK TEXT</a>';
?>

I made my lightbox form more usable by using ajax to submit the form to another page callback. First, I had to add an onSubmit javascript event handler to my form to prevent it from submitting.

<?php
function MYCALLBACK_form($form_state) {
 
// ...code...
 
$form['#attributes'] = array(
   
'onsubmit' => 'return my_js_submit_function(this);'
 
);
 
// ...code...
}
?>

Now, define a javascript function to validate and submit the form using AJAX.

function my_js_submit_function(whichThis) {
  // validate your form here

  // define arguments to pass to ajax page callback
  // you'll actually want to collect the user submitted form data here
  var args = {
    myArg1: 'blah',
    myArg2: 'blah',
  };

  // submit the data using jQuery
  // in this case, I'm using the getJSON function which uses GET and expects a JSON object in return
  $.getJSON('/MY/URL/SUBMIT', args,
    function(json){
      // check for a return status, show a message, close the lightbox window, etc
      alert(json.message);
      if (json.status == true) {
        Lightbox.end('forceClose');
      }
    }
  );
}

You'll need a final page callback and menu item to process the AJAX

<?php
function MYMODULE_menu() {
 
// ...code...
 
$items['MY/URL/SUBMIT'] = array(
   
'page callback' => 'MYMODULE_CALLBACK_SUBMIT',
   
'type' => MENU_CALLBACK,
  );
 
// ...code...
}

function
MYMODULE_CALLBACK_SUBMIT() {
 
// 1. validate $_GET (not shown, use your imagination)
  // 2. process $_GET (not shown, use your imagination)
  // 3. return a JSON object

  // create return object
 
$returnO = new StdClass();
 
$returnO->status = true;
 
$returnO->message = 'MY INFORMATIVE MESSAGE HERE';

 
// output json result
 
print drupal_json($returnO);

 
// NOTE: if you don't die here, then the theme will be processed. we only want to return a JSON object
 
die;
}
?>

In the end, what we have is a link that opens up a lightbox window that contains a form that is submitted via ajax.

My last thoughts... because the lightmodal functionality loads the URL from the href in the A tag, you might want to create a template file for your page layout that is simplified to prevent your normal page layout from being rendered. For instance, you could create a theme file called, page-MY-URL.tpl.php that contains the following:

<?php
if ($title) print "<h1>$title</h1>";
if (
$messages) print $messages;
if (
$help) print $help;
if (
$content) print $content;
?>

Syndicate content