Write an intermediate blueprint plugin

Applicable:

This tutorial applies to Confluence Server 5.1 and higher.

Level of experience:

Intermediate.

This tutorial will create a plugin that can only be installed on Confluence Server. To create a blueprint for Confluence Cloud head to Multi-page Blueprints with Confluence Connect.


Overview of the tutorial

If you successfully completed Write a simple Confluence Blueprint plugin you have a functional but basic Blueprint plugin.  In this tutorial, you create a blueprint that populates its template with data.  You can populate a template by implementing a ContextProvider class in your plugin. You can also populate a template by creating an interactive wizard using Javascript.  In this tutorial, you do both.

Plugin source

If you want to skip ahead or check your work when you finish, you can find the plugin source code on Atlassian Bitbucket. Bitbucket serves a public Git repository containing the tutorial's code. Alternatively, you can download the source as a ZIP archive To clone the repository, issue the following command:

git clone https://bitbucket.org/atlassian_tutorial/confluence-populated-blueprint.git

About these Instructions

You can use any supported combination of OS and IDE to create this plugin. These instructions were written using Eclipse Classic Version 3.7.1 on Mac OS X. If you are using another OS or IDE combination, you should use the equivalent operations for your specific environment.

This tutorial was last tested with Confluence 5.10.1 using the Atlassian SDK 6.2.6.

Step 1. Add a variable and some instructional text to the template 

In this step, you'll add a variable to the template you created in the Write a simple Confluence Blueprint plugin.  If you don't have that code, you can can download the source as a ZIP archive of the project to use.

  1. Open a terminal and navigate to the root of the project.
  2. Edit the src/main/resources/templates/mytemplate.xml file.
  3. Replace the Enter your name here text with a variable:

    <td><at:var at:name="vName"/></td>
  4. Add a placeholder around the Enter today's date here text to make it instructional:

    <td><ac:placeholder>Enter today's date here</ac:placeholder></td>
      Click to check your work against the entire file.
    <table>
      <tbody>
        <tr>
          <th>Name</th>
          <th>Date</th>
        </tr>
        <tr>
          <td><at:var at:name="vName"/></td>
          <td><ac:placeholder>Enter today's date here</ac:placeholder></td>
        </tr>
      </tbody>
    </table>
  5. Save and close the file.

Confluence does not support adding <at:var> elements inside of other <at:> namespace elements. For example, an <at:var> inside a macro parameter renders correctly for the end-user creating a page, but an admin subsequently editing the template will not be able to edit the variable as the macro will not render.

 The recommended workaround is to make the entire macro element an <at:var> in the template. To correctly insert XHTML from a variable into the template, you'll need to define the variable with an extra "rawxhtml" attribute, like so:

<at:var at:name="myNameWithSomeXhtmlInIt" at:rawxhtml="true"/>

If the at:rawxhtml attribute is not present, the system escapes all XHTML in the attribute value when rendering.

Step 2. Add a new dependency to the pom.xml file

