Skip to content
Gravity Tables
major v1.0.0 · · 3 min read

Hello, world, the first table

The original release. Born from a freelancer notebook, copy-pasted across 12 client projects, finally extracted into a real plugin. Here is how Gravity Tables started.

  • First public release, GPL-2.0+ licensed
  • Read entries from any Gravity Form, render as a table via shortcode
  • Sortable columns, basic pagination, mobile-friendly base layout
  • No frontend editing yet, that arrives in 2.x
  • Shipped to WordPress.org as Advanced Data Tables for Gravity Forms

Every shipped product has an origin moment. Gravity Tables has two, the first was a Slack DM in 2023.

The DM#

“Can your tables thing show only the user’s own submissions? My client’s customers are asking for it.”

The “tables thing” was a 200-line snippet I’d been pasting into client projects for two years. It read Gravity Forms entries via the standard API, rendered them in a <table>, and shipped them through a custom shortcode that took 6 parameters.

The Slack DM was the third client that month asking for it. The shape of the request was always the same: display GF entries, filter by user, allow some sort of frontend interaction.

I extracted it that weekend. By Monday it was a plugin. By the Friday after that, it had a gravity-tables.php file and a shortcode that read [gravity_table id="X"].

What 1.0.0 did#

The first public release was deliberately small:

  • Read entries from any Gravity Form via id="X"
  • Pick columns with include="field_id_1,field_id_2" or exclude="..."
  • Sort columns by clicking headers (alphabetical and numeric, auto-detected)
  • Pagination with prev/next buttons
  • Filter by user with filter_by_user="true", the original Slack-DM request

That’s it. No editing. No bulk operations. No exports. No filters beyond user. No mobile cards.

I shipped it knowing what it didn’t do, on the theory that shipping the smallest thing that works is more useful than waiting to ship the thing that does everything.

What I got wrong#

Looking back at 1.0.0 with the benefit of two years of feature work:

  1. The architecture was procedural PHP, single 2,400-line gravity-tables.php file. It worked, but every new feature in 1.x slowed the codebase down. The 2.0 rewrite (a year later) fixed this.
  2. jQuery for the front-end, fine for the time, but it accumulated jQuery-plugin dependencies that all needed updating later.
  3. No tests, the kind of decision that feels fast for a week and slows everything for a year.
  4. No upgrade path planned, when 2.0 dropped with a different shortcode parameter shape, migrating 1.x users took real care.

What I got right#

  • Shipped narrowly. The 1.0 feature set is tiny. That made it possible to maintain confidently.
  • Shortcode-first. Every feature mapped to a shortcode parameter. This API has held up across every subsequent release.
  • GPL from day one. No source-available, no funny licensing experiments. The free tier could be forked, extended, used however.
  • WordPress.org submission immediately. The plugin was discoverable from week one, not after I felt “ready”.

The line through to today#

If you read the shortcode for v4.1.8, [gravity_table id="42" filter_by_user="true" auto_refresh="true" totals="amount"], the first three of those parameters are exactly what shipped on day one. The totals is new in 4.1.8. The shape of the API hasn’t changed.

That’s the test of a good v1: when v4 looks like v1 with more parameters, you got the foundation right.

Next step from 1.0#

The first major addition was filters in 1.1, then search in 1.3, then export in 1.6, then the architectural rewrite in 2.0. Every step felt small at the time. Two years later they add up to a plugin that does ten things instead of three, but the three from day one still work the same way.

Thanks for reading this far. If you’ve shipped a v1 of anything, you know how strange it is to look back at the working version that did almost nothing. Strange, and also kind of important.

#origin-story#first-release#shortcode