Obsidian Sample Plugin

repository·master·Indexed 26 days ago

https://github.com/obsidianmd/obsidian-sample-plugin

A TypeScript-based template and scaffold for developing Obsidian plugins. It includes build scripts, ESLint configuration, and guidance on implementing the Plugin class, adding ribbon icons, status bar items, commands, settings tabs, and custom modals. The documentation covers environment setup, manual installation, and the process for releasing new plugin versions to the Obsidian community.

Tokens
2.6K
Snippets
11
Records
14
Agent score
89%

What's inside obsidian-sample-plugin

  1. Set up a new Obsidian plugin development environment

    master

    To start developing an Obsidian plugin using this template:

    1. Use the "Use this template" button on GitHub to create your own repository.
    2. Clone your repository to a local folder. For easiest development, place it directly in your vault's plugin folder: .obsidian/plugins/your-plugin-name.
    3. Ensure you have NodeJS installed (version 18 or higher).
    4. Run npm i to install dependencies.
    5. Run npm run dev to compile src/main.ts into main.js in watch mode.
    6. Reload Obsidian to load the plugin and enable it in the settings window.

    To update the Obsidian API definitions, run npm update in your repository folder.

    npm i
    npm run dev
  2. Release a new version of your plugin

    master

    When preparing a release, follow these steps:

    1. Update manifest.json with the new version number and the required minAppVersion.
    2. Update versions.json to map your new version to the minimum Obsidian version: "new-plugin-version": "minimum-obsidian-version".
    3. Create a GitHub release using the version number as the "Tag version" (do not include a v prefix).
    4. Upload manifest.json, main.js, and styles.css as binary attachments to the release.
    5. Ensure manifest.json exists in both the root of your repository and within the release assets.

    Tip: You can automate version bumping by running npm version patch, npm version minor, or npm version major after manually updating minAppVersion in manifest.json. This updates manifest.json, package.json, and versions.json automatically.

  3. Configure plugin funding URLs in manifest.json

    master

    You can allow users to support your plugin financially by adding a fundingUrl field to your manifest.json. You can provide a single string or an object containing multiple labeled URLs.

    {
    	"fundingUrl": "https://buymeacoffee.com"
    }
    
    // Or multiple URLs:
    {
    	"fundingUrl": {
    		"Buy Me a Coffee": "https://buymeacoffee.com",
    		"GitHub Sponsor": "https://github.com/sponsors",
    		"Patreon": "https://www.patreon.com/"
    	}
    }
  4. Define and implement plugin settings

    master

    To manage plugin configuration in Obsidian, you should define a settings interface, a constant for default values, and a class extending PluginSettingTab to render the UI.

    1. Define the interface: Create an interface (e.g., MyPluginSettings) representing your configuration keys.
    2. Set defaults: Create a DEFAULT_SETTINGS object implementing that interface.
    3. Create the Settings Tab: Extend PluginSettingTab. In the display() method, use the Setting class to build the UI.
    4. Handle updates: When a user changes a value in the UI (e.g., via .onChange()), update the plugin's settings object and call this.plugin.saveSettings() to persist the changes to disk.
    import { App, PluginSettingTab, Setting } from 'obsidian';
    
    export interface MyPluginSettings {
    	mySetting: string;
    }
    
    export const DEFAULT_SETTINGS: MyPluginSettings = {
    	mySetting: 'default',
    };
    
    export class SampleSettingTab extends PluginSettingTab {
    	plugin: MyPlugin;
    
    	constructor(app: App, plugin: MyPlugin) {
    		super(app, plugin);
    		this.plugin = plugin;
    	}
    
    	display(): void {
    		const { containerEl } = this;
    		containerEl.empty();
    
    		new Setting(containerEl)
    			.setName('Settings #1')
    			.setDesc("It's a secret")
    			.addText((text) =>
    				text
    					.setPlaceholder('Enter your secret')
    					.setValue(this.plugin.settings.mySetting)
    					.onChange(async (value) => {
    						this.plugin.settings.mySetting = value;
    						await this.plugin.saveSettings();
    					}),
    			);
    	}
    }
  5. Implement the MyPlugin class

    master
    To create an Obsidian plugin, extend the Plugin class and implement the onload() lifecycle method. The onload() method is where you register ribbon icons, status bar items, commands, settings tabs, and event listeners. Use onunload() to perform any necessary cleanup if you are not using Obsidian's automatic registration methods (like registerDomEvent or registerInterval).
  6. Add commands to the Command Palette

    master

    You can add three types of commands using this.addCommand():

    1. Simple Command: Uses callback to run logic regardless of context.
    2. Editor Command: Uses editorCallback to provide access to the current Editor instance and the active MarkdownView or MarkdownFileInfo.
    3. Complex Command: Uses checkCallback to conditionally show the command in the Command Palette. The checking parameter is true when Obsidian is verifying if the command is available, and false when the command is actually being executed.
    // Simple command
    this.addCommand({
    	id: 'open-modal-simple',
    	name: 'Open modal (simple)',
    	callback: () => {
    		new SampleModal(this.app).open();
    	},
    });
    
    // Editor command
    this.addCommand({
    	id: 'replace-selected',
    	name: 'Replace selected content',
    	editorCallback: (editor, _ctx) => {
    		editor.replaceSelection('Sample editor command');
    	},
    });
    
    // Complex command with conditional visibility
    this.addCommand({
    	id: 'open-modal-complex',
    	name: 'Open modal (complex)',
    	checkCallback: (checking: boolean) => {
    		const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);
    		if (markdownView) {
    			if (!checking) {
    				new SampleModal(this.app).open();
    			}
    			return true; // Command is visible
    		}
    		return false; // Command is hidden
    	},
    });
  7. Manage plugin settings

    master

    Use this.loadData() and this.saveData(data) to persist settings. It is recommended to merge loaded data with DEFAULT_SETTINGS using Object.assign to ensure all configuration keys exist.

    async loadSettings() {
    	this.settings = Object.assign(
    		{},
    		DEFAULT_SETTINGS,
    		(await this.loadData()) as Partial<MyPluginSettings>,
    	);
    }
    
    async saveSettings() {
    	await this.saveData(this.settings);
    }
  8. Register DOM events and intervals

    master

    To ensure resources are cleaned up automatically when the plugin is disabled, use this.registerDomEvent() and this.registerInterval(). These methods automatically remove the event listener or clear the interval when the plugin unloads.

    // Register a DOM event
    this.registerDomEvent(activeDocument, 'click', (_evt: MouseEvent) => {
    	new Notice('Click');
    });
    
    // Register an interval
    this.registerInterval(
    	window.setInterval(() => console.log('setInterval'), 5 * 60 * 1000),
    );