Why live shipping calculations for ecommerce are the bane of my existence

I’ll be frank: I don’t really like ecommerce. I’ve floated for most of my 23-year career in web development in the fantasy of a Platonic ideal of an online world: bytes streaming from point to point on a perfect network. No messy complexities of the physical world to concern me.

Well, obviously none of that is true. And I’ve been dealing with ecommerce in some form or another for at least 20 of those 23 years. But I still find the nitpicky details of sales tax and shipping logistics both mind-numbingly dull and infuriatingly (seemingly pointlessly) complex.

Which brings me to the crux of today’s rant. Bringing simplicity to all of this… or, at least, to the part I have to deal with.

Granted, I am not an accountant, and I don’t have to deal with balancing my clients’ numbers at the end of the quarter. But from my perspective, there are some simple solutions to the fact that calculating shipping sucks.

These days I deal mainly with WordPress, and therefore with WooCommerce. There are a lot of extensions to WooCommerce now for live shipping rate calculations. You can pay an annual fee for tools that connect you to shippers’ APIs to give you exact shipping rates. And all you need to do is:

a) determine exact weights and dimensions of all of your products,

b) figure out exactly what types of boxes/packages you’re going to use (and determine their exact weights and dimensions), and

c) plug all of those numbers into WooCommerce, and also

d) decide which of those types of packages are applicable to which products, create the appropriate Shipping Classes, and apply them to the corresponding products; then

e) set up Shipping Zones for each part of the world you’ll ship to,

f) add shipping methods in each of those zones for each of the shippers you’re working with,

g) go into each shipper, in each Shipping Zone, and select from the dozens of shipping services each shipper offers (although you might have to do this multiple times, if you want to restrict the methods you offer based on your Shipping Classes), then

h) test adding these products to your cart, enter an applicable shipping address, and see if you get the right shipping charges… or any shipping charges at all… because you very likely won’t, because for instance you may not realize that

i) WooCommerce Services no longer offers free access to USPS live shipping calculations for new sites created after WooCommerce 3.6, and you now need to buy a separate extension for $79/year to do that. But the free plugin won’t give you any indication that this is the case; it will still show you all of the shipping methods in the configuration pages, it just won’t give you back any rates on the checkout page, and you won’t have a clue as to why until you stumble upon a small note to this effect on the WooCommerce documentation website.

In case you didn’t guess, I just went through all of this today. And this was on a site that only has 7 SKUs!

Of course, there’s a different way to approach this. You could, instead:

a) offer flat-rate shipping.

Obviously it’s not quite that simple. But here’s the thing: there’s no law saying you can’t charge customers more for shipping than it costs you. That’s the whole idea behind “shipping and handling.” In fact, whether you’re doing the fulfillment yourself, or you’ve hired an outside fulfillment vendor, you’re paying more to ship those products than the shipper’s calculated rate anyway, so you should charge more.

Here’s what I recommend.

First, decide on a shipping method. Or maybe a few. Depending on what you sell, you might want to use USPS Media Mail (if it’s applicable). Otherwise, you’ll most likely want to offer two shipping methods: a) ground (cheap but slow) and b) 2-day air (more expensive but reasonably fast). You choose the vendor you like best: USPS, UPS, FedEx, some guy they call “Crusty Pete” with a rusty old pickup truck, etc.

Find out approximately what it will cost, on average, to ship each of your products, by each of these methods. (This is a good use for Shipping Classes.) Then tack on an arbitrary “handling” fee, say $1 per item for ground and $2 per item for 2-day air.

Now, decide: do you want customers to see a shipping charge, or do you want to offer “free” shipping? My logic for this is relatively easy. You just need to balance these two considerations:

  1. People like to see free shipping.

  2. People don’t like to see ridiculously high prices for individual items.

If you are going to offer “free” shipping, you’re really going to take that approximated shipping cost for each item and add it to the selling price of the item itself. Does that make the price of the item seem exorbitant? If not, go for it. People like free shipping.

