Custom Post Types Relationships

- by Anastis Sourgoutsidis | Posted under: Freebies, Plugins

Custom Posts Types Relationships is a WordPress plugin that allows you to define relationships between posts in a manual way. This second version of the plugin now supports posts, pages and custom posts types, as well as allow you to define cross-type relationships. Sure, plugins that automatically get the job done are nice, but cat take you that far as they might link to irrelevant posts or change the output as more posts are added.

This version, renamed, is work based on Gerasimos’ original plugin, Custom Post Relationships, but extended to support custom post types, pages, a shortcode, a theme function, and an admin panel.

Download

You can download the CPTR plugin from our server, or visit the WordPress plugin directory page.

Installation

To install the plugin, you follow the same steps as with any other plugin. You download the plugin to your hard drive, unzip the archive and upload the resulting folder along with all files into the wp-content/plugins directory of your WordPress installation. You may also upload the zip file directly into the wp-content/plugins directory and extract it there using CPanel or whatever tools your host provides. Don’t forget to delete the zip file from your server once extracted. You may now activate the Custom Post Types Relationships plugin from the Plugins admin panel.

WARNING: In order for the thumbnail to be displayed, your theme must support post thumbnails. If it doesn’t, check that the add_theme_support( 'post-thumbnails' ) declaration is in your theme’s functions.php file and add it if necessary. The plugin should work fine without it though, it just won’t show any pictures.

Defining post relationships

Once the plugin is activated, a new box named Custom Post Types Relationships (CPTR) will appear at the bottom of the post editing screen (it will actually on post, page and custom post type editing screens). Depending on the configuration of your WordPress and/or your theme, this box may be shown under the main post editor, at the very bottom of the page, or anywhere in between.

The plugin’s interface is pretty simple, but for completeness sake I’ll include a few screenshots. A picture is worth a thousand words, right?

Configuring the plugin

To configure the default behavior of the CPTR plugin, navigate on your WordPress’ back-end, and under the Settings menu select the Custom Post Types Relationships sub-item.

There, you can set default values for all parameters, namely:

  1. The maximum number of items to display.
  2. Whether to show the excerpt.
  3. The maximum number of words that the excerpt should be.
  4. Whether to display the post’s thumbnail.
  5. The width and height of the post’s thumbnail.

Showing your relationships

The plugin supports a shortcode that can be used in individual posts and pages, as well as a function call that can be used more permanently within the themes. Both the function call and the shortcode, support the same features, although the shortcode does not require a particular order for the supported parameters. There is also a function that just returns the related posts, and then it’s up to you to implement your display logic, exactly the way you want it.

We purposely left out the ability to have a permanent heading showing up before the list of links, so that you can have total control over the output. Don’t want a heading? Don’t write one. Want one? Write it then. Too much of a hassle to always write a heading in each post? Use the theme function!

The easy, amateur or occasional way

So, you’ve written excellent copy, and you want to link it to more excellent copy. How to do it? You just type [cptr] in whatever place in your post you want them to show up. Easy, right? Just remember to write a title, heading or whatever before using the shortcode, so that people will know what they are reading.

The simplest way of using the shortcode is by typing anywhere in your post [cptr]. This will display the list of the related posts using the defaults as defined in the plugin’s admin panel.
If you want to override any of the defaults, you can do it by passing parameters to the shortcode. For example, if you want to show the excerpt you should type [cptr excerpt=1] or if you want to hide it you should type [cptr excerpt=0].

This is a list of all supported parameters that can be used with the shortcode. All parameters are optional.

  1. limit – Max number of relationships to show. 0 means unlimited. E.g. [cptr limit=5]
  2. excerpt – Shows or hides the excerpt. 1 means show, 0 means hide. E.g. [cptr excerpt=1]
  3. words – Max number of words in the excerpt. Default is 55. E.g. [cptr words=10]
  4. thumb – Shows or hides the post thumbnail. 1 means show, 0 means hide. E.g. [cptr thumb=1]
  5. width – Max width of thumbnail in pixels. Needs height to be set as well. E.g. [cptr width=300 height=200]
  6. height – Max height of thumbnail in pixels. Needs width to be set as well. E.g. [cptr width=300 height=200]

Of course, you can mix and match the attributes, so it’s perfectly fine to have a shortcode like this: [cptr thumb=1 words=40 excerpt=1 limit=10]

The hard, pro, permanent way

So, you want to integrate the CPTR plugin with the theme you are using or developing. For that, you can use the cptr() function call within your theme.

Like any PHP function with default parameters, all parameters of the cptr() function are optional but you have to follow a few rules. Have a look at the PHP documentation regarding default parameters, if you don’t know what I’m talking about.

All parameters to the function call are optional, but if set, they follow the default parameter rules of PHP. If you want to define some of the parameters but not a few preceding ones, you can pass a null value to that parameters, and it will use the default set in the plugin’s admin panel. The function’s signature is:
function cptr($echo=null, $limit=null, $excerpt=null, $words=null, $thumb=null, $width=null, $height=null)

Let’s examine the parameters:

  1. $echo – Boolean. When true it echoes the list and when false it returns it. Default is true.
  2. $limit – Integer. When 0 shows all relations. Any positive integer limits the number of relations. Default is 0.
  3. $excerpt – Boolean. When true it shows the excerpt and when false it hides it. Default is false.
  4. $words – Integer. Limits the number of words in the excerpt. Default is 55.
  5. $thumb – Boolean. When true it show the post’s thumbnail, and when false it hides it. Default is false.
  6. $width – Integer. The width of the thumbnail in pixels. Needs the height to be set as well. Default is 100.
  7. $height – Integer. The height of the thumbnail in pixels. Needs the width to be set as well. Default is 100.

So, for example, if you wanted all the default options, you would just call:
cptr();

If you wanted to return a max of 3 relations you would call:
cptr(false, 3);

And if you wanted everything to be default, but display the thumb, you would call:
cptr(null, null, null, null, true);

Implementing Custom Display Logic

So you don’t care about shortcodes and ease of use. You want to do something extraordinary with your theme, but you wish there was a way to get all the related items of that post. Wish no more, cptr_populate($postID) is here for you.

