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/Cargoon your server. No fancy sub‑directories needed – Cargo is tidy. - Run the updater. Fire up
php maintenance/update.php. Cargo will create itscargo_tables,cargo_pagesandcargo_backlinkstables (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.
| Setting | Default | What it does |
|---|---|---|
$wgCargoDecimalMark | . | Character used for decimal points in numbers. |
$wgCargoDigitGroupingCharacter | , | Thousands separator (e.g., 1,000 vs 1 000). |
$wgCargoDefaultQueryLimit | 100 | How many rows #cargo_query returns if you don’t specify limit=. |
$wgCargoMaxQueryLimit | 5000 | Upper bound to keep runaway queries from hogging the server. |
$wgCargoDefaultMapService | OpenLayers | Choose googlemaps, leaflet, or stick with OpenLayers. |
$wgCargoDBtype … $wgCargoDBRowFormat | null | Set 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}}} booksNotice 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_backlinkstable 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
$wgCargoHideNamespaceNameor usenamespace=Filein 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
NULLvalues in Lua queries – you can now toggle$wgCargoLegacyNullLuaFieldsAsEmptyStringto retain old behaviour if you have legacy scripts. - Performance boost for large
#cargo_querycalls – the query engine now streams results, cutting memory usage by about 30% on busy wikis. - Support for
jsonbcolumns 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:
- Name tables clearly. Use singular nouns (
Book,Event) rather than plurals; it matches the primary‑key convention and reads nicer in queries. - Document your schema. Add a comment block in the template’s
<noinclude>explaining each field – future you (or a new contributor) will thank you. - Limit exposure. Set
$wgCargoMaxQueryLimitlow on public wikis to prevent accidental “SELECT * FROM huge_table” attacks. - Use
#cargo_attachfor shared tables. It avoids duplicate#cargo_declareblocks and keeps the DB schema in one place. - Test queries in a sandbox page. Before dropping a heavy query into a live article, try it on
Special:CargoQuerywithformat=debugto 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.