Write a simple Confluence Space Blueprint

Applicable:

This tutorial applies to Confluence 5.3 and higher.

Level of experience:

Beginner.

Time estimate:

It should take you less than 1 hour to complete this tutorial.

Overview of the tutorial

This tutorial shows you how to create a very simple space blueprint plugin.  This tutorial does not require writing any Java classes. To complete this tutorial, you should have installed the Atlassian SDK and worked through the Atlassian Plugin SDK tutorial. It will also help to have completed the Write a simple Confluence Blueprint plugin tutorial.

On this page:

Step 1. Add your space blueprint definition

In this step you will define your space blueprint and have a simple create space dialog wizard.

Edit the src/main/resources/atlassian-plugin.xml file, and create the web-item for the create space dialog, add the following: 

    <web-item key='example-space-blueprint-item' i18n-name-key='confluence.blueprints.space.example.name'
              section='system.create.space.dialog/content'>
        <description key='confluence.blueprints.space.example.description'/>
        <param name='blueprintKey' value='example-space-blueprint'/>
    </web-item>

The section='system.create.space.dialog/content' attribute is what makes the dialog available in the create space popup

Add the space blueprint definition and a wizard with one page. Note that the category is an optional attribute which essentially adds a label to all spaces created via this blueprint. This will show an "Examples" category listed in the space directory with all the spaces created with our example space blueprint.

<space-blueprint key="example-space-blueprint" i18n-name-key="confluence.blueprints.space.example.name" category="examples">
    <dialog-wizard key="example-space-blueprint-wizard">
        <dialog-page id="exampleSpaceId"
                     template-key="Confluence.SpaceBlueprints.Example.dialogForm"
                     title-key="confluence.blueprints.space.example.dialog.create.title"
                     description-header-key="confluence.blueprints.space.example.dialog.create.heading"
                     description-content-key="confluence.blueprints.space.example.dialog.create.description"
                     last="true"/>
    </dialog-wizard>
</space-blueprint>

The key attribute must be the same for the create space dialog web-item and for the space-blueprint.

Step 2. Add your space dialog wizard 

Update the web-resources to include the dialog-page.soy for your wizard form (note we will need the transformers  soyTransformer and jsI18n). Also add some contexts to ensure your resources are included on every page.
        <transformation extension="soy">
            <transformer key="soyTransformer">
                <functions>com.atlassian.confluence.plugins.soy:soy-core-functions</functions>
            </transformer>
            <transformation extension="js">
                <transformer key="jsI18n"/>
            </transformation>
        </transformation>
 
        <resource type="download" name="dialog-page.js" location="/soy/dialog-page.soy"/>
 	<dependency>com.atlassian.confluence.plugins.confluence-create-content-plugin:space-blueprints</dependency>   <!-- This dependency is not required for confluence 5.4+ -->
	<context>atl.general</context>
    <context>atl.admin</context>
<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="spacebp"/>
    
    <!-- add our web resources -->
    <web-resource key="spacebp-resources" name="spacebp Web Resources">
        <transformation extension="soy">
            <transformer key="soyTransformer">
                <functions>com.atlassian.confluence.plugins.soy:soy-core-functions</functions>
            </transformer>
            <transformation extension="js">
                <transformer key="jsI18n"/>
            </transformation>
        </transformation>

        <resource type="download" name="spacebp.css" location="/css/spacebp.css"/>
        <resource type="download" name="spacebp.js" location="/js/spacebp.js"/>
        <resource type="download" name="dialog-page.js" location="/soy/dialog-page.soy"/>
        <resource type="download" name="images/" location="/images"/>
	    <dependency>com.atlassian.confluence.plugins.confluence-create-content-plugin:space-blueprints</dependency>   <!-- This dependency is not required for confluence 5.4+ -->
        <context>atl.general</context>
        <context>atl.admin</context>
    </web-resource>
    
    <web-item key='example-space-blueprint-item' i18n-name-key='confluence.blueprints.space.example.name'
              section='system.create.space.dialog/content'>
        <description key='confluence.blueprints.space.example.description'/>
        <param name='blueprintKey' value='example-space-blueprint'/>
    </web-item>
 
    <space-blueprint key="example-space-blueprint" i18n-name-key="confluence.blueprints.space.example.name">
        <dialog-wizard key="example-space-blueprint-wizard">
            <dialog-page id="exampleSpaceId"
                         template-key="Confluence.SpaceBlueprints.Example.dialogForm"
                         title-key="confluence.blueprints.space.example.dialog.create.title"
                         description-header-key="confluence.blueprints.space.example.dialog.create.heading"
                         description-content-key="confluence.blueprints.space.example.dialog.create.description"
                         last="true"/>
        </dialog-wizard>
    </space-blueprint>
    
