Relationship Fields: The Pizza Shop Example

Relationship fields allow you to create relationships between one entry and one or more other entries. When you show information for one entry, you can also show all of the information from entries related to that entry.

Let’s start with a very simple example. You’ve been tasked with building a website for a small chain of local pizza joints. Mamma Robin’s has a variety of tasty pizzas:

Pizzas

There are Mamma Robin Restaurants in 3 locations: Battleground Ave, South Street and Hilltop Street. It’s a simple matter to create 2 channels, one to hold information about the pizzas and one to hold information about the stores. Since this is a template writing tutorial, we’ll go ahead and layout the channels for you:

Stores
  title       Text Input
  url_title   Text Input
  address     Textarea
  phone       Text Input

Pizzas
  title       Text Input
  url_title   Text Input
  description Textarea
  ingredients Checkbox

Now let’s complicate things a bit. Though the pizza places share a menu of specialty pizzas, each individual store manager gets to decide which pizzas will be available on any particular week. You need to be able show the pizzas available at each restaurant. Similarly, for each pizza, you need to be able to show which stores are currently carrying that pizza.

A relationship field allows you to link the stores and the pizzas, without entering any of the information twice.

To make this happen, we’ll add one more field to our Store channel specialty_pizzas. Set our relationship field so only entries in the Pizza channel can be related and allow multiple relationships (since a restaurant can have more than 1 pizza).

With the channel and field structure set, we can turn to our template tags.

Child Entries: Displaying the Stores and their Menus

First things first. We need to write a page to list each Store and which pizzas they have to offer.

Stores

Here’s the template tag:

{exp:channel:entries channel="stores"}
  <h1>{title}</h1>
  <div class="right">
    Phone: {phone}</p>
    <p>Address: {address}</p>
  </div>
  <h2>Specialty Pizzas</h2>
  {specialty_pizzas}
    <h3>{specialty_pizzas:title}</h3>
    <p>{specialty_pizzas:ingredients}</p>
  {/specialty_pizzas}
{/exp:channel:entries}

We start with the standard {exp:channel:entries} tag, pulling from the Stores channel. For each Store entry we display the Store name, the Store’s phone number and its address. Then we display which specialty pizzas are available:

<h2>Specialty Pizzas</h2>
{specialty_pizzas}
  <h3>{specialty_pizzas:title}</h3>
  <p>{specialty_pizzas:ingredients}</p>
{/specialty_pizzas}

The {specialty_pizzas} tag is a Relationship variable tag. Since it is a relationship that can take multiple entries, it is a looping tag pair. So these two lines, contained in the pair, will be looped over:

<h3>{specialty_pizzas:title}</h3>
<p>{specialty_pizzas:ingredients}</p>

The variables will be replaced for each Pizza entry that is attached to the current Store entry. In those lines {specialty_pizzas:title} will be replaced by the title of the current Pizza entry and {specialty_pizzas:ingredients} will be replaced by a comma separated list of ingredients.

Notice that what we’re doing here is prefixing the names of the variables in the Pizza channel with the name of the Relationship field that relates the Store channel to the Pizza channel. We call this namespacing and it’s a very powerful tool. This is what allows us to access the variables of the related entries, even though they may be the same as those of the parent entries.

Inside the {specialty_pizzas} tag pair, you can use {title} to display the title of the current Store entry and {specialty_pizzas:title} to display the title of the current Pizza entry. This means we can nest relationships as deeply as we want to with out having to worry too much about naming collisions.

Parent Entries: Which Stores have Which Pizza?

Another template you might want to make is a page for each pizza where you give a description of the pizza, list its ingredients and show which stores currently have the pizza available.

Pizzas

The {parents} tag outputs all restaurants currently featuring a specific pizza. Like so:

{exp:channel:entries channel="pizzas"}
  <h2>{title}</h2>
  <p>{description}</p>
  <p>{ingredients}</p>
  <h3>Where can I find this pizza?</h3>
  {parents field="specialty_pizzas"}
    <strong>{parents:title}</strong>: <br />
    {parents:phone} <br />
    <p>{parents:address}</p>
  {/parents}
{/exp:channel:entries}