As long as the shipping price itself isn’t so huge that it causes people to balk when they see it on the checkout page, you can keep the item prices low and present the shipping charge there. Or, a mix: offer “free” ground shipping, included in the price of the item, and then at checkout give the option of “free ground shipping” or paid 2-day air, with the 2-day air prices set at whatever you determined they should be, minus the amount you had already rolled into the item prices for free ground shipping.

Flat-rate shipping isn’t literally flat rate, as in one fixed price no matter what you’re buying. Generally it’s a formula… a base price, plus a multiplier based on the number of items.

For instance, your flat-rate formula might be $5 base plus $2 per item. The customer buys one item? $7 shipping. Two items? $9 shipping. You just plug the formula into the settings, and the rest gets calculated automatically.

The whole purpose of having shipping charges at all is to cover your expenses. Paying an annual license fee for a live shipping calculator extension, plus paying a developer or consultant for their time in helping you wade through all of these complicated configurations, and troubleshoot the problems that crop up, only to end up charging customers exactly what you’re paying for shipping and not a penny more just ends up costing you money. And the fact that these extensions include an option to add on an arbitrary amount above the calculated rate gives the game away… You don’t have to charge customers exactly what you’re paying for shipping. You just need to cover your expenses.

Your time and (my) mental wellbeing are expenses too. As long as your accountant doesn’t get too frustrated with the variable amount of ancillary income you’re getting from the modest overage you’ve calculated into shipping and handling charges, free or flat-rate shipping is a much simpler and more manageable alternative to live shipping calculations.

How to REALLY check if the content is empty in WordPress

Problem: You want to check if the content in a WordPress post is empty. Seems easy, but do a Google search on the topic and you’ll see the question asked and — incorrectly — answered several times.

The fact is, I know how to do this. I was just hoping there was a built-in function in WordPress that I didn’t know about. Apparently not, so I wrote my own.

Why isn’t it easy and obvious how to check for the content being empty? Well, you could do this:

if ($post->post_content == '') { ... }

That will work. If the content is really empty. That means a zero-length string. As in strlen($post->post_content) == 0. Which it might be. But probably not.

If you’ve worked with real world site content, or even someone else’s Word documents before, you know that blank space is invisible, and a lot of times there’s a lot of blank space in a document that is not truly “empty.” Spaces, line breaks, HTML paragraphs with nothing but a non-breaking space in them. It all takes up space, and makes the content look empty, even when it’s not.

That last example is the critical one here. A WordPress post may look like it has no content, but if someone pressed Enter while the cursor was in the content box and then saved the page, it most likely has at least one <p>&nbsp;</p> in it.

So what you need is a function that takes all of that invisible cruft into account. Since it doesn’t seem like WordPress has such a function built in, I wrote my own, which I have made as compact as possible:

function empty_content($str) {
    return trim(str_replace('&nbsp;','',strip_tags($str))) == '';
}

This function takes the string you pass into it, strips out all HTML tags, then removes any non-breaking space entities, and then trims all whitespace. If there’s nothing but that stuff, then it becomes an empty string. If there’s any “real” content, the string won’t be empty. Then it just compares whatever it has left against an actual empty string, and returns the boolean result.

So now if you want to check if the WordPress content is really empty, you can do this:

if (empty_content($post->post_content)) { ... }

This will return true if the content is empty; false if it’s not.

Update (8/31/2017): This post continues to be one of the most frequently viewed on my blog, and I’ve been meaning for ages to amend it with this important note. As written here, you’ll get an erroneous true returned if the only content is in HTML, for instance, an image. If you want the function to return false if there’s no text content, then leave it as-is. But you can add a second input parameter to the strip_tags() function to tell it to leave certain HTML tags alone. If you want to allow image tags, for instance, the modified code would read as such:

function empty_content($str) {
    return trim(str_replace('&nbsp;','',strip_tags($str,'<img>'))) == '';
}

