I had a similar issue where i needed to add the ACF fields meta_id. Below is my solution to the same problem
function build_meta_key($field){
// Loop over parents.
$return_name = $field["_name"];
if(empty($field["prefix"])){
return $return_name;
}
$is_row = preg_match("/row-(\d)+/", $field["prefix"], $matches);
if(!$is_row){
return $return_name;
}
//now figure out the row number from the field name
$return_name = $matches[1]."_".$return_name;
while ( $field['parent'] && $field = acf_get_field( $field['parent'] ) ) {
if(isset($field["_name"])){
$return_name = $field["_name"]."_".$return_name;
}
}
return $return_name;
}
function get_all_meta_info_by_key($post_id, $meta_key, $meta_type = "post"){
global $wpdb;
if ( ! $meta_type || ! $post_id || trim($meta_key) == "") {
return false;
}
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$meta = $wpdb->get_row( $wpdb->prepare("SELECT * FROM {$table} WHERE post_id = %d AND meta_key = %s", $post_id, $meta_key) );
if ( empty( $meta ) ) {
return false;
}
if ( isset( $meta->meta_value ) ) {
$meta->meta_value = maybe_unserialize( $meta->meta_value );
}
return $meta;
}
/**
* Add in the ACF fields meta id to the field itself. so we can build the download links
* @param $field
*
* @return mixed
*/
function prepare_field( $field ) {
global $post;
$acf_meta_key = $this->build_meta_key($field);
$meta_information = $this->get_all_meta_info_by_key($post->ID, $acf_meta_key);
if(!empty($meta_information->meta_id)){
$field["post_meta_id"] = $meta_information->meta_id;
}
return $field;
}
Think i have found a way to achieve what i need.
I ended up using the pre_load_value filter. which if you hook into and return a value. is then skipped when the repeater field goes to load its value.
This way i can mimic the load_value function and the acf_get_value function just returns my value as opposed to the system value.
incase anyone ever needs this in the future here is the code i used.
add_filter('acf/pre_load_value', array($this, 'pre_load_value'), 3, 3);
function pre_load_value( $value, $post_id, $field ){
if($field['type'] != 'repeater'){
return $value;
}
if(!$this->search_sub_fields_for_type($field['sub_fields'], $this->name)){
return $value;
}
// Get field name.
$field_name = $field['name'];
// Check store.
$store = acf_get_store( 'values' );
if( $store->has( "$post_id:$field_name" ) ) {
return $store->get( "$post_id:$field_name" );
}
// Load value from database.
$value = acf_get_metadata( $post_id, $field_name );
// Use field's default_value if no meta was found.
if( $value === null && isset($field['default_value']) ) {
$value = $field['default_value'];
}
//User our own load_value filter to add additional information to subfields
$value = apply_filters( "ttc_repeater_load_value", $value, $post_id, $field );
// Update store.
$store->set( "$post_id:$field_name", $value );
// Return value.
return $value;
}
add_filter('ttc_repeater_load_value', array($this, 'try_add_grid_info'), 2, 3);
function try_add_grid_info($value, $post_id, $field){
// bail early if no sub fields
if( empty($field['sub_fields']) ) return $value;
// vars
$value = intval($value);
$rows = array();
$field["total_rows"] = $value;
// loop
for( $i = 0; $i < $value; $i++ ) {
// create empty array
$rows[ $i ] = array();
// loop through sub fields
foreach( array_keys($field['sub_fields']) as $j ) {
// get sub field
$sub_field = $field['sub_fields'][ $j ];
// bail ealry if no name (tab)
if( acf_is_empty($sub_field['name']) ) continue;
// update $sub_field name
$sub_field['name'] = "{$field['name']}_{$i}_{$sub_field['name']}";
$sub_field["original_order"] = $i;
$sub_field["latest_row"] = (($field["total_rows"]-1) == $i);
$sub_field["total_row_count"] = ($field["total_rows"]);
// get value
$sub_value = acf_get_value( $post_id, $sub_field );
// add value
$rows[ $i ][ $sub_field['key'] ] = $sub_value;
}
}
return $rows;
}
/** function to loop through sub fields and look for a particular sub field type.
* @param $sub_fields array of repeater sub fields
* @param $field_type - Field type we are looking for
* @return bool
*/
function search_sub_fields_for_type($sub_fields, $field_type){
if(!empty($sub_fields)){
foreach($sub_fields as $sub_field){
if(!empty($sub_field["type"]) && $sub_field["type"] == $field_type ){
return $sub_field;
}
}
}
return false;
}
Hi John,
Thanks for the response. What i need is to be able to add some variables to the sub field (specifically the repeater’s total rows and the sub field’s row count) before it is rendered.
I need the value passed the field before the sub field runs it’s load_value function. As I’m using these values to do a seperate DB query for additional information.
If i set the priority > 10 the sub field has already run through its load_value function and i would have to loop through everything a second time. Which will be fine if i only had a few rows. But i am anticipating over time there will be quite a few rows and i think this will impact in load times.
in a javascript file you can add this code to run when a row is added to the repeater field
(function( $ ) {
$(".acf-input .acf-repeater").on('click a[data-event="add-row"]', function(evt, el){
console.log(evt);
});
})( jQuery );
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 Cookie Policy. If you continue to use this site, you consent to our use of cookies.