How to connect different CPTs together?

I hope this question has its place here.

I’ve always thought that connecting different Custom Post Types together is a rather common need, like in popular tutorial examples of custom taxonomy usage (books/authors/titles, films/actors/directors, etc). I personally use “Posts 2 Posts”, but support stopped.

Read More

On Google the most relevant results point to this plugin right now. Which long term alternatives exist? What would a seasoned WordPress web developer use to design a book/author/title management system with WordPress today, if P2P plugin is finished?

Related posts

3 comments

  1. 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.

  2. Since the original question is “What would you do if P2P went away?” I have a thought/suggestion. I actually needed, because if you’re building a plugin, telling users to install another plugin isn’t always viable.

    One simple method would be to use the Post Meta. For example. In the post_meta of Author, you can store the books. Either as unique entries or a single comma separated entry or a serialized array. Then on the book, you store the inverse info of Author(s).

    Another would be to add a new DB table (frowned upon) that stores the relationships and other pertinent information.

    No idea how efficient either solution is at scale, but they work.

Comments are closed.