Applicable: | This tutorial applies to Confluence 5.9.1 and higher. |
Level of experience: | Beginner. |
Time estimate: | It should take you less than 1 hour to complete this tutorial. |
In this tutorial, you’ll learn how to create a simple blueprint plugin for your Confluence instance. Developing for Confluence Cloud? Learn how to create a blueprint for Confluence Cloud
To complete this tutorial, you should:
We encourage you to work through this tutorial. If you want to skip ahead or check your work when you have finished, you can find the plugin source code on Atlassian Bitbucket. To clone the repository, run the following command:
1 2git clone git@bitbucket.org:atlassian_tutorial/confluence-space-blueprint.git
About these Instructions
You can use any supported combination of operating system and IDE to create this plugin. These instructions were written using Intellij IDEA 2017.2 on macOS Sierra. If you are using another operating system or IDE combination, you should use the equivalent operations for your specific environment. This tutorial was last tested with Confluence 6.7.1 using the Atlassian SDK 6.3.10.
In this step, you'll create a plugin skeleton using atlas-
commands. Because you won't need some of the files created in the skeleton, you'll also delete them in this step.
Open a Terminal and navigate to your workspace directory.
To create a Confluence plugin skeleton, run the following command:
1 2atlas-create-confluence-plugin
To identify your plugin enter the following information :
group-id |
|
artifact-id |
|
version |
|
package |
|
Confirm your entries when prompted with Y
or y
.
Navigate to the project directory created by the previous step.
1 2cd space-blueprint/
Delete the test directories.
Setting up testing for your plugin isn't part of this tutorial. Run the following commands to delete the generated test skeleton:
1 2rm -rf ./src/test/java rm -rf ./src/test/resources/
Delete the unneeded Java class files.
1 2rm -rf ./src/main/java/com/example/plugins/tutorial/confluence/*
In this step, you will define your space blueprint and have a simple create space dialog wizard.
To create a web item for the create space dialog, in the src/main/resources/atlassian-plugin.xml
file, add the following:
1 2<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 pop-up window.
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.
1 2<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 for <space-blueprint>
should be the same as the value attribute for <param key=”blueprintKey”>
inside <web-item>
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 inside Create space
dialog.
1 2<transformation extension="soy"> <transformer key="soyTransformer"> <functions>com.atlassian.confluence.plugins.soy:soy-core-functions</functions> </transformer> </transformation> <transformation extension="js"> <transformer key="jsI18n"/> </transformation> <resource type="download" name="dialog-page.js" location="/soy/dialog-page.soy"/>
1 2The following code snippet shows the full file including the previous example. ``` xml <atlassian-plugin key="${atlassian.plugin.key}" 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="space-blueprint"/> <!-- add our web resources --> <web-resource key="space-blueprint-resources" name="space-blueprint Web Resources"> <transformation extension="soy"> <transformer key="soyTransformer"> <functions>com.atlassian.confluence.plugins.soy:soy-core-functions</functions> </transformer> </transformation> <transformation extension="js"> <transformer key="jsI18n"/> </transformation> <resource type="download" name="space-blueprint.css" location="/css/space-blueprint.css"/> <resource type="download" name="space-blueprint.js" location="/js/space-blueprint.js"/> <resource type="download" name="images/" location="/images"/> <resource type="download" name="dialog-page.js" location="/soy/dialog-page.soy"/> <context>create-space</context> <dependency>com.atlassian.auiplugin:ajs</dependency> </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" 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> </atlassian-plugin> ```
Create a soy
folder for your dialog wizard template under src/main/resources
(or use your IDE):
1 2mkdir 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.
1 2{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
.
In the src/main/resources/js/space-blueprint.js
file, 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".
1 2AJS.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.space-blueprint: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); }); });
src/main/resources/space-blueprint.properties
:
1 2confluence.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
Space blueprints let you define a custom home page template to use when creating the space.
Create an xml
folder for your home page template
1 2mkdir src/main/resources/xml
In the folder that includes the children macro, create a new file called example-space-home.xml
:
1 2<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>
Add the content template to the atlassian-plugin.xml
file:
1 2<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>
Add the content template reference to the space blueprint definition:
1 2<space-blueprint key="example-space-blueprint" i18n-name-key="confluence.blueprints.space.example.name" category="examples"> <content-template ref="example-space-homepage-template"/> ....
The following code snippet shows the full atlassian-plugin.xml
file including previous example.
1 2<atlassian-plugin key="${atlassian.plugin.key}" 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="space-blueprint"/> <!-- add our web resources --> <web-resource key="space-blueprint-resources" name="space-blueprint Web Resources"> <transformation extension="soy"> <transformer key="soyTransformer"> <functions>com.atlassian.confluence.plugins.soy:soy-core-functions</functions> </transformer> </transformation> <transformation extension="js"> <transformer key="jsI18n"/> </transformation> <resource type="download" name="space-blueprint.css" location="/css/space-blueprint.css"/> <resource type="download" name="space-blueprint.js" location="/js/space-blueprint.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>create-space</context> </web-resource> <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> <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" category="examples"> <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>
Add the new keys to the i18n properties file:
1 2confluence.blueprints.space.example.homepage.name=Example Space Homepage confluence.blueprints.space.example.homepage.desc=Example Space Homepage Description confluence.blueprints.space.example.home.children.heading=Child pages will be shown here
At this point, you have created a skeleton space blueprint plugin.
To start a local Confluence instance, run the following command:
1 2atlas-run
Log in to the instance as user admin
using a password of admin
.
Click Spaces > Create Space in the header, 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 children macro pre populated.
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 home page.
Add description and home page heading fields to your dialog-page.soy
template:
1 2<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="description" 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>
Here is full template including example above.
1 2{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="description" 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:
1 2confluence.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 in the home page template, so update the template to refer to the new heading:
1 2<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>
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.
Now that you know how to create Confluence Space blueprint plugin you’re ready to explore more about blueprints. Check out tutorial for [intermediate blueprint plugin] (/server/confluence/write-an-intermediate-blueprint-plugin/) or try to write [advanced blueprint plugin] (/confdev/confluence-plugin-guide/confluence-blueprints/write-an-advanced-blueprint-plugin).
Rate this page: