Using image submit buttons in 5.x with $_POST

There are several places scattered around Drupal.org discussing how to make image submit buttons work. None of them seem to do it this way, and this only requires a few extra lines in your form builder function. You may wonder if it's a hack to use the $_POST array, but this is the current way to handle Back/Cancel buttons without validating forms. So why not here?

The code:

<?php
 
function imagebutton_test_form() {
   
// Check to see if the image button was clicked.
   
if (isset($_POST['submit_x'])) {
     
$form['submit'] = array(
       
'#type' => 'submit',
       
'#value' => 'submit',
      );
    }

   
$form['submit_image'] = array(
     
'#value' => '<input name="submit" type="image" title="'. t('Submit the form.') .'" src="/files/mysubmit.gif">',
    );

    return
$form;
  }
?>

The explanation:

This is the builder function for a form that submits using an image button. Ignoring for a moment the check to see if the button was clicked, notice that the second part of the function simply adds the image button using straight HTML. This is just the quick and easy way to do it without creating a whole new form element type. Just make sure you're using good HTML and you won't have a problem.

When an image button is clicked to submit a form, a couple extra variables are submitted representing x and y coordinates for where on the image you clicked. These will be named using the name of the image element with an _x or _y after it. In the case of the example, the coords are named submit_x and submit_y.

So, you can use a simple check at the beginning of the form function to see if the form was submitted using our image button. If so, we want to add a submit element to the form array to fake a submission through the button. You must make sure the name of the image element and the value of the submit element are the same. If they are, the Forms API will then process the form like it was submitted using the fake submit element!

In this case, whatever validation or submit function you're wanting to process would follow the normal Forms API naming convention: imagebutton_test_form_validate() and imagebutton_test_form_submit().

This method has been tested and is currently in use for the PayPal module in Ubercart. You can see it in action by going to the Livetest, adding something to the cart, and clicking the PayPal Express Checkout button.

A few more references

dgorton - September 14, 2007 - 17:37

Just adding some potentially useful reading links:
http://drupal.org/node/144758 ("Change submit buttons to images for a given form")
http://drupal.org/node/62647 ("HOWTO: Create image submit button")

Drew Gorton
Gorton Studios

$form['#post']['Submit_x'] versus $_POST['submit_x']

andrabr - February 29, 2008 - 05:43

One can use $form['#post']['Submit_x'] instead of $_POST['submit_x']

The outcome is same, but using a Drupal internal structure seemed possibly more future-proof (or not?)

Two days of my life have produced this:

andrabr - February 29, 2008 - 10:08

I was struggling with the same issue (and unfortunately stumbled across this most excellent post only 10 hours into my VERY frustrated adventure), and want to share a few observations:

My goal was rather specific: I wanted to have pretty Submit and Delete buttons in the node/xxx/edit form.

There are two problems with it:
i) the one described above (only it did not quite work for me), and
ii) It appears to be a multipage form, where the Delete branch does not go through validation. It is triggered by submission of op=Delete, which does not happen in IE (IE submits op_x and op_y with the click coordinates instead). I am not aware of a politically correct way to modify $_POST values prior to a form being built, so I had to fall back to jQuery :(

For some reason the technique above was not working out, so I came up with the following variation:

1) In template.php I styled the form: told Drupal that the Submit and Delete buttons have been printed and called a template where I manually entered my "pretty" HTML

In template.php:

function phptemplate_post_node_form($form) {
  $form['submit']['#printed'] = 1;
  $form['delete']['#printed'] = 1;
  return _phptemplate_callback('form_edit_post', array('form' => $form));
}

Simplified form_edit_post.tpl.php:

<?php
     
print drupal_render($form);
?>


<input name="Submit" id="edit-submit" class="clear" value="<?=$form['submit']['#value']?>" class="form-<?=$form['submit']['#type']?>" type="image" src="http://test.mysite.com/images/submit.gif" />

<?php
if ($form['delete']) {
?>

<input name="Delete" id="edit-delete" value="Delete" class="form-submit" type="image" src="http://test.mysite.com/images/delete-button.png">
<?php  ?>

Notice that I tried to copy the original Drual statements as closely as possible (who needs extra headache!).
I also changed the name of the inputs from "op" to "Submit" and "Delete" respectively.

2) I used hook_form_alter to
a) fake the proper inputs for "civilized" browsers
b) insert a hidden input field named "op" and a jQuery script for IE

function my_form_alter($form_id, &$form) {
  if ($form_id == 'post_node_form'){

    if (isset($form['#post']['Submit_x']) || ($form['#post']['Submit'] == 'Submit')) {

      $horrible_hack['#parents'] = array ('op');
      form_set_value($horrible_hack,'Submit');

      global $form_submitted;
      $form_submitted = TRUE;
    }

    if (isset($form['#post']['Delete_x']) || ($form['#post']['Delete'] == 'Delete')) {
      $horrible_hack['#parents'] = array ('op');
      form_set_value($horrible_hack,'Delete');

      global $form_submitted;
      $form_submitted = TRUE;
    }
// now we create the hidden 'op' field, because IE expects it

    $form['op'] = array(
      '#type' => 'hidden',
      '#value' => ''
      );
// add a script that will populate the field
    $script = '$(function() {$("#edit-delete").click(function(){ $("input[name=\'op\']").attr("value","Delete");});})';
    drupal_add_js($script, 'inline');

  }
}

Notice that I did not have to apply jQuery magik to Submit image, since it is processed properly and can be tackled by hook_form_alter.

The $horrible_hack is there because function form_set_value is not documented well and I probably handled it wrong. But it worked!

It is possible to move most of the code from hook_form_alter to a custom validation function. The manuals suggest that it is an improper use of the validation mechanism, but this whole solution is ugly as sin anyway.

Parts of this code are probably redundant...

I really hope that someone smarter than me can take this little code-monster and make it all generic, pretty, and proper.

Bit confused: if an error is

ceej23 - July 12, 2008 - 12:02

Bit confused: if an error is generated, the form is re-rendered but since the image was clicked and $_POST['submit_x'] is set, the fake submit button is also rendered. Have I missed something?

http://www.drupalnotes.org

 
 

Drupal is a registered trademark of Dries Buytaert.