Support » Plugin: Advanced Custom Fields: Extended » Creating a Complex Relationship

  • David Bee

    (@davidbawiec)


    Hi Konrad!

    I’m working on a new site where I need to create a complex relationship between a “Show” custom post type and Users. In a normal situation, I would use your Bidirectional field (which is fantastic BTW!). However, this setup is a little more complex, so I’m hoping you can help in figuring out what the best option would be.

    Every “Show” has a list of actors. The actors have to be ordered manually, based on how important their role was. So I was thinking that implementing a Flexible Content field would be a good fit for this as I could add as many actors as necessary for that show, and manually re-order them as needed. Now each “row” would have the actor’s name, but I’d love to turn this into a relationship field, linking to the User ID.

    On the other end, on each User’s profile, I want to display all the shows that they have participated in. Initially, I thought that using the bidirectional field would be perfect for this. However, on the user profiles, I need to sort the Show post IDs by date of the show (which is another ACF field on the Show custom post type). So I’m wondering:

    1. Will the Bidirectional field even work inside a Flexible Content row?
    2. Is it better to make the Flexible Content rows use a non-bidirectional User relationship and then run a custom query on the User Profiles that tries to retrieve all the shows the user has been “tagged” in (similar to Example 4 on How to Query Posts using custom sub field values)?
    3. Is there an even better way to achieve all this?

    Thanks a LOT for your help!
    David

Viewing 9 replies - 1 through 9 (of 9 total)
  • Plugin Author hwk-fr

    (@hwk-fr)

    Hello,

    Thanks for the feedback! Unfortunately the bidirectional setting isn’t compatible with repeater/flexible content, since the logic is simply unsustainable with those fields types. You can read more about it in my answer here.

    Regarding your question, it looks like a User Field <> Relationship bidirectional setup will work. The “User Field” on the “Show” post type will allow you to choose and order users by importance. And on the other side, the Relationship (or Post Object) will save the “Shows” of the selected User.

    You can then easily order those “Shows” on the front-end using a WP Query and order Post ID based on a meta_value & meta_key. See WP Query order & order by documentation.

    I would recommend to stick to ACF/ACFE fields compatible with the bidirectional setting, but if you really want to use a Flexible Content, it’s manageable. You’ll have to write the whole relationship logic by yourself tho, which can become quite complex (depending on your ACF knowledge level).

    Hope it helps!

    Regards.

    Thread Starter David Bee

    (@davidbawiec)

    Thanks for the detailed response Konrad! Really appreciate it! And you’re a true rockstar for the amount of work you’ve put into the plugin throughout the years.

    In my case, for each actor, I not only have to attach the user ID (the user relationship) but also fill out the character name field. Which is why I think I have to do it as a flexible content/repeater field.

    I’m pretty code savvy, so I don’t mind getting my hands dirty in the code. But it sounds like my option #2 may be the easiest way to go. Would you agree? Though I’m curious to hear how you would suggest implementing a custom bi-directional relationship in this case.

    Thanks!
    David

    Plugin Author hwk-fr

    (@hwk-fr)

    Hello,

    Yes, in that case you could probably use a Repeater field (Flexible Content is useful when having different layouts, in your case a repeater should be enough). Also you don’t really need Bidirectional setting, since bidirectional setup is useful if you want to update the user shows from the User screen, which is not necessary here, since the actor will have additional data (character name).

    To setup your one-way relationship, you could either use hooks on the “Actor” field itself (within the repeater), or use a global hook on post save like acf/save_post.

    If you decide to use field hooks, then you should use acf/update_value & acf/delete_value. Usage exmple:

    add_filter('acf/update_value/name=actor', 'my_acf_update_actor', 10, 4);
    function my_acf_update_actor($value, $post_id, $field, $original){
        
        // Bail early if the post type is not 'show'
        if(!is_numeric($post_id) || get_post_type($post_id) !== 'show')
            return $value;
        
        // Vars
        $user_id = $value;
        $show_id = $post_id;
        
        // Get User Shows
        
        // Check if the show is already in uder shows
        
        // Add show to user shows
        
        // Update user shows
        
        return $value;
        
    }
    
    add_action('acf/delete_value/name=actor', 'my_acf_delete_actor', 10, 3);
    function my_acf_delete_actor($post_id, $field_name, $field){
    
        // Bail early if the post type is not 'show'
        if(!is_numeric($post_id) || get_post_type($post_id) !== 'show')
            return;
    
        // Vars
        $value = acf_get_value($post_id, $field);
        $user_id = $value;
        $show_id = $post_id;
        
        // Get User Shows
        
        // Check if the show is already in uder shows
        
        // Remove show to user shows
        
        // Update user shows
        
    }
    

    If you decide to use global post save hook, I would recommend to use the acfe/pre_save_post/post_type=show hook (See documentation).

    It will allow you to navigate thru data using get_field() and have_rows('my_repeater'): the_row(). You can then compare the data that is about to be saved with the data already save in DB to determine if an actor has been added or removed from the repeater.

    Regarding the relationship on the User screen, you should probably just hide it, since it’s one-way relationship, and removing a show from the user screen will have no effect. You can easily hide a field using the Advanced Field Settings, the Field Visibility Widget or using acf/prepare_field.

    Hope it helps!

    Regards.

    Thread Starter David Bee

    (@davidbawiec)

    Great to know! Thanks a TON for taking all this time to provide the samples and detailed explanation!

    From a performance standpoint, is there a difference between saving the User’s Shows as its own usermeta field entry and retrieving that, rather than just running a WP_Query() to try to retrieve them dynamically?

    Regards!
    David

    Plugin Author hwk-fr

    (@hwk-fr)

    Hello,

    It depends what you want to display. If you want to display shows for a specific user, then it’s far better to use a User Meta with already saved post ids. Otherwise you’ll have to perform a large & complex query on all shows (and there’s probably more shows than users) to determine which shows should be displayed.

    When you retrieve the show ids from the User Meta, you can then order them with an another meta key using a WP_Query or get_posts() in combination with post__in & meta_key. Usage example:

    $show_ids = get_field('shows', 'user_42', false);
    
    $shows = get_posts(array(
        'post_type' => 'show',
        'post__in'  => $show_ids,
        'meta_key'  => 'show_date',
        'orderby'   => 'meta_value_num',
        'order'     => 'DESC',
    ));
    

    Regards.

    Thread Starter David Bee

    (@davidbawiec)

    Got it. Great suggestion. This is a smaller theatre company, so the number of shows will pretty much always be smaller than the number of users (actors). But it’s good to know for future reference anyway!

    I figured I’d do the WP_Query on acf/update_value/name=actor filter or acfe/pre_save_post/post_type=show to order the show post IDs right away and save it to the usermeta table at that point. That way it’s all handled when the shows are being created and the front-end retrieval is fast on user profiles. Hopefully, that logic makes sense to you as well?

    Anyway, you’ve been extremely helpful with this! Appreciate it!

    Plugin Author hwk-fr

    (@hwk-fr)

    Hello,

    Yep, it makes sense.

    If you enjoy the plugin and the support, feel free to submit a review, it always helps and it’s much appreciated 🙂

    Have a nice day!

    Regards.

    Thread Starter David Bee

    (@davidbawiec)

    Absolutely! Done!! Have a great weekend Konrad!
    D

    Plugin Author hwk-fr

    (@hwk-fr)

    Hello,

    Thanks a lot for that very kind review 🙂

    Have a nice day!

    Regards.

Viewing 9 replies - 1 through 9 (of 9 total)
  • You must be logged in to reply to this topic.