Introduction
This tip will show you a quick and simple way to add multiple PayPal Buy Now (or other similar buttons) to an ASP.NET web form. The solution is needed because of the way PayPal provides HTML snippets for each button, each is encapsulated within its own form with hidden values specific for that button. This is far from ideal for the ASP.NET world as nested forms are not permitted (as discussed in Implementing-Non-ASP-NET-Posts-in-ASP-NET).
This tip will show you how to avoid this and other associated problems through the implementation of some simple JavaScript manipulation of the hidden input fields PayPal uses when the Buy Now buttons are clicked.
Solution
The PayPal Code
When you create a Buy Now button, you will be presented with an HTML snippet similar to the following:
<form action="https://www.paypal.com/cgi-bin/webscr"
method="post" target="_top">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="[unique identifier]">
<input type="image" src=https://www.paypalobjects.com/en_US/GB/i/btn/btn_buynowCC_LG.gif>
border="0" name="submit" alt="PayPal - The safer, easier way to pay online.">
<img alt="" border="0" src=https://www.paypalobjects.com/en_GB/i/scr/pixel.gif
width="1" height="1">
</form>
If you've included some of the optional elements like specifying the quantity of items to buy, you may also have some additional HTML like the following:
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="[unique identifier]">
<table>
<tr><td><input type="hidden" name="on0"
value="Quantity">Quantity</td></tr><tr><td>\<select name="os0">
<option value="1">1 £15.99 GBP</option>
<option value="2">2 £29.98 GBP</option>
<option value="3">3 £42.97 GBP</option>
</select> </td></tr>
</table>
<input type="image" src="https://www.paypalobjects.com/en_US/GB/i/btn/btn_buynowCC_LG.gif"
border="0" name="submit" alt="PayPal - The safer, easier way to pay online.">
<img alt="" border="0" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" width="1" height="1">
</form>
So you can see above that I have HTML for 2 buttons, one which includes an option to specify quantity. Each button has its own form, a hidden input
named cmd
with the same value "_s-xclick
", one named hosted_button_id
with a unique identifier for that button, an image
input
which submits the page and a 1x1 pixel img
.
The Modified Cleaned Up Code
Leaving aside some of the more trivial and irksome issues with the validity of the HTML (input tags should be self-closing in HTML5, empty alt
tag, etc.) for the moment the first thing needed is to remove the nested forms
entirely, so you either need to move the action, method and target attributes to within the form
tag on your page or, if you're working with master pages, you'll only want these attributes setting on the relevant page so I would suggest doing this programmatically in the Page_Load
event like so:
protected void Page_Load(object sender, EventArgs e)
{
Page.Form.Action = "https://www.paypal.com/cgi-bin/webscr";
Page.Form.Method = "post";
Page.Form.Target = "_top";
}
Now, look more closely at the hidden input
elements, you can see the duplication, the PayPal target URL will simply look for an input with the correct name and take its value, thus with two or more buttons on your page, you will find they all direct to the same item rather than their own specific unique identifier. Therefore, you need to rationalise to only one instance of each of these hidden fields (you may wish to locate them all together at the top of your code) and to give each an id
. This id
will enable finding the hidden input elements through the DOM. You should also take the opportunity to tidy-up the HTML to suit your own personal development standards (e.g. you can remove the table
from the Quantity drop down and simply use a label
and your own CSS for layout) to leave the code looking something like this:
<input type="hidden" name="cmd" value="_s-xclick"/>
<input type="hidden" id="hidButtonId" name="hosted_button_id" value="[unique identifier]"/>
<input type="hidden" id="hidQuantity"
name="on0" value="Quantity"/>
<input type="image" src="https://www.paypalobjects.com/en_US/GB/i/btn/btn_buynowCC_LG.gif" name="submit" alt="PayPal - The safer, easier way to pay online."/>
<img alt="*" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif"
width="1" height="1"/>
<label for="ddlQuantity">Quantity:</label>
<select id="ddlQuantity" name="os0">
<option value="1">1 - £15.99</option>
<option value="2">2 - £29.98</option>
<option value="3">3 - £42.97</option>
</select>
<input type="image" src="https://www.paypalobjects.com/en_US/GB/i/btn/btn_buynowCC_LG.gif" name="submit" alt="PayPal - The safer, easier way to pay online."/>
<img alt="*" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" width="1" height="1"/>
So you can see for each additional button you now only need to include the Buy Now button and 1x1 pixel img
(and any additional options like the drop down list for quantity). Now we need to add the JavaScript function and attach it to the onclick
event on each button. The JavaScript is simple, all we need it to do is set the hosted_button_id
hidden input
field value to the correct value for that item and then to also set any other hidden input
fields appropriately. It is important to notice that for the buttons that don't use the extra options like Quantity you need to prevent the PayPal target page wrongly sniffing out their values, I've chosen to do this by clearing the value of the associated hidden field.
Add a JavaScript function into your page (or your JavaScript file) that is something like the following:
<script type="text/javascript">
function setPPHiddenProperties(itemId, isQuantity) {
document.getElementById('itemValue').value = itemId;
if (isQuantity == 1) {
document.getElementById('hidQuantity').value = "Quantity";
}
else {
document.getElementById('hidQuantity').value = "";
}
}
</script>
And then add an onclick
attribute to each of your Buy Now buttons calling the function passing the relevant values for that button like so:
<input type="hidden" name="cmd" value="_s-xclick"/>
<input type="hidden" id="hidButtonId" name="hosted_button_id" value="[unique identifier]"/>
<input type="hidden" id="hidQuantity" name="on0" value="Quantity"/>
<input type="image" src="https://www.paypalobjects.com/en_US/GB/i/btn/btn_buynowCC_LG.gif" name="submit" onclick="setPPHiddenProperties('uId1',0);" alt="PayPal - The safer, easier way to pay online."/>
<img alt="*" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" width="1" height="1"/>
<label for="ddlQuantity">Quantity:</label>
<select id="ddlQuantity" name="os0">
<option value="1">1 £14.99 GBP</option>
<option value="2">2 £29.98 GBP</option>
<option value="3">3 £44.97 GBP</option>
</select>
<input type="image" src="https://www.paypalobjects.com/en_US/GB/i/btn/btn_buynowCC_LG.gif" name="submit" onclick="setPPHiddenProperties('uId2',1);" alt="PayPal - The safer, easier way to pay online."/>
<img alt="*" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" width="1" height="1"/>
Using this method and extending it to cover any further button options you may implement should allow you to have as many Buy Now buttons on your page as you like.
Summary
In summary, the idea is to:
- Remove the form tags and move the attributes to your ASP.NET form for the relevant page.
- Rationalise the hidden fields and assign them an id.
- Write a JavaScript function to set the values of the hidden fields based upon the incoming parameters.
- Tidy up the HTML and add an
onclick
event to each of your Buy Now buttons to call the JavaScript function with the unique values for that button. - Test the resulting code.
I hope this helps, I think it is an elegant and simple solution and it would have saved me some pain had someone else published it previously. The fact it is a JavaScript solution is mitigated by the fact that PayPal itself requires JavaScript to be enabled for check-out to complete.