Create Plugins

Jump ahead to:


You can write custom Javascript plugins and share them with the community by submitting a pull request to our official GitHub repo. Find example of other plugins in the same repo. This article walks you through how to start creating a plugin.

Plugin Setup

A plugin is made up of at least two files: plugin.json and script.js (the name is defined in the plugin.json). 

The plugin.json file contains the meta-information about the plugin like id, author, name, etc. and it defines which commands will be available in NotePlan's Command Bar. 

The script.js contains the actual code. NotePlan will call specific functions in this call, depending on which command was executed.

All plugin files have to be inside NotePlan's database folder. Here is an example of the folder structure:

  • /root 
    • Plugins
      • Plugin-name // one folder per plugin, the name is expected to the plugin.id below
        • plugin.json // metadata
        • script.js // the script file containing the code)
        • other supporting files, like other Javascript dependencies.

The easiest way to find the folder is to open it from the plugin preferences by clicking on "Open Plugin Folder".

plugin.json

Here is an example of a minimal plugin.json file:

{
  "noteplan.minAppVersion": "3.0.21", 
  "macOS.minVersion": "10.15.7",
  "iOS.minVersion": "14",
  "plugin.id": "eduardme.move", 
  "plugin.name": "Move selected note to another folder", 
  "plugin.description": "Move a note from the current folder into another.", 
  "plugin.author": "Eduard Metzger",
  "plugin.url": "https://…",
  "plugin.version": "0.0.2", 
  "plugin.dependencies": [ ], 
  "plugin.script": "script.js",
  "plugin.lastUpdateInfo": "",
  "plugin.requiredFiles": "",
  "plugin.commands": [ 
    {
      "name": "move", 
      "alias": ["m", "mv"],
      "description": "Moves note to another folder", 
      "jsFunction": "moveNote",
      "arguments": ["note title", "heading"]
    },
  ],
  "plugin.settings": []
}
  • noteplan.minAppVersion Set the minimum NotePlan version number this plugin works on. The plugin API is constantly extended, so older versions might not have the API features you are using. Version numbers will be documented in the API, when a change is made.
  • macOS.minVersion This defaults to macOS 10.15.7 (latest Catalina version) if you don't define it. Older macOS versions have outdated Javascript engines so that new JS syntax is not supported. The minimum version supported by NotePlan is 10.12 (Sierra), but this doesn't support async/await. Use a transpiler to support older JS versions and set the macOS.minVersion to "10.13" if you are using async/await, otherwise use "10.12" as the minimum version. Set nothing and "10.15.7" is assumed.
    • Note: In NotePlan 3.0.23 it still defaults to macOS 11 (Big Sur). 
  • iOS.minVersion Similar to the macOS minVersion, but for iOS. Version 14 supports all plugins, lower versions might not anymore. But this is less critical as most phones are updated quickly, while relatively many Macs are not updated due to old hardware.
  • plugin.id should be unique and identical to the folder which is containing the plugin files. If you plan to submit your plugin (please do!), we need to keep the IDs unique across the repository, so that NotePlan can load them properly. If the plugin is downloaded through NotePlan's preferences, it will use the plugin.id to create and name the folder automatically.
  • plugin.name, plugin.authorplugin.url (website of your plugin), and plugin.description will be used in the plugin preferences in NotePlan to describe the released versions.
  • plugin.version is important when the plugin is available as release on the repo. NotePlan will read this field and compare it to the local version. Use semantic versioning and avoid using anything other than numbers and periods, like "1.4.1".
  • In plugin.dependencies you can add the file names of third-party Javascript libraries. They have to be in the same folder as the plugin.json (which means you need to download and add them to the folder). NotePlan will load them at runtime.
  • plugin.script defines the name of the Javascript file that NotePlan will load to execute the commands.
  • plugin.lastUpdateInfo (Optional) This text field should describe what major changes are present in the latest update of this plugin. A user who is using this plugin will see this message when the plugin auto-updates (when the user runs a plugin command).  
  • plugin.requiredFiles (Optional) List of files so that you can have extra files copied to the plugin folder when your plugin is packaged (e.g. for use in an HTML window opened by the plugin). Any files to be copied should be in your: <plugin-root-folder>/requiredFiles folder. A filename listed in the plugin.requiredFiles array will be copied from the requiredFiles folder into your plugin root. NOTE: subdirectories are not legal inside the requiredFiles or in the plugin folder.
  • plugin.commands is an array containing the list of available /commands. NotePlan will load this list and make it available in the Command Bar as auto-complete options.
    • Each command refers to a function in the plugin.script file. NotePlan will call this function when the user executes the /command. You can have multiple commands per plugin. Ideally, the commands are related.
    • "name" = Name of the "/command" (don't include the "/" here) which will be available to the user.
    • "alias" = (Note: available from v.3.0.26, backward compatible) Optional string array of alternative keywords when searching for the plugin. The user can search for the name "move", in this example or "mv" to find the command.
    • "description" = Short description of what the command does which will be displayed in the Command Bar's list of commands which appears when the user starts to type the "/name" into the Command Bar. 
    • "jsFunction" = The exact function name NotePlan should call which is available in the file "plugin.script" file.
    • "hidden" = You can optionally hide commands from the UI and the command bar, but still call them from within other plugins. 
    • "arguments" = Optional list of descriptions of each argument the JavaScript function behind this command supports. You can get the list of arguments using DataStore.listPlugins() for example and show them to the user when you call this command from another plugin.
  • plugin.settings is an array with settings that will be used by NotePlan to build a configuration UI, so the user can configure the plugin. See more details here (available since v3.3.2).

plugin.script ("script.js")

This is the Javascript file containing the actual code NotePlan will run. It consists of at least one or more functions which will be called by NotePlan after the user has executed the referenced /command. Here is an example file:

function moveNote() {
    console.log("Hello World")
}

The function name moveNote has to be defined in the plugin.json as one of the available commands.

Installing Your Plugin

Once you've written your basic plugin, you need to put it somewhere that NotePlan can find it. Go to NotePlan > Preferences > Plugins and click the button "Open Plugins Folder":

Create a new folder in that directory (you can name it whatever you want), and drop the files you created (script.js and plugin.json) into that folder. The next time you open the Command Bar and type "/", your new plugin will be loaded and you should see and be able to select your new command (whatever you put for "plugin.command" in the plugin.json).

More Complex / Efficient Plugin Development

The instructions above work fine for a basic plugin, but there is a lot of tooling in the GitHub repository that will make you more efficient in creating more complex plugins. After you've acquainted yourself with the basics of plugin development on this page, we highly recommend following the instructions on GitHub.

Logging and Debugging

For simple debugging purposes, you can use  console.log(string) inside your JavaScript code. Before running the command, open the Plugin Console under "Help" > "Plugin Console" in the menubar:

Interfaces (Global Objects)

Inside the plugin.script file, NotePlan provides various global objects as an interface to your notes, the editor, and to NotePlan in general. With these interfaces, you can read data (like the content of a note), prompt user input, and change the data. For example Editor.content returns you the current text in the editor and lets you set the text if you call Editor.content = "text".

You can find examples of how to use the interfaces in the API documentation. In the next article, we will list and explain the various global objects and how to use them.

Javascript Promises

Promises are supported and you need to use them in order to wait for user input for example. The preferred syntax is to use await before the Promise function. Note: Functions that use Promises with await have to be prefixed with async. Here is an example:

async function selectFolder() {
    let folder = await CommandBar.showOptions(DataStore.folders, "Select")
    // Use folder.value or folder.index [...]
}

Fetch

Use fetch to get data from the internet, like weather information, or connect to the API of another app to sync data between NotePlan and the app. Fetch supports the following options parameters: "method" (like "GET"), "headers", and "body" (which takes a string as value).

Note: Fetch only works with websites that have an SSL certificate installed. This means "https://" must work.

Here are examples:

async function weatherFetch() {
    let response = await fetch("https://api.weatherapi.com/v1/current.json?key=f4c442d67eef4574b99184324211404&q=Berlin&aqi=no")
    console.log(response)
}

async function fetchWithParameters() {
  const response = await fetch('https://api.ninox.com/v1/teams', 
  { method: 'GET',
    headers: {
      'Authorization': 'Bearer cfda1581-1a36-11ec-b44d-f9d8217e4195', 
      'Content-Type': 'application/json'
    }
  })
  console.log(response)
}

Syncing Plugins

Avoid adding a node_modules folder or any other large folder with many files to the plugins directory. Syncing will probably max out. Additionally, NotePlan v3.3 will exclude node_modules folders from syncing it with CloudKit.


Next up: Javascript Plugin API →

Jump to: