Yea, that line in the docs is why I was trying to do it with add_row
in the first place. Although it wasn’t until I read the update_field
docs that I knew to use the "acf_fc_layout"
keys and finally got it working for one row. The more I looked at add_row source the more I thought it wouldn’t do what it said it did, but for some reason I didn’t ever try update_field
. Thanks for waking me up to it, it works like a charm. I’ll file a ticket to update the docs.
Sweet, I’ve got it figured out! update_field
was the trick.
Before I was looping through a bunch of rows and attempting to add them each individually with add_row
, but now I’m looping through and creating an array of fields and then add them all at once with update_field
. This works because I’m only doing this on new pages and therefore the flexible content field is always empty. I imagine that if there was any content in the FC at the time this was run then the existing content would be overridden. Here’s the updated code that’s working for reference and posterity:
function bagpress_sitemapper_new_page( $ID, $post, $update ) {
// set content and modules as set in sitemap/json
if ( $post->post_type !== 'page' ||
$post->post_status === 'auto-draft' ||
get_post_meta('modules') ) {
//if not a page or an autodarft or has already been updated or has any content in the modules already, don't update it. get out!
//use modules custom field as the flag since it will exist automatically in there are any modules. and in that case we don't want to add any more
return;
}
//read module json data from the content
$content = json_decode( get_post_field('post_content', $ID) );
//if not array/json end this
if ( !is_array($content) ) {
return;
}
//flexible content field key
$fc_key = 'field_55ce0e107c687';
$fc_rows = [];
//read json stored in content for this post and use it to add rows to the flexible content
foreach($content as $row){
switch($row->layout){
case 'billboard':
$row_i = array( 'acf_fc_layout'=>'billboard', 'field_55ce0ed27c68a'=>$row->headline);
break;
case 'callout':
$row_i = array( 'acf_fc_layout'=>'callout', 'field_564e22d0da4ef'=>$row->headline);
break;
case 'content':
$row_i = array( 'acf_fc_layout'=>'content', 'field_55ce0e6c7c688'=>$row->headline);
break;
case 'headline':
$row_i = array( 'acf_fc_layout'=>'headline', 'field_55df18296e4b3'=>$row->headline);
break;
case 'recent':
$row_i = array( 'acf_fc_layout'=>'recent', 'field_55e5d3f2b7ec7'=>$row->headline);
break;
case 'subheadline':
$row_i = array( 'acf_fc_layout'=>'subheadline', 'field_55df18be00e56'=>$row->headline);
break;
default:
//unknown layout type - skip
// $row_i = update_post_meta($ID, 'module_error', json_decode($row) );
}
array_push($fc_rows, $row_i);
}
update_field($fc_key, $fc_rows, $ID);
//turn off save_post hook so we can update the post without triggering it
remove_action('save_post', 'bagpress_sitemapper_new_page', 10, 3);
//remove json data from content
wp_update_post( array(
'ID' => $ID,
'post_content' => ''
));
//turn save_post hook back on
add_action( 'save_post', 'bagpress_sitemapper_new_page', 10, 3);
}
add_action( 'save_post', 'bagpress_sitemapper_new_page', 10, 3 );
If one wanted to use update_field
to update a field that already contained existing content, I don’t think it’d be too hard to first read that field and put the contents into an array and then add the new rows/layouts to the array and call update_field
sending in the new array.
Right, my thoughts exactly. Add row does create the FC properly if there isn’t anything saved in it yet, it lets you add one row, but trying a second the same way busts it.
I will try out update_field()
now and see what it can do. Thanks!
The new clone field solves this! Amazing work @elliot, as usual!
https://www.advancedcustomfields.com/resources/clone/
I’ve found potentially a better way to add menus to the network admin menu. Rather than just adding actions for both admin_menu and network_admin_menu, let’s add a conditional check in the acf admin_menu function so that we’re not adding pages to both menus.
after you’ve added the action on line 25 as stated above, thanks @snitchhomer.
update admin_menu function on /advanced-custom-fields-pro/pro/admin/options-page.php line 161
function admin_menu() {
// vars
$pages = acf_get_options_pages();
// create pages
if( !empty($pages) ) {
foreach( $pages as $page ) {
// vars
$slug = '';
if ( current_filter() === 'admin_menu' ) {
if( empty($page['parent_slug']) ) {
// add page
$slug = add_menu_page( $page['page_title'], $page['menu_title'], $page['capability'], $page['menu_slug'], array($this, 'html'), $page['icon_url'], $page['position'] );
} else {
// add page
$slug = add_submenu_page( $page['parent_slug'], $page['page_title'], $page['menu_title'], $page['capability'], $page['menu_slug'], array($this, 'html') );
}
} elseif ( current_filter() === 'network_admin_menu' ) {
if ( $page['parent_slug'] === 'network/' ) { //if parent_slug is 'network/'
//add network menu page - remove network from the parent_slug though
$slug = add_menu_page( $page['page_title'], $page['menu_title'], $page['capability'], $page['menu_slug'], array($this, 'html'), $page['icon_url'], $page['position'] );
} elseif ( substr( $page['parent_slug'], 0, 8 ) === 'network/' ) { //if parent_slug starts with 'network/'
// add page
$slug = add_submenu_page( substr( $page['parent_slug'], 8), $page['page_title'], $page['menu_title'], $page['capability'], $page['menu_slug'], array($this, 'html') );
}
}
// actions
add_action("load-{$slug}", array($this,'admin_load'));
}
}
}
This will check if the parent slug includes ‘network/’ so we can use the same idea of just specifying the parent slug and the plugin will properly place the menu in the right spot, since the network menu always starts with ‘network/’. If it’s exactly ‘network/’ then it creates a page, and if it starts with ‘network/’ it creates a sub page, and if it’s not one of this it doesn’t belong in the network menu anyways so it’s ignored. We’re also checking if the filter came from ‘admin_menu’ or ‘network_admin_menu’ and only firing off the corresponding add_menu calls in each case.
I haven’t done extensive testing, but so far it’s working great for me. @elliot, let me know if there’s a way to submit a patch or pull request. I’d be happy to contribute.
Yes, this makes sense. I’m able to find and target the flexible content area, but I’m not finding much success once I have that target to add more layouts or rows to that flexible content field.
It looks like I have to set the focus to that element and then the acf.fields.flexible_content object is updated and when I add elements it goes to the right place, but that doesn’t seem to be working 100%. I can set the focus with trigger.(‘focus’) or simply .focus() but it still doesn’t add them all the time. If there are multiple flexible content fields, I’m not sure how to set the acf focus to one vs the other via the script. It does seem to work however if I click the ‘add row’ button to focus on that flexible content field and then trigger my script. So I’m doing that for now, not ideal, but functional at least. Still saving quite a few clicks.
@James Thanks for the suggestions. I really am interested in doing this via javascript. I was wondering if there was any documentation about how to make it happen. I am in fact a developer and am looking for direction.
So far I have been able to add some but it’s spotty. I just call:
acf.fields.flexible_content.add('my_layout_name');
I’m having trouble finding a way to target certain flexible content fields over others.
This may be a solution to a similar problem, but I don’t think it will help my situation. I already have the fields all set up and working on a page. I’m just looking for a scripted way to add a group of fields rather than just adding one at a time.
Say I have a flexible content created with 10 different layout options. I could manually select each one in order on the page and fill in the fields and select images to include etc as usual. It’s just time consuming if I am going to be creating a lot of pages. I’d like an option to add a radio or select field and when it’s value is updated to add a predefined set of fields from my flexible content in a certain order.
+10 for having this functionality built in. I’ve been thinking of ways to do this for a while now. It’d be great to abstract out custom field groups and set them up for reuse later.
Many examples of this such as: a big select list that will need to be managed but used in multiple places on the site, complex groupings like for a button field where you need a text field paired with a page link or url and a select list of styles or colors…
I’ve tested out the https://github.com/mvpdesign/acf-reusable-field-group add-on field and am impressed thus far. Grabbing the data is a bit different in that it returns all the values in an array, but once I realized that it was easy to work with. But I think the interface in the back-end used here is the ideal way to do it. It keeps it all very simple.
Fixed my issues too. Thanks for the speedy fix!
Same here, I had some wysiwyg fields named ‘content’ that were not displaying. They were within a flexible content field, I had others that were named ‘content’ as well, and they were showing, in the same flexible content group. Rolled back to 5.1.0 and all is well again.
Awesome, that seems to have fixed it for me! Thanks
I’m seeing this as well:
Advanced Custom Fields: Options Page
You have version 1.2.0 installed. Update to 1.2.0. View version 1.2.0 details.
It only shows up sometimes. Like I’ll have a list of updates, run them, and then this one will show up afterwards, if I switch between the plugins page and the updates page sometimes it goes away for a bit, but seems to keep coming back. I’ve got it on a handful of different sites and a couple different hosts and seeing the same on all of them.
Happy to help debug if needed.
Yea, I guess that could work.
Feature request then: Would it be possible to create a new field type of a custom field group? Selecting this type would give you a select list of all the custom field groups and selecting one would pull it into this group (maybe not in this edit screen, but where the actual content is entered. Just an idea.
This is awesome! How have I never heard of this before. Thanks for sharing!
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.