How to connect different CPTs together?

As a programmer, I would start writing my own code to connect my post types. It’s not a quick way, it’s not easy, but it’s a lot of fun.

The post types

We start by creating two simple post types, Author and Books:

add_action('init', 'p2p2_register_author');
add_action('init', 'p2p2_register_book');

function p2p2_register_author(){
    $labels = array(
        'name'               => 'Author',
        'singular_name'      => 'Author',
        'add_new'            => 'Add New',
        'add_new_item'       => 'Add New Author',
        'edit_item'          => 'Edit Author',
        'new_item'           => 'New Author',
        'all_items'          => 'All Authors',
        'view_item'          => 'View Authors',
        'search_items'       => 'Search Authors',
        'not_found'          => 'No authors found',
        'not_found_in_trash' => 'No authors found in Trash',
        'parent_item_colon'  => '',
        'menu_name'          => 'Authors'
    );

    register_post_type(
        'Author',
        array (
            'labels'             => $labels,
            'public'             => true,
            'publicly_queryable' => true,
            'show_ui'            => true,
            'show_in_menu'       => true,
            'query_var'          => true,
            'rewrite'            => array( 'slug' => 'author' ),
            'capability_type'    => 'post',
            'has_archive'        => true,
            'hierarchical'       => false,
            'menu_position'      => null,
            'supports'           => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments' )
        )
    );
}
function p2p2_register_book(){
    $labels = array(
        'name'               => 'Books',
        'singular_name'      => 'Book',
        'add_new'            => 'Add New',
        'add_new_item'       => 'Add New Book',
        'edit_item'          => 'Edit Book',
        'new_item'           => 'New Book',
        'all_items'          => 'All Books',
        'view_item'          => 'View Book',
        'search_items'       => 'Search Books',
        'not_found'          => 'No books found',
        'not_found_in_trash' => 'No books found in Trash',
        'parent_item_colon'  => '',
        'menu_name'          => 'Books'
    );

    register_post_type(
        'Book',
        array (
            'labels'             => $labels,
            'public'             => true,
            'publicly_queryable' => true,
            'show_ui'            => true,
            'show_in_menu'       => true,
            'query_var'          => true,
            'rewrite'            => array( 'slug' => 'book' ),
            'capability_type'    => 'post',
            'has_archive'        => true,
            'hierarchical'       => false,
            'menu_position'      => null,
            'supports'           => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments' )
        )
    );
}

Nothing fancy there. In fact, it’s from the Codex!

The metabox

Let’s continue by adding a metabox for our author to our book post type:

add_action('admin_init', 'p2p2_add_author_metabox');

function p2p2_add_author_metabox(){
    add_meta_box( 
        'book_author', 
        __('Book Author', 'bandpress'), 
        'p2p2_book_author_metabox', 
        'book', 
        'side', 
        'default', 
        array( 'id' => 'p2p2_author') 
    );
}

Here you can see a callback function p2p2_book_author_metabox which is going to be what’s inside our metabox.

The content of the metabox

Let’s create the function:

function p2p2_book_author_metabox($post, $args){
    wp_nonce_field( plugin_basename( __FILE__ ), 'p2p2_book_author_nonce' );
    $author_id = get_post_meta($post->ID, 'p2p2_book_author', true);

    echo "<p>Select the author of the book</p>";
    echo "<select id='p2p2_book_author' name="p2p2_book_author">";
    // Query the authors here
    $query = new WP_Query( 'post_type=author' );
    while ( $query->have_posts() ) {
        $query->the_post();
        $id = get_the_ID();
        $selected = "";

        if($id == $author_id){
            $selected = ' selected="selected"';
        }
        echo '<option' . $selected . ' value=" . $id . ">' . get_the_title() . '</option>';
    }
    echo "</select>";
}

Here’s where the magic happens. First we’re going to query the database for authors and then we fill a <select> with our query results. Check the Codex for more about WP_Query. Now you can go to your book post type and see your dropdown:

Our dropdown

Saving our content

Off course we want to save our selection so we add another function that’s going to save the metabox for us:

add_action('save_post', 'p2p2_save_author_metabox', 1, 2);

function p2p2_save_author_metabox($post_id, $post){
    // Don't wanna save this now, right?
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
        return;
    if ( !isset( $_POST['p2p2_book_author_nonce'] ) )
        return;
    if ( !wp_verify_nonce( $_POST['p2p2_book_author_nonce'], plugin_basename( __FILE__ ) ) )
        return;

    // We do want to save? Ok!
    $key = 'p2p2_book_author';
    $value = $_POST["p2p2_book_author"];
    if ( get_post_meta( $post->ID, $key, FALSE ) ) { // If the custom field already has a value
        update_post_meta( $post->ID, $key, $value );
    } else { // If the custom field doesn't have a value
        add_post_meta( $post->ID, $key, $value );
    }
    if ( !$value ) delete_post_meta( $post->ID, $key ); // Delete if blank
}

Now go and save a book with an author! The author of the book will be saved in the wp_postmeta database table and the selected value of the dropdown will be that in the meta.

An author column for book

Let’s expand the admin area for our books. We will start by changing the columns:

add_filter('manage_edit-book_columns', 'p2p2_add_book_columns');

function p2p2_add_book_columns($columns){
    $new_columns['cb'] = '<input type="checkbox" />';

    $new_columns['title'] = _x('Title', 'column name', 'bandpress');

    $new_columns['p2p2_author'] = __('Author', 'bandpress');

    return $new_columns;
}

This function makes sure we only see the columns title and p2p2_author. The cb checkbox column is needed for WordPress’ mass edit functionality. Now we need to add some information to our column. We add this function:

add_action('manage_book_posts_custom_column', 'p2p2_fill_book_columns', 10, 2);

function p2p2_fill_book_columns($column_name, $id) {
    global $wpdb;
    switch ($column_name) {
        case 'p2p2_author':
            $author_id = get_post_meta($id, 'p2p2_book_author', true);
            $author = get_post($author_id);
            $permalink = get_permalink($author_id);
            echo "<a href="" . $permalink . "">" . $author->post_title . "</a>";
            break;
        default:
            break;
    } // end switch
}

The switch is for every column you just added in the previous function. You fill it by echoing what you want to show. We get the post that’s the author of our book and create a nice permalink to his/her ‘profile page’. This is what it looks like:

Our author column

To be continued

We connected two post types in the backend of our WordPress site, but we can’t see a thing of it in the frontend. It’ll need a lot more work to accomplish this, but the possibilities are somewhat endless. We could:

  1. Sort books by author
  2. Show a list of books on the author page
  3. Show a list of other books of the author on the book page
  4. Create a fancy metabox with pictures of the author
  5. Create a column in the author admin page for the books he/she wrote
  6. And a lot more…

I will continue working on this answer, as I need this solution myself. However, I will stop working on in for now. I’ll start updating this answer tomorrow.

Leave a Comment