Skip to content

First spike for Roam to WP plugin

Status update on getting the first “spike/prototype” of code working.

Scaffolding initial plugin code

I’ve looked into a number of scaffolding solutions:

I’ve initially tried to use WordPress Plugin Boilerplate Powered but it generated so much boilerplate code that it was just too much work to actually write my own code.

So I ended up using wp scaffold that produced a very nice skeleton that I could start writing code into.

Settings Screen

I first needed to build a screen where I could upload my exported data. Final result looks like this for now:

What was really useful in this research was article by Delicious Brains – 5 Ways to Create a WordPress Plugin Settings Page. I ended up using Carbon Fields as I didn’t want to invest too much time into scaffolding my own HTML Form code just to process a few fields.

Processing the data export

For now the general idea is that I only need to look at the first level of blocks inside Roam. So I’ll have structure like this:

  "create-time": 1621153344466,
  "title": "!Resources/BASB/Reviews",
"children": [
  "string": "Wordpress:: #publish",
  ":create/user": {
    ":user/uid": "D9GErGIgWMcqL1SJ9egralKACQ62"

and I need to find all blocks that have somewhere in the first level of children a string that matches "Wordpress:: #publish". The problem is that tree searching libraries like jsonq only return the matching child node but not the parent structure.

No problem we just need to write a single node depth search:

function extract_nodes_to_publish( array $data ): array {
	$rules = \preg_split( "/\r\n|\n|\r/", carbon_get_theme_option( 'rtw_import_rules' ) );
	if ( ! $rules ) {
		return [];

	$matching_pages = [];
	foreach ( array_splice( $data, 0 ) as $page ) {
		if ( isset( $page['children'] ) ) {
			foreach ( $page['children'] as $block ) {
				if ( in_array( $block['string'], $rules ) ) {
					ray( $block['string'] );
					$matching_pages[] = $page;

	return $matching_pages;

Rendering whole content tree

After we have a list of pages that match we need to render whole Roam content page that is in Markdown strings into HTML. Since I’ve been inspired by “Roam Blocks” plugin I’ve decided to reuse their function that does that:

First rendered page

With a bit more glue code I can already see how this plugin creates a new Note custom post types and inserts a page that I tagged with #publish:

Next steps

  • Figure out how to grab Title:: attribute if present so I don’t need to expose internal Roam page titles
  • Figure out what should be a bullet and what should be just a paragraph.
  • Publish to Github so maybe some other brave soul could give it a try