Sears eCommerce debacle

No wonder Sears is getting kicked in the rear by Amazon and others. I want to buy a socket set, cool it’s on sale at sears for $17.99 regularly $29.99. The Newington store has two in stock. Continuing with my iPad I start the order.

I notice on the checkout page,it say something about use your “shop you way rewards points”. I think I may have some because we bought some school uniform pant’s for Jameson last fall.I login and sure enough, I’ve got a 7,000 surprise points good for $7 off the order. I click the apply points button and it places the order without applying the points. Great.

That’s OK, I’ll just cancel the order and be more careful the next time. After hunting around for a while, I find the hidden cancel order button and cancel the first order and I find the set again start a second order. This time when I click the apply points and checkout button I see there is a “enter your pin code” text box several inches over and down with some tiny text about rewards points.

Great so once again, I’ve ordered without the credit so this time I call customer service…no help there, the first level rep and supervisor both tell me they can’t apply the credit after the order is placed.

While on the phone with the reps who are continuing to be unhelpful, I use my desktop and start a third order. This time I enter a usual pin code and click apply. No that’s not it. I try another likely code. No that’s not it. OK I’ll try one more I use sometimes and it’s still not it. Still on the phone with the rep, I say it won’t take a pin code, what do I do. He says enter your zip code. Wow that works! How I was supposed to know that my pin code is my zip code I have no idea. I know I didn’t set that up.

Good, now I can place the third order however it’s now showing 3-5 day before it will be ready. I know that both of the two in stock are being held for me. I ask the rep how long before the system will catch up and return to stock the first one I purchased…three to five days.

I was tempted to cancel the second order but I’ve decided to leave it, when I go to pick it up, I’m going to make them cancel it and fulfill the third order with that set. Wonder how that’s going to go.

Another way to redirect mobile devices to m. subdomain

Mortaza Kamal Nourestani posted here a way to ensure that mobile devices are served at a “m.” subdomain site, and that desktop devices are served at the normal domain.
Here’s my take on that using a resolver in the httprequest pipeline. This only requires adding a class, and .config file with no modifications to existing files. I’ve reused his IsMobileBrowser method.

using System;
using System.Linq;
using System.Web;
using Sitecore.Pipelines.HttpRequest;

namespace Samples.Extensions.Resolvers
{
    public class MobileSiteResolver : Sitecore.Pipelines.HttpRequest.SiteResolver
    {
        public override void Process(HttpRequestArgs args)
        {
            string absoluteUri = String.Format("{0}://{1}{2}", HttpContext.Current.Request.Url.Scheme,
                                                       HttpContext.Current.Request.Url.Host,
                                                       HttpContext.Current.Request.RawUrl);

            string host = HttpContext.Current.Request.Url.Host;

            if (host.StartsWith("m."))
            {
                if (!IsMobileBrowser(HttpContext.Current))
                {
                    host = host.Replace("m.", "");
                    absoluteUri = absoluteUri.Replace(HttpContext.Current.Request.Url.Host, host);
                    HttpContext.Current.Response.Redirect(absoluteUri);
                }
            }
            else
            {
                if (IsMobileBrowser(HttpContext.Current))
                {
                    host = String.Format("{0}.{1}", "m", HttpContext.Current.Request.Url.Host);
                    absoluteUri = absoluteUri.Replace(HttpContext.Current.Request.Url.Host, host);
                    HttpContext.Current.Response.Redirect(absoluteUri);
                }
            }
        }

