Best practices for extensions

This page lists best practices for MediaWiki extensions to follow. Each item has a rating of how important it is. Ideally every extension should strive for the "gold standard".

This list was originally started at the 2017 Wikimania Hackathon.


 * REQUIRED - Meeting these criteria likely means your extension will work, but it may not be sustainable or maintainable.
 * SHOULD - Meeting these criteria likely means your extension works well and will continue to work well in the future
 * GOLD - Meeting these criteria means your extension is the ideal standard we all aspire to be, and should be used as an example to other developers

Meta

 * REQUIRED: Use the normal MediaWiki bug tracker / code review systems
 * REQUIRED: The extension should not be Wikimedia or organization specific
 * REQUIRED: For deployment on Wikimedia Wikis - Performance & Security review
 * SHOULD: Have co-maintainers! Doesn't matter if it's a WMF employee, but there should be 2 minimum.
 * SHOULD: Create a MediaWiki-Vagrant role for your extension.

Documentation

 * REQUIRED: Have a Extension:Foo page on mediawiki.org
 * REQUIRED: Add it to the appropriate extension categories
 * REQUIRED: Quick explanation of what it does
 * REQUIRED: Complete list of any dependencies and how to install them, configure, and uninstall* (TODO: clarify uninstall)
 * SHOULD: Clear description of exactly which MW versions it works with or declare the compatibility policy of your extension.
 * SHOULD: All configuration settings described in one place, from most-used to most-obscure
 * GOLD: Compare and contrast with similar extensions
 * GOLD: Document hooks used in the extension infobox, it's a nice method of exposing examples so that other developers can learn (they get automagically categorised).
 * GOLD: Instructions how to/information on limitations regarding uninstallation
 * REQUIRED: Having a Help:Extension:Foo page on mediawiki.org
 * GOLD: Documentation should have screenshots in multiple languages, ideally one in RTL
 * GOLD: Documentation should discuss some edge cases that were tested - to prove due diligence of not just testing on simple/generic articles
 * SHOULD: Consistently use &#x3C;code>, &#x3C;source> in documentation (TODO: create a documentation style guide?)
 * GOLD: Add/update the extension's page on WikiApiary (if required).

File structure
Overall, the extension's file layout should be organized: consistent naming, directory structure that is logical and not messy.
 * REQUIRED: Using the standard directory layout of resources/ includes/ i18n/ etc.
 * or : Contains all PHP code
 * SHOULD: One class per file.
 * GOLD: Use PSR-4 structure for classes/files. Should be in  namespace.
 * : Contains JS and CSS for ResourceLoader
 * : Contains localized messages in JSON files.
 * : Contains PHPUnit test cases
 * : Contains parser test files
 * or : Contains full copy of the relevant license the code is released under
 * REQUIRED: Not having a giant root level directory
 * SHOULD: Not having dozens of nested directories that all only contain one or two things
 * SHOULD: Not having giant files/many separate tiny files (but follow one class per file pattern - many tiny classes may be a sign of something else wrong)
 * SHOULD: A README file that summarized the docs and gives detailed installation directions
 * Prominent $VERSION indication in the README and main php file (ideally all files) (TODO: ???)
 * Prominent $VERSION indication in the README and main php file (ideally all files) (TODO: ???)

Database

 * REQUIRED: If adding database tables, it should use the LoadExtensionSchemaUpdates hook to ensure update.php works.
 * REQUIRED: Database access should always use database abstraction layer
 * Doing so will avoid a lot of easy SQL injection attack vectors
 * SHOULD: It works well in a distributed environment (concurrency, multiple databases, clustering).
 * Uninstallation maintenance script (dropping tables, removing added columns, deleting log entries, deleting page properties). (TODO: ???)
 * SHOULD: If it needs persistence, it creates nice SQL (primary keys, indexes where needed) and uses some caching mechanism where/if necessary

