# 3.3 Creating your own formatting functions

### Step 1 : Define a global function

Custom functions must be defined with the syntax `window.customMetadata = function(item) { ... }` rather than `function customMetadata(item){ ... }` , otherwise an error will be thrown. This syntax is needed to make the function globally available, so that it can be found by the extension.

### Step 2 : Construct your metadata template within the function

All formatting functions must do the following :

* The function must **take a single argument** - the item's data object, as returned by the Zotero Web API. [See here](https://gist.github.com/dstillman/f1030b9609aadc51ddec) for an official gist from the Zotero API docs, showing an example object returned for a single item.
* The function must **return a single array** - specifying the contents of the blocks that should be added to the item's page in Roam.&#x20;
  * **Each element** of the array will be processed as **a top-level Roam block** to be added to the item's Roam page. If the element is a *String* of text, the block will be childless. If the element is an *Object*, it can have children blocks (see [Nesting metadata](/zotero-roam/v0.6/customization/formatting/nesting-metadata.md)).
    * *String* elements will be added as top-level, childless blocks.&#x20;
    * *Object* elements will be processed recursively and support nested blocks.
  * The ordering of the blocks in Roam will reflect the ordering of the array.

To help you with writing your own functions, I've made an [Observable interactive notebook](https://observablehq.com/@greenmeen/zoteroroam-metadata-formatting), where you can try your hand at writing functions & using them to process your own Zotero data :

{% embed url="<https://observablehq.com/@greenmeen/zoteroroam-metadata-formatting>" %}

#### Getting Started

```javascript
// You can use the following code to start customizing the output
// It replicates exactly what the default formatting function does :
window.customMetadata = function(item){
    // Initialization of the array of blocks :
    let metadata = [];
    
    // Title of the item
    if (item.data.title) {
        metadata.push(`Title:: ${item.data.title}`)
    };
    // Creators of the item
    if (item.data.creators.length > 0) {
        metadata.push(`Author(s):: ${zoteroRoam.formatting.getCreators(item, {creators_as: "string", brackets: true, use_type: true})}`) 
    };
    // Abstract for the item
    if (item.data.abstractNote) { 
        metadata.push(`Abstract:: ${item.data.abstractNote}`) 
    };
    // Type of the item
    if (item.data.itemType) {
        metadata.push(`Type:: [[${zoteroRoam.formatting.getItemType(item)}]]`) 
    };
    // Publication/Book title
    metadata.push(`Publication:: ${ item.data.publicationTitle || item.data.bookTitle || "" }`)
    // URL
    if (item.data.url) {
        metadata.push(`URL : ${item.data.url}`) 
    };
    // Date the item was added to Zotero
    if (item.data.dateAdded) {
        metadata.push(`Date Added:: ${zoteroRoam.utils.makeDNP(item.data.dateAdded, {brackets: true})}`) 
    };
    // Links to the item in Zotero (local + web links)
    metadata.push(`Zotero links:: ${zoteroRoam.formatting.getLocalLink(item, {format: "markdown", text: "Local library"})}, ${zoteroRoam.formatting.getWebLink(item, {format: "markdown", text: "Local library"})}`); // Local + Web links to the item
    // Tags attached to the item
    if (item.data.tags.length > 0) {
        metadata.push(`Tags:: ${zoteroRoam.formatting.getTags(item)}`)
    };
    
    // Requesting the item's PDF files + notes
    let children = zoteroRoam.formatting.getItemChildren(item, {pdf_as: "links", notes_as: "formatted"});
    // Links to the PDF files
    if(children.pdfItems){
        metadata.push(`PDF links : ${children.pdfItems.join(", ")}`);
    }
    // Contents of notes
    if(children.notes){
        let notesBlock = {string: `[[Notes]]`, children: []};
        notesBlock.children.push(...children.notes.flat(1));
        metadata.push(notesBlock);
    }

    return metadata; 
}
```

### Step 3 : Assign the function to item types

Custom functions can be assigned to item types using [funcmap](/zotero-roam/v0.6/customization/other/funcmap.md). You can assign a function to specific item types, or set it as the default formatting function.

*Assigning the `customMetadata` function to be used for conference papers and journal articles, and letting the extension handle other item types with its own defaults.*

```javascript
zoteroRoam_settings = {
    // dataRequests: {...},
    funcmap: {
        conferencePaper: "customMetadata",
        journalArticle: "customMetadata"
    }
}

// ---

window.customMetadata = function(item){
    // your code for the formatting function
}
```

*Using the `customPaperFormat` function for all item types*

```javascript
zoteroRoam_settings = {
    // dataRequests: {...},
    funcmap: {
        DEFAULT: "customMetadata"
    }
}

// ---

window.customMetadata = function(item){
    // your code for the formatting function
}
```

{% hint style="info" %}
The function's code is located outside of the `zoteroRoam_settings` object.\
To avoid confusion or typos, you can place it in a separate Roam code block. Select JavaScript as language & make sure it's nested under an active `roam/js`block.
{% endhint %}

## Examples

Head over to the [Academia Roamana graph page](https://roamresearch.com/#/app/AcademiaRoamana/page/pJvpz2sln) for templates shared by the community, with code, screenshots, etc !


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://alix-lahuec.gitbook.io/zotero-roam/v0.6/customization/formatting.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
