“We’re sorry, your order for $3.7 trillion worth of bumper stickers has failed.”

One of my web clients emailed me about a rash of fake orders they received a few days ago.

Usually these fake orders are for very small amounts, because the people (or bots) placing them are testing stolen credit cards, so they try to fly under the radar.

I’m not sure what was going on here. Needless to say, my client was unable to fulfill this order. And I’m not masking their IP address (the only part of this that isn’t fake) because they don’t deserve anonymity.

This person (most likely not a bot in this case) placed 174 orders in a span of just under 2 hours. Many of them were for reasonable amounts. Some were… like this. A few included clumsy attempts at code injection. None of them went through, of course, and no real harm was done. I’m just a bit mystified at what this person was hoping to achieve.

It almost seems like the work of a bored teenager, trying to flex their ersatz hacking skills.

It’s just kind of unfortunate that this wasn’t real. The sales tax alone could have fully funded the Minnesota and Hennepin County governments for quite a while. (I looked it up. The state’s revenue is around $2 billion per month. At that rate, this single order could have kept the state fully funded for about 13 years. Oh, and this was only one of several orders for amounts like this.)

It gets even better! I checked the order notes, and it turns out PayPal rejected the order because the quantity exceeded the allowed value. No shit. Why doesn’t WooCommerce limit the quantity input field? Ridiculous.

OK, so how do we fix this?

It seems obvious that we should be able to set a maximum value for the quantity input. And there are WooCommerce add-ons that give you a lot of flexibility to set minimum and maximum quantities on an individual product basis. There are plenty of reasons a complex ecommerce store might want or need those kinds of rules, but I want something more basic. I just want to set a hard upper limit of 100 on the quantity field for all products in this store.

The WooCommerce quantity field is an <input type="number"> field. And that field has min and max attributes you can use to set the valid number range. A number input is a special text input field that has up and down arrow keys that let you increment/decrement the value by amounts controlled by the step attribute.

But here is what I find absolutely fucking maddening about number inputs: you can also type in them. You can type whatever you want in them. You can type letters. Special characters. And worst, numbers outside the range dictated by the min and max attributes. Browsers are “supposed” to validate the input and prevent submitting the form, but in practice I’ve seen that both be extremely hit-or-miss, and also vary wildly from browser to browser.

It makes no sense to me at all why browsers allow anything other than numerical characters in a number input, i.e. the digits 0-9, plus periods, commas, and hyphens. Why? WHY???

Sometimes I really hate this job.

Anyway… let’s pretend number inputs don’t suck. Hooks make it easy to set the max value for the WooCommerce quantity input. Here’s what I used:

function my_woocommerce_quantity_input_args($args, $product) {
    $args['max_value'] = 100;
    return $args;
}
add_filter(
    'woocommerce_quantity_input_args',
    'my_woocommerce_quantity_input_args',
    PHP_INT_MAX - 1, 2
);

You could add a conditional to only set the max_value to 100 when it’s not already set (the default value is -1 by the way), although I was having some trouble getting that to work and I didn’t want to bother troubleshooting it any further… especially since, as indicated by my previous rant, max doesn’t actually do anything to prevent users from typing in a ludicrously large number, or the entire text of the Declaration of Independence, if they so desire. (OK, to be fair, in my testing, Safari’s validation does prevent you from submitting the form with text in the field. But it totally ignores the max value. And I don’t understand why it doesn’t just wipe out invalid characters as you type.)

Side note on my code snippet above: I like to ensure that my code isn’t going to get changed by something else that runs later, so I have a habit of setting the priority on WordPress hooks to PHP_INT_MAX - 1 to get it to run as late as possible. (I use the - 1 to give myself an “out” if I need to add something even later.)

Anyway… we still need a solution, and that’s where we have to resort to JavaScript. (Specifically I’m using jQuery because it’s WordPress.) It’s 2025 and we still have to use JavaScript to work around mind-numbingly basic limitations of HTML. ¯\_(ツ)_/¯

Here’s the jQuery code I wrote to both a) force the quantity input to only accept non-negative integers, and b) actually force the min and max limits, as the user types. (Of course someone could still get around this by disabling JavaScript, but I’m pretty sure there are other steps in the ordering process that would fail without it anyway.)

jQuery('input[type="number"].qty').on('change keyup', function() {
    var min = jQuery(this).attr('min');
    var max = jQuery(this).attr('max');
    var q = jQuery(this).val();
    q = q.replace(/\D/g, '');
    if (typeof min != 'undefined' && min != '') {
        if (Number(q) < Number(min)) { q = ''; }
    }
    if (typeof max != 'undefined' && max != '') {
        if (Number(q) > Number(max)) { q = ''; }
    }
    jQuery(this).val(q);
});

