Duskel Start a project
Blog/Product Engineering

Pick a WordPress development company by how they handle update day

A WordPress development company earns its fee on update day, not launch day. Ask about composer.json, autoloaded options, and custom tables before you sign — the answers take five minutes.

Duskel·16 Sept 2026·7 min read·Product Engineering

The call comes at 9:40 on a Tuesday: checkout is a white screen. A payment gateway plugin auto-updated itself overnight — auto-updates switched on in 2022 by someone who has since left — and it calls a WooCommerce method that was removed two minor releases ago. The fatal fires only on the order-pay route, so the homepage returns 200, uptime monitoring stays green, and nobody notices for six hours. Nobody can say which plugin versions were running yesterday, either.

That morning is what you're buying, not launch week. Every site looks fine in month one — fresh theme, current plugins, a green Lighthouse score earned against eleven posts and no logged-in traffic. So skip the portfolio carousel and ask the company to walk you through last week's plugin update on a site with real traffic. Strong answers have a branch, a staging refresh from a production snapshot, and a version to pin back to. Weak ones stop at 'we take a backup first' — which is a plan to hear about breakage from customers and then lose every order placed since midnight.

The update-day test

The clearest tell is whether core and plugins are declared in composer.json and pulled from WPackagist, or clicked into place in wp-admin. Composer-managed means production state is a lockfile in Git: the update arrives as a pull request whose diff reads woocommerce 8.1.1 → 8.2.0, and a bad release is undone by pinning the old version and deploying. Four minutes, no database restore that would also roll back every order taken since the snapshot. Dashboard-managed sites have no such record — the only description of what's installed is the installation itself, which is the thing that just broke.

Next: where does wp-content/uploads live? Not in the repo, and preferably not on the app server. Offloaded to S3, a staging rebuild is a database dump plus a config swap — ten minutes, not a 40GB sync nobody volunteers for. Teams that skip this end up with a staging copy eight months stale, so nobody trusts it, so nobody tests, so every update goes straight to production and the client's customers file the bug reports.

Then ask about WP-Cron. By default WordPress fires scheduled tasks on page loads: the nightly feed import runs whenever a visitor happens to arrive, twice if two arrive in the same second and the lock transient loses the race, and never on a quiet night. Anyone who has run a site where the schedule mattered has set DISABLE_WP_CRON and pointed system cron at wp-cron.php every five minutes. A blank look means they have never had an importer stop silently over a weekend.

Where WordPress actually gets slow

It is almost never the theme. Start with wp_options, where every plugin that ever touched the site writes settings with autoload set to yes — rows selected and unserialized on every request, including admin-ajax and REST. We inherited a site carrying 20MB of autoloaded options: dead license keys, years of cached API responses, and one long-removed plugin that had been storing an entire product feed in a single row. Pruning it below 500KB took an afternoon and moved TTFB from 1.4s to under 600ms on cache misses. No caching plugin reaches that, because the cost lands on exactly the requests that can't be cached.

Second, meta_query. postmeta is key-value with an index on meta_key and a prefix index on meta_value, nothing composite, so filtering products on three custom fields becomes three self-joins across millions of rows and a temp table on disk. The skill is knowing when to stop fighting it: move the filter into a taxonomy, which joins through term_relationships properly, or lift the fields into a custom table with the columns you actually query. WooCommerce made that call itself — High-Performance Order Storage exists because wp_posts stopped scaling for orders. Ask whether they've run an HPOS migration, and what they did about the plugins still writing to the old tables.

Third, object caching. Without Redis behind WP_Object_Cache, every request re-runs the same option and term lookups, and page caching is the only defence — covering exactly the traffic that is logged out and not in checkout. On an editorial site with fifty writers, wp-admin is the product, and a four-second post list is the complaint you hear every week.

Custom post types are not a schema

Registering a custom post type takes nine lines, which is why it ends up holding things it shouldn't: sensor readings, event logs, per-row financial records, anything with more than a handful of queryable fields. Each field is another postmeta join. The tell is a client dashboard that takes six seconds because it runs WP_Query with four meta keys and a date range, and the fix on record was raising max_execution_time.

The right move is a custom table with dbDelta migrations, composite indexes on the columns you filter, and a thin repository class between it and everything else. Keep wp-admin as the interface, because editors know it, but let the storage match the data. A firm that only knows ACF and post types ships the version that works at launch with 2,000 rows and becomes the reason you rebuild at 400,000. Ask directly: when do you create a custom table instead of a post type? Any answer other than 'never' is the one you want.

What you'll still own in three years

Editorial tooling is where lock-in accumulates. We use ACF and it's good software, but a site built entirely from flexible content fields keeps its page structure as serialized field keys — field_5f3a1b2c — in postmeta, legible only to a plugin plus your current theme's render loop. Native blocks defined in block.json and rendered server-side cost more up front and far less at redesign, because the content sits in post_content as parseable markup and survives the theme. The split we hold to: blocks for anything an editor arranges visually, ACF for structured fields on a fixed template.

That same line decides whether going headless later is a project or a re-entry of every page. Server-rendered blocks come out of WPGraphQL as clean markup; nested flexible-content rows come out as a JSON blob whose keys are hashes and whose meaning lives in the old theme's PHP. You may never go headless. But the site that could is the one built by people arguing about the content model in week two instead of the launch date — the same habit that keeps update day boring.

What to ask before you sign

Four questions, five minutes. How did you deploy a plugin update to production last week? What's in your composer.json? When do you use a custom table instead of a custom post type? Which persistent object cache do you run? You don't need to follow the implementation to hear the difference between a team describing last Thursday and a team composing an answer live. One gives you principles; the other gives you version numbers and the name of the thing that broke.

Then get the maintenance terms in writing before the build starts, because that's where the incentives sit. A fixed-price build with no ongoing agreement means the people choosing your architecture never have to live with it — they're gone by the WooCommerce release that kills the gateway. We prefer to still be there in month fourteen: partly because clients like it, mostly because knowing you'll be the one debugging the 3am auto-update is the only thing that reliably keeps shortcuts out of the codebase.

Written by Duskel

A software studio that ships and maintains its own products — KeepChats, Gwora and Cairn — and builds the same way for clients. Founded and led by codewithumar.

Talk to the studio →
RELATED READING
Product Engineering · 7 min read

What Strapi actually costs once you get past the free tier

Product Engineering · 8 min read

A Strapi tutorial for the people who have to maintain it

Product Engineering · 7 min read

The Strapi architecture diagram nobody draws correctly

PRODUCT ENGINEERING

If you're weighing a WordPress build or inheriting one that's gone slow, tell us what's breaking and we'll give you a straight read on it.

Send the problem. You get one fixed number and a plan back within a business day.

Duskel
Duskel
AI AUTOMATIONSOFTWARE

We build software worth keeping — for clients, and for ourselves.

Founded & led by codewithumar

© 2026 Duskel. All rights reserved.DUSKEL SMC-Private Limited · Incorporated 2021 · Lahore, PakistanBuilt to last, not to demo.