Support

Account

Home Forums Search Search Results for 'event date repeater'

Search Results for 'event date repeater'

topic

  • Unread

    New user needing a little help with date field

    I’m sure for people here this will be a no-brainer, but I’m new to ACF and not a coder, but I do have a basic knowledge of WordPress and how it works.

    I have set up a custom post type called ‘events’ and a custom field called ‘event_date’.

    I’m using Oxygen and trying to set up a repeater to query the post type ‘events’, but how do I get it to only show events on a specific day?

    Any help appreciated.

  • Unread

    Clone sub field values from relationship post

    I found this topic from 2019 which was solved. But was trying to make this work with sub fields. i.e. – What if the Events fields were repeater fields that could be populated multiple Places fields (Map/Address fields, etc.). I gave it a shot below, but I’m missing something.

    https://support.advancedcustomfields.com/forums/topic/clone-field-value-from-relationship-post/#post-135706

    add_action('acf/save_post', 'save_event_update_address', 20);
    function save_event_update_address($post_id) {
      if (get_post_type($post_id) != 'events') {
        // not and event post, bail
        return;
      }
      // get location post ID
      // you said it's a relationship field, a relationship field will turn an array of posts
      // I am setting the 3rd parameter because we only need the IDs
      $related_places = get_sub_field('relationship_field_name');
      // also the 
      if ($related_places) {
        $place_id = $related_places[0];
        $address = get_field('address_field_on_place_name', $place_id);
        update_sub_field('address_field_on_event_repeater_name, $address, $post_id);
      }
    }
  • Solved

    Override issue when repeater is populated both via backend and frontend

    I use a repeater field for creating a visitor list:

    
        First Name    Last Name
    ---------------------------
    1   John          Miller
    ---------------------------
    2   Tom           Brown
    ---------------------------
    3   Mike          Smith
    ---------------------------
    ...
    

    My field can be populated in two ways:

    1. via the WordPress backend (when I edit the post containing the field)
    2. via a form in the frontend of my site (I use the add_row() function when the form is submitted.)

    My problem:

    • I edit the related post in the WordPress backend. There, I see a list of 3 visitors.
    • In the meantime, someone enters a 4th visitor via the frontend form. The 4th visitor is saved to the DB.
    • If I refreshed my page in the backend, I would see that a 4th visitor was added. Fine!
    • But if I don’t refresh my page in the backend (i.e. I still see the list of 3 visitors) and hit the post “Update” button, the list of 3 visitors is saved and overrides the list that actually contains 4 visitors. The 4th visitor is lost.

    So, my question is:
    How can I prevent this? How can I check if new entries were added to the list before it is saved? I guess, I could use the acf/update_value filter or the acf/save_post action – but I don’t know how.

    Thanks a lot,
    Karl

  • Unread

    How to Target ACF Edit Page?

    We have a PHP snippet that is being deployed using the Woody Snippets plugin. The code works great and does what it needs to do, which is to populate an ACF text field when the ACF form is saved or updated on the backend.

    But, that snippet is set to “run everywhere” because the only other option within Woody Snippets is to add it to a post or page via a shortcode. We don’t know how to add a shortcode (and have it execute) on an ACF/custom post type form on the back-end.

    The question: How could we edit the snippet (below) to only execute when someone is editing our custom post type on the back-end? We need this because running the snippet everywhere is breaking the Elementor editor, so we’re unable to edit the custom post template.

    Hope that makes sense! Here’s our snippet, if it matters:

    
    // This populates and saves search terms for product landing pages based on what lives in the product tables
    
    function save_search_terms( $post_id ) {
        
        $searchterms = array();
        
        if( have_rows('product_table') ):
        while( have_rows('product_table') ) : the_row();
    
        // Loop over sub repeater rows        
    
            if( have_rows('product_table_products') ):
                while( have_rows('product_table_products') ) : the_row();
    
        // Get sub value
        
        foreach( $tempsearchterms as $tempsearchterm );
            $tempsearchterm = get_sub_field('product_table_product');
                $searchterms[] = $tempsearchterm->part_number . " " . $tempsearchterm->product_name . " " . $tempsearchterm->model_type;
        
                endwhile;
            endif;
        endwhile;
    endif;    
        
        // update field
        
        update_field('search_terms', implode(' ', $searchterms) );
    }
    
    add_action('acf/save_post', 'save_search_terms');
    
    ?>
        <style type="text/css">
    
            #search-terms {
            pointer-events: none;
        }
    
        </style>
    
  • Helping

    How to transfer form Gutenberg-Block to another ACF-Field

    Hi

    I have registered an ACF field as a Gutenberg-Block.

    add_action('acf/init', 'my_acf_init');
    function my_acf_init() {  
        if( function_exists('acf_register_block_type') ) {
            acf_register_block_type(array(
                'name'                => 'event-date',
                'title'                => __('Veranstaltungs-Datum'),
                'description'            => __('Veranstaltungs-Datum'),
                'render_template'   => 'block-rendering/events_date.php',
                'icon'                => 'format-image',
                'keywords'            => array( 'Event' ),
                'mode'                 => 'edit',
                'supports'          => array('multiple' => false, 'className' => true ), 
                'post_types' => array('events',),
            ));
     
        }    
    }  

    It is a repeater field with a date picker (and other fields).
    Is there a way to automatically transfer the date from the Gutenberg block to another ACF field (not registered as a block)?

    Thank you all!
    Matthias

  • Solved

    Date Field – change div class based by date

    Hello ,

    In the site that i develop i was try to change a class to a div by the date that choose in the date field in the admin, the page is events page, and i am using with a repeater field, the date field is a sub-field.

    What in the end i want to achieve – When the date is far from the date event or it is the day – add class to a div “webinar-holder”.
    When the date of the event has passed – add class “old-event”

    i was try as follow

    
                            <?php if( $webinarDate <= date('dmY') ) { ?>
                            <div class="webinar-holder old-event">
                             <?php } elseif ( $webinarDate >= date('dmY') ) { ?>
                             <div class="webinar-holder">
                             <?php } ?>
    

    And this is the long code (with the repeater):

    
               <div class="webinars-container">
                <?php if( have_rows('webinars-repeater') ){ ?>
                        <?php while( have_rows('webinars-repeater') ) { the_row();                                           
                            // vars
                            $webinarTitle = get_sub_field('webinar-title');                                          
                            $webinarDate = get_sub_field('webinar-date');                                           
                            $webinarStartTime = get_sub_field('webinar-time-start');                                           
                            $webinarEndTime = get_sub_field('webinar-time-end');                                           
                            $webinarLecturerImg = get_sub_field('webinar-lecturer');                                           
                            $webinarAboutLecturer = get_sub_field('webinar-about-lecturer');                                           
                            $webinarLink = get_sub_field('webinar-link');                                           
                            $webinarLinkText = get_sub_field('webinar-link-text');                                                                                     
                            ?>
                            
                            <?php if( $webinarDate <= date('dmY') ) { ?>
                            <div class="webinar-holder old-event">
                             <?php } elseif ( $webinarDate >= date('dmY') ) { ?>
                             <div class="webinar-holder">
                             <?php } ?>
                               <!-- details -->
                               <div class="webinar-details">
                                   <div class="webinar-subject">
                                      <?php if (get_locale() == 'he_IL')  {  ?>
                                          <div class="title">על מה נדבר?</div>
                                      <?php } elseif (get_locale() == 'en_US') { ?>
                                          <div class="title">What will we talk about?</div>
                                      <?php } ?>      
                                       <?php echo $webinarTitle; ?>
                                   </div>
                                   <div class="webinar-date">
                                      <?php if (get_locale() == 'he_IL')  {  ?>
                                          <div class="title">בתאריך</div>
                                      <?php } elseif (get_locale() == 'en_US') { ?>
                                          <div class="title">Date</div>
                                      <?php } ?>  
                                       <?php echo $webinarDate; ?>
                                   </div>
                                   <div class="webinar-time">
                                      <?php if (get_locale() == 'he_IL')  {  ?>
                                          <div class="title">בין השעות</div>
                                      <?php } elseif (get_locale() == 'en_US') { ?>
                                          <div class="title">Time</div>
                                      <?php } ?>   
                                       <?php echo $webinarStartTime; ?>&nbsp;-&nbsp;<?php echo $webinarEndTime; ?>
                                   </div>
                               </div>
                               <!-- end details -->
                               <div class="webinar-about-lecturer-container">
                                       <div class="lecturer-image">
                                             <img src="<?php echo $webinarLecturerImg['url']; ?>" alt="<?php echo $webinarLecturerImg['alt'] ?>" />
                                       </div>
                                  <div class="about-lecturer-text"><?php echo $webinarAboutLecturer; ?></div>
                                   <a href="<?php echo $webinarLink; ?>" target="_blank" class="webinar-link" rel="nofollow"><?php echo $webinarLinkText; ?></a>
                               </div>
                            </div>
    
                        <?php } ?>
                <?php } ?>     
               </div>
    

    I don’t now what i missed that isn’t working.

    I will very appreciat for every Instruction what to do to fix this….

  • Solving

    Repeater row in WPQuery issue

    Hi,

    So i have a repeater inside post-type ‘properties’ that stores Lot No and Auction Date for all the Auctions a property is in.

    When going into an event page, say for 12th August it needs to list all of the properties in this auction in Lot No order.

    When i use WP Query i’m doing it as so:

            function my_posts_where( $where ) {
    
            	$where = str_replace("meta_key = 'auctions_$", "meta_key LIKE 'auctions_%", $where);
    
            	return $where;
            }
    
            add_filter('posts_where', 'my_posts_where');
    
            $args = array (
                'post_type'=>'properties',
                'post_status'=>'publish',
                'posts_per_page'=> 40,
                'paged'=> $paged,
                'suppress_filters' => false,
                'meta_query' => array(
                 'proparray' => array(
                   'key' => 'auctions_$_auction_date',
                   'value' => $today2,
                   'compare' => 'LIKE',
                 ),
                 'lot-nos' => array(
                   'key' => 'auctions_$_lot_no',
                   'type' => 'NUMERIC',
    
                ),
            ),
           'orderby' => array(
              //  'auction-dates' => 'ASC',
                'lot-nos' => 'ASC',
            ),
              );
            $wpb_all_query = new WP_Query($args);

    My problem is that it’s picking up Lot Nos from other rows. So if a property has the following date:

    Auction Date : 7th June 2020
    Lot No: 2
    Auction Date: 12th August 2020
    Lot No: 14

    It is picking up the auction date 12th August 2020, but ordering it as Lot No 2, NOT 14. I need it to match to the specific row of the date in question, then get the Lot No from that row. is this possible?

  • Unread

    multiple forms in front end user account

    Hi all.

    I’m building a website that is for booking events, the e-commerce platform is woocommerce. I’ve acted an action to add a new page to the user account called family, where I want the user to be able to manage their family members and contact info.

    So far I’ve added the page, created a repeater for user where they can add a family member and fill in that members information, it saves and all works great.

    Now I’d like to add an ACF group before the repeater that has main information such as emergency contact details and next of kin, but I can’t figure out how to display two fields (the group and the repeater) within the one action and only have one save button to save the details to the users account.

    This is what I have so far that works for the repeater, but if anyone could steer me in the right direction as to how to add the group field, it’d be hugely appreciated.

    <?php
      acf_form_head();
      get_header(); 
    ?>
    
    Family
    
    <div class="family-members-form"><?php 
    
     if ( !is_user_logged_in() ){ 
     echo 'You are not logged in. <br /> <a href="' . get_permalink(31) .'">Log In &rarr;</a>';
    
     } else {
    
     $user = wp_get_current_user();
     
    
    $options = array(
      // 'field_groups' => ['group_5cbd99ef0f584'],
      'fields' => ['field_5f24194f719ca'],
      'form_attributes' => array(
        'method' => 'POST',
        'action' => admin_url("admin-post.php"),
      ),
      'html_before_fields' => sprintf(
        '<input type="hidden" name="action" value="adaptiveweb_save_profile_form">
        <input type="hidden" name="user_id" value="user_%s">',
        $user->ID
      ),
      'post_id' => "user_{$user->ID}",
      'form' => true,
      'html_submit_button' => '<button type="submit" class="acf-button button button-primary button-large" value="Update Profile">Update Profile</button>',
    );
    
    acf_form($options);
     }
    
     ?>
     
     </div>
  • Helping

    Query on a repeater date pear (acf)

    I’m struggling with this. I a have list of date (not fixed, I can have as many date as I want) made thanks to the ACF Repeater. In my query, I want to filter by date.

    But, I have to hide some post if the date choosen is not between my 2 date fields (evenement_date_start and evenement_date_end). This is an example of my date list.

    fields

    So if I choose between 01/10/2020 and 20/10/2020, the event should not show up. But right now, it does and I can’t figure out why.

    This is my query args, my date and variable have this format “Ymd” :

        $args[] =
        ['relation' => 'OR',
            ['relation' => 'AND',
                [
                    "key" => "evenements_liste_dates_AAA_evenement_date_start",
                    "compare" => "<=",
                    "type" => 'DATE',
                    "value" => $startDate,
                ],
                [
                    "key" => "evenements_liste_dates_AAA_evenement_date_end",
                    "compare" => ">=",
                    "type" => 'DATE',
                    "value" => $endDate,
                ]
            ],
            ['relation' => 'OR',
                [
                    "key" => "evenements_liste_dates_AAA_evenement_date_start",
                    "compare" => "BETWEEN",
                    "type" => 'DATE',
                    "value" => [$startDate, $endDate],
                ],
                [
                    "key" => "evenements_liste_dates_AAA_evenement_date_end",
                    "compare" => "BETWEEN",
                    "type" => 'DATE',
                    "value" => [$startDate, $endDate],
                ]
            ],
        ];

    And my post where rewriting

    
        add_filter('posts_where', function ($query, WP_Query $wp_query) {
            if(!is_admin() && $wp_query->query_vars['post_type'] == "evenement" && !$wp_query->is_main_query()) {
                $query = str_replace("meta_key = 'evenements_liste_dates_AAA_evenement_date_start'", "meta_key LIKE 'evenements_liste_dates_%_evenement_date_start'", $query);
                $query = str_replace("meta_key = 'evenements_liste_dates_AAA_evenement_date_end'", "meta_key LIKE 'evenements_liste_dates_%_evenement_date_end'", $query);
            }
            return $query;
        }, 10, 2);

