A Simple Example – Backbone.js Tutorial Part 3 – Creating a Paginated View

Thanks for checking out part 3 of my Backbone.js tutorial.

I have previously covered my efforts to use backbone.js to create a paginated view. They were somewhat successful, but in light of my efforts to revamp my work I am going to tackle this task again. I think I will simply defer to those blog entries in some areas, but it’s a useful and necessary exercise to do this again – this time in the context of the overarching app view I have created.

First off, I should clarify something: I’m not trying to build pagination that allows the user to skip between pages, go to previous and next pages, etc. I’m trying to load details about projects Fortified Studio has worked on. I want to load an initial set of projects, then allow the user to click a “load more” button to view the next set (or page, if you will).

I think I can create the most basic structure by merely cloning what I have done for Fortified’s employee profiles.

< … Cloning, then doing a replacing all mentions of “profile” with “project” … >

Indeed that works well, although it loads all the projects. Hopefully we’ll fix that next.

The code – including the underscore template for each project – is getting a little lengthy at this point, so I’m not going to copy and paste it here. If you’ve looked through the previous entry where I created the model, collection, and view for profiles, you’ve seen what the projects model, collection, and view look like – they’re practically identical. You can, however, download the source code if you want to see what everything looks like at this point: backbone.blog.3a.zip. Note that I am not including images in the my source code zips, nor am I including any styling. I’m just demonstrating the loading of data at this point. Perhaps I will walk though adding styling in a future entry.

Now I’m going to try to limit the initial rendering to only show five projects. Basically I just need to split this _.each loop so it only renders a subset of projects:

_.each(this.model.models, function(project){
   var projectTemplate = this.template(project.toJSON());
      $(this.el).append(projectTemplate);
}, this);

As I mentioned, I’ve already done this, so I’m going to cheat a bit. First I’m going to add some properties to the view so I know how to split up the projects:

var ProjectView = Backbone.View.extend({
   el: "#projects",
   template: _.template($('#projectTemplate').html()),
   page: 0,
   perPage: 5,
   totalPages: 0,
   ...
});

Then, instead of rendering all the projects as I had previously done, I will render the initial page of five projects:

render: function (eventName) {
   this.totalPages = Math.ceil(_.size(this.model.models) / this.perPage);
   return this.renderProjectGroup(0, this.perPage - 1);
},
renderProjectGroup : function(start, end) {
   var that = this;
   var subset = _.filter(this.model.models, function(num, index){
      return (index >= start) && (index <= end);
   });

   _.each(subset, function (project) {
      var projectTemplate = this.template(project.toJSON());
      $(this.el).append(projectTemplate);
   }, this); 

   return this;
}

renderProjectGroup is a new method that filters out a range of projects then uses an _.each loop to render each of them. renderProjectGroup is used to render the initial group of five projects, but more importantly can be called on again to render additional subsets of project models.

To trigger the loading of additional projects, we’ll need a button. In our case, this button is a little tricky because it needs to be determined if it should be hidden or visible. If it’s going to be visible, it should be placed at the end of the list of projects.

I tried to imagine a way of doing this that didn’t involve simply injecting some jQuery into the ProjectView that will hide or show the load more button. Here’s what I came up with. You can tell me if it makes sense.

var LoadMoreProjectsView = Backbone.View.extend({
   el: $("#load-more-projects")
});

LoadMoreProjectsView is a view that simply creates a reference to an existing DOM element. It may seem pointless to do this, but I like that I can now refer to the view’s el property instead of the DOM element directly. It also allows the option of expanding the button into something more complex later on. UPDATE (7/25/12): This turned out to be a better idea than I had imaged. See below for details.

I need to create an instance of LoadMoreProjectView, but I’m not sure whether to do it in ProjectView or AppView. AppView makes sense because, so far anyway, I’m creating each view there. ProjectView makes sense because I’ll need to hide and show the load more button based on the properties of the ProjectView. It will be a lot easier to grab them from within the ProjectView. Here’s how I have created the LoadMoreProjectView instance:

First I create a property within ProjectView that will refer to the LoadMoreProjectView instance, then I set the property in ProjectView’s initialize method:

var ProjectView = Backbone.View.extend({
   ... 
   loadMore: null,

   initialize: function() {
      this.loadMore = new LoadMoreView();
   },
   ...
});

Each time the load more button is clicked, we’ll want to load the next group of projects, so I’ll bind a call to load the next group to the click:

events: {
   "click .load-more-projects": "renderNextProjectGroup"
},

I’d really like that to be something like “click this.loadMore” instead of referring to the CSS class of the load more button, but I can’t figure out how to do it.

UPDATE (7/25/12): I figured out how to avoid referring to the CSS class of the load more button. I removed the events property above and augmented ProjectView’s initialize function to look like this:

initialize: function() {
   var that = this;

   // Create a reference to the load more button
   this.loadMore = new LoadMoreProjectsView();

   // Bind the load more button
   (this.loadMore.$el).on("click", function() {
      that.renderNextProjectGroup();
   })
},

Turns out it was a better idea than I had thought to use LoadMoreProjectsView, despite its simplicity. Now back to the pre-update info ….

Now I need to define the renderNextProjectGroup function. It should determine what “page” we’re on and try to render the next page. I can use the properties I defined for ProjectView to figure out what page we’re on and the start and end positions of the next group of projects. Here’s what it looks like:

renderNextProjectGroup: function () {
   if(this.page < this.totalPages) {
      this.page++;
      var start = this.page * this.perPage;
      var end = start + (this.perPage - 1);
      this.renderProjectGroup(start, end);
   }
}

Finally, each time renderProjectGroup() is called, it should determine whether or not the load more button should still be displayed. I’ll call the function to determine the visibility of the button renderLoadMoreButton:

renderLoadMoreButton: function() {
   // If we're on the last page, hide the load more button
   if(this.page >= (this.totalPages - 1)) {
      this.loadMore.$el.hide();
   }
   // Otherwise we need to push the load more to the bottom
   // of the portfolio view
   else {
      this.$el.append( this.loadMore.$el.detach().show() );
   }
}

That’s all looking good. I definitely missed some detail above, but you can check out the source code here: backbone.blog.3b.zip. I added just a tiny bit of CSS to make things a little more wieldy, but this is still all about data for the time being.

Here are some handy links to parts 1 and 2 of this tutorial:

A Simple Example – Backbone.js Tutorial Part 2 – Creating an App View

Thanks for checking out part 2 of my Backbone.js tutorial.

In my previous entry I set up a model, a collection, and a view related to a “profile” – essentially bios for the people who work with me at Fortified Studio. The collection grabbed some JSON, used that data to create corresponding models, then displayed the data in a view. I’m still not sure I’m doing things in the best backbone.js way, but it’s working and I don’t think I’m doing anything outrageously against the rules.

Ultimately though, my page needs to have several views, each of which grab their data from JSON files. So I’d like to have a master view that render all the sub-views. I can render my profiles view now, then add other views as I build them.

I’ve seen app views created before, but none of them have struck me as the definitive way to do things. I’m sure I’ve tried this before, but I am once again going to look to the todos.js example for some guidance. Their AppView is somewhat lengthy, but I’ll start slowly and see what I can glean from it.

Firstly, I’ll follow the todos.js lead and bind the view to an existing DOM element. In my case I will bind it to the <body> tag. Is there anything wrong with that? Should I be binding it to a tag within the body? I’ll also use the app view’s initialize method to call fetch on the collection of profiles. Here then, is the very simple first iteration of the app view:

var AppView = Backbone.View.extend({
   el: "body",
   initialize: function() {
      profiles.fetch();
   }
});

Simple and it works. Next I’d like to trigger the rendering of subviews within the app view’s render function. Then again, I guess I don’t need to do this because I’ve already bound the rendering of the profiles to the ‘reset’ event triggered by the profiles collection.

How about if I instead insert all profiles-related instantiations into the app view’s initialize method. This doesn’t affect the functionality, but I suppose it cleans things up a bit.

var AppView = Backbone.View.extend({
   el: "body",
   initialize: function() {
      var profiles = new ProfileList(); 
      var profilesView = new ProfileView({
         model: profiles
      });

      // When profiles have been successfully grabbed,
      // display them using profile template
      profiles.bind('reset', function () {
         profilesView.render();
      });

      profiles.fetch();
   }
 });

Now I only instantiate the app view and the rest takes care of itself.

var App = new AppView;

This seems ok for now. Tomorrow I’ll see what happens when I try to add a second, more complicated subview. Here’s the code from today: backbone.blog.2.zip

Here are some handy links to parts 1 and 3 of this tutorial:

A Simple Example – Backbone.js Tutorial Part 1 – Collection based on JSON + View

I still don’t feel like I understand Backbone at all. I decided to scrap what I had previously built – despite the fact that it’s working – because I don’t truly understand why it’s working. The result is this simple example presented as a backbone.js tutorial.

So … starting from nothing. Here we go. It won’t take long before I am completely stuck.

I want to create a simple list of user profiles. The profiles will be brought in via a JSON file and displayed as a list. Seems so simple!

I’ll start by creating the model:

var Profile = Backbone.Model.extend();

I’ve seen it done this way in many examples. Sometimes default values are added, but usually it’s just this simple declaration. According to the backbone.js documentation, it’s also possible to add an initialize function and to add validation. I’m going to keep things as simple as possible for now though.

Next, I know I want a collection of Profiles, so I will create that in its most simple form:

var ProfileList = Backbone.Collection.extend({
   model: Profile
});

That looks to me to be a collection of individual Profiles.

I know I want to generate the models based on the values in an external JSON file. According to backbone.js: “Set the url property (or function) on a collection to reference its location on the server. Models within the collection will use url to construct URLs of their own.” As a result, I have this:

var ProfileList = Backbone.Collection.extend({
   model: Profile,
   url: '/json/profiles.json'
});

Does the collection automatically go out and grab the JSON? I don’t think I should need to explicitly call fetch() because the documentation says: “Note that fetch should not be used to populate collections on page load — all models needed at load time should already be bootstrapped in to place.” And further: “fetch is intended for lazily-loading models for interfaces that are not needed immediately.” So if I create an instance of ProfileList the models should be created automatically, correct? I’ll try it:

var profiles = new ProfileList();
console.log(profiles);

This results in an empty object. Am I not giving it enough time to grab the JSON? If I could trigger the call to console.log on a “success” event or something similar, that would be a good way to know the collection has grabbed the data.

Changing my code to this produces different results:

var profiles = new ProfileList(); 
profiles.fetch();
console.log(profiles);

But I still think I need to trigger console.log with an event. When I look at the results using Firebug, it still shows me an empty object, but now when I click through to see the empty object in more detail I can see that the data is there. It had showed me more emptiness when I clicked through it before adding the explicit call to fetch().

Here is my attempt to bind the call to console to when the collection grabs the data (note that this at least partially derived from this StackOverflow example):

var profiles = new ProfileList(); 
profiles.fetch();
profiles.bind('reset', function () { console.log(profiles); });

And indeed this works. The backbone.js documentation says I shouldn’t call fetch explicitly on page load though. So how do I get the data without calling fetch()?

I found a StackOverflow thread that addresses this exact issue. The answers are not crystal clear to me though. I think the conclusion is that you can either send in a static reference to an initial set of data, then call fetch() as needed to grab more, or you call fetch explicitly like I am doing.

I suppose I could change my JSON file to create a variable holding all my data, then pass it directly to the collection. That avoids a server call, but it doesn’t seem right. For one thing it will be a little cumbersome to switch to a dynamic data source (e.g. a db) down the line. I guess it just seems less flexible in general.

I’ll stick with explicitly calling fetch() for now.

Now I need to display my data. I need to create a view to display the profiles. The view should use an underscore template I have created and the rendering should be triggered by the ‘reset’ event of the profiles collection. I have a div already on the page and I’d like the newly created DOM elements to be inserted into that div.

The ID of the element into which I want the new DOM elements inserted is “profiles,” so the first line of my view is :

el: "#profiles"

My understanding is that by setting the ‘el’ property I am telling backbone there is an existing DOM element I want to use. If instead I were to set values for “tagName”, “className”, “id” or “attributes” properties, backbone would create a new element with those attributes.