In this template we list the Pizza channel’s variables – {title}, {description} and {ingredients}. Then we have a section to show in which stores this pizza is currently available. To accomplish this, we use the {parents} tag.

The {parents} tag will pull entries that have the current Entry from the {exp:channel:entries} tag as a child through the field that you specify. If you use the same field group in multiple channels, you may want to also specify the channel. In this case, we’re passing it the specialty_pizzas field. It will look for all entries attached to any channel through the specialty_pizzas field that have the current Pizza entry as a child. In our case, specialty_pizzas is only used in the Stores channel and this will have the result of finding all Stores that currently have this Pizza available.

The {parents} tag is a looping tag pair. So for each Store it finds, it will loop over the section of template contained in the pair:

<strong>{parents:title}</strong>: <br />
{parents:phone} <br />
<p>{parents:address}</p>

It will replace that section’s variables and append it to the final output. Here, we use namespacing again to access the parent Store’s variables. We access its title, phone and address using parents:title, parents:phone, and parents:address.

Robin Sowell's avatar
Robin Sowell

Robin got involved with EllisLab in 2002, using pMachine Pro to build a personal site. Since then, her casual interest has grown into an obsession and she enjoys nothing more than seeing what new…

Comments 1

March 9, 2021

alma

2258 / 5000 Resultados de traducción Good evening Robin Sowell would it be possible to contact you we have a problem with the Relationships and the grids. We have two channels 1st channel “accounting accounts” 2nd channel “material orders” In the orders channel we have a grid entry in which a Grid Fields with a Relationships field where we enter the Accounting Accounts channel. The problem is that we want to relate each of the Relationships only with its channel, right now we use this code:

{exp:channel:entries channel=”pedidos_de_material” status=”open|closed|rechazado|aprobado|pendiente” limit=”1000” show_future_entries=”yes” show_expired=”yes”} <ul> <li>Titulo del canal: {title} <ul> {pedido} <li>
Concepto del grip: {pedido:conceptos} - {pedido:precio}€

</li> {/pedido} </ul> </li> </ul> {/exp:channel:entries}


{exp:channel:entries channel=”cuentas_contables” status=”open|closed” limit=”1000” show_future_entries=”yes” show_expired=”yes”} <ul> <li>{title} - {preupuesto_anual} {preupuesto_anual:presupuesto}€ - Año: {preupuesto_anual:ano format=”%Y”} {/preupuesto_anual} <ul> {parents status=”open|closed|aprobado|rechazado”} <li>
{parents:title}

{parents:pedido} * {parents:pedido:fecha_pedido format=”%d/%m/%Y”} {parents:pedido:conceptos} - {parents:pedido:precio}€ *

{/parents:pedido} </li> {/parents} </ul> </li> </ul> {/exp:channel:entries}

The problem comes now since it returns all the relationships in all the channels example:

• 621099 CLUB: RENTING FOTOCOPIADORA - 60000€ - Año: 2021 o Pedido prueba alma [no borrar] * 09/03/2021 Pedido prueba 111 - 1€ * Esta correcto * 10/03/2021 Pedido prueba 222 - 2€ * It should not be shown here * 10/03/2021 Pedido prueba 333 - 3€ * It should not be shown here

• 621002 CLUB: CANON PISCINA CLIMATIZADA - o Pedido prueba alma [no borrar] * 09/03/2021 Pedido prueba 111 - 1€ * It should not be shown here * 10/03/2021 Pedido prueba 222 - 2€ * Esta correcto * 10/03/2021 Pedido prueba 333 - 3€ * It should not be shown here

• 621001 CLUB: CAFETERIA - EQUIPAMIENTO - 50.000€ - Año: 2021 o Pedido prueba alma [no borrar] * 09/03/2021 Pedido prueba 111 - 1€ * It should not be shown here * 10/03/2021 Pedido prueba 222 - 2€ * It should not be shown here * 10/03/2021 Pedido prueba 333 - 3€ * Esta correcto

We would like each Relationships to only be related to its channel only. This is possible?