cptr_populate() accepts one parameter, the post ID of the post you want to retrieve the related items for, and returns an array of post objects. If no related posts are defined, an empty array is returned.

Displaying simple bits of info

The following example, coded into single.php will display a simple list of the titles of the related posts.

global $post;
$related = cptr_populate( $post->ID );
foreach ( $related as $item )
{
echo "<p>" . $item->post_title . "</p>";
}

A full list of the available object properties that can be used, is given in the WordPress Codex.

Using template tags

The following example prints a simple list of titles linked to their posts, showing how you can use template tags in your code, such as the_title() and get_the_title(), the_permalink() and get_permalink(), etc.

global $post;
$original_post = $post;
$related = cptr_populate($post->ID);
foreach ( $related as $post )
{
setup_postdata($post);
echo '<p><a href="' . get_permalink() . '">' . get_the_title() . '</a></p>';
}
$post = $original_post;
setup_postdata($post);

Notice that because we overwrite the $post object when we use setup_postdata() within the foreach loop, we must keep a backup of it beforehand, hence the $original_post = $post; and restore it when we are finished, as done on the last 2 lines.

Conclusion

We take pride on our little plugin. Do you think it’s useful? We definitely think so. Is there any room for improvement? Let us know in the comments, and show us where and how you use it.

Download – Changelog

  • version 2.4 (7/Jan/2012)
    • Fixed a bug where the normal post object was not restored after the execution of cptr_category_selector(), when selecting related posts. (Thanks Pascal Rosin).
  • version 2.3 (14/Nov/2011)
    • Fixed a bug where the relations outputted wrongly by the shortcode.
  • version 2.2 (8/Nov/2011)
    • All functions/pages/settings etc that included the acronym CPT have been renamed to CPTR. Functions have been deprecated and will be available until v3.0.
    • Implemented automatic upgrade of settings etc for earlier version users.
  • version 2.1 (18/Feb/2011)
    • Version number changed to match the plugin repo.
    • Fixed a bug where the last related post was the current for $post after the plugin run.
    • Thumbnail now links to the post too.
    • The cpr_populate() function now always returns an array, even if empty.
  • version 1.0 (08/Oct/2010)
    • Initial release