I know that to specify the template to be used by the view I do this:

template: _.template($('#profileTemplate').html()),

Where the template with the id ‘profileTemplate’ looks like this:

<script id="profileTemplate" type="text/template">
   <div class="profile">
      <div class="info">
        <div class="name"><%= name %></div>
        <div class="title"><%= title %></div>
        <div class="background"><%= background %></div>
      </div>
  </div>
</script>

I think my view can have a simple render function that looks like this:

render: function(eventName) {
   _.each(this.model.models, function(profile){
      var profileTemplate = this.template(profile.toJSON());
      $(this.el).append(profileTemplate);
   }, this);

   return this;
}

So the complete view looks like this:

var ProfileView = Backbone.View.extend({
   el: "#profiles",
   template: _.template($('#profileTemplate').html()),
   render: function(eventName) {
      _.each(this.model.models, function(profile){
         var profileTemplate = this.template(profile.toJSON());
         $(this.el).append(profileTemplate);
      }, this);
      return this;
   }
});

Indeed, this works as I had hoped.

Here’s the code from today’s complicated look at a simple backbone application:
backbone.blog.1.zip

Tomorrow I’m going to jump to a slightly more complicated example. I’d also like to incorporate the above code into a more general app view that can handle multiple sub views.

Here are some handy links to parts 2 and 3 of this tutorial:

More with Backbone

In my last entry I had made a small change to an existing backbone.js application. Instead of loading all projects in my company’s portfolio, I adjusted the view to only load a subset of them. I still need, however, to create a “load more” button to allow the user load the remainder of the projects as desired. I left my previous entry wondering how to do this.

I think I know how to add the event that the button will trigger at least. It should look like this:

 events:{
    "click .more" : "renderNextProjectGroup"
 }

And renderNextProjectGroup should figure out how many projects are currently being displayed n, then load n + 1 through n + 1 + projectsPerLoad. How do I determine how projects are currently being displayed?

I know I can do this using basic jQuery:

renderNextProjectGroup: function () {
   var that = this;

   var start = $(".project").length;
   var end = start + (that.projectsPerLoad - 1);
   that.renderProjectGroup(start, end);
},

start grabs the number of projects currently displayed. end simply adds the number of additional projects to show.

This works but it feels wrong. Should a view (or model?) be keeping track of how many projects are currently displayed, or is ok to grab that info as-needed like I’m doing?

I think a bigger offense, however, is using “.project” instead of grabbing this value from the ProjectView, which look like this:

var ProjectView = Backbone.View.extend({
   className: "project coda-slider-wrapper",
   template: $("#projectTemplate").html(),

   render: function () {
      var tmpl = _.template(this.template);
      this.$el.html(tmpl(this.model.toJSON()));
      return this;
   }
});

How do I use backbone/underscore to determine how many elements there are with ProjectView.className?

I tried this but it doesn’t work:

var Portfolio = Backbone.Collection.extend({
   model: Project,
   url: '/json/projects.json',
   projectClass: "project2 coda-slider-wrapper"
});

var ProjectView = Backbone.View.extend({
   className: this.Portfolio.projectClass,
   ....
});

Hm. I’ve decided I’m never going to figure out how this is typically done within backbone until I see it done using backbone. I need to find an existing example of a similar effort.

< … googling “backbone pagination” … >

I found a backbone plugin (or component, if you will) that seems to do exactly what I’m trying to do: http://addyosmani.com/blog/backbone-paginator-new-pagination-components-for-backbone-js/

< … frustrating efforts to use addy osmani’s pagination components … >

I can’t get Addy Osmani’s pagination components to work. Despite the ability to customize the query parameters, I can’t figure out how to get the paginator to work with my data. It calls my data but I don’t know if the data is being successfully set up in a array somewhere or what has happened to it.

Maybe there is something more simple out there. Maybe I can just do this myself after all. All I really need is the load more button and a better way to keep track of the total number of projects. Maybe I can use the pagination component for ideas, but just code it myself.

One thing I haven’t been sure of is whether I should simply hard code the HTML for the load more button or use a template. Osmani’s pagination component uses a template and that seems reasonable, so I will start there. The code for the button will look like this (adapted from Osmani’s):

