• Hello,

    First I have to say: what a nice little plugin! All seems to be working excellent except one situation, here it is:

    I have a 1:N relationship between 2 CPTs, Courses and Terms.

    • Each Course can have several Terms
    • Each Term can be assigned only to one Term.
    • For the Course I use Relationship field (without any limits)
    • For the Term I use Post Object field (no multiple selections allowed)

    Lets have a simple situation:

    • 2 courses (A, B)
    • 4 terms (1,2,3,4)
    • All 4 terms are are assigned to Course A.

    Action:
    I open the Course B and select Term 1, then save.

    What I would expect:

    • After attemting to save the course I should be alerted that I cannot select the Term 1, because it’s already assigned to another course.

    OR

    • Course is saved, but the relationship field is left empty, no new term was added.

    OR (best solution)

    • The Term 1 should be grayed out in the select list (in fact all 4 courses should be) as it is used by another course and cannot be added.

    What really happens:

    • Term 1 still has only Course A assigned (which is correct)
    • Course A has all 4 terms assigned (also correct)
    • Course B has Term 1 assigned (not correct)

    When I changed the behaviour to overwrite the settings it all worked as expected:

    • Term 1 has Course B assigned
    • Course A has only 3 terms assigned (2,3,4)
    • Course B has Term 1 assigned

    Here is the filter I used:

    add_filter('acf-post2post/overwrite-settings', 'bleye_acf_post2post_overwrite');
    function bleye_acf_post2post_overwrite($settings) {
      $settings['termin_kurz'] = array(
          'overwrite' => true,
      );
      return $settings;
    }

    So, is this an intended behaviour? It doesn’t seem to me. For now, I will get by by overwriting the settings, but I would prefer, it wasn’t be possible to select the posts which are already in use (when overwriting is disabled).

    Could you please look into it and give me some feddback?

    Thank you very much
    Petr

    • This topic was modified 2 years, 11 months ago by blackeye0013.
Viewing 2 replies - 1 through 2 (of 2 total)
  • Plugin Author John Huebner

    (@hube2)

    This is working as expected.

    There is no mechanism in ACF to give a “warning” or “message” that the field on the other end will not be updated without returning an error for the field that will prevent the post from being saved. Let me know if you need me to expand on this.

    Preventing a post from being saved is not something that I would want to do because there would be people on the other side of the coin that would not want this. I have made the decision to ignore the update if it breaks the rules on the other end of the relationship and leave it up to the individual developer to alter this to allow overwriting the value on the other end.

    Something like this is left up do the developer using this plugin. Using the acf/validate_value filter provided by ACF this can be accomplished.

    For example:

    
    // this code has not been tested
    add_filter('acf/validate_value/type=post_object', 'validate_bidirectional_relationships', 20, 4);
    add_filter('acf/validate_value/type=relationship', 'validate_bidirectional_relationships', 20, 4);
    function validate_bidirectional_relationships($valid, $value, $field, $input) {
      global $post;
      if (!$valid || empty($value)) {
        return $valid;
      }
      $posts_ids = $value;
      if (!is_array($posts_ids)) {
        $posts_ids = array($posts_ids);
      }
      $messages = array();
      foreach ($posts_ids as $post_id) {
        $remote_value = get_field($field['name'], $post_id);
        if (empty($remote_value)) {
          continue;
        }
        if (!is_array($remote_value)) {
          $remote_value = array($remote_value);
        }
        $max_posts = 0;
        $remote_field_object = get_field_object($field['name'], $post_id);
        if ($remote_field_object['type'] == 'post_object') {
          if (!$remote_field_object['multiple']) {
            $max_posts = 1;
          }
        } elseif ($remote_field_object['type'] == 'relationship') {
          if ($remote_field_object['max']) {
            $max_posts = $remote_field_object['max'];
          }
        }
        if ($max_posts > 0 && count($remote_value) == $max_posts && !in_array($post->ID, $remote_value)) {
          $remote_post = get_post($post_id);
          $messages[] = $remote_post->post_title.' cannot be selected';
        }
      } // end foreach
      if (!empty($messages)) {
        $valid = implode('<br />', $messages);
      }
      return $valid;
    } // end function
    

    There is also no mechanism in ACF to disable (“gray out”) a value in a select2 field so that it is not selectable. The only thing that could possibly be done here is to use an acf/fields/relationship/query or acf/fields/post_object/query filter to filter out posts that cannot be selected by adding a “post__not_in ” argument. Similar but more complicated than the above filter. However, such a filter would likely be detrimental to performance because you’d need to look at the value of every possible post that could be selected to determine if selection would mean the other post would have too many. In all likely hood this would time out the AJAX request and just break the field.

    • This reply was modified 2 years, 11 months ago by John Huebner.
    Thread Starter blackeye0013

    (@blackeye0013)

    Hello John,

    Thanks for your reply. Unfortunately, your code doesn’t work as expected – it disables all the fields. But never mind, I’ve realized the rewrite behaviour is perfectly suitable for my case.

    Concerning the default behaviour, it’s good that I know now how it works and I can deal with it on my own.

    Thanks again

Viewing 2 replies - 1 through 2 (of 2 total)
  • The topic ‘1:N Relationship not Working as Expected’ is closed to new replies.