← Back to blog

May 8, 2026 · 5 min read

Why I Shipped a Pickup Plugin to WordPress.org

A weekend of trying every existing pickup plugin convinced me to write my own. RestoPick does pickup date and time at WooCommerce checkout, ASAP mode, and opening hours that don't drift twice a year.

Plugin: RestoPick: Restaurant Pickup for WooCommerce on WordPress.org

This one started with a single restaurant client. The brief was small: customers should pick a date and time at WooCommerce checkout, the order should show up like any other order, and the kitchen should see the pickup window without hunting for it.

I spent a weekend trying every pickup plugin I could find. Some were paid-only, some assumed you also wanted delivery, some hard-coded American date formats. None of them got out of the way. So I wrote my own.

It went live on that client’s site in late 2025. In May 2026 I cleaned it up and pushed it to the WordPress.org repository, where it sits today at fewer than ten active installations and no reviews at all. That’s the honest scale of this thing: built for one kitchen, now running in a handful.

What happens at checkout

At checkout, two extra fields appear: Pickup date and Pickup time. The calendar only shows days the restaurant is open. Closed days are unselectable. Holidays are visually marked and disabled. The time dropdown is filtered to slots that fit that day’s hours and respect a minimum lead time the restaurant configured, so a customer can’t order at 6:59 for a 7:00 pickup the kitchen can’t actually make.

If the restaurant turns on ASAP mode, customers also see an “order now, pick up as soon as possible” option. The ASAP card greys itself out when the kitchen is about to close. It does that live, without reloading the page, because nothing makes me trust a checkout less than one that lies about availability:

var pageLoad = Date.now();

function asapTargetMinutes() {
    var elapsed = Math.floor((Date.now() - pageLoad) / 60000);
    return cfg.nowMinutes + elapsed + (cfg.leadTime || 0);
}

The server stamps “it’s X minutes past midnight” once at render. The page adds the wall-clock time elapsed since, and the result is the minute-of-day the order would actually be ready. When that crosses today’s closing time, the ASAP button disables itself and the form flips to “Schedule for later”.

The thing I deliberated longest about: timezones

Everything else was straightforward. Timezones weren’t.

WordPress lets you pick a named zone like Asia/Jakarta or America/New_York, which observes daylight saving. For an editorial site that’s exactly right. For a restaurant that opens at 8 am year-round it’s wrong in a subtle way, because twice a year the stated hours would silently shift by an hour and someone would eventually show up at a locked door.

So RestoPick stores pickup hours as a fixed UTC offset (e.g. +07:00) and ignores DST entirely. The hours the owner types in are the hours the customer sees, 365 days a year. If the owner wants their internal admin to track local clock time across DST, they can flip the offset manually twice a year. But I’d rather make the default the boring, predictable choice.

Where the pickup info ends up

Once an order is placed, the date and time appear in four places:

  1. WooCommerce admin order page, with an “ASAP” badge if applicable.
  2. Orders list column, for a quick scan.
  3. Customer and admin emails, so the receipt the customer keeps already has it.
  4. Thank-you page, one more time before they close the tab.

The rule I followed throughout: nobody should ever have to go looking for the pickup time.

The part I got wrong

The plugin started life in a folder called woo-pickup-order, and 1.0.0 shipped with that history smeared all over it. PHP identifiers prefixed wpc_. An admin JS global called wpcPickupAdmin. An order-list column keyed wpc_order_type. And, worst, checkout markup using the CSS class woocommerce-pickup-fields.

That last one still bothers me.

woocommerce- is not my namespace. I was squatting on the prefix of the plugin I depend on, in markup that ships to every checkout page on every site running this. Nothing broke. Nothing was ever going to warn me either, which is the part that makes it a bad habit rather than a bug: a collision would have shown up as someone else’s stylesheet quietly restyling my fields, on a site I don’t own, reported as “the checkout looks weird”.

Versions 1.1.1 through 1.1.3 are almost entirely that cleanup. Every identifier moved to a restopick prefix, the JS global renamed, both CSS classes renamed. Three point releases spent undoing a naming decision I made in an afternoon and never revisited before shipping.

What’s not in the free plugin

There’s a Pro layer I built on top for the restaurants I maintain: per-product time windows (breakfast items only 6–10 am), recurring closed days (“every Monday”), a shortcode to render the pickup form outside checkout, and a small REST API to flip pickup on or off remotely. It has its own write-up.

It isn’t for sale. Which makes the usual disclaimer easy: the free version isn’t crippled to push you toward an upgrade, because there’s no upgrade to push.

One caveat I’d rather say than have someone find. Menu Hours and Tips shipped in the free plugin in 1.0.0, and I moved them into Pro in 1.1.1 and 1.1.2. Taking a working feature away from free users is not a good look, and I’d think harder about it today. The only reason it went cleanly is that it affected approximately nobody.