Related Object Fields
MasterPress includes a suite of field types which allow you to setup related posts, terms, users, post types, taxonomies, user roles, and even sites in a multisite network. These fields can be useful for relating one or more objects to your current post, term, or user, but can also be useful for building sequenced lists of these objects to display anywhere on your site.
Each of the related field types can be set up to support just one selection, or multiple selections, and the default interface for this uses the superb Select2 jQuery plugin by Igor Vaynberg. This library replaces the rather limited standard HTML select interface with a searchable select box; this control is a decent improvement on a single select, and a massive improvement on the fairly awful HTML multi-select control.
These field types are very flexible, and there are a lot of ways you can utilise them. The MasterPress website itself uses a single-select related post field to relate the feature touts on the home page to either a specific feature or page in the site:
Figure 1: Single-item related post field to select features or pages for home page touts
We also use a multi-select related post field to record the sequence of feature posts (based on a custom post type “feature”) on the Features page. Since this field type supports drag and drop re-ordering of posts, it’s a nice lightweight way to manage them, rather than sorting the feature posts using the standard menu order:
Figure 2: A multi-item related post field to define the sequence for the features page
The developer Class Reference also makes heavy use of both related post fields, and related term fields to define relationships between methods and their classes, relate methods to each other, and define method argument and return types.
Now let’s take a look at how we can access the values stored by these fields for your theme templates. Since these field types are all very similar, let’s look at two key aspects that apply to all of them, which makes access to their content a whole lot easier – class delegates and dynamic iterators.
Single item fields, and class delegates
Each of the related field types uses a class delegate to forward method calls to. The classes used for each of them correspond to the type of object they represent, specifically:
- Related Post delegates to MEOW_Post
- Related Term delegates to MEOW_Term
- Related User delegates to MEOW_User
- Related Post Type delegates to MEOW_PostType
- Related Taxonomy delegates to WOOF_Taxonomy
- Related User Role delegates to WOOF_Role
- Related Site delegates to MEOW_Site
If you’re unfamiliar with class delegates, this simply means that you can call the methods of each of these class delegates directly on the field object. Please read through the Class Delegates section for more information.
The use of class delegates makes interacting with related field objects via the API very intuitive. For example, let’s look at how we might link to, and show fields from the selected feature in Figure 1 above:
Example 1: Accessing feature post info
In this example, we’re looping over our multi-item features_touts field set with the loop variable $tout. In lines 4 and 5, we access two things from the linked feature: a link to the feature, via the WOOF_Post::link method, and a custom screenshot field from a details field set in our feature.
The key point about this example is that while there’s a lot of dynamic behaviour operating behind the scenes via our class delegates, the code feel obvious. You can essentially keep drilling down into the properties you want, and everything just works like you’d expect.
Note: when dealing with multi-item fields, the delegate object will be the first selected item in the collection
Multi-item fields, and dynamic iteration
One of the curious things about the MEOW_Field object, which represents a single custom field, is that it extends the WOOF_Collection class – a class which is generally used to store multiple items. Before we explain the reason for this, let’s look at an application of it. Here is part of the code that we use to list the (glorious) features of MasterPress on our Features page:
Example 2: Looping over our features sequence
On line 1, the sequence property is a MEOW_Field and in this example we are simply iterating over the features in the field to run through our feature post items in sequence. Again, the API strives for ease-of-use here, and we couldn’t imagine this being much easier.
But how does this work? The WOOF_Collection class is the key here – while it is usually fed an array of items for the collection at the time of creation which are stored in an internal property, it can support the concept of dynamic iteration, where it can instead ask a callback method iterator_items for an array of items to use instead. In the case of our fields, this is a little more complicated by the fact that MEOW_Field is asking the delegate for its iterator_items, but the concept is the same.
Each of our related field types has a method to return a collection of the items in the order they’re defined in the UI. These are all named as the plural form of the object they represent: MPFT_RelatedPost::posts, MPFT_RelatedTerm::term, MPFT_RelatedUser::users,
MPFT_RelatedPostType::post_types, MPFT_RelatedTaxonomy::taxonomies, MPFT_RelatedUserRole::roles, and MPFT_RelatedSite::sites. These are the methods we use to feed our dynamic iteration callback “iterator_items”. it also means that we could access the posts in our sequence like this:
Example 3: Looping over posts explicitly
Again, we’ve strived for a concise API though, so you don’t have to access the posts method explicitly – it is useful to know that there’s a method behind the magic though.
All related field types created equal
The examples for single-item and multi-item field sets we’ve just explored form the basis of knowledge for all of our related object field sets. It’s of little value to explore how to access information from each type of field set, since this would get very repetitive.
Here is a boilerplate single-item code example for all of them, assuming we had a “related_[object_type]” field for each of them in a “details” field set:
Example 4: Single item access for each field type
And here is a boilerplate multiple-item code example for all of them, assuming we had a “related_[object_type]s” field for each of them in a “details” field set:
Example 5: Looping over each multi-item field type
Even that felt repetitive. The takeaway is that they’re all consistent – learn the concepts behind one, and you’ve mastered them all.