*
* @par Example:
* @code
- * $wgLogoHD = array(
+ * $wgLogoHD = [
* "1.5x" => "path/to/1.5x_version.png",
* "2x" => "path/to/2x_version.png"
- * );
+ * ];
* @endcode
*
* @since 1.25
$wgEnableAsyncUploads = false;
/**
- * These are additional characters that should be replaced with '-' in filenames
+ * Additional characters that are not allowed in filenames. They are replaced with '-' when
+ * uploading. Like $wgLegalTitleChars, this is a regexp character class.
+ *
+ * Slashes and backslashes are disallowed regardless of this setting, but included here for
+ * completeness.
*/
-$wgIllegalFileChars = ":";
+$wgIllegalFileChars = ":\\/\\\\";
/**
* What directory to place deleted uploads in.
* The string 'local' signifies the default local file repository.
*
* Example:
- * $wgForeignUploadTargets = array( 'shared' );
+ * $wgForeignUploadTargets = [ 'shared' ];
*/
$wgForeignUploadTargets = [ 'local' ];
/**
* Full path on the web server where shared uploads can be found
*/
-$wgSharedUploadPath = "http://commons.wikimedia.org/shared/images";
+$wgSharedUploadPath = null;
/**
* Fetch commons image description pages and display them on the local wiki?
/**
* Path on the file system where shared uploads can be found.
*/
-$wgSharedUploadDirectory = "/var/www/wiki3/images";
+$wgSharedUploadDirectory = null;
/**
* DB name with metadata about shared directory.
*
* @par Example:
* @code
- * $wgMaxUploadSize = array(
+ * $wgMaxUploadSize = [
* '*' => 250 * 1024,
* 'url' => 500 * 1024,
- * );
+ * ];
* @endcode
* Sets the maximum for all uploads to 250 kB except for upload-by-url, which
* will have a maximum of 500 kB.
/**
* Plugins for media file type handling.
* Each entry in the array maps a MIME type to a class name
+ *
+ * Core media handlers are listed in MediaHandlerFactory,
+ * and extensions should use extension.json.
*/
-$wgMediaHandlers = [
- 'image/jpeg' => 'JpegHandler',
- 'image/png' => 'PNGHandler',
- 'image/gif' => 'GIFHandler',
- 'image/tiff' => 'TiffHandler',
- 'image/webp' => 'WebPHandler',
- 'image/x-ms-bmp' => 'BmpHandler',
- 'image/x-bmp' => 'BmpHandler',
- 'image/x-xcf' => 'XCFHandler',
- 'image/svg+xml' => 'SvgHandler', // official
- 'image/svg' => 'SvgHandler', // compat
- 'image/vnd.djvu' => 'DjVuHandler', // official
- 'image/x.djvu' => 'DjVuHandler', // compat
- 'image/x-djvu' => 'DjVuHandler', // compat
-];
+$wgMediaHandlers = [];
/**
* Plugins for page content model handling.
* @par Example:
* @code
* // PNG is lossless, but inefficient for photos
- * $wgTiffThumbnailType = array( 'png', 'image/png' );
+ * $wgTiffThumbnailType = [ 'png', 'image/png' ];
* // JPEG is good for photos, but has no transparency support. Bad for diagrams.
- * $wgTiffThumbnailType = array( 'jpg', 'image/jpeg' );
+ * $wgTiffThumbnailType = [ 'jpg', 'image/jpeg' ];
* @endcode
*/
$wgTiffThumbnailType = false;
/**
* Additional XML types we can allow via MIME-detection.
- * array = ( 'rootElement' => 'associatedMimeType' )
+ * array = [ 'rootElement' => 'associatedMimeType' ]
*/
$wgXMLMimeTypes = [
'http://www.w3.org/2000/svg:svg' => 'image/svg+xml',
* needs in order to be used as the reference for a given thumbnail. For example, with the
* following buckets:
*
- * $wgThumbnailBuckets = array ( 128, 256, 512 );
+ * $wgThumbnailBuckets = [ 128, 256, 512 ];
*
* and a distance of 50:
*
'imagesPerRow' => 0, // Default number of images per-row in the gallery. 0 -> Adapt to screensize
'imageWidth' => 120, // Width of the cells containing images in galleries (in "px")
'imageHeight' => 120, // Height of the cells containing images in galleries (in "px")
- 'captionLength' => 25, // Length of caption to truncate (in characters)
+ 'captionLength' => true, // Deprecated @since 1.28
+ // Length to truncate filename to in caption when using "showfilename".
+ // A value of 'true' will truncate the filename to one line using CSS
+ // and will be the behaviour after deprecation.
'showBytes' => true, // Show the filesize in bytes in categories
'mode' => 'traditional',
];
* Default to false or fill an array :
*
* @code
- * $wgSMTP = array(
+ * $wgSMTP = [
* 'host' => 'SMTP domain',
* 'IDHost' => 'domain for MessageID',
* 'port' => '25',
* 'auth' => [true|false],
* 'username' => [SMTP username],
* 'password' => [SMTP password],
- * );
+ * ];
* @endcode
*/
$wgSMTP = false;
/**
* Allow users to enable email notification ("enotif") when someone edits their
* user talk page.
+ *
+ * The owner of the user talk page must also have the 'enotifusertalkpages' user
+ * preference set to true.
*/
$wgEnotifUserTalk = false;
$wgEnotifRevealEditorAddress = false;
/**
- * Send notification mails on minor edits to watchlist pages. This is enabled
- * by default. User talk notifications are affected by this, $wgEnotifUserTalk, and
- * the nominornewtalk user right.
+ * Potentially send notification mails on minor edits to pages. This is enabled
+ * by default. If this is false, users will never be notified on minor edits.
+ *
+ * If it is true, editors with the 'nominornewtalk' right (typically bots) will still not
+ * trigger notifications for minor edits they make (to any page, not just user talk).
+ *
+ * Finally, if the watcher/recipient has the 'enotifminoredits' user preference set to
+ * false, they will not receive notifications for minor edits.
+ *
+ * User talk notifications are also affected by $wgEnotifMinorEdits, the above settings,
+ * $wgEnotifUserTalk, and the preference described there.
*/
$wgEnotifMinorEdits = true;
*
* Short names of ExternalStore classes may be specified in an array here:
* @code
- * $wgExternalStores = array("http","file","custom")...
+ * $wgExternalStores = [ "http","file","custom" ]...
* @endcode
*
* CAUTION: Access to database might lead to code execution
* @par Example:
* Create a cluster named 'cluster1' containing three servers:
* @code
- * $wgExternalServers = array(
- * 'cluster1' => array( 'srv28', 'srv29', 'srv30' )
- * );
+ * $wgExternalServers = [
+ * 'cluster1' => [ 'srv28', 'srv29', 'srv30' ]
+ * ];
* @endcode
*
* Used by LBFactorySimple, may be ignored if $wgLBFactoryConf is set to
*
* @par Example:
* @code
- * $wgDefaultExternalStore = array( 'DB://cluster1', 'DB://cluster2' );
+ * $wgDefaultExternalStore = [ 'DB://cluster1', 'DB://cluster2' ];
* @endcode
*
* @var array
/**
* Kept for extension compatibility; see $wgParserCacheType
- * @deprecated 1.26
+ * @deprecated since 1.26
*/
$wgEnableParserCache = true;
* @par Example configuration to send purges for upload.wikimedia.org to one
* multicast group and all other purges to another:
* @code
- * $wgHTCPRouting = array(
- * '|^https?://upload\.wikimedia\.org|' => array(
+ * $wgHTCPRouting = [
+ * '|^https?://upload\.wikimedia\.org|' => [
* 'host' => '239.128.0.113',
* 'port' => 4827,
- * ),
- * '' => array(
+ * ],
+ * '' => [
* 'host' => '239.128.0.112',
* 'port' => 4827,
- * ),
- * );
+ * ],
+ * ];
* @endcode
*
* You can also pass an array of hosts to send purges too. This is useful when
*
* @par Example of sending purges to multiple hosts:
* @code
- * $wgHTCPRouting = array(
- * '' => array(
+ * $wgHTCPRouting = [
+ * '' => [
* // Purges to text caches using multicast
- * array( 'host' => '239.128.0.114', 'port' => '4827' ),
+ * [ 'host' => '239.128.0.114', 'port' => '4827' ],
* // Purges to a hardcoded list of caches
- * array( 'host' => '10.88.66.1', 'port' => '4827' ),
- * array( 'host' => '10.88.66.2', 'port' => '4827' ),
- * array( 'host' => '10.88.66.3', 'port' => '4827' ),
- * ),
- * );
+ * [ 'host' => '10.88.66.1', 'port' => '4827' ],
+ * [ 'host' => '10.88.66.2', 'port' => '4827' ],
+ * [ 'host' => '10.88.66.3', 'port' => '4827' ],
+ * ],
+ * ];
* @endcode
*
* @since 1.22
'zh-yue' => 'yue',
];
-/**
- * Character set for use in the article edit box. Language-specific encodings
- * may be defined.
- *
- * This historic feature is one of the first that was added by former MediaWiki
- * team leader Brion Vibber, and is used to support the Esperanto x-system.
- */
-$wgEditEncoding = '';
-
/**
* Set this to true to replace Arabic presentation forms with their standard
* forms in the U+0600-U+06FF block. This only works if $wgLanguageCode is
* To allow language-specific main page and community
* portal:
* @code
- * $wgForceUIMsgAsContentMsg = array( 'mainpage', 'portal-url' );
+ * $wgForceUIMsgAsContentMsg = [ 'mainpage', 'portal-url' ];
* @endcode
*/
$wgForceUIMsgAsContentMsg = [];
*/
$wgUseMediaWikiUIEverywhere = false;
+ /**
+ * Whether to label the store-to-database-and-show-to-others button in the editor
+ * as "Save page"/"Save changes" if false (the default) or, if true, instead as
+ * "Publish page"/"Publish changes".
+ *
+ * @since 1.28
+ */
+ $wgEditButtonPublishNotSave = false;
+
/**
* Permit other namespaces in addition to the w3.org default.
*
*
* @par Example:
* @code
- * $wgResourceModules['ext.myExtension'] = array(
+ * $wgResourceModules['ext.myExtension'] = [
* 'scripts' => 'myExtension.js',
* 'styles' => 'myExtension.css',
- * 'dependencies' => array( 'jquery.cookie', 'jquery.tabIndex' ),
+ * 'dependencies' => [ 'jquery.cookie', 'jquery.tabIndex' ],
* 'localBasePath' => __DIR__,
* 'remoteExtPath' => 'MyExtension',
- * );
+ * ];
* @endcode
*/
$wgResourceModules = [];
*
* @par Example:
* @code
- * $wgResourceModules['bar'] = array(
+ * $wgResourceModules['bar'] = [
* 'scripts' => 'resources/bar/bar.js',
* 'styles' => 'resources/bar/main.css',
- * );
+ * ];
*
- * $wgResourceModuleSkinStyles['foo'] = array(
+ * $wgResourceModuleSkinStyles['foo'] = [
* 'bar' => 'skins/Foo/bar.css',
- * );
+ * ];
* @endcode
*
* This is mostly equivalent to:
*
* @par Equivalent:
* @code
- * $wgResourceModules['bar'] = array(
+ * $wgResourceModules['bar'] = [
* 'scripts' => 'resources/bar/bar.js',
* 'styles' => 'resources/bar/main.css',
- * 'skinStyles' => array(
+ * 'skinStyles' => [
* 'foo' => skins/Foo/bar.css',
- * ),
- * );
+ * ],
+ * ];
* @endcode
*
* If the module already defines its own entry in `skinStyles` for a given skin, then
*
* @par Example:
* @code
- * $wgResourceModules['bar'] = array(
+ * $wgResourceModules['bar'] = [
* 'scripts' => 'resources/bar/bar.js',
* 'styles' => 'resources/bar/basic.css',
- * 'skinStyles' => array(
- * 'default' => 'resources/bar/additional.css',
- * ),
- * );
+ * 'skinStyles' => [
+ * 'default' => 'resources/bar/additional.css',
+ * ],
+ * ];
* // Note the '+' character:
- * $wgResourceModuleSkinStyles['foo'] = array(
+ * $wgResourceModuleSkinStyles['foo'] = [
* '+bar' => 'skins/Foo/bar.css',
- * );
+ * ];
* @endcode
*
* This is mostly equivalent to:
*
* @par Equivalent:
* @code
- * $wgResourceModules['bar'] = array(
+ * $wgResourceModules['bar'] = [
* 'scripts' => 'resources/bar/bar.js',
* 'styles' => 'resources/bar/basic.css',
- * 'skinStyles' => array(
+ * 'skinStyles' => [
* 'default' => 'resources/bar/additional.css',
- * 'foo' => array(
+ * 'foo' => [
* 'resources/bar/additional.css',
* 'skins/Foo/bar.css',
- * ),
- * ),
- * );
+ * ],
+ * ],
+ * ];
* @endcode
*
* In other words, as a module author, use the `styles` list for stylesheets that may not be
*
* @par Example:
* @code
- * $wgResourceModuleSkinStyles['foo'] = array(
+ * $wgResourceModuleSkinStyles['foo'] = [
* 'bar' => 'bar.css',
* 'quux' => 'quux.css',
* 'remoteSkinPath' => 'Foo',
* 'localBasePath' => __DIR__,
- * );
+ * ];
* @endcode
*/
$wgResourceModuleSkinStyles = [];
*
* @par Example:
* @code
- * $wgResourceLoaderLESSVars = array(
+ * $wgResourceLoaderLESSVars = [
* 'baseFontSize' => '1em',
* 'smallFontSize' => '0.75em',
* 'WikimediaBlue' => '#006699',
- * );
+ * ];
* @endcode
* @since 1.22
*/
*
* @par Example:
* @code
- * $wgExtraNamespaces = array(
+ * $wgExtraNamespaces = [
* 100 => "Hilfe",
* 101 => "Hilfe_Diskussion",
* 102 => "Aide",
* 103 => "Discussion_Aide"
- * );
+ * ];
* @endcode
*
* @todo Add a note about maintenance/namespaceDupes.php
*
* @par Example:
* @code
- * $wgNamespaceAliases = array(
+ * $wgNamespaceAliases = [
* 'Wikipedian' => NS_USER,
* 'Help' => 100,
- * );
+ * ];
* @endcode
*/
$wgNamespaceAliases = [];
* @par Examples:
* @code
* $wgAllowExternalImagesFrom = 'http://127.0.0.1/';
- * $wgAllowExternalImagesFrom = array( 'http://127.0.0.1/', 'http://example.com' );
+ * $wgAllowExternalImagesFrom = [ 'http://127.0.0.1/', 'http://example.com' ];
* @endcode
*/
$wgAllowExternalImagesFrom = '';
* - RaggettInternalHHVM: Use the limited-functionality HHVM extension
* - RaggettInternalPHP: Use the PECL extension
* - RaggettExternal: Shell out to an external binary (tidyBin)
+ * - Html5Depurate: Use external Depurate service
+ * - Html5Internal: Use the built-in HTML5 balancer
*
* - tidyConfigFile: Path to configuration file for any of the Raggett drivers
* - debugComment: True to add a comment to the output with warning messages
* (or any subdomains) will not be set to rel="nofollow" regardless of the
* value of $wgNoFollowLinks. For instance:
*
- * $wgNoFollowDomainExceptions = array( 'en.wikipedia.org', 'wiktionary.org',
- * 'mediawiki.org' );
+ * $wgNoFollowDomainExceptions = [ 'en.wikipedia.org', 'wiktionary.org', 'mediawiki.org' ];
*
* This would add rel="nofollow" to links to de.wikipedia.org, but not
* en.wikipedia.org, wiktionary.org, en.wiktionary.org, us.en.wikipedia.org,
],
];
-/**
- * Disable AuthManager
- * @since 1.27
- * @deprecated since 1.27, for use during development only
- */
-$wgDisableAuthManager = false;
-
/**
* Configure AuthManager
*
*
* An advanced example:
* @code
- * $wgPasswordConfig['bcrypt-peppered'] = array(
+ * $wgPasswordConfig['bcrypt-peppered'] = [
* 'class' => 'EncryptedPassword',
* 'underlying' => 'bcrypt',
- * 'secrets' => array(),
+ * 'secrets' => [],
* 'cipher' => MCRYPT_RIJNDAEL_256,
* 'mode' => MCRYPT_MODE_CBC,
* 'cost' => 5,
- * );
+ * ];
* @endcode
*
* @since 1.24
* @par Example:
* To whitelist [[Main Page]]:
* @code
- * $wgWhitelistReadRegexp = array( "/Main Page/" );
+ * $wgWhitelistReadRegexp = [ "/Main Page/" ];
* @endcode
*
* @note Unless ^ and/or $ is specified, a regular expression might match
* @par Example:
* To allow reading any page starting with 'User' regardless of the case:
* @code
- * $wgWhitelistReadRegexp = array( "@^UsEr.*@i" );
+ * $wgWhitelistReadRegexp = [ "@^UsEr.*@i" ];
* @endcode
* Will allow both [[User is banned]] and [[User:JohnDoe]]
*
* combined with the permissions of all groups that a given user is listed
* in in the user_groups table.
*
- * Note: Don't set $wgGroupPermissions = array(); unless you know what you're
+ * Note: Don't set $wgGroupPermissions = []; unless you know what you're
* doing! This will wipe all permissions, and may mean that your users are
* unable to perform certain essential tasks or access new functionality
* when new permissions are introduced and default grants established.
$wgGroupPermissions['user']['reupload'] = true;
$wgGroupPermissions['user']['reupload-shared'] = true;
$wgGroupPermissions['user']['minoredit'] = true;
-$wgGroupPermissions['user']['purge'] = true; // can use ?action=purge without clicking "ok"
+$wgGroupPermissions['user']['purge'] = true;
$wgGroupPermissions['user']['sendemail'] = true;
$wgGroupPermissions['user']['applychangetags'] = true;
$wgGroupPermissions['user']['changetags'] = true;
* @par Example:
* To allow sysops to add themselves to the "bot" group:
* @code
- * $wgGroupsAddToSelf = array( 'sysop' => array( 'bot' ) );
+ * $wgGroupsAddToSelf = [ 'sysop' => [ 'bot' ] ];
* @endcode
*
* @par Example:
* Implicit groups may be used for the source group, for instance:
* @code
- * $wgGroupsRemoveFromSelf = array( '*' => true );
+ * $wgGroupsRemoveFromSelf = [ '*' => true ];
* @endcode
* This allows users in the '*' group (i.e. any user) to remove themselves from
* any group that they happen to be in.
* @todo Redocument $wgAutopromote
*
* The format is
- * array( '&' or '|' or '^' or '!', cond1, cond2, ... )
+ * [ '&' or '|' or '^' or '!', cond1, cond2, ... ]
* where cond1, cond2, ... are themselves conditions; *OR*
* APCOND_EMAILCONFIRMED, *OR*
- * array( APCOND_EMAILCONFIRMED ), *OR*
- * array( APCOND_EDITCOUNT, number of edits ), *OR*
- * array( APCOND_AGE, seconds since registration ), *OR*
- * array( APCOND_INGROUPS, group1, group2, ... ), *OR*
- * array( APCOND_ISIP, ip ), *OR*
- * array( APCOND_IPINRANGE, range ), *OR*
- * array( APCOND_AGE_FROM_EDIT, seconds since first edit ), *OR*
- * array( APCOND_BLOCKED ), *OR*
- * array( APCOND_ISBOT ), *OR*
+ * [ APCOND_EMAILCONFIRMED ], *OR*
+ * [ APCOND_EDITCOUNT, number of edits ], *OR*
+ * [ APCOND_AGE, seconds since registration ], *OR*
+ * [ APCOND_INGROUPS, group1, group2, ... ], *OR*
+ * [ APCOND_ISIP, ip ], *OR*
+ * [ APCOND_IPINRANGE, range ], *OR*
+ * [ APCOND_AGE_FROM_EDIT, seconds since first edit ], *OR*
+ * [ APCOND_BLOCKED ], *OR*
+ * [ APCOND_ISBOT ], *OR*
* similar constructs defined by extensions.
*
* If $wgEmailAuthentication is off, APCOND_EMAILCONFIRMED will be true for any
*
* The format is:
* @code
- * array( event => criteria, ... )
+ * [ event => criteria, ... ]
* @endcode
* Where event is either:
* - 'onEdit' (when user edits)
* @endcode
* Bureaucrats can only remove bots and sysops:
* @code
- * $wgRemoveGroups['bureaucrat'] = array( 'bot', 'sysop' );
+ * $wgRemoveGroups['bureaucrat'] = [ 'bot', 'sysop' ];
* @endcode
* Sysops can make bots:
* @code
- * $wgAddGroups['sysop'] = array( 'bot' );
+ * $wgAddGroups['sysop'] = [ 'bot' ];
* @endcode
* Sysops can disable other sysops in an emergency, and disable bots:
* @code
- * $wgRemoveGroups['sysop'] = array( 'sysop', 'bot' );
+ * $wgRemoveGroups['sysop'] = [ 'sysop', 'bot' ];
* @endcode
*/
$wgAddGroups = [];
*
* @par Example:
* @code
- * $wgDnsBlacklistUrls = array(
+ * $wgDnsBlacklistUrls = [
* // String containing URL
* 'http.dnsbl.sorbs.net.',
* // Array with URL and key, for services that require a key
- * array( 'dnsbl.httpbl.net.', 'mykey' ),
+ * [ 'dnsbl.httpbl.net.', 'mykey' ],
* // Array with just the URL. While this works, it is recommended that you
* // just use a string as shown above
- * array( 'opm.tornevall.org.' )
- * );
+ * [ 'opm.tornevall.org.' ]
+ * ];
* @endcode
*
* @note You should end the domain name with a . to avoid searching your
* @par Example:
* To set a generic maximum of 4 hits in 60 seconds:
* @code
- * $wgRateLimits = array( 4, 60 );
+ * $wgRateLimits = [ 4, 60 ];
* @endcode
*
* @par Example:
* You could also limit per action and then type of users.
* @code
- * $wgRateLimits = array(
- * 'edit' => array(
- * 'anon' => array( x, y ), // any and all anonymous edits (aggregate)
- * 'user' => array( x, y ), // each logged-in user
- * 'newbie' => array( x, y ), // each new autoconfirmed accounts; overrides 'user'
- * 'ip' => array( x, y ), // each anon and recent account
- * 'subnet' => array( x, y ), // ... within a /24 subnet in IPv4 or /64 in IPv6
- * )
- * )
+ * $wgRateLimits = [
+ * 'edit' => [
+ * 'anon' => [ x, y ], // any and all anonymous edits (aggregate)
+ * 'user' => [ x, y ], // each logged-in user
+ * 'newbie' => [ x, y ], // each new autoconfirmed accounts; overrides 'user'
+ * 'ip' => [ x, y ], // each anon and recent account
+ * 'subnet' => [ x, y ], // ... within a /24 subnet in IPv4 or /64 in IPv6
+ * ]
+ * ]
* @endcode
*
* @warning Requires that $wgMainCacheType is set to something persistent
$wgGrantPermissions['createaccount']['createaccount'] = true;
+$wgGrantPermissions['privateinfo']['viewmyprivateinfo'] = true;
+
/**
* @var Array Map of grants to their UI grouping
* @since 1.27
'createaccount' => 'administration',
'highvolume' => 'high-volume',
+
+ 'privateinfo' => 'private-information',
];
/**
*
* @par Advanced example:
* @code
- * $wgDebugLogGroups['memcached'] = array(
+ * $wgDebugLogGroups['memcached'] = [
* 'destination' => '/var/log/mediawiki/memcached.log',
* 'sample' => 1000, // log 1 message out of every 1,000.
* 'level' => \Psr\Log\LogLevel::WARNING
- * );
+ * ];
* @endcode
*/
$wgDebugLogGroups = [];
*
* @par To completely disable logging:
* @code
- * $wgMWLoggerDefaultSpi = array( 'class' => '\\MediaWiki\\Logger\\NullSpi' );
+ * $wgMWLoggerDefaultSpi = [ 'class' => '\\MediaWiki\\Logger\\NullSpi' ];
* @endcode
*
* @since 1.25
* This should be a map of namespace IDs to priority
* @par Example:
* @code
- * $wgSitemapNamespacesPriorities = array(
+ * $wgSitemapNamespacesPriorities = [
* NS_USER => '0.9',
* NS_HELP => '0.0',
- * );
+ * ];
* @endcode
*/
$wgSitemapNamespacesPriorities = false;
* The JSON-specific options are:
* * 'channel' -- if set, the 'channel' parameter is also set in JSON values.
*
- * @example $wgRCFeeds['example'] = array(
+ * @example $wgRCFeeds['example'] = [
* 'formatter' => 'JSONRCFeedFormatter',
* 'uri' => "udp://localhost:1336",
* 'add_interwiki_prefix' => false,
* 'omit_bots' => true,
- * );
- * @example $wgRCFeeds['exampleirc'] = array(
+ * ];
+ * @example $wgRCFeeds['exampleirc'] = [
* 'formatter' => 'IRCColourfulRCFeedFormatter',
* 'uri' => "udp://localhost:1338",
* 'add_interwiki_prefix' => false,
* 'omit_bots' => true,
- * );
+ * ];
* @since 1.22
*/
$wgRCFeeds = [];
*
* To register a new one:
* @code
- * $wgRecentChangesFlags['flag'] => array(
+ * $wgRecentChangesFlags['flag'] => [
* // message for the letter displayed next to rows on changes lists
* 'letter' => 'letter-msg',
* // message for the tooltip of the letter
* // will set the top-level flag if any line contains the flag, 'all' will
* // only be set if all lines contain the flag.
* 'grouping' => 'any',
- * );
+ * ];
* @endcode
*
* @since 1.22
* subprojects on the interwiki map of the target wiki, or a mix of the two,
* e.g.
* @code
- * $wgImportSources = array(
- * 'wikipedia' => array( 'cs', 'en', 'fr', 'zh' ),
+ * $wgImportSources = [
+ * 'wikipedia' => [ 'cs', 'en', 'fr', 'zh' ],
* 'wikispecies',
- * 'wikia' => array( 'animanga', 'brickipedia', 'desserts' ),
- * );
+ * 'wikia' => [ 'animanga', 'brickipedia', 'desserts' ],
+ * ];
* @endcode
*
* If you have a very complex import sources setup, you can lazy-load it using
*
* @par Complex example:
* @code
- * $wgMessagesDirs['Example'] = array(
+ * $wgMessagesDirs['Example'] = [
* __DIR__ . '/lib/ve/i18n',
* __DIR__ . '/lib/oojs-ui/i18n',
* __DIR__ . '/i18n',
- * )
+ * ]
* @endcode
* @since 1.23
*/
* All but 'name', 'path' and 'author' can be omitted.
*
* @code
- * $wgExtensionCredits[$type][] = array(
+ * $wgExtensionCredits[$type][] = [
* 'path' => __FILE__,
* 'name' => 'Example extension',
* 'namemsg' => 'exampleextension-name',
- * 'author' => array(
+ * 'author' => [
* 'Foo Barstein',
- * ),
+ * ],
* 'version' => '1.9.0',
* 'url' => 'http://example.org/example-extension/',
* 'descriptionmsg' => 'exampleextension-desc',
* 'license-name' => 'GPL-2.0+',
- * );
+ * ];
* @endcode
*
* The extensions are listed on Special:Version. This page also looks for a file
* @endcode
* - A function with some data:
* @code
- * $wgHooks['event_name'][] = array( $function, $data );
+ * $wgHooks['event_name'][] = [ $function, $data ];
* @endcode
* - A an object method:
* @code
- * $wgHooks['event_name'][] = array( $object, 'method' );
+ * $wgHooks['event_name'][] = [ $object, 'method' ];
* @endcode
* - A closure:
* @code
* Hooks that are used for outputting exceptions. Format is:
* $wgExceptionHooks[] = $funcname
* or:
- * $wgExceptionHooks[] = array( $class, $funcname )
+ * $wgExceptionHooks[] = [ $class, $funcname ]
* Hooks should return strings or false
*/
$wgExceptionHooks = [];
*
* @par Example:
* @code
- * $wgFilterLogTypes = array(
- * 'move' => true,
- * 'import' => false,
- * );
+ * $wgFilterLogTypes = [ 'move' => true, 'import' => false ];
* @endcode
*
* Will display show/hide links for the move and import logs. Move logs will be
*
* @par Example:
* @code
- * $wgNamespaceRobotPolicies = array( NS_TALK => 'noindex' );
+ * $wgNamespaceRobotPolicies = [ NS_TALK => 'noindex' ];
* @endcode
*/
$wgNamespaceRobotPolicies = [];
*
* @par Example:
* @code
- * $wgArticleRobotPolicies = array(
+ * $wgArticleRobotPolicies = [
* 'Main Page' => 'noindex,follow',
* 'User:Bob' => 'index,follow',
- * );
+ * ];
* @endcode
*
* @par Example that DOES NOT WORK because the names are not canonical text
* forms:
* @code
- * $wgArticleRobotPolicies = array(
+ * $wgArticleRobotPolicies = [
* # Underscore, not space!
* 'Main_Page' => 'noindex,follow',
* # "Project", not the actual project name!
* 'Project:X' => 'index,follow',
* # Needs to be "Abc", not "abc" (unless $wgCapitalLinks is false for that namespace)!
* 'abc' => 'noindex,nofollow'
- * );
+ * ];
* @endcode
*/
$wgArticleRobotPolicies = [];
*
* @par Example:
* @code
- * $wgExemptFromUserRobotsControl = array( NS_MAIN, NS_TALK, NS_PROJECT );
+ * $wgExemptFromUserRobotsControl = [ NS_MAIN, NS_TALK, NS_PROJECT ];
* @endcode
*/
$wgExemptFromUserRobotsControl = null;
*
* @code
* $wgAPIModules['foo'] = 'ApiFoo';
- * $wgAPIModules['bar'] = array(
+ * $wgAPIModules['bar'] = [
* 'class' => 'ApiBar',
* 'factory' => function( $main, $name ) { ... }
- * );
- * $wgAPIModules['xyzzy'] = array(
+ * ];
+ * $wgAPIModules['xyzzy'] = [
* 'class' => 'ApiXyzzy',
- * 'factory' => array( 'XyzzyFactory', 'newApiModule' )
- * );
+ * 'factory' => [ 'XyzzyFactory', 'newApiModule' ]
+ * ];
* @endcode
*
* Extension modules may override the core modules.
*
* @par Example:
* @code
- * $wgCrossSiteAJAXdomains = array(
+ * $wgCrossSiteAJAXdomains = [
* 'www.mediawiki.org',
* '*.wikipedia.org',
* '*.wikimedia.org',
* '*.wiktionary.org',
- * );
+ * ];
* @endcode
*/
$wgCrossSiteAJAXdomains = [];
* When $wgJobRunRate > 0, try to run jobs asynchronously, spawning a new process
* to handle the job execution, instead of blocking the request until the job
* execution finishes.
+ *
* @since 1.23
*/
-$wgRunJobsAsync = true;
+$wgRunJobsAsync = (
+ !function_exists( 'register_postsend_function' ) &&
+ !function_exists( 'fastcgi_finish_request' )
+);
/**
* Number of rows to update per job
/**
* Name of the external diff engine to use. Supported values:
- * * false: default PHP implementation
- * * 'wikidiff2': Wikimedia's fast difference engine implemented as a PHP/HHVM module
- * * 'wikidiff' and 'wikidiff3' are treated as false for backwards compatibility
- * * any other string is treated as a path to external diff executable
+ * * string: path to an external diff executable
+ * * false: wikidiff2 PHP/HHVM module if installed, otherwise the default PHP implementation
+ * * 'wikidiff', 'wikidiff2', and 'wikidiff3' are treated as false for backwards compatibility
*/
$wgExternalDiffEngine = false;
*
* @par Example:
* @code
- * $wgPoolCounterConf = array( 'ArticleView' => array(
+ * $wgPoolCounterConf = [ 'ArticleView' => [
* 'class' => 'PoolCounter_Client',
* 'timeout' => 15, // wait timeout in seconds
* 'workers' => 5, // maximum number of active threads in each pool
* 'maxqueue' => 50, // maximum number of total threads in each pool
* ... any extension-specific options...
- * );
+ * ];
* @endcode
*/
$wgPoolCounterConf = null;
CONTENT_MODEL_CSS, // Make categories etc work, people put them into comments.
];
-/**
- * Whether the user must enter their password to change their e-mail address
- *
- * @since 1.20
- */
-$wgRequirePasswordforEmailChange = true;
-
/**
* Register handlers for specific types of sites.
*
*
* Example config for Parsoid:
*
- * $wgVirtualRestConfig['modules']['parsoid'] = array(
+ * $wgVirtualRestConfig['modules']['parsoid'] = [
* 'url' => 'http://localhost:8000',
* 'prefix' => 'enwiki',
* 'domain' => 'en.wikipedia.org',
- * );
+ * ];
*
* @var array
* @since 1.25
]
];
+/**
+ * Share data about this installation with MediaWiki developers
+ *
+ * When set to true, MediaWiki will periodically ping https://www.mediawiki.org/ with basic
+ * data about this MediaWiki instance. This data includes, for example, the type of system,
+ * PHP version, and chosen database backend. The Wikimedia Foundation shares this data with
+ * MediaWiki developers to help guide future development efforts.
+ *
+ * For details about what data is sent, see: https://www.mediawiki.org/wiki/Manual:$wgPingback
+ *
+ * @var bool
+ * @since 1.28
+ */
+$wgPingback = false;
+
/**
* For really cool vim folding this needs to be at the end:
* vim: foldmarker=@{,@} foldmethod=marker
* @file
*/
+use MediaWiki\Logger\LoggerFactory;
+
/**
* The edit page/HTML interface (split from Article)
* The actual database and text munging is still in Article,
/** @var bool */
public $tooBig = false;
- /** @var bool */
- public $kblength = false;
-
/** @var bool */
public $missingComment = false;
/** @var bool */
protected $edit;
+ /** @var bool|int */
+ protected $contentLength = false;
+
/**
* @var bool Set in ApiEditPage, based on ContentHandler::allowsDirectApiEditing
*/
return $handler->makeEmptyContent();
} else {
- # nasty side-effect, but needed for consistency
- $this->contentModel = $rev->getContentModel();
- $this->contentFormat = $rev->getContentFormat();
+ // Content models should always be the same since we error
+ // out if they are different before this point.
+ $logger = LoggerFactory::getInstance( 'editpage' );
+ if ( $this->contentModel !== $rev->getContentModel() ) {
+ $logger->warning( "Overriding content model from current edit {prev} to {new}", [
+ 'prev' => $this->contentModel,
+ 'new' => $rev->getContentModel(),
+ 'title' => $this->getTitle()->getPrefixedDBkey(),
+ 'method' => __METHOD__
+ ] );
+ $this->contentModel = $rev->getContentModel();
+ }
+
+ // Given that the content models should match, the current selected
+ // format should be supported.
+ if ( !$content->isSupportedFormat( $this->contentFormat ) ) {
+ $logger->warning( "Current revision content format unsupported. Overriding {prev} to {new}", [
+
+ 'prev' => $this->contentFormat,
+ 'new' => $rev->getContentFormat(),
+ 'title' => $this->getTitle()->getPrefixedDBkey(),
+ 'method' => __METHOD__
+ ] );
+ $this->contentFormat = $rev->getContentFormat();
+ }
return $content;
}
return $this->mPreloadContent;
}
- $handler = ContentHandler::getForTitle( $this->getTitle() );
+ $handler = ContentHandler::getForModelID( $this->contentModel );
if ( $preload === '' ) {
return $handler->makeEmptyContent();
case self::AS_CANNOT_USE_CUSTOM_MODEL:
case self::AS_PARSE_ERROR:
- $wgOut->addWikiText( '<div class="error">' . $status->getWikiText() . '</div>' );
+ $wgOut->addWikiText( '<div class="error">' . "\n" . $status->getWikiText() . '</div>' );
return true;
case self::AS_SUCCESS_NEW_ARTICLE:
// is if an extension hook aborted from inside ArticleSave.
// Render the status object into $this->hookError
// FIXME this sucks, we should just use the Status object throughout
- $this->hookError = '<div class="error">' . $status->getWikiText() .
+ $this->hookError = '<div class="error">' ."\n" . $status->getWikiText() .
'</div>';
return true;
}
return $status;
}
- $this->kblength = (int)( strlen( $this->textbox1 ) / 1024 );
- if ( $this->kblength > $wgMaxArticleSize ) {
+ $this->contentLength = strlen( $this->textbox1 );
+ if ( $this->contentLength > $wgMaxArticleSize * 1024 ) {
// Error will be displayed by showEditForm()
$this->tooBig = true;
$status->setResult( false, self::AS_CONTENT_TOO_BIG );
}
// Check for length errors again now that the section is merged in
- $this->kblength = (int)( strlen( $this->toEditText( $content ) ) / 1024 );
- if ( $this->kblength > $wgMaxArticleSize ) {
+ $this->contentLength = strlen( $this->toEditText( $content ) );
+ if ( $this->contentLength > $wgMaxArticleSize * 1024 ) {
$this->tooBig = true;
$status->setResult( false, self::AS_MAX_ARTICLE_SIZE_EXCEEDED );
return $status;
$wgOut->addHTML( Html::rawElement( 'div', [ 'class' => 'hiddencats' ],
Linker::formatHiddenCategories( $this->page->getHiddenCategories() ) ) );
- $wgOut->addHTML( Html::rawElement( 'div', [ 'class' => 'limitreport' ],
- self::getPreviewLimitReport( $this->mParserOutput ) ) );
+ if ( $this->mParserOutput ) {
+ $wgOut->setLimitReportData( $this->mParserOutput->getLimitReportData() );
+ }
$wgOut->addModules( 'mediawiki.action.edit.collapsibleFooter' );
);
}
if ( $this->getTitle()->isSubpageOf( $wgUser->getUserPage() ) ) {
+ $wgOut->wrapWikiMsg( '<div class="mw-usercssjspublic">$1</div>',
+ $this->isCssSubpage ? 'usercssispublic' : 'userjsispublic'
+ );
if ( $this->formtype !== 'preview' ) {
if ( $this->isCssSubpage && $wgAllowUserCss ) {
$wgOut->wrapWikiMsg(
'wrap' => "<div class=\"mw-titleprotectedwarning\">\n$1</div>" ] );
}
- if ( $this->kblength === false ) {
- $this->kblength = (int)( strlen( $this->textbox1 ) / 1024 );
+ if ( $this->contentLength === false ) {
+ $this->contentLength = strlen( $this->textbox1 );
}
- if ( $this->tooBig || $this->kblength > $wgMaxArticleSize ) {
+ if ( $this->tooBig || $this->contentLength > $wgMaxArticleSize * 1024 ) {
$wgOut->wrapWikiMsg( "<div class='error' id='mw-edit-longpageerror'>\n$1\n</div>",
[
'longpageerror',
- $wgLang->formatNum( $this->kblength ),
+ $wgLang->formatNum( round( $this->contentLength / 1024, 3 ) ),
$wgLang->formatNum( $wgMaxArticleSize )
]
);
* @param string $summary The text of the summary to display
*/
protected function showSummaryInput( $isSubjectPreview, $summary = "" ) {
- global $wgOut, $wgContLang;
+ global $wgOut;
# Add a class if 'missingsummary' is triggered to allow styling of the summary line
$summaryClass = $this->missingSummary ? 'mw-summarymissed' : 'mw-summary';
if ( $isSubjectPreview ) {
return;
}
}
- $summary = $wgContLang->recodeForEdit( $summary );
$labelText = wfMessage( $isSubjectPreview ? 'subject' : 'summary' )->parse();
list( $label, $input ) = $this->getSummaryInput(
$summary,
return '';
}
- $limitReport = Html::rawElement( 'div', [ 'class' => 'mw-limitReportExplanation' ],
- wfMessage( 'limitreport-title' )->parseAsBlock()
+ return ResourceLoader::makeInlineScript(
+ ResourceLoader::makeConfigSetScript(
+ [ 'wgPageParseReport' => $output->getLimitReportData() ],
+ true
+ )
);
-
- // Show/hide animation doesn't work correctly on a table, so wrap it in a div.
- $limitReport .= Html::openElement( 'div', [ 'class' => 'preview-limit-report-wrapper' ] );
-
- $limitReport .= Html::openElement( 'table', [
- 'class' => 'preview-limit-report wikitable'
- ] ) .
- Html::openElement( 'tbody' );
-
- foreach ( $output->getLimitReportData() as $key => $value ) {
- if ( Hooks::run( 'ParserLimitReportFormat',
- [ $key, &$value, &$limitReport, true, true ]
- ) ) {
- $keyMsg = wfMessage( $key );
- $valueMsg = wfMessage( [ "$key-value-html", "$key-value" ] );
- if ( !$valueMsg->exists() ) {
- $valueMsg = new RawMessage( '$1' );
- }
- if ( !$keyMsg->isDisabled() && !$valueMsg->isDisabled() ) {
- $limitReport .= Html::openElement( 'tr' ) .
- Html::rawElement( 'th', null, $keyMsg->parse() ) .
- Html::rawElement( 'td', null, $valueMsg->params( $value )->parse() ) .
- Html::closeElement( 'tr' );
- }
- }
- }
-
- $limitReport .= Html::closeElement( 'tbody' ) .
- Html::closeElement( 'table' ) .
- Html::closeElement( 'div' );
-
- return $limitReport;
}
protected function showStandardInputs( &$tabindex = 2 ) {
if ( Hooks::run( 'EditPageBeforeConflictDiff', [ &$this, &$wgOut ] ) ) {
$stats = $wgOut->getContext()->getStats();
$stats->increment( 'edit.failures.conflict' );
- if ( $this->mTitle->isTalkPage() ) {
- $stats->increment( 'edit.failures.conflict.byType.talk' );
- } else {
- $stats->increment( 'edit.failures.conflict.byType.subject' );
- }
- if ( $this->mTitle->getNamespace() === NS_PROJECT ) {
- $stats->increment( 'edit.failures.conflict.byNamespace.project' );
+ // Only include 'standard' namespaces to avoid creating unknown numbers of statsd metrics
+ if (
+ $this->mTitle->getNamespace() >= NS_MAIN &&
+ $this->mTitle->getNamespace() <= NS_CATEGORY_TALK
+ ) {
+ $stats->increment( 'edit.failures.conflict.byNamespaceId.' . $this->mTitle->getNamespace() );
}
$wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourdiff" );
* @return string
*/
function getPreviewText() {
- global $wgOut, $wgUser, $wgRawHtml, $wgLang;
+ global $wgOut, $wgRawHtml, $wgLang;
global $wgAllowUserCss, $wgAllowUserJs;
$stats = $wgOut->getContext()->getStats();
$note = wfMessage( 'previewnote' )->plain() . ' ' . $continueEditing;
}
- $parserOptions = $this->page->makeParserOptions( $this->mArticle->getContext() );
- $parserOptions->setIsPreview( true );
- $parserOptions->setIsSectionPreview( !is_null( $this->section ) && $this->section !== '' );
-
# don't parse non-wikitext pages, show message about preview
if ( $this->mTitle->isCssJsSubpage() || $this->mTitle->isCssOrJsPage() ) {
if ( $this->mTitle->isCssJsSubpage() ) {
ContentHandler::runLegacyHooks( 'EditPageGetPreviewText', $hook_args );
Hooks::run( 'EditPageGetPreviewContent', $hook_args );
- $parserOptions->enableLimitReport();
-
- # For CSS/JS pages, we should have called the ShowRawCssJs hook here.
- # But it's now deprecated, so never mind
-
- $pstContent = $content->preSaveTransform( $this->mTitle, $wgUser, $parserOptions );
- $scopedCallback = $parserOptions->setupFakeRevision(
- $this->mTitle, $pstContent, $wgUser );
- $parserOutput = $pstContent->getParserOutput( $this->mTitle, null, $parserOptions );
-
- $parserOutput->setEditSectionTokens( false ); // no section edit links
- $previewHTML = $parserOutput->getText();
+ $parserResult = $this->doPreviewParse( $content );
+ $parserOutput = $parserResult['parserOutput'];
+ $previewHTML = $parserResult['html'];
$this->mParserOutput = $parserOutput;
$wgOut->addParserOutputMetadata( $parserOutput );
$note .= "\n\n" . implode( "\n\n", $parserOutput->getWarnings() );
}
- ScopedCallback::consume( $scopedCallback );
} catch ( MWContentSerializationException $ex ) {
$m = wfMessage(
'content-failed-to-parse',
return $previewhead . $previewHTML . $this->previewTextAfterContent;
}
+ /**
+ * Get parser options for a preview
+ * @return ParserOptions
+ */
+ protected function getPreviewParserOptions() {
+ $parserOptions = $this->page->makeParserOptions( $this->mArticle->getContext() );
+ $parserOptions->setIsPreview( true );
+ $parserOptions->setIsSectionPreview( !is_null( $this->section ) && $this->section !== '' );
+ $parserOptions->enableLimitReport();
+ return $parserOptions;
+ }
+
+ /**
+ * Parse the page for a preview. Subclasses may override this class, in order
+ * to parse with different options, or to otherwise modify the preview HTML.
+ *
+ * @param Content @content The page content
+ * @return Associative array with keys:
+ * - parserOutput: The ParserOutput object
+ * - html: The HTML to be displayed
+ */
+ protected function doPreviewParse( Content $content ) {
+ global $wgUser;
+ $parserOptions = $this->getPreviewParserOptions();
+ $pstContent = $content->preSaveTransform( $this->mTitle, $wgUser, $parserOptions );
+ $scopedCallback = $parserOptions->setupFakeRevision(
+ $this->mTitle, $pstContent, $wgUser );
+ $parserOutput = $pstContent->getParserOutput( $this->mTitle, null, $parserOptions );
+ ScopedCallback::consume( $scopedCallback );
+ $parserOutput->setEditSectionTokens( false ); // no section edit links
+ return [
+ 'parserOutput' => $parserOutput,
+ 'html' => $parserOutput->getText() ];
+ }
+
/**
* @return array
*/
public function getEditButtons( &$tabindex ) {
$buttons = [];
- $buttonLabelKey = $this->isNew ? 'savearticle' : 'savechanges';
+ $labelAsPublish = $this->mArticle->getContext()->getConfig()->get( 'EditButtonPublishNotSave' );
+ if ( $labelAsPublish ) {
+ $buttonLabelKey = $this->isNew ? 'publishpage' : 'publishchanges';
+ } else {
+ $buttonLabelKey = $this->isNew ? 'savearticle' : 'savechanges';
+ }
$buttonLabel = wfMessage( $buttonLabelKey )->text();
$attribs = [
'id' => 'wpSave',
* @return string
*/
protected function safeUnicodeOutput( $text ) {
- global $wgContLang;
- $codedText = $wgContLang->recodeForEdit( $text );
return $this->checkUnicodeCompliantBrowser()
- ? $codedText
- : $this->makeSafe( $codedText );
+ ? $text
+ : $this->makesafe( $text );
}
/**