</atlassian-plugin> 
Create a soy folder for your dialog wizard template under src/main/resources (or use your IDE):
mkdir src/main/resources/soy

In that folder, create a file called dialog-page.soy. This calls a generic space form (with space key and name fields) already available for you.
{namespace Confluence.SpaceBlueprints.Example}
/**
 * Dialog form template
 *
 * @param atlToken the XSRF token to send with the form
 * @param? fieldErrors the map of errors to display keyed by field name
 * @param? name initial value for the name field
 * @param? key initial value for the key field
 */
{template .dialogForm}
<form action="#" method="post" id="decisions-form" class="common-space-form aui">
    {call Confluence.Templates.Blueprints.CreateSpace.createSpaceFormFields}
        {param showSpacePermission: false /}
        {param fieldErrors: $fieldErrors /}
        {param name: $name /}
        {param key: $key /}
    {/call}
    <input type="hidden" name="atl_token" value="{$atlToken}" />
</form>
{/template}

The template-key attribute in the plugin definition must match the namespace and template name in the soy template. In this case, our namespace is Confluence.SpaceBlueprints.Example, and our template is .dialogForm, so the template-key must be Confluence.SpaceBlueprints.Example.dialogForm.

Create the src/main/resources/js/spacebp.js file and hook into the wizard apis. They are similar to the blueprint ones. In our example here, we update the space home page title to be the space name and a suffix of " Home Page".
AJS.bind("blueprint.wizard-register.ready", function () {
    function submitExampleSpace(e, state) {
        state.pageData.ContentPageTitle = state.pageData.name + " " + AJS.I18n.getText("confluence.blueprints.space.example.home.title.suffix"); 
        return Confluence.SpaceBlueprint.CommonWizardBindings.submit(e, state);
    }
    function preRenderExampleSpace(e, state) {
        state.soyRenderContext['atlToken'] = AJS.Meta.get('atl-token');
        state.soyRenderContext['showSpacePermission'] = false; 
    }
    Confluence.Blueprint.setWizard('com.example.plugins.tutorial.confluence.spacebp.spacebp:example-space-blueprint-item', function(wizard) {
        wizard.on("submit.exampleSpaceId", submitExampleSpace);
        wizard.on("pre-render.exampleSpaceId", preRenderExampleSpace);
        wizard.on("post-render.exampleSpaceId", Confluence.SpaceBlueprint.CommonWizardBindings.postRender);
    });
});

Add the i18n strings to src/main/resources/confluence-space-blueprints.properties:
confluence.blueprints.space.example.name=Example Space Blueprint
confluence.blueprints.space.example.description=An example of a space blueprint
confluence.blueprints.space.example.dialog.create.title=Create your Example Space
confluence.blueprints.space.example.dialog.create.heading=About Example Spaces
confluence.blueprints.space.example.dialog.create.description=The example space is a way of demonstrating the features of space blueprints
confluence.blueprints.space.example.home.title.suffix=Home Page

Step 3. Create a home page for your space blueprint

