Converting the Addteq Blog from WordPress to Confluence

The decision to move the Addteq blogs from WordPress to Confluence was an easy one. All of our employees use Confluence on a daily basis, and forcing them to exit the Atlassian Suite workflow that they use for everything else other than creating blog posts, was not ideal. The only dilemma that was raised was simply, how is it possible to present the content to the end user in a suitable and attractive user interface while allowing content creators to stay within the familiar realms of Confluence.

We have been using the Scroll Viewport plugin by K15t Software for over a year for our Careers section of our website. Once we realized we can use that plugin for our blog instances, the conversion process officially began. An epic was created in JIRA and we were off. The epic contained the following major user requests. 

  • Create overall theme design 
  • Create sidebar widgets for added functionality
  • Move blog posts from WordPress to Confluence
  • Update blog post authors 
  • Redirect old blog post links to the new url
  • Add url redirects for blog posts
  • Create new workflow and document it

Create Overall Theme Design

This was the easy part and for all individuals with a creative air, it will probably be the funnest part. It involves looking online for inspiration and sleek design ideas. Once we felt inspired, creating a demo of the blog site using dummy data was the next step. By using HTML, CSS and Javascript a mockup of what we wanted the site to look like was created. The initial mockup was written in Sublime Text and then copied over to the Scroll Viewport Theme Editor.

Our viewport configuration involved copying one of the default themes and renaming it as the Addteq Blog Theme. Our content tab is shown in the image below. This is the configuration you would use if you only want to show blog posts, by checking both the pages and the blog posts buttons, you can have the two content types within your viewport.

The URL tab settings can be seen in the image below. The URL we wanted the blogs page to show up under was nebula.addteq.com/blogs, so for the path prefix we use the /blog command and we leave the page path as hierarchical. A hierarchical page path for blog posts uses the posting date to navigate to the page. This means that the following URLs will all contain content that will show up as blog overview pages:

  • /path-prefix  (eg. /blog)
  • /path-prefix/year   (eg. /blog/2016)
  • /path-prefix/year/month   (eg. /blog/2016/04)

Then an individual blog post will be shown at the end of this tree in the format of /path-prefix/year/month/page-title.

The last tab which is the Permissions tab and this allows you to set certain confluence user groups that will be able to access the confluence space or pages. Any individuals who aren’t part of the selected groups get redirected to the viewport screen. 

With the configuration setup, the next step was to ensure that the content displayed correctly within the viewport. We wanted the front page of our site to display the latest blog posts but we also wanted to have category pages which would sort blog posts based on a specific label. The category page functionality at the time of this writing was unavailable (tracked here) so a workaround had to be created.

In the root directory a blogs.vm page was created with the following code inside. A category path was created and used as the navigation links for our specific categories, If the url contained the word category the blogs-category.vm template would be loaded otherwise load the blogs-main.vm template.

				
					#if ($stringUtils.contains($url.path, 'category'))
    $include.template('blogs-category.vm')
#else
	$include.template('blogs-main.vm')
#end 
				
			

Within the blogs-main.vm template we used the following code to loop through all of the blog posts and output them in the desired format. The foreach command creates a blogPost object that can then be used to obtain specific information.

				
					
#foreach($blogPost in $blogPosts)
  <div class='post-preview clearfix'>
    <a href="$blogPost.link">
      <h2 class='post-title'>$blogPost.title</h2>
    </a>
    <p class='post-content'>$blogPost.getDescription(300)</p>
    <div class='row'>
      <div class='col-sm-7 col-xs-12'>
        	<div class='media'>
            <div class='media-left media-middle'>
              <a href="#">
                <img decoding="async" data-img="$blogPost.creator.email" class="media-object user-image lazy" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201%201'%3E%3C/svg%3E" data-src="${theme.baseUrl}/assets/images/default-user.png"/>
              </a>
            </div>
            <div class='media-body'>
              <p class='post-meta'><a href="">$user.fullName($blogPost.creator.username)</a><span> posted on $blogPost.creationDate('MMM dd, yyyy')</span></p>
            </div>
          </div>
      </div>
      <div class='col-sm-5 col-xs-12'>
      	<p class='post-meta text-right mt-15'>
          <span class='post-comment-count'><span class='fb-comments-count' data-href='$url.protocol://$url.host$blogPost.link'></span>  <i class='fa fa-comments'></i></span>
          <span class='label-data'>#foreach($label in $blogPost.labels) <a href="/blog/search?q=labelText:$label"><span class='label label-default'>$label</span></a> #end</span>
        </p>
      </div>
    </div>
  </div>
  <hr>
#end 
				
			

There are three things to note in the above code. 

  1. We didn’t directly pull the creator’s user image from Confluence as we wanted to implement Gravatar images. This involved placing the creator’s email as an attribute of the image and then passing it through an MD-5 hash function and appending that hash to the Gravatar url.
  2. We used the Facebook comments plugin as our commenting and moderation tool. To obtain the number of comments on a specific blog post we had to create a span tag with an attribute of data-href that equaled the full path of the specific blog post.
  3. To sort our content by label we used the Confluence CQL function labelText: to allow this type of linking to occur.