<script id="projectPagination" type="text/html">
   <% if (page < totalPages) { %>
      <a href="#" class="btn project_next">Show More</a>
   <% } %>
</script>

Obviously I need to put values to page and totalPages. Osmani’s pagination component declares those values in the collection, which makes sense. I can set the totalPages value when the collection finishes fetching the data. Here’s what I end up with:

var Portfolio = Backbone.Collection.extend({
   model: Project,
   url: '/json/projects.json',
   projectClass: "project2 coda-slider-wrapper",
   numProjects: 0,
   page: 0,
   perPage: 5,
   totalPages: 0,

   parse: function(response) {
      this.numProjects = _.size(response);
      this.totalPages = Math.ceil(this.numProjects / this.perPage);

      return response;
   }
 });

This all works as expected. But what about the page variable? Where and when should that be set? Beyond the initial declaration the page variable is nowhere to be found in the collection. Osmani’s collection does extend paginator.requestPager though. It’s all over the place there. Because our needs are so much more simple than what Osmani’s code does though, I think I will just do this myself.

First I’m going to set up the event that’s triggered when the load more button is clicked.

< … big time struggling with how to share a controller between multiple views … >

I can’t figure out how to have my PortfolioView, which displays all the projects, and my LoadMoreView, which is simply the button that will load more projects, both get values from the controller. PortfolioView needs the models from the controller to display each project, and LoadMoreView needs to know if it should continue to be displayed.

Finally I have found “Developing Backbone.js Applications” and the “Gotchyas” section of “A Conceptual Understanding of Backbone.js For The Everyman“. Both describe passing a model and the collection it belongs to to each view. I’m going to give that a try.

 

Backbone attempt #4080

I have neglected the blog for some time. I think it was due to the fact that I began working on a project in WordPress and it just wasn’t presenting me with the type of challenge that I want to focus on in this blog. Or maybe I just got lazy, one of the two.

I don’t mean to say WordPress isn’t challenging. I have worked with WP before but I’m far from an expert. I learned a lot about it and I learned as I built out the project – not always the best way to do things, but I think it came out pretty well. I created a (very simple) plugin, contributed to another, and built a child theme. I’m quite sure there are things I could have done better, but the site feels pretty solid and our client has a straightforward UI to work with to enter new content.

I’m now going to return to looking at backbone.js. It’s an MVC framework that I have looked at using previously, but I never got too far with it.

For one thing, is it just me or is the backbonejs.org home page daunting? The single-huge-scrolling-page thing is off-putting to me. I know the left hand navigation should alleviate my anxiety but it just doesn’t. I guess I’ll get used to it over time.

Fortunately I have a real-world project I get to dig into instead of needing to build something from scratch. The Fortified Studio Web site needs a small alteration, so I’m going to see what I can do about it.

Instead of listing all x Fortified projects, we want to list just y (where y = 5 for starters). I should be able to do this, right?

For starters, what is the present value of x? I have sadly never really used underscore.js, so I need to try it out. I see right away there is a method called size(). Let’s try it out.

Indeed it works like a charm. By running the following statement in the View’s render I find out Fortified is currently displaying 14 projects in its portfolio. Not too shabby.

console.log("# projects = " + _.size(this.collection.models));

Seems like it would be easy enough to limit the display to any number of projects. And providing a link to show the rest would also be easy to do (I think). But what about loading a specific number of additional projects? For example, what if we initially display five projects, then provide a load more button that will load up to five more and continue to display the load more button if more projects are available? We’d have to keep track of how many projects are currently displayed, but I can’t think of any other complications.

My View (“PortfolioView”) currently has a render method that triggers the rendering of all portfolio items, and a renderProject method that handles the rendering of each project. I’m going to add a renderProjectGroup method that will load, well, a group of projects. This will  replace render’s job of rendering all projects at once. Here’s the signature of the method I will create:

renderProjectGroup : function(start, begin) {}

My unfamiliarity with underscore.js flares up again. Is there a way to extract a subset from a collection like this – by providing a start and end index? None of the underscore methods are jumping out at me, so I’ll turn to Google.

