Skip to main content

Tool Plugin

Tools are a different way to extend your visual editor. They allow you to improve your productivity by adding some functionality to the editor. Two examples of Tools are importing and exporting content or a custom clipboard.

Tools are specific to stories and will appear in your Visual Editor when editing a story. You can access the installed tools from the top bar {1}. Here we have installed the Import Translatable Fields {2}.

app.storyblok.com
Tools
1
2

Getting Started

To create a new tool you need to be signed up as a Partner. Head into the partner portal and click on Apps {1} and then the New App button {2}. As App type select Tool {3} and click Save {4}.

app.storyblok.com
Create New Tool
1
2
3
4

Create New Tool

To get started we will clone the tool plugin starter template: github.com/storyblok/storyblok-tool-example

$ git clone https://github.com/storyblok/storyblok-tool-example.git
$ cd storyblok-tool-example
$ npm install 

You will need to add the tunnel URL to the development settings in your tool settings. Open your tool and go to Oauth 2 {1} You need a URL to the app, e.g. the tunnel URL + auth/connect/storyblok{4} and an Oauth2 callback, e.g. the tunnel URL + auth/callback{5}.

We will need to install ngrok to create a tunnel to our local application. Once you installed ngrok, you can start the tunnel to port 3000.

npm i -g ngrok 
ngrok http 3000

app.storyblok.com
Tool Settings
1
2
3
4
5

Tool Settings

Inside the starter, you will find a .env-example file. Rename this file to .env and fill in the client id {2} and client secret {3} as well as the Oauth2 callback {5}.

.env.local
CONFIDENTIAL_CLIENT_ID="Id from Storyblok App"
CONFIDENTIAL_CLIENT_SECRET="Secret from Storyblok App"
CONFIDENTIAL_CLIENT_REDIRECT_URI=https://YOUR_ID.ngrok.io/auth/callback

Now we can start our development server:

npm run dev

Now if you open http://localhost:3000/ it should redirect to Storyblok, but nothing happens. In order to test it, we first need to install our tool plugin in a specific space. To install the plugin go to the General tab {1} and copy the Install Link {2} and open it in a new tab.

app.storyblok.com
General Settings
1
2

General Settings

You will see a screen to install the app. Here you can select the space {1} you want to install the tool in. After selecting the space, click on the Install app button {2}

app.storyblok.com
Installing Plugin
1
2

Installing the Tool

After installation, you will be redirected to the App Directory of the space for which you installed the tool and you will be able to see the tool under the Installed section.

Now, go to the content section and open a story.

HINT:

Make sure to append ?dev=1 in the end of your url like app.storyblok.com/#!/me/spaces/1/apps/1/detail?dev=1 to open the app with the development URL.

Inside the story, go to the Tools section {1}. The first time you should see a confirmation screen inside the installed tool window to authorize the application to have access to Storyblok. Click Approve {2}.

app.storyblok.com
Approving the tool
1
2

Approving the tool

Once you authenticate your tool you should be able to see it working.

app.storyblok.com
Working tool

Tool in action

Reading the Story Context

Inside a tool, you can use the context to get the data of the current story. For that you have to use two window events: message and postMessage.

First, we let Storyblok know that there is a tool via the following event. Make sure that name of the tool you created matches the name in the tool parameter.

window.parent.postMessage({
  action: 'tool-changed', 
  tool: 'storyblok-gmbh@my-test-tool', 
  event: 'getContext'
}, 'https://app.storyblok.com')

After that Storyblok will reply with the Story context, so we need to listen for that with the following listener:

 window.addEventListener('message', this.processMessage, false)

Finally, we need to connect everything and add the processMessage method to set our local component data:

export default {
  data() {
    return {
      story: {},
      loadingContext: true
    }
  },

  mounted() {
    // redirects you to Storyblok
    if (window.top === window.self) {
      window.location.assign('https://app.storyblok.com/oauth/tool_redirect')
    }
    // listens for Storyblok answer
    window.addEventListener('message', this.processMessage, false)
    // Use getContext to get the current story
    window.parent.postMessage({action: 'tool-changed', tool: 'storyblok-gmbh@my-test-tool', event: 'getContext'}, 'https://app.storyblok.com')
  },
  methods: {
    processMessage(event) {
      // processes the event answer
      if (event.data && event.data.action == 'get-context') {
        this.loadingContext = false
        // get the context story
        this.story = event.data.story
        // get the context language
        this.language = event.data.language
      }
    }
  }
}

Changing the Height of the Tool

It's possible to change the height of the tool by sending an event with the name heightChange with a height parameter to the parent window

window.parent.postMessage({
  action: 'tool-changed',
  tool: 'storyblok-gmbh@my-test-tool',
  event: 'heightChange',
  height: 500}, 
'https://app.storyblok.com')

Reading the Editor Language

It's possible to get the current language from the get-context event.

export default {

  mounted() {
    window.addEventListener('message', this.processMessage, false)
    window.parent.postMessage({action: 'tool-changed', tool: 'storyblok-gmbh@my-test-tool', event: 'getContext'}, 'https://app.storyblok.com')
  },
  methods: {
    processMessage(event) {
      if (event.data && event.data.action == 'get-context') {
        this.language = event.data.language
      }
    }
  }
}

Changing Content via the API

Tools work with the storyblok-nuxt-auth module to retrieve and change data from Storyblok via the Storyblok Management API. Inside of a tool you can get for example the user information with the following request:

axios.get('/auth/user', {params: {space_id: this.$route.query.space_id}})
      .then((response) => {
        console.log(response.data)
      })

You can also change stories inside of Storyblok by making post or put requests. You can create for example a new story with the following code:

import axios from 'axios'

export default {
  data() {
    return {
      loading: false,
      story: {
        name: ''
      }
    }
  },
  methods: {
    createStory() {
      this.loading = true

      // The request body is the same from Management API
      // https://www.storyblok.com/docs/api/management#core-resources/stories/create-story
      const body = {
        story: { ...this.story }
      }

      // get the space id from URL and use it in requests
      return axios
        .post(`/auth/spaces/${this.$route.query.space_id}/stories`, body)
        .then((res) => {
          this.loading = false
        })
      }
  }
}