138 thoughts on “Custom Post Types Relationships

  1. I’ll try it.

    I was waiting for the developer of custom post relationships to update it to use custom post types for a long time.

    I think you should send this plugin to the wordpress repository asap.

    Just a question: what I should write on the ‘supports’ parameter for the custom post types for the metabox to appear?

    • I’m not sure I understand your situation. Isn’t the plugin working for you?

      The meta box should appear on all pages, posts and custom post types, either builtin or custom, except from the “attachment” post type.

      The “supports” parameter of register_port_type() shouldn’t make any difference really. Anyway, you can try adding “custom-fields” for the parameter, as I suspect it might not allow metaboxes to appear when custom fields are disabled.

      Could you share your attempt’s results please?

  2. Love the plugin! I’ve been playing around with it and its just what I will be needing when I launch my website.

    I’m wondering if its possible to get a search/list function for multiple authors/editors. For example my website will have multiple editors and I want to give them the option to link to their own related articles (or other authors) instead of searching for their articles (could get tedious with multiple articles) Either way, Great Plugin!! Thanks!

  3. Hello,

    I have a problem using within my single.php template. Basically if its placed above any comments on the site (So below the post, but above the comments), the comments section instead shows posts related to the last related post.

    Thanks

    • This can be resolved by changing the “cpr_show” function in custom-post-types-relationships-cptr/cpr.php to

      function cpr_show( $echo=true,
      $limit=CPR_DEFAULT_LIMIT,
      $excerpt=CPR_DEFAULT_EXCERPT,
      $words=CPR_DEFAULT_EXCERPT_LENGTH,
      $thumb=CPR_DEFAULT_THUMB,
      $width=CPR_DEFAULT_THUMB_WIDTH,
      $height=CPR_DEFAULT_THUMB_HEIGHT) {
      global $post;
      global $wpdb;

      $text = "";
      $thispost = $post->ID;

      $related_meta = get_post_meta($post->ID, CI_CPR_POST_RELATED, true);
      $related_posts = array();
      if (!empty($related_meta)) {
      //Get a list of post IDs
      foreach ($related_meta as $related) {
      $related_post = get_post($related);
      $related_posts[] = $related_post;
      }

      if(count($related_posts)>0)
      {
      $text .= '';

      $count=0;
      foreach ($related_posts as $related_post)
      {
      setup_postdata($related_post);
      if ($limit!=CPR_DEFAULT_LIMIT and $count>=$limit)
      break;
      $text .= '';
      $text .= 'ID).'">'.get_the_title($related_post->ID).'';
      if (current_theme_supports('post-thumbnails') and $thumb==true and has_post_thumbnail($related_post->ID))
      {
      $thumbnail = get_the_post_thumbnail($related_post->ID, array($width, $height));
      $text .= $thumbnail;
      }

      if ($excerpt==true)
      {
      $the_excerpt = _create_excerpt($related_post->post_content, $words);
      $text .= '' . $the_excerpt . '';
      }
      $text .= '';
      $count++;
      }
      $text .= '';
      }

      }

      setup_postdata($thispost);

      if ($echo)
      echo $text;
      else
      return $text;
      }

      • Hey,

        is there a fix for the comments problem? I tried the suggestion from above, and basically it should work, because it a system function but I still am seeing the comments of the last related article that is shown in the cptr list.

        I think that is a serious problem, because your content gets compromised, even doubled and that is something that search engines does not like at all.

        Is there a possibilty to get an update for that problem?

        Cheers,
        Ben

  4. Does the original Gerasimo’s function to pull related posts and grab information about them still work in this plugin?

    cpr_populate(get_the_ID());

    I need to create pages and video posts (as posts or custom post type) and have the video posts display both in their own section, and in the pages that are related to them. But I don’t want to just list the titles of those posts, I want to actually display the posts (including the video player). I cannot do that with the new shortcode from what I have seen in the explanation above.

    But if the original function works, that would let us programmers do almost anything.

    Please advice.
    Thanks.

    • Hi Andres,
      yes, Gerasimos’ original cpr_populate() function is still there.
      It returns an array of post objects or NULL when there aren’t any. I believe returning an empty array instead of NULL is more appropriate, so I’ll change it as such in the next version update. If you want to have that functionality for future compatibility, feel free to edit cpr.php and swap lines 200 and 201, so that the IF’s closing brace comes before the return $related_posts.

  5. Hello @ all!

    Thank you very much for your plugin, I’m testing it and it works very well. I wonder if it’s possible to have the full text with the images included in place the simple summary?

    Thank you for your answers :)

    • The only way you can do that at this moment, is by calling the undocumented cpr_populate() function manually from within your template, passing the post id as the parameter. It returns an array of post objects, or an empty array if no related posts have been found.

  6. Hi, I just have some improvement proposals:

    - an option to remove the css stylesheet
    - an option for the thumb to be placed before the title
    - also link the image to the post

  7. Sorry I’m a newbee, but I was wondering if the plugin could be used to populate a widget so related posts can be listed in the sidebar.

    Thanks,

    Dan

    • Hi Dan,
      I assume you mean in a Text/HTML widget. You can use the shortcode within the widget, but since wordpress doesn’t parse the widget for shortcodes by default you will need to edit your theme’s functions.php file and add somewhere the following line:
      add_filter(‘widget_text’, ‘do_shortcode’);
      Hope this helps.

      • Another newbie here, attempting to use your wonderful widget in the Text/HTML sidebar.

        Could you elaborate on where exactly that code snippet should go in my functions.php file please?

        I have experimented with putting it in different places and I continue to receive errors.

        Many thanks!

        • It shouldn’t matter where you put it, as long as it is outside of any functions and/or conditional statements. Just make sure it runs every time. What kind of errors do you get?

          • Thanks Anastis. The exact 403 error message I receive is:

            “Forbidden

            You don’t have permission to access /derrytest/wp-admin/theme-editor.php on this server.

            Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request.”

          • I do get the same error when the plugin is disabled. Having looked at it, I think it’s a hosting issue – something to do with the mod_security rule being triggered. Thanks for your help and hopefully I can get your plugin working soon!

  8. Hello! So sorry to bother you, but if you have the time to help me with this I’d be enormously appreciative!

    I have installed your plugin and I was wanting to alter the code so that the related posts show the full post content instead of just an excerpt (including attachments, etc – basically an embedded sub-post). What exactly do I have to change to make this happen? I know you mentioned the process above, but I tried my best to follow the instructions and I got very lost. I’m a little bit new to PHP, I’m afraid.

    Thanks so much for your great app!

    • The only way you can do that at this moment, is by calling the undocumented cpr_populate() function manually from within your template, passing the post id as the parameter. It returns an array of post objects, or an empty array if no related posts have been found.

      Will consider it for the next version though.

  9. Thanks for this plugin, IMHO this is more usefull than automaticly creating relating posts (and less DB-load anyway). Time will tell (I’m building my first blog).

    Still, I have a feature request:
    I’d like to have a “random (true, false)”

    Say you have selected 10 related post, but the template is only provided to show 5. Now the first five will be shown (AKA random=false). With random=true, then 5 randomly selected from those related post would be shown.

    Thanks,
    Wyando/Rudi

  10. Amazing… so close to what I need. The only thing missing is the ability to filter by category, like the original CPR plugin. So close…

    -m

  11. Hi everybody,
    Thanks for this awesome plugin.
    I have two questions : at the end of my article, I see the links for similar article 1 and similar article 2, ect….. but I also see that link 2 is surrounded with dotted line and it’s the same thing for article 4 and article 6. How can I fix that ? And last question : how can I reduce the size of the police. I mean for the display of the similar articles ?
    Thank you
    Nicolas (from France)

    • For your first question, there is probably some CSS rule overlap happening on the “.even” class.

      You can reduce the number of related articles shown, using the “limit” parameter, depending on the way you use the plugin, or via the options page.

  12. Anastis, thank you!

    I have been looking for something like this for ages – just simply creating relationships and links between custom post types.

    Just installed it and its working perfectly
    :-)

  13. Is there a way to have the plugin just return a list of the related post ID’s.

    The reason I as ask is that the site I’m using this on would like to have different views of the related post on different pages .. ie, some with an excerpt, some with some custom imagery etc .. so I figured it would be easier to just get a list of the related IDs and create the loops manually on each page.

  14. Hi, I have a problem with WP Version 3.1.1 in German language. The plugin is all in English besides the dropdown menue “posts, pages, …” It says ‘Artikel’ and ‘Seiten’ instead (and nothing further like ‘audio’). That means I cannot filter several hundred posts/pages.

    Any help is appreciated!
    Thanks in advance.

  15. Hi guys, thank you first of all for an awesome plugin, you have saved me hours of pain. If it’s not asking too much I wondered if there’s a way I could make one small change to the plugin to serve what I need, what I would like is:

    - In the search box inside at the bottom of a post, I would like it to only return posts/pages/custom posts created by that author and no others. In other words I only want a user to be able to use your plugin to link to other posts that they created (and not anybody else)

    This is because on the site I am hoping to launch it is essential that users only see the posts they have made when in the admin screen.

    I have already managed to successfully hack the functions.php file to stop them viewing other user’s posts in the general posts view thanks to the following code I got from the WordPress Codex:

    function posts_for_current_author($query) {
    global $pagenow;

    if( ‘edit.php’ != $pagenow || !$query->is_admin )
    return $query;

    if( !current_user_can( ‘manage_options’ ) ) {
    global $user_ID;
    $query->set(‘author’, $user_ID );
    }
    return $query;
    }
    add_filter(‘pre_get_posts’, ‘posts_for_current_author’);

    I know it’s probably asking a lot in terms of support for a free plugin, but I wondered if there is a simple way that you knew of (perhaps a similar line of code) that could do the same with your plugin?

    Thanks for reading and really appreciate any help you can give

    Nick

  16. I have a question/suggestion:
    Want a little comment as text on each related posts. The excerpt isn’t what im looking for. Maybe just a small textfield that appears after the post has been added to “related posts box”.

    Awsome plugin btw!

  17. Hi!

    I’m trying your plugin…i think it could be very useful, thank you very much!

    I have 1 question…

    How does the permalinks works with the plugin?

    I have a great headache about permalinks…

  18. Great plugin guys!

    Before CPTR being released, I used to use CPR. In CPR’s plugin page you had provided a piece of code which it had to be placed in single.php. It was something like this:

    Related Entries
    <?php
    $relations = cpr_populate(get_the_ID());
    if (!empty($relations)) {
    echo "”;
    foreach ($relations as $related) {
    echo “ID).”‘>”.$related->post_title.”“;
    }
    echo “”;
    }
    else {
    echo “No related entries”;
    }
    ?>

    Now, which piece of code should I use for the related entries to appear? (I didn’t understand how to use shortcodes)

    Also, in the metabox I can see only “Post” and “Pages” and not all the post types (image, quote, etc). Any idea to fix this?

    Disclaimer: i’m a novice user.

    Thank you.

  19. Has anyone used this plugin for 50,000 plus posts? Run into scalability issues yet? Anyone try the posts-to-posts plugin?

    Looks great, I’ll have to give it a try.

  20. Great plugin, I just want to be sure I have the latest version. There appears to be a link you shared in January…(look below) but when you go to the wp repo. the last updated date is in 2010. What is the most current… repo or the link you’ve provided below.

    Thanks.

    in a Gerasimos says:
    January 25, 2011 at 8:56 pm
    Hi Guys,

    We have updated the plugin and it should be ok now. Grab the version from our server and we will update the one at the wp repo too

    Here’s the link…

  21. Having an odd issue, when used on posts, using [cptr] to call the stated relevant post list.

    The last added post to be displayed (in the selected posts area) has its ‘all in one seo’ title, description and keywords settings placed in the fields on the new post, instead of the original all in one settings for the new post (this ONLY occurs after the new post is published once)

    If the post is then re published, the last posts all in one settings are used, ouch….

    Using all in one seo Version 1.6.13.4, wp 3.2.1 and Version 2.0

  22. Is it possible to create two types of relationships for one CPT? Eg I have a CPT “product” that needs an “Associated products”-relationship for related products and another “Also available with”-relationship for products that only have a different color (but are treated as an separate products).

    • Hi Marco.
      There is no “simple” way to do this with this plugin. Not without two separate instances of it anyway, which is not currently supported.

      One way you could do it, would be to select all your “associated products” AND your “also available with” products, and then implement custom display logic differentiating the two. You can do this by calling the undocumented cpr_populate() function manually from within your template, passing the post id as the parameter. It returns an array of post objects, or an empty array if no related posts have been found.

      So, depending on your setup, you could check the categories, titles or some custom fields if you have, and you could know if it is the same product but different color.

  23. Hi
    This looks great.

    I am not getting any thumbnails however.
    I have set it to show thumbnails in the plugin’s settings, but I just get a bullet point with the link and excerpt on the page.

    My theme is Oriental.

    I don’t see a way of linking a thumbnail picture to my posts. Could this be the Theme’s doing?

    Many thanks for your advice.
    Olly

    • Hi Olly,
      thumbnails are created automatically from the “Featured Image” of each post. Images uploaded before the plugins’ installation, may not be displayed as the thumbnails will not have been created. In this case, I would suggest using a plugin to regenerate the thumbnails, such as this one.

      Hope this helps.

      P.S. I love Somerset. I’ve been studying in Bridgwater college back in 1999.

  24. Hi,

    I’m loving this plugin. It’s working great so far, after a day full of trial and error with other options. So, thanks!

    I do have a question. I’m using a custom post type with custom fields/data/meta, and there isn’t an excerpt or thumbnail. How might I get all the info from each of these posts to show up when CPTR calls them? I know I’d need to modify cpr.php with a $text, but I wanted to see if you recommended a way that would work well with the plugin.

    Thanks!

    Dave

    • Hi Dave,
      unfortunately there is no straightforward way to do what you ask.

      You should implement custom display logic directly into your theme files. You can do this by calling the undocumented cpr_populate() function manually from within your template, passing the post id as the parameter. It returns an array of post objects, or an empty array if no related posts have been found. You then use those posts’ IDs and fetch whatever you want with get_post_meta() for example.

      (Note to self: I really need to document this function and create some examplar code, soon!)

      I don’t recommend editing the cpr.php file directly, as any future plugin updates will overwrite your code.

      • Hey Anastis,

        I’m trying to get the cpr_populate() to work, but I’m not so confident in my php-from-scratch skills. I’ve been looking at the WP Codex for hints, but can’t seem to figure it out.

        I have started, but would you be able to show me how to pull one post meta item (e.g. exhibitor_table) from my custom post type? I can figure out how to get the rest if I know how to do one.

        I really appreciate the help.
        Thanks,
        Dave

        • E.g. in your single.php file:

          global $post;
          $related = cpr_populate($post->ID);
          foreach ($related as $article)
          {
          $meta = get_post_meta($article->ID, "exhibitor_table", true);
          echo $meta;
          }

          I hope this makes sense.

          • Great! On my way I think.

            That code pulls all of the data in all of the “exhibitor_table” fields. Shouldn’t the “true” of the get_post_meta make it return only one per post? Or I guess it might be echoing them individually, but without any html wrapping, right?

            I guess, here’s a screenshot of what I’m trying to do: http://thegallerymusic.com/EventListingFormat.png
            You’ll see the “Exhibitors” section at the bottom (This is for a client. Not my site). I just need each piece of data from the related post(thanks to your plugin), wrapped in a span, div, etc.

            By the way, did you just update your plugin to version 2.2? I just got an update notice.

            Thanks again for any help,
            Dave

    • That code gets the related articles/posts/whatever and for each one it pulls the “exhibitor_table” field (not plural). It then echoes them on the page. You can build around this code if you want extra markup, e.g.
      echo '<p>'.$meta.'</p>';

      The default behavior of get_post_meta() is to return an array of the history of the values that where saved on that custom field. “true” makes it return just the most current value.

      Now, for your problem, it all depends on what you store and where. For example, if you have a separate custom field for each piece of info, you might have to do:

      $name = get_post_meta($article->ID, "exhibitor_name", true);
      $booth = get_post_meta($article->ID, "exhibitor_booth", true);
      etc...and then echo them appropriately...

      or you may be storing an array within “exhibitor_table”, so you would do something like:

      $meta = get_post_meta($article->ID, "exhibitor_table", true);
      echo "<p>".$meta['exhibitor_name']."</p>"

      Yes, I updated the plugin to v2.2 today. Everything CPR was renamed to CPTR, so cpr_populate() is renamed to cptr_populate(); Apart from custom code, all internal options should be updated automatically.

      • Thanks, you’ve really been a huge help! And got a jump on that documentation haha.

        I’ve got a jump on this now. I really appreciate it. Love the plugin. Keep up the good work.

  25. Hi Anastis

    Thanks for your reply.

    I was able to get the thumbnails working by ticking the featured images box in screen options =)

    My next question is –
    How can I increase the space between the text above and the [cptr]
    ie The related post(s) (with beautiful thumbnails) are stuck right underneath the text above it on the page. Be nice to have a space after the text before the first related post excerpt.

    Can’t believe you know Bridgwater! Did you see the awful crash on the M5 this weekend?

    Olly

    • Hi Olly,
      this is really a CSS question. You can edit your theme’s style.css file, and add a line similar to the following:

      #cptr_related_posts { margin-top: 20px; }

      Play around with that “20″ and see what works best for you.

      I left Bridgewater in 2000 and haven’t been able to revisit yet, the memories are still vivid though. I also loved Weston-super-mare, as it had a Greek restaurant and sea! Taunton never really did it for me.

  26. I just downloaded the upgrade and sincerely wish I hadn’t. For some reason it inserts the related posts link always above my content, instead of wherever I place [cptr] on the page, as the old version used to. So frustrating! I wish I could roll back to the old version but I didn’t keep it. ..

    • Hi Rachel,
      you can download the previous version 2.1 from the Changelog. The version number is also a link for download.
      Meanwhile, I will look into it and release an update as soon as I get it fixed.

      • There is a serious bug in cptr_category_selector(). You are altering the global $post variable without setting it back (and without need). This causes code loaded after the CPTR editor to use the last related post and not the actual post.

        The problem can be fixed by changing line 88 of cptr.php from

        global $post_ID, $post;

        to

        global $post_ID;

  27. Amazing plugin! One thing lacking though, the ability to apply a reciprocity when creating a conexion. Would be awesome to get this option so we could navigate between connected posts without having to create the conexion twice in the admin.

    Great job anyway, it saved me on a site i’m working on right now.

    Cheers

  28. Hi,

    We use your plugin in all our articles. Even though it’s powerfull, it has some limitations for a several-times-a-day use :

    1. Why load all the articles before the filter kicks in ? High server charge, slow and you have to wait a good 20s every time (when using the 500 posts option). Would be better to ask for the filter first, and use it as a search query.

    2.the 500 post limit is too small for us, only puting us back 2 months. Impossible to add older posts: bad for rarely talked-about subjects

    3. I don’t know if it’s our config, but it only looks for the filter words in the title of the posts, ignoring tags and the main text. Not very good exept for SEO-only minded titles.

    4. By default, it charges the posts by title and ascending order. In my experience, default should be by date and descending order (the most recent first). Or at least there should be an option to change this, again saving time for us.

    Otherwise it’s a very good plugin. I also want to mention I’m only an end user, with no specific coding skills ^^

    • Hi Jeff,
      yes, the plugin is currently operating in a very specific manner. Searching only searches titles, because that’s all you can see. If it looked on tags and main text, it would be impossible for you to tell what exactly matched.

      Setting the default order is a good idea, and I’ll try to implement it in the next version. You’ll be able to change it from within the settings page.

      Now, about the 500 posts limit you are mentioning, there isn’t such a thing. The limits that are implemented are 10, 50, 100 and “All”. Make sure you have updated to the latest version.

  29. Hi Anastis,

    This plugin works great. It’s very easy to associate custom post types with others cpt’s; it’s pretty much self-explanatory. It’s great when plugins are simple and work as they should. Thank you.

    Question: I’m not using Featured Images, but instead meta boxes to upload images, and consequently, haven’t been able to show the thumbnails per related post. Is there a way to display the first photo of a cpt instead of the featured photo?

    Also, is it possible to display the word “Similar” before the list of related posts/cpt’s? I know I can add it before the , but I don’t want it to appear when there aren’t related posts. So, I want it to be included in the php. Could you please provide a tip on how to achieve this?

    Thanks again for your plugin and tips. I’ve been wanting something like this for a long time.

    • Hi, and thanks for your kind words.

      Unfortunately, there is currently no way you can grab any other image than the post’s thumbnail. Using the plugin that is.
      If you examine the function get_the_post_thumbnail() in the file wp-includes/post-thumbnail-template.php you will see there is a filter executing when returning the html of the image. You can hook a function on that ‘post_thumbnail_html’ filter, and have it return the html of your custom field images (the html string will be empty in your case anyway, since you don’t use featured images). In that hooked function, you could also use something like this function to get your first image. I’m not sure it will work though, as it will depend on when and how the things are run, i.e. your custom fields may be included in your content later than the hook, or not included in the content at all).

      For your second question, the editor may have stripped whatever you wrote in the <code> block, so I don’t know to what exactly you are referring to. I’ll assume you use the function call of the plugin though, and not the shortcode.
      You can have the function return the related articles instead of echoing them, (see first parameter of cptr() in the documentation) into a variable, and test if empty. The function returns an unordered list of posts only if one or more are related. Otherwise it returns an empty string.
      So you could do something like:

      $related = cptr(false);
      if( !empty( $related ) )
      {
      echo "<h2>Similar</h2>";
      echo $related;
      }

      Hope this helps.

      • Wow, I appreciate the responsive and extensive reply. Much appreciated.

        So, the second tip worked out quickly. Thank you. In regards to the first issue, yes, we can probably just filter the photo. Makes sense. Good idea, thanks.

        I seriously appreciate this plugin and tutorial. Have a good one.

  30. Great plugin. I was wondering if there is a way to make the related links that appear at the bottom of a post either dofollow or nofollow ?

    • Unfortunately, there is no way to do it without editing the plugin itself. Which means that in future plugin updates your changes will be lost.

      If you still go ahead and edit the plugin, you should look on cptr.php lines 262 and 265.

  31. Hi,

    first of all thanks for this plugin. It’s really great!

    I was editing the css-file to change the look of the list and it worked well.

    But one thing about the excerpt disturbs me. I want the custom excerpt to be shown, not the first x words of the article/page. I read about something familiar in the comments above, but I still can not solve the problem.

    Can you please tell me how to display the custom excerpt?

    • As with the question above, there is not way to do it currently. I will implement it sometime in the future.
      If you absolutely need it, you can edit the plugin, file cptr.php line 271:
      Replace:
      $the_excerpt = _create_excerpt($post->post_content, $words);
      with:
      $the_excerpt = get_the_excerpt();

      This should work. Just keep in mind that any future plugin updates will overwrite your change.

      • Thanks for your response!

        It is working with the solution you have described; the custom excerpt is now displayed.

        It would be great if you let the user decide which excerpt (first x words of the article/page or custom excerpt) will be displayed. Maybe it would be good if one can also limit the words of the custom excerpt.

        I would appreciate this feature in the next version of the plugin.

  32. Hello,

    This is a wonderful plugin that saved my life in an application where I relate stored tweets with news items.

    I retrieve and store tweets in my WP database with the custom post_type “tweet”, and have set up the custom display of these related tweets using cptr_populate( ).

    Being a seasoned ColdFusion programmer who is very much struggling to learn PHP, I could not find a solution to the following two issues, and kindly ask for your guidance:

    1. I want to be able to limit the related tweets to 3 on home page, and unlimited on the single post page. I know this can be achieved via the limit parameter, but how would I use that along with cptr_populate( )? (I need to use the populate function, because I have set up a custom display for my related tweets.)

    Here’s my code:


    ID);
    foreach ( $related as $post ) : setup_postdata($post); ?>

    <a href="" class="body">

     

    <a href="">Yorum Yap
    Begen

     

    2. The related tweets appear under each post/news item, and when a tweet is clicked, it opens its own single post page. How would I go about linking back to the parent post from the related tweet itself?

    Thank you so much in advance, and all the best.

  33. Sorry for the messy code. Let me just try with this bit:

    ID);
    foreach ( $related as $post ) : setup_postdata($post); ?>

    • Hi,
      since you are using a custom loop to display the tweets, you need custom checks to limit the number of related items shown. You should edit your foreach as such:

      $related_count = 0;
      
      foreach ( $related as $post ) : setup_postdata($post);
      
      	$related_count++;
      	if( is_front_page() )
      	{
      		if($related_count > 3)
      			break;
      	}
      ?>
      
    • About question number 2, there is currently no way to look back at which post linked to another one, which would really be reciprocal linking. It is on our to-do list on the next major plugin update though.

  34. Thank you so much for your quick response.

    I have tried your suggestion (also replacing is_front_page with is_home, thinking perhaps that might be the problem) but to no avail. I still see more than 3 tweets on home page.

    Here’s the entire code block if it can help you pinpoint what exactly I am doing wrong.

    Code snippet

    Thank you!

    • Which file are you editing? Most probably, single post pages and the home page use different template files, so you’d have to paste the code I gave you in (at least) two files.

  35. I pasted the code in content.php which deals with the looped news items for index.php. In the single post page, I already want to show all tweets, so no problem there.

    Thanks!

  36. Hi Anastis,

    Great plugin. I want to thank you. With so much crap out there released daily, its refreshing to see a wordpress plugin that actually delivers what’s promised, works great with everything thrown at it, and never giving a hard time.

    Too many hustlers peddling bad plugins these days. I was looking at a premium plugin called ‘auto-sortable portfolio’ that had a great demo. So I buy it, and turns out, that the ‘auto-sorting’ functionality is not included!?! So I just bought a post type, 15 lines of code, for $10. Hahah.

    So that’s why products such as yours, that deliver what they promise and work flawlessly are a blessing.

    Thanks again and wish you the best!

    Nick M.

  37. Hello again Anastis,

    I have managed to work through the earlier problem and managed to limit my posts, thanks to your help.

    I have one more question: during cptr_save, I need to update the post_status of my related posts; that is, I keep the child posts as ‘pending’ until they are assigned as related to a parent post, and upon saving of the parent post, I want to update them as ‘publish’.

    Fiddling with the plugin, I am assuming it should be something similar to this, but cannot get it to work (actually, it throws memory errors, so I’m guessing I’m creating an infinite loop somewhere).

    Your kind assistance is, once again, much appreciated.

    Code Snippet

    Cheers.

    • I’ve commented inline the code to see the logic.
      Just be careful on future updates of the plugin, because you will loose this code. I’ve meant to introduce action and filter hooks some time now, just didn’t find time to actually do it.
      Anyway, hope this helps.

      function cptr_save() {	
      	global $post_ID;
      
      	if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) return;
      	if (!isset($_POST['myplugin_noncename'])) return;
      	if (!wp_verify_nonce( $_POST['myplugin_noncename'], plugin_basename(__FILE__))) return;
      	if (!current_user_can( 'edit_post', $post_ID ) ) return;
      
      	$id = $_POST['post_ID'];
      	$related = isset($_POST['reladded']) ? $_POST['reladded'] : array();
      	update_post_meta($id, CI_CPTR_POST_RELATED, $related);
      	
      
      	
      	// this is where I attempt to update the post_type
      
      	// You don't really need $related_meta since it's the same with $related above
      	// So i've renamed all instances of $related_meta to $related from now on.
      	//$related_meta = get_post_meta($id, CI_CPTR_POST_RELATED, true);
      	
      	// Also, can't find a reason to store the post objects, as it can be done in one go.
      	//$related_posts = array();
      
      	if (count($related) > 0) {
      		//Get a list of post IDs
      		foreach ($related as $rel_id) {
      			// Why retrieve the object? We can update it just by its ID.
      			//$post = get_post($myrelated);
      			//$related_posts[] = $post;
      			
      			$my_post = array( 'id' => $rel_id, 'post_status' => 'publish');
      			wp_update_post( $my_post );
      		}
      		
      		// The following whole block of code is not needed.
      		// Your error is probably because you used $post to assign a different post object
      		// but it's a WordPress global and bad things happen if you're not careful (and you were not!)
      		/*
      		if(count($related_posts)>0)
      		{
      			foreach ($related_posts as $post)
      			{
      			// Update post
      			 $my_post = array( 'id' => $post->ID, 'post_status' => 'publish');
      			// Update the post into the database
      			  wp_update_post( $my_post ); 
      				
      			}
      		}
      		*/
      		
      	}
      	
      }
      
    • Feel free to clean up the code i pasted from the comments.
      Also, the if (count($related) > 0) statement can also be omitted as the $related will always be an array, and the foreach statement will only execute if the array has one or more elements.

    • There is nothing in this code that could cause an endless loop. It could be caused by it’s caller function. Are you calling this function directly, or have you edited any other part of the file?

  38. I just added the extra lines of code to the original cptr_save function, located in cptr.php, and haven’t touched anything else.

    Thank you.

  39. Perhaps it’s not a loop, but when the Update Post button is clicked, nothing happens, and the page seems to hang forever. The moment I take the additional code out, it functions properly again.

    • It could be that it just takes a long time to update all the posts in the database, if you associate quite a few of them…
      Can’t tell without taking a closer look on a live website.

  40. I have associated a single related item, but still, the update page seemed to hang, and wouldn’t even throw an error afterwards.

    I am wondering if it is something in the way the parameters are named, (reserved words, a param used elsewhere for another purpose, etc.)

    Will test this again, and let you know. I appreciate the time you’ve put in trying to help me, thank you very much.

  41. Located this on WordPress Codex page, perhaps it’s relevant?

    ‘Caution!

    When executed by an action hooked into save_post (e.g. a custom metabox), wp_update_post() has the potential to create an infinite loop. This happens because (1) wp_update_post() results in save_post being fired and (2) save_post is called twice when revisions are enabled (first when creating the revision, then when updating the original post—resulting in the creation of endless revisions).

    If you must update a post from code called by save_post, make sure to verify the post_type is not set to ‘revision’ and that the $post object does indeed need to be updated.

    Likewise, an action hooked into edit_attachment can cause an infinite loop if it contains a function call to wp_update_post passing an array parameter with a key value of “ID” and an associated value that corresponds to an Attachment.’

    http://codex.wordpress.org/Function_Reference/wp_update_post

    • Nice catch.
      According to this, having a

      global $post;
      if( $post->post_type == 'revision' ) return;
      

      when the function begins, should fix your problem.

  42. Unfortunately, that didn’t work either. I went so far as to disable revisions and delete revision history as well.

    Perhaps it is simply not possible to update other posts while saving one post. :(

  43. To explain the process of the error: the post has been added to the database 313 times before the server timed out.

  44. Alright. Let’s do something else.
    Removed all your customizations from cptr_save() and add into it:

    $update_later = get_option('ci_cptr_temp_update_later');
    if($update_later===false) $update_later = array();
    $update_later[$post_ID] = $related;
    update_option('ci_cptr_temp_update_later', $update_later);
    

    Then, outside of this function enter the following:

    add_action('init', 'ci_cptr_update_later');
    function ci_cptr_update_later()
    {
      if(!is_admin()) return;
      $update_later = get_option('ci_cptr_temp_update_later');
      if($update_later===false) $update_later = array();
    
      foreach($update_later as $key=>$value)
      {
            // You can use $key as the ID of the post that the $rel_id's were associated from.
            foreach ($value as $rel_id) {
                $my_post = array( 'id' => $rel_id, 'post_status' => 'publish');
                wp_update_post( $my_post );
            }
    
      }
    }
    
  45. Thank you, Anastis, but still no luck unfortunately. Update process doesn’t hang anymore, and works fine, but the related post/posts remains ‘pending’.

    I don’t know if it’s relevant, but the related posts are a custom post type, called ‘tweet’.

    Just to make sure I haven’t done anything wrong in implementing your suggestions, here’s what I have now:

    http://pastebin.com/J8VDCpcg

    Your kind efforts are much appreciated.

  46. Try changing ‘id’ to ‘ID’ on your $my_post array. Field names should match the database column names.

  47. Eisai katapliktikos! S’euxaristo para poli!

    For non-Greek speakers, that, obviously did the trick.

    Thank you ever so much, Anastis. Cheers from Istanbul.

  48. If you can believe it, I have one last question. :)

    How would I go about sorting the order of related posts by date descending, using cptr_populate(). I realize some sort of array sort is in order, would it be something similar to this perhaps?

    $related_posts = array();
    foreach($related_meta as $related){
    $a = (array)$related;
    $mytweets[$a['post_date']] = $related;
    }
    krsort($mytweets);

    But then how do I return posts? Or does this make no sense whatsoever?

    Thank you!

    • It will be easier if you assume that post IDs are directly related to the post’s date, i.e. newest posts have bigger IDs.
      If this is acceptable, then just rsort($related_meta, SORT_NUMERIC); before the foreach statement, and you should be all set.

  49. Thanks – the admin panel has solved a problem for us.

    We want to front end filter the related posts based on post type – so, having a pre-populated array of posts returned by ctpr_populate() is a little inefficient. It might be a good idea to provide a version that just returns an array of the post IDs (or simply document that they can be fetched with get_post_meta!).

    Thanks again, Roger

  50. Love the plugin … but isn’t there supposed to be a category dropdown so that I can handpick related posts only from a certain category? As it stands now, I have to go back through my entire archives to find the related posts I want to show.

  51. you should update this page and it’s code to show the 2.2 changes that update the acronym in code to CPTR – otherwise anyone hard coding into their theme will think the plugin is broken or not working.

    • Hmmm… what? The plugin is in v2.4 for more than a year now, and the documentation IS using the cptr_ prefix.

      • actually the code above is not. For example this snippet:

        $related_meta = get_post_meta($post->ID, CI_CPR_POST_RELATED, true);
        $related_posts = array();
        if (!empty($related_meta)) {
        //Get a list of post IDs

        should be CI_CPTR_POST_RELATED, if you copy/paste your version above – it fails. I had to read the changelog of your plugin to figure out CPR had to be changed to CPTR since the code on this page wasn’t updated.

        • Indeed. It’s just that, that comment is over two years old, and I didn’t actually thought of the comments at all.

          Although I’ve tried to deprecate things as smoothly as possible, it seems I forgot about the constants.

          Now all I need is time to get around to do it…

  52. Hi,

    First of all: thanks for this wonderful plugin!

    I’m having a question. I want to check if the array is empty before I print an introduction-text. My code is:

    ID); ?>

    Projects:

    <?php foreach ( $related as $post ) {

    $output .= '‘ . get_the_title() . ‘‘.$separator; }
    echo trim($output, $separator);
    ?>.

    The problem is that the check doesn’t work, so it prints ‘Projects:’ everywhere.

    Is there a way to make this happen?

    • It’s because you unconditionally print “Projects:”.
      You can do something like that:

      <?php if( ! empty( $related ) ): ?>
      Projects:
      <?php endif; ?>
      
  53. Hi there – anything known about WP 3.5.1 and the plugin not working? Got a website running on 3.5.1 with CPTR v2.4 and for some reason when trying to add the posts it doesn’t do it. Same site running on WP 3.4.2 works fine.

    • I just tried it in an updated 3.5.1 installation (with the latest version of the plugin from the repo) and it works.
      Perhaps it’s something else interfering. Have you tried disabling all other plugins?

      • Yep. My fault – tracked it down to the advanced post types order plugin which needed an upgrade. Sorry, for ‘doubting’ you wonderful plugin. ;-)

  54. Hello.
    First of all thanks for the great plugin.I have one question though.
    I have 2 custom post types and I would like to display related posts from both these types in a page. Is there a way to filter them by post type?

    Thanks in advance

    • I’m afraid this isn’t possible at the moment (using the shortcode or the cptr() function), and probably will never be, as it will be either inefficient or complex or both.
      Your only option is to use the cptr_populate() function, in combination with conditional printing according to get_post_type().
      If you go down that route, let me know if I can assist.

      • Thanks for the answer.

        I was trying to do it with conditional printing but I’ m afraid i don’t really know how to do it. (I just started using wordpress to build things). I can’t find a way to aplly any filter to $related. I would appreciate if you could just give me an example of any kind.

        • In its simplest form, you can have this code in multiple places:

          global $post;
          $original_post = $post;
          $related = cptr_populate($post->ID);
          foreach ( $related as $post )
          {
          	setup_postdata($post);
          	if(get_post_type() == 'post')
          	{
          		// The post type is 'post' so do whatever you want in here
          		echo '<p><a href="' . get_permalink() . '">' . get_the_title() . '</a></p>';
          	}
          }
          $post = $original_post;
          setup_postdata($post);
          

          Alternatively, you could create a more generic function inside your functions.php file, like this:

          if(!function_exists('cptr_show_post_type')):
          function cptr_show_post_type($type='')
          {
          	global $post;
          	$original_post = $post;
          	$related = cptr_populate($post->ID);
          	foreach ( $related as $post )
          	{
          		setup_postdata($post);
          
          		if(!empty($type) and get_post_type() != $type)
          			continue;
          
          		// The post type is either empty or the same as the one you passed,
          		// so do whatever you want here.
          		echo '<p><a href="' . get_permalink() . '">' . get_the_title() . '</a></p>';
          	}
          	$post = $original_post;
          	setup_postdata($post);
          }
          endif;
          

          and use it wherever you want like this:

          cptr_show_post_type('product');
          cptr_show_post_type('post');
          // etc...
          
          • Thank you! This answer really worked for me.

            And by the way, this plugin is drop-dead amazing!

            Thank you so much!

        • I forgot to mention that the function I provided, will show all related items if you don’t provide a $type paramater.

  55. Love this. One thing I haven’t figured out how to do, though- I want a heading on my list of CPTs but ONLY if there are actually relationships defined. Basically looking for something like IF there are related custom posts, output the following HTML first, then output my list, ELSE do nothing. Thanks!

  56. get_the_category returns “Array” in my case.

    How do we specify the ID in the code, so that the proper category is returned for each related post?

    For example:

    echo '' . get_the_category() . '';

    • I don’t see how this relates to the plugin.

      Anyway, assuming you are within the loop, get_the_category() returns an array of category objects, as a post may have many categories, therefore you’ll need to manually get what you want from it. If you are outside of the loop, you can pass a post id as a parameter.
      E.g.

      global $post;
      $related = cptr_populate( $post->ID );
      foreach ( $related as $item )
      {
          $categories = get_the_category( $item->ID );
          foreach ( $categories as $cat )
          {
              echo ' ' . $cat->name . ' ';
          }
      }
      

      If you just want to print the categories, you probably want to use the_category() instead.

      • I’m sorry I wan’t more clear. Here’s my code I’m using to show related posts on a WordPress page:


        ID);
        foreach ( $related as $post )
        {
        setup_postdata($post);
        echo '';
        echo '' . get_the_post_thumbnail() . '';
        echo '';
        echo '' . get_the_category() . '';
        echo '' . get_the_title() . '';
        echo 'READ MORE';
        echo '';
        echo '';
        }
        $post = $original_post;
        setup_postdata($post);
        ?>

        I follow your example, but am unsure of how to integrate it into my code.

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>