< … googling but finding nothing … >

I thought for sure that would be a common issue. Stupid internet. I took a closer look at the underscore methods and I think I may have something.

The filter() method returns each element in a collection and returns a new collection comprised of the elements that pass a given test. The documentation doesn’t mention it, but if the second parameter passed to the filter is the index of the element being passed. We can then check for the value of the index in the filter, and cut the collection off after a given number. Like this:

var start = 0;
var end = 3;
var sublist = _.filter([1, 2, 3, 4, 5, 6], function(num, index){
     return (index >= start) && (index <= end);
});

The result is:

[1, 2, 3, 4]

Sweet. That seems to work. Here’s how it looks within the Fortified site:

renderProjectGroup : function(start, end) {
    var that = this;
    var subset = _.filter(this.collection.models, function(num, index){
        return (index >= start) && (index <= end);
    });

    _.each(subset, function (item) {
        that.renderProject(item);
    }, this); 
},

Still need to create a load more button that will call that renderProjectGroup. I’m not sure how to approach this in the best backbone way. Do I include the button in the HTML then add the functionality to a view or controller? Or do I use a view to generate the button then bind its events to a method in a view or controller? I’m going to stop here and continue tomorrow.

WordPress: Adding meta boxes

In an earlier post, I created some custom post types from scratch. They’re working, but they’re mostly still sitting there with their default settings. So they just have a title field and a big ol’ description field. I need to add some custom fields. The first one I’d like to add is a FAQ field. I guess that will be a question field and a corresponding answer field. And the user should be able to create as many as he or she would like (I believe that’s called a “repeatable” field). < … googling … > I found what appears to be a solid tutorial on creating metaboxes with all kinds of fields – including repeatable fields. I’m going to start here and see how it goes. Hmm … just realized … I want to create a meta box that will appear on a Page, but I don’t know where to put the code. 

Getting the meta box to appear on a Page is very simple. The add_meta_box() method has an option $page where you can specify the $post_type on which it should appear. Simply set it to “page” and you’re good to go.

< Need to detail the difficulties with creating a repeatable FAQ item meta box >

I now need to list all the FAQ items on the page. First I simply need to put the page title and content on the page. The title is straightforward:

<h1><?php the_title(); ?></h1>

But how do I get the content for a single page to appear without using The Loop?

< … some googling … >

Apparently there is no way to avoid this. Seems silly to have a whole loop set up when I know I will only ever have one title and one content item. Oh well.

Side note: I need to integrate data sanitization into my meta boxes.

Another problem I’ve run into is how do I get a meta box to appear only on a specific page in the admin interface? It turns out that there is no good way to do this. Actually the question itself doesn’t really make sense. Let’s break it down: I want the FAQ item meta box to only appear on my FAQ page. If I haven’t already created that page, how can I write any kind of conditional to include it? If I have already created the page, I can then say something like “if this is the FAQ page, include the meta box.” But then I get the awkward progression: 1) Create and save the FAQ page, 2) Reload the FAQ page so the meta box appears.

