April 2008 Archives

You guys have been great. The integration of Ingram Micro into our webstore was huge. That alone saved us days of work — not to mention the support and know-how from your team along the way... what a difference compared to our previous provider.

We just wanted to say, THANK YOU for all your help. We tell all our friends about your service.

— Harvey & Rolondia, TopSales Too HP Laser Jet and Lexmark parts

Build a Smart Catalog

One of the most important jobs you have as an online entrepreneur is to create a store where people can easily shop for goods in an online environment. Just like Mail Order, a well structured catalog is easy to use. If they are going to enjoy shopping your store, the catalog has to be easy to browse. The larger your product offering, the more of a challenge this will become.

Remember, your catalog is the way you present your products to the consumer. It should not necessarily follow the same model in which you purchase these products or store them in your warehouse. Basically always look at the catalog from your consumers point of view rather than your own.

Example: you buy all your stuff wholesale and have all the SKU's memorized. Obviously, the easy was is to make customers search by SKU... wrong. They want to browse by category or price range or brand name — maybe even season or type. Keep this in mind as you create your online catalog and refine it as you go.

Write Just Enough, But Not Too Much

Spend extra time naming and describing both your products and categories. For example: Instead of having a category called "Shirts" filled with 117 shirts, consider breaking it up a bit. How about 4 or 5 categories like "Mens Short Sleeve Tee's", "Ladies Tank Tops", "Kids Long Sleeve Shirts", etc... this makes your store easier for the user and better for search engines at the same time.

Don't Forget About the Shipping

Shipping can make or break a sale and/or your wallet. Many new online store owners are taken by surprise when they have to setup, plan or even execute a shipment. The more planning upfront you do with shipping, the better.

Try to mirror your real world warehouse experience. The closer you can get your online store setup to match your real-world shipping methods, the happier you and your shoppers will be in the end. Setting up a quality shipping table or ensuring an accurate shipping quote from an integrated shipper should be right up there with your catalog when it comes to planning and setup.

ProStores has a built in mail processor that it uses to send messages - like the Email a Friend feature for example. The cool part is, you can use the form mail processing that is built in to send your own forms - perhaps a "Contact Us" form or an "Ask a Question" form.

You can use the code below on any ProStores template to create a form that sends a message.


<form name="emailfriend" method="POST" action="Send.bok">

	<p>FROM</p>
	<p>Name <input type="text" name="$$email.senderName" value=" "></p>
	<p>E-Mail <input type="text" name="$$email.senderEmail" value=" "></p>

	<p>TO</p>
	<p>Name <input type="text" name="$$email.recipientName" value=" "></p>
	<p>E-Mail <input type="text" name="$$email.recipientEmail" value=" "></p>

	<hr size="1"/>
	<p>MESSAGE<br><textarea name="$$email.message" cols="40" rows="3" wrap="virtual"></textarea></p>
	<p><input type="submit" value="Send"></p>

</form>

The ".bok" on the action may not be needed - it depends on the type of ProStores installation in which your store lives.

Key ingredients for Tribal Hollywood project:

  • Brand image - creating a graphical theme that connects with their target market
  • Recreating the successful in-store sales experience online
  • Up sell and add-on opportunities
  • Search Engine Optimization

Our image is Tribal and Urban. It's tribal symbols combined with the style and coolness of a hot Hollywood nightclub. It's tattoo imagery... but not rocker.

The guys over at Tribal Hollywood were able to describe what they wanted with a refreshing clarity. By using lots of texture and style we were able to create the shopping environment Tribal wanted. This was going to be an important part of connecting with their audience.

study-th-home.jpg

Category pages needed different ways to present products - similar to the physical location. The ProStores template language (SSML) allowed us to create certain page styles for certain categories. For example, the Pendants page should have a different layout than the Ed Hardy Watches.

study-th-listsub.jpg

The biggest challenge was the add-on options for the Pendants. To be able to add many different necklace styles to all the different pendants was a tall order for sure. Our programmers worked some black magic and created an easy, insightful way for the shopper to get just what they want.

th_detail.jpg

Aboriginal Boomerang

Dear neoverve,
In honor of a Tribal website well done, we want to present you with this authentic, hand-made Aboriginal Boomerang. Thank You!

— Grant & Kent, Tribal Hollywood

Glad you like the site guys! It's one of our favorites too - our super-speed designer-stud Tom Le really drove it home. The whole team loves hearing about successes when our sites drive business into a physical store location — bridging the gap between e-stores and the-stores. The boomerang you sent is ACE!

The documentation provided for the ProStores XTE (XML Transaction Engine) authentication scheme is pretty thorough, so I will assume that you are familiar with the variables, and how to receive them into your application. That being said, here is a way to create an XTE 3.0 token using PHP.