Space blueprints let you define a custom homepage template to use when creating the space. 

  1. Create an xml folder for your homepage template

    mkdir src/main/resources/xml
  2. Create a new file called example-space-home.xml in that folder that includes the children macro:

    <ac:layout>
        <ac:layout-section ac:type="single">
            <ac:layout-cell>
                <h2><at:i18n at:key="confluence.blueprints.space.example.home.children.heading" /></h2>
                <p>
                   <ac:macro ac:name="children">
                       <ac:parameter ac:name="page"></ac:parameter>
                       <ac:parameter ac:name="all">true</ac:parameter>
                   </ac:macro>
                </p>
            </ac:layout-cell>
        </ac:layout-section>
    </ac:layout>
    
    
  3. Add the content template to the atlassian-plugin.xml file:

        <content-template key="example-space-homepage-template" i18n-name-key="confluence.blueprints.space.example.homepage.name">
            <description key="confluence.blueprints.space.example.homepage.desc"/>
            <resource name="template" type="download" location="/xml/example-space-home.xml"/>
        </content-template>
    
    
  4. Add the content template reference to the space blueprint definition:

        <space-blueprint key="team-space-blueprint" i18n-name-key="confluence.blueprints.space.example.name">
            <content-template ref="example-space-homepage-template"/>
            ....
    
    
    <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="spacebp"/>
        
        <!-- add our web resources -->
        <web-resource key="spacebp-resources" name="spacebp Web Resources">
            <transformation extension="soy">
                <transformer key="soyTransformer">
                    <functions>com.atlassian.confluence.plugins.soy:soy-core-functions</functions>
                </transformer>
                <transformation extension="js">
                    <transformer key="jsI18n"/>
                </transformation>
            </transformation>
    
            <resource type="download" name="spacebp.css" location="/css/spacebp.css"/>
            <resource type="download" name="spacebp.js" location="/js/spacebp.js"/>
            <resource type="download" name="dialog-page.js" location="/soy/dialog-page.soy"/>
            <resource type="download" name="images/" location="/images"/>
    	    <dependency>com.atlassian.confluence.plugins.confluence-create-content-plugin:space-blueprints</dependency>   <!-- This dependency is not required for confluence 5.4+ -->
            <context>atl.general</context>
            <context>atl.admin</context>
        </web-resource>
        
        <web-item key='example-space-blueprint-item' i18n-name-key='confluence.blueprints.space.example.name'
                  section='system.create.space.dialog/content'>
            <description key='confluence.blueprints.space.example.description'/>
            <param name='blueprintKey' value='example-space-blueprint'/>
        </web-item>
     
        <content-template key="example-space-homepage-template" i18n-name-key="confluence.blueprints.space.example.homepage.name">
            <description key="confluence.blueprints.space.example.homepage.desc"/>
            <resource name="template" type="download" location="/xml/example-space-home.xml"/>
        </content-template>
        <space-blueprint key="example-space-blueprint" i18n-name-key="confluence.blueprints.space.example.name">
            <content-template ref="example-space-homepage-template"/>
            <dialog-wizard key="example-space-blueprint-wizard">
                <dialog-page id="exampleSpaceId"
                             template-key="Confluence.SpaceBlueprints.Example.dialogForm"
                             title-key="confluence.blueprints.space.example.dialog.create.title"
                             description-header-key="confluence.blueprints.space.example.dialog.create.heading"
                             description-content-key="confluence.blueprints.space.example.dialog.create.description"
                             last="true"/>
            </dialog-wizard>
        </space-blueprint>
        
    </atlassian-plugin> 

  5. Add the new keys to the i18n properties file:

    confluence.blueprints.space.example.homepage.name=Example Space Homepage
    confluence.blueprints.space.example.homepage.desc=Example Space Homepage
    confluence.blueprints.space.example.home.children.heading=Child pages will be shown here

Step 4. Run your plugin

