NonincludableNamespaces

From TestWiki
Jump to: navigation, search
This extension is not currently installed on this wiki.
MediaWiki logo.png
This extension is also documented at
Extension:NonincludableNamespaces
on MediaWiki.org.

If the pages are not in sync. then this version on my test wiki is always the most up-to-date.

This extension is designed to emulate and extend the function of the $wgNonincludableNamespaces configuration variable, which was introduced in MediaWiki v1.10.0.

  • In versions of MW < 1.10.0, it emulates the functionality of the config variable, along with the additional functionality detailed below.
  • In versions of MW >= 1.10.0 there is already code to handle this variable correctly, but the extension adds a couple of short-cuts that make configuration a bit simpler.

Usage[edit]

This extension adds the full functionality of $wgNonincludableNamespaces, plus the enhancements below, to versions of MediaWiki < 1.10.0. From 1.10.0 upwards, $wgNonincludableNamespaces exists natively in the software, in which case the extension simply implements the additional features.

Emulated features[edit]

  • If $wgNonincludableNamespaces is not set, then all transclusion is allowed.
  • If $wgNonincludableNamespaces is an array then transclusion is not allowed for any namespaces included in the array. Elements must be numeric namespace ids.

Additional features[edit]

  • If $wgNonincludableNamespaces is not an array then it is evaluated as a boolean with the following results:
    • If True then no transclusion is allowed, except from the template namespace.
    • If False then no transclusion is allowed at all.

Developers[edit]

The extension defines the constant NIN_Installed when it is loaded, so extension developers can check whether the $wgNonincludableNamespaces variable is supported, either via MW or this extension, by using the following code:

if ( version_compare($wgVersion, '1.10.0', '>=') || NIN_Installed ) {
	// Installed
}

Source[edit]

Copy the source code to a file called NonincludableNamespaces.php in your extensions directory, and add the following line to the bottom of your LocalSettings.php file:

include_once("extensions/NonincludableNamespaces.php");

You may then use the variable $wgNonincludableNamespaces to configure your wiki, as described above.

Live sourcecode viewer: NonincludableNamespaces.php
Last modified: 2024-06-11 04:19:38

<?php
if (!defined('MEDIAWIKI'))
	die("MediaWiki extensions cannot be run directly.");
/**
 * An extension to emulate (and slightly extend) the functionality of
 * $wgNonincludableNamespaces.
 *
 * @author Mark Clements <mclements at kennel17 dot co dot uk>
 * @copyright Copyright © 2007-2024, Mark Clements
 * @license http://creativecommons.org/licenses/by-sa/2.5/ cc-by-sa 2.5 or later
 * @version $Rev: 2439 $
 */
 
// The $wgVersion global variable was deprecated in MW 1.35, in favour of a new
// constant.  All code should use the constant rather than the variable, but for
// backwards compatibility we create the constant if it is not already defined.
// Note that the constant was back-ported to other release branches, but was not
// present in the *.0 release, so they do not affect the minimum version requirements
// for removing this shim.
// @back-compat MW < 1.35
	if (!defined("MW_VERSION"))
		define("MW_VERSION", $wgVersion);
 
// Set version number from SVN revision tag.
	$pMCExt_Version = '$Rev: 2439 $';
	$pMCExt_Version = substr($pMCExt_Version, 6, -2);
// Set description depending on MW version in use.
	$pNIN_Description = '[http://www.mediawiki.org/wiki/Manual'
					  . ':$wgNonincludableNamespaces $wgNonincludableNamespaces]';
	if (version_compare(MW_VERSION, '1.10.0', '<')) {
		$pNIN_Description = 'Emulates (and extends) ' . $pNIN_Description
						  . ' for MW < 1.10.0';
	}
	else {
		$pNIN_Description = 'Makes configuration of ' . $pNIN_Description
						  . ' easier for a few common situations';
	}
 
// Setup extension credits
	$wgExtensionCredits['other'][] = array(
		'name' => "NonincludableNamespaces",
		'version' => "r" . $pMCExt_Version,
		'author' => "Mark Clements",
		'description' => $pNIN_Description,
		'url' => "http://www.mediawiki.org/wiki/User_talk:HappyDog",
	);
 
// Tidy up global variable.
	unset($pMCExt_Version);
	unset($pNIN_Description);
 
	$wgExtensionFunctions[] = "wfNIN_Setup";
 
