Support

Account

Home Forums ACF PRO Showing reverse relationships within admin

Solved

Showing reverse relationships within admin

  • Is there a way to show the reverse relationship of a taxonomy relationship, namely for what would normally be considered a M2M relationship?

    For example, lets say I have two custom post types, Movies and Genres.

    1 – I add an ACF to Movies of type “Relationship” with “Post Filter” set to “Genres”.

    2 – I create a movie – “Spiderman” and add two genres, “Action”, “Comic” via the admin panel.

    3 – Via theme functions, in the frontend, I can display the genres belonging to Spiderman, and, conversely, in the frontend, I can display the movies belongs to “Action” or to “Comic”.

    4 – The missing part – While in the admin area, can I show the movies belonging to a genre, while editing said genre.

    Note I can add an ACF of type “Relationship” with “Post Filter” set to “Movies” in Genres as well – but they don’t marry up as it seems at the db level they maintain there own sense of metadata.

  • Hi @cjke7777

    In this case, you need to use the Bidirectional Relationships. You can check our tutorial here: https://www.advancedcustomfields.com/resources/bidirectional-relationships/.

    I hope this helps 🙂

  • I just read through the code, looks really good. The example shows post<->post, but I would imagine it could be applied to any custom type (being that they all “inherit” from post anyway, in that strange lovely way WP does things).

    One follow up question – with different types (like Movie + Genre), would you add the Relationship ACF to both the movie and the genre for the above snippet to work correctly?

    As a sidenote, and in hindsight, I realise genre is really a poor example (ie could be taxonomy, but just an example 🙂 )

  • Hi @cjke7777

    Yes, I believe you need to add the relationship to both of the post types to make it works.

  • Cool I will try it out in the next few hours and leave an update here to confirm either way for future readers. Thanks for help, I will touch base shortly

  • Ok so yep it seems like you need a relationship field in both. I’m not totally comfortable with storing the relationship twice – I feel like thats a sleeper-bug waiting to happen.

    ie:
    – Movie A stores thats it is GenreA, GenreB, and
    – GenreA stores (separately) that is has Movie A
    – GenreB stores (separately) that is has Movie A

    So, as a compromise, for each relation, I nominate one as the relationship owner and only it can edit the relationship. And for the non-relationship owner I have added the following meta box which will list all possible relations.

    
    // Helper to grab all possible post types that could contain relationships
    if (! function_exists('get_content_post_types')) {
        function get_content_post_types() {
            return array_merge(
                ['page', 'post'],
                array_values(get_post_types([ '_builtin' => false ]))
            );
        }
    }
    
    // Create a query that finds our parent id in the serialised array
    if (! function_exists('acf_find_parents')) {
        function acf_find_parents($id, $fields) {
            return new \WP_Query([
                'post_type' => get_content_post_types(),
                'meta_query' => [
                    'relation' => 'OR',
                    array_map(function($field) use ($id) {
                        return [
                            'key'       => $field,
                            'value'     => '"' .$id. '"',
                            'compare'   => 'LIKE'
                        ];
                    }, $fields),
                ]
            ]);
        }
    }
    

    And then the usage would be something like:

    
    // Inside the genre page
    // This would find all times that this post has existed in anothers relation
    acf_find_parents($post->ID, ['music', 'movies', 'books']);
    

    An example of formatting this nicely would be:

    
    // Using laravels collect methods
    add_action('add_meta_boxes', function() {
        add_meta_box('genre_relationships', 'Relationships', function($post) {
            collect(acf_find_parents($post->ID, ['music', 'movies'])->posts)
                ->groupBy('post_type')
                ->each(function($type, $key) {
                    echo "<h3>{$key}</h3>";
                    $type->each(function($related) {
                        echo "<div>{$related->post_title}</div>";
                    });
                });
        });
    });
    

    This would spit out:

    music
    song G
    song F
    movies
    movie A
    movie C

    Again, its a bit of a compromise, but I would prefer this over duplicating the data.

    Disclaimer: The query probably should extend to join against the post table to make the post_type is actually a acf field

Viewing 6 posts - 1 through 6 (of 6 total)

You must be logged in to reply to this topic.