In this article, we're going to do something most people didn't know was possible. We're going to add a entirely new custom field to a product. You may ask why I would do that when I could use a product template. Well, for every good question there's (usually) a good answer or two. In fact, product templates have some limitations. First, you can only have one template assigned to your product. Change the template, and you've changed the field choices for ALL the assigned products. Second, you have to assign the product template to each product. Depending on the number of products involved, that could become quite tedious and/or time-consuming for you.
Product custom fields are different. We're going to design them right into the main Edit Product page. This makes them faster and easier to access for the site admin. It also makes them VERY noticeable - no clicking into sub-screens to see what fields are there or how they're assigned. Product custom fields also gives you the flexibility to offer the new custom field to all your store products in one swoop. Plus product custom fields are just cooler. You want to be a cool site admin right? Of course you do!
As always - make a backup of the files you modify BEFORE you change them. That way you can put things back the way they were if something doesn't go as planned.
What's the Plan, Stan
Before we begin, let's talk a little about your "need". No, not THAT need. Let's keep it clean because this is a forum for professionals. Our "need" today is simple. We have certain products in our catalog that qualify for free shipping. In order to improve sales on these products, we want something on the product page to show the visitor that the displayed product qualifies for free shipping. Sure, you could create a product template with merchant-side field for free-shipping and look for that in the product page code. But that means you have to assign that template to all the products, and those products already have a product template assigned. So we're going to leverage product custom fields by adding a new custom field called "FreeShip".
Now that we know our need, we want to put together a plan. The plan isn't quite as simple. We have to make a custom field. We're going to need to give the site admin a way to set the value of that field on the edit product page. Then we've got to find a way to display the free shipping teaser on the product page itself. My Indiana farmtown math skills tell me we're going to have 3 major steps to this modification. Great, now we have a plan - let's get started!
The New Custom Field
To get our custom field off the ground, we start with the Admin-side Edit Product page. This page is pretty large, so we'll have to be careful when we make changes lest we blow something (else) up. Since our custom field is a shipping-related field, we're going to add it the "Taxes and Shipping" section of the edit product page.
Find the ~/Admin/Products/EditProduct.aspx file and edit it. When your editor loads, search for the word "TAXES" and it should take you to a line that looks just like this:
Code: Select all
<tr class="sectionHeader">
<td colspan="4">
TAXES & SHIPPING
</td>
</tr>
Code: Select all
<tr class="sectionHeader">
<td colspan="4">
TAXES & SHIPPING
</td>
</tr>
<tr>
<th class="rowHeader" nowrap>
<asp:Label ID="lbl_FreeShip" runat="server" Text="Free Shipping?" />
</th>
<td>
<asp:CheckBox ID="chk_FreeShip" runat="server"/>
</td>
</tr>
"Swell - I've got the field but it doesn't work" you might say. That's correct - all we've done is display a checkbox. We haven't told the server to save (or load) the checkbox value. Read on and I'll explain how to read and write the actual product custom field values.
Save/Load a Product Custom Field
Able did a fantastic job with the data classes. Everything ties together nicely so that it's almost always quick and easy to find a related piece of data. In our case, the primary object is a product. But a part of that product is a collection of sub-objects. One such sub-object is the product custom fields class. Since the product custom fields are stored in their own seperate table in the database, we're free to create as many as we like for each product.
In our project today, we just need to create one product custom field. We're going to call it "freeship". You could also call it "freeshipping" or even "customertakesmyprofitsagain" but "freeship" self-explanatory without being excessively lengthy. Keeping field names to a reasonable length (<10) keeps your programming code more organized and easier to follow down-the-road.
Let's get started with adding a custom field. This step is broken into two parts - The Save and the Load. When someone edits the product, we want to save whether the checkbox was checked or not. When someone pulls up the product record to edit it, we need to make sure the checkbox is set to the value of the "freeship" custom field.
Start with the Save step by editing the ~/Admin/Products/EditProduct.aspx.cs code file. In the file, search for "SaveButton_Click". It should take you straight to this code:
Code: Select all
public void SaveButton_Click(object sender, EventArgs e)
{
ValidateFieldsLengths();
if (Page.IsValid)
{
//BASIC INFO
Code: Select all
public void SaveButton_Click(object sender, EventArgs e)
{
ValidateFieldsLengths();
if (Page.IsValid)
{
//BASIC INFO
// BEGIN MOD: AbleMods.com
bool _PCFExists = false;
string _FreeShipValue = chk_FreeShip.Checked.ToString();
foreach (ProductCustomField _PCF in _Product.CustomFields)
{
if (_PCF.FieldName == "freeship")
{
_PCF.FieldValue = _FreeShipValue;
_PCF.Save();
_PCFExists = true;
break;
}
}
if (! _PCFExists)
{
ProductCustomField _NewPCF = new ProductCustomField();
_NewPCF.ProductId = _Product.ProductId;
_NewPCF.FieldName = "freeship";
_NewPCF.FieldValue = _FreeShipValue;
_NewPCF.Save();
}
// END MOD: AbleMods.com
Code: Select all
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
//BASIC INFO
Code: Select all
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
//BASIC INFO
// BEGIN MOD: AbleMods.com
foreach (ProductCustomField _PCF in _Product.CustomFields)
{
if (_PCF.FieldName == "freeship")
{
chk_FreeShip.Checked = AlwaysConvert.ToBool(_PCF.FieldValue, false);
break;
}
}
// END MOD: AbleMods.com
Displaying the Product Custom Field
Finally we're to the fun part - the visitor display side. Here's where we get to enjoy the fruits of our effort. For today's project, the free shipping indicator, we want something to appear on the product page when the product qualifies for free shipping. We've already added a custom field for free shipping, so now we just need to see if that value exists for the currently displayed product. Since all product pages will use the BuyProductDialog user control, we're going to make our modification there. Open your ~/ConLib/BuyProductDialog.ascx.cs file and search for the text "Page_PreRender". You should find this line:
Code: Select all
protected void Page_PreRender(object sender, EventArgs e)
{
Code: Select all
protected void Page_PreRender(object sender, EventArgs e)
{
//BEGIN MOD: AbleMods.com
// Show Free Shipping image if product qualifies
foreach (ProductCustomField _PCF in _Product.CustomFields)
{
if (_PCF.FieldName == "freeship")
{
if (_PCF.FieldValue == "True")
{
this.Controls.Add(new LiteralControl("<img src='/images/freeship.gif'/>"));
break;
}
}
}
// END MOD: AbleMods.com
The image (or text) will appear directly below the add-to-cart button. Feel free to play with the size of the image to suite your particular site design needs.
The Next Step
Now that you've gone through the entire process of adding a product custom field, you probably have some questions. Here are some common questions and answers to help you get further:
Q: What if I want a text box instead of a checkbox? I have several possible values for a single custom field.
A: No problem. On the EditProduct.ascx page, you're going to add an <asp:Textbox> control instead of a checkbox. Then in the EditProduct.ascx.cs Page_Load() code, make sure you change the "chk_freeship.Checked" to "chk_FreeShip.Text". Then change the AlwaysConvert.ToBool() function to AlwaysConvert.ToString(). In the SaveButton_Click() function change the chk_FreeShip.Checked.ToString() to chk_FreeShip.Text. Finally, on the BuyProductDialog.ascx.cs page, change the line that looks for "= True" to " = whateveriwant". It'd be easier to code a dropdown list but that goes beyond the scope of this document.
Q: What if I want more than one custom field? I have lots of needs!
A: Easy as pie. Duplicate all the code you've done for each unique custom field you want. Just be sure to use different names for each one so they don't overlap or confuse the web server.
Q: This seems like a lot of work for one custom field. Why again didn't we use a product template?
A: How many product records did you have to edit so they would show a free shipping checkbox? I thought so.
Conclusion
Able went to a lot of trouble to design an excellent database structure. By leveraging this structure in ways that go beyond the admin pages available, you find all sorts of new ways to enhance your storefront. In this project, we've added a nifty checkbox to the edit-product page. When the checkbox is checked, an enticing graphic is automatically displayed on the visitor-side product page to indicate free shipping is available. This same concept can be applied to other product-specific situations like flat-rate shipping or in-store purchase required. The possibilities are endless.