I think what I’d like to do is include a button that can add the meta box dynamically to any page. So the user can click “Add FAQ items to this page” and the meta box will appear. In that case I will have to move the loop that displays the FAQ items to a more general Page template (right now it’s only on the FAQ page. I’m not sure how to set that up.

WordPress: Creating a child theme

I’m going to try to be a good WP citizen today. Instead of just hacking the new theme (Roots) I just installed, I am going to create a child theme.

Roots seems to want to discourage users from creating a child theme:

There is a tradeoff however. One of the philosophies behind Roots is to be clean and simple which is why we rewrite URLs in the form of /wp-content/themes/roots/ to /css/js, etc. Unfortunately, this doesn’t work with child themes.

I haven’t run into too many issues though. I created a “Proteus” folder to hold the child theme’s files, then I copied the empty style.css file from the Roots theme. As advertised on the WordPress Codex site, the style.css file is the bare minimum needed to create a theme.

Roots also discourages importing the parent style.css file because it hurts performance. I’m going to follow their advice for now because Roots’ style.css file is empty anyway.

In my early efforts to create the theme, I have borrowed a few other files from the Roots parent theme:

  1. front-page.php: I needed this one to create the home page carousel. I copied in the code I created in earlier effort to create the carousel.
  2. functions.php: I needed this file to call in the custom post types I created earlier. That’s all I put in this file. The parent version of the file will still be called (after the child version).
  3. main.js, vendor/bootstrap-carousel.js: Needed these for the front page carousel.
  4. inc/scripts.php: Needed this to call in the two JS files above.

When I created inc/scripts.php, I unwittingly lost everything in Roots’ version of inc/scripts.php. I tried a bunch of different things to include the contents of the parent theme until finally this snippet was the ticket:

if (!defined('__DIR__')) { define('__DIR__', dirname(__FILE__)); }
include __DIR__ . "/../../roots/inc/scripts.php";

I set up a Sass directory in the child theme, then wrote some code in my new inc/scripts.php file to point to the resulting CSS files. All good.

Roots Theme for WordPress

The Roots theme for WordPress integrates Twitter Bootstrap and the HTML5 Boilerplate into WordPress. I’m going to see what it’s all about.

Installation is straightforward, as it is for most WordPress themes. I have some custom post types from a previous project that I need to bring over, so I’m going to do that now. I’ve mentioned before that I need to move these custom post types into a plugin instead of having them tied to a theme, but that’s a task for later.

I simply copied my post type definitions (I had placed each of them in separate files) into the Roots theme folder, then I require’d them in my functions.php file. They post types show up in the admin nav, so things are looking promising.

When I go to create the first instance of my one of my new post types, however, I get some errors. I try to upload several images at once and for each upload I get this error:

"image name" has failed to upload due to an error
Unable to create directory /Users/me/Sites/wordpress/assets. Is its parent directory writable by the server?

After temporarily setting the permissions on /Users/me/Sites/wordpress/assets to 777, I am able to upload the files.

I had used Nathan Searle’s simple carousel script in my previous effort to create a carousel on the home page, but now that I’m using a theme based on Twitter Bootstrap, I may as well use their carousel plug-in.

< … some coding … >

Carousel is working now, though I had to battle through some stuff. The carousel section of the Twitter Bootstrap documentation doesn’t mention that you need to include transitions.js and you need to include the class of the transition you want in your main div. The example HTML looks like this:

<div id=”myCarousel” class=”carousel”>

But to add the slide transition (like the one used in the example carousel), it needs to look like this:

<div id=”myCarousel” class=”carousel slide“>

I need to add some styles from my previous effort so the label and text information for each slide are overlayed on the graphic. Before I do that, however, I need to set up Sass (via Compass) for this new installation.

<… trying to get Compass/Sass working … >

I had some difficulties with the Compass config.rb file – particularly with getting the http_path and the css_dir correct – but eventually I got it smoothed out. I then had some problems trying to figure out where to put my styles within the Roots theme. Eventually I figured that out too: inside the roots/app.css file. A little different than a typical WP theme, but that’s ok.

 

 

Using Sass with WordPress

I’ve never used Sass, so this will be an interesting task. I’ve used LESS a little, so I think I get the basic idea and I know the benefits of using a CSS generator. I was fiddling with a theme recently and it seemed to be crying out for Sass or LESS so I’m going to give it a go.

As usual I’m going to look for tutorials that will walk me through this. I’ve found a few promising entries so far:

  • Using Sass and Compass for managing CSS in WordPress
  • I think that first one will get me well on my way, but I also have never used Compass. Hopefully the Compass site will help me figure things out.
  • Finally, I’ve seen Forge mentioned a couple times (including the comments of the tutorial linked to above). The Forge home page describes it as a “command-line toolkit for bootstrapping and developing WordPress themes in a tidy environment using front-end languages like Sass, LESS, and CoffeeScript.” I’ll check it out.

< … gets one minute into tutorial … >

This is not starting well. I’ve tried to install Ruby 1.9.3-p0 per the instructions, but I’m getting the following error message:

The provided compiler '/usr/bin/gcc' is LLVM based, it is not yet fully supported by ruby and gems, please read `rvm requirements`.

I’ve come across this error before but I can’t remember if I solved it or just worked around it. I’m also not sure if really need 1.9.3 or if I can just use 1.9.2-p320, my currently installed ruby version.

On a whim (it should have been the first thing I did) I ran rvm list and it turns out I have 1.9.3-p194 already installed. How’s about if I just use that.

Hmm … What’s the command for switching versions in rvm? rvm use 1.9.3 is the command I needed.

Next issue: I installed compass but when I go to run compass create test I get “compass: command not found”.

< … research resarch research … >

Turns out I needed to run sudo gem install compass. With that cleared up, I followed the rest of the tutorial and I’m all good.

One note about the tutorial: It seems that if you provide an incorrect path to the config.rb file for compass, it will not only not give you an error message, it will create the non-existent directory and any other non-existent directories that comprise the path. I found this out the mildly hard way.

WordPress – Creating a carousel on the home page

I’ve been looking around for a way to implement a carousel on the home page. I have used some jQuery libraries that are good and flexible for this sort of task. But how do I set up WordPress to provide the content that will comprise the elements of the carousel?

Do I let the admin just create posts, then bring the post information into a jQuery-powered carousel? Or do I create a custom data type where the user creates a single instance with a bunch of images? What if I need images plus text? Should I just grab a plugin?

I want this to be as easy as possible for the admin. They should just pick their content and the order they want it in and presto, carousel.

I found a promising pair of blog entries from Bluelime Media:

I have only skimmed through the posts, but I think they’ll get me where I want to go.

< … code, code, code … >

The first tutorial did indeed set up a carousel on my home page. The carousel takes images inserted into a static page I created, and spit out the attached images into a div that is converted to a carousel by the Nathan Searle’s simple carousel script.

Pretty simple stuff, although I did have to figure out how to get the site to point to the static page I had created as the home page. The full explanation for creating a static home page can be found on this WordPress Codex page, but it basically involves 1) going into the admin settings > reading panel and selecting my static page as the home page and 2) editing front-page.php to suck in my new static page and spit out the images as I wanted.

