How do I create a relationship between two custom post types?

I want to build a TV series database using WordPress. I have followed some tutorials and I have two custom post types: one for movies, one for and series. I followed this post for the structure.

My question is: how can I make the relationship between the movies and series post types?

Related posts

3 comments

  1. Using a Plugin

    Some very good plugins for relationships:

    Using a Metabox

    You can build a simple relationship using metaboxes:

    add_action( 'admin_init', 'add_meta_boxes' );
    function add_meta_boxes() {
        add_meta_box( 'some_metabox', 'Movies Relationship', 'movies_field', 'series' );
    }
    
    function movies_field() {
        global $post;
        $selected_movies = get_post_meta( $post->ID, '_movies', true );
        $all_movies = get_posts( array(
            'post_type' => 'movies',
            'numberposts' => -1,
            'orderby' => 'post_title',
            'order' => 'ASC'
        ) );
        ?>
        <input type="hidden" name="movies_nonce" value="<?php echo wp_create_nonce( basename( __FILE__ ) ); ?>" />
        <table class="form-table">
        <tr valign="top"><th scope="row">
        <label for="movies">Movies</label></th>
        <td><select multiple name="movies">
        <?php foreach ( $all_movies as $movie ) : ?>
            <option value="<?php echo $movie->ID; ?>"<?php echo (in_array( $movie->ID, $selected_movies )) ? ' selected="selected"' : ''; ?>><?php echo $movie->post_title; ?></option>
        <?php endforeach; ?>
        </select></td></tr>
        </table>
    }
    
    add_action( 'save_post', 'save_movie_field' );
    function save_movie_field( $post_id ) {
    
        // only run this for series
        if ( 'series' != get_post_type( $post_id ) )
            return $post_id;        
    
        // verify nonce
        if ( empty( $_POST['movies_nonce'] ) || !wp_verify_nonce( $_POST['movies_nonce'], basename( __FILE__ ) ) )
            return $post_id;
    
        // check autosave
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
            return $post_id;
    
        // check permissions
        if ( !current_user_can( 'edit_post', $post_id ) )
            return $post_id;
    
        // save
        update_post_meta( $post_id, '_movies', array_map( 'intval', $_POST['movies'] ) );
    
    }
    

    And then, to get the movies relationship as a list for series posts:

    $series = new WP_Query( array(
        'post_type' => 'movies',
        'post__in' => get_post_meta( $series_id, '_movies', true ),
        'nopaging' => true
    ) );
    
    if ( $series-> have_posts() ) { while ( $series->have_posts() ) {
        $series->the_post();
        ?>
        <li><a href="<?php the_permalink(); ?>"><?php the_title(); ></a></li>
        <?php
    } }
    
  2. I recommend the Posts 2 Posts plugin, which I’ve just started using.

    It allows you to create many-to-many relationships between posts and page types, meaning you can link movies to series, and any other CPTs you may create.

    This plugin also allows you to create connection metadata which will allow you to get finer detail when creating your connections. It is quite flexible in its usage, allowing for control over admin metaboxes, connection types, and ways to display your connections on the front end. Lastly, it is well-documented.

  3. Unfortunately, the Posts 2 Posts plugin is deprecated and no longer maintained. There is a new alternative plugin for that MB Relationships. It’s inspired by P2P and provides a similar API to create relationships between posts, terms and users.

    MB Relationships supports bi-directional relationships by default and use a custom table to store relationships (like P2P) for a better performance (than post meta).

    It’s worth taking a look at the plugin.

Comments are closed.