My (just-discovered) workaround to the WebKit letter-spacing bug

Update (5/29/2012): Upon working further with the project that formed the basis of this post, I discovered that my solution did not work, or at least, no longer worked. It’s not uncommon as I get deeper into a project with a large CSS file that there are subtle, inadvertent effects of the various CSS properties that get added along the way. Looking back now, I can’t determine for sure whether my solution did once work with the simpler version of the site, and something else I added later counteracted it, or if I was just too eager about a solution to realize it never quite worked in the first place. As a result, I had considered deleting this post entirely, but I have decided to leave it live, to further the discussion of the topic, or at the very least to serve as a monument to my challenges.

WebKit, the rendering engine “under the hood” in both Safari and Chrome, has a known issue handling the CSS letter-spacing property at certain small increments, and at certain font sizes.

Specifically, if defining letter-spacing in increments smaller than 1px or 0.1em, it seems to just ignore the property altogether… except at larger-than-default sizes.

I typically use em or % these days to define text sizes in CSS. So in my situation, I’ve found that my letter-spacing: 0.05em works if I also specify font-size: 125% (or larger), but if I have font-size set to 100% or less, the letter-spacing gets ignored.

Typically, after loading reset.css, I set a baseline font size for the document with body { font-size: 100%; } (or some size… actually it’s usually 80% but these days I’ve been leaning towards larger type).

I decided to play around with this a bit to see if I could resolve the letter-spacing issue, and I found a nice, easy solution that works at least for the particular site I’m currently testing it on. Your experience may vary, depending on how your HTML is structured and how complex your design is.

Here’s the solution:

body {
  font-size: 125%;
  letter-spacing: 0.05em;
  line-height: 1.3em;
}

body>* {
  font-size: 85%;
  line-height: 1.3em;
}

You may want to adjust the exact values of font-size to suit your needs. (And, yes, I’m aware that mathematically 125% and 85% don’t cancel each other out, but they’re close enough for my purposes.) It’s important to include the line-height property in body>* to define your target line height; otherwise your lines will be too far apart. Set it to whatever your ideal value is. (I usually prefer line-height: 1.5em personally, but for larger type, as on the site I’m currently working on, it gets too spaced-out.)

So what’s going on here? Well, strangely, it seems WebKit can actually render smaller type with line-spacing less than 1px or 0.1em just fine, but it won’t unless somewhere in the “cascade” the type has been defined as being a certain amount larger than 100%. I don’t get it, but until the bug (which it seems clearly to be after all of this) gets fixed, at least this seems to be a reasonably clean workaround.

It’s very important that you use body>* and not just body *. If you don’t know why, well… try it out and see. (The upshot: we’re applying a uniform scaling-down across the board on all elements directly under body, which is practically the same as just defining our target font size directly on body itself, but with the benefit of working around the letter-spacing bug.)

Note: I have only tested this using em as the unit of measure for letter-spacing. I’m aware of the issue with px as well, but I’m not sure this solution will work for that. But… really… just use em instead!

How are open source CMSes like Microsoft enterprise software?

Aside from the fact that both topics would put the average blog reader to sleep before the end of the first…

OK, now that they’re asleep, let’s talk. Throughout most of my career, open source software and Microsoft’s (or, really, any software behemoth’s) enterprise “solutions” have seemed diametrically opposed. But the more I think about the situation, I begin to find some startling similarities, at least in their implementation (and reasons for said implementation), if not in their actual structure and licensing.

If you’re the one person (besides me) who’s spent any significant amount of time reading this blog, you probably know two things: 1) I don’t like Microsoft, and 2) I don’t like Drupal. So these are the objects of my scorn in today’s post as well, although the problems I’m describing can be generalized, I think, to the broader sectors of the software industry that they represent.

