[ad_1]
Hello,
Thanks for the feedback!
The problem come from the usage of WP_Query inside the acf/load_field hook, which is executed everywhere, including in the WP Admin panel and thus in the ACFE Form UI.
There is a 11 years old bug which prevent WP_Query & wp_reset_postdata() to work correctly in the WP Admin panel.
See the related core trac ticket #18408. The current developer motto is to not use them in the admin panel.
From the ticket discussion:
The root issue is that
wp_reset_postdata()is designed to reset globals to match the main query. But in the case ofpost.php, there is no main query – the$postglobal is populated manually, usingget_post(), rather than through the normal$wp_queryloop.
The preferred method is to use get_posts() instead, which doesn’t override the global $post object.
Here are some solutions in order to fix your code:
Solution 1: Use get_posts()
This is the most safe method. It is also faster than the WP_Query. Usage example:
add_filter('acf/load_field/name=associated_account', 'acf_load_associated_account_field_choices');
function acf_load_associated_account_field_choices($field){
// reset choices
$field['choices'] = array();
// query accounts
$accounts = get_posts(array(
'posts_per_page' => -1,
'post_type' => 'accounts',
'fields' => 'ids' // return post ids only
));
foreach($accounts as $post_id){
// get values
$value = get_post_field('post_name', $post_id);
$label = get_post_field('account_name', $post_id);
// append to choices
$field['choices'][ $value ] = $label;
}
// return
return $field;
}Solution 2: Clone the global $post and re-assign it
If you really want to keep using WP_Query, then you can clone the global $post and re-assign it once you finished using it. Usage example:
add_filter('acf/load_field/name=associated_account', 'acf_load_associated_account_field_choices');
function acf_load_associated_account_field_choices($field){
// get global post
global $post;
// clone original post
$_post = $post;
// reset choices
$field['choices'] = array();
// query accounts
$my_query = new WP_Query(array(
'posts_per_page' => -1,
'post_type' => 'accounts'
));
if($my_query->have_posts()){
while($my_query->have_posts()){
$my_query->the_post();
// get values
$value = get_post_field('post_name', get_the_ID());
$label = get_post_field('account_name', get_the_ID());
// append to choices
$field['choices'][ $value ] = $label;
}
wp_reset_postdata();
}
// re-assign global post back to default
$post = $_post;
// return
return $field;
}
A note on the usage of acf/load_field
I would not recommend to use the acf/load_field hook in order to populate field choices, unless you have some work to do with Ajax Queries.
In fact, as explained earlier, this is hook is executed everywhere, on every page load. Which means that your query will slow down your website and your admin panel since it will retrieve all posts from the accounts post type.
Also, you’ll see that the dynmically populated choices will appear in the ACF Field Group UI, when you edit the associated_account field. Those choices will be also exported in the Json/PHP if you export your Field Group with the ACF tools. This is really not optimized.
Instead, I would recommend to use the acf/prepare_field, which works the exact same way but is only executed on the Post Edit screen when the field is actually printed on the page.
So here is my final optimized solution of your code:
add_filter('acf/prepare_field/name=associated_account', 'acf_prepare_associated_account_field_choices');
function acf_prepare_associated_account_field_choices($field){
// reset choices
$field['choices'] = array();
// get accounts
$accounts = get_posts(array(
'posts_per_page' => -1,
'post_type' => 'accounts',
'fields' => 'ids' // return post ids only
));
foreach($accounts as $post_id){
// get values
$value = get_post_field('post_name', $post_id);
$label = get_post_field('account_name', $post_id);
// append to choices
$field['choices'][ $value ] = $label;
}
// return
return $field;
}
Hope it helps!
Have a nice day!
Regards.
