How to Use the Cargo Extension in MediaWiki for Structured Data Management

At a glance, Cargo feels a bit like adding a tiny spreadsheet behind every wiki page

What Cargo brings to a MediaWiki

At a glance, Cargo feels a bit like adding a tiny spreadsheet behind every wiki page. Instead of sprinkling raw data in prose, you let the extension declare a table, store rows, and later query it from any special page, a template or even the API. In practice this means a wiki can evolve from a collection of articles into a modest‑scale database without touching the underlying MySQL directly.

Installation in a nutshell

  • Download the extension (or pull it via Composer: composer require mediawiki/cargo).
  • Drop the Cargo folder into extensions.
  • Add $wgEnableUploads = true; and wfLoadExtension( 'Cargo' ); to LocalSettings.php.
  • Run the update script: php maintenance/update.php.

If you’re on MediaWiki 1.40 or newer, the extension should spin up automatically. A quick refresh of “Special:Version” will show Cargo listed among the active extensions.

Declaring a table – the #cargo_declare parser function

Think of #cargo_declare as the CREATE TABLE statement you’d write in SQL. It lives in the part of a template so the declaration is stored once, not on every page that uses the template.

<noinclude>
{{#cargo_declare:
  _table=Books
| Title=String
| Authors=List (,) of Page
| Genres=List (,) of String
| Year=Date
| Pages=Integer
}}
</noinclude>

Notice the underscore‑prefixed _table parameter – that tells Cargo the name of the table. The rest are column definitions. Types are deliberately lightweight: String, Integer, Date and the List helper, which automatically splits a comma‑separated value into an array.

Storing a row – #cargo_store

The #cargo_store call goes inside so that every time the template is transcluded the data lands in the table.

<includeonly>
{{#cargo_store:
  _table=Books
}}
{| class="wikitable"
! Title
| {{{Title}}}
|-
! Author(s)
| {{#arraymap:{{{Authors|}}}|,|x|[[{{x}}]]}}
|-
! Genre(s)
| {{{Genres}}}
|-
! Year
| {{{Year}}}
|-
! Pages
| {{{Pages}}}
|}
</includeonly>

When a page like Book:The Great Gatsby contains {{Book|Title=The Great Gatsby|Authors=F. Scott Fitzgerald|Genres=Novel|Year=1925|Pages=180}}, Cargo adds a row to Books. The page title itself is stored automatically in a hidden column called _pageName, so you can always join back to the source page.

Reading data – #cargo_query

A query can live on a special page, a template, or directly on a wiki page. The most common shape looks like this:

{{#cargo_query:
| tables=Books
| fields=Title,Authors,Year
| where=Year>=2000
| format=table
| order by=Year
}}

That snippet produces a plain HTML table of all books published from the year 2000 onward, sorted chronologically. The format=table argument is just one of many; you can also ask for plainlist, csv or even a custom #lua template for fancy rendering.

Example project – a personal library catalog

Imagine you want a wiki that tracks every book on your shelf, plus a page for each author. You’d need two templates: Book (shown above) and Author.

<noinclude>
{{#cargo_declare:
  _table=Authors
| Country=String
}}
</noinclude>

<includeonly>
{{#cargo_store:
  _table=Authors
}}
{| class="wikitable"
! Country
| {{{Country}}}
|-
! Books
| {{#cargo_query:
    tables=Books
    fields=Title
    where=Authors HOLDS '{{PAGENAME}}'
    format=plainlist
  }}
|}
</includeonly>

The trick here is the where=Authors HOLDS '{{PAGENAME}}' clause. “HOLDS” is Cargo’s way of asking “does the list column Authors contain this value?”. Because the page name of an author page is automatically the author’s name, the query pulls every book that lists that author.

Display formats – making the data pretty

Cargo ships a handful of built‑in formats. Here are the most useful ones, with a quick note on when to pick each:

  • table – classic two‑dimensional view; great for admin pages or “list of all entries”.
  • ul – unordered list; handy for sidebars or “related pages” widgets.
  • csv – raw comma‑separated values; perfect if you intend to export to Excel.
  • template – feed the rows into a custom template of your own design, giving you full control over HTML and CSS.

For a more visual presentation you can combine Cargo with Page Forms or even Graph to turn query results into charts.

Exporting and the API

Every Cargo table is exposed via the MediaWiki Action API. A simple GET request like the following returns JSON:

https://yourwiki.org/w/api.php?action=cargoquery&format=json&tables=Books&fields=Title,Authors,Year

That means external tools – Python scripts, Node‑JS bots, even a spreadsheet plugin – can pull the data without scrubbing the HTML output. The API also supports limit, offset and where clauses, mirroring the power of #cargo_query.

Common pitfalls (and how to dodge them)

  1. Forgetting _table in the declaration. The extension will silently ignore the template, leaving you with an empty table.
  2. Using reserved column names. Names like page_id or _pageName are reserved for internal use – pick something else.
  3. Mixing list delimiters. Cargo expects a single character (usually a comma) to split list fields. Accidentally using a semicolon will give you an “empty list” in the query results.
  4. Performance hiccups on huge tables. If a table crosses the 10,000‑row mark, consider adding indexes (via #cargo_sql or a manual DB tweak) or splitting the data into multiple tables.

Putting it all together – a short walkthrough

1. Create Template:Book and Template:Author as shown.

2. Add a few sample pages:

[[Book:The Hobbit]]
{{Book|Title=The Hobbit|Authors=J. R. R. Tolkien|Genres=Fantasy|Year=1937|Pages=310}}

[[Author. R. R. Tolkien]]
{{Author|Country=United Kingdom}}

3. Visit a special page like Special:CargoQuery (or embed a query on a regular wiki page) with:

{{#cargo_query:
| tables=Books
| fields=Title,_pageName,Year
| where=Year>1900
| format=ul
}}

The output will be a bullet list of all books after 1900, each entry linking back to its own page. That’s the whole workflow: declare, store, query, display.

Why you might choose Cargo over Semantic MediaWiki

Both extensions let you treat a wiki like a database, yet they differ in philosophy. Semantic MediaWiki (SMW) leans heavily on RDF‑style triples and a separate query language (#ask). Cargo, on the other hand, keeps data in traditional relational tables, which feels more familiar to folks with SQL backgrounds. If you need fast CSV exports, direct API access, or simply want to avoid the extra learning curve of SMW’s property hierarchy, Cargo is often the smoother road.

Wrapping up

Once the scaffolding is in place, adding a new structured dataset is as easy as creating another template with a fresh #cargo_declare line. The extension handles table creation, row insertion and even cleanup when pages are deleted. In short, Cargo gives you a lowmaintenance, low‑code way to turn a MediaWiki into a modest‑scale data hub – perfect for internal documentation, community inventories, or any project where “pages plus tables” makes sense.

Give it a spin on a test wiki, sprinkle a few #cargo_query calls, and you’ll quickly see how the once‑static pages start behaving like living, queryable records. That’s the magic of Cargo: data, simply stored where you already write it.

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