Many to many relationships let you connect between posts. We will explain how to setup this sort of relationship and how to display websites that feature it.

Our Example – Bands and Events

Let’s say that we’re creating a website for music bands. We’d like to list events where these bands play.

A band will play in many events and each event includes many bands. We call this a “many-to-many” relationship.

Different bands appear in different events

In this tutorial, we’ll show how to:

  1. Use an intermediary object to create the many-to-many relationship
  2. Define the parent / child relationship
  3. Populate content and create the relationship
  4. Display related content

Creating Many to Many Relationships Using an Intermediary Object

So, you’re probably wondering how to make this connection. After all, the band doesn’t really belong to events and events certainly don’t belong to any band.

The answer is in an intermediary object, which sits between bands and events. That intermediary object will naturally belong to both the bands and the events, connecting between them.

In our example, bands appear in events. Appearances will be the connecting objects.

Each band has many appearances and each event has many appearances. Appearances are the key to creating the many-to-many relationship we’re looking for between bands and events.

If you want to list all the events where a band appears, you will query the appearances that belong to the band and then list the events that belong to these appearances.

Similarly, to list all the bands that appear in an event, you will query the appearances that belong to an event and the list the bands that belong to these appearances.

Takeaway: The key to defining a many-to-many relationship is identifying the intermediary object.

Defining Many-to-Many Relationship with Types

If we want to implement the above example with Types, we’ll create the three custom post types for:

  • Bands
  • Events
  • Appearances

Go to Toolset->Post Types and click on Add New. If custom post types are new to you, start by readying about setting up custom post types.

Now, you want to connect between these three types. At the bottom of the custom post type editor, you will find Post Relationship (Parent / Child) section (learn more about post relationship in Types).

Since appearances belong to both bands and events, we should edit the appearances type and set both ‘bands’ and ‘events’ as parents of appearance.

Post relationship for Appearances

Populating Content

Now that we have the parent relationship set up correctly, we can start creating the site’s content. You can create the bands, events and appearances that you need.

When you create an appearance, scroll down to the bottom of the page. You’ll discover a Post Relationship box. Since appearances belong to both bands and events, you’ll see both parent types there.

Selecting parents for Appearances

Choose the correct band and event for each appearance and you’ve made the connection.

There are other ways to create connected content. You can edit the appearances directly from the bands and event edit screens.

Appearances showing on bands edit page

You can read more about it in Editing Post Fields of Child Posts.

Displaying Connected Content

So far, we covered defining and populating content. The last piece of the puzzle is being able to display that content.

  • When we are on a bands page, we want to display the events where you can listen to that band.
  • When we are on an event page, you want to see which bands are playing.

The recipe to do this is:

  1. Load the intermediary objects that belong to side A.
  2. Display the objects from side B that are their parents.

We’ll show how to do this both using Views and with plain PHP code. Let’s say that we want to list all the bands that play in an event.

Displaying Many-to-Many Relationships Using Views

The steps that we’ll take are:

1. Create a View that loads all the appearances that belong to the Event

Creating a View to query appearances

When you create this View, remember that we are querying the intermediary post. In our case – appearances. Add a filter for event parent, selecting Post where this View is inserted. This will keep just the appearances that belong to the displayed event.

2. In the View loop, display the title of band parent post

Displaying the band parent fields

Use any layout you like and insert the fields that you want to display from the parent post type. Then, edit the meta HTML and add id="$band" to the shortcodes. This tells Views to display the fields of the Band parent, instead of the Appearance parent. Read more about displaying fields of parent pages.

3. Insert that View into the Event Content Template

Insert the new View in the the Events Content Template

The View we’ve just created will display the Bands that belong to an Event. You should add it to the Content Template that you’re using to display single Events.

Displaying Many-to-Many Relationship Using Types PHP API

The basic PHP code that will display many-to-many relationship uses the Types API function:

  • types_child_posts('child-post-type-slug')

that loads the children of the current parent post.

Similarly to the View implementation, the below code example will first query all the Appearance children, iterate through them and then display the Band parents of these appearances.

//It will query all child posts of the current event, that are appearance type
$child_posts = types_child_posts('appearance');
foreach ($child_posts as $child_post) {
    $band_id = wpcf_pr_post_get_belongs($child_post->ID, 'band');

    //You can also use WP Native API get_post_meta to get the parent post ID
    //as it is stored in a hidden custom field _wpcf_belongs_post-type-slug_id
    //$band_id = get_post_meta($child_post->ID, '_wpcf_belongs_band_id', true);

    $band = get_post($band_id);
    echo $band->post_title;

Once we have this code, we need to edit the PHP template of the Event custom post type and insert it into the right place.

Below, there is an example on how to create a shortCode that returns all children posts IDs, which is useful to check if a post has child posts, inside a Views Loop.

function child_posts_exist_func( $atts ){
    $child_posts = types_child_posts('child-post-type-slug');
    if ($child_posts) {
        return 1;
    } else {
        return 0;
add_shortcode( 'has-child-posts', 'child_posts_exist_func' );

Then, you can evaluate like this:

[wpv-conditional if="( '[has-child-posts]' eq '0' )"]
    You display things if does NOT have child posts

[wpv-conditional if="( '[has-child-posts]' eq '1' )"]
    You display things if DOES have child posts

Further reading

For another perspective on the same subject try reading about post relationships in our Beyond the Basics training guide.