In this step, you add a new dependencies to your pom.xml file. The Blueprint API is provided by a plugin called the confluence-create-content-plugin. To interact with the API, you need to add a dependency in your project's pom.xml.

  1. Edit the pom.xml file in your project's root.
  2. Add two dependency elements to the confluence-create-content-plugin artifact. 
    Make sure you added it in the <dependencies/> section.

    <dependency>
       <groupId>com.atlassian.confluence.plugins</groupId>
       <artifactId>confluence-create-content-plugin</artifactId>
       <version>${create.content.version}</version>
       <scope>provided</scope>
    </dependency>
  3. Scroll to file's end and locate the <properites/> block.
  4. Add the create-content-version  element.

    <create.content.version>6.0.13</create.content.version>
      Click to see how your pom.xml file should look now.
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.example.plugins.tutorial.confluence.simplebp</groupId>
        <artifactId>simplebp</artifactId>
        <version>1.0-SNAPSHOT</version>
        <organization>
            <name>Example Company</name>
            <url>http://www.example.com/</url>
        </organization>
        <name>simplebp</name>
        <description>This is the com.example.plugins.tutorial.confluence.simplebp:simplebp plugin for Atlassian Confluence.</description>
        <packaging>atlassian-plugin</packaging>
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.10</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>com.atlassian.confluence</groupId>
                <artifactId>confluence</artifactId>
                <version>${confluence.version}</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>com.atlassian.confluence.plugins</groupId>
                <artifactId>confluence-create-content-plugin</artifactId>
                <version>${create.content.version}</version>
                <scope>provided</scope>
            </dependency>
            <!-- WIRED TEST RUNNER DEPENDENCIES -->
            <dependency>
                <groupId>com.atlassian.plugins</groupId>
                <artifactId>atlassian-plugins-osgi-testrunner</artifactId>
                <version>${plugin.testrunner.version}</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>javax.ws.rs</groupId>
                <artifactId>jsr311-api</artifactId>
                <version>1.1.1</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>com.google.code.gson</groupId>
                <artifactId>gson</artifactId>
                <version>2.2.2-atlassian-1</version>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>com.atlassian.maven.plugins</groupId>
                    <artifactId>maven-confluence-plugin</artifactId>
                    <version>${amps.version}</version>
                    <extensions>true</extensions>
                    <configuration>
                        <productVersion>${confluence.version}</productVersion>
                        <productDataVersion>${confluence.data.version}</productDataVersion>
                    </configuration>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.6</source>
                        <target>1.6</target>
                    </configuration>
                </plugin>
            </plugins>
        </build>
        <properties>
            <confluence.version>5.10.1</confluence.version>
            <confluence.data.version>5.10.1</confluence.data.version>
            <create.content.version>6.0.13</create.content.version>
            <amps.version>6.2.4</amps.version>
            <plugin.testrunner.version>1.2.3</plugin.testrunner.version>
        </properties>
    </project>
  5. Save and close the pom.xml file.

Step 3. Implement a simple ContextProvider

In this step, you create a simple implementation of a com.atlassian.plugin.web.ContextProvider interface by extending the com.atlassian.confluence.plugins.createcontent.api.contextproviders.AbstractBlueprintContextProviderYou can inject into your ContextProvider any components available to the Confluence plugin system.  Once you add the provider Java code, you need to specify where it resides for the plugin system. You do this in the content-template module of your atlassian-plugin.xml file.

 

  1. Create a MyContextProvider.java file in the src/main/java/com/example/plugins/tutorial/confluence/simplebp directory. 
  2. Your class should extend com.atlassian.confluence.plugins.createcontent.api.contextproviders.AbstractBlueprintContextProvider. The AbstractBlueprintContextProvider implements ContextProvider and provides additional Blueprint-specific behaviour.

    package com.example.plugins.tutorial.confluence.simplebp;
    
    import com.atlassian.confluence.plugins.createcontent.api.contextproviders.AbstractBlueprintContextProvider;
    import com.atlassian.confluence.plugins.createcontent.api.contextproviders.BlueprintContext;
    
    public class MyContextProvider extends AbstractBlueprintContextProvider {
        
    }
  3. Override the updateBlueprintContext() method:

    package com.example.plugins.tutorial.confluence.simplebp;
    
    import com.atlassian.confluence.plugins.createcontent.api.contextproviders.AbstractBlueprintContextProvider;
    import com.atlassian.confluence.plugins.createcontent.api.contextproviders.BlueprintContext;
    
    public class MyContextProvider extends AbstractBlueprintContextProvider {
    	@Override
        protected BlueprintContext updateBlueprintContext(BlueprintContext blueprintContext)
        {
            blueprintContext.put("vName", "Sherlock");
            return blueprintContext;
        }
    }
  4. Save and close the file.
  5. Open the atlassian-plugin.xml file.
  6. Locate the content-template module.
  7. Specify a context-provider sub element.

    <content-template key="simplebp-template" template-title-key="my.blueprint.title">
      <resource name="template" type="download" location="xml/template-body.xml"/>
      <context-provider class="com.example.plugins.tutorial.confluence.simplebp.MyContextProvider"/>
    </content-template> 
      Click check your work against the entire atlassian-plugin.xml file.
    <atlassian-plugin key="${project.groupId}.${project.artifactId}" name="${project.name}" plugins-version="2">
        <plugin-info>
            <description>${project.description}</description>
            <version>${project.version}</version>
            <vendor name="${project.organization.name}" url="${project.organization.url}" />
            <param name="plugin-icon">images/pluginIcon.png</param>
            <param name="plugin-logo">images/pluginLogo.png</param>
        </plugin-info>
        <!-- add our i18n resource -->
        <resource type="i18n" name="i18n" location="simplebp"/>
        
        <!-- add our web resources -->
        <web-resource key="simplebp-resources" name="simplebp Web Resources">
            <dependency>com.atlassian.auiplugin:ajs</dependency>
            
            <resource type="download" name="simplebp.css" location="/css/simplebp.css"/>
            <resource type="download" name="simplebp.js" location="/js/simplebp.js"/>
            <resource type="download" name="images/" location="/images"/>
            <context>simplebp</context>
        </web-resource>
        
        <!-- Blueprint -->
        <blueprint key="my-blueprint" content-template-key="simplebp-template" index-key="my-index" />
        
        <!-- Add to the Create Menu -->
        <web-item key="create-by-sample-template" i18n-name-key="my.create-link.title" section="system.create.dialog/content">
    		<description key="my.create-link.description" />
    		<resource name="icon" type="download" location="/images/myblueprint.png" />
    		<param name="blueprintKey" value="my-blueprint" />
         </web-item>
        
        
        <!-- Template for Blueprint -->
        <content-template key="simplebp-template" template-title-key="my.blueprint.title">
    		<resource name="template" type="download" location="/templates/mytemplate.xml" />
    		<context-provider class="com.example.plugins.tutorial.confluence.simplebp.MyContextProvider"/>
    	</content-template>
            
        
        <!-- import from the product container -->
        <component-import key="applicationProperties" interface="com.atlassian.sal.api.ApplicationProperties" />
        
    </atlassian-plugin>
  8. Save and close the file.

