- Config
- API
- Reconciliation
- Tips
If all your edits are made on the same Wikibase instance with the same credentials, simply pass it all at initialization
import WBEdit from 'wikibase-edit'
const generalConfig = {
// A Wikibase instance is required
instance: 'https://www.wikidata.org',
// The instance script path, used to find the API endpoint
// Default: /w
wgScriptPath: '/w',
// One authorization mean is required (unless in anonymous mode, see below)
credentials: {
// either a username and password
username: 'my-wikidata-username',
// Optional: generate a dedicated password with tailored rights on /wiki/Special:BotPasswords
// See the 'Credentials' paragraph below
password: 'my-wikidata-password',
// OR OAuth tokens
oauth: {
// Obtained at registration
// https://www.mediawiki.org/wiki/OAuth/For_Developers#Registration
consumer_key: 'your-consumer-token',
consumer_secret: 'your-secret-token',
// Obtained when the user authorized your service
// see https://www.mediawiki.org/wiki/OAuth/For_Developers#Authorization
token: 'a-user-token',
token_secret: 'a-secret-token'
}
},
// Flag to activate the 'anonymous' mode,
// which actually isn't anonymous as it signs with your IP
// Default: false
anonymous: true,
// Optional
// See https://meta.wikimedia.org/wiki/Help:Edit_summary
// Default: empty
summary: 'some edit summary common to all the edits',
// See https://www.mediawiki.org/wiki/Manual:Tags
// Default: on Wikidata [ 'WikibaseJS-edit' ], empty for other Wikibase instances
tags: [ 'Some general tag' ],
// Default: `wikidata-edit/${pkg.version} (https://github.com/maxlath/wikidata-edit)`
userAgent: 'my-project-name/v3.2.5 (https://project.website)',
// See https://www.mediawiki.org/wiki/Manual:Bots
// Default: false
bot: true,
// See https://www.mediawiki.org/wiki/Manual:Maxlag_parameter
// Default: 5
maxlag: 2
}
const wbEdit = WBEdit(generalConfig)
wbEdit.label.set({ id, language, value })
So if you have a local Wikibase instance installed via wikibase-docker
with the default settings, that would look something like:
import WBEdit from 'wikibase-edit'
const generalConfig = {
instance: 'http://localhost:8181',
credentials: {
username: 'WikibaseAdmin',
password: 'WikibaseDockerAdminPass'
}
}
const wbEdit = WBEdit(generalConfig)
If you make requests to different Wikibase instances or with different credentials (typically when using different users OAuth keys), you can pass those specific configuration parameter per function call:
import WBEdit from 'wikibase-edit'
const generalConfig = { userAgent }
const wbEdit = WBEdit(generalConfig)
const requestConfig = {
instance: 'https://project-915215.wikibase.farm',
credentials: {
// Either a username and password
username,
password,
// OR
oauth
},
// Default: false
anonymous: false,
// See https://www.mediawiki.org/wiki/Manual:Bots
// Default: false
bot: true,
// See https://meta.wikimedia.org/wiki/Help:Edit_summary
// Default: empty
summary: 'some request specific edit summary',
// An id for the last known revision that can be passed per request so that the server can detect edit collisions
// That id can be found in any edit response as `lastrevid`
// See https://www.mediawiki.org/wiki/Wikibase/API#Request_Format
baserevid: 1234,
// See https://www.mediawiki.org/wiki/Manual:Tags
// Default: on Wikidata [ 'WikibaseJS-edit' ], empty for other Wikibase instances
tags: [ 'Some edit specific tag' ],
// See https://www.mediawiki.org/wiki/Manual:Maxlag_parameter
// Default: 5
maxlag: 5
}
wbEdit.label.set({ id, language, value }, requestConfig)
Rules:
- All parameters can either be set in
generalConfig
orrequestConfig
Different options are available to authentify your requests as a single user. (That's typically what you need unless you are building a web service where multiple users would be making edits in their name. If you are building this kind of web service, see Multi-user setup).
- That's the least secured way to do it but perfectly fine for prototyping on your local Wikibase instance
⚠️ This method is using theAPI:Login
endpoint, which has been deprecated for a while: for a safer and more long term solution, prefer using an Owner-only OAuth consumer (see below)- Your config object would then look something like:
const generalConfig = { instance: 'http://localhost:8181', credentials: { username: 'TestWikibaseUser', password: 'TestWikibaseUserPassword' } }
- Any user (not just bot accounts despite the name) can generate passwords with restricted rights. Recommanded grants:
Edit existing pages
Delete pages, revisions, and log entries
(Optional, required bywbEdit.entity.delete
)
⚠️ This method is also using theAPI:Login
endpoint, which has been deprecated for a while: for a more long term solution, prefer using an Owner-only OAuth consumer (see below)- Your config object would then look something like:
const generalConfig = { instance: 'https://www.somewikibase.instance', credentials: { username: 'MyUsername', password: 'password_name@jkvbxgq9xiu16yb8vgzjp4gtd6m258os' } }
- Can be created without the validation of an administrator on
/wiki/Special:OAuthConsumerRegistration/propose?wpownerOnly=1
, but not all users have the permission to do it (if that's your case, you should probably use the bot password method above). - For Wikimedia instances (
www.wikidata.org
,test.wikidata.org
), consumer registration is done on meta: https://meta.wikimedia.org/wiki/Special:OAuthConsumerRegistration/propose?wpownerOnly=1 - Requires that your Wikibase instance has installed the Extension:OAuth (you can check that on
/wiki/Special:Version
). - Your config object would then look something like:
const generalConfig = { instance: 'https://www.somewikibase.instance', credentials: { oauth: { 'consumer_key': 'c60acb4f8abfa667ea5bafcdb2b673c7', 'consumer_secret': '1adbc98303a0b5b03311ebeee80d6916cbe1bd1f', 'token': '8de15abb42b8f9f15444ee4f13bb1f3d', 'token_secret': '2ba1e72cb947adda5da196d5d2cc57adf12aeaec' } } }
If you are running a web service that lets people other than yourself make edits on a Wikibase instance, using their usernames and passwords isn't an option: you're only option is to setup an OAuth consumer. That's for example what inventaire.io uses to allow users to make edits on wikidata.org in their name.
- First, you need to request an OAuth consumer on the desired Wikibase instance:
- For Wikimedia instances (
www.wikidata.org
,test.wikidata.org
), consumer registration is done on meta: https:// meta.wikimedia.org/wiki/Special:OAuthConsumerRegistration/propose - For other Wikibase instance, see
/wiki/Special:OAuthConsumerRegistration/propose
- For Wikimedia instances (
- Then you will need to setup an OAuth authentification process to allow users of your web service to authorize your consumer to make edits in their name. That's the tricky part. Some libraries should help you to do that, such as
passport-mediawiki-oauth
(see Help:Toolforge/My first NodeJS OAuth tool), but some people just prefer rolling their own (ex: inventaire.io implementation). (If you go for this later option,⚠️ beware of the documentation footnotes: make sure to use the right URLs before loosing hours at ainvalid signature
error message).- As your requests might now be done in the name of different users each time, you will the need to pass the credentials in the request config objects rather than the general config objects:
import WBEdit from 'wikibase-edit' // At initialization const generalConfig = { instance: 'https://www.somewikibase.instance', credentials: { oauth: { 'token': '8de15abb42b8f9f15444ee4f13bb1f3d', 'token_secret': '2ba1e72cb947adda5da196d5d2cc57adf12aeaec' } } } const oauthConsumer = { 'consumer_key': 'c60acb4f8abfa667ea5bafcdb2b673c7', 'consumer_secret': '1adbc98303a0b5b03311ebeee80d6916cbe1bd1f', } const wbEdit = WBEdit(generalConfig) // Later, when a user with OAuth tokens already setup (see previous step) makes an edit request const requestOauth = { 'consumer_key': oauthConsumer['consumer_key'], 'consumer_secret': oauthConsumer['consumer_secret'], 'token': user.oauth['token'], 'token_secret': user.oauth['token_secret'] } const requestConfig = { credentials: { oauth: requestOauth } } wbEdit.label.set({ id, language, value }, requestConfig)
- As your requests might now be done in the name of different users each time, you will the need to pass the credentials in the request config objects rather than the general config objects:
When running wikibase-edit
in the browser, it should be possible to use the browser session, but for it to work, the Wikibase instance needs to support CORS (unless your script is doing the request from the Wikibase instance domain itself). If that's your intent, set the config as follow:
const generalConfig = {
// Note that it will only work for domains on HTTPS
instance: 'https://www.wikidata.org',
credentials: {
browserSession: true
}
}
It is also possible to use wikibase-edit
without credentials at all: it currently means that your edits will then be signed with your IP address, but [that might change in the future}(https://meta.wikimedia.org/wiki/IP_Editing:_Privacy_Enhancement_and_Abuse_Mitigation).
const generalConfig = {
// Note that it will only work for domains on HTTPS
instance: 'https://www.wikidata.org',
anonymous: true
}
The bot
flag will mark your edits as made by a bot account
See maxlag
parameter documentation. If the Wikibase server returns a maxlag
error, the request will automatically be re-executed after the amount of seconds recommended by the Wikibase server via the Retry-After
header. This automatic retry can be disabled by setting autoRetry
to false
in the general config or the request config.
As specified in the MediaWiki documentation Interactive tasks (where a user is waiting for the result) may omit the maxlag parameter. To do so, set maxlag = null
in the config object.
All functions return promises. See also Wikidata API documentation.
wbEdit.label.set({
id: 'Q4115189',
language: 'fr',
value: 'Bac à sable bulgroz'
})
This can also be used to remove a label
wbEdit.label.set({
id: 'Q4115189',
language: 'fr',
value: ''
})
wbEdit.description.set({
id: 'Q4115189',
language: 'fr',
value: 'description du Bac à sable bulgroz'
})
This can also be used to remove a description
wbEdit.description.set({
id: 'Q4115189',
language: 'fr',
value: ''
})
// Add one alias
wbEdit.alias.add({
id: 'Q4115189',
language: 'fr',
value: 'foo'
})
// Add several aliases
wbEdit.alias.add({
id: 'Q4115189',
language: 'fr',
value: [ 'foo', 'bar' ]
})
// Remove one alias
wbEdit.alias.remove({
id: 'Q4115189',
language: 'fr',
value: 'foo'
})
// Remove several aliases
wbEdit.alias.remove({
id: 'Q4115189',
language: 'fr',
value: [ 'foo', 'bar' ]
})
// Replace the current list of aliases in French on Q4115189 by 'foo'
wbEdit.alias.set({
id: 'Q4115189',
language: 'fr',
value: 'foo'
})
// Replace the current list of aliases in French on Q4115189 by 'foo' and 'bar'
wbEdit.alias.set({
id: 'Q4115189',
language: 'fr',
value: [ 'foo', 'bar']
})
NB: By default, no check is performed to see if the claims values already exist. To perform this kind of check and avoid creating duplicated claims, see the section on reconciliation.
// Simplest case
wbEdit.claim.create({
id: 'Q4115189',
property: 'P2002',
value: 'bulgroz'
})
// With a datatype requiring a rich value (see below for the different datatypes)
wbEdit.claim.create({
id: 'Q4115189',
property: 'P1476',
value: { text: 'bulgroz', language: 'it' }
})
// Advanced case with a rank, qualifiers, and references
wbEdit.claim.create({
id: 'Q4115189',
property: 'P2002',
value: 'bulgroz',
rank: 'preferred',
qualifiers: {
P370: 'foo'
},
references: [
{ P143: 'Q8447', P813: '2020-07' },
{ P143: 'https://some.source/url', P813: '2020-07-19' }
]
})
// Monolingualtext property
wbEdit.claim.create({
id: 'Q4115189',
property: 'P1476',
value: { text: 'bulgroz', language: 'it' }
})
// Quantity:
// pass a single value for a count without a specific unit
wbEdit.claim.create({
id: 'Q4115189',
property: 'P1106',
value: 9000
})
// pass an object for a value with a specific unit. Example here to specify minutes (Q7727)
wbEdit.claim.create({
id: 'Q4115189',
property: 'P2097',
value: { amount: 9000, unit: 'Q7727', lowerBound: 9000, upperBound: 9315 }
})
wbEdit.claim.create({
id: 'Q4115189',
property: 'P569',
value: '1802-02-26'
})
see https://www.wikidata.org/wiki/Help:Dates#Precision
By default, the precision is inferred from the input
// Inferred year precision (9)
wbEdit.claim.create({ id, property, value: '1802' })
// Inferred month precision (10)
wbEdit.claim.create({ id, property, value: '1802-02' })
// Inferred day precision (11)
wbEdit.claim.create({ id, property, value: '1802-02-26' })
But in some cases it needs to be explicitly specified:
// billion years
wbEdit.claim.create({ id, property, value: { time: '-13000000000', precision: 0 }})
// million years
wbEdit.claim.create({ id, property, value: { time: '-1000000', precision: 3 }})
// hundred thousand years
wbEdit.claim.create({ id, property, value: { time: '-100000', precision: 4 }})
// ten thousand years
wbEdit.claim.create({ id, property, value: { time: '-50000', precision: 5 }})
// millennium
wbEdit.claim.create({ id, property, value: { time: '1000', precision: 6 }})
// century
wbEdit.claim.create({ id, property, value: { time: '1800', precision: 7 }})
// decade
wbEdit.claim.create({ id, property, value: { time: '1800', precision: 8 }})
// year
wbEdit.claim.create({ id, property, value: { time: '1802', precision: 9 }})
// month
wbEdit.claim.create({ id, property, value: { time: '1802-02', precision: 10 }})
// day
wbEdit.claim.create({ id, property, value: { time: '1802-02-26', precision: 11 }})
Only 2 calendar are currently supported by Wikibase: Gregorian (Q1985727) and Julian (Q1985786)
// Default calendar: Gregorian
wbEdit.claim.create({ id, property, value: '1802-02-26' })
// Use an object value to set a custom calendar. All the following options are valid:
wbEdit.claim.create({ id, property, value: { time: '0302-05-01', calendar: 'julian' }})
wbEdit.claim.create({ id, property, value: { time: '0302-05-01', calendar: 'Q1985786' }})
wbEdit.claim.create({ id, property, value: { time: '0302-05-01', calendar: 'http://www.wikidata.org/entity/Q1985786' }})
wbEdit.claim.create({ id, property, value: { time: '0302-05-01', calendarmodel: 'http://www.wikidata.org/entity/Q1985786' }})
// with a precision of an arcsecond
wbEdit.claim.create({
id: 'Q4115189',
property: 'P626',
value: { latitude: 45.758, longitude: 4.84138, precision: 1 / 360 }
})
// somevalue
wbEdit.claim.create({
id: 'Q4115189',
property: 'P19',
value: { snaktype: 'somevalue' }
})
// novalue
wbEdit.claim.create({
id: 'Q4115189',
property: 'P27',
value: { snaktype: 'novalue' }
})
A function to change the value of an existing claim without having to remove it and while keeping its references and qualifiers.
wbEdit.claim.update({
id: 'Q4115189',
property: 'P2002',
oldValue: 'initial-value',
newValue: 'new-value'
})
It will return a rejected promise if several claims with the same value already exist.
It can also be used for rich values such as globecoordinate
claims:
const oldValue = { latitude: 18.65, longitude: 226.2, precision: 0.01, globe: "http://www.wikidata.org/entity/Q111" }
const newValue = { latitude: 18.65, longitude: 226.2, precision: 0.01, globe: "http://www.wikidata.org/entity/Q313" }
wbEdit.claim.update({
id: 'Q4115189',
property: 'P2002',
oldValue,
newValue
})
Instead of passing the old value, you can pass the claim guid. That's generally considered a more reliable approach.
const guid = 'Q4115189$E66DBC80-CCC1-4899-90D4-510C9922A04F'
wbEdit.claim.update({
guid,
newValue: 'new-value'
})
It is possible to set the claim rank along setting a new value
wbEdit.claim.update({
guid,
rank: 'preferred',
newValue: 'new-value'
})
It is also possible to change the claim rank alone
wbEdit.claim.update({
guid,
rank: 'preferred'
})
Move a claim from an entity to another and/or from a property to another
This function requires to know about claim guid.
- change the property of a claim (without changing entity)
const wbEdit.claim.move({
// This guid identifies a P19 claim on Q4115189
guid: 'Q4115189$13681798-47F7-4D51-B3B4-BA8C7E044E1F',
id: 'Q4115189',
property: 'P20'
})
- move the claim to another entity (without changing the property)
const wbEdit.claim.move({
// This guid identifies a P19 claim on Q4115189
guid: 'Q4115189$13681798-47F7-4D51-B3B4-BA8C7E044E1F',
id: 'Q13406268',
property: 'P19'
})
- move the claim to another entity and another property
const wbEdit.claim.move({
// This guid identifies a P19 claim on Q4115189
guid: 'Q4115189$13681798-47F7-4D51-B3B4-BA8C7E044E1F',
id: 'Q13406268',
property: 'P20'
})
- move the claim to another entity, another property, and change the value (but, as before, keeping qualifiers and references unchanged)
const wbEdit.claim.move({
// This guid identifies a P19 claim on Q4115189
guid: 'Q4115189$13681798-47F7-4D51-B3B4-BA8C7E044E1F',
id: 'Q13406268',
property: 'P20',
newValue: 'foo'
})
- change the property of all
Q4115189
P19
claims (without changing entity)
const wbEdit.claim.move({
propertyClaimsId: 'Q4115189#P19'
id: 'Q4115189',
property: 'P20'
})
- move
Q4115189
P19
claims to another entity (without changing the property)
const wbEdit.claim.move({
propertyClaimsId: 'Q4115189#P19'
id: 'Q13406268',
property: 'P19'
})
- move
Q4115189
P19
claims to another entity and another property
const wbEdit.claim.move({
propertyClaimsId: 'Q4115189#P19'
id: 'Q13406268',
property: 'P20'
})
If the origin and target properties are of different datatypes, a type conversion will be attempted in the following cases:
origin datatype | target datatype | comment |
---|---|---|
external-id |
string |
|
monolingualtext |
string |
|
quantity |
string |
|
string |
external-id |
|
string |
quantity |
In other cases, an error will be thrown: if you think that another type conversion should be possible, please open a ticket
// remove one claim
const guid = 'Q4115189$E66DBC80-CCC1-4899-90D4-510C9922A04F'
wbEdit.claim.remove({ guid })
// remove several claims on the same entity
const guids = [
'Q4115189$BB467A9A-9123-4D0C-A87A-B7BF7ACD6477',
'Q4115189$D2CC0D8C-187C-40CD-8CF3-F6AAFE1496F4'
]
wbEdit.claim.remove({ guid: guids })
See also: How to get a claim guid
Removing claims by their guids
is the most relyable way, but it can also convenient to just specify claims to be removed from their value:
await wbEdit.claim.remove({
id: 'Q4115189',
property: 'P123',
value: 'Q3208426'
})
To customize the way the claims to remove are found, a reconciliation
object can be passed (see the section on reconciliation for more details)).
await wbEdit.claim.remove({
id: 'Q4115189',
property: 'P123',
value: 'Q3208426',
qualifiers: { P370: 'foo' },
reconciliation: {
matchingQualifiers: [ 'P370' ]
}
})
Those functions require to know about claim guid.
const guid = 'Q4115189$E66DBC80-CCC1-4899-90D4-510C9922A04F'
// entity qualifier
wbEdit.qualifier.set({
guid,
property: 'P155',
value: 'Q4115189'
})
// string qualifier
wbEdit.qualifier.set({
guid,
property: 'P1545',
value: '123'
})
// time qualifier
wbEdit.qualifier.set({
guid,
property: 'P580',
value: '1802-02-26'
})
wbEdit.qualifier.set({
guid,
property: 'P580',
value: { time: '1802-02-26', precision: 11 }
})
// quantity qualifier
wbEdit.qualifier.set({
guid,
property: 'P2130',
value: 13
})
// quantity qualifier with a unit
wbEdit.qualifier.set({
guid,
property: 'P2130',
value: { amount: 123, unit: 'Q4916' }
})
// monolingualtext qualifier
wbEdit.qualifier.set({
guid,
property: 'P3132',
value: { text : "les sanglots long des violons de l'automne", language: 'fr' }
})
// somevalue
wbEdit.qualifier.set({
guid,
property: 'P3132',
value: { snaktype : 'somevalue' }
})
// novalue
wbEdit.qualifier.set({
guid,
property: 'P3132',
value: { snaktype : 'novalue' }
})
See also: How to get a claim guid
wbEdit.qualifier.update({
guid: 'Q4115189$E66DBC80-CCC1-4899-90D4-510C9922A04F',
property: 'P155',
oldValue: 'Q4115189',
newValue: 'Q4115190'
})
// somevalue
wbEdit.qualifier.update({
guid,
property,
oldValue,
newValue: { snaktype : 'somevalue' }
})
// novalue
wbEdit.qualifier.update({
guid,
property,
oldValue,
newValue: { snaktype : 'novalue' }
})
A function to move qualifiers between properties within a claim:
wbEdit.qualifier.move({
guid: 'Q4115189$E66DBC80-CCC1-4899-90D4-510C9922A04F',
hash: '239ef1c81ef0c24611d6d7c294d07036e82c4666',
oldProperty: 'P155',
newProperty: 'P156'
})
That's exactly the same as above, just not specifying a hash
wbEdit.qualifier.move({
guid: 'Q4115189$E66DBC80-CCC1-4899-90D4-510C9922A04F',
oldProperty: 'P155',
newProperty: 'P156'
})
This will behave in the same way as for moving claims between properties of different datatypes
const guid = 'Q4115189$E66DBC80-CCC1-4899-90D4-510C9922A04F'
// qualifierHash can be either a single hash string or an array of reference hash strings
const qualifierHash = '239ef1c81ef0c24611d6d7c294d07036e82c4666'
wbEdit.reference.remove({
guid,
hash: qualifierHash
})
Those functions require to know about claim guid.
const guid = 'Q4115189$E66DBC80-CCC1-4899-90D4-510C9922A04F'
wbEdit.reference.set({
guid,
snaks: {
// reference url (P854) is 'https://example.org/rise-and-fall-of-the-holy-sand-box'
P854: 'https://example.org/rise-and-fall-of-the-holy-sand-box'
// imported from (P143) the French Wikipedia 'Q8447'
P143: 'Q8447',
// snaks can also have special snaktypes
P370: { snaktype : 'novalue' },
// or have several values
P369: [
'Q123',
{ snaktype : 'somevalue' }
]
}
})
To update an existing reference, pass its current hash value:
const guid = 'Q4115189$E66DBC80-CCC1-4899-90D4-510C9922A04F'
const referenceHash = '239ef1c81ef0c24611d6d7c294d07036e82c4666'
wbEdit.reference.set({
guid,
hash: referenceHash,
snaks: {
// Will override all existing snaks of that reference with this unique snak
P854: 'https://example.org/rise-and-fall-of-the-holy-sand-box'
}
})
const guid = 'Q4115189$E66DBC80-CCC1-4899-90D4-510C9922A04F'
// referenceHash can be either a single hash string or an array of reference hash strings
const referenceHash = '239ef1c81ef0c24611d6d7c294d07036e82c4666'
wbEdit.reference.remove({
guid,
hash: referenceHash
})
wbEdit.sitelink.set({
id: 'Q123',
site: 'frwiki',
title: 'Septembre',
})
wbEdit.sitelink.set({
id: 'Q123',
site: 'frwiki',
title: 'Septembre',
badges: [ 'Q17437796', 'Q17437798' ]
})
wbEdit.sitelink.set({
id: 'Q123',
site: 'frwiki',
title: null,
})
Handle badges on an existing sitelink
Add badges without removing the badges that might already have been set on the sitelink
wbEdit.badge.add({
id: 'Q123',
site: 'frwiki',
badges: [ 'Q17437798', 'Q17437796' ],
})
wbEdit.badge.remove({
id: 'Q123',
site: 'frwiki',
badges: [ 'Q17437798', 'Q17437796' ],
})
Make many edits on an entity at once.
By default, every label, description, claim, or sitelink that isn't included in the passed object will stay untouched: only those with a remove
flag will be removed. Beware that this isn't true for qualifiers and references, which can be removed by just being omitted (see P1114 example below).
NB: By default, no check is performed to see if the claims values already exist. To perform this kind of check and avoid creating duplicated claims, see the section on reconciliation.
wbEdit.entity.edit({
// Required
id: 'Q4115189',
// All the rest is optional but one of labels, descriptions, aliases, claims, or sitelinks must be set
labels: {
// Set a label
en: 'a new label in English',
// Remove a label
fr: null
},
descriptions: {
// Set a description
en: 'a new description',
// Remove a description
fr: null
},
aliases: {
// Pass aliases as an array
en: [ 'foo', 'bar' ],
// Or a single value
de: 'buzz',
// /!\ for any language specified, the values you pass will overwrite the existing values,
// which means that the following empty array will remove all existing aliases in French.
fr: [],
// To add aliases without removing existing values, you must set 'add=true'
nl: [
{ value: 'bul', add: true },
{ value: 'groz', add: true },
],
// The same effect of clearing all aliases in a given language can be optained by passing null
es: null
},
claims: {
// Pass values as an array
P361: [ 'Q1', 'Q2' ],
// Or a single value
P2002: 'bulgroz',
// Or a rich value object, like a monolingual text
P2093: { text: 'Author Authorson', language: 'en' },
// Or even an array of mixed simple values and rich object values
P1106: [ 42, { amount: 9001, unit: 'Q7727' } ],
// Add statements with special snaktypes ('novalue' or 'somevalue')
P626: { snaktype: 'somevalue' },
// or special rank (Default: 'normal'. Possible values: 'preferred' or 'deprecated')
P6089: { rank: 'preferred', value: 123 },
// Add qualifiers and references to value objects
P369: [
// Qualifier values can also be passed in those different forms
{
value: 'Q5111731',
qualifiers: {
P580: '1789-08-04'
P1416: [ 'Q13406268', 'Q32844021' ],
P1106: { amount: 9001, unit: 'Q7727', lowerBound: 9000, upperBound: 9315 }
}
},
// References can be passed as a single reference group
{ value: 'Q2622004', references: { P143: 'Q8447' } },
// or as multiple references groups
{
value: 'Q2622009',
references: [
{ P855: 'https://example.org', P143: 'Q8447' },
{ P855: 'https://example2.org', P143: 'Q8447' }
]
}
],
P1114: [
// Edit an existing claim
// /!\ Beware that while editing an existing claim,
// anything omitted (rank, qualifiers, or references) will be omitted!!
{ id: 'Q4115189$BC5F4F72-5B49-4991-AB0F-5CC8D4AAB99A', value: 123 },
// Remove an existing claim
{ id: 'Q4115189$afc56f6c-4e91-c89d-e287-d5691aeb063a', remove: true }
]
},
sitelinks: {
// Set a sitelink
frwiki: 'eviv bulgroz',
// Remove a sitelink
eswikisource: null
// Set a sitelink with badges
dewiki: {
title: 'eviv bulgroz',
badges: [ 'Q17437796', 'Q17437798' ]
},
},
// For convenience, the summary and baserevid can also be passed from this edit object
summary: 'doing a bunch of edits',
baserevid: 1234,
})
If the entity you are editing requires a big cleanup, instead of adding a remove
flag to all the elements that needs to be removed, you can set the clear
flag to true
, which will delete all the entity data before adding the specified data:
// Remove ALL the labels, descriptions, aliases, claims, and sitelinks, and set the English label to 'Sandbox'
wbEdit.entity.edit({
id: 'Q4115189',
clear: true,
labels: {
en: 'Sandbox'
}
})
Create an item from scratch.
The item data follow the same rules as wbEdit.entity.edit
, simply without the id
const { entity } = await wbEdit.entity.create({
type: 'item',
labels,
descriptions,
aliases,
claims,
sitelinks
})
console.log('created item id', entity.id)
Creating a property is just like creating an item, but with a type=property
and a datatype
const { entity } = await wbEdit.entity.create({
type: 'property',
datatype: 'string',
labels,
descriptions,
aliases,
claims
})
console.log('created property id', entity.id)
// Merge Q1 into Q2, turning Q1 into a redirection
wbEdit.entity.merge({ from: 'Q1', to: 'Q2' })
Wikibase doesn't allow to merge properties
wbEdit.entity.delete({ id: 'Q1' })
wbEdit.entity.delete({ id: 'P1' })
All the functions above handle authentification for you, but you can also access the auth data, that is session cookies and the currently valid csrf token, using the getAuthData
function.
import WBEdit from 'wikibase-edit'
const wbEdit = WBEdit({ instance, credentials })
const { cookie, token } = await wbEdit.getAuthData()
It can also be used as a way to validate credentials:
import WBEdit from 'wikibase-edit'
const wbEdit = WBEdit({ instance, credentials })
wbEdit.getAuthData()
.then(onValidCredentials)
.catch(onInvalidCredentials)
⚠️ Experimental. You are invited to use with caution: test on a small sample and see if it behaves as expected. Please report any issue, counter-intuitive behavior, or missing capability.
Several functions accept a reconciliation
object, allowing to customize how the input is matched to existing claims, and what should be done once a match is established:
By default, a claim is considered to be matching if its value (a.k.a. mainsnak
) is matching.
To also require to take qualifiers in consideration, when determining if a claim is matching, you can specify an array of matchingQualifiers
properties. Example:
{
reconciliation: {
matchingQualifiers: [ 'P580', 'P582' ]
// The line above is equivalent to
matchingQualifiers: [ 'P580:all', 'P582:all' ]
// that is that all qualifiers in the input should match qualifiers
// on the existing claim for the claim to be considered a match.
// To match on any qualifier for each of those properties instead, you could add the suffix `any`
matchingQualifiers: [ 'P580:any', 'P582:any' ]
}
}
Once a claim is determined as matching (be it only from its mainsnak
value or also taking its qualifiers
into account), references can also be matched by specifying a matchingReferences
array, but this is specific to references and won't influence the claim matching. It is just a way, once a matching claim is found, to avoid creating duplicated references.
{
reconciliation: {
matchingReferences: [ 'P854', 'P813' ]
// The line above is equivalent to
matchingQualifiers: [ 'P854:all', 'P813:all' ]
// that is that all reference snaks in the input should match reference snaks
// on an existing reference for the reference to be considered a match.
// To match on any reference snak for each of those properties instead, you could add the suffix `any`
matchingQualifiers: [ 'P854:any', 'P813:any' ]
}
}
Once a claim is determined as matching, several modes can be used to determine what should be done with that matching claim. This also applies to matching references.
- Checks if there is already a statement for that property, whatever the value
- If any statement is found, no change is performed on that statement, no new statement is added either
wbEdit.entity.edit({
id: 'Q4115189',
reconciliation: {
mode: 'skip-on-any-value'
},
claims: {
// If Q4115189 already has a P361 claim, this won't add anything
P361: [
'Q1',
]
},
})
If the initial state was
{ id: 'Q4115189', claims: { P361: [ 'Q1' ] }
after this edit it will still be
{ id: 'Q4115189', claims: { P361: [ 'Q1' ] }
- Checks if there is a statement with the specified value
- If a matching statement is found, no change is performed on that statement, no new statement is added either
wbEdit.entity.edit({
id: 'Q4115189',
reconciliation: {
mode: 'skip-on-value-match'
},
claims: {
// Those new values will only be added if there is no P361 statement with those values
P361: [
'Q1',
'Q2'
]
},
})
If the initial state was
{ id: 'Q4115189', claims: { P361: [ 'Q1' ] }
after this edit it will still be
{ id: 'Q4115189', claims: { P361: [ 'Q1' ] }
- Checks if there is a statement with the specified value
- If a matching statement is found, no change is performed on that statement, missing statements will be added
wbEdit.entity.edit({
id: 'Q4115189',
claims: {
P361: [ 'Q1', 'Q2' ]
},
reconciliation: {
mode: 'merge'
}
})
If the initial state was
{ id: 'Q4115189', claims: { P361: [ 'Q1' ] }
after this edit it will be
{ id: 'Q4115189', claims: { P361: [ 'Q1', 'Q2' ] }
A globally unique identifier, or guid
for short, is the unique identifier of a claim. As such, it is used by several functions working with existing claims. While the Wikibase API sometimes just refers to those as ids, wikibase-edit
always refer to those as guids to avoid the confusion with entities ids.
But "how do I get those guids?" you may ask. There are different pathways:
Maybe you got that id in a response from a previous edit:
const res = await wbEdit.claim.create({
id: 'Q4115189',
property: 'P2002',
value: 'bulgroz'
})
// Here is our new claim guid, ready to be used in our next edit!
const guid = res.claim.id
const res2 = await wbEdit.claim.remove({ guid }, { summary: 'oops' })
// res2.claim.id === guid
Maybe you fetched an entity's data:
// Example where we try to get the guid of Q1's first P31 claim
import { WBK } from 'wikibase-sdk'
const wbk = WBK({ instance: 'https://www.wikidata.org', sparqlEndpoint: 'https://query.wikidata.org/sparql' })
const url = wbk.getEntities({ ids: [ 'Q1' ] })
const { entities } = await customFetch(url).then(res => res.json())
const firstP31Claim = entities.Q1.claims.P31[0]
// Here is our guid!
const guid = firstP31Claim.id
Maybe you got guids from a SPARQL query:
const sparql = 'SELECT ?statement { ?item p:P4033 ?statement . } LIMIT 5'
const url = wbk.sparqlQuery(sparql)
const results = await customFetch(url)
.then(res => res.json())
.then(wbk.simplify.sparqlResults)
// Here are our statement guids!
const guids = results.map(result => result.statement)