A few weeks ago I've found Locomotive CMS, an open source CMS for Ruby on Rails written by the french guys from NoCoffee. The project is still in beta but after some nights spent on it seemed to me a good piece of code and I decided to use it to serve my portfolio site http://www.kreations.it. In this how-to I'll explain my experience while building it, you can follow these steps to build your own site.

For italian readers: questa guida è stata scritta in inglese affinchè possa contribuire alla scarsa documentazione presente.

Requirements

For a basic installation follow the official guide: http://www.locomotivecms.com/support/installation/engine

If you want to use it in production you can follow my old guide to use Nginx+Unicorn (italian language). However this how-to refers to a local development installation (Engine installation method) because i'm having a lot of problems with the deployment. I'll add a new paragraph when i'll succeed in it :-)

To install MongoDB on Debian-based distribution take a look here.

Choose or create a web template (HTML, CSS, Javascripts).

I suggest to install Locomotive on your pc with a theme proposed here. Browse pages, templates and models and try to understand how Locomotive works. I think it's not so easy to understand it if you, like me, are coming from a long experience with Wordpress, Drupal or Joomla. When you fell just a bit comfortable with it, go on with this how-to. If you need help you can look in the support forum or the Github page.

Pages and Templates

The main work in the backend while building the website will be done in the Page panel. From there, click the Pages badge and you can see existing pages or add a new page.
Every page except the first inherits from the Home page or one of its children (and so do their templates). This means that we'll write a template in the Home page's Template section and the other pages will inherit their templates from it. This means that, except for local content, there's only a place where to modify the HTML template. Obviously if you need you can prevent a page to inherit the template and write a new one.

Go back to the Page panel and open the Home Page. There are two sections: General information and  Template.
The General information section's content is well inline-explained, just dwell on Templatized: you can choose if that page is a template. If you activate this option, the page will be a template for a model, ie it can be used to create new content of that model type  (see the Contact page paragraph below for an example).
The Template section is the more important: you can write the HTML template of your site using the Liquid Templating Language and if you define editable sections, a useful WYSIWYG will appear after the update.
Templates are really a great feature because you can create a complex template and then give the control of the contents to a not-technician who can fill the editable sections with a powerful editor.

