Extension:CommunityRequests
Release status: beta |
|
---|---|
Implementation | Parser function , Special page , API |
Description | An on-wiki system for managing a wiki community's requests for technical development. |
Author(s) | WMF Community Tech team |
Compatibility policy | Main branch maintains backward compatibility. |
MediaWiki | >= 1.45 |
Database changes | Yes |
Tables | communityrequests_counters communityrequests_entities communityrequests_tags communityrequests_translations |
License | GNU General Public License 2.0 or later |
Download | README |
Help | Help:Extension:CommunityRequests |
|
|
|
|
|
|
Translate the CommunityRequests extension if it is available at translatewiki.net | |
Issues | Open tasks · Report a bug |
The CommunityRequests extension is a system for managing a wiki community's requests and suggestions for technical development. It aims to provide a flexible and user-friendly platform for community-empowered project management.
For user help please see Help:Extension:CommunityRequests.
Background
[edit ]CommunityRequests was built to power the Wikimedia Foundation's Community Wishlist , where community members create and vote on wishes for improvements to the platform. As such, all user-facing messaging and the code itself uses the name "Community Wishlist". Wishes can be grouped together by Wishlist organizers into focus areas. Both wishes and focus areas can be voted on, if configured.
The Foundation's Wishlist spawned from an older bot and template-powered system known as the annual Community Wishlist Survey. For this reason, CommunityRequests largely uses the wiki as the storage medium, with a system of parser functions such that we can enforce and store structured data, while allowing manual editing for advanced users such as translation admins.
Out-of-the-box, this extension assumes you want something similar to the Community Wishlist, but it can be configured to suit various use cases.
Dependencies
[edit ]Hard dependencies
- Extension:VisualEditor – We plan to remove this dependency, but for now it is the sole means to edit descriptions of wishes and focus areas.
Recommended dependencies
- Extension:Translate – If your wiki is multilingual, you will want this installed. $wgNamespacesWithSubpages must also be set to
true
for the namespace(s) where wishes and focus areas are configured be stored. - Extension:WikimediaMessages – If you're developing for the Wikimedia installation.
- Phabricator – The extension currently assumes Phabricator is used as a bug tracking system.
Installation
[edit ]- Download and move the extracted
CommunityRequests
folder to yourextensions/
directory.
Developers and code contributors should install the extension from Git instead, using:cdextensions/ gitclonehttps://gerrit.wikimedia.org/r/mediawiki/extensions/CommunityRequests
- Add the following code at the bottom of your LocalSettings.php file:
$wgPageLanguageUseDB = true; // If your wiki is multilingual $wgNamespacesWithSubpages[ NS_MAIN ] = true; // If you use Extension:Translate. Replace NS_MAIN accordingly. wfLoadExtension( 'CommunityRequests' );
- Run the update script which will automatically create the necessary database tables that this extension needs.
- Add the
phab
interwiki prefix for linking to Phabricator tasks, if desired. - Yes Done – Navigate to Special:Version on your wiki to verify that the extension is successfully installed.
Configuration
[edit ]The following can be set in your LocalSettings.php file.
$wgCommunityRequestsEnable
- The main feature flag for this extension, that must be set to
true
in order for anything other than system messages to function. $wgCommunityRequestsHomepage
- The wiki page title (including the namespace) of the homepage for Community Requests.
$wgCommunityRequestsWishCategory
- The category to put all wishes in.
$wgCommunityRequestsWishPagePrefix
- Path for the page title of wishes. Should include a trailing slash, and an optional prefix for the auto-generated title id. Wishes will only be saved and handled by this extension if within this path.
$wgCommunityRequestsWishIndexPage
- The wiki page that lists all of the wishes using the wish-index parser function.
$wgCommunityRequestsWishTypes
- The available types of wishes. The keys are wikitext values. The
label
properties are message keys to be suffixed with-label
and-description
. Theid
value must be an integer that is forever associated with the meaning of the label. Types can freely be renamed, but new ones or ones with a significant change in meaning should get a new ID. $wgCommunityRequestsFocusAreaCategory
- The category to put all focus areas in.
$wgCommunityRequestsFocusAreaPrefix
- Path for the page title of focus areas. Should include a trailing slash, and an optional prefix for the auto-generated title id. Focus areas will only be saved and handled by this extension if within this path.
$wgCommunityRequestsFocusAreaIndexPage
- The wiki page that lists all of the focus areas.
$wgCommunityRequestsProjects
- For use by wiki farms. An object keyed by the value that will be saved to the page's wikitext, with values being objects with the following keys:
Key Description id Unique numerical ID for this project. domain The domain name of the project. label The message key for the project name. logo The full URL to a ~200px square SVG logo.
$wgCommunityRequestsStatuses
- The available statuses for wishes and focus areas. An object keyed by the value that will be saved to the page's wikitext, with values being objects with the following keys:
Key Description id Unique numerical ID for the status. label The message key for the status. default Setting this indicates the status should be the default when creating new wishes and focus areas.
$wgCommunityRequestsWishVotingEnabled
- Whether to enable voting for wishes.
$wgCommunityRequestsFocusAreaVotingEnabled
- Whether to enable voting for focus areas.
Architecture
[edit ]The core understanding to this extension is that everything originates from wikitext. See #Background on why we ended up here. Additionally, the extension is highly configurable, so it's important to make use of the WishlistConfig
class that abstracts this.
Lifecycle
[edit ]- User submits an entity using Special:WishlistIntake or Special:EditFocusArea. Clinetside validations are performed.
- The Special class constructs a backend API request to ApiWishEdit or ApiFocusAreaEdit. API validations are enforced, which bubble up to the Special page on failure.
- We confirm we can parse and then re-create the same wikitext we were given.
- A new ID is generated for the entity, if it's a new entity.
- An entity value class is constructed.
- The wikitext (which uses the
{{#CommunityRequests:}}
parser function) is saved to the page. - The hook handlers in
CommunityRequestsHooks
do their thing, ultimately callingAbstractWishlistStore::save()
, which has one final round of validations to ensure data integrity.
Clientside
[edit ]Path: /modules
There are several ResourceLoader modules that power the extension. Each should load only the subset of Codex components needed for that modules, and same for any Codex icons. Similarly in the name of performance, we use virtual JSON files to pass in configuration variables, should any be needed by the module.
Each module also has an init script, which is the entrypoint for the module and would load the corresponding Vue application.
ext.communityrequests.styles
[edit ]Path: /modules/common/styles.less
Render-blocking module styles. This should contain only styles essential for the initial rendering of pages.
ext.communityrequests.intake
[edit ]Path: /modules/intake
Powers the Special:WishlistIntake and Special:EditFocusArea. Until we are able to use Codex PHP, these Vue applications are required for the Special pages to function.
Note this module has dynamic messages that come from configuration. The SpecialWishlistIntake::addResourceLoaderMessages()
factory method ensures they packaged with the ResourceLoader module.
ext.communityrequests.mint
[edit ]Path: /modules/mint
Contains the translation banner Vue app that provides machine translations using the MinT service.
ext.communityrequests.voting
[edit ]Path: /modules/voting
The Vue app for the voting button and submission dialog. When a vote is submitted, it makes an edit to the /Votes
subpage using the {{#CommunityRequests:vote}}
parser function.
Stores
[edit ]Paths: /includes/AbstractWishlistStore.php
, /includes/**/*Store.php
The stores are responsible for all database operations related to wishlist entities. Most logic between WishStore
and FocusAreaStore
is shared in the parent AbstractWishlistStore
. Each subclass defines its schema through static methods like ::tableName()
, ::fields()
, or ::pageField()
. This is then used in the abstract class to construct queries in a consistent manner.
Subclasses also must define abstract methods that indicate which fields live only in wikitext, or which fields may be wrapped with <translate>...</translate>
tags. This is used by ApiQueryWishes
and elsewhere to ensure we only fetch wikitext content when necessary, as opposed to pulling data directly from our own database tables. This behaviour is controlled using the ::FETCH_WIKITEXT_*
constants with the store's ::get()
or ::getAll()
methods.
Hook handlers
[edit ]Path: /includes/HookHandler
CommunityRequestsHooks.php
is where all the parts of the application are tied together. While the Special forms exist, everything comes from wikitext, so we leverage a system of hooks to process the data and generate output – paying mind to which hooks are either before or after the parser caches the output.
Hook | Description |
---|---|
GetUserPermissionsErrorsExpensive | Called before saving the edit or starting a new editing session, in order to verify the user has the requisite rights to edit the page. |
Edit is now saved | |
ParserFirstCallInit | Called for each {{#CommunityRequests:}} parser function that appears on the page. The associated parser function renderers will set the extension data for use in handlers that are called later in the process. The renderers also return any PHP-generated HTML that then gets added to the parser output.
|
ParserAfterTidy | Called when there are votes on the wish or focus area page. The voting strip marker in the parser output is replaced with the final vote count. |
Parser output is now cached | |
RevisionDataUpdates | Called when the revision is saved. We use this hook to change the page language to the user's language when creating new entities. |
LinksUpdateComplete | Called a single time after page saves. Using the extension data added by the renderers, this is the method that saves the entity to the CommunityRequests tables. |
BeforePageDisplay | This adds any outstanding ResourceLoader modules we may need, including the render-blocking styles-only module ext.communityrequests.styles .
|
SkinTemplateNavigation::Universal | Adds the "Edit with form" tab and hides other edit tabs based on permissions, and updates any "Discussion" links to point to the root entity talk page. |
RecentChange::save | Called when the edit is saved to recent changes. If the edit was made using the form, this handler will retroactively add the change tag to the revision. |
Hook | Description |
---|---|
LoginFormValidErrorMessages | Adds the communityrequests-please-log-in message as an allowable message shown on Special:UserLogin. The
|
ListDefinedTags | Registers CommunityRequestsHooks::WISHLIST_CHANGE_TAG as a known change tag.
|
ChangeTagsListActive | Registers CommunityRequestsHooks::WISHLIST_CHANGE_TAG as an active change tag.
|
PageDeleteComplete | Called when a page is deleted. Any related data in CommunityRequets tables is deleted. |
BeforeDisplayNoArticleText | Used to customize the standard MediaWiki:Noarticletext message shown when viewing a nonexistent entity page. |
GetPreferences | Registers the preference giving users the ability to use machine translation on the Community Wishlist. |
ID generation
[edit ]Path: /includes/IdGenerator
Works the same as WikiBase.
TODO: expand
Renderers
[edit ]Paths: /includes/AbstractRenderer.php
, /includes/**/*Renderer.php
These are called during the ParserFirstCallInit hook. They define the PHP output, and add categories and tracking categories. Basic validation is done from the data given in the parser functions, with the errors explained in the parser output.
While an "entity" refers to only a wish or focus area, in the context of renderer classes, the ::$entityType
property refers to any one of the parser function types: wish
, wish-index
, focus-area
, focus-area-index
and vote
. This all gets tied together in the RendererFactory
, with that factory's ::render()
method being the one that is called in CommunityRequestsHooks
.
Value classes
[edit ]Path: /includes/AbstractWishlistEntity.php
These are value objects that contain no setters. They should be largely static with no dependencies on services.
The subclasses Wish
and FocusArea
define PARAM_
constants, which are used when referencing parser functions parameters, extension data, and API parameters. These subclasses also define how the data is transformed to and from wikitext.
Special pages
[edit ]Paths: /includes/AbstractWishlistSpecialPage.php
, /includes/**/SpecialPage.php
There are two Special pages, SpecialWishlistIntake
and SpecialEditFocusArea
with most logic living in the parent AbstractWishlistSpecialPage
class. If an entity ID or page title is passed in, the entity and associated metadata (such as available focus areas) are loaded and supplied to the ext.communityrequests.intake module by way of JS config variables.
On submission, we construct a backend API request to ApiWishEdit or ApiFocusAreaEdit. This is necessary to ensure all side effects and integrations with editing are ran (hooks, abuse filters, title blacklist, etc). This only safe to edit is through the notorious EditPage.php, and in our case we access it through API:Edit, which is used by our APIs.
APIs
[edit ]Path: /includes/Api
TODO
ApiWishEdit
[edit ]TODO: Link to auto-generated docs
ApiFocusAreaEdit
[edit ]TODO: Link to auto-generated docs
ApiQueryWishes
TODO: Link to auto-generated docs
Glossary
[edit ]- Component tag
- A tag that identifies a component that a wish relates to according to Developers/Maintainers.
- Detail pages
- Refers to either the wish detail page or the focus area detail page.
- Display value (or "label")
- Refers to the localized, fully human-readable variant of wish or focus area property values. See also "wikitext value".
- Entity
- Refers to either a wish or a focus area. This may be considered analogous to entities on Wikidata, where wish and focus areas are types of pages that hold (semi-)structured data.
- Focus area detail page
- The page showing the full focus area details including the description – which is not the same as the "short description" shown on the focus area index page. The votes subpage is also transcluded here.
- Focus area index page
- The page that list all of the focus areas. Here only the "short descriptions" are displayed.
- Index pages
- Refers to either the wish or focus area index pages.
- Intake
- User-facing this refers to Special:WishlistIntake and related processes, but in the extension, code is also shared with Special:EditFocusArea.
- Navigation tag
- A tag that serves as a general topic classifier for an entity.
- Proposal
- A mostly legacy term that is synonymous with "wish".
- Steward tag
- A tag that identifies the code steward (such as WMF team) who is responsible for a wish, as defined by Developers/Maintainers.
- Tag
- A keyword or phrase that is used to categorize wishes. There are three types of tags: "navigation tags", "component tags" and "steward tags"
- Translation subpage
- Refers to the subpage of a wish or focus area in a specific language, such as
/fr
for French. - Votes subpage
- The
/Votes
(or as configured) subpage on which votes are stored. This applies to both wishes and focus areas. - Wikitext value
- This refers to the values of wish or focus area properties as they would appear in wikitext. They are single-word, semi-human-readable codes. Wikitext values are also what are used when working with the API. Wikitext values have an equivalent "display value" associated with them.
- Wish detail page
- The page showing the full wish details including the description and votes.
- Wish index page
- The page that lists all of the wishes.
- Wish view page
- The page showing a single wish.
- Wishlist entity
- The term that refers to either a wish or focus area.
- Beta status extensions
- Parser function extensions
- Special page extensions
- API extensions
- GPL licensed extensions
- Extensions in Wikimedia version control
- BeforeDisplayNoArticleText extensions
- BeforePageDisplay extensions
- ChangeTagsListActive extensions
- GetPreferences extensions
- LinksUpdateComplete extensions
- ListDefinedTags extensions
- LoadExtensionSchemaUpdates extensions
- LoginFormValidErrorMessages extensions
- PageDeleteComplete extensions
- ParserAfterTidy extensions
- ParserFirstCallInit extensions
- RecentChange save extensions
- RevisionDataUpdates extensions
- SkinTemplateNavigation::Universal extensions
- GetUserPermissionsErrorsExpensive extensions
- All extensions
- Extensions used on Wikimedia