At this point, you have created a skeleton space blueprint plugin. 

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

    atlas-run
  3. Log into the instance as user admin using a password of admin.
  4. Click Create Space and then select your space blueprint. It should take you through a wizard with a basic space form to create a space and see your home page with a child a children macro pre populated.

Step 5. Add new fields to the create space dialog

During the creation of your new space, you might want to ask the user for some information in the create dialog. In our example here, we will add a space description field. We will also add a custom heading field to display it on the space homepage.

Add description and homepage heading fields to your dialog-page.soy template:
    <fieldset>
        <div class="field-group">
            <label for="space-description">{getText('confluence.blueprints.space.example.dialog.label.description')}</label>
            <textarea id="space-description" class="textarea long-field" rows="3" type="text" name="spaceDesc"
                placeholder="{getText('confluence.blueprints.space.example.dialog.label.description.placeholder')}"></textarea>
        </div>
    </fieldset>
    <fieldset>
        <div class="field-group">
            <label for="space-homepage-heading">{getText('confluence.blueprints.space.example.dialog.label.heading')}</label>
            <textarea id="space-homepage-heading" class="textarea long-field" rows="3" type="text" name="spaceHomepageHeading"
                placeholder="{getText('confluence.blueprints.space.example.dialog.label.heading.placeholder')}"></textarea>
        </div>
    </fieldset>
{namespace Confluence.SpaceBlueprints.Example}
/**
 * Dialog form template
 *
 * @param atlToken the XSRF token to send with the form
 * @param? fieldErrors the map of errors to display keyed by field name
 * @param? name initial value for the name field
 * @param? key initial value for the key field
 */
{template .dialogForm}
<form action="#" method="post" id="decisions-form" class="common-space-form aui">
    {call Confluence.Templates.Blueprints.CreateSpace.createSpaceFormFields}
        {param showSpacePermission: false /}
        {param fieldErrors: $fieldErrors /}
        {param name: $name /}
        {param key: $key /}
    {/call}
    <fieldset>
        <div class="field-group">
            <label for="space-description">{getText('confluence.blueprints.space.example.dialog.label.description')}</label>
            <textarea id="space-description" class="textarea long-field" rows="3" type="text" name="spaceDesc"
                placeholder="{getText('confluence.blueprints.space.example.dialog.label.description.placeholder')}"></textarea>
        </div>
    </fieldset>
    <fieldset>
        <div class="field-group">
            <label for="space-homepage-heading">{getText('confluence.blueprints.space.example.dialog.label.heading')}</label>
            <textarea id="space-homepage-heading" class="textarea long-field" rows="3" type="text" name="spaceHomepageHeading"
                placeholder="{getText('confluence.blueprints.space.example.dialog.label.heading.placeholder')}"></textarea>
        </div>
    </fieldset>
    <input type="hidden" name="atl_token" value="{$atlToken}" />
</form>
{/template}
Add the new keys to the i18n properties file:
confluence.blueprints.space.example.dialog.label.description=Description
confluence.blueprints.space.example.dialog.label.description.placeholder=Briefly describe this space
confluence.blueprints.space.example.dialog.label.heading=Homepage Heading
confluence.blueprints.space.example.dialog.label.heading.placeholder=Add a custom heading for the heading on the homepage

There is some magic that injects form variables from the create dialog into a context that is provided to the home-page template, so update the template to refer to the new heading:
<ac:layout>
    <ac:layout-section ac:type="single">
        <ac:layout-cell>
            <h2><at:var at:name="spaceHomepageHeading"/></h2>
            <p>
               <ac:macro ac:name="children">
                  <ac:parameter ac:name="page"></ac:parameter>
                  <ac:parameter ac:name="all">true</ac:parameter>
               </ac:macro>
            </p>
        </ac:layout-cell>
    </ac:layout-section>
</ac:layout>

Now reload your plugin and you should be able to see two additional fields, description and heading in the dialog wizard and have it passed through to the created space home page.
Was this page helpful?

Have a question about this article?

See questions about this article

Powered by Confluence and Scroll Viewport