Citation Keys
Generating citekeys for your items
The BibTeX citations keys generated by the standard Zotero exporters are always generated at time of export, using an algorithm that usually generates unique keys. For serious LaTeX users, “usually” presents the following problems:
- If a non-unique key is generated, which one gets postfixed with a distinguishing character is essentially non-deterministic.
- The keys are always auto-generated, so if you correct a typo in the author name or title, the key will change
- You can’t see the citation keys until you export them
For a LaTeX author, the citation keys have their own meaning, fully separate from the other entry data, even if people usually pick a naming scheme related to them. As the citation key is the piece of data that connects your bibliography, this is a piece of data you want to have control over. BBT offers you this control:
- Stable citation keys, without key clashes. BBT generates citation keys that take into account other existing keys in your library in a deterministic way, regardless of what part of your library you export, or the order in which you do it.
- BBT is conservative about citation key changes, and allows you to fix keys to any value of your choosing.
- Generate citation keys from JabRef(-ish) patterns.
You can also
- Drag and drop LaTeX citations using these keys to your favorite LaTeX editor
- Show your citation keys in the item list view.
Set your own, fixed citation keys
By default, BBT generates the citation key from the item information, and this key may change when you edit the item. Such keys are called dynamic
keys. In contrast, fixed
keys are marked with a pushpin in the item list view and in the item details to distinguish them from dynamic keys.
You can fix the citation key (called pinning
in BBT) for an item by adding the text Citation Key: <your citekey>
anywhere in the
extra
field of the item on a line of its own. You can generate a pinned citation key by selecting one or more items, right-clicking, and selecting Generate BibTeX key
, which will add the current citation key to the extra
field, thereby pinning it.
Drag and drop/hotkey citations
You can drag and drop citations into your LaTeX/Markdown/Orgmode editor, and it will add a proper \cite{citekey}
/[@citekey]
/[[zotero://select...][@citekey]
. The cite
command is
configurable for LaTeX by setting the config option in the preferences. Do not include the leading backslash.
This feature requires a one-time setup: choose the Quick Copy format under the Citation keys
preferences for BBT, and go to Zotero preferences, tab Export, under Default Output Format, select “Better BibTeX Quick Copy: [format you just selected]”.
Configurable citekey generator
BBT also implements a citekey generator for those entries that don’t have a citekey set explicitly; the formatter pattern language used to follow the JabRef key formatting syntax, but now uses a javascript-ish format. You can set your generator pattern in the Better BibTeX preferences (you can get there via the Zotero preferences, or by clicking the Better BibTeX “Preferences” button in the addons pane.
Better BibTeX knows four kinds of “things” to build the citekey from:
- “functions”, these produce text based on the item the key is being constructed from, eg
shorttitle
. Even though these are largely case insensitive, they must start with a lowercase letter. - “field access”, direct text from the zotero item fields; these again are largely case insensitive, but they must start with an uppercase letter
- “filters”, these are actions that act on the text returned from either functions, field access, or from a subformula like
(auth + title || year)
. these are fully case insensitive, and you can chain these together, each acting on the output of the previous filter. - bare strings (text quoted in single or double quotes)
There are 5 ways you can build subformulae:
- composition:
(auth + title)
- alternates:
(auth || title)
(use the first thing that returns any text, soauth
if that returns text, otherwisetitle
) - conditions:
(auth && title)
(ascertain that the first returns any text before using the last, so usetitle
only ifauth
would have returned something) - ternaries:
(auth ? year : title)
(ifauth
returns any text, useyear
, otherwise usetitle
). Ternary operators have the formatcondition ? output_if_true : output_if_false
, and you can use it like an if-or statement. (auth + title) > 0
orauth > 0
are shorthand for(auth + title).len
/auth.len
.
these can be combined, eg (auth || shorttitle || year) ? (auth + title) : (year || title)
, but subformulae cannot appear in parameters, so title.select(auth ? 3 : 4)
is not valid. Filters (explained below) can be applied to subformulae, so (title || auth).lower
checks whether the title
function produces output (i.e. not empty). If it does, the title
function is used; otherwise, the formula will use the auth
function. It then converts the output of (title || auth)
to lowercase.
You can also explicitly test whether a formula part is not empty and jump to the next formula if not:
title.lower.len + year; auth + year
which would have the formula evaluate whether the title
function returns a non-empty text; if this condition is not met, formula evaluaton jumps to the next formula auth + year
. You can also test for a minimal length using eg
(title > 1) + year; auth + year
which is shorthand for
title.len('>',1) + year; auth + year
which checks whether the title
output is longer than 1 character. Note the parentheses around the >
expression – the formula uses javascript operator precedence, and title > 1 + year
means title > (1 + year)
.
The default key pattern is auth.lower + shorttitle(3,3) + year
; if you have papers that use keys which were generated by the key generator of the standard Bib(La)TeX exporters of Zotero you may want to use zotero.clean
instead in order to ease migration from existing exports for people who previously used the standard Zotero Bib(La)TeX exports.
auth.lower + shorttitle(3,3) + year
, means
- last name of first author without spaces, in lowercase because of the
.lower
filter - The first
n
(default: 3) words of the title, apply capitalization to firstm
(default: 0) of those. - year of publication if any,
- a letter postfix (a, b, c, etc) in case of a clash (this part is always added, you can’t disable it, although you can change it to Zotero-style numeric)
Changing a pattern will only affect items created/changed after you changed the pattern; existing keys are not automatically regenerated when you change the pattern. If you want your keys to update after a pattern change you will have to select your items, right-click, and select Refresh
. This will not affect keys you have pinned.
If you want to get fancy, you can set multiple patterns separated by a semicolon (;
) or vertical bar (|
), of which the first will be applied
that yields a non-empty string. If all return a empty string, a random key will be generated.
An example application for this behavior is to use the tex.shortauthor
from the extra field when defined to generate short citation keys for entries with long group author names, but to default to auth.lower
otherwise:
extra('tex.shortauthor').transliterate.clean.lower.len + year; auth.lower + year
You can add a verbatim text by just including it in single or double quotes:
extra('tex.shortauthor').transliterate.clean.lower.len + year; 'default' + auth.lower + year
Formulas have some ternary and or-style choice support; you can use them in formulas instead of a function, but not in parameters; you can for example use
(title ? title : auth).lower + year
or
(title || auth).lower + year
instead of
title.len + year; auth + year
and you can test for length of subsections; what you would previously do with
auth + title + len + year
to jump to the next formula if auth
and title
were both empty is now
(auth + title).len + year
Generating citekeys
To generate your citekeys, you use a formula composed of functions and filters. Broadly, functions grab text from your item, and filters transform that text. Note that the formula syntax has changed from a bracketed format to a javascript-ish format. The old syntax was getting harder to maintain and its inflexibility prevented new extensions to the functions being implemented cleanly.
For more details, head over to the functions and filters list.