$entry_url = {$_GET variable};
$app_id = {$_GET variable or hardcoded};
$secret = {$_GET variable or hardcoded};
$timestamp = time();

$entry_url_pre_sig = "$secret&appid=$app_id&ts=$timestamp";
$entry_url_sig = md5($entry_url_pre_sig);

$complete_entry_url = "$entry_url/getInfo?appid=$app_id" . "&ts=$timestamp" . "&sig=$entry_url_sig";

$result = http_post_send($complete_entry_url, 80, '', 'text/xml', '');        
$responseXML = str_replace('&#174;', "", $result['body']); 
$tree = GetXMLTree($responseXML);

$xml_api = $tree["XTE"][0]["RESPONSE"][0]["XMLAPI"][0]["VALUE"];
$rest_api_non_secure = $tree["XTE"][0]["RESPONSE"][0]["RESTAPINONSECURE"][0]["VALUE"];

$api_ticket = $_GET['ticket'];

$get_token_pre_sig = "$secret&appid=$app_id&ts=$timestamp&ticket=$api_ticket";
$get_token_sig = md5($get_token_pre_sig);

$complete_token_url = $rest_api_non_secure . "auth/getToken?appid=$app_id" . "&ts=$timestamp" . "&ticket=$api_ticket" . "&sig=$get_token_sig";

$token_result = http_post_send($complete_token_url, 80, '', 'text/xml', '');        
$responseXML = str_replace('&#174;', "", $token_result['body']); 
$tree = GetXMLTree($responseXML);

$token = $tree["XTE"][0]["RESPONSE"][0]["TOKEN"][0]["VALUE"];

echo "Your sweet token = $token ";

/*  These facilitate the transmission of data to the xte, and parsing the data into a nice array */

function http_post_send($url, $port, $body, $content_type, $cookie) {
	$url = ereg_replace("^http://", "", $url);
	$host = substr($url, 0, strpos($url, "/"));
	$uri = strstr($url, "/");
	$header = http_post_header($uri, $host, strlen($body), $content_type, $cookie);
	$socket = fsockopen($host, $port, $errno, $errstr);
	fputs($socket, $header.$body);
	$ret = array("header" => array(), "body" => "");
	$reading_header = true;
	$status = array("unread_bytes" => 1);
	while ($status["unread_bytes"] != 0){
		$chunk = fgets($socket);
		$status = socket_get_status($socket);
		if($reading_header){
			if ($chunk == "\r\n"){
				$reading_header = false;
			}
			else{
				$ret["header"][] = $chunk;
			}
		} 
		else{
			$ret["body"] .= $chunk;
		}
	}
	
	while ($more = fgets($socket)){
		$ret["body"] .= $more;
	}
	
	fclose($socket);
	return $ret;
}

function http_post_header($uri, $host, $content_length, $content_type, $cookie) {
	$h  = "POST $uri HTTP/1.0\n";
	$h .= "Host: $host\n";
	$h .= "User-Agent: Mozilla/4.0 [en] (Windows NT 5.0; U)\n";
	$h .= "Accept: */*\n";
	$h .= "Accept-Language: en-us\n";
	$h .= "Accept-Encoding: gzip, deflate\n";
	$h .= "Connection: Keep-Alive\n";
	$h .= "Content-Type: $content_type\n";
	$h .= "Content-Length: $content_length\n";
	$h .= "\n";
	return $h;
}

function GetXMLTree($data) { 
	$parser = xml_parser_create('ISO-8859-1');
	xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); 
	xml_parse_into_struct($parser, $data, $vals, $index); 
	xml_parser_free($parser); 
	
	$tree = array(); 
	$i = 0; 
	$tree[$vals[$i]['tag']][] = GetChildren($vals, $i); 
	return $tree; 
} 