When I worked in the corporate world, I resented Microsoft’s dominance across the board from operating systems to desktop software to enterprise systems. It just seemed that most of their tools weren’t really that good, and eventually I began to realize that the reason they were successful was that Microsoft’s customers were not the end users, but rather the IT managers who made purchasing decisions. These decisions were largely based on their own knowledge and experience with Microsoft’s software (to the detriment of other, possibly superior options), but also (I believe cynically) to preserve their own jobs and those of their staffs. Microsoft’s systems require(d?) constant maintenance and support. Not only did this mean bigger IT staffs on the corporate payroll, but it meant lots of highly paid “consulting” firms whose sole job was to promote and then support the sales and implementation of Microsoft products.

In the indie developer world, where I now reside, the culture and software platforms are different, but perhaps not as different as they seem. Apple’s computers dominate the desktops in small studios, and the tabletops in coffeehouses where freelancers can frequently be spotted hunched over their MacBooks hard at work while sipping lattes and meeting (usually a little too loudly) with clients. And open source software dominates at the server level.

But just like Microsoft’s platforms, I think most open source software just isn’t really very good. And the problem, once again, is the customer (or… well… whatever you call the person who makes the decisions when selecting a free product). It seems that the end user experience is rarely given much priority when most open source software is being designed and developed. Part of the problem is a lack of direct contact between the development teams and those end users (or, to be honest, even between the geographically scattered members of the development teams themselves). Devs don’t really know what end users want or need. They only know what they want or need, along with what’s been submitted to their bug trackers.

It’s not that these devs are bad people, or bad at what they do. There’s just a disconnect between coder and user, and as a result the goal of building good software isn’t met.

So, why do independent developers still use tools that are not really the best for their clients? Again, cynically, I wonder sometimes if job security isn’t a factor. It’s a lot easier to build something that works, but that requires indefinite, ongoing attention and support, than to build something that is flawless, that you can hand off to your client and never touch again. It’s easier… and it provides built-in job security.

Now, I’m not perfect, and I’m not above all of this. There is no such thing as flawless software, and I have ongoing support contracts with some of my bigger clients. But I’m proud to say that’s mostly because I’m constantly building new sites for them, or building functional enhancements onto the sites they already have, rather than doing endless bug fixes and technical support because the tools I’ve sold them are too confusing or simply don’t work right. Sure, the bug fixes and tech support do happen. But the tools — primarily WordPress and cms34, my own CMS — are built much more with the end user in mind, and have managed to avoid the pitfalls that mean a guaranteed job for me at the expense of a mediocre user experience for my clients.

That’s harder, and riskier. But it’s better. I’m delivering a higher quality product to the clients, and I’m keeping my own work interesting and moving forward.

The definition of madness: $2500 for a ticket to a Yankees game

No, those aren’t scalper prices. From kottke.org:

Option 1: Two tickets to Tuesday night, June 30, Mariners at Yanks, cost for just the tickets, $5,000.

Option 2: Two round-trip airline tickets to Seattle, Friday, Aug. 14, return Sunday the 16th, rental car for three days, two-night double occupancy stay in four-star hotel, two top tickets to both the Saturday and Sunday Yanks-Mariners games, two best-restaurant-in-town dinners for two. Total cost, $2,800. Plus-frequent flyer miles.

The thing that scares me most is that even after last year’s Wall Street collapse, there are probably still plenty of New Yorkers (though probably not so many who actually live in the Bronx, where the Yankees call home) who can easily afford these tickets. Personally, I’d take the mini-vacation and use the extra $2,200 I saved to buy a 55-inch flat panel to watch the other 160 games. But I guess the Yankees have to pay those 8-figure player salaries somehow. I just figured the $10 hot dogs and $15 MGDs would do it. (I’m just guessing at those prices — they’re probably more.)

This makes me a bit nervous as I anticipate the 2010 Twins season at Target Field. Sure, there’s no way in hell the Twins will be able to justify those kinds of ticket prices, but I fear the days of my beloved $8 “cheap seats” are numbered.