The rest of our file structure can be seen in the image above and explained below.

  • blog.vm –  Individual blog post handler. 
  • search.vm – Search results handler.
  • error.vm – All error messages such as 404s are handled.
  • include – This directory was used to structure each page as it contained code snippets for the header, footer and for including the sitewide javascript and css files. 
  • overrides – This directory was used to override the output of certain Confluence macros to allow for the output of each macro to coincide with the overall style of the site.

Create Sidebar Widgets for Added Functionality

One of the main features of WordPress is the ability to add widgets to the sidebar of any content page. On our old site two widgets that we used extensively were the Tag Cloud widget and the Archive widget, these features don’t come packaged with the Scroll Viewport plugin but with a bit of creativity we were able to achieve them. The first thing we did was create a javascript object of all the blog posts.

				
					var blogData = [#foreach($yearOverview in $blog.home.children)
                     #foreach($monthOverview in $yearOverview.children)
                     	#foreach ($post in $monthOverview.children)
                          {
                              title: "$post.title",
                              link: "$post.absoluteLink",
                              year:"$post.creationDate('YYYY')",
                              month:"$post.creationDate('MMM')",
                              author:"$user.fullName($post.creator.username)",
                              tags: [#foreach($label in $post.labels)"$label",#end]
                          },
                        #end
                      #end
                     #end
                  ];
				
			

Using this blogData object we were able to then manipulate the data using the lodash javascript utility library and display the data using the handlebarsjs templating library. 

				
					var nest = function (seq, keys) {
        if (!keys.length)
            return seq;
        var first = keys[0];
        var rest = keys.slice(1);
        return _.mapValues(_.groupBy(seq, first), function (value) { 
            return nest(value, rest)
        });
    };
 
var archive = nest(blogData, ['year', 'month']);
				
			
				
					
  {{#each .}}
  	<a data-toggle="collapse" href="#year{{@key}}" data-parent="#archive-container" class="list-group-item">{{@key}}</a>
	<div id="year{{@key}}" class="collapse archive-year">
    	{{#each this}}
        	<a data-toggle="collapse" href="#month{{@key}}{{@../key}}" data-parent="#month{{@key}}{{@../key}}" class="list-group-item">{{@key}}</a>
        	<div id="month{{@key}}{{@../key}}" class="collapse list-group-submenu archive-month">
            	{{#each this}}
                	<a class="list-group-item" href="{{this.link}}">{{this.title}}</a>
                {{/each}}
            </div>
        {{/each}}
    </div>
  {{/each}}
				
			

Using the above handlebars template we were able to create a toggleable / nested  archive list.

Move Blog Posts from WordPress to Confluence

This was a manual process for us as we did not have many blog posts, however if a manual process is overwhelming, a SQL script to migrate the blog posts could be used. 

Update Blog Post Authors 

Due to the fact that we manually updated the blog posts, they ended up with the wrong authors. We handled this problem by creating a SQL script to change the authors of each post. 

Redirect Old Blog Post Links to the New Url

By modifying the .htaccess file this was easily achieved.

Add Url Redirects for Blog Posts

We wanted to enable both /blog and /blogs to load our blog homepage. This was easily enabled by accessing the URL Redirects section of the Scroll Viewport plugin within the  Confluence Admin page.

Create and Document New Workflow

 The new workflow involves the Comala Publishing Plugin, which allows us the ability to have a Blog Drafts space as well as a Published Drafts space. When writing a blog post our users also have to take certain steps to allow the content to be displayed consistently due to the use of the macro overrides used within the viewport.  An example of this is how we display embedded videos.

To override a macro a page with the name of the macro must be created within the overrides directory. 

  • Code Block Macro – code.vm
  • Widget Connector Macro – widget.vm

even the images used within blog post can be overwritten by creating the sp-image.vm page. It should be noted that if you leave an override page blank you essential hide that macro from your viewport. An example of our widget override code can be seen below.

				
					
<div class="embed-responsive embed-responsive-16by9">
  <iframe class="embed-responsive-item" src="$params.url" allowfullscreen></iframe>
</div>
				
			

With the new workflow documented our blogs are ready for the end users. Please leave comments below on how you like the new look and feel or if you have any questions about customizing Confluence.

Need help customizing Confluence?

Related Content
work from anywhere
Embracing the Freedom: Work from anywhere
If our products can be used from anywhere, we should also be able to work from anywhere. This blog shows...
Be_Unstoppable
Jira Accessibility: Best Practices for enhancing collaboration
Jira is a powerful tool to streamline workflows and enhance productivity. This blog explores four best...
addteq_fb_collab4b
The Perfect Match: Confluence & Excellentable
Discover the perfect match for your team's collaboration needs this Valentine's Day. Learn how to seamlessly...

Leave a Reply

Your email address will not be published. Required fields are marked *