Integrating Cargo Extension for Structured Data Management in MediaWiki

Why Cargo feels like the Swiss‑army knife of MediaWiki data

Ever tried to turn an infobox into a spreadsheet? You’ll know the pain – a little template here, a stray pipe there, and suddenly you’re juggling rows like a circus performer on a unicycle. Cargo swoops in, not with a cape, but with a very practical toolbox that lets you stash and fetch data without turning your wiki into a full‑blown database admin’s nightmare.

In short, Cargo is the “just‑right” extension for folks who want structured data, yet dread the learning curve of Semantic MediaWiki. It stores everything in ordinary SQL tables (MySQL, PostgreSQL – SQLite works in a pinch) while keeping the familiar MediaWiki wiggle‑room of templates and parser functions. Think of it as a bridge: the wiki‑side stays cozy, the data‑side gets a tidy, queryable home.

Getting Cargo onto your wiki – a semi‑spontaneous walk‑through

First off, make sure you’re riding MediaWiki 1.40 or newer. As of September 2025 the latest Cargo version is 3.8.4 – a stable release that has already survived a few months of real‑world traffic on wiki farms like Fandom and Miraheze.

  • Drop it in. Unpack the folder into extensions/Cargo on your server. No fancy sub‑directories needed – Cargo is tidy.
  • Run the updater. Fire up php maintenance/update.php. Cargo will create its cargo_tables, cargo_pages and cargo_backlinks tables (the latter still a stub in some installs). If you prefer a separate DB, set the $wgCargoDB* variables – see the table below.

Tell MediaWiki. Add a line to LocalSettings.php:

wfLoadExtension( 'Cargo' );

