Building the Ultimate Obsidian-to-WordPress Bridge: A Deep Dive

I love Obsidian. It's my second brain. I write everything in it—code snippets, daily logs, architectural plans, and yes, blog posts. But getting those posts into WordPress? That was a friction-filled nightmare that killed my writing flow.

Copy-pasting text is easy. But images? That’s where the dream dies. You have to export them, upload them to the WordPress Media Library, get the URL, and manually replace every single link in your post. If you have 10 screenshots, that’s 10 minutes of mindless clicking. And don't get me started on videos or updating a post after you find a typo.

I tried existing plugins. Some were abandoned years ago. Others broke when I used "Wiki Links" (![[image.png]]). None of them handled video correctly.

So, I built my own: Obsidian WP Publisher.

The Goal

I didn't want a "comprehensive solution" with a million settings. I wanted a tool that does one thing perfectly: takes my Markdown note and puts it on my WordPress site, exactly as I see it.

My requirements were strict:

  1. Zero Friction Media: Automatically upload images and videos found in the note.
  2. Idempotency: If I publish a note again, it must update the existing post, not create a duplicate.
  3. Metadata Support: Use YAML frontmatter for titles, slugs, categories, and tags.
  4. Native Obsidian Feel: Support both standard Markdown links and Obsidian's Wiki links.

How It Works (The Architecture)

The plugin is built in TypeScript using the Obsidian API. It communicates with WordPress via the standard REST API.

1. Authentication

I chose Application Passwords over OAuth. Why? Because for a personal tool, OAuth is over-engineering. Application Passwords are secure, easy to generate in WordPress (Users -> Profile), and work perfectly with Basic Auth.

2. The Publishing Pipeline

When you hit "Publish", the plugin executes a linear pipeline:

  1. Frontmatter Parsing: It reads the YAML block to get the slug, title, categories, and tags.
  2. Post Resolution: It queries WordPress: "Do you already have a post with this slug?"
    • If Yes: We get its ID and prepare for an UPDATE.
    • If No: We prepare for a CREATE.
  3. Taxonomy Handling: It checks if the specified Categories and Tags exist. If not, it creates them on the fly and retrieves their IDs.
  4. Media Processing (The Hard Part):
    • The plugin scans the content for image (.png, .jpg) and video (.mp4, .webm) links.
    • It supports both ![[image.png]] and ![alt](image.png) syntax.
    • For each file, it reads the binary data directly from the Obsidian Vault.
    • It uploads the file to the WordPress Media Library (POST /wp-json/wp/v2/media).
    • It replaces the local link in the content with the new remote URL (or a <video> tag for videos).
  5. Markdown Conversion: WordPress expects HTML. Sending raw Markdown results in a mess. I integrated the marked library to convert the processed Markdown into clean, semantic HTML.
  6. Final Push: It sends the payload (HTML content, title, featured image ID, taxonomy IDs) to WordPress.

Key Technical Challenges

Handling "Wiki Links"

Obsidian users love ![[link]]. Standard Markdown parsers hate them. I had to write a custom regex parser to identify these links, resolve their real path in the Vault (which might be in a subfolder), and upload them correctly.

Video Support

WordPress doesn't automatically embed videos from raw URLs in the content. I added logic to detect video extensions (.mp4, .mov) and generate a native HTML5 <video controls> tag instead of a simple <img> tag.

The "Update" Logic

Most plugins just create new posts. To enable updates, I used the slug as the unique key.

// Simplified logic
let existingPost = await api.getPostBySlug(slug);
if (existingPost) {
    await api.updatePost(existingPost.id, postData);
} else {
    await api.createPost(postData);
}

How to Run It

I’ve open-sourced the project. You don't need to be a developer to use it, but you do need to install it manually for now (until it's in the community list).

Installation

  1. Go to the GitHub Releases page.
  2. Download main.js, manifest.json, and styles.css.
  3. Create a folder in your vault: .obsidian/plugins/obsidian-wp-publisher.
  4. Drop the files there.
  5. Reload Obsidian and enable the plugin in Community Plugins.

Configuration

  1. Go to Settings -> Obsidian WP Publisher.
  2. WordPress URL: https://your-site.com
  3. Username: Your WordPress login.
  4. Application Password: Generate one in your WordPress User Profile.

Usage

Add frontmatter to your note:

---
title: "My Awesome Post"
slug: "my-awesome-post"
categories: ["Tech"]
tags: ["Obsidian", "Guide"]
featured_image: "cover.png"
---

Then open the Command Palette (Ctrl+P) and run "Obsidian WP Publisher: Publish".

Conclusion

This tool bridged the gap between my thinking environment (Obsidian) and my publishing environment (WordPress). It removed the friction, which means I write more and ship more.

If you're a developer, check out the code on GitHub. Pull requests are welcome!

Leave a comment

👁️ Views: 909