function GetChildren($vals, &$i){ 
	$children = array();
	if(isset($vals[$i]['value'])){ 
		$children['VALUE'] = $vals[$i]['value']; 
	}
	while(++$i < count($vals)){ 
		switch ($vals[$i]['type']){ 
			case 'cdata': 
				if(isset($children['VALUE'])){
					$children['VALUE'] .= $vals[$i]['value'];
				}
				else{
					$children['VALUE'] = $vals[$i]['value'];
				}
				break;
			case 'complete': 
				if(isset($vals[$i]['attributes'])) {
					$children[$vals[$i]['tag']][]['ATTRIBUTES'] = $vals[$i]['attributes'];
					$index = count($children[$vals[$i]['tag']])-1;
				
					if(isset($vals[$i]['value'])){ 
						$children[$vals[$i]['tag']][$index]['VALUE'] = $vals[$i]['value'];
					}
					else{
						$children[$vals[$i]['tag']][$index]['VALUE'] = '';
					} 
				} 
				else{
					if(isset($vals[$i]['value'])){ 
						$children[$vals[$i]['tag']][]['VALUE'] = $vals[$i]['value'];
					} 
					else{
						$children[$vals[$i]['tag']][]['VALUE'] = '';
					} 
				}
				break; 
			case 'open': 
				if(isset($vals[$i]['attributes'])){
					$children[$vals[$i]['tag']][]['ATTRIBUTES'] = $vals[$i]['attributes'];
					$index = count($children[$vals[$i]['tag']])-1;
					$children[$vals[$i]['tag']][$index] = array_merge($children[$vals[$i]['tag']][$index],GetChildren($vals, $i));
				} 
				else{
					$children[$vals[$i]['tag']][] = GetChildren($vals, $i);
				}
				break; 
			case 'close': 
				return $children; 
		} 
	} 
} 

This post may stray from my usual uber-helpful code snippet. But, it could save you unbelievable amounts of time so pay very close attention...

The ampersand character is known around here as the devil symbol. Not the word "ampersand" mind you, but ---> & <---- this evil guy. Stay away from it unless you're using it to escape your HTML. The word 'and' is only two characters longer. In fact, in order to produce that symbol, you have to hold down the shift key, and press 7 which definitely takes more energy and concentration. So the next time your xml_parse_into_struct fails to push data into the array, check to see that your sweet & sour chicken is both sweet and sour.

P.S. all symbols are stupid. Stay away from them.
P.P.S. Don't ever use Word for web text. It's stupid, and has stupid characters.

Several ProStores hosting customers experienced a critical error early Monday morning (04/07/2008). An error message appeared on the Store Front and in the Store Administration for affected customers, causing the store to be inoperable. We believe the issue was triggered by our regularly scheduled maintenance, but the error didn't occur until several hours after the maintenance was completed. We have not experienced any issues previously with regards to ProStores hosting or any of our other offerings due to routine server maintenance.

Since this was a software error and not an actual server/service down event, our automated monitoring systems were unable to detect the issue and alert our technical staff.

In addition, our telephone paging service was unavailable during the early morning on Monday. Therefore, the technical staff was not alerted to this issue until we opened our office at the start of the business day. Upon discovery of the problem, the issue was immediately escalated to top tier and the ProStores application was restored.

The application vendor of ProStores, Ebay, was alerted shortly thereafter and a proposed fix was sent to Neoverve. According to Ebay, there is a bug in the configuration where a section for multi-cast clustering is enabled by default.

An updated configuration fix will be completed today on all ProStores servers. We are also investigating a new paging system with multiple escalation support to be implemented immediately.

We fully understand the severity of the service interruption and apologize for its effect. All measures will be taken to ensure continuous service for our customers.

Here is an example of the order confirmation code you receive from become.com - customized for use within your ProStores Order Confirmation template source code.



<!-- Become.com -->

<ss:set name="a1" value="https://partner.become.com/tracking/t.gif?merchantid=/*Your merchantID would go here*/&order_id="/>
<ss:set name="a2" value="$invoice.invoiceNumber"/>
<ss:set name="a3" value="&order_value="/>
<ss:set name="a4" value="$invoice.total" format="none"/>
<ss:set name="a5" value="&num_items="/>
<ss:set name="a6" value="$invoice.itemCount"/>
<ss:set name="aTotal" value="$string.concat($a1, $string.concat($a2, $string.concat($a3, $string.concat($a4, $string.concat($a5, $a6)))))"/>

<img src="$aTotal" id="become_t"/> 
<script type="text/javascript" language="javascript" src="https://partner.become.com/tracking/conversion.js"> </script>

<!-- Become.com -->

Sometimes a secure XTE call is necessary based on the type of information you plan to extract from ProStores and use in your PHP application.  I know the big one that I need is anything having to do with credit card details.  So, whether you are looking to retrieve those details, or if you would like to know how to process http data via a secure channel here's some info.

One of the best functions I've found to process the proper http data is a built in function called fsockopen.  You're basic URL call would look something like the following:


$socket = fsockopen("www.domain.com", 80); 
// 80 = port that you want to post through

Now if you wanted to go secure, you would need to change it up a smidge.


$socket = pfsockopen("ssl://www.domain.com", 443); 
// 443 = secure port

Also, you'll need to make sure your PHP has openssl installed and configured.

About this Archive

This page is an archive of entries from April 2008 listed from newest to oldest.

March 2008 is the previous archive.

May 2008 is the next archive.

Find recent content on the main index or look in the archives to find all content.