reply

  • This is my test code I am using at the moment

    add_action('save_post_product', 'rl_acf_test', 999);
    function rl_acf_test($post_id) {
        // Avoid infinite loop when using update_field()
        remove_action('save_post_product', __FUNCTION__);
    
        // Check if stock is managed
        $product = wc_get_product($post_id);
        if (!$product ) {
            return;
        }
    
        // Update the repeater
                $rows = [[
                        'event_date' => "30062025",
                        'shipping_date' => "30062025",
                        'return_send_date' => "30062025",
                        'return_arrival_date' => "30062025",
                ]];
        //$status = update_field($repeater_name, $new_rows, $post_id);
        //$status = update_field($acfFieldObject['key'], $rows, $post_id);
        $status = update_field('rental_info', $rows, $post_id);
        error_log("Status is: " . var_export($status,true));
        $product->save();
    }
  • Not sure if this is already fixed in an upcoming release, but I’d like to add my two cents.

    Best way that I have found to replicate this is to make a repeater-field with two required text fields and a true/false which is used for conditional logic.
    Set one textfield to show when the true/false is unchecked and hide the other. viceversa for when the true/false is checked.

    IE;
    Textfield A*: show if value is equal to unchecked.
    Textfield B*: show if value is equal to checked.

    If you then reload the edit page it wil invalidate the block and prevent the entire page from being updated. When you nibble on the true/false checkbox (or kick any field in the repeater) it will update and presumably see the conditional logic and validate the field again, allowing you to update the page.
    Although, it doesn’t seem to be limited to just repeaters, as similar logic in the block itself has problems too.

    This is in combination with ACF’s Gutenberg block functionality by the way.

  • Ok i have updated the code and now it works but somehow you need to have atleast one layout in flexible content for dragging to work.

    add_action('acf/input/admin_footer', function () {
        ?>
        <script type="text/javascript">
    
            (function($) {
    
                acf.add_action('ready', function($el){
                    $(".acf-flexible-content .values").sortable({
                        connectWith: ".acf-flexible-content .values",
                        start: function(event, ui) {
                            acf.do_action('sortstart', ui.item, ui.placeholder);
                        },
                        stop: function(event, ui) {
                            acf.do_action('sortstop', ui.item, ui.placeholder);
                            $(this).find('.mce-tinymce').each(function() {
                                tinyMCE.execCommand('mceRemoveControl', true, $(this).attr('id'));
                                tinyMCE.execCommand('mceAddControl', true, $(this).attr('id'));
                            });
                        }
                    });
    
                    $(".acf-repeater .acf-flexible-content").sortable({
                        connectWith: ".acf-repeater .acf-flexible-content",
                        start: function(event, ui) {
                            acf.do_action('sortstart', ui.item, ui.placeholder);
                        },
                        stop: function(event, ui) {
                            acf.do_action('sortstop', ui.item, ui.placeholder);
                        }
                    });
                });
    
                acf.add_action('sortstop', function ($el) {
                    var $repeater = $($el).closest('.acf-input > .acf-repeater');
                    
                    if ($repeater.length) {
                        var $row = $el.closest('.acf-row');
                        var column_num = $row.attr('data-id');
    
                        // Loop through fields within the dropped element and update names
                        $el.find('[name^="acf[field_"]').each(function() {
                            var field_name = $(this).attr('name');
                            field_name = field_name.match(/\[([a-zA-Z0-9_-]+)\]/g);
                            field_name[1] = '[' + column_num + ']';
                            var new_name = 'acf' + field_name.join('');
                            $(this).attr('name', new_name);
                        });
    
                        // Loop through layouts within the flexible content field
                        $repeater.find('.acf-flexible-content .values > .layout').each(function(index) {
                            $(this).find('.acf-fc-layout-order:first').html(index + 1);
    
                            // Loop through fields within each layout and update names
                            $(this).find('[name^="acf[field_"]').each(function() {
                                var field_name = $(this).attr('name');
                                field_name = field_name.match(/\[([a-zA-Z0-9_-]+)\]/g);
                                var tempIndex = parseInt(field_name[3].match(/([0-9]+)/g));
                                field_name[3] = field_name[3].replace(tempIndex, index);
                                var new_name = 'acf' + field_name.join('');
                                $(this).attr('name', new_name);
                            });
    
                            // Trigger click on selected buttons to activate conditional logic
                            $(this).find('.acf-button-group label.selected').trigger('click');
                        });
                    }
                });
    
            })(jQuery);
    
            function GetSubstringIndex(str, substring, n) {
                var times = 0, index = null;
                while (times < n && index !== -1) {
                    index = str.indexOf(substring, index + 1);
                    times++;
                }
                return index;
            }
    
        </script>
        <?php
    });
    
  • In both sets of code you are resetting the value to an empty array and then updating the field on each loop. This means that only the last value will exist when done.

    You need to build the repeater and update with all rows at the same time

    going by your first code

    
    $group_key = 'field_64e765bfc42ef';
    $repeater_key = 'field_64e76f9210338';
    $group_value = array();
    $repeater_value = array();
    foreach ($event->lineup as $item) {
      // add row to repeater
      $repeater_value[] = array(
        'field_64e770e717754' => $item->details,
        'field_64e770f317755' => $item->time
      );
    } // end foreach row
    $group_value = array(
      $repeater_key => $repeater_value
    );
    

    Now you can update the group field with the group value.

    Also, do not forget that if the group, or the repeater has any values other than these fields then you will need to get the current value of the group field and modify that existing value instead of starting with nothing.

    To get the value of the existing group before you updated in

    
    if (have_rows('group_field_name')) {
      // group field always true
      while (have_rows('group_field_name')) {
        // always happens 1 time for group fields
    
        // the row returns an array with field key => unformatted value pairs
        // ready for use in update_field();
        $group_field_value = the_row();
      }
    }
    
  • Hi Simon,

    I guess ‘field_64e76f9210338’ is your group field key.
    If that’s the case, i don’t think you need it if you only want to update your repeater inside your group.

    Maybe you could try something like the code below.
    Let me know if it helps you.

    Cheers

    <?php
    //be sure that's your repeater key
    $repeater_key = 'field_64e765bfc42ef';
    $repeater_name = 'your_rep_name';
    
    //$rep_count will be used to create a new repeater OR add rows to an existing repeater
    $rep_count = count(get_field($repeater_name)); //not sure if it works with field key
    
    foreach ($event->lineup as $item) {
    	$updated_rep = []; //Not sure if this is needed - it won't hurt
    	
    	//Create an entirely new repeater
    	if($rep_count === 0) {
    		$new_rep = array(
    			array(
    				'field_64e770e717754' => $item->details,
    				'field_64e770f317755' => $item->time
    			),
    		);
    		update_field( $repeater_key, $new_rep, $post_id );
    	} 
    	//Or keep previous values and add new rows
    	elseif($rep_count >= 1) {
    		$new_row = array(
    			'field_64e770e717754' => $item->details,
    			'field_64e770f317755' => $item->time
    		);
    		add_row($repeater_key, $new_row, $post_id);
    	}
    }
  • I have played with the ACF JS API and I’ve never been able to get it to work with sub fields when I need to detect a field changing or update sibling fields.

    Instead I have always had to add a change action by targeting the field using jquery and using doing it on my own

    
    
    // example event on change of sub field
    // this needs to be on on the document level because rows and be added
    // field_XXXXXX == sub field key to create action for
    $(document).on('change', '[data-key="field_XXXXXX"] .acf-input select', function(e) {
      // get the target of the change
      target = $(e.target);
      // get the row of the repeater
      row = target.closest('.acf-row');
      // get another field in the row
      other_field = row.find('[data-key="field_YYYYY"] input');
      // update value
      other_field.val('new value');
      // trigger change so that ACF knows it has been changed
      other_field.trigger('change');
    });
    
    
  • Yes, this has been discussed here many times.

    When there are many rows in a repeater (this includes flex fields because they are just a special kind of repeater) and or there are a lot of fields for each layout, performance of the admin will degrade as more rows are added. Eventually this will cause a timeout on the saving of edits.

    There are ways to improve initial page load, this can be done by setting fields like wysiwyg fields to not initialize until they are being edited.

    There is nothing that can be done in ACf to improve/speed up saving under these conditions. ACF calls update_post_meta() or other similar function for each field. This means that every field creates its own DB queries to update the value. Repeaters do not scale well.

  • @hube2
    Hi John, That’s really useful, wish i had found this sooner it would saved me a day or so.

    I’m really interested in your filtering is a sub field in repeater that is nested in another repeater that is then nested in a group field that is nested in another repeater.

    I am trying and failing to update my sub fields of nested repeaters.

    I have the following options page, basically i want to create business events (repeater 1)

    Field Group: group_6380cf9026f49
    Repeater (1): field_6380d01f71839 (these are events)
    Group(1): field_645e4a88f718e
    Group(2): field_645e3a33aa018
    Repeater (2): field_646205bfe80ff
    Group (3): field_6462172e85e75
    Select field: field_646206abe8102 (these are Tips)

    The select field is grabbing a field group name from a field in Group (2): field_645e628bf1588 which pulls all the field name values as choices from another field group.

    I’ve used your class code solution and it fetches the group name fine from Group (2): field_645e628bf1588, i can see it’s pulling back the field group values for Select field (field_646206abe8102)

    But the sub repeater that allows people to select the Tips per event aren’t the correct fields for the event when either adding new tips or editing previous tips. The very first tip in the first event is fine, then they are all out of sync to the row index or don’t show at all.

    I think i need another index counter for the sub rows, but i am not quite sure how best to achieve this. Would love to know more on how you handle this? especially as i’m going crazy now

    
    class MY_PROJECT_NAME_acf_filters 
    {
    
        // variable for row index
        private $my_field_name_index = 0;
    
        public function __construct()
        {
            // add a filter when preparing repeater for monitoring index count
            // Field: event -> field_6380d01f71839
            add_filter('acf/prepare_field/key=field_6380d01f71839', array($this, 'init_my_field_name_index'));
    
            // add filter for ths sub field that you want to filter
            // FIeld: tips field_646206abe8102
            add_filter('acf/prepare_field/name=field_646206abe8102', array($this, 'filter_my_sub_field_name'));
        }
    
        public function init_my_field_name_index($field)
        {
            $this->my_field_name_index = 0;
            return $field;
        }
    
        public function filter_my_sub_field_name($field)
        {
                // Get the index count
                $row_index = $this->my_field_name_index;
    
                //acf[field_6380d01f71839][row-2][field_645e4a88f718e][field_645e3a33aa018][field_646205bfe80ff][acfcloneindex][field_6462172e85e75]" (overview group)
               
    
                // Get Group Key Name from Group(2): field_645e3a33aa018  -> field_645e628bf1588 
                $getGroupKey = get_option('events_judging_event_' . $row_index . '_all_settings_judging_settings_judging_field_group');
    
                if ($getGroupKey) {
                    $field['choices'] = [];
    
                    // Get all fields for the group
                    $choices = acf_get_fields($getGroupKey);
    
                    if (is_array($choices)) {
                        // loop through array and add to field 'choices'
                        foreach ($choices as $choice) {
                            //Set the select values
                            if ($choice['type'] != 'message') {
                                $field['choices'][$choice['key']] = $choice['label']; 
                            }
                        }
                    }
                }
    
                // after filtering increment the field index
                $this->my_field_name_index++;
                return $field;
            } else {
                return $field;
            }
        
    }
    new MY_PROJECT_NAME_acf_filters ();
    
  • So your filter basically runs multiple times for each product post for each row of the import that matches that post.

    There is no way to do this in a single function call.

    You will need to track a list of every row that is imported and this list of data will need to be updated each time your filter is run.

    Do to the way that WPAI works, this information will need to be stored in a session variable because WPAI may or may not import every row in a single request and this is the only way to compile a list of everything during a single import.

    An alternative session to this would be two write all of the data out to a temporary file on the server and then load updated and re-save that file every time your filter runs, basically duplicating what a PHP session does.

    The data could be as simple as an array something like

    
    $data = array(
       $post_id => (
         // list of row indexes updated or added
       )
    );
    

    With this compiled list of data created you would then add a WPAI pmxi_after_xml_import action. This runs after the import is complete and then in this action you can look at your compiled list of rows that were imported and compare them to the rows for each post ID and then delete the missing ones. Basically to do this you would get the repeater for each post again and then look to see what rows should be kept and delete the rest.

    On top of this you also need to keep in mind that when deleting rows from an ACF repeater you must go in descending index order to make sure you delete the correct rows. For example let’s say that you need to delete rows 1 & 2. If you delete 1 first, then 2 becomes 1 and 3 becomes 2 and when you attempt to delete row 2 you’ll actually be deleting what was row 3.

    To make matters worse, none of this may work. This solution would not be scalable. Updating many products, hundreds or thousands, would likely cause a server timeout during the delete process unless certain precautions are taken. This would depend on your hosting environment and what your hosting company allows, like extending the amount of time the server is allowed to process and possibly preventing the browser from timing on the AJAX request. The latter may not even be possible.

    Overall this is several hours or more of R&D work and you’ll need to find a developer if you can’t do it. You might want to look into hiring a freelancer.

  • first thing is that I do not see a have_posts() loop in your code, but this will not matter.

    It is impossible using WP_Query() to list a post more than once. It is also impossible to order posts by a repeater sub field. So you’ve basically set an impossible task for yourself using only these things and it requires something much more complex.

    In order to show a post multiple times, well, basically you need multiple posts. If you look at the way others have done this you will find that they also have a second post type that is hidden from users. When an event is saved what happens is that a new post in the hidden post type is created for each of the dates entered when creating the event and each of these posts is related to the event post (parent). Then the archive page for events actually uses this post type to get all of the events listed in the correct order and pulls most of the data from the “parent” event.

    There are likely other ways to do this, but the method I’ve described is used by the most popular events plugin.

  • I have never seen the article that you linked, but I find it very interesting. I had not thought of the work-a-round suggested making bidirectional relationships work in repeaters. However, I do think it would be a little confusing for some.

    The idea is to, for example, you my plugin to create a bidirectional relationship field at the top level. For example a field named “related_events_people”. This relationship is added at the top level of both the events CPT and the people CTP. This filed will hole all of the relationships between these 2 CPTs. The main purpose of a bidirectional relationship field is to easily find the related posts from either site and this would accomplish this. However, in this case this field will not be editable and it’s value will only be updated dynamically.

    then the idea is that when an events post is saved you loop over the repeater and get the values from the relationship field in the repeater and you push the merged values from the repeater into the top level relationship field. Updating an ACF relationship field automatically triggers my plugin to update the top level relationship field on the the related posts.

    
    add_action('acf/save_post', 'repeater_bidirectional_update', 20);
    function repeater_bidirectional_update($post_id) {
      $update_field = 'field_XXXXXXX'; // field key of top level relationship field
      $collected_posts = array();
      if (have_rows('repeater_field_name', $post_id)) {
        while (have_rows('repeater_field_name', $post_id)) {
          the_row();
          // get the value of the relationship sub field
          // 2rd argument is false, do not format value
          // causes only post IDs to be returned
          $values = get_sub_field('relationship_field', false);
          if (!$empty($values)) {
            if (!is_array($value)) {
              // this check insures the value is an array
              // post object fields return a single value
              $values = array($values);
            }
            // loop over related posts and add them to collected posts
            foreach ($values as $value) {
              if (!in_array(intval($value), $collected_posts)) {
                // add if not added before
                $collected_posts[] = intval($value);
              } // end if
            } // end foreach value
          } // end if !empty
        } // end while have_rows
      } // end if have_rows
      
      // update the top level relationship field
      // with collected posts
      update_field($update_field, $collected_posts, $post_id);
      
    } // end function
    

    You’re obviously going to need to do more because you have a nested repeater, so you’ll need a nested loop and you’ll need to collect posts from 2 separate repeagter sub fields and update 2 top level relationship fields.

    The last step I would take, after I am sure everything is working would be to make the top level field not editable by removing it.

    
    // again, field key of top level field
    add_filter('acf/prepare_field/name=related_events_people', 'my_remove_field');
    function my_remove_field($field) {
      return false;
    }
    
  • I have only one experience that could potentially relate to this. In my case I was creating a custom events calendar for a client. The client wanted to have events that could have multiple dates, for example a class that happens every week.

    They also wanted the events to show multiple times in the “Upcoming Events” list, once for each date. This is not possible with a standard WP query as WP will only return a post once in each query.

    I had a couple of choices. The first was to make them create a new event for every date. The problems with this were that it would be a PITA to use and there would not be a consistent URL for the event. Having a single event page with a consistent UEL multiple dates would be better for SEO.

    The only logical way I could provide this was to use a repeater. The main issues here were going to be having them appear in lists multiple times and how I was going to sort them.

    What I ended up doing was using child posts.

    Each event post has a repeater that allows entering start and end dates. Each event post also has other fields of data related to the post.

    I used parent/child posts. When an event is saved a child post is created for each date entered into the repeater. To the child post I also copied other fields that would be needed for searching, filtering and ordering the events.

    In addition to the above I also added actions/filters for when an event was updated to check the existing child posts and compare the dates, deleting and adding child posts as needed. There are also filters/action that happen when an event is trashed, untrashed and deleted to apply those same actions to all the child posts.

    In the admin I used a pre_get_posts filter to hide all of the child posts, the client does not even know they exist.

    On the front end I used a pre_get_posts filter for archives to only query the child posts and not the parent posts. All child post URLs redirect to the single parent event post. All the links in the archive actually pointed to the parent post, not the child post.

    This was complicated, but the only way I could find to accomplish the needed end result.

    Your case is far more complicated, but it has the same idea. You want to be able to query and sort by start/end date. You need something that has only one start date and end date.

    Another alternative:

    Save the dates and the posts they are associated with into a lookup array as a WP option.

    The array I would set up would be something like

    
    $option_name = array(
      // an array of post id => array pairs, the array will hold dates
      {$post_id} = array(
        array(
          //each sub array holds a start date and end date
          'start_date' => 'value',
          'end_date' => 'value'
        ),
        array(
          //each sub array holds a start date and end date
          'start_date' => 'value',
          'end_date' => 'value'
        )
        // etc
      }
    )
    

    When I want to search I would load this option, loop over the array, find the entries that match the date I’m looking for and collect a list of post IDs then use this list of post IDs in the “post__in” argument of a WP_Query.

  • Hi John, thank you for your reply and for your suggestions. I had just written you an extensive reply and edited it because the images appeared as broken, and now it seems to have vanished, so I’m writing it again! 🙁

    I have changed the priority as advised, many thanks, however if I remove the extra depth in the nested repeaters, then my default Prices no longer appear. Instead, I get 19 Offers, all with empty Prices repeaters inside.

    If I start with my current code, including the extra array depth, then I get a sinlge Offer repeater, with it’s nested Prices repeater containing the desired 19 rows, all populated with the desired dates:

    Screen capture of the correct default values I'm getting inside the nested Prices repeater, which is inside the Offers repeater.

    This part works fine, so I understand that this part of the code is OK.

    My problem is that I want to be able to press the ADD (+) button on the parent Offers repeater, so that it adds a new row, when we will find that one of the contents of the row is the Prices repeater, which I was to appear populated by default with these same 19 rows and their contents.

    I’m guessing the only way to do this is going to be via jQuery, since I can’t alter the function of the ADD (+) button on the Offers repeater.

    Screen capture of the Alert I have managed to generate in jQuery, triggered by the correct Add Row Repeater button.

    I have managed to add a custom event to this exact button simply by locating it using jQuery and then I can make an Alert with an array of all the default values that I want to stick in the new Prices repeater, after it has added 19 rows to itself. I don’t even know if this is possible. I suspect it is, but very, very complicated. Any help is greatly appreciated!

  • if (!have_rows('event_dates'))
    should do the same thing.

    The function returns a truthy or falsey value.

    I your case it is likely returning an empty string because the repeater was never set to any value, but that is just a guess.

  • I’m also having this issue with the ACF field not being updated in the backend (without full page refresh) using update_field($field_key, $field_value, $post_id) during ‘acf/save_post.’

    
        public function register_hooks()
        {
            // add_action('acf/save_post', [$this, 'acf_save_post'], 5);
            add_action('acf/save_post', [$this, 'acf_save_post'], 20);
        }
        public function acf_save_post($post_id)
        {
            $post_type = get_post_type($post_id);
            switch ($post_type) {
                case 'event':
                    $this->acf_save_post_event($post_id);
            }
        }
        public function acf_save_post_event($post_id)
        {
            $field_key = 'field_6247dc975b487';
            $new_value = 'hello';
    
            if ($new_value) {
    
                //$_POST['acf'][$field_key] = $new_value;
                update_field($field_key, $new_value, $post_id);
    
            } else {
                //$_POST['acf'][$field_key] = '';
                delete_field($field_key, $post_id);
    
            }
        }
    

    I am using the field key rather than the field name. I attempted the methods under “Applied after save” and “Applied before save” at href=”https://www.advancedcustomfields.com/resources/acf-save_post/. This is top-level field, not under a group or repeater. It is a jQuery datepicker field, by I also attempted this with a plain text field, with the same results. The field updates properly in the database, but this isn’t reflected in the post edit screen until a full page refresh. The Gutenberg editor is active for the post type edit, so the page does not fully refresh on “Update.”

  • Thanks John, I was able to upgrade my code using an array eventually.

    function create_post_after_order( $order_id ) {
      if (  $order_id instanceof WC_Order ){
        return;
      }
    	
      $order = wc_get_order( $order_id );
      $order_items = $order->get_items(); 
    	
    	foreach ( $order_items as $item_id => $item_data ) {
        $product = $item_data->get_product();
    	$qty.= $item_data->get_quantity();
        $name.= $product->get_name();
      }
    	
    	$new_post = array(
        'post_title' => "Order {$order_id}",
        'post_content' => $content,
        'post_status' => 'private',
        'post_date' => date('Y-m-d H:i:s'),
        'post_author' => $user_ID,
        'post_type' => 'groeiproces',
        'post_status' => 'publish',
      );    
      $post_id = wp_insert_post($new_post);
    
    // repeater field with multiple subfields
    $class_field_key = 'field_61645b866cbd6';
    $class_subfield_name = 'field_61645b916cbd7';
    $class_subfield_colour = 'field_6165450699ffa';
    $class_names = array($name,$name);
    $class_colours = array($qty,$qty);
    
    foreach ($class_names as $index => $class_names) {
    	$class_value[] = array($class_subfield_name => $class_names, $class_subfield_colour => $class_colours[$index]);
    	update_field( $class_field_key, $class_value, $post_id );
    }
        
    }
    add_action( 'woocommerce_thankyou', 'create_post_after_order', 10, 1 );

    Right now the only problem is that this combines the values in one field. e.g.

    Name
    Product1Product2

    Quantity
    11

    Does anyone know how to split those values and save them separated. e.g.

    Product1 1
    Product2 1

    Thanks in advance!

Viewing 25 results - 26 through 50 (of 150 total)