Extension:Page Exchange

Page Exchange (abbreviated "PX") is an extension that enables installing and updating "packages", which are groups of one or more wiki pages. The pages in a package usually have one common purpose, such as defining an entire data structure. Packages are defined in JSON files, known as "package files", which use a custom syntax described below. Anyone can publish such package files, just by putting them online. In order to use a particular file, a wiki administrator just needs to add its URL to the $wgPageExchangePackageFiles variable in LocalSettings.php; see below.

Once this extension has been installed, and one or more package files are included in LocalSettings.php, all the installation and upgrading of packages is done at the page Special:Packages.

If a package contains JavaScript or CSS pages - defined as pages named MediaWiki:PageName.js or MediaWiki:PageName.css - then those JavaScript or CSS pages will get loaded for users on every page of the wiki, as is already done with the pages MediaWiki:Common.js and MediaWiki:Common.css.

If a package contains any template page that includes a call to #cargo_declare, i.e. the package defines a table for the Cargo extension, then those tables will get created automatically when the package is installed.

Uses
PX packages can be created for a variety of purposes:
 * Enabling wikis to have a data structure similar to, or inspired by, a popular wiki such as Wikipedia
 * Enabling those running a wiki farm to impose a standard starting set of pages across all wikis
 * Allowing users who are getting started with extensions that can involve complex syntax and rules (Cargo, Page Forms, Semantic MediaWiki and related extensions, Scribunto, etc.) to download working examples to their wiki
 * Allowing consultants who develop their own branded bundle of extensions to also add wiki pages and images to their offering
 * A substitute for a lightweight extension or skin, assuming that extension consists of only JavaScript and/or CSS
 * An alternative way to do a transfer of content (pages and/or images) between wikis, on a regular basis or even just once.

In all these cases (except for the last one or two), there could be multiple versions of each package in different languages, so that (ideally) every wiki that wants such a package could have one available in its own language.

Download
You can download the Page Exchange code, in .zip format, here: https://github.com/wikimedia/mediawiki-extensions-PageExchange/archive/0.6.zip

You can also download the code directly via Git from the MediaWiki source code repository (see available tags). From a command line, call the following:

Installation
Once you have obtained a "PageExchange" directory and placed it in your /extensions directory, add the following to LocalSettings.php:

Then go to the MediaWiki /maintenance directory, and run the following:

The installation and other handling of packages can be done by anyone with the 'pageexchange' permission; by default, this is available to those in the 'sysop' group. To extend this permission to, for instance, anyone in the 'bureaucrat' group, you can add the following to LocalSettings.php:

Finally, in order for this extension to be useful, you will need to populate either the global variable $wgPageExchangePackageFiles, or the global variable $wgPageExchangeFileDirectories, or both, in LocalSettings.php. Both hold a set of URLs; the first holds JSON URLs, while the second holds URLs of pages that themselves hold a set of JSON URLs, one per line. The first variable would be populated in the following way:

...while the second would be populated like this:

(The URLs populating wgPageExchangeFileDirectories can actually have any file extension, not just ".txt", as long as what they hold is plain text.)

See the next section for some examples of generic package files that can be used.

Usable package files
Anyone can create their own package files. If you have created a package file meant to be widely useful, feel free to add it to the list below, with a short description of the package(s) it defines.


 * Cargo books demo - a data structure, and sample data, for books and their authors, using Cargo and Page Forms
 * SMW books demo - a data structure, and sample data, for books and their authors, using Semantic MediaWiki and Page Forms
 * Skills matrix - Provides a form and template for users to add skills to their user pages.
 * Packages from the WikiTeq team get added here. The ones not listed here are under active development.

Including JavaScript and CSS pages
You can have a package include JavaScript or CSS pages, which are pages that have the namespace "NS_MEDIAWIKI" and a name that ends with ".js" or ".css". Any such page will then get loaded during all regular page loads, as already happens with the pages MediaWiki:Common.js and MediaWiki:Common.css.

If a package contains any such JS or CSS page, only users who have permission to edit JS or CSS pages on the wiki (in addition to the permission to access Special:Packages) will be allowed to install it.

This functionality will only work for sites that have $wgUseSiteJs and $wgUseSiteCss both set to true (they are both true by default).

API
Page Exchange defines three API actions: "pxinstallpackage", "pxupdatepackage" and "pxuninstallpackage". On your wiki, you can go to api.php to see documentation on how to call these three actions.

Package file syntax
Packages are defined in "package files": JSON files available at some public URL, each of which defines one or more packages. There is no limit to the number of packages that can be defined in one package file, and the packages can be completely unrelated to one another. Each package, in turn, includes one or more wiki pages.