So, let's start uploading the needed files: css, javascripts and images. Do it from Settings > Theme files, if you use the images, javascripts and stylesheets folder they will be put in the right place and you can get it with liquid's tags (I'm getting big errors while uploading in production, but everyting works fine in the development environment).
Then copy your HTML template and paste it in the Template section inside the Home page. Before saving it, let's edit it.

Css and javascripts tags must be replaced with the liquid ones. In my case:

{{ 'reset-min' | stylesheet_tag }}
{{ '960grid' | stylesheet_tag }}
{{ 'style' | stylesheet_tag }}
{{ 'nivo-slider' | stylesheet_tag }}

{{ 'jquery.min.js' | javascript_tag }}
{{ 'jquery.nivo.slider.pack' | javascript_tag }}

As you can see, if you have used the right folders while uploading, now it's really easy to add them to the template.

The site title can be get from the Locomotive site, do it with:

<title>{{ site.name }}</title>

My template has a side menu listing. I can create it using liquid:

<nav id="main_menu">
  <ul>
    <li class="{% if page.fullpath == 'index' %}on{% endif %}"><a href="/">Home Page</a></li>
    {% nav site, no_wrapper: true %}
  </ul>
</nav>

This will generate a list with every page with the Listed option set as on. The active page will automatically get the on class, so remember to use it.

Before saving the template let's add a block: a block is a part of the template which can be overwritten from the pages which inherits from that template. I'll call it main_content and it will contain the section of the page which changes between the various pages.

{% block main_content %}
  ...
{% endblock %}

Models

After this basic introduction to liquid templates, let's jump to the models: a model is a custom content type where you can define the fields the content type must have. Are you puzzled? Ok, let's do an example..

I want to create a simple blog section in the site and I want to show the last 3 entries in the footer. So i need to create a blog page to show the posts (with pagination) and in the footer I must show only the last 3 posts' summary.

The first step is to create the model. Go to the Page panel and click on the New model link on the top-right of that page. Insert the model's title and slug (if empty) then choose your custom fields. For my posts I choosed a title (Simple Input), a summary (Text), a content (Text) and a thumbnail (File). Save the model then add a few posts. Jump back to the Home page template and add this into the footer:

{% for post in contents.posts limit:3 %}
  <article>
    <h2>{{ post.title }}</h2>
    {{ post.summary }}
    <a href="/blog/{{ post._permalink }}">Continue reading &raquo;</a>
  </article>
{% endfor %}

The for cycle gets the content of the posts (contents.posts) and show its summary with a link to the full article.  To let the post._permalink work we must create a new page (blog) which will show the posts and a templatized page to contain a single post.

The blog page template will contain:

{% extends 'parent' %}

{% block main_content %}
 {% paginate contents.posts by 10 %}
   {% for post in paginate.collection %}
     <article>
       <h4><a href="/blog/{{ post._permalink }}">{{ post.title }}</a></h4>
       <summary>
         {{ post.summary }} <a href="/blog/{{ post._permalink }}">Continua &raquo;</a>
       </summary>
     </article>
   {% endfor %}
   {{ paginate | default_pagination: 'previous_label:Recent', 'next_label:Older' }}
 {% endpaginate %}
{% endblock %}

This will show the last 10 entries and the links to go backward and forward. The order can be changed from the post model, Edit model > Advanced options > Order by select menu.

For a single post let's create a new templatized page with the blog page as parent and with posts as Content type. The template will be:

{% extends 'parent' %}

{% block main %}
 <article>
   <h2>{{ post.title }}</h2>
   {{ post.body }}
 </article>
{% endblock %}

Editable content

As mentioned above it's possible to declare editable content: this will give you the possibility to edit part of a page with a handy editor. As usual let's make an example.
Add a new page and use this code as template:

{% extends 'parent' %}

{% block main_content %}
 {% editable_long_text 'page_content' %}
 blabla
 {% endeditable_long_text %}
{% endblock %}

Save the page and, et voilà, you'll see the WYSIWIG appear under the Main content tab. Edit the page content directly from there.

Contact page and API

I want to add a page from which I can be contacted by visitors. This is pretty simple: add a new messages model with the custom field you need (in my case: Name, Email and Message) then activate the Advanced options > API enabled option. Choose the accounts to be notified and save.
This will create a model which can be populated from inside a page and an email message will be sent to the selected accounts when this message is posted.

To finish, let's put this code into the contact page template:

{% extends 'parent' %}

{% block main_content %}
<div class="text">
 {% editable_long_text 'main_content' %}
   bla bla
 {% endeditable_long_text %}
</div>

<form id="contactform" name="contact" action="{{ contents.messages.api.create }}" method="post">
 <p>
  <label for="name">Nome</label>
  <input type="text" id=name name="content[name]" placeholder="First and last name" required tabindex="1" />
 </p>
 <p>
  <label for="email">Email</label>
  <input type="text" id=email name="content[email]" placeholder="example@domain.com" required tabindex="2" />
 </p>
 <p>
  <label for="comment">Il tuo messaggio</label>
  <textarea name="content[message]" id="comment" tabindex="3" required></textarea>
 </p>
 <p class="action">
  <input name="submit" type="submit" id="submit" tabindex="4" value="Send Message" />
 </p>
</form>

<script type="text/javascript">
 $(document).ready(function() {
  var form = $('form[name=contact]');

  form.submit(function(e) {
   e.stopPropagation();
   e.preventDefault();

   $.post(form.attr('action'),
   form.serializeArray(),
   function(data) {
    if (data.errors == null) {
     alert("Thank you ! Your message have been received");
     form[0].reset();
    } else {
     alert("We are sorry but we were unable to treat your message. Please try later.");
    }, "json");
  });
 });
</script>
{% endblock %}

Eventually you can write some javascript checks.

Conclusions

With this little guide I've covered the few things you should know to set up a basic portfolio. There're a lot of other arguments to cover, surely I'll write again when I'll be more prepared.
Currently all this guide is about self-teaching, so please insert a comment to this post if I made a mistake or if exists a better way to do something. As an example I admit i havo no idea what the Assests panel and the Settings > Theme files > Snippets are.... Or how to edit images while uploading, I don't know if this is possible, but ImageMagick is a requisite so it should... :-)

As mentioned before, you can see the result of my work here: http://www.kreations.it

blog comments powered by Disqus