Guides
Tutorials
Pop Tags

Routes

Handling URLs from an extension

By default every URL in a Webpop project corresponds to the permalink of a specific content in the content repository (or a file in the public folder). This is fine for most cases, but sometimes it can be useful to handle specific URLs from an extension.

There's two different ways to do that:

  1. Export a routes object from the extension and create routes based on the filename of the extension.
  2. Link an extension to a section and export "get" or "post" routes that correspond to URLs within that section.

Custom routes from the name of an extension

You can respond to paths that match the filename of an extension by exporting a routes object from the extension. Here's a simple "Hello, World" example:

greeter.js

exports.routes = {
get: {
":name": function(params) {
response.send("Hello, " + params.name);
}
}
}

This greeter.js extension would respond to a GET request to "/greeter/Mathias" by returning a plain text saying: "Hello, Mathias".

You can handle the following HTTP verbs with exports.routes: OPTIONS, GET, HEAD, POST, PUT, DELETE.

Check out the cart.js extension in the Ecommerce Theme for an example of handling different kinds requests with the object.

Extending sections with custom routes

You can also extend any section with an extension. When an extension has been assigned to a section, it can define routes that respond to URLs within that section. That is, if the section has the permalink “/blog”, then an extension linked with that section can handle any URL starting with “/blog/”.

Any actual content (with a template) matching the URL takes priority for responding to the route.

To handle URLs for a section, an extension must export handlers for the different type of HTTP requests (normally GET and POST) that it wants to handle. Here’s a simple example that will respond to URLs of the kind section.permalink + “/hello/:name” when assigned to a section.

exports.get = {
  "hello/:name": function(params) {
    response.send("Hello, " + params.name);
  }
};

If we assigned this extension to our section with the permalink “/blog”, then “/blog/hello/mathias” would return a simple “Hello, mathias” string.

The response object

When handling a URL, extensions can use the response object to take control of the response.

The simplest method is response.send(body, [headers], [status]). The send method simply sends the specified body and you can optionally specify any additional headers and a status code to send. Here’s a simple extension that would always redirect a URL to the home page:

exports.get = {
  "redirect": function(params) {
    response.send("Redirecting", {"Location": site.url}, 301);
  }
};

Instead of generating a response body manually, you can also handle a request by rendering a template in the Templates folder by using response.render(template, content, [headers], [status]). Here’s a small example of simply rendering the template /hello.tpl

exports.get = {
  "hello/:name": function(params) {
    response.render("hello", {title: params.name});
  }
};

With this “hello.tpl”:

<pop:content><h1><pop:title/></h1></pop:content>

And the extension assigned to the home section, then the following request “/hello/mathias” would return:

<h1>mathias</h1>

Notice how the object passed as the second argument to the render method becomes that <pop:content> tag in the template.

You can handle optional parameters in routes by adding a ? to the parameter. Here’s the simple hello example with an optional name:

exports.get = {
  "hello/:name?": function(params) {
    response.render("hello", {title: params.name || "Anonymous"});
  }
};

When an extension is handling a request, you can access the section as a global variable. Here’s an extension that finds any entry from a given year in the section it has been attached to:

exports.get = {
  ":year": function(params) {
    var result = site.search({
      filters: {published_at: params.year},
      "in": section,
      type: "entry"
    });
    response.render("yearly", {year: params.year, entries: result.results});
  }
};

Here’s an example “yearly.tpl” that would show a list of entries from a given year:

<pop:content>
  <h1>Entries from <pop:year/></h1>
  <pop:entries>
    <h1><pop:title/></h1>
    <pop:body/>
  </pop:entries>
</pop:content>

When an extension is assigned to a section, all the methods the extension exports also get added to the section object. This means that if the following extension:

exports.extended_title = function() {
  return 'The title is: "' + section.title + '"';
};

Extends our section “blog”, then the you can use extended_title in your templates as if it was a custom field added to the section. An example:

<pop:content from="blog">
  <h1><pop:extended_title/></h1>
</pop:content>

This would output <h1>The title is: "Blog"</h1>.

Continue to Global Site Object »