Post object, Page link, Relationship, Taxonomy and User
6 min read
Relational fields point to other things in WordPress. They store IDs, not copies, so a renamed post or term shows its new name everywhere.
Type | Type id | Links to | Column |
|
|---|---|---|---|---|
Post object |
| One post of chosen post types |
| post ID ( |
Page link |
| One post of chosen post types |
| post ID ( |
Relationship |
| Several posts |
| list of post IDs ( |
Taxonomy |
| Terms of one taxonomy |
| list of term IDs ( |
User |
| Users, optionally by role |
| list of user IDs ( |
Common behaviour:
- IDs are checked when saved: an ID that does not exist, or is not allowed by the field's settings, is dropped.
- The stored IDs are not removed when the target is later deleted.
wpmcf_get_field()returns what is stored; the printed output skips items that no longer exist. - Pickers search through a protected admin route, so they need an editor who may edit posts (User fields need the right to list users). Post object, Page link, Relationship and User are not available in front-end forms (Pro). Taxonomy is.
Post object
Chooses one post, page or custom post type entry.
Setting | Default | Effect |
|---|---|---|
Post types | Post | The post types editors can pick from ("Editors can only pick posts of these types."). Choose up to 10. Unknown types are dropped; if none remain, |
On the edit screen an editor types in the Search posts… box and clicks a result. Search covers published, scheduled, draft, pending and private posts the editor is allowed to read, 20 results at a time, with the post type (and the status, if not published) next to the title.
What is saved. One ID. If several are posted, the last one is used. The post must exist, be of an allowed type and be readable by the current user; an editor cannot link a draft they cannot see. A post that was already linked stays linked even when the editor cannot see it, so editing never unlinks it silently.
What is printed. The post title as a link to the post when visitors can open it. Visitors who cannot open the post (a draft, private or password-gated item) see nothing; users who can read it see the plain title.
$id = wpmcf_get_field( 'review', 'product' ); // 708 (int) or null
if ( $id ) {
printf( '<a href="%s">%s</a>', esc_url( get_permalink( $id ) ), esc_html( get_the_title( $id ) ) );
}
wpmcf_the_field( 'review', 'product', null, [ 'wrap' => false ] );
// <a href="http://example.com/blue-widget/">Blue widget</a>[wpmcf_field group="review" field="product" wrap="false"]Page link
Works like Post object, but prints the post's address (permalink) as the link text, which is useful for plain "go to this page" links. It uses the same Post types setting (default Post; set it to Page to link to pages).
[wpmcf_field group="review" field="landing" wrap="false"]
→ <a href="http://example.com/pricing/">http://example.com/pricing/</a>Only posts visitors can open are printed; a draft prints nothing (even though its ID is stored). In templates, use the ID with get_permalink():
$id = wpmcf_get_field( 'hero', 'landing' );
if ( $id && 'publish' === get_post_status( $id ) ) {
echo '<a href="' . esc_url( get_permalink( $id ) ) . '">' . esc_html( get_the_title( $id ) ) . '</a>';
}You can switch a field between Post object and Page link without losing data.
Relationship
Chooses several posts and keeps them in the order picked. The picker has no drag handle: to change the order, remove an item (×) and pick it again.
Setting | Default | Effect |
|---|---|---|
Post types | Post | As above. |
Maximum items | 0 | 0 means no limit, up to 100. A lower number stops the editor from picking more, and extra IDs are dropped on save. |
What is saved. A list of unique IDs of existing, readable posts of the allowed types, in the order posted. An empty selection clears the field.
What is printed.
<ul class="wpmcf-relationship">
<li><a href="http://example.com/page-one/">Page one</a></li>
<li><a href="http://example.com/page-two/">Page two</a></li>
</ul>Only posts visitors can open are listed; if none are public, nothing is printed.
$ids = wpmcf_get_field( 'course', 'lessons' ); // [708, 709] (int[]), or [] if empty
if ( $ids ) {
$lessons = get_posts( [ 'post__in' => $ids, 'orderby' => 'post__in', 'post_type' => 'any', 'posts_per_page' => count( $ids ) ] );
foreach ( $lessons as $lesson ) {
echo '<h3>' . esc_html( get_the_title( $lesson ) ) . '</h3>';
}
}orderby => post__in keeps the order the editor chose.
CSV imports take comma-separated post IDs (708,709,710).
Taxonomy
Chooses terms of one taxonomy (categories, tags, a custom taxonomy). The IDs are stored in this field; optionally the post's real terms are kept in sync as well.
Setting | Default | Effect |
|---|---|---|
Taxonomy | Category | Any taxonomy that has an admin screen. An unknown name falls back to Category. |
Appearance | Checkboxes | Checkboxes (several terms), Radio buttons (one term), Select (one term) or Search (several terms through a search box). Checkboxes and Select show child terms indented under their parent. |
Maximum terms | 0 | Search appearance only: 0 means no limit, up to 100. Radio buttons and Select always take one term. |
Save terms | Off | "Also assign the chosen terms to the post." When the field is saved, the post's terms in that taxonomy are replaced by the chosen ones (empty clears them). Needs a post type that uses the taxonomy and permission to assign terms. |
Load terms | Off | "Show the post's current terms as the value." The edit screen opens the field with the post's current terms instead of the stored list. |
Notes:
- A list of more than 300 terms is not shown in full; the field switches to the search box instead (in front-end forms it shows "This list is too long to show here.").
- Save terms and Load terms work for top-level taxonomy fields on posts. They work on the edit screen, the REST API and
wpmcf_update_field(). - Load terms only changes what the edit screen shows. The value stored in the field (and returned by
wpmcf_get_field()) is updated when the post is saved. If terms are changed elsewhere,wpmcf_get_field()can differ fromwp_get_object_terms(). When the real terms matter, read them with WordPress functions.
$term_ids = wpmcf_get_field( 'project', 'topics' ); // [12, 13] or []
$names = wp_list_pluck( get_terms( [ 'include' => $term_ids, 'taxonomy' => 'category', 'hide_empty' => false ] ), 'name' );What is printed. Term names separated by commas; each name links to its archive when the taxonomy has public archives.
[wpmcf_field group="project" field="topics" wrap="false"]
→ <a href="http://example.com/category/news/">News</a>, <a href="http://example.com/category/news/local/">Local</a>CSV imports take comma-separated term IDs, slugs or names.
User
Chooses users, optionally only some roles.
Setting | Default | Effect |
|---|---|---|
Roles | none ticked | "Editors can only pick users with these roles. None ticked means every role." |
Maximum users | 0 |
|
- The result is always a list, even with Maximum users
1:[19], not19. Use$ids[0] ?? null. - User search matches the login, nicename and display name, never email addresses. Only people who can list users can search.
- IDs of users who do not exist or have a role that is not allowed are dropped on save.
$ids = wpmcf_get_field( 'project', 'owners' ); // [1, 19]
foreach ( (array) $ids as $user_id ) {
$user = get_userdata( $user_id );
if ( $user ) {
echo esc_html( $user->display_name );
}
}[wpmcf_field group="project" field="owners" wrap="false"] → Ada, FatihThe printed output is the display names, comma separated, without links. CSV imports take comma-separated user IDs or logins.
Troubleshooting
- My picker lists nothing. The field's Post types (or Roles) filter excludes the items, or the editor lacks the permission to read them.
- The related page prints nothing on the site. The post is a draft, private or otherwise not public. IDs are stored, but only public items print.
wpmcf_get_field()returns the ID of a deleted post. Stored IDs are not cleaned when a target is deleted; test withget_post( $id ).- I linked a page with Post object and it will not save. The field's Post types is still Post. Add Page.
Still stuck? Contact support