Module:Authority control
Jump to navigation
Jump to search
This Lua module is used on approximately 2,000,000 pages, or roughly 127714% of all pages. To avoid major disruption and server load, any changes should be tested in the module's /sandbox or /testcases subpages, or in your own module sandbox. The tested changes can be added to this page in a single edit. Consider discussing changes on the talk page before implementing them. |
This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing. |
Related pages |
---|
This module uses one or more Wikidata properties; see § Parameters for details.
Lua error in Module:Lua_banner at line 112: attempt to index field 'edit' (a nil value). This module contains the code of the {{Authority control}} and {{Pages with authority control identifiers}} templates.
Parameters, Wikidata properties, and tracking categories
Lua error at line 378: attempt to index field 'wikibase' (a nil value).
Additional tracking categories
This module also implements the following hidden tracking categories:
- Category:Pages with red-linked authority control categories (0) – error category to identify missing categories
- Category:Articles with suppressed authority control identifiers (0) – tracking only (no error)
- Category:Pages using authority control with parameters (0) – migrate IDs to Wikidata, if possible (no error)
- Category:Pages using authority control with parameters different on Wikidata (0) – determine/remove incorrect IDs & migrate to Wikidata
- Category:Pages using authority control with parameters all matching Wikidata (0) – template parameters may safely be removed
State parameter
- Category:AC using state parameter: collapsed (0)
- Category:AC using state parameter: expanded (0)
- Category:AC using state parameter: autocollapse (0)
- Category:AC using state parameter: other (0)
See also
- m:Interwiki map – definition of global custom interwiki prefixes
require('strict')
local p = {}
local title = mw.title.getCurrentTitle()
local namespace = title.namespace
local testcases = (string.sub(title.subpageText,1,9) == 'testcases')
local function addCat(cat,sortkey)
if cat and cat ~= '' and (namespace == 0 or namespace == 14 or testcases) then
local redlinkcat = ''
if testcases == false and mw.title.new(cat, 14).exists == false then
redlinkcat = '[[Category:Pages with red-linked authority control categories]]'
end
if sortkey then
cat = '[[Category:'..cat..'|' .. sortkey .. title.text .. ']]'
else
cat = '[[Category:'..cat..']]'
end
cat = cat .. redlinkcat
return cat
else
return ''
end
end
local function getCatForId(id,faulty)
local cat = 'Articles with '
if faulty then cat = cat .. 'faulty ' end
cat = cat .. id .. ' identifiers'
return addCat(cat)
end
local function getIdsFromWikidata(qid,property)
local ids = {}
if not mw.wikibase or not qid then
return ids
end
local statements = mw.wikibase.getBestStatements(qid,property)
if statements then
for _, statement in ipairs( statements ) do
if statement.mainsnak.datavalue then
table.insert( ids, statement.mainsnak.datavalue.value )
end
end
end
return ids
end
local function makelink(conf,val,nextid,qid) --validate values and create a link
local link
if nextid==1 then
if conf.prefix then
link = '*' .. conf.prefix .. '\n**'
else
link = '*'
end
else
link = '\n**'
end
local valid_value = false
if conf.link2 then -- use function to validate and generate link
if conf.link2(val) then
link = link .. conf.link2(val)
valid_value = true
end
else
if conf.pattern then -- use pattern to determine validity if defined
valid_value = val:match(conf.pattern)
elseif conf.patterns then
for i = 1,#conf.patterns do
valid_value = val:match(conf.patterns[i])
if valid_value then break end
end
elseif conf.valid then -- otherwise use function to determine validity
valid_value = conf.valid(val)
else -- no validation possible
valid_value = val
end
if valid_value then
link = link .. '<span class="uid">'
if not conf.label or nextid>1 then
conf.label = tostring(nextid)
end
if conf.link then
valid_value = valid_value:gsub('%%', '%%%%')
link = link .. '[' .. mw.ustring.gsub(conf.link,'%$1',valid_value) .. ' ' .. conf.label .. ']'
else
link = link .. valid_value
end
link = link .. '</span>'
end
end
if valid_value then
link = link .. getCatForId(conf.category or conf[1])
else
--local preview = require("Module:If preview")
local wdlink = qid and '[[:wikidata:' .. qid .. '#P' .. conf.property .. ']]' or ''
link = link .. '[[File:345-409 Ambox warning centered.svg|20px|frameless|link=' .. wdlink ..'|The '..conf[1]..' id '..val..' is not valid.]]'
if conf.errorcat then
link = link .. addCat(conf.errorcat)
else
link = link .. getCatForId(conf.category or conf[1],true)
end
link = link .. addCat('All articles with faulty authority control information',conf[1])-- .. preview._warning({'The '..conf[1]..' id '..val..' is not valid.'})
end
return link
end
--[[==========================================================================]]
--[[ Main ]]
--[[==========================================================================]]
function p.authorityControl(frame)
local resolveEntity = require('Module:ResolveEntityId')
local function resolveQID(qid)
if qid then
qid = 'Q'..mw.ustring.gsub(qid, '^[Qq]', '')
qid = resolveEntity._id(qid) --nil if unresolvable
end
return qid
end
local config = require("Module:Authority control/config")
local conf = config.config
local parentArgs = frame:getParent().args
local iParentArgs = 0 --count original/manual parent args
local iMatches,suppressedIdCount = 0,0
local auxCats = ''
local rct = 0 -- total number of links returned
local qid
if namespace == 0 then
qid = mw.wikibase.getEntityIdForCurrentPage()
end
if not qid then
qid = resolveQID(parentArgs['qid']) --use qid parameter if no wikidata item is connected
end
local qids = {} -- setup any additional QIDs
if parentArgs.additional then
for _,v in ipairs(mw.text.split(parentArgs.additional,"%s*,%s*")) do
table.insert(qids,v)
end
end
local sections = {}
for _ = 1,#config.sectionNames + #qids do table.insert(sections,{}) end
local qslink = '' -- setup link to add using QuickStatements
-- check for suppressed identifiers
local suppress = {}
if parentArgs.suppress then
local suppresslist = mw.text.split(parentArgs.suppress,"%s*,%s*") -- split parameter by comma
for _,v in ipairs(suppresslist) do
if v:match("^%d+$") then
v = "P"..tostring(v)
else
v = string.upper(v)
end
suppress[v] = true -- index table by identifier name
end
end
local function makeSections(qid,addit)
local tval = {}
local function parameter_is_used(property)
local used = false
if property then
if tval[property] then
if tval[property][1] then
used = true
end
elseif tval[property] == false then -- property has been manually suppressed
used = true
end
end
return used
end
for _, params in ipairs(conf) do
tval[params.property] = getIdsFromWikidata(qid, 'P' .. params.property) -- setup table for values with property number as key
if addit then
if suppress["P"..tostring(params.property)] or suppress[string.upper(params[1])] then
tval[params.property] = false -- indicates the identifier is suppressed
end
else
local val = parentArgs[mw.ustring.lower(params[1])] or parentArgs[params[1]]
if suppress["P"..tostring(params.property)] or suppress[string.upper(params[1])] or val == '' then
if tval[params.property][1] and (namespace == 0 or testcases) then
suppressedIdCount = suppressedIdCount + 1
if parentArgs['arts'] ~= 'arts' then
auxCats = auxCats .. '[[Category:Articles with suppressed authority control identifiers|'..params[1]..']]'
end
end
tval[params.property] = false -- indicates the identifier is suppressed
elseif val then -- add local parameter to wikidata
iParentArgs = iParentArgs + 1
local bnew = true
for _, w in pairs(tval[params.property]) do
if val == w then
bnew = false
end
end
if bnew then -- add new value to table
if tval[params.property][1] then
auxCats = auxCats .. '[[Category:Pages using authority control with parameters different on Wikidata|'..params[1]..']]'
end
if qid then
qslink = qslink .. '%7C%7C' .. qid .. '%7CP' .. params.property .. '%7C%22' .. mw.uri.encode(val,"PATH") .. '%22%7CS143%7CQ328'
end
table.insert(tval[params.property],val)
else
iMatches = iMatches+1
end
end
end
local suppress = false
if params.suppressedbyproperty then
for _,sc in ipairs(params.suppressedbyproperty) do
if parameter_is_used(sc) then
suppress = true
end
end
end
if not tval[params.property] == false and not suppress then
local tlinks = {} -- setup table for links
local nextIdVal = 1
local row = ''
for _,val in ipairs(tval[params.property]) do
local link = makelink(params,val,nextIdVal,qid)
row = row .. link
table.insert(tlinks,link)
nextIdVal = nextIdVal + 1
end
if nextIdVal>=2 then
row = row .. '\n'
table.insert(sections[addit or params.section],row)
rct = rct + 1
end
end
end
end
local function pencil(qid)
if not qid then
return ''
end
local args = { pid = 'identifiers' } -- #target the list of identifiers
args.qid = qid
return require('Module:EditAtWikidata')._showMessage(args)
end
makeSections(qid,false)
for c = 1,#qids do
makeSections(qids[c],#config.sectionNames+c)
end
if iMatches > 0 and iMatches == iParentArgs then
auxCats = auxCats .. '[[Category:Pages using authority control with parameters all matching Wikidata]]'
end
if parentArgs['arts'] == 'arts' and suppressedIdCount > 0 then
if namespace == 0 or testcases then
local s = 's'
if suppressedIdCount == 1 then s = '' end
auxCats = auxCats .. addCat('ACArt with '..suppressedIdCount..' suppressed element'..s)
end
end
--configure Navbox
local outString = ''
if rct > 0 then -- there is at least one link to display
local Navbox = require('Module:Navbox')
local sect,lastsect = 0,0
local navboxArgs = {
name = 'Authority control',
navboxclass = 'authority-control',
bodyclass = 'hlist',
state = parentArgs.state or 'autocollapse',
navbar = 'off'
}
for c=1,#config.sectionNames+#qids do
if #sections[c] ~= 0 then -- section is non-empty
sect = sect + 1
lastsect = c
local sectname
if c <= #config.sectionNames then -- regular section
sectname = config.sectionNames[c]
else -- section from additional qid
sectname = mw.wikibase.getLabel(qids[c-#config.sectionNames]) .. pencil(qids[c-#config.sectionNames])
end
navboxArgs['group' .. c] = sectname
navboxArgs['list' .. c] = table.concat(sections[c])
end
end
local aclink = '[[Help:Authority control|Authority control]]'
if qslink ~= '' then
qslink = '<span class="qs autoconfirmed-show"> [[File:Commons to Wikidata QuickStatements.svg|20px|link=https://quickstatements.toolforge.org/#/v1=' .. qslink .. '|Add values to Wikidata.]]</span>'
end
if sect == 1 then -- special display when only one section
if lastsect == 1 or lastsect == 8 then -- no special label when only general or other IDs are present
navboxArgs['group' .. lastsect] = aclink .. pencil(qid) .. qslink
elseif lastsect <= #config.sectionNames then -- other regular section
navboxArgs['group' .. lastsect] = aclink .. ': ' .. config.sectionNames[lastsect] .. pencil(qid) .. qslink
else -- section from additional qid
navboxArgs['group' .. lastsect] = aclink .. ': ' .. navboxArgs['group' .. lastsect] .. qslink
end
else -- add title to navbox
navboxArgs.title = aclink .. pencil(qid) .. qslink
end
outString = Navbox._navbox(navboxArgs)
end
if parentArgs.state then
if namespace == 0 or testcases then
local sCat
if parentArgs.state == 'collapsed' then sCat = 'AC using state parameter: collapsed'
elseif parentArgs.state == 'expanded' then sCat = 'AC using state parameter: expanded'
elseif parentArgs.state == 'autocollapse' then sCat = 'AC using state parameter: autocollapse'
else sCat = 'AC using state parameter: other'
end
auxCats = auxCats .. addCat(sCat)
end
end
if testcases then
auxCats = mw.ustring.gsub(auxCats, '(%[%[)(Category)', '%1:%2') --for easier checking
end
--out
outString = outString..auxCats
if namespace ~= 0 then
outString = mw.ustring.gsub(outString,'(%[%[)(Category:Articles)([^%|%]]+)%|?[^%|%]]*(%]%])','%1:%2%3%4')
outString = mw.ustring.gsub(outString,'(%[%[)(Category:All articles)([^%|%]]+)%|?[^%|%]]*(%]%])','%1:%2%3%4')
end
local check = require('Module:Check for unknown parameters')._check
local sortkey
if namespace == 0 then
sortkey = '*' .. title.text
else
sortkey = title.fullText
end
local tracking = check({
['unknown']='[[Category:Pages using authority control with parameters|' .. sortkey .. ']]',
['preview']='Page using [[Template:Authority control]] with "_VALUE_", please move this to Wikidata.',
'arts', 'suppress', 'additional', 'qid', 'state'
}, parentArgs)
if namespace == 0 -- mainspace
or namespace == 14 -- category
or namespace == 2 -- user
or namespace == 118 then -- draft
outString = outString .. tracking
end
return outString
end
-- Creates a human-readable standalone wikitable version of conf, and tracking categories with page counts, for use in the documentation
function p.docConfTable(frame)
local wikiTable = '<table class="wikitable sortable">'..
'<tr><th>Code</th>'..
'<th>Identifier</th>'..
'<th data-sort-type=number>Wikidata property</th>'..
'<th>Section</th>'..
'<th>Appears as</th>'..
'<th>[[:Category:Articles with authority control information|Articles]]</th>'..
'<th>[[:Category:Articles with faulty authority control information|Faulty IDs]]</th></tr>'
local columns = 7
local lang = mw.getContentLanguage()
local a, f, P = 0, 0, 0 --cumulative sums
local config = require("Module:Authority control/config")
local getlink = require("Module:Wikidata table")._getLink
local function checkcat(category,label)
local ret='[[:Category:'..category..'|'..label..']]'
if mw.title.new(category, 14).exists == false then
ret = ret..' <span class="plainlinks" style="font-size:85%;">[['..tostring(mw.uri.fullUrl('Category:'..category,'action=edit&preload=Template:Authority_control/preload'))..' create]]</span>'
end
return ret
end
for _, conf in pairs(config.config) do
local category = conf.category or conf[1]
local articleCat = 'Articles with '..category..' identifiers'
local wpl = frame:expandTemplate{ title = 'Wikidata property link', args = { id = 'f', conf.property } }
local faultyCat = conf.errorcat or 'Articles with faulty '.. (conf.errorcat or category) ..' identifiers'
local articleCount = lang:formatNum( mw.site.stats.pagesInCategory(articleCat, 'pages') )
local faultyCount = lang:formatNum( mw.site.stats.pagesInCategory(faultyCat, 'pages') )
P = P + 1 --property count
a = a + lang:parseFormattedNumber(articleCount)
f = f + lang:parseFormattedNumber(faultyCount)
local name = mw.wikibase.getBestStatements('P'..conf.property,"P9073")
if name then
if name[1] then
name = name[1].mainsnak.datavalue.value.id
if name then
name = getlink(name)
end
else
name = false
end
end
if conf.remark then
wikiTable = wikiTable..'<tr><td rowspan=2>'
else
wikiTable = wikiTable..'<tr><td>'
end
wikiTable = wikiTable..'[['..(conf.idlink or conf[1]..' (identifier)')..'|'..conf[1]..']]</td>'
wikiTable = wikiTable..'<td>'..(name or '')..'</td>'..
'<td data-sort-value='..conf.property..'>'..wpl..'</td>'..
'<td>'..config.sectionNames[conf.section]..'</td>'..
'<td>' .. mw.getCurrentFrame():expandTemplate{title = "Hlist", args = {'\n' .. makelink(conf,conf.example,1)}} .. '\n</td>'..
'<td style="text-align: right;">'..checkcat(articleCat,articleCount)..'</td>'..
'<td style="text-align: right;">'..checkcat(faultyCat,faultyCount)..'</td></tr>'
if conf.remark then
wikiTable = wikiTable.."<tr><td colspan=" .. columns-1 .. "6>'''Remarks:''' "..conf.remark.."</td></tr>"
end
end
wikiTable = wikiTable..'<tr><th style="text-align: right;" colspan=' .. columns-3 .. '>Totals</th>'..
'<th style="text-align: right;">'..lang:formatNum(P)..'</th>'..
'<th style="text-align: right;">'..lang:formatNum(a)..'</th>'..
'<th style="text-align: right;">' .. '[[:Category:All articles with faulty authority control information|' .. lang:formatNum(f) .. ']]</th></tr></table>'
return require('Module:Suppress categories').main(wikiTable)
end
-- Local Utility Functions
local function whichTOC( frame )
-- standardize TOC behavior via {{CatAutoTOC}}
return frame:expandTemplate{ title = 'CatAutoTOC', args = { align = 'center' } }
end
-- Main/External Call for Pages with authority control identifiers
function p.autoDetect( frame )
local ac_conf = require('Module:Authority control/config').config
local rmCats = require('Module:Suppress categories').main
--For use in [[Category:Articles with faulty authority control information]], i.e. on [[Category:Articles with faulty VIAF identifiers]]
local function wpfaulty( frame, id )
for _, conf in pairs(ac_conf) do
if conf.category == id or conf[1] == id then
local outString = frame:expandTemplate{ title = 'Cat more', args = {'Wikipedia:Authority control', conf.idlink or conf[1]..' (identifier)', ':d:Property:P'..conf.property} }
.. frame:expandTemplate{ title = 'Possibly empty category' }
.. frame:expandTemplate{ title = 'Wikipedia category', args = { hidden = 'yes', tracking = 'yes' } }
.. frame:expandTemplate{ title = 'Polluted category' }
.. whichTOC( frame )
.. '\nPages in this category should only be added by [[Module:Authority control]].'
.. addCat('Articles with '..id..' identifiers')
.. addCat('Articles with faulty authority control information',id)
return outString
end
end
return ''
end
--For use in [[Category:Articles with authority control information]], i.e. on [[Category:Articles with VIAF identifiers]]
local function wp(frame,id )
for _, conf in pairs( ac_conf ) do
if conf.category == id or conf[1] == id then
local link = '[[' .. (conf.idlink or conf[1] .. ' (identifier)') .. '|' .. conf[1] .. ']]'
local outString = frame:expandTemplate{ title = 'Category explanation', args = {'articles with '..link..' identifiers.'..' Please do not add [[Wikipedia:Categorization#Subcategorization|subcategories]].'} }
.. frame:expandTemplate{ title = 'Cat more', args = {'Wikipedia:Authority control', ':d:Property:P'..conf.property} }
.. frame:expandTemplate{ title = 'Possibly empty category' }
.. frame:expandTemplate{ title = 'Wikipedia category', args = { hidden = 'yes', tracking = 'yes' } }
.. whichTOC( frame )
.. '\nPages in this category should only be added by [[Module:Authority control]].'
.. addCat('Articles with authority control information',id)
return outString
end
end
return ''
end
if namespace == 14 then --cat space
local wpfaultyID = mw.ustring.match(title.text, 'Articles with faulty ([%w%.%- ]+) identifiers')
local wpID = mw.ustring.match(title.text, 'Articles with ([%w%.%- ]+) identifiers')
if wpfaultyID then
return wpfaulty(frame,wpfaultyID)-- must be before wpID check, in case they both match
elseif wpID then
return wp(frame, wpID)-- to keep the regex simple
else
return '[[Category:Pages with authority control identifiers unknown category]]'
end
end
return ''
end
return p