A few notes on this:

  1. I’m using input[type="number"].qty as the jQuery selector because it efficiently identifies the quantity input on both the individual product page and the cart page in WooCommerce. I also probably don’t need to watch both the change and keyup events but I wanted to cover all the bases.
  2. After some trial and error with confusing behavior, I determined that the best UX for this comes from casting the values as Number() right at the point of comparison, and changing the value not to the min or max value, but to just empty it out.
  3. The .replace() method here uses a regular expression that rejects all non-numeric characters. If you need to accept negative numbers or fractions, you’ll need to change /\D/g to /[^\d.-]/g or /[^\d,-]/g if your locale uses commas as the decimal delimiter… or just /[^\d.,-]/g if you want to cover all the bases (and/or allow thousands separators).
  4. Still I am finding some odd behavior here with .replace() that I have never experienced before, and I’m having trouble narrowing down why. It seems to me that this code should be simply stripping non-numeric characters out of the string. So for example if I typed “56g” the value for q would become 56. But what I’m observing is that if the initial value for q is composed entirely of digits, it passes it along, but if there are any non-numeric characters in the string, the entire value gets wiped out. (I tested this with various regular expressions, e.g. \D, [^\d], [^0-9] etc. And I used alert() to output the value of q immediately after the .replace() line, to make sure it wasn’t an issue with the subsequent logic. I am absolutely mystified by this, but I’ve already spent more time on it than I can bill to the client, so I need to stop here.)
  5. I’ve been working with JavaScript for over 20 years, but it’s never been my primary area of emphasis… it still kind of feels like a foreign language to me, whereas PHP is my native tongue. So I don’t always do my JavaScript in the most “JavaScript-y” way.

Obama: anatomy of a logo

OK, I will admit it. The first thing (OK, the second thing; his speech at the 2004 DNC was the first) that piqued my interest in Barack Obama was the sight of his logo on a sticker, way early on in the primary campaign (like, summer of 2007 early). It was clear right away that Obama had the best design team in the history of political campaigns working for him.

Let’s take a look at what makes this logo so great. Ultimately what it boils down to is that every detail is imbued with relevant meaning, and the overall result is very aesthetically pleasing.

First, it’s an O, for Obama. No-brainer there. It incorporates the requisite colors: red, white and blue. But what it does with them, and with a few simple shapes, is brilliant. The red and white stripes of the U.S. flag are there as well, blended into an unmistakable and powerful image: the sun rising over a rural American hillside (a cornfield, no less) into a perfect, clear blue sky. Now that’s “morning in America.”

On a related note, I’ll leave it to you to interpret the meaning of the logo’s appearance in a John McCain commercial.

On another related note, this.

Periods. Overused. Everywhere. The Mad Libs approach to marketing

I spotted this ad for Little People Big World, a TLC reality show, in a magazine recently. I’ll save the matter of the exploitative (or perhaps self-exploitative) nature of the show for another rant. Or not; honestly I don’t really care. What does bother me is the copy on the ad. I mean: The. Copy. On. The. Ad.

I have loathed marketing’s overuse of the period for as long as I can remember. And I do distinctly remember loathing it when I was no more than 10 or 11, at least. In fact, I specifically remember seeing this usage on the billboard that used to be on top of the old liquor store where Oakland Avenue curves and becomes a one-way at 12th St SW, where now there’s a Kwik Trip, in my hometown of Austin, Minnesota. And I complained to my mom about it. Yes, I remember things like this. Forever.

But I think marketing’s abuse of the period has grown increasingly loathsome in recent years, resulting in utterly pointless examples like what you see here. I suppose “Live. Lived. Large.” does, perhaps, convey a slightly different meaning than simply saying “Life lived large.” But, really. Does it ultimately serve any purpose greater than annoying me?

I’ve come to realize, though, that there’s a very easy formula here, suitable to serve as the foundation for a Mad Libs approach to writing marketing copy. Observe:

I suppose I shouldn’t be using the Mad Libs logo without their permission, but come on… they claim it’s “the world’s greatest word game!” (Exclamation point included.) Take that, Scrabble! (I mean, “Scrabble BRAND Crossword Game”) Besides… does the world really need a Space Chimps-themed Mad Libs book?

Got a good marketing tagline using the Mad Lib? Post it below!