Background: I’m using the classic editor and have disabled Gutenberg blocks and global styles.
I’ve created a custom post type named Resources, for which I’ve also created an archive archive-resources.php
.
I’ve created a Taxonomy Custom Field labeled Resource Type (name: res_type), which is linked to Resources and has a Radio Button appearance.
I’ve created a Taxonomy for my custom post type and custom field labeled Materials (the three options for materials are “Book,” “Course,” and “eBook”).
In my archive file, I’ve started the loop (if “…”, etc.), and in the loop, I am trying to display which Material was selected from the Taxonomy Custom Field in the Resource that was created.
Initially, I was trying to use the following code:
$res_type = get_field('res_type');
if ($res_type) {
echo '<h4 class="open-sans-lite resource-subtitle smaller-text">'.esc_html($res_type).'</h4>';
}
This code doesn’t work because if my Taxonomy Custom Field “Return Value” is set to ID, it only returns a number, and if it’s set to Object, it returns an error (please see images attached).
Instead, I tried this code:
$res_type = get_field('res_type');
if ($res_type) {
echo '<h4 class="open-sans-lite resource-subtitle smaller-text">'.esc_html($res_type->name).'</h4>';
}
However, this resulted in nothing at all in my HTML, not even an empty H4 element.
I’ve also been trying get_field_object()
to no avail.
Please help me understand how to retrieve the “Book,” “eBook,” or “Course” taxonomy that’s selected for their respective Resource when I target the Taxonomy Custom Field in the loop.
So question. I have a ACF Field Group that I am using a repeater in as an accordion for an FAQ section. Each item has a header (text), sub header (text) and content section (WYSIWYG Editor). In the ACF editor for the ‘header – presentation’, I added a new class ‘smaller-h5’, and added it to the ‘Wrapper Attributes’ section… which all seems to work fine. See the two screenshots.
Issue is, the class doesn’t seem to be appearing on the page ‘header’ section.
<h5 class=”acf-element acf-element-heading [it should appear here]”>XXXX</h5>
I did republish the page after I made the ACF changes, so upon the republish it should have grabbed the latest ACF changes… but it didn’t seem to. Cache is not an issue either.
Is there something I have to do to publish ACF field group data? I am fairly new to ACF! Thanks for the info!
Hi there,
Yesterday, trying to change my permalinks using taxonomies, things went sideways quickly! I learned a tough lesson: I can’t just change the URL slug of a CPT nor can I change the Taxonomy Key. I did both 🙁
So now all my CPT archive pages and posts went 404 but the CPT posts (except for one CPT) are still there!!! That’s months of work I’m seeing in trouble and I’m super scared now that I do something to make it worse
I’m a simple website developer, already proud that I even got this far.
The website I’m working on is in staging. Another lesson learned, the usual backup doesn’t apply to the staging website so I lost all posts in this one CPT.
I assume they are lost forever, but I am desperate to know how I can protect my posts besides the usual backup.
Can I export the CPT posts and save them somewhere for them to import again in case a taxonomy breaks for whatever reason? Just to prevent days of work being lost :'(
Also, any advice on how to back up a staging website?
If anyone could help this damsel in stress, I would be very grateful.
Thanks ina advance,
Femke
I’m attempting to use the Block Binding API with WP 6.7 and ACF Pro 6.3.12.
I have CPT, Case Study, with an ACF text field, the_challenge. I want that fields value to be the content of a paragraph block on the case study card inside the query loop block.
<!-- wp:paragraph {"align":"center","metadata":{"bindings":{"content":{"source":"acf/field","args":{"key":"the_challenge"}}}},"fontSize":"label-small"} -->
<p class="has-text-align-center has-label-small-font-size">This will display the challenge on the front end.</p>
<!-- /wp:paragraph -->
The above looks very promising in the editor. (See screenshot)
But in the front end, no content is rendered, just and empty paragraph tag.
I’m a little stuck on how to proceed with debugging from this point. I’ve tried other fields. I’ve tried in the single content rather than inside a query loop.
Get top-quality laundry & dry-cleaning services with Upsoak. Enjoy fresh clothes, quick delivery, and eco-friendly cleaning services right to your door today.
Hi,
I’m working on my personal portfolio site, and for the individual project pages I want to be able to create a flexible number of galleries in a repeater, that I can then add one by one to the page with help of Gutenberg blocks.
I have the fields added and the block all set up, but for some reason I can just not manage to get the galleries.
This is what I have so far, based on an old example found on the forum:
<!-- CHECK OUT REPEATER "project_galleries" -->
<?php if( have_rows('project_galleries') ): ?>
<!-- CHECK TO SEE IF IT HAS ROWS IN IT -->
<?php while ( have_rows('project_galleries') ) : the_row(); ?>
<!-- DISPLAY THE TEXT-FIELD THEN ASSIGN OUR GALLERY TO VARIABLE $images -->
<?php
$images = get_sub_field('project_gallery');
if( $images ):?>
<?php foreach( $images as $image ): ?>
<a href="<?php echo $image['url']; ?>">
<img src="<?php echo $image['sizes']['thumbnail']; ?>" alt="<?php echo $image['alt']; ?>" />
</a>
<p><?php echo $image['caption']; ?></p>
<?php endforeach; ?>
<?php endif;
endwhile;
else :
// no rows found
echo 'Nothing found'
endif; ?>
I would really appreciate any help on this!
Hi I’m having a bit of a problem with setting the location for a field group in my functions.php file. The code below adds a location of ‘entrant_2025’ only if it doesn’t already exist as a selected location in the location array.
It works fine. The fields gets added to the custom post type and I can also see it as a selected option in the field group location settings in the ACF UI.
The problem comes when I save the field group in the UI for whatever reason such as making a change or adding a new field. Each time I click save, another location gets added for ‘entrant_2025’.
Here is the code:
add_filter( 'acf/validate_field_group', 'add_custom_location_dynamic', 10, 1 );
function add_custom_location_dynamic( $field_group ) {
if ( $field_group['key'] === 'group_6786e0728946a' ) {
$location = false;
foreach($field_group["location"] as $loc){
if(in_array('entrant_2025', $loc[0])){
$location = true;
}
}
if(!$location){
$field_group['location'][][0] = array(
'param' => 'post_type',
'operator' => '==',
'value' => 'entrant_2025',
);
}
}
return ($field_group);
}
I dont know for sure what is happening but I presume ACF doesn’t see or recognise my saved location and so adds the location again and again and again each time I save.
I’ve tried changing the priority of 10 to much higher to see if that helps to run the code after acf has run it’s own or way lower to see if ACF will recognise the saved location and therefore not save another one but nothing works.
Any pointers would be a great help. Thanks.
Hi, I have a select field which is empty and I want to fill it with acf/load_value.
I used the following code, but the select field is empty.
If I insert something into the select field via the dashboard in ACF, it is displayed in the dashboard, but the $value is also empty.
add_filter('acf/load_value/key=field_67878669b82ab', 'loadStartLocation', 10 , 3);
function loadStartLocation( $value, $post_id, $field ) {
$value = array('Hamburg', 'Bremen');
return $value;
}
array(
'key' => 'field_67878669b82ab',
'label' => 'Startort',
'name' => 'product_ballon_start_location',
'aria-label' => '',
'type' => 'select',
'instructions' => '',
'required' => 0,
'conditional_logic' => 0,
'wrapper' => array(
'width' => '',
'class' => '',
'id' => '',
),
'choices' => array(
'cool' => 'cool',
),
'default_value' => false,
'return_format' => 'value',
'multiple' => 0,
'allow_null' => 0,
'allow_in_bindings' => 0,
'ui' => 0,
'ajax' => 0,
'placeholder' => '',
),
Hi all,
I’ve searched on the forum and cannot find an answer to my question. So I hope someone can help me.
I have a post type called Technologies. In it I have posts that describe each technology that I have an interest in, and it becomes a landing page.
Here’s an example:
I have one post each for the following technologies:
AI
ChatGPT
LLM
I use these posts for landing pages such as:
example.com/technologies/ai
example.com/technologies/chatgpt
example.com/technologies/llm
Now, I want to associate these technologies with articles (using a post type articles) that I write regarding these technologies. I would rather not have a custom field call technology in these posts, because that means I have to manage these technologies in two places as I add or delete technologies that I want to write about.
Is there a way in my post type articles that can have the various technologies I have defined in my technologies post types?
I hope I’ve explained this correctly and clearly.
Thanks in advance.
Ben
I have a hidden datetime field in a repeater. When a repeater row is duplicated, I would like to change the datetime value. I have tried using acf.getField
and then setting
field.val( new-date-string)
also
jQueryElement.attr('value', new-date-string)
and
jQueryElement.val(new-date-string)
finally
jQueryElement.datepicker('setDate', new-date-string)
none of these seem to alter the datetime value. I’m assuming maybe I’m accessing the wrong element but I’m not sure which one I should get?
I want to automatically collapse all flexible content fields that are nested within a repeater field.
I am building a restaurant menu that is quite large and each items has multiple pricing options that depend on quantity or toppings.
I have managed to do this using the flexible content field type that is nested under a repeated field and it works well except for one issue.
As I mentioned, the menu is quite large and each item itself has 5 fields so it takes up a lot of vertical space as all flexible content fields are opened by default and need to be manually collapsed by clicking on the inverted triangle icon (click to toggle option).
Is there a way these fields are close by default? Say, as soon as the content is filled-in they automatically collapse instead of having to manually close them?
I’m struggling getting a field value updated using a plugin.
Can anyone tell me what i’m doing wrong when calling to the update_field function?
Thanks
THis is the simple plugin code
// Adding option to admin panel
add_action(‘admin_menu’, ‘ple_add_admin_menu’);
function ple_add_admin_menu() {
add_menu_page(
‘Product Location Editor’,
‘Location Editor’,
‘manage_woocommerce’,
‘product-location-editor’,
‘ple_admin_page_content’,
‘dashicons-location-alt’,
20
);
}
// Function to create the admin page
function ple_admin_page_content() {
?>
<div class=”wrap”>
<h1>Change Location of Product</h1>
<form method=”post” action=””>
<label for=”product_search”>Search product by SKU or description:</label><br>
<input type=”text” name=”product_search” id=”product_search” placeholder=”input SKU o description” required>
<input type=”submit” value=”Search Product” class=”button button-primary”>
</form>
<?php
if (!empty($_POST[‘product_search’])) {
ple_search_and_update_product(sanitize_text_field($_POST[‘product_search’]));
}
?>
</div>
<?php
}
// Function to search the product
function ple_search_and_update_product($search_term) {
// Buscar productos por SKU o descripción
$args = array(
‘post_type’ => ‘product’,
‘s’ => $search_term,
‘posts_per_page’ => 10,
);
$products = new WP_Query($args);
if ($products->have_posts()) {
echo ‘<h2>Resultados de la búsqueda:</h2>’;
while ($products->have_posts()) {
$products->the_post();
$product_id = get_the_ID();
$product_name = get_the_title();
$location = get_field(‘location’, $product_id);
echo ‘<form method=”post” action=””>’;
echo ‘<p>‘ . esc_html($product_name) . ‘</p>’;
echo ‘<input type=”hidden” name=”product_id” value=”‘ . esc_attr($product_id) . ‘”>’;
echo ‘<label for=”new_location”>Location actual: ‘ . esc_html($location) . ‘</label><br>’;
echo ‘<input type=”text” name=”new_location” placeholder=”Nuevo Location” required>’;
echo ‘<input type=”submit” value=”Actualizar Location” class=”button button-primary”>’;
echo ‘</form>’;
echo ‘<hr>’;
}
wp_reset_postdata();
} else {
echo ‘<p>The search did not provide results.</p>’;
}
}
// Function to update field value “location”
add_action(‘admin_post_ple_update_location’, ‘ple_update_location’);
function ple_update_location() {
if (!empty($_POST[‘product_id’]) && !empty($_POST[‘new_location’])) {
$product_id = intval($_POST[‘product_id’]);
$new_location = sanitize_text_field($_POST[‘new_location’]);
// Update sentence
update_field(‘location’, $new_location, $product_id);
//update_post_meta($product_id, ‘location’, $new_location);
wp_redirect(admin_url(‘admin.php?page=product-location-editor&updated=true’));
exit;
}
}
I’m building a site with ACF Pro and using Bricks as my page builder and query system. I’ve created a custom post type for products, and I have a field set with 8 attributes. Most products will not have values for all 8 attributes for a variety of reasons.
What is a good approach that would allow me to only show attributes that contain a value on the product detail page? I’m sort of struggling to understand the best way to solve this.
thanks!
Hi team,
I have a post_type = project
and a taxonomy for post_type = project_page
– Now I create a relationship name = taxpage_order for taxonomy project_page
how to: in project_page load current post_type = project of taxonomy
my code get current: post of taxonomy: but not true
function vnt_taxpage_order( $args, $field, $post_id ) {
$queried_object = get_queried_object();
if ( isset( $queried_object->taxonomy ) && $queried_object->taxonomy === 'project_page' ) {
$term_id = $queried_object->term_id;
$args['tax_query'] = array(
array(
'taxonomy' => 'project_page',
'field' => 'term_id',
'terms' => $term_id,
),
);
}
return $args;
}
add_filter( 'acf/fields/relationship/query/name=taxpage_order', 'vnt_taxpage_order', 10, 4 );
Any idea for my case?
Thanks team!
I feel like I’m missing something really basic here:
– I have a “Hero” group that I’ve added to the homepage field set as a clone
– I’ve now cloned the same group to my general Page fieldset, so I can use it on all pages.
– Now, pages (there are a lot of them!) are consistently throwing the following error:
Warning: Trying to access array offset on value of type null in /Users/dafydd/Local Sites/cymdeithas-madog/app/public/wp-content/themes/cm24/cm24_inc/hero.php on line 3
– I know this is because the hero field hasn’t been added to these pages’ database entries.
– I can resolve this issue by entering the edit interface for each page and hitting Update, which adds the Hero entry to the page’s database entry. Bulk editing doesn’t work.
I’m using the following to get the Hero group:
$hero = get_field(‘hero’)[“hero”];
My questions:
1. Is there a way to update all pages at once to register the new field?
2. Barring that, is there a way to allow get_field() to fail without throwing an error?
Grateful for any advice here!
Greetings ACF team,
Since ACF Pro is an industry standard plugin or software (according to what I have read) in wordpress world, how does it take to ACF Pro team to implement or bring other payment options for non-US user to purchase your product beside credit card method?
I submitted a ticket to what now seems to be WP Engine support to no avail, so will post here just in case!
I have a block called Link List, which well is just a list of links. It was a repeater for manually entered link items but it was updated to include existing site content as well. I seem to have successfully migrated the fields in the old repeater to the fields in the updated repeater, I can see them in block preview and when viewing the block on the front end. However, when editing the block, there are no populated fields to edit.
Old json – repeater field with three subfields (subhead, url, short_description):
{
"key": "field_64837282e5ad9",
"label": "Old Link List Items",
"name": "items",
"aria-label": "",
"type": "repeater",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"layout": "block",
"pagination": 0,
"min": 0,
"max": 0,
"button_label": "Add Row",
"rows_per_page": 20,
"sub_fields": [
{
"key": "field_6483729ae5ada",
"label": "Old Subhead",
"name": "subhead",
"aria-label": "",
"type": "text",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"default_value": "",
"maxlength": "",
"placeholder": "",
"prepend": "",
"append": "",
"parent_repeater": "field_64837282e5ad9"
},
{
"key": "field_64837357e5adc",
"label": "Old URL",
"name": "url",
"aria-label": "",
"type": "url",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"default_value": "",
"placeholder": "",
"parent_repeater": "field_64837282e5ad9"
},
{
"key": "field_648372afe5adb",
"label": "Old Short Description",
"name": "short_description",
"aria-label": "",
"type": "textarea",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"default_value": "",
"maxlength": 155,
"rows": "",
"placeholder": "",
"new_lines": "",
"parent_repeater": "field_64837282e5ad9"
}
]
},
New json – repeater with three sub fields (entry_method, custom_item, existing_item), the custom_item containing the original three item fields (subhead, url, short_description) from above.
{
"key": "field_66b4df4663782",
"label": "Link List Items",
"name": "link_list_items",
"aria-label": "",
"type": "repeater",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"layout": "row",
"pagination": 0,
"min": 0,
"max": 0,
"collapsed": "",
"button_label": "Add Link Item",
"rows_per_page": 20,
"sub_fields": [
{
"key": "field_66b11540e682f",
"label": "Entry Method",
"name": "entry_method",
"aria-label": "",
"type": "select",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"choices": {
"custom": "Custom URL",
"existing": "Existing Page Content"
},
"default_value": "custom",
"return_format": "value",
"multiple": 0,
"allow_null": 0,
"ui": 0,
"ajax": 0,
"placeholder": "",
"parent_repeater": "field_66b4df4663782"
},
{
"key": "field_6758a9a91df40",
"label": "Custom Link List Item",
"name": "custom_item",
"aria-label": "",
"type": "group",
"instructions": "",
"required": 0,
"conditional_logic": [
[
{
"field": "field_66b11540e682f",
"operator": "==",
"value": "custom"
}
]
],
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"layout": "block",
"sub_fields": [
{
"key": "field_6758a8101df3e",
"label": "Subhead",
"name": "subhead",
"aria-label": "",
"type": "text",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"default_value": "",
"maxlength": "",
"placeholder": "",
"prepend": "",
"append": ""
},
{
"key": "field_66b4e13bd37ad",
"label": "URL",
"name": "url",
"aria-label": "",
"type": "url",
"instructions": "",
"required": 1,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"default_value": "",
"placeholder": ""
},
{
"key": "field_66b4e13bd37ae",
"label": "Short Description",
"name": "short_description",
"aria-label": "",
"type": "textarea",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"default_value": "",
"maxlength": 155,
"rows": "",
"placeholder": "",
"new_lines": ""
}
],
"parent_repeater": "field_66b4df4663782"
},
{
"key": "field_66b1161ae6830",
"label": "Existing Link List Item",
"name": "existing_item",
"aria-label": "",
"type": "relationship",
"instructions": "",
"required": 0,
"conditional_logic": [
[
{
"field": "field_66b11540e682f",
"operator": "==",
"value": "existing"
}
]
],
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"post_type": "",
"post_status": "",
"taxonomy": "",
"filters": [
"search",
"post_type",
"taxonomy"
],
"return_format": "id",
"min": "",
"max": 1,
"elements": "",
"bidirectional": 0,
"bidirectional_target": [],
"parent_repeater": "field_66b4df4663782"
}
]
}
PHP – migrating the old item fields into new Link List Items > Custom Item
$old_items = get_field('items') ?: [];
$link_list_items = get_field('link_list_items', $post_id) ?: [];
if ($old_items) {
foreach ($old_items as $old_item) {
$is_duplicate = false;
foreach ($link_list_items as $existing_item) {
if (
$existing_item['entry_method'] === 'custom' &&
$existing_item['custom_item']['subhead'] === $old_item['subhead'] &&
$existing_item['custom_item']['url'] === $old_item['url'] &&
$existing_item['custom_item']['short_description'] === $old_item['short_description']
) {
echo '<p>Duplicate found:</p>
'; var_dump($old_item); echo '
';
$is_duplicate = true;
break;
}
}
// If not a duplicate, add to the new structure
if (!$is_duplicate) {
echo '<p>Adding new item:</p>
'; var_dump($old_item); echo '
';
$link_list_items[] = [
'entry_method' => 'custom',
'custom_item' => [
'subhead' => $old_item['subhead'],
'url' => $old_item['url'],
'short_description' => $old_item['short_description'],
],
'existing_item' => null,
];
}
}
echo '<p>New link_list_items array to update:</p>
'; var_dump($link_list_items); echo '
';
// Update the field with the current + migrated items
$update_result = update_field('link_list_items', $link_list_items, $post_id);
// // Check if the update was successful
if ($update_result) {
echo '<p>Field updated successfully.</p>';
} else {
echo '<p>Failed to update field.</p>';
}
}
Just to reiterate, after running the migration script I can now see the old field data in the new fields on the front end, but if I edit the Link List block it’s as if there is no content.
Any help troubleshooting this would be appreciated, thanks!
I am trying to show an auto-populated field. I have generated it using load_field
filter.
I’ve auto-populated a textfield pmname using User select_a_project_manager field. I retrieved display_name and It auto-populated the pmname field. It’s working. Code below-
function pm_load_field( $field ) {
$user = get_field("select_a_project_manager");
if( $user ): ?>
<div class="author-box">
<h3><?php $user['display_name']; ?></h3>
</div>
<?php endif;
$field['value'] = $user['display_name'];
return $field;
}
add_filter('acf/load_field/name=pmname', 'pm_load_field');
The problem is I cannot show the pmname field in the template (In my case Elementor). It doesn’t return anything. So I assume the the field value is not saved. How can I save it?
I have a cpt as a template for courses. Each course template can contain several courses. The courses are recorded in a repeater, which in turn contains a repeater for dates.
I need to query all course template that have a course without a date. My existing code to query only the first course of each template is:
$args = array(
'post_type' => 'kurs-vorlage',
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'kurse_repeater_0_daten_0_datum',
'compare' => '=',
'value' => '',
),
),
);
Customization with the $ sign returns no results:
$args = array(
'post_type' => 'kurs-vorlage',
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'kurse_repeater_$_daten_0_datum',
'compare' => '=',
'value' => '',
),
),
);
How can the meta-query be changed to check all courses in a template for an empty first date field? Thanks!
Just a question. I’m trying to remove the CPT slug from the URL but I don’t want to use another plugin for a such simply task. Any advice please?
I found on some forum to set the user permalink and replace the slug with “/”. But this doesn’t work. So maybe to add some code to advanced scripts. Thank you.
Hey everyone, hoping you can lend some advice if possible. I’m pretty new to website development and coding, so am pretty out of my element here! This might be very easy to do, so apologise for my ignorance, but I’d appreciate the clarification/help if possible. Thanks in advance!
Basically, I’m building a website (using Elementor Pro) for a forthcoming magazine that’s going to publish several issues a year. There are going to be a number of Loop Items on the site that cycle through the magazine’s posts across various categories, and within each Loop Item template is a Post Info widget that ideally needs to list the author name, genre of post and the issue number that post can be found within. Obviously the first two are already present, but I figured I needed ACF to create the custom taxonomy of Issue Number.
Unlike the other taxonomies for author, genre etc., what I basically want to happen regarding this custom taxonomy is that, instead of triggering a query and taking you through to a filtered archive of posts at, e.g. ‘[website address].com/issue-number/issue-1’ etc., I want clicking on this issue number to actually take you to the direct product page where you can buy that issue, e.g. (in my case) ‘[website address].com/shop/standalone-issues/issue-1’. Is this viable, and if so, how would I go about implementing it? Much appreciated!
I was trying to organize my configuration fields in option page in multiple depths of tabs but found that trying to close a nested tabgroup to add nother tab in parent tabgroup was impossible, like exposed by @tdmalone in this thread.
Also, using group field is not an option : my code is already written and I don’t want to have to handle useless additional array dimensions or non unique field names, like suggested by @jackfowler.
So I tried to fix the issues caused by poor DOM tree the code of ACF generates.
1. Add the tab field a custom tabgroupend
setting:
add_action( 'acf/render_field_settings/type=tab', function( array $field ) {
acf_render_field_setting( $field, [
'label' => __( 'End of tab group', 'mydom' ),
'instructions' => '', // Tooltip
'hint' => '',
'type' => 'true_false',
'name' => 'tabgroupend',
'ui' => 1,
'class' => 'acf-field-object-true-false-ui',
], global: false );
And set a custom class on the tabs where this setting is enabled:
add_filter( 'acf/prepare_field', function( array $field ) {
if( ! empty( $field['tabgroupend'] ) ) {
$field['class'] .= ' acf-tabgroupend';
}
return $field;
} );
This results to add acf-tabgroupend
on tab links.
2. Set up a nested tabs structure with such logic :
3. Now script a bit through in a JS loaded on backend only :
(written in ES6)
window.acf?.addAction('ready', function() { // This allows to delay a bit after ACF other actions execution
if( ! acfTabgroupendEls.length ) {
return
}
/**
* Move acf-tabgroupend subsequent tabs to upper tabgroup
*/
acfTabgroupendEls.forEach( tabpanel => {
const ownTab = document.querySelector( .acf-tab-button[data-key="${tabpanel.dataset.key}"]
).parentNode // li
const ownTabWrap = ownTab.closest( '.acf-tab-wrap' )
// Tabs to move
let tabsToMove = []
let p = false // used to flag the tab
ownTabWrap.querySelectorAll( 'li' ).forEach( li => {
if( ! p ) {
if( li.isSameNode( ownTab ) ) {
p = true
}
return
}
tabsToMove.push( li )
} )
// Find tab group to move to
let elem = ownTabWrap.previousElementSibling
let secu = 0
let parentTabWrap
// Loop over the previous siblings to find possible parent in previous tabwraps
while( elem && secu < 1000 ) {
secu++
if( elem.matches( '.acf-tab-wrap' ) ) {
// tabwrap has an explicit end: continue to search up
if( ! elem.querySelector( '.acf-tabgroupend' ) ) {
parentTabWrap = elem
break
}
}
elem = elem.previousElementSibling
}
// No parent found: abort
if( ! parentTabWrap ) {
return
}
const newSiblingsTabs = parentTabWrap.querySelectorAll( 'li' )
// Move tabs to parent
tabsToMove.forEach( tab => {
parentTabWrap.childNodes[0].appendChild( tab )
} )
} )
/**
* Rework tabs showing/hiding
*/
document.querySelectorAll( '.acf-fields' ).forEach( acfFieldsEl => {
const childrenEls = Array.from( acfFieldsEl.childNodes ).filter( x => x.nodeType == Node.ELEMENT_NODE )
// No children elements: skip
if( ! childrenEls.length ) {
return
}
let tabTree = {}
let tabs = {}
let depth = 0
let currentKey
childrenEls.forEach( childEl => {
if( childEl.matches( '.acf-tab-wrap' ) ) {
childEl.querySelectorAll( '.acf-tab-button[data-key]' ).forEach( tabBtn => {
if( tabBtn.dataset.endpoint == '1' ) {
depth++
}
tabs[tabBtn.dataset.key] = {
depth: depth,
element: tabBtn.parentNode,
children: [],
}
if( tabBtn.matches( '.acf-tabgroupend' ) ) {
depth--
}
} )
}
} )
// No tabgroup in there: skip
if( _.isEmpty( tabs ) ) { // use of Lodash isEmpty helper, build your own if you prefer
return
}
// Store children with each parent tab
childrenEls.forEach( childEl => {
if( childEl.matches( '.acf-field-tab[data-key]' ) ) {
currentKey = childEl.dataset.key
}
else if( currentKey ) {
tabs[currentKey].children.push( childEl )
}
} )
Object.values( tabs ).forEach( tab => {
tab.element.addEventListener( 'click', ( e ) => {
Object.values( tabs ).forEach( t => {
// Different depth: skip
if( t.depth != tab.depth ) {
return
}
const activate = t.element.isSameNode( tab.element )
t.element.classList.toggle( 'active', activate )
t.children.forEach( child => {
child.classList.toggle( 'acf-hidden', ! activate )
if( ! activate ) {
child.setAttribute( 'hidden', '' )
}
else {
child.removeAttribute( 'hidden' )
}
} )
} )
} )
} )
} )
/**
* Fixes wrong visible tabs at load
*/
document.querySelectorAll( '.acf-tab-wrap .active' ).forEach( tabBtn => tabBtn.dispatchEvent( new MouseEvent( 'click' ) ) )
}
Worth to say that this solution will let unchanged the field groups where you did not enable tabgroupend
custom setting on any tab.
I have 2 groups within my block
It all displays correctly and saves correctly. No issues.
However, in my template I try to get the values and I get strange issues.
var_dump(get_field('group_four_square_main_square_background'));
var_dump(get_field('group_four_square_main_square_cta'));
Both return the SAME values!
Why?
function init_four_square_fields() {
acf_add_local_field_group([
'key' => 'group_four_square',
'title' => 'Four Square',
'fields' => [
[
'key' => 'field_four_square_main_square_title',
'label' => 'Title',
'name' => 'four_square_main_square_title',
'type' => 'text',
'prefix' => '',
'instructions' => '',
'required' => 0,
'conditional_logic' => 0,
'wrapper' => [
'width' => '100',
'class' => '',
'id' => '',
],
'default_value' => '',
'placeholder' => '',
'prepend' => '',
'append' => '',
'maxlength' => '',
'readonly' => 0,
'disabled' => 0,
],
[
'key' => 'field_four_square_main_square_description',
'label' => 'Description',
'name' => 'four_square_main_square_description',
'type' => 'textarea',
'prefix' => '',
'instructions' => '',
'required' => 0,
'conditional_logic' => 0,
'wrapper' => [
'width' => '100',
'class' => '',
'id' => '',
],
'default_value' => '',
'placeholder' => '',
'prepend' => '',
'append' => '',
'maxlength' => '',
'readonly' => 0,
'disabled' => 0,
],
[
'key' => "group_four_square_main_square_cta",
'label' => 'CTA',
'type' => 'group',
'layout' => 'block',
'sub_fields' => [
[
'key' => 'link',
'name' => 'link',
'label' => 'Link',
'type' => 'link',
'instructions' => '',
'required' => 0,
'conditional_logic' => 0,
'wrapper' => [
'width' => '50',
'class' => '',
'id' => '',
],
'return_format' => 'array',
'wpml_cf_preferences' => 2,
'acfml_field_group_mode' => 'advanced',
],
[
'key' => 'class',
'name' => 'class',
'label' => 'Class',
'type' => 'text',
'required' => 0,
'conditional_logic' => 0,
'wrapper' => [
'width' => '50',
'class' => '',
'id' => '',
],
'wpml_cf_preferences' => 0,
'maxlength' => '255',
]
]
],
[
'key' => "group_four_square_main_square_background",
'label' => 'Main Square Background',
'type' => 'group',
'layout' => 'block',
'sub_fields' => [
[
'key' => 'type',
'label' => 'Type',
'name' => 'type',
'type' => 'radio',
'instructions' => '',
'required' => 0,
'conditional_logic' => 0,
'wrapper' => [
'width' => '50',
'class' => '',
'id' => '',
],
'choices' => [
'image' => 'Image',
'video' => 'Video',
'color' => 'Color',
// 'embed' => 'Embed video',
],
'allow_null' => 0,
'other_choice' => 0,
'default_value' => 'color',
'layout' => 'horizontal',
'return_format' => 'value',
'save_other_choice' => 0,
'wpml_cf_preferences' => 0,
'acfml_field_group_mode' => 'advanced',
],
[
'key' => 'image',
'label' => 'Image',
'name' => 'image',
'type' => 'image',
'instructions' => '',
'required' => 0,
'conditional_logic' => [
[
[
'field' => 'type',
'operator' => '==',
'value' => 'image',
],
],
],
'wrapper' => [
'width' => '50',
'class' => '',
'id' => '',
],
'return_format' => 'array',
'preview_size' => 'full',
'library' => 'all',
'min_width' => '',
'min_height' => '',
'min_size' => '',
'max_width' => '',
'max_height' => '',
'max_size' => '',
'mime_types' => '',
],
[
'key' => 'video',
'label' => 'Video',
'name' => 'video',
'type' => 'file',
'instructions' => '',
'required' => 0,
'conditional_logic' => [
[
[
'field' => 'type',
'operator' => '==',
'value' => 'video',
],
],
],
'wrapper' => [
'width' => '50',
'class' => '',
'id' => '',
],
'return_format' => 'array',
'library' => 'all',
'min_size' => '',
'max_size' => '',
'mime_types' => '',
],
[
'key' => 'color',
'name' => 'color',
'type' => 'select',
'choices' => [],
'conditional_logic' => [
[
[
'field' => 'type',
'operator' => '==',
'value' => 'color',
],
],
],
]
]
],
],
'location' => [
[
[
'param' => 'block',
'operator' => '==',
'value' => 'acf/four-square',
],
],
],
'menu_order' => 0,
'position' => 'normal',
'style' => 'default',
'label_placement' => 'top',
'instruction_placement' => 'label',
'hide_on_screen' => '',
]);
}
add_action('acf/init', 'init_four_square_fields');
Hey there! Long question taken short:
I want to be able to only edit from the admin interface so I dont need to enter a page to edit the fields as I wont need to do that, Im interessted in having the default values to be set as the text / values to be shown always.
Any ideas people?, I dont know much about coding, just a bit.
Hi!
I have repeater list with text fields list-text
How to fill-in example for repeater in block.json?
I tried these variants:
"example": {
"attributes": {
"data": {
"list": [
[
["list-text", "Element 1"]
],
[
["list-text", "Element 2"]
],
[
["list-text", "Element 3"]
]
]
}
}
}
"example": {
"attributes": {
"data": {
"list": [
{
"list-text": "Element 1"
},
{
"list-text": "Element 2"
},
{
"list-text": "Element 3"
}
]
}
}
}
But it doesn’t work.