Support

Account

Home Forums ACF PRO Sort a repeater field by date (and store it)

Solved

Sort a repeater field by date (and store it)

  • I have a post type profiles, which has a repeater field named sd_tour_schedule.
    Each schedule can have multiple dates and has 3 sub fields (city, from, until).

    The output shows all posts, with the first upcoming date shown, but (as far as I can debug it) the posts get sorted by the ‘first’ post date in the repeater. So I want to sort the repeater after saving.

    If I run this code, the values do get sorted (which I can see in the back-end) and on the single view, but on a page which queries this repeater value it’s not shown anymore. I think I might not store the subfield correctly.

    Any insight to this ?

    function sd_sort_tour_dates( $post_id ) {
    
        if ( isset( $_POST[ 'acf' ][ 'field_5a0de683a21cf' ] ) ) {
            $tour_dates = get_field( 'sd_tour_schedule', $post_id );
            foreach ( $tour_dates as $key => $row ) {
                $column_id[ $key ] = $row[ 'from' ];
            }
            array_multisort( $column_id, SORT_NUMERIC, $tour_dates );
            $key = 0;
            foreach ( $tour_dates as $key => $tour_info ) {
                $key++;
                if ( is_array( $tour_info ) && count( $tour_info ) > 0 ) {
                    foreach( $tour_info as $column => $value ) {
                        update_sub_field( array('sd_tour_schedule', $key, $column ), $value );
                    }
                }
            }
        }
    }
    add_action( 'save_post', 'sd_sort_tour_dates' );
  • This is my meta query.

    $query->set( 'meta_query', array(
        'tour_clause' => array(
            'key'     => 'sd_tour_schedule_%_until', 
            'value'   => date( 'Ymd' ),
            'compare' => '>'
        ),
        'move_up_clause' => array(
            'key'     => 'sd_move_item_up_timestamp',
            'compare' => 'EXISTS'
        ),
    ));
    $query->set( 'orderby', array( 'tour_clause' => 'ASC', 'move_up_clause' => 'DESC' ) );

    And the filter which is called.

    function sd_tour_city_filter( $where ) {
        global $wpdb;
        $where = str_replace(
            "meta_key = 'sd_tour_schedule_%",
            "meta_key LIKE 'sd_tour_schedule_%",
            $wpdb->remove_placeholder_escape( $where )
        );
        return $where;
    }

    It returns the output but sorts by the row numbers/index. Hence why the order needs to be correct in the back-end and that’s why the order has to be ‘re-stored’ after saving a post. I disabled the ordering of repeaters on the front-end so users can’t change this. I don’t want them to think about this.

  • After some testing, I think this will do the trick.

    if ( isset( $_POST[ 'acf' ][ 'field_5a0de683a21cf' ] ) ) {
        $tour_dates = get_field( 'sd_tour_schedule', $post_id );
    
        if ( $tour_dates ) {
            foreach ( $tour_dates as $key => $row ) {
                $column_id[ $key ] = $row[ 'from' ];
            }
            array_multisort( $column_id, SORT_NUMERIC, $tour_dates );
            $key = 0;
            foreach ( $tour_dates as $key => $tour_info ) {
                if ( is_array( $tour_info ) && count( $tour_info ) > 0 ) {
                    foreach( $tour_info as $column => $value ) {
                        if ( 'city' != $column ) {
                            $value = date( 'Ymd', (int) $value );
                        }
                        update_post_meta( $post_id, 'sd_tour_schedule_' . $key . '_' . $column, $value );
                    }
                }
                $key++;
            }
        }
    }
Viewing 4 posts - 1 through 4 (of 4 total)

You must be logged in to reply to this topic.