Home › Forums › Backend Issues (wp-admin) › Update ACF fields in WordPress admin using Ajax
I have a problem that I’ve been trying to solve for some time now. It seems to me that the task is relevant for those who use ACF and want to substitute fields from one post to another. Somebody may be interested in helping solve this problem, or solved it before.
There are ACF fields that need to be updated programmatically – substitute fields from another record without reloading the page, i.e. using ajax in the admin.
What is done:
1.Connect ajax to admin – functions.php
add_action( 'admin_enqueue_scripts', function() {
wp_enqueue_script( 'ajax-acf', get_stylesheet_directory_uri() . '/ajax-acf.js', array( 'jquery' ), time(), true );
} );
2.Run jquery when input button is clicked (receive “ok” response) – i use button from ACF Extended plugin.
jQuery( function ( $ ) {
$ ('.acf-field-64647e4980e03').click( function(){
var input = $(this);
$.ajax({
type : 'POST',
url : ajaxurl,
data:{
action:'my_acf_update',
post_id: $_POST['post_id']
},
success : function( data ) {
alert( data );
}
})
} );
} );
The following hook does not work – only “ok0” is returned in the popup
add_action( 'wp_ajax_my_acf_update', function(){
// Get post id
$post_id = $_POST['post_id'];
// Get id another post from the relation field
$another_post_id = get_field('Blocks-FirstSlide-copyBlock', $post_id );
// Getting data
$source_fields = get_fields($another_post_id );
// Update fields in this post
foreach ($source_fields as $field_name => $field_value) {
update_field($field_name, $field_value, $post_id);
}
update_field( 'Blocks-FirstSlide-copyBlock', $another_post_id, $post_id );
echo 'ok';
wp_die;
});
Also a have hook that solves the problem but with a reboot (when i saving the post). In this case, the true/false field is also manages hook:
// Substitution of field values
add_action('acf/save_post', 'my_acf_save_post', 20);
function my_acf_save_post( $post_id ) {
// Checking if substitution is needed
$acf_value = get_field('Blocks-FirstSlide-update', $post_id);
if ($acf_value == true) {
// Get id another post from the relation field
$another_post_id = get_field('Blocks-FirstSlide-copyBlock', $post_id );
// Getting data
$source_fields = get_fields($another_post_id );
// Update fields in this post
foreach ($source_fields as $field_name => $field_value) {
update_field($field_name, $field_value, $post_id);
}
update_field( 'Blocks-FirstSlide-copyBlock', $another_post_id, $post_id );
}
Your AJAX function is updating the values in the database but this will not show these updated values without doing something more. You are expecting the live page to automatically be updated but that will never happen.
1) Refresh the page
2) Return all of the updated field values in the response and a JSON array (field key => value pairs) and they in your jQuery code for success:
update the values on the page using the ACF JS API
In fact, you should not be updated the database values at all, you should be requesting the values for the post and populating the fields and then letting ACF do the updating when the post is saved, it’s going to happen anyway a second time. The only think you’re accomplishing by updating it is slowing the response time down.
Thanks for your reply.
I understand that substituting values in the database and not in the fields, which is the wrong way, it is correct to use then save_post.
But then how to update the fields in the current record? It is necessary to write and add code to everything in the success section. I tried a couple of options but it didn’t work. Can you suggest what command should I use?
I try thic code, but its not working:
jQuery( function ( $ ) {
$ ('.acf-field-64647e4980e03').click( function(){
var input = $(this);
var post_id = $('#post_ID').val();
$.ajax({
type: 'POST',
url: ajaxurl,
data: {
action: 'copy_block_data',
post_id: post_id
},
success: function(response) {
if (response.success) {
acf.do_action('append', response.data);
} else {
alert(response.data);
}
},
error: function(xhr, status, error) {
console.log(error);
}
});
}
);
});
add_action('wp_ajax_copy_block_data', 'copy_block_data_callback');
function copy_block_data_callback() {
$post_id = get_field('Blocks-FirstSlide-copyBlock', $post_id );
if ($post) {
$acf_data = get_fields($post_id);
wp_send_json_success($acf_data);
} else {
wp_send_json_error('Not found');
}
}
… It is necessary to write and add code to everything in the success section?
Yes.
none of this has been tested
// changes to ajax function
$source_fields = get_field_objects($another_post_id);
$response = array();
foreach ($source_fields as $field) {
$response[$field['key']] = $field['value'];
}
echo json_encode($response);
exit;
// changes to success code
// basic example up updating a field
for (var key in json) {
var field = acf.getField(key);
field.val(json[key]);
}
As to your other question, if you are updating the field values on the active page using AJAX then there is no reason to have an acf/save_post action that duplicates the work done with AJAX. Instead of a button that needs to be clicked you would create an on chnage
event for the field containing the post ID that you want to get the values from so that the fields you want to update will be done automatically whenever they user alters their selection. If you keep the button approach then yes you will need to duplicate the work using acf/save_post since you will not know if the values have been updated already or not.
Thank you for reply. If i correct understand, i write this code in funtions.php
add_action( 'wp_ajax_my_acf_update2', function(){
// Get post id
$post_id = $_POST['post_id'];
// Get id another post from the relation field
$another_post_id = get_field('Blocks-FirstSlide-copyBlock', $post_id );
// Getting data
$source_fields = get_field_objects($another_post_id);
//Creating response
$response = array();
foreach ($source_fields as $field) {
$response[$field['key']] = $field['value'];
}
echo json_encode($response);
exit;
});
and this code in script:
jQuery( function ( $ ) {
$ ('.acf-field-64647e4980e03').click( function(){
var input = $(this);
var post_id = $('#post_ID').val();
$.ajax({
type : 'POST',
url : ajaxurl,
data:{
action:'my_acf_update2',
post_id: post_id
},
success: function(data) {
for (var key in json) {
var field = acf.getField(key);
field.val(json[key]);
}
}
});
} );
} );
Result:
Uncaught ReferenceError: json is not defined
at Object.success
About button you give good idea, i change trigger next time.
Can you help me with code above?
jQuery( function ( $ ) {
$ ('.acf-field-64647e4980e03').click( function(){
var input = $(this);
var post_id = $('#post_ID').val();
$.ajax({
type : 'POST',
dataType: 'json', // add this
url : ajaxurl,
data:{
action:'my_acf_update2',
post_id: post_id
},
success: function(json) { // change this
for (var key in json) {
var field = acf.getField(key);
field.val(json[key]);
}
}
});
} );
} );
Hello. My thanks for your help in finding a solution to the problem.
The code in this version did not work as expected, but if i change json to JSON, then the text fields change.
Unfortunately, the checkbox and image fields remain unchanged. What could be the problem?
Thanks again. For me, to achieve such a result is already a great progress. I’ve been trying to solve this problem for a week now.
Some fields take more coding to update. To be honest I’m not sure what you have to do.
this returns the field
var field = acf.getField(key);
the field type will be part what is returned. You’ll need to look at that and then do something different for more complex fields. Unfortunately, like I said, I don’t know what needs to be done for every field type.
It might help if you change you php to not format the values being returned
Change this
$source_fields = get_field_objects($another_post_id);
to this
$source_fields = get_field_objects($another_post_id, false);
Thank you for your help.
So far, the result is the same, but I believe you have indicated the direction in which I can move further in order to solve this problem.
In fact, I’m trying to update fields using template, which is another record (I specify it in the record object type field).
And I try to do this while editing.
I managed to achieve a partial solution – text fields change.
However, there is a problem with other field types, it may make sense to specify field types.
Also in the process, I found that in case of a field change – specifying another template record (the record object field) – the current fields are updated based on the record previously stored in this field.
You must be logged in to reply to this topic.
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.