Home › Forums › Add-ons › Repeater Field › Using acf_form() to store/fetch a multidimensional array meta_key
Hi there,
We’re using the acf_form() function to update a custom post type on the front-end. So far, the plugin has been working absolutely brilliantly; we are just getting stuck on one issue: we would like to update/edit values that are stored as a multidimensional array in a pre-existing _postmeta meta_key field via an ACF repeater field.
I realise that this post might be a bit esoteric and a tad bit complicated, so I’ve done my best to outline things in the most detailed way that I can.
I’ve thrown a ton of hours at this and would appreciate any insights, so thanks in advance to anyone who might be able to help.
Here’s what we have:
1) The value stored in my field _my_array_field (this is the default format when the Custom Post Type is edited within WP):
a:1:{i:0;a:5:{s:4:"type";s:5:"type2";s:8:"yesno";s:3:"yes";s:8:"priority";i:10;s:4:"nummin";s:1:"2";s:2:"nummax";s:1:"3";}}
2) I’ve figured out that the array (echoed as a variable) that would cause this output is:
<?php
$array = array(
array(
array(
"type" => "type1",
"yesno" => "yes",
"priority" => "10",
"nummin" => "1",
"nummax" => "2",
),
array(
"type" => "type2",
"yesno" => "no",
"priority" => "2",
"nummin" => "333",
"nummax" => "444",
),
array(
"type" => "type3",
"yesno" => "no",
"priority" => "1",
"nummin" => "444",
"nummax" => "555",
),
),
);
?>
3) In ACF, we have a repeater field for ‘_my_array_field’ and it’s ID is ‘_my_array_field.’ For the child fields, we have the nested array labels accordingly: ‘type,’ ‘yesno,’ ‘priority,’ ‘nummin,’ ‘nummax’.
When we display the value of the acf field via the get_field() function, we are able to replicate the multi-dimensional array exactly.
4) We have a page template rendering our ACF form using
<?php
$options = array(
'post_id' => $post_id,
'post_title' => true,
'field_groups' => array(
123
),
'updated_message' => __("Post updated", 'acf'),
'submit_value' => 'Update'
);
?>
5) When we update the Custom Post Type from our front-end ACF form, this happens:
a) The ‘_my_array_field’ is empty in the _postmeta table for the CPT in questions
b) Rows have been created for each ‘child’ field in the repeater such as:
meta_key | meta_value
_my_array_field_1_type | type1
__my_array_field_1_type | field_randostuff1
_my_array_field_1_yesno | yes
__my_array_field_1_yesno | field_randostuff2
_my_array_field_1_priority | 1
__my_array_field_1_priority | field_randostuff3
_my_array_field_1_nummin | 123
__my_array_field_1_nummin | field_randostuff4
_my_array_field_1_nummax | 456
__my_array_field_1_nummax | field_randostuff5
_my_array_field_2_type | type1
__my_array_field_2_type | field_randostuff6
_my_array_field_2_yesno | yes
__my_array_field_2_yesno | field_randostuff7
_my_array_field_2_priority | 1
__my_array_field_2_priority | field_randostuff8
_my_array_field_2_nummin | 123
__my_array_field_2_nummin | field_randostuff9
_my_array_field_2_nummax | 456
__my_array_field_2_nummax | field_randostuff10
…etc, etc
6) When we edit the multi-dimensional array field ‘_my_array_field’ from within WordPress, the ACF repeater field renders ‘row,’ but the values don’t seem to be passing through
So, now my question(s), how can we store/fetch the repeater values using the acf_form() function so that
1) when posting on the front-end, the ACF repeater field value gets stored as a multidimensional array into a pre-existing meta_key > meta_value?
2) how an ACF repeater field can render/parse values from a pre-existing multidimensional array meta_key > meta_value on the front-end?
Is there some kind of a hook / function that will allow us to store the values created through something like ‘foreach’ for our repeater field? How might this be accomplished?
Many thanks in advance!
Ryan
Repeaters do not store values as a multidimensional array. If you must have the field that holds a multidimensional array and this field already exists then you’re going to need to have two ways of storing the data.
The first thing that you’re going to need to do is create an acf/load_value filter http://www.advancedcustomfields.com/resources/acfload_value/ for the repeater. The array is already formatting the way it needs to be, you just need to use the value from the other field.
add_filter('acf/load_value/name=my_repeater_field',
'load_my_repeater_field_value', 10, 3);
function load_my_repeater_field_value($value, $post_id, $field) {
$load_value = maybe_unserialize(get_post_meta($post_id, 'the_original_field', true));
return $load_value;
}
The second thing you’re going to need to do is create an acf/save_post filter http://www.advancedcustomfields.com/resources/acf_save_post/ for the repeater that puts the new value back into your original field. This filter needs to run after ACF has updated the field value.
add_filter('acf/save_post', 'update_my_repeater_field_value', 20);
function update_my_repeater_field_value($post_id) {
// check the post type
// you don't want to do this on every post type
if (get_post_type($post_id) != 'my_post_type') {
return;
}
$value = get_field('my_repeater_field', $post_id);
update_post_meta($post_id, 'the_original_field', $value);
}
Hi John,
Thanks for the response!
I’ve been fiddling with the code that you sent. The good news is with your code, I’m able to get empty rows to show in the repeater field. The not-so-good news is I’m still not able to pre-populate the form rows with values on the front end, nor post the values to the correct pre-existing field.
I’ve noticed that the pre-existing field (‘availability’ field, we’re using WooCommerce Bookings) is wrapping the item in an extra array, such as:
Array ( [0] => Array ( [0] => Array ( [type] => custom [bookable] => yes [priority] => 10 [from] => 2016-02-02 [to] => 2016-02-03 ) [1] => Array ( [type] => custom [bookable] => no [priority] => 10 [from] => 2016-02-10 [to] => 2016-02-12 ) [2] => Array ( [type] => custom [bookable] => no [priority] => 10 [from] => 2016-02-04 [to] => 2016-02-20 ) ) )
…whereas, the array output from ACF using your code is:
Array ( [0] => Array ( [type] => custom [bookable] => yes [priority] => 10 [from] => 2016-02-02 [to] => 2016-02-03 ) [1] => Array ( [type] => custom [bookable] => no [priority] => 10 [from] => 2016-02-10 [to] => 2016-02-12 ) [2] => Array ( [type] => custom [bookable] => no [priority] => 10 [from] => 2016-02-04 [to] => 2016-02-20 ) )
The code I’m using so far:
<?php
/**
* The template for displaying full width pages.
*
* Template Name: ACF Front End Repeater Form
*
* @package storefront
*/
?>
<?php $post_id = 55; ?>
<?php acf_form_head(); ?>
<?php get_header(); ?>
<div id="primary" class="content-area">
<main id="main" class="site-main" role="main">
<?php
add_filter('acf/load_value/name=my_repeater_field','load_my_repeater_field_value', 10, 3);
function load_my_repeater_field_value($value, $post_id, $field) {
/*
--> adding the array() around get_post_meta() makes this output array match the default one (see line 57 below please), but it does not render form rows
$load_value = maybe_unserialize(get_post_meta($post_id, '_wc_booking_availability', true));
*/
$load_value = maybe_unserialize(get_post_meta($post_id, '_wc_booking_availability', true));
return $load_value;
/*
--> tried this, but it added extra empty rows somehow
return call_user_func_array('array_merge', $load_value);
*/
};
?>
<?php
$options = array(
'post_id' => $post_id,
'post_title' => true,
'field_groups' => array(
18,
),
'submit_value' => __("Update", 'acf'),
'updated_message' => __("Post updated", 'acf'),
'uploader' => 'wp'
);
?>
<?php acf_form($options); ?>
<?php
add_filter('acf/save_post', 'update_my_repeater_field_value', 20);
function update_my_repeater_field_value($post_id) {
// check the post type
// you don't want to do this on every post type
if (get_post_type($post_id) != 'product') {
return;
}
$value = get_field('my_repeater_field', $post_id);
update_post_meta($post_id, '_wc_booking_availability', $value);
} // when i submit the field, the ACF array (output below) deletes all the values
?>
<?php
// Printing both the pre-existing field and the ACF field arrays for debugging/testing
// ACF
$acf_repeater_array = get_field( "my_repeater_field", $post_id);
echo 'ACF repeater field array:<br><br>';
if( empty( $acf_repeater_array ) ){
echo '<strong>Empty</strong><br><br>';
} else {
print_r(array_values($acf_repeater_array)); // this doesn't match the array for the pre-existing field unless i wrap get_post_meta() in an array() on line 25
echo '<br><br><hr>';
};
// Pre-existing field
$pre_existing_array = get_post_meta( $post_id, '_wc_booking_availability' );
echo 'Pre-existing field array:<br><br>';
if( empty( $pre_existing_array ) ){
echo '<strong>Empty</strong><br><br>';
} else {
print_r(array_values($pre_existing_array));
echo '<br><br><hr>';
echo 'Pre-existing field array (when I \'flatten\' the pre-existing array):<br><br>';
$flat = call_user_func_array('array_merge', $pre_existing_array);
print_r(array_values($flat)); // this DOES match the array for the pre-existing field
echo '<br><br><hr>';
};
?>
</main><!-- #main -->
</div><!-- #primary -->
<?php get_footer(); ?>
I’m at the point where I don’t know if I’m making progress or just getting more lost, so huge, huge thanks in advance for any insights!
The first thing you’re going to want to do is take the filters out of your template and put them in your functions.php file.
With the additional information about the fields and arrays I think the following should make it work.
<?php
add_filter('acf/load_value/name=my_repeater_field','load_my_repeater_field_value', 10, 3);
function load_my_repeater_field_value($value, $post_id, $field) {
$load_value = maybe_unserialize(get_post_meta($post_id, '_wc_booking_availability', true));
if (is_array($load_value)) {
// this will remove the extra array wrapper
$load_value = $load_value[0];
}
if (is_array($load_value)) {
// this is seperate
// just in case the above does not return a nested array
// you need to format some of the values differently for acf
// acf stores dates without the -
foreach ($load_value as $index => $row) {
$load_value[$index]['from'] = str_replace('-', '', $load_value[$index]['from']);
$load_value[$index]['to'] = str_replace('-', '', $load_value[$index]['to']);
}
}
return $load_value;
};
add_filter('acf/save_post', 'update_my_repeater_field_value', 20);
function update_my_repeater_field_value($post_id) {
// check the post type
// you don't want to do this on every post type
if (get_post_type($post_id) != 'product') {
return;
}
$value = array(get_field('my_repeater_field', $post_id));
update_post_meta($post_id, '_wc_booking_availability', $value);
}
?>
Hi John,
Thanks for the super-quick response. I’ve removed those filters from the page template and placed the code that you’ve provided in my functions.php.
This however, triggered some errors:
Warning: Illegal string offset 'from' in ~/wp-content/themes/storefront/functions.php on line 32
Warning: Illegal string offset 'from' in ~/wp-content/themes/storefront/functions.php on line 32
Warning: Illegal string offset 'to' in ~/wp-content/themes/storefront/functions.php on line 33
Warning: Illegal string offset 'to' in ~/wp-content/themes/storefront/functions.php on line 33
Warning: Illegal string offset 'from' in ~/wp-content/themes/storefront/functions.php on line 32
Warning: Illegal string offset 'from' in ~/wp-content/themes/storefront/functions.php on line 32
Warning: Illegal string offset 'to' in ~/wp-content/themes/storefront/functions.php on line 33
Warning: Illegal string offset 'to' in ~/wp-content/themes/storefront/functions.php on line 33
Warning: Cannot use a scalar value as an array in ~/wp-content/themes/storefront/functions.php on line 32
Warning: Cannot use a scalar value as an array in ~/wp-content/themes/storefront/functions.php on line 33
Warning: Illegal string offset 'from' in ~/wp-content/themes/storefront/functions.php on line 32
Warning: Illegal string offset 'from' in ~/wp-content/themes/storefront/functions.php on line 32
Warning: Illegal string offset 'to' in ~/wp-content/themes/storefront/functions.php on line 33
Warning: Illegal string offset 'to' in ~/wp-content/themes/storefront/functions.php on line 33
Warning: Illegal string offset 'from' in ~/wp-content/themes/storefront/functions.php on line 32
Warning: Illegal string offset 'from' in ~/wp-content/themes/storefront/functions.php on line 32
Warning: Illegal string offset 'to' in ~/wp-content/themes/storefront/functions.php on line 33
Warning: Illegal string offset 'to' in ~/wp-content/themes/storefront/functions.php on line 33
I’m going to start investigating these myself, but thought I’d send you this along already if you know why this is happening.
Thanks in advance!
Hi again,
I created a ‘clean’ post to re-test this and am posting what i found in hopes that it helps a bit. I found that the array being output from ACF is:
Array ( [0] => Array ( [type] => custom [bookable] => yes [priority] => 10 [from] => 20160223 [to] => 20160216 ) )
the value from the pre-existing field straight from WordPress is
Array ( [0] => Array ( [0] => Array ( [type] => custom [bookable] => yes [priority] => 10 [from] => 2016-02-23 [to] => 2016-02-16 ) ) )
Thanks again!
The only thing that I can think of is that the original field may not have a value at some point that that’s messing it up. I added some more error checking to the first array.
If this this doesn’t help then you’ll need to start dumping some values to the screen at each point to see what’s going on.
<?php
add_filter('acf/load_value/name=my_repeater_field','load_my_repeater_field_value', 10, 3);
function load_my_repeater_field_value($value, $post_id, $field) {
$load_value = maybe_unserialize(get_post_meta($post_id, '_wc_booking_availability', true));
if (!is_array($load_value)) {
return $value;
}
if (is_array($load_value)) {
// this is seperate
// just in case the above does not return a nested array
// you need to format some of the values differently for acf
// acf stores dates without the -
foreach ($load_value as $index => $row) {
if (count($row)) {
$load_value[$index]['from'] = str_replace('-', '', $load_value[$index]['from']);
$load_value[$index]['to'] = str_replace('-', '', $load_value[$index]['to']);
} // end if count row
} // end foreach row
} // end if is array
return $load_value;
};
add_filter('acf/save_post', 'update_my_repeater_field_value', 20);
function update_my_repeater_field_value($post_id) {
// check the post type
// you don't want to do this on every post type
if (get_post_type($post_id) != 'product') {
return;
}
$value = array(get_field('my_repeater_field', $post_id));
update_post_meta($post_id, '_wc_booking_availability', $value);
}
?>
Hi John,
Thanks again for another response!
I’ve implemented the code that you sent and see that:
1) the ACF form is still loading the row, but the values are empty
2) when i click the ‘update button on the ACF form, I get the following error
Warning: Cannot modify header information - headers already sent by (output started at ~/wp-content/themes/storefront/template-acf.php:12) in ~/wp-includes/pluggable.php on line 1228
In my page template, I’ve the following code to see what’s going on with the arrays:
<?php
// Printing both the pre-existing field and the ACF field arrays for debugging/testing
// ACF
echo 'ACF repeater field array from load value filter:<br><br>';
if( empty( $load_value ) ){
echo '<strong>Empty</strong><br><br>';
} else {
print_r(array_values($load_value)); // this doesn't match the array for the pre-existing field unless i wrap get_post_meta() in an array() on line 25
echo '<br><br><hr>';
};
// ACF
$acf_repeater_array = get_field( "my_repeater_field", $post_id);
echo 'ACF repeater field array:<br><br>';
if( empty( $acf_repeater_array ) ){
echo '<strong>Empty</strong><br><br>';
} else {
print_r(array_values($acf_repeater_array)); // this doesn't match the array for the pre-existing field unless i wrap get_post_meta() in an array() on line 25
echo '<br><br><hr>';
};
// Pre-existing field
$pre_existing_array = get_post_meta( $post_id, '_wc_booking_availability' );
echo 'Pre-existing field array:<br><br>';
if( empty( $pre_existing_array ) ){
echo '<strong>Empty</strong><br><br>';
} else {
print_r(array_values($pre_existing_array));
};
?>
ACF repeater field array from load value filter:
Empty
ACF repeater field array:
Array ( [0] => Array ( [type] => custom [bookable] => yes [priority] => 10 [from] => 20160211 [to] => 20160219 ) )
Pre-existing field array:
Array ( [0] => Array ( [0] => Array ( [type] => custom [bookable] => yes [priority] => 10 [from] => 2016-02-11 [to] => 2016-02-19 ) ) )
In case this helps, the value pasted directly from phpMyadmin for the pre-existing array field (_wc_booking_availability) is:
a:1:{i:0;a:5:{s:4:"type";s:6:"custom";s:8:"bookable";s:3:"yes";s:8:"priority";i:10;s:4:"from";s:10:"2016-02-11";s:2:"to";s:10:"2016-02-19";}}
I really appreciate your effort and time with helping me on this, so thanks again in advance!
looking it over I missed something in the last code I posted
add_filter('acf/load_value/name=test_repeater','load_my_repeater_field_value', 10, 3);
function load_my_repeater_field_value($value, $post_id, $field) {
$load_value = maybe_unserialize(get_post_meta($post_id, 'inserted_into_repeater', true));
if (!is_array($load_value)) {
return $value;
}
if (is_array($load_value)) {
$load_value = $load_value[0];
foreach ($load_value as $index => $row) {
if (count($row)) {
$load_value[$index]['from'] = str_replace('-', '', $load_value[$index]['from']);
$load_value[$index]['to'] = str_replace('-', '', $load_value[$index]['to']);
} // end if count row
} // end foreach row
} // end if is array
return $load_value;
};
add_filter('acf/save_post', 'update_my_repeater_field_value', 20);
function update_my_repeater_field_value($post_id) {
// check the post type
// you don't want to do this on every post type
if (get_post_type($post_id) != 'product') {
return;
}
$value = get_field('my_repeater_field', $post_id);
if (is_array($value)) {
foreach ($value as $index => $row) {
if (count($row)) {
$value[$index]['from'] = date('Y-m-d', strtotime($value[$index]['from']));
$value[$index]['to'] = date('Y-m-d', strtotime($value[$index]['to']));
} // end if count row
} // end foreach row
}
$value = array($value);
update_post_meta($post_id, '_wc_booking_availability', $value);
}
Hey John,
Thanks again for another response!
I’ve implemented the code and have found the following:
1) when I create a new, clean product, with no value in the field where the multidimensional array is stored, I see the five rows in my form and the following error output:
Notice: Undefined offset: 0 in /Applications/MAMP/htdocs/acf/wp-content/themes/storefront/functions.php on line 26
Warning: Invalid argument supplied for foreach() in /Applications/MAMP/htdocs/acf/wp-content/themes/storefront/functions.php on line 27
2) when i do create a field (via WooCommerce’s Booking plugin…the ‘_wc_booking_availability’ field, on the front-end ACF form, I see
Warning: Illegal string offset 'from' in /Applications/MAMP/htdocs/acf/wp-content/themes/storefront/functions.php on line 29
Warning: Illegal string offset 'from' in /Applications/MAMP/htdocs/acf/wp-content/themes/storefront/functions.php on line 29
Warning: Illegal string offset 'to' in /Applications/MAMP/htdocs/acf/wp-content/themes/storefront/functions.php on line 30
Warning: Illegal string offset 'to' in /Applications/MAMP/htdocs/acf/wp-content/themes/storefront/functions.php on line 30
Warning: Illegal string offset 'from' in /Applications/MAMP/htdocs/acf/wp-content/themes/storefront/functions.php on line 29
Warning: Illegal string offset 'from' in /Applications/MAMP/htdocs/acf/wp-content/themes/storefront/functions.php on line 29
Warning: Illegal string offset 'to' in /Applications/MAMP/htdocs/acf/wp-content/themes/storefront/functions.php on line 30
Warning: Illegal string offset 'to' in /Applications/MAMP/htdocs/acf/wp-content/themes/storefront/functions.php on line 30
Warning: Cannot use a scalar value as an array in /Applications/MAMP/htdocs/acf/wp-content/themes/storefront/functions.php on line 29
Warning: Cannot use a scalar value as an array in /Applications/MAMP/htdocs/acf/wp-content/themes/storefront/functions.php on line 30
Warning: Illegal string offset 'from' in /Applications/MAMP/htdocs/acf/wp-content/themes/storefront/functions.php on line 29
Warning: Illegal string offset 'from' in /Applications/MAMP/htdocs/acf/wp-content/themes/storefront/functions.php on line 29
Warning: Illegal string offset 'to' in /Applications/MAMP/htdocs/acf/wp-content/themes/storefront/functions.php on line 30
Warning: Illegal string offset 'to' in /Applications/MAMP/htdocs/acf/wp-content/themes/storefront/functions.php on line 30
Warning: Illegal string offset 'from' in /Applications/MAMP/htdocs/acf/wp-content/themes/storefront/functions.php on line 29
Warning: Illegal string offset 'from' in /Applications/MAMP/htdocs/acf/wp-content/themes/storefront/functions.php on line 29
Warning: Illegal string offset 'to' in /Applications/MAMP/htdocs/acf/wp-content/themes/storefront/functions.php on line 30
Warning: Illegal string offset 'to' in /Applications/MAMP/htdocs/acf/wp-content/themes/storefront/functions.php on line 30
I really do appreciate your time in helping me with this so thanks again in advance. I don’t want to violate any kind of policy of ACF’s forum by soliciting services or whatnot, but would it be possible for me just to hire you to knock this out? I have the ability to create an environment and furnish access quickly.
Thanks again!
The topic ‘Using acf_form() to store/fetch a multidimensional array meta_key’ is closed to new replies.
Welcome to the Advanced Custom Fields community forum.
Browse through ideas, snippets of code, questions and answers between fellow ACF users
Helping others is a great way to earn karma, gain badges and help ACF development!
We use cookies to offer you a better browsing experience, analyze site traffic and personalize content. Read about how we use cookies and how you can control them in our Privacy Policy. If you continue to use this site, you consent to our use of cookies.