Docs » Relationships

A core concept in Webhook, relationships allow you to link two forms between each other. Authors <-> Articles, Games <-> Genres, Movies <-> Peoples are all examples of relationships that link items together in meaningful ways.

Below we'll use relations to build a simple IMDB site that links movies to the cast and crew that make them.

Creating a relationship in the CMS.

1. Build two forms: one for Movies, one for People.

First lets assume that we've created two forms in Webhook's CMS. One called "People" that include the person's name, gender, a short bio and a head shot image of that person. We'll also create a form for "Movies" that include the movie name, the poster for the movie, the release date and a small synopsis.

A simple person form.
A simple movie form.

2. Edit one of the forms to add a relation.

Now that we have our two forms set up, it's time to link them together. To do that we'll need to edit the movie form by going to the "Add/Edit Content Types" section of the CMS. Then, using the form builder add a "Relationship" widget somewhere on the form.

Once inserted, click on the widget to bring up it's properties on the left side. You'll see something like this.

We're adding a relation widget to movies. Let's call it "Actors" and set the relation to allow a link to "people".

We're going to name the relation "Actors" and select "People" in the dropdown for "Relationships to allow". This will link our movie page to our people form.

But there are more than actors in movies. So let's also create another relationship called "Director" to this same form, following the same steps. The only difference this time is we'll click "Only allow one searched item and no more". This attribute basically tells Webhook that there can ONLY be one Director per movie.

3. Add some movies and actors!

Now that we have our new relationship widgets in the forms we can start filling out our forms and adding data. Below we've entered in a couple Martin Scorsese movies with links to Robert Deniro and Joe Pesci.

Note how the Director field only allows one relation and no more, while actors can have more.
When we related some actors to our movies, those movies were also automatically related to our actors as well.

Using relations in templates

Relations are called in the template much like any other Webhook widget. You simply use the label name for the widget. Here's an example on our movies/individual.html page.

<h1>{{ item.name }}</h1>
<p>Released on {{ item.release_date|date('M d Y') }}</p>

<h3>Director</h3>
<a href="{{ url(item.director) }}">{{ item.director.name }}</a>

<h3>Actors</h4>
<ul>
{% for actor in item.actors|sort('name') %}
  <li>
    <a href="{{ url(actor) }}">
      {{ actor.name }}
      <img src="{{ actor.head_shot|imageSize(200, 200) }}" />
    </a>
  </li>
{% endfor %}
</ul>

The biggest things to take away from this example is the way the director and the actors are called. We use the LABEL used for the relation widget ("actors"), not the form name we're relating too ("people").

Also note that the actors come in an array of data, and the director can be called directly without a forloop. That's because when we set up the CMS we told Webhook to allow only one Director to be attached to each movie. With actors, we used the default setting, which allows multiple actors to be tied to the movie, so we need to use the forloop in our code.

Sorting relations

Relations can be sorted like any other array in Webhook. In our code example above, we use |sort('name') to sort the list of actors alphabetically. By default, relation arrays are sorted by the order they are listed in the CMS. If we need to change that order, we can simply drag and drop the order to something we're happy with, then hit publish.

Pulling items from your array

Sometimes you don't need the full list of actors. You just need the first one, or need to pass different styling to only the first few. You can do that easily like so.

{# This is the first actor in our movie. #}
{{ item.actors[0].name }}

{# This will return the first 3 actors in our movie. #}
{% for actor in item.actors|slice(1,3) %}
  {{ actor.name }}
{% endfor %}

{# This will print the image for the first two actors in our list #}
{% for actor in item.actors %}
  {% if loop.index < 3 %}
    <img src="{{ actor.head_shot|imageSize(200, 200) }}" />
  {% endfor %}
  {{ actor.name }}
{% endfor %}

Relations within relations

In your templates you can pull data from relations of your relations as well. Let's go back to our /movie/individual.html page and list out other movies by the director of the movie we're looking at.

<h1>{{ item.name }}</h1>
<p>Released on {{ item.release_date|date('M d Y') }}</p>

<h3>Director</h3>
<a href="{{ url(item.director) }}">{{ item.director.name }}</a>

<h3>Other movies by this director</h3>

{# Remember, the movies_directed bit is just the label for the widget on the Person form. #}
{% for movie in item.director.movies_directed %}
  <a href="{{ url(movie) }}">{{ movie.name }}</a>
{% endfor %}

This will print our all other movies by this director, but that might include the movie we're actually looking at! To exclude it form the list, we'll just use Webhook's |exclude filter like so on our forloop.

{# This will exclude any movies in the array that have the same name as the movie we're at right now! #}

{% for movie in item.director.movies_directed|exclude('name', item.name) %}
  <a href="{{ url(movie) }}">{{ movie.name }}</a>
{% endfor %}

Relations to unpublished items

By default the relationship property excludes unpublished items from the resulting array. However, if for some reason you need to access the unpublished objects as well as the published objects you can use the special _relationship parameter on the object to get these items, where relationship is the name of the relationship field.

{# This will get even the unpublished actors #}
{% for actor in item._actors %]
    {{ actor.name }}
{% endfor %}