        public static bool IsMobileBrowser(HttpContext context)
        {
            //FIRST TRY BUILT IN ASP.NT CHECK
            if (context.Request.Browser.IsMobileDevice)
            {
                return true;
            }
            //THEN TRY CHECKING FOR THE HTTP_X_WAP_PROFILE HEADER
            if (context.Request.ServerVariables["HTTP_X_WAP_PROFILE"] != null)
            {
                return true;
            }
            //THEN TRY CHECKING THAT HTTP_ACCEPT EXISTS AND CONTAINS WAP
            if (context.Request.ServerVariables["HTTP_ACCEPT"] != null &&
                context.Request.ServerVariables["HTTP_ACCEPT"].ToLower().Contains("wap"))
            {
                return true;
            }
            //AND FINALLY CHECK THE HTTP_USER_AGENT
            //HEADER VARIABLE FOR ANY ONE OF THE FOLLOWING
            if (context.Request.ServerVariables["HTTP_USER_AGENT"] != null)
            {
                //Create a list of all mobile types
                string[] mobiles =
                    {
                        "midp", "j2me", "avant", "docomo",
                        "novarra", "palmos", "palmsource",
                        "240x320", "opwv", "chtml",
                        "pda", "windows ce", "mmp/",
                        "blackberry", "mib/", "symbian",
                        "wireless", "nokia", "hand", "mobi",
                        "phone", "cdm", "up.b", "audio",
                        "SIE-", "SEC-", "samsung", "HTC",
                        "mot-", "mitsu", "sagem", "sony"
                        , "alcatel", "lg", "eric", "vx",
                        "NEC", "philips", "mmm", "xx",
                        "panasonic", "sharp", "wap", "sch",
                        "rover", "pocket", "benq", "java",
                        "pt", "pg", "vox", "amoi",
                        "bird", "compal", "kg", "voda",
                        "sany", "kdd", "dbt", "sendo",
                        "sgh", "gradi", "jb", "dddi",
                        "moto", "iphone"
                    };


                //Loop through each item in the list created above
                //and check if the header contains that text
                if (mobiles.Any(s => context.Request.ServerVariables["HTTP_USER_AGENT"].ToLower().Contains(s.ToLower())))
                    return true;

            }

            return false;
        }
    }
}

To enable this resolver create a config file in /app_config/includes/ such as mobiledeviceresolver.config with these content:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
    <sitecore>
        <pipelines>
            <httpRequestBegin>
                <processor patch:before="*[@type='Sitecore.Pipelines.HttpRequest.SiteResolver, Sitecore.Kernel']"
                type="Samples.Extensions.Resolvers.MobileSiteResolver, Logica.Extensions"/>
            </httpRequestBegin>
        </pipelines>
    </sitecore>
</configuration>

The usual caveats apply, this is untested in a production environment, test throughly before using. It could also be significantly optimized for performance.

Best practice for managing Rewrite Rules in IIS7

When moving a client from an old site to a new one, you frequently need to redirect Legacy URLs to new ones to maintain SEO. IIS 7 Rewrite Rules with Rewrite Maps easily accomplish this. A Rewrite Map is simply a subset of a rule with a list of source/destinations. With a bit of massaging, you can take a Excel workbook and export to a map.

The only problem with IIS rewrites are they are added to the web.config file, which for a Sitecore app is already 4000+ lines. Here’s how to keep it clean:
Add the section everything inclusive of the <rewrite> tags just before the ending </system.webServer> tag.


<system.webServer>
    {lots of stuff here}
        <rewrite>
            <rewriteMaps configSource="RewriteMaps.config" />
            <rules configSource="RewriteRules.config" />
        </rewrite>
</system.webServer>

Add two files RewriteMaps.config and RewriteRules.config (samples below) to the web root. IIS will save any changes and additions to the external config files instead of the web.config.

In my starter files (below) are two rewrite maps, Legacy URLs and Marketing URL’s. Legacy would be for the old to new pages which will likely never change, and Marketing rules is for advertising campaigns etc. Keeping them segregated makes updates easier.

RewriteMaps.config

<rewriteMaps>
    <rewriteMap name="Legacy URLS">
        <add key="/about_directory.asp" value="/About/Find-an-Office.aspx" />
        <add key="foo" value="bar" />
    </rewriteMap>
    <rewriteMap name="Marketing Rules">
        <add key="/jobs" value="/AboutUs/Careers.aspx" />
    </rewriteMap>
</rewriteMaps>

RewriteRules.config

<rules>
    <rule name="Redirect rule1 for Legacy URLS">
        <match url=".*" />
        <conditions>
            <add input="{Legacy URLS:{REQUEST_URI}}" pattern="(.+)" />
        </conditions>
        <action type="Redirect" url="{C:1}" appendQueryString="false" />
    </rule>
    <rule name="Rewrite rule1 for Marketing Rules">
        <match url=".*" />
        <conditions>
            <add input="{Marketing Rules:{REQUEST_URI}}" pattern="(.+)" />
        </conditions>
        <action type="Rewrite" url="{C:1}" appendQueryString="false" />
    </rule>
</rules>

One thing to note with this: If you make changes to either of these files manually (in a text editor) it seems that IIS Caches them. So, after your done editing either of those files you need to open the web.config file and re-save it so it forces a refresh.