Coding conventions
Overall, follow the MediaWiki coding conventions for PHP, JavaScript, CSS, and any other languages that could be used.
 * SHOULD: Run MediaWiki-CodeSniffer for PHP coding conventions
 * SHOULD: Run eslint for JS coding conventions
 * SHOULD: Run stylelint for CSS coding conventions
 * In JS especially, don't dump everything into one function. If you're indented off the screen, you're doing it wrong
 * Use code comments to document why you do things, not what you do. In long blocks of code, adding comments stating what each paragraph does is nice for easy parsing, but generally, comments should focus on the questions that can't be answered by just reading the code.

Development / Code

 * Provides all the same functionality over API and web, without duplicating implementation
 * Use dependency injection, avoid static calls for other than utility methods + hook entry points
 * Don't overuse private visibility in services
 * Avoid global state
 * Easy to Debug:
 * Use structured logging, with meaningful levels
 * Exceptions only for situations it should not handle
 * Shelling out should escape arguments
 * Don't hardcode wikicode / templates or stuff, especially in a way that's not configurable for other websites
 * Code should be readable by someone who is familiar in that area
 * Don't call out to static functions in an unrelated class because it wasn't refactored or thought out well

Testing

 * Unit tests QUnit / PHPUnit (real unit tests)
 * Integration/ browser tests
 * Having CI run
 * parser functions/tags need parser tests

i18n & Accessibility

 * Don't have hardcoded non-translatable strings in your code, use the proper l10n functions (wfMessage)
 * Using i18n and translate wiki
 * GOLD: Add qqq message strings for all messages that exist in en.json
 * Test against RTL languages!
 * Test against language converter languages!
 * i18n escape as close to output as possible. document whether functions take/except wikitext vs HTML
 * Use HTML elements for their intended purpose. Aka use a &#x3C;button> and not a &#x3C;div> with a click handler for accessibility.
 * id's should only be for things you can navigate to. Everything else should be a class. Even if you want to only use it once, just use a unique class

Don't reinvent / abuse MediaWiki

 * Don't reimplement MediaWiki
 * Don't reimplement libraries that exist, don't reinvent the wheel
 * Don't disable OutputPage
 * Don't disable parser cache unless you have a really good reason
 * Don't make things harder than yourself - use standard functionality like extension.json's tests/phpunit auto discovery stuff
 * Use global mediawiki configuration such as read-only mode
 * Use MW functionality/wrappers for things like WebRequest vs $_GET. etc.
 * Use hooks as opposed to hacks/reimplementing things
 * Use MW's validation/sanitization methods e.g. HTML class, htmlspecialchars, etc.
 * REQUIRED: Use Composer for 3rd party PHP library management.
 * Use ContentHandler and this kind of abstractions instead of hooks

Uncategorized
NOTE: Check on Boilerplate extension T97105
 * Has a clear separation of concerns between what it actually does, and how its presented to the user
 * Can I read the code with reasonable effort? Is it convoluted / unnecessarily complex?
 * Know when you should use ParserOutput methods vs. same methods in OutputPage
 * Don't touch HTML after it has been sanitized (common pattern is to use regex, but that's bad)
 * All write actions should be protected with CSRF
 * skin and extension functionality should not be tightly integrated.
 * Don't load external resources for privacy and performance
 * It's okay to file duplicate bugs (it's better than not filing it at all!)
 * https://www.mediawiki.org/wiki/Technical_Collaboration_Guidance
 * https://en.wikipedia.org/wiki/User:Risker/Risker%27s_checklist_for_content-creation_extensions
 * Make sure privacy related issues (checkuser, oversight) are still covered when refactoring or writing new code
 * Think twice before adding new wikitext syntax functionality or something that will have a stable API for a very long time
 * Should extensions be adding userrights in the default extension?
 * Adding user rights are easy in code, but can be politically controversial and should be discussed with the community about who grants the rights and who has them by default
 * Don't add new user preferences! https://www.mediawiki.org/wiki/Just_make_it_a_user_preference
 * If you do, have a very good reason - actual research into different use cases etc
 * Expose your Javascript methods so 1) user scripts can access them, 2) it is easy to debug them. Do not make everything private.