Toolset Types 3.0 introduces a completely new post relationship features and the new Post Relationship API. This page explains how to migrate existing sites that use post relationships through custom PHP.

On this page, we will use “legacy” for referring to the old post relationship features before the Types 3.0 release. Please note that the Types 2.2.22 release added the new Post Relationships API to the legacy relationships.

At the moment, we provide the following two parts of the Post Relationship API that are completely safe to use for both legacy and new relationships:

  1. New WP_Query argument for querying by a related post.
  2. A set of public functions for obtaining related posts.

Originally, if you needed to query related posts, you would refer directly to the postmeta. With the new toolset_relationships query argument, you need to do this a bit differently.

In our example, we have a relationship between “Writer” and “Book”, where “Writer” is a parent of “Book”. The following code queries the “Book” posts.

Old approach

Using Old WP_Query Argument
$query = new WP_Query( 
 array(
  'post_type' => 'book',
  'posts_per_page' => -1,
  'meta_query' => array(
    array(
     'key' => '_wpcf_belongs_writer_id', 
     'value' => get_the_ID()
    )
   ),
   'meta_key' => 'wpcf-genre',
   'orderby' => 'meta_value',
   'order' => 'ASC',
 )
);
$posts = $query->posts;

New approach

Using New toolset_relationships Argument
$query = new WP_Query( 
 array(
  'post_type' => 'book',
  'posts_per_page' => -1,
  //new toolset_relationships query argument
  'toolset_relationships' => array(
   'role' => 'child',
   'related_to' => get_the_ID(),
   // this will work only with relationships that have existed before the migration
   // if possible, use the relationship slug instead of an array
   'relationship' => array( 'writer', 'book' )
  ),
  'meta_key' => 'wpcf-genre',
  'orderby' => 'meta_value',
  'order' => 'ASC',
 )
);
$posts = $query->posts;

Please keep in mind that code 'relationship' => array( 'writer', 'book' ) will work only with relationships that have existed before the migration. If you can use the relationship slug instead of array( 'writer', 'book' ).

Advanced example

It is also possible to query posts by two different relationships at once. Let’s also add a “publisher” post type to our previous example. It is set as the parent of the “book” post type. The following example will query “books” that are children of the currently displayed “writer” and at the same time, they are children of a selected “publisher” (please note that you need to set the $selected_parent value beforehand):

Using New toolset_relationships Argument - Advanced Example
$query = new WP_Query( 
    array(
        'post_type' => 'book',
        'posts_per_page' => -1,
        'toolset_relationships' => array(
            array(
                'role' => 'child',
                'related_to' => get_the_ID(),
                'relationship' => array( 'writer', 'book' )
            ),
            array(
                'role' => 'child',
                'related_to' => $selected_parent,
                'relationship' => array( 'publisher', 'book' )
            )
        ),
        'meta_key' => 'wpcf-genre',
        'orderby' => 'meta_value',
        'order' => 'ASC',
    )
);
$posts = $query->posts;

As you can see, there can be multiple relationship conditions, each stored as a separate associative array in the toolset_relationships query argument.

Using The New Post Relationships

The examples in the previous section are meant to be used with the legacy post relationships, where each relationship is uniquely identified by the two post types that it connects. When the new post relationship functionality is activated, this is no longer true:

  • There can be multiple relationships between the same two post types, and each relationship is identified by its unique slug.

However, you do not have to worry about the queries not working after migrating to new post relationships. During the migration process, a hidden “is legacy” flag is added to each of the migrated relationships. This way, when the WP_Query receives a pair of post types, it is still able to identify such relationships. However, for relationships created after activating the new post relationships, this will not work and the relationship slug must be used instead. Example:

Using toolset_relationships Argument with New Post Relationships
$query = new WP_Query( 
    array(
        'post_type' => 'book',
        'posts_per_page' => -1,
        'toolset_relationships' => array(
            array(
                'role' => 'child',
                'related_to' => get_the_ID(),
                'relationship' => array( 'writer', 'book' )
            ),
            array(
                'role' => 'parent',
                'related_to' => $selected_post,
                'relationship' => 'new-many-to-many-relationship'
            )
        ),
        'meta_key' => 'wpcf-genre',
        'orderby' => 'meta_value',
        'order' => 'ASC',
    )
);
$posts = $query->posts;

When new post relationships are enabled, it also becomes possible to query by (or for) intermediary post types of many-to-many relationships.

Full documentation of the query argument

The new toolset_relationship arguments of the WP_Query class can contain one or multiple conditions. Each condition is represented by a nested associative array, but if there is only a single condition, it doesn’t have to be nested. If multiple conditions are used, they’re handled as conjunctions (AND). Each condition array has these elements:
role‘ – ‘parent’ | ‘child’ | ‘intermediary’

  • Role of the queried post (the one that will be included in the results).
  • Optional. Defaults to ‘child’.

related_to‘ – int | WP_Post

  • Post to which the results are connected.
  • Mandatory.

relationship‘ – string | string[]

  • Relationship identified either by its slug or by a pair of the parent and child post types.
  • Mandatory.
  • The array variant can be used only for legacy relationships (or those migrated from the legacy implementation, after the new post relationships are enabled).
  • The relationship slug variant will obviously work only if the new post relationships are already enabled.

role_to_query_by‘ – ‘parent’ | ‘child’ | ‘intermediary’ | ‘other’

  • Role of the ‘related_to’ post in the relationship.
  • ‘other’ means the opposite of ‘role’ and can be used only if ‘role’ is ‘parent’ or ‘child’.
  • Optional. Defaults to ‘other’.

Remarks

All this functionality will work as soon as Types is entirely loaded, which happens during the init action. It is a good idea to perform the queries as late as possible to prevent potential timing issues. At the very least, we recommend using the init action with the priority 15 or higher.

We always validate the inputs and if something in the input is completely wrong (e.g. wrong role name, argument type mismatch, etc.), we throw an InvalidArgumentException. That will give the developer an opportunity to immediately realize that something is wrong, opposed to failing quietly.

If a relationship, post type or a specific post provided as an argument doesn’t exist, all the functions or the WP_Query return no results (zero or an empty array respectively).

Besides the new WP_Query argument, there are more functions that can be safely used for getting related posts. Their advantage is that they were designed for post relationships and in certain situations may be lighter and easier to use than WP_Query. You can find the full list on the main Toolset Relationships API page.

Additional information about backward compatibility

Types 3.0 implemented a set of functions that provide backward compatibility with existing sites and legacy post relationships.