So that’s set up, but it doesn’t seem very flexible. For instance, what if I want more than just an image in one of my carousel slides? The second of the two blog entries promises to create a carousel of custom post types, which seems like it’s exactly what I want.

< … much frustrating searching and experimentation … >

Annoying. I am trying to set up the carousel using a custom post type, but it depends on setting a featured image for east post. No matter what I do, however, I can’t get the option to select a featured image to show up!

Update: Finally figured it out. I needed to include this line in my functions.php file:

add_theme_support('post-thumbnails');

A second argument, an array of post types, can also be passed to add_theme_support.

Aside: Here’s a kind of interesting thing that happened: One of my custom post types needed to change from “Story” to “Conversation.” If I simply copy and replace and make the changes, however, I lose any existing stories. They’re still in the DB, but there’s no way to access them. This blog post explains that I just need to make a couple simple changes to each of the posts and they will appear as the new post type. And indeed it does work.

I was able to follow the second blog post and get things working. One thing that is lacking, however, is the ability to order the carousel items. I think this can be remedied fairly easily by adding a meta box to allow an admin to specify a weight or an order number. Weights would be easier but are obviously not as specific, whereas order numbers are specific but the logic (i.e. making sure no other carousel item has the same order number) can get complicated. Order numbers would be best added on the page where all carousel items are listed, but I currently have no idea how to do that.

I’ve found a seemingly good plugin that allows for drag-and-drop ordering of hierarchical post types. It allows admins to reorder posts on the page where all posts are listed. The only problem is that I don’t know how to extract the hierarchical order when I’m trying to create the carousel. 

Aha! I found an error in the code provided in the second of the Bluelime media tutorials. The code for querying the DB looked like this:

$loop = new WP_Query(array('post_type' => 'carousel', 'posts_per_page' => -1, 'orderby' => 'ASC'));

But setting the value of ‘orderby’ to ‘ASC’ doesn’t make sense. I changed “orderby” to “order” and added ‘orderby’ => ‘menu_order’ and it’s all good now.

$loop = new WP_Query(array('post_type' => 'carousel', 'posts_per_page' => -1, 'orderby' => 'menu_order', 'order' => 'ASC'));