Using Ghost with Drafts

Using Drafts with Ghost

Ghost is an open-source CMS/Blogging platform. Drafts supports integration both for creating posts on a Ghost-powered site, and scripting more advanced integrations through the Ghost Admin API.

Authorization

The first time you use any Ghost-integrated actions in Drafts, you will be prompted to provide two pieces of information:

  • The URL of your Ghost site. This should be provided as the full URL to the home page of the site, like https://my-ghost-blog.com/
  • Your Ghost “staff access token.” Obtain your token from your profile in Ghost admin. Visit your admin page, select your account at the bottom left, then “Your Profile”.

You will only be prompted once for this information, if you enter it incorrectly, or need to update your token later, you can forget your Ghost credentials in Drafts Settings.

“Ghost” Action Step

The “Ghost” action step provides a simplified method to post to Ghost with a number of common options, the values of which are generated with Drafts’ template tags. Start by installing this example action:

  • Post to Ghost: Creates a draft post in Ghost with the first line of the draft as title, and remaining text as content. As configured, the post will be created with “Draft” status.

After install, see action step documentation for details on configurable options. For example, you might with to change the defeat behavior to create posts in published status, or visible only to members.

Scripting Ghost API

In addition to the convenience of the Ghost action step, Drafts provides the Ghost script object, which provides a wrapper for making requests to any available endpoint in the Ghost Admin API. This allow importing data from Ghost, updating existing posts, and more.

Using the API directly requires an understanding of the API but simplifies access by taking care of authentication, and marshaling JSON request and result data to and from Javascript objects for you.

A couple of example actions demonstrate usage:

  • Post to Ghost with Options: A scripted action to create a post that prompts the user to select a variety of options for the post before creating it.
  • List Posts from Ghost: Imports recents posts from Ghost, and creates a new draft with a Markdown list of post titles and links.

About Markdown, HTML and Ghost

Ghost stores content in a native structured format, and, of course, publishes at HTML. The integrations in Drafts send content to Ghost as HTML, which is supported by their API. Generally, we recommend writing in Markdown, and the default behavior of the actions above is to convert your Markdown to HTML to upload.

Conclusion

These examples should get you started with basic Ghost integration. Please feel free to ask if you have additional questions.

4 Likes

I publish to multiple Ghost blogs. Is there any way that I can store the credentials of multiple Ghost blogs at the same time? Needing to access the settings, clear credentials, and then paste the staff token in each time means that it’s actually more convenient just to publish to Ghost myself.

You need to duplicate the actions and change the Ghost blog credential ID a little. Then you will be able to tie each set to a set of credentials.

See this section on multiple accounts.

Where can I edit the Ghost blog credential ID in the duplicated action? This is all I see in the action editor:

And the code is:

// configure title and body
// body should contain HTML, so pre-process Markdown
const title = draft.processTemplate("[[display_title]]")
const body = draft.processTemplate("%%[[body]]%%")

let f = () => {
	// prompt for options
	let p = new Prompt()
	p.title = "Ghost Options"
	p.message = "Select options for this Ghost post."
	
	p.addTextField("slug", "Slug", "")
	p.addTextView("excerpt", "Excerpt", "")
	p.addLabel("Status", "Status")
	p.addTextField("tags", "Tags (comma-separated)", "")
	p.addSwitch("featured", "Featured", false)
	p.addSegmentedControl("status", "Status", ["Draft", "Published"], "Draft")
	p.addButton("Post")
	
	if (!p.show()) { return false }

	// construct data to send to Ghost API
	// see API docs for details: https://ghost.org/docs/admin-api/#creating-a-post
	let post = {
		"title": title,
		"html": body,
		"status": p.fieldValues["status"].toLowerCase(),
		"featured": p.fieldValues["featured"]		
	}
	let slug = p.fieldValues["slug"]
	if (slug.length > 0) {
		post["slug"] = slug
	}
	let excerpt = p.fieldValues["excerpt"]
	if (excerpt.length > 0) {
		post["custom_excerpt"] = excerpt
	}
	let tags = p.fieldValues["tags"]
    if (tags.length > 0) {
		post["tags"] = tags.split(",").map(t => t.trim())
	}
	let data = {
		"posts": [
			post
		]
	}

	// make request to API
	let g = new Ghost()
	let response = g.request({
		"path": "/admin/posts/",
		"method": "POST",
		"parameters": {"source": "html"},
      "data": data
	})
	if (response.success) {
		let url = response.responseData["posts"][0]["url"]
		if (url) {
			console.log(`Ghost Post Created: ${url}`)
		}
		console.log(response.responseText)
	}
	else {
		console.log(`Ghost Post Failed: ${response.statusCode}
${response.responseText}
`)
		context.fail()
	}
	return true
}

if (!f()) {
	context.cancel()
}



I don’t see any references to the ID that I can change.

Most scripting object, [Ghost included(Ghost | Drafts Script Reference), take an optional identifier parameter in their initializer to specify alternate credentials to use.


// change this…
let ghost = new Ghost()

// to…
let ghost = new Ghost("Blog Name")

Thanks! That makes sense. I appreciate the link to the docs! I wasn’t aware of those docs, so that’s helpful.

I’m finding that even with an identifier though, all actions that use Ghost seem to be using the same instance, so I can’t get it to use two separate sets of credentials.

I see an issue here with the intializers. Due to an oddity with the Javascript-Swift bridging you have to init the Ghost object with the create constructor for an alternate identifier to be used. Try this:

let g = Ghost.create("Blog Name")

That works. Thanks! FWIW, it might be worth updating the code in the official plugin.