Here is the set of parameters that can be set for an overall package file:
 * - The default publisher
 * - The default URL for the publisher
 * - The default author
 * - The default language for all defined packages, using the (usually) two-letter IETF language tag for that language.
 * - The default license under which these packages are published.
 * - Holds the set of packages, with the package name as the key and the set of package parameters as the values.

Here is the set of parameters that can be set for a single package:
 * - (mandatory) A text identifier for this package, which is ideally globally unique. Ideally it uses reverse domain name notation. For example, for a package in the Spanish language for a CRM data structure, created by a company called Acme, whose internet domain is acme.com, the package identifier could be "com.acme.CRM.es". You can feel free to be creative within this system. For example, if you are publishing a package on your own and do not have your own internet domain, but you do have a username on mediawiki.org ("Joey User"), then you could give such a package the identifier "org.mediawiki.user.Joey_User.CRM.es". The important thing is uniqueness. It's also important, once people have started using a package, not to change its global ID - changing it would prevent people who have already downloaded the package from updating to more recent versions.
 * - The publisher.
 * - The URL for the publisher.
 * - The author or authors of this package.
 * - The language for this package, using the IETF language tag.
 * - A URL for a web page describing this entire package, if one exists.
 * - A version number for the package, which can be updated so that users know if their local copy of the package is out of date.
 * - The name of the license under which this package is published.
 * - An array of the names of any extensions required for this package to work. (In the future, this parameter may also allow defining specific versions that are required for specific extensions, but this is not currently possible.)
 * - An array of the names of any additional packages required by this package.
 * - Holds a URL fragment (like 'https://example.com/packages/') that should be prepended to the  or   values set for any individual pages.
 * - The set of pages in this package.
 * - For pages stored within a single repository (like GitHub), specifies the structure of that repository, instead of (or in addition to) any pages explicitly listed.

Within the  value, here is the set of parameters for any individual page:
 * - The name (minus of the namespace) of a wiki page
 * - The namespace code for the namespace of the wiki page, though stored as a string (like "NS_TEMPLATE"). The default is "NS_MAIN".
 * - The URL at which the contents of the page can be found. This can be any URL, and does not have to be part of a wiki. If you are using a MediaWiki wiki page for the URL, make sure that the URL ends with "?action=raw" (or "&action=raw"), so that only the actual wikitext for the page is retrieved.
 * - If this is a file/image page (i.e. with a "namespace" value of "NS_FILE"), this parameter holds the actual file, while the "url" parameter holds a URL containing the text contents of the wiki page.
 * - Similar to, but gets appended to the   value set for the package, if one was set.
 * - Similar to, but gets appended to the   value set for the package, if one was set.

Within, the following parameters can be set:
 * - The service being used to hold the data on individual pages. Currently only value is supported for this: "GitHub".
 * - The name of the account, i.e. the GitHub username of the repository.
 * - The name of the specific repository.
 * - The group of settings, per namespace, that together dictate the structure of the directory.

Within, here are the parameters for each individual entry:
 * - The namespace code for this namespace, though stored as a string (like "NS_TEMPLATE").
 * - The prefix (potentially including slashes) for any file that corresponds to a page in this namespace.
 * - The suffix (if any) for any file that corresponds to a page in this namespace.
 * - Used only for the "NS_FILE" namespace; specifies the prefix for the actual files (e.g., the images)
 * - Used only for the "NS_FILE" namespace; specifies the suffix for the actual files

The  setup only works if the name of each file in the (GitHub) repository is the same as, or at least contains, the name of the wiki page it defines. As an example, see this repository; every namespace has its own directory, and every file name is the wiki page name plus the ".mediawiki" suffix. You can see a JSON file configured for this repository here.

Version history

 * 0.1 - May 15, 2020 - Initial version


 * 0.2 - June 10, 2020 - Added special handling for imported JS, CSS pages; bug fixes
 * 0.2.1 - June 25, 2020 - Fixes for display of installed packages
 * 0.2.2 - July 7, 2020 - Fixed handling for MW < 1.32
 * 0.2.3 - December 14, 2020 - Added "licenseName" property to packages; fixed handling for MW 1.34+; other bug fixes


 * 0.3 - June 10, 2021 - Added API for installing, updating and uninstalling packages; added $wgPageExchangeFileDirectories setting; added "directoryStructure", "baseURL" and "urlPath" JSON settings


 * 0.4 - November 11, 2021 - Removed support for MW < 1.33; improved support for MW 1.34+; added auto-creation of Cargo tables; bug fixes
 * 0.4.1 - April 4, 2022 - Added support for GitHub's new "main" default branch; improved support for MW 1.37+; bug fixes


 * 0.5 - August 8, 2022 - Removed support for MW < 1.34; improved support for MW 1.36+; improved handling for pages with non-wikitext content types; bug fixes


 * 0.6 - March 2, 2023 - Removed support for MW < 1.35