Step 4. Test your plugin 

At this point, you've added some instructional text, a form field, and a way to fill out the field.  Now is a good point to test your code.

  1. Use the atlas-run command to start a local Confluence instance.
  2. Run the following command:

    atlas-run

    This command takes a minute or so to run. It builds your plugin code, starts a Confluence instance, and installs your plugin. When the process has finished, you will see many status lines on your screen concluding with something like the following:

    [INFO] confluence started successfully in 132s at http://localhost:1990/confluence
    [INFO] Type Ctrl-D to shutdown gracefully
    [INFO] Type Ctrl-C to exit

    You'll see the output includes a URL for the Confluence instance.

  3. Log into the instance as user admin using a password of admin.
    The Confluence Dashboard appears.
  4. Choose Spaces  from the menu bar. 
  5. Select the Demonstration Space.
    The system places you in the space home. 
  6. Press the Create button at the top of the page.
    The system displays the Create dialog.
  7. Select your blue print and create a new page.
    Your should see the new page filled with the context and instructional text you defined.
  8. Shut down the atlas-run process (a full restart is required in this case, and QuickReload will not work.

Step 5. Add a Soy template and support it with Javascript

In this example, you write a basic Soy (Closure) template file.  A Soy template file is a way of dynamically building an HTML file and UI.   Atlassian Soy is Atlassian's implementation of Google Closure. You'll use the Soy template to write a wizard for your blueprint.  This tutorial doesn't really describe in depth on either Soy or Closure; you can learn more about them here.  Once you describe your wizard in Soy, you write a simple blueprint-wizard.js file. The Javascript file registers the wizard and calls the Soy template.

  1. Add a soy subdirectory to the src/main/resources directory.
  2. Create a file called simplebp.soy to this new directory.
  3. Edit the simplebp.soy file and add this content:

    {namespace MyPlugin.Blueprints.Simple}
    /**
    *  A form that accepts a person's name
    */
    {template .page1Form}
     	<form action="#" method="post" class="aui">
     	  <fieldset>
     	    <div class="field-group">
     	        <label for="vname">{getText('my.blueprint.form.label.title.vName')}</label>
     	        <input id="vname" class="text" type="text" name="vName">
     	    </div>
     	  </fieldset>
     	</form>
    {/template}

    The template defines a single page, page1Form, that contains a one-field form. You'll reference the namespace value from your Javascript and later from the atlassian-plugin.xml file.  You also specify a label value that you need to add to your i18n strings.

  4. Save and close the simplebp.soy file.

  5. Edit the simplebp.properties file
  6. Add the my.blueprint.form.label.title to the file.

    my.blueprint.form.label.title.vName=Name
    my.blueprint.wizard.page1.title=Simplebp WIZARD
      Click to check against the whole file.
    #put any key/value pairs here
    my.plugin.name=MyPlugin
    my.blueprint.title=Sample Template
    my.create-link.title=My Sample Template
    my.create-link.description=Create a new SimpleBB template
    my.blueprint.form.label.title.vName=Name
    my.blueprint.wizard.page1.title=Simplebp WIZARD
  7. Save and close the simplebp.properties file.
  8. Edit the src/main/resources/js/simplebp.js file in your project.
  9. At the top of the file, call the setWizard() Javascript API:

    Confluence.Blueprint.setWizard('com.example.plugins.tutorial.confluence.simplebp.simplebp:create-by-sample-template', function(wizard) {});

    The setWizard(() method takes the fully qualified pathname to the web-item that creates the blueprint link.  The fully qualified pathname takes the format:
     ${project.groupId}.${artifactId}:web-item-name.
    Your atlassian-plugin.xml file defines the project's groupId and artifactId values.

  10. Save and close the simplebp.js file.

Step 6. Update the atlassian-plugin.xml file and test

In the previous steps, you add some dependencies to your pom.xml file.  You also used a Soy template to specify a Wizard page and wrote a Javascript file to call it. In this step, you update the web-resource component in your atlassian-plugin.xml file to access the dependencies.  You'll modify the content-template module to remove the context-provider element; the user fills in the Name through the wizard. You'll add a dilaog-wizard element to the <blueprint/> module. The dialog-wizard element describes each dialog-page in your wizard. A dialog-page  has three required attributes:

Field Description
id A unique identifier.
template-key A fully-qualified Soy template reference. The template defines the page content.
title-key The i18n key for the page's title.

When you are done updating your atlassian-plugin.xml file, you'll run your plugin and see the Wizard in action.

  1. Edit the src/main/resources/atlassian-plugin.xml file.
  2. Locate the <web-resource/> module.
    The SDK atlas-create-confluence-plugin command generates this module for you. 
  3. Add a <dependency> element for the confluence-create-content-plugin.

    <!-- add our web resources -->
    <web-resource key="simplebp-resources" name="simplebp Web Resources">
        <dependency>com.atlassian.auiplugin:ajs</dependency>
        <dependency>com.atlassian.confluence.plugins.confluence-create-content-plugin:resources</dependency>
    
        <resource type="download" name="simplebp.css" location="/css/simplebp.css" />
        <resource type="download" name="simplebp.js" location="/js/simplebp.js" />
        <resource type="download" name="images/" location="/images" />
    
        <context>simplebp</context>
    </web-resource>
  4. Add a <transformation/> module for soy.

    <!-- add our web resources -->
    <web-resource key="simplebp-resources" name="simplebp Web Resources">
        <dependency>com.atlassian.auiplugin:ajs</dependency>
        <dependency>com.atlassian.confluence.plugins.confluence-create-content-plugin:resources</dependency>
    
        <transformation extension="soy">
            <transformer key="soyTransformer">
                <functions>com.atlassian.confluence.plugins.soy:soy-core-functions
                </functions>
            </transformer>
        </transformation>
    
        <resource type="download" name="simplebp.css" location="/css/simplebp.css" />
        <resource type="download" name="simplebp.js" location="/js/simplebp.js" />
        <resource type="download" name="images/" location="/images" />
    
        <context>simplebp</context>
    </web-resource>

     

  5. Add an resource for your soy template right before the /images entry.
    When, specifying the name value, append .js to the template name. This notifies the plugin system that your Soy resource transforms to Javascript on the client.

    <!-- add our web resources -->
    <web-resource key="simplebp-resources" name="simplebp Web Resources">
        <dependency>com.atlassian.auiplugin:ajs</dependency>
        <dependency>com.atlassian.confluence.plugins.confluence-create-content-plugin:resources</dependency>
    
        <transformation extension="soy">
            <transformer key="soyTransformer">
                <functions>com.atlassian.confluence.plugins.soy:soy-core-functions
                </functions>
            </transformer>
        </transformation>
    
        <resource type="download" name="simplebp.css" location="/css/simplebp.css" />
        <resource type="download" name="simplebp.js" location="/js/simplebp.js" />
        <resource type="download" name="simplebp.soy.js" location="/soy/simplebp.soy" />
        <resource type="download" name="images/" location="/images" />
    
        <context>simplebp</context>
    </web-resource>

     

  6. Add two context elements after the simplebp entry.

    <!-- add our web resources -->
    <web-resource key="simplebp-resources" name="simplebp Web Resources">
        <dependency>com.atlassian.auiplugin:ajs</dependency>
        <dependency>com.atlassian.confluence.plugins.confluence-create-content-plugin:resources</dependency>
    
        <transformation extension="soy">
            <transformer key="soyTransformer">
                <functions>com.atlassian.confluence.plugins.soy:soy-core-functions
                </functions>
            </transformer>
        </transformation>
    
        <resource type="download" name="simplebp.css" location="/css/simplebp.css" />
        <resource type="download" name="simplebp.js" location="/js/simplebp.js" />
        <resource type="download" name="simplebp.soy.js" location="/soy/simplebp.soy" />
        <resource type="download" name="images/" location="/images" />
    
        <context>simplebp</context>
        <context>atl.general</context>
        <context>atl.admin</context>
    </web-resource>
  7. Define the dialog-wizard in the <blueprint/> module.

    <!-- Blueprint -->
    <blueprint key="my-blueprint" content-template-key="simplebp-template" index-key="my-index" >
        <dialog-wizard key="simplebp-wizard">
             <dialog-page id="page1Id" template-key="MyPlugin.Blueprints.Simple.page1Form" title-key="my.blueprint.wizard.page1.title" last="true"/>
        </dialog-wizard>
    </blueprint>
  8. Comment out the context-provider where it appears in the <content-template/> module.
     

    <!-- Template for Blueprint -->
    <content-template key="simplebp-template" template-title-key="my.blueprint.title">
    	<resource name="template" type="download" location="/templates/mytemplate.xml" />
    <!-- <context-provider class="com.example.plugins.tutorial.confluence.simplebp.MyContextProvider" /> -->
    </content-template>
      Click here to verify your entire file.
    <atlassian-plugin key="${project.groupId}.${project.artifactId}"
    	name="${project.name}" plugins-version="2">
    	<plugin-info>
    		<description>${project.description}</description>
    		<version>${project.version}</version>
    		<vendor name="${project.organization.name}" url="${project.organization.url}" />
    		<param name="plugin-icon">images/pluginIcon.png</param>
    		<param name="plugin-logo">images/pluginLogo.png</param>
    	</plugin-info>
    	<!-- add our i18n resource -->
    	<resource type="i18n" name="i18n" location="simplebp" />
    	<!-- add our web resources -->
    	<web-resource key="simplebp-resources" name="simplebp Web Resources">
    		<dependency>com.atlassian.auiplugin:ajs</dependency>
    		<dependency>com.atlassian.confluence.plugins.confluence-create-content-plugin:resources</dependency>
    		<transformation extension="soy">
    			<transformer key="soyTransformer">
    				<functions>com.atlassian.confluence.plugins.soy:soy-core-functions
    				</functions>
    			</transformer>
    		</transformation>
    		<resource type="download" name="simplebp.css" location="/css/simplebp.css" />
    		<resource type="download" name="simplebp.js" location="/js/simplebp.js" />
    		<resource type="download" name="simplebp.soy.js" location="/soy/simplebp.soy" />
    		<resource type="download" name="images/" location="/images" />
    		<context>simplebp</context>
    		<context>atl.general</context>
    		<context>atl.admin</context>
    	</web-resource>
    	<!-- Blueprint -->
    	<blueprint key="my-blueprint" content-template-key="simplebp-template"
    		index-key="my-index" >
    		<dialog-wizard key="simplebp-wizard">
    		    <dialog-page id="page1Id" template-key="MyPlugin.Blueprints.Simple.page1Form" title-key="my.blueprint.wizard.page1.title" last="true"/>
    		</dialog-wizard>
    	</blueprint>
    	<!-- Add to the Create Menu -->
    	<web-item key="create-by-sample-template" i18n-name-key="my.create-link.title"
    		section="system.create.dialog/content">
    		<description key="my.create-link.description" />
    		<resource name="icon" type="download" location="/images/myblueprint.png" />
    		<param name="blueprintKey" value="my-blueprint" />
    	</web-item>
    
    	<!-- Template for Blueprint -->
    	<content-template key="simplebp-template"
    		template-title-key="my.blueprint.title">
    		<resource name="template" type="download" location="/templates/mytemplate.xml" />
    <!-- 		<context-provider -->
    <!-- 			class="com.example.plugins.tutorial.confluence.simplebp.MyContextProvider" /> -->
    	</content-template>
    
    	<!-- import from the product container -->
    	<component-import key="applicationProperties"
    		interface="com.atlassian.sal.api.ApplicationProperties" />
    </atlassian-plugin>
  9. Save and close the atlassian-plugin.xml file.
  10. Return to the command line and run the plugin.

    atlas-run

     

  11. Test your blueprint in Confluence to view your wizard.
     

Step 7.  Add a description to your blueprint

Although the Wizard form is quite simple, a complex or multi-page Wizard can benefit from some explanatory text. In this step, you add description-header-key and a description-content-key to display this explanatory text. 

  1. Edit the atlassian-plugin.xml file.
  2. Add two attributes to the dialog-page element.

    <blueprint key="myplugin-blueprint"
               index-key="myplugin-index">
      ...
      <dialog-wizard key="myplugin-wizard">
        <dialog-page id="page1Id"
                     template-key="MyPlugin.Blueprints.Simple.page1Form"
                     title-key="my.blueprint.wizard.page1.title"
                     description-header-key="my.blueprint.wizard.page1.desc.header"
                     description-content-key="my.blueprint.wizard.page1.desc.content"
    			     last="true" />
      </dialog-wizard>
    </blueprint>

     

  3. Save and close the atlassian-plugin.xml file.
  4. Edit the simplebp.properties file.
  5. Add an entry for the description title and content.

    #put any key/value pairs here
    my.plugin.name=MyPlugin
    my.blueprint.title=Sample Template
    my.create-link.title=My Sample Template
    my.create-link.description=Create a new SimpleBB template
    my.blueprint.form.label.title.vName=Name
    my.blueprint.wizard.page1.title=Simplebp WIZARD
    my.blueprint.wizard.page1.desc.header=About this blueprint
    my.blueprint.wizard.page1.desc.content=Use this blueprint to create a table with your name and email.

     

  6. Save and close the simplebp.properties file.
  7. Rebuild your plugin, and QuickReload will automatically reinstall it for you.
     

Step 8. Add validation to your template

Through the setWizard() Javascript API you can add fuller interaction to your wizard.  For example, you can use this API to validate values entered in a wizard's forms. For validation, you use the submit hook to check the fields on a page.  The submit hook takes the id value of the dialog-page and a state object.   Values from the wizard's form are properties of the state.pageData object.  Do the following to validate the entry of the Name field in your wizard:

  1. Edit the resources/js/simplebp.js file.

  2. Add the hook to the setWizard(){} body.

    Confluence.Blueprint.setWizard('com.example.plugins.tutorial.confluence.simplebp.simplebp:create-by-sample-template', function(wizard) {
    	 wizard.on('submit.page1Id', function(e, state) {	
    		 var vName = state.pageData.vName;
    		 if (!vName){
    			 alert('Please provide a name value.');
    			 return false;
    		 }
    	 });
     });

    This hook checks to make sure the field is not empty.

  3. Save and close the simplebp.js file.
  4. Reload your plugin with FASTDEV.
  5. Test the create again.

Learn more

You can continue onto the next tutorial, Write an advanced blueprint plugin. to learn how to construct multiple page tutorials and add event listeners.

Was this page helpful?

Have a question about this article?

See questions about this article

Powered by Confluence and Scroll Viewport