Home Forums Add-ons Repeater Field Combine dates between repeater field Reply To: Combine dates between repeater field

  • It is not possible to order the posts by a repeater sub field, so what you want to do is not possible. Even if it were possible, the nature of WP_Query would give you additional problems.

    Let’s say for example that “Show 1” is on “date 1” and “date 2” while “Show 2” is on “date 1” and “date 3”. Using WP_Query you will only see each “Show” listed once.

    Date 1
      => Show 1
      => Show 2
    Date 2
       Nothing listed, show 1 already shown
    Date 3
      Nothing listed, show 2 already shown

    I am actually currently working on a project that has a similar problem. The client wants “Events”. Each event can happen on multiple dates. Basically the same thing that you are doing. I have no choice but to use a repeater for this. How am I solving this.

    1) I’ve made my post type hierarchical.

    2) On top level posts I have a field group with the repeater. On child posts I have a field group that contains just a start date/time and an end date/time field. This requires a custom location rule.

    3) When an event is saved I have an acf/save_post action that creates creates and deletes child posts for the event based on the dates saved in the repeater field.

    4) In the admin list of posts I am hiding the child posts so that the client cannot see them. I am also hiding the fact that they can create child posts. I have a filter on pre_get_posts for this post type in the admin and I’m using ACF “hide on screen” to hide the page attribute blocks. So, basically, the client will never see the fact that all these posts are being added and deleted.

    I will post the relevant code for the above at the end of this.

    The remaining is not done. When showing posts on the front end I will do a pre_get_posts filter that will remove parent posts from the query and order all of the child posts by their start date/end date fields. When showing links I will link to the parent post instead of the child post. I’m probably also going to need to limit the number of dates that the client is allowed to add so that updating a post does not time out.

    The following code has not been made to work for your needs, it is just provided as as example of what I’ve done so far. The only thing that I’ve done is remove the client’s name from the code. It also has not been completely tested since I’m in the process of building it.

      class client_name_events {
        private $post_type = 'events';
        public function __construct() {
          add_action('pre_get_posts', array($this, 'hide_children_in_admin'));
          add_filter('acf/location/rule_types', array($this, 'acf_location_rule_types'));
          add_filter('acf/location/rule_values/post_level', array($this, 'acf_location_post_level_values'));
          add_filter('acf/location/rule_match/post_level', array($this, 'acf_location_post_level_match'), 20, 3);
          add_action('acf/save_post', array($this, 'save_event'), 20);
        } // end public function __construct
        public function hide_children_in_admin($query) {
          if (!is_admin() || !$query->is_main_query()) {
          if (!isset($query->query_vars) ||
              !isset($query->query_vars['post_type']) ||
              $query->query_vars['post_type'] != $this->post_type) {
          $query->set('post_parent', 0);
        } // end public function hide_children_in_admin
        public function save_event($post_id) {
          if (get_post_type($post_id) != $this->post_type) {
            // not our post type
          $parent = wp_get_post_parent_id($post_id);
          if ($parent) {
            // this is a child post
            // this should never happen
            // it's only here to cover all bases
          // get all dates from repeater
          $dates = array();
          if (have_rows('dates', $post_id)) {
            while (have_rows('dates', $post_id)) {
              $dates[] = array(
                'start' => get_sub_field('start'),
                'end' => get_sub_field('end')
          // get list of existing date posts
          $existing_dates = array();
          // get all child posts
          $args = array(
            'post_type' => 'events',
            'post_parent' => $post_id,
            'numberposts' => -1,
          $children = get_children($args);
          $new = array();
          $delete = array();
          if (!empty($children)) {
            foreach ($children as $id => $event) {
              $existing_dates[$id] = array(
                'id' => $id,
                'title' => $event->post_title,
                'start' => get_field('start_date', $id),
                'end' => get_field('end_date', $id)
            } // end foreach children
          } // end if !empty children
          // create list of dates to add
          // loop over all $dates, and all $existing_dates
          // if a date does not exist add it to the list to be added
          $add = array();
          if (count($existing_dates)) {
            foreach ($dates as $date) {
              $found = false;
              foreach ($existing_dates as $existing_date) {
                if ($date['start'] == $existing_date['start'] && $date['end'] == $existing_date['end']) {
                  $found = true;
              } // end foreach existing date
              if (!$found) {
                $add[] = $date;
            } // end foreach dates
          } else {
            // no existing dates
            // add them all
            $add = $dates;
          // create list of dates to remove
          // loop over all existing dates and all dates
          // if a date does not exist then add it to list of dates to remove
          $remove = array();
          if (count($exisiting_dates)) {
            foreach ($existing_dates as $id => $existing_date) {
              $found = false;
              foreach ($dates as $date) {
                if ($date['start'] == $existing_date['start'] && $date['end'] == $existing_date['end']) {
                  $found = true;
              if (!$found) {
                $remove[] = $id;
            } // end foreach existing date
          } // end if existing dates
          // delete posts
          if (count($remove)) {
            foreach ($remove as $id) {
              wp_delete_post($id, true);
          } // end if posts to remove
          // add posts
          if (count($add)) {
            foreach ($add as $date) {
              $post = array(
                'post_title' => $date['start'].' to '.$date['end'],
                'post_type' => 'events',
                'post_parent' => $post_id,
                'post_status' => 'publish'
              $new_id = wp_insert_post($post);
              if ($new_id) {
                update_field('field_5c6eb7f6dc628', $date['start'], $new_id);
                update_field('field_5c6eb81ddc629', $date['end'], $new_id);
            } // end foreach date to add
          } // end if posts to add
        } // end public function save_event
        public function acf_location_rule_types($choices) {
          if (!isset($choices['Other'])) {
            $choices['Other'] = array();
          if (!isset($choices['Other']['post_level'])) {
            $choices['Other']['post_level'] = 'Post Level';
          return $choices;
        } // end public function acf_location_rule_types
        public function acf_location_post_level_values($choices) {
          $choices['top'] = 'Top Level Post';
          $choices['child'] = 'Child Post';
          return $choices;
        } // end public function acf_location_post_level_values
        public function acf_location_post_level_match($match, $rule, $options) {
          if ($rule['param'] == 'post_level') {
            $post_id = $options['post_id'];
            $parent = wp_get_post_parent_id($post_id);
            if ($parent) {
              $level = 'child';
            } else {
              $level = 'top';
          switch ($rule['operator']) {
            case '==':
              $match = ($level == $rule['value']);
            case '!=':
              $match = ($level != $rule['value']);
              // do nothing
          return $match;
        } // end public function acf_location_post_level_match
      } // end class client_name_events