(You can also sprinkle a little comment after it, like “# Load Cargo – because we like tables”.)

Grab the code. Either pop the Extension:Cargo tarball from the Packagist page or, if you’re a Composer fan, run:

composer require mediawiki/cargo "^3.8"

And that’s it. If you see a nice “Cargo is installed” message on Special:Version, you’ve done it right.

Configuration – the knobs you can turn without a wrench

Cargo ships with a handful of global variables. Most folks leave them at defaults, but a few tweaks can save you headaches later.

SettingDefaultWhat it does
$wgCargoDecimalMark.Character used for decimal points in numbers.
$wgCargoDigitGroupingCharacter,Thousands separator (e.g., 1,000 vs 1 000).
$wgCargoDefaultQueryLimit100How many rows #cargo_query returns if you don’t specify limit=.
$wgCargoMaxQueryLimit5000Upper bound to keep runaway queries from hogging the server.
$wgCargoDefaultMapServiceOpenLayersChoose googlemaps, leaflet, or stick with OpenLayers.
$wgCargoDBtype$wgCargoDBRowFormatnullSet these if you want Cargo to use a dedicated database instead of the main MediaWiki DB.

A quick tip: put the configuration lines near the bottom of LocalSettings.php. That way, any later wfLoadExtension() calls won’t accidentally overwrite your tweaks.

Storing data – the “declare, store, query” mantra

It’s a three‑step tango, and you can do it all inside a single template if you like.

Query it. Anywhere on the wiki, you can retrieve rows with:

{{#cargo_query:
  tables=Book
| fields=Title, Author, Year
| where=Year > 2000
| format=table
| limit=20
}}

(The result is a neat HTML table, no extra CSS needed.)

Store a row. In the <includeonly> part, drop:

#cargo_store
| Title = {{#if:{{{title|}}}|{{{title}}}|Unknown title}}
| Author = {{#if:{{{author|}}}|{{{author}}}|Unknown author}}
| Year = {{{year|0}}}
| Pages = {{{pages|0}}}

(Note the use of #if to dodge empty parameters – a tiny redundancy that feels more human than a perfect “always present” script.)

Declare the table. In your template’s <noinclude> section, add:

#cargo_declare
|+ TableName = Book
|+ PrimaryKey = ISBN
|+ Fields = Title:Text, Author:Page, Year:Int, Pages:Int

(This tells Cargo to make a book table with those columns.)

Pro tip: if you have a bunch of templates that share a schema, you can have them all point to the same table by using #cargo_attach. That way, you only write the #cargo_declare once.

Querying tricks – making the most of Cargo’s SQL‑like flavour

Even though Cargo abstracts away raw SQL, you can still sprinkle in functions. For example, #cargo_query supports AVG(), COUNT(), and even GROUP_CONCAT() if you enable them via $wgCargoAllowedSQLFunctions. Here’s a quick illustration that counts how many books each author has written:

{{#cargo_query:
  tables=Book
| fields=Author, COUNT(*) AS Books
| groupby=Author
| format=template
| templatename=AuthorStats
}}

And the AuthorStats template could be something as simple as:

* '''{{{Author}}}''' – {{{Books}}} books

Notice the use of a pipe‑delimited alias (AS Books) – a little SQL‑ish flair that feels like a secret handshake among data‑savvy editors.

Mapping data – when points on a map matter more than rows in a table

If you store latitude/longitude in a Coordinate field, Cargo can render a map with a single line:

{{#cargo_display_map:
  tables=Landmarks
| latfield=Lat
| lonfield=Lon
| zoom=12
}}

Swap OpenLayers for googlemaps in $wgCargoDefaultMapService if you prefer the Google look, but remember you’ll need an API key ($wgCargoGoogleMapsKey) for that.

Comparing Cargo and Semantic MediaWiki – a quick, friendly debate

Both extensions let you treat wiki content as data, yet they differ in philosophy. Semantic MediaWiki (SMW) is a heavyweight, full‑featured ontology engine. It shines when you need complex reasoning, inferencing, or integration with Wikidata. Cargo, on the other hand, is lightweight, focused on tabular data and SQL‑style queries.

When you’re building a simple catalog – say, a list of community‑run events, a collection of recipes, or a database of open‑source projects – Cargo’s lower overhead usually wins. If you need to model relationships like “author of” that cascade through many classes, SMW might be the better fit. In practice, many wikis run both side‑by‑side, using Cargo for flat tables and SMW for richer semantic webs.

Real‑world hiccups – a few bumps you might hit

Nothing worth doing is completely smooth. Here are some quirks you may encounter:

  • Database changes. After installing Cargo, you must run update.php. Forgetting that step leaves you with missing tables and cryptic “Cargo table does not exist” errors.
  • Back‑links aren’t always populated. The cargo_backlinks table is currently a placeholder; if you rely on reverse look‑ups, you’ll need to script a custom solution or file a bug.
  • SQLite quirks. Cargo works with SQLite, but some advanced SQL functions (e.g., GROUP_CONCAT) behave oddly. If you’re on a tiny test wiki, stick to MySQL or PostgreSQL for full feature support.
  • Namespace hiding. By default Cargo hides namespace 6 (File) from query results. If you store data in that namespace, adjust $wgCargoHideNamespaceName or use namespace=File in your query.

Most of these issues have community‑driven workarounds posted on the Cargo talk page or the Phabricator bug tracker – a good place to pop a quick “I’m stuck here” comment.

Recent updates – what’s new in 3.8.4

Version 3.8.4, released September 2025, brings a handful of under‑the‑hood improvements:

  • Better handling of NULL values in Lua queries – you can now toggle $wgCargoLegacyNullLuaFieldsAsEmptyString to retain old behaviour if you have legacy scripts.
  • Performance boost for large #cargo_query calls – the query engine now streams results, cutting memory usage by about 30% on busy wikis.
  • Support for jsonb columns on PostgreSQL, making it easier to store nested structures without resorting to separate tables.
  • Minor UI polish on Special:CargoTables, with a new “Export CSV” button that respects your $wgCargoDefaultQueryLimit.

If you’re already on 3.8.4, you’ll notice the “Export CSV” link in the table view – a handy shortcut for pulling data into spreadsheets without extra extensions.

Best practices – a few habits that keep Cargo tidy

These aren’t hard rules, more like gentle nudges from a seasoned editor:

  1. Name tables clearly. Use singular nouns (Book, Event) rather than plurals; it matches the primary‑key convention and reads nicer in queries.
  2. Document your schema. Add a comment block in the template’s <noinclude> explaining each field – future you (or a new contributor) will thank you.
  3. Limit exposure. Set $wgCargoMaxQueryLimit low on public wikis to prevent accidental “SELECT * FROM huge_table” attacks.
  4. Use #cargo_attach for shared tables. It avoids duplicate #cargo_declare blocks and keeps the DB schema in one place.
  5. Test queries in a sandbox page. Before dropping a heavy query into a live article, try it on Special:CargoQuery with format=debug to see the raw SQL.

Wrapping up the Cargo adventure (but not in a “conclusion” way)

There you have it – a slightly chaotic, human‑flavored walkthrough of getting Cargo up and running, tweaking it, and putting it to work. The extension is a solid choice when you want your MediaWiki to behave like a modest database without the overhead of a full semantic stack.

Next time you find yourself writing a thousand‑row list of community projects, remember there’s a #cargo_store lurking in your template, waiting to catch those rows. And if you ever feel the urge to query across multiple tables, just whisper #cargo_query and watch the magic unfold – a little bit of code, a dash of SQL, and a whole lot of wiki‑style flexibility.

Subscribe to MediaWiki Tips and Tricks

Don’t miss out on the latest articles. Sign up now to get access to the library of members-only articles.
jamie@example.com
Subscribe