/*
	Emulates the functionality of $wgNonincludableNamespaces:
	(http://www.mediawiki.org/wiki/Manual:%24wgNonincludableNamespaces)
 
	* If $wgNonincludableNamespaces is not set, then all transclusion is allowed.
	* If $wgNonincludableNamespaces is an array then transclusion is not allowed for
	  any namespaces included in the array.  Elements must be numeric namespace ids.
 
	...with a few additional features:
	* If $wgNonincludableNamespaces is not an array, then it is evaluated as a
	  boolean, with the following results:
		* IF TRUE then NO transclusion is allowed, except from the template
		  namespace.
		* IF FALSE then NO transclusion is allowed at all.
 
	This extension adds the full functionality of $wgNonincludableNamespaces,
	including the above enhancements to versions of MediaWiki < 1.10.0.  From 1.10.0
	upwards, $wgNonincludableNamespaces exists natively in the software, in which
	case the extension simply implements the additional features described above.
 
*/
 
/////////////////////////////////////////////////
 
define("NIN_Installed", true);
 
/////////////////////////////////////////////////
 
	function wfNIN_Setup() {
		global $wgNonincludableNamespaces;
		global $wgCanonicalNamespaceNames;
 
	//////// TIDY INPUT
	// Check value of $wgNonincludableNamespaces and adjust it so it contains a
	// valid array.
	// * If not set, or False, convert to empty array.
	// * If True, convert
	// all Namespace IDs that should not be transcludable (or an empty array, if all
	// are transcludable).
 
	// NOT SET 			-> No namespaces disallowed.
		if (!isset($wgNonincludableNamespaces)) {
			$wgNonincludableNamespaces = array();
		}
 
	// ARRAY 			-> Array of namespaces IDs that are blocked from
	//					   transclusion.  No modification necessary.
		elseif (is_array($wgNonincludableNamespaces)) {
			// Drop through
		}
 
	// NON-ARRAY			-> Evaluate as a boolean and block all namespaces (or
	//						   all but template namespace).
		else {
		// If $wgNonincludableNamespaces is true then pages in the template namespace
		// may be included, otherwise they are blocked from inclusion.
			if ($wgNonincludableNamespaces == true)
				$AllowTemplateInclusion = true;
			else
				$AllowTemplateInclusion = false;
 
		// Main namespace is not in CanonicalNamespaceNames, as it has no name, so
		// add it manually here.
			$wgNonincludableNamespaces = array(NS_MAIN);
 
		// Then add all defined namespaces (except the Template namespace if true).
		// This includes any namespaces specified in $wgExtraNamespaces.
			foreach ($wgCanonicalNamespaceNames as $NS_ID => $NS_Name) {
			// If $AllowTemplateInclusion is true then we don't include the template
			// namespace in the array.
				if (!($AllowTemplateInclusion && $NS_ID == NS_TEMPLATE)) {
					$wgNonincludableNamespaces[] = $NS_ID;
				}
			}
		}
 
	//
	//////// END TIDY INPUT
 
	// If version is < 1.10.0 (and there are any namespaces that need blocking)
	// we need to add a handler to deal with the above settings.
	// @back-compat MW < 1.10
		if (version_compare(MW_VERSION, '1.10.0', '<')) {
			if (count($wgNonincludableNamespaces) > 0)
				$wgHooks['ParserAfterStrip'][] = "wfNIN_NonincludableNamespaces";
		}
 
	// MW 1.10 and above will automatically handle the above settings appropriately.
	}
 
/////////////////////////////////////////////////
 
// wfNIN_NonincludableNamespaces()
// Callback hook for the ParserAfterStrip tag, to prevent inclusion from
// non-includable namespaces on MediaWiki < 1.10.
// This function is not called on MW 1.10 and above, as the functionality is now
// built-in to MediaWiki.
// @back-compat MW < 1.10
	function wfNIN_NonincludableNamespaces(&$Parser, &$Text, &$StripState) {
		global $wgNonincludableNamespaces;
		global $wgContLang, $wgCanonicalNamespaceNames;
 
		$BlockedNamespaces = array();
		$LocalNamespaces = $wgContLang->getNamespaces();
 
	// Build list of blocked namespaces.
		foreach ($wgNonincludableNamespaces as $NS_ID) {
 
		// Add the 'no prefix' option for the template namespace (as well as the
		// actual namespace name(s), which are added below).
			if ($NS_ID == NS_TEMPLATE)
				$BlockedNamespaces[] = "";
 
		// For the main namespace, there is no name so we just add the colon.
			if ($NS_ID == NS_MAIN)
				$BlockedNamespaces[] = ":";
		// For all other namespaces, we add the canonical (English) name which works
		// on all wikis, plus the localised name (if different).
			else {
				if (isset($wgCanonicalNamespaceNames[$NS_ID]))
					$BlockedNamespaces[] = $wgCanonicalNamespaceNames[$NS_ID] . ":";
				if (isset($LocalNamespaces[$NS_ID])
					&& $LocalNamespaces[$NS_ID]
						!= $wgCanonicalNamespaceNames[$NS_ID])
				{
					$BlockedNamespaces[] = $LocalNamespaces[$NS_ID] . ":";
				}
			}
		}
 
	// For each blocked namespace, filter out all transclusions of that namespace.
		foreach ($BlockedNamespaces as $NS_Name) {
		// 0 - Entire matched text (from one char before start of template tag to
		//	   end of content).
		// 1 - Character before start of template tag (or blank if at start of
		//	   content).
		// 2 - Namespace (including colon)
		// 3 - Page name
		// 4 - Remainder of page content - to be checked to find correct closing tag.
			$Regex = '/(^|[^{])\{\{(' . $NS_Name . ')([^|}]+)(.*)/is';
			$SearchText = $Text;
 
		// Match all transclusions of this namespace ($Matches[2] is namespace,
		// $Matches[3] is page).
			while (preg_match($Regex, $SearchText, $Matches)) {
			// Build the Link that will be used to replace the template parameter.
				$Link = $Matches[3];
				if ($Matches[2] == "")
					$Link = $wgContLang->getNsText(NS_TEMPLATE);
				elseif ($Matches[2] != ":")
					$Link = $Matches[2] . $Link;
				$Link = "[[" . $Link . "]]";
 
			// Work out the BadTemplateCode that will be replaced by the above link.
				$Pos = 0;
			// This is an array of tags that need to be closed, which is used like a
			// stack.  Whenever an opening tag is found it is unshift()ed onto the
			// front of the array, and whenever a closing tag is matched, it is
			// shift()ed off again.  This ensures that template calls that include
			// templates/special parameters/parser functions, etc. as parameters are
			// properly replaced.
				$TagsToMatch = array("}}");
				$BadTemplateCode = "";
				$Source = $Matches[4];
 
				while (($NextClosePos = strpos($Source, $TagsToMatch[0], $Pos))
							!== false)
				{
					$NextOpenPos = strpos($Source, "{{{", $Pos);
					if ($NextOpenPos !== false && $NextOpenPos < $NextClosePos) {
						array_unshift($TagsToMatch, "}}}");
						$Pos = $NextOpenPos + 3;
						continue;
					}
					$NextOpenPos = strpos($Source, "{{", $Pos);
					if ($NextOpenPos !== false && $NextOpenPos < $NextClosePos) {
						array_unshift($TagsToMatch, "}}");
						$Pos = $NextOpenPos + 2;
						continue;
					}
				// If no opening tags before the matching close tag, remove it from
				// the array and update the Pos to search from.
					$Pos = $NextClosePos + strlen($TagsToMatch[0]);
					array_shift($TagsToMatch);
 
				// If no more tags, then we can exit the loop.
					if (count($TagsToMatch) == 0)
						break;
				}
 
				$BadTemplateCode = substr($Source, 0, $Pos);
 
			// Only replace code if all tags are closed, otherwise this is an invalid
			// template inclusion and the software will ignore it automatically.
				if ($BadTemplateCode != "") {
					$BadTemplateCode = "{{" . $Matches[2] . $Matches[3]
									 . $BadTemplateCode;
					$Text = str_replace($BadTemplateCode, $Link, $Text);
				}
 
			// Only search in the remainder of the text.  This wouldn't be needed if
			// we could guarantee that all tags were closed, but as we can't we only
			// search the remainder to avoid getting into an infinite loop.
				$SearchText = $Source;
			}
		}
 
		return true;
	}