You cannot. WP offers ASC and DESC orders. https://wordpress.stackexchange.com/questions/293113/wp-query-custom-orderby-not-asc-nor-desc/293125
It would probably not be impossible to do this, but it would be very difficult and I don’t know how to accomplish it.
If you have custom taxonomies for each post type would be one thing, but on the other hand if you are using a single taxonomy for all post types then it would get even more complicated.
In the latter case, that is using a single taxonomy for all post types, it would probably be impossible to do this and allow for terms to be added in the future and to automatically populate the field based on those unknown future terms. The only way that I can think of to work around this problem would be that if the taxonomy is hierarchical and all of the terms for a specific post type are all children of a main term used for that post type.
If you do have custom taxonomies (or even if you done) then using a taxonomy field is difficult because you would need to intercept the AJAX call that ACF makes to get the list of terms modify the request and inject the selected post type into that request. Then you’d need to build a filter that modifies the get_terms() query that ACF runs https://www.advancedcustomfields.com/resources/acf-fields-taxonomy-query/.
If I needed to do this I would not use a taxonomy field. I would use another select field and I would populate the values of the second select field dynamically based on the selection of the first field as in this example https://github.com/Hube2/acf-dynamic-ajax-select-example/tree/master/dynamic-select-example.
While using the WP admin and you drag a field group, WP makes an AJAX request with the action “meta-box-order”. This causes the built in action on that request to run which saves the order. The ajax action I posted fires before the built in WP action because the priority is set to 0 (zero) and the one for WP is set to 1. The new action prevents both the saving of the meta box order and the internal WP action from firing.
The only way to get them “unstuck” is to delete the user’s meta box order entries in the DB. There isn’t any real way to fix this without working directly in the DB.
The code I posted will prevent them being moved in the future. Or I should say, if you add the PHP part then the boxes can be moved but when the page reloads then the boxes will be back where they are supposed to be. If you also implement the JS code then the boxes can never be moved.
You have to generate your own unique ID.
I do this with the sites I am working on to have an ID for generation of dynamic CSS and to allow clients the ability to link to portions of the page using #{ID}.
What I have is a group with a single field called layout_id. This group is cloned into all of my flex layouts.
I add a filter to this field to make it readonly.
add_filter('acf/load_field/key=field_5dd6ea9c6325c'.$key, 'readonly_field', 20, 1);
function readonly_field($field) {
$field['readonly'] = true;
return $field;
}
Then I have a bit of JS in my custom admin.js file that generates the unique ID values. I do this in the JS to ensure that the id is unique on the page. It is potentially possible for the ID value to change, but this is rare. This cannot be done with prepare field because all of the rows would end up with the same ID.
(function($){
if (typeof acf != 'undefined') {
acf.add_action('ready append', function($el) {
// array to hold list of existing ID values
var layout_ids = [];
// selector targets id field butnot hidden clones of layouts
var fields = $('[data-key="field_5dd6ea9c6325c"] .acf-input input').not('.clones [data-key="field_5dd6ea9c6325c"] .acf-input input');
if (fields.length) {
for (i=0; i<fields.length; i++) {
var field = $(fields[i]);
var value = field.val();
if (value == '' || layout_ids.indexOf(value) != -1) {
value = 'pnl-'+acf.uniqid();
field.val(value);
field.trigger('change');
}
layout_ids.push(value);
}
}
});
}
})(jQuery);
If yo wanted to not use the JS method then you’d need to construct an acf/save_post action that did the generation after the fields are saved to ensure that they are unique on the page.
The reason is that the “meta_key” in the database is different for repeater and group.
meta_key for repeater sub field = "{$parent_name}_{$row_index}_{$sub_field_name}"
meta_key for group sub field = "{$parent_name}_{$sub_field_name}"
When you make the switch the field data is then stored incorrectly in the database.
Thanks for your explanation John!
However I think it’s not my problem: I never call get_field()
on update/create post process, I call get_field()
on page reload AFTER the process is completely finished (after several seconds, and after several reloads ^^). And I call wp_post_update()
BEFORE any ACF update_field()
(but there are ACF get_field()
calling before wp_post_update()
to populate data).
To briefly explain:
1. I call Airtable API (a Database/Excel like) to retrieve new data
2. Retrieve the WP Post from WP ID stored in Airtable
3. Populate Company PHP Object with existing data in WP (use get_field()
)
4. Update data in Company PHP Object with new data retrieved in Airtable (custom PHP)
5. Commit data in WP from new Company PHP Object with wp_update_post()
and (only after) update_field()
.
6. I go to the Company Page Edition in WP Back Office: All data are updated!
7. I check in database with an SQL Query: All data are updated correctly
8. I go to the Company Page in Front End to view modifications (so the PHP process is completely finished) by page reload (several reloads to be sure ^^), but nothing changed, old data are displayed :'( (no cache issue).
I think my issue doesn’t covered by your explanation, but I could be wrong 😶
I am currently developing a new getField() function, but if you have a secret sauce… 😁
This is bizarre – the fields are definitely not changing, and in the db I see the keys are all the same. Even further if I simply change the field type back to “repeater” from “group”, my data reappears…
Additionally, if I try to add new data in this state, it does not show up on the frontend. And in the backend, validation is totally screwy – subfields that have no validation required fail validation for being empty (and don’t have the red asterisk).
I suspect this tampering just totally confuses some part of ACF…
I am currently using the allowed_block_type filter to control the available blocks in my theme, similar to the following example:
function acf_allowed_blocks($allowed_blocks, $post)
{
// Register core blocks
$core_blocks = array(
'core/buttons',
'core/heading',
'core/image',
'core/list',
'core/paragraph',
);
// Register custom blocks
$custom_blocks = array(
'acf/test-block',
);
// Register plugin specific blocks
$plugin_blocks = array(
'gravityforms/form',
);
// Specify block groupings available on specific post types
switch ($post->post_type) {
case 'post_type_example':
$allowed_blocks = array_merge($core_blocks);
break;
default:
$allowed_blocks = array_merge($core_blocks, $custom_blocks, $plugin_blocks);
}
return $allowed_blocks;
}
add_filter('allowed_block_types', 'acf_allowed_blocks', 10, 2);
While this works perfectly, I am trying to determine whether or not it’s possible to remove the gravityforms/form block, but allow it inside the acf/test-block. Currently, if I remove the block from this function, it’s also becomes unavailable as an inner block in my ACF block markup, which looks like this:
$allowed_blocks = array( 'gravityforms/form' );
echo '<InnerBlocks allowedBlocks="' . esc_attr(wp_json_encode($allowed_blocks)) . '" />';
Does anyone have any idea on whether or not this is even possible with the current state of Gutenberg? I can just as easily live with it being available as both a main and an inner block, but it would be my preference to only use it as an inner block.
I cannot honestly say without more understanding of the entire code that is being executed when the post is saved. Looking at the functions you’re calling I’m assuming that it would likely take me hours to get this level of understanding. Things can get quite complicated.
Here is a simple example. You submit a post, on the front end 2 things happens. First is that acf runs the acf/pre_save_post hook that gets the post ID. Next the post is saved and following that acf saves the fields, acf/save_post runs.
If you call get_field() during this process ACF will not know what the post ID is that it’s supposed to get the field for because it does not know the post ID. You must supply the correct post ID. The global post ID, if any, will be the post ID where the acf form appears. This is why acf passes the post ID to all acf/save_post actions. You need to pass this ID to any function that will need to get a value from the post that was just saved.
Then there is the issue of calling wp_update_post() inside of an acf/save_post action. What happes is that you cause acf/save_post to run again because this action is tied to WP’s updating of any post. Usually this causes an infinite loop.
Sooooo I have a workaround:
remove_action('post_updated', 'wp_save_post_revision');
...
wp_update_post($postData);
...
update_field('field_XYZ123', $value, $post_id);
...
add_action('post_updated', 'wp_save_post_revision');
And it works apparently, on the other hand we have no revision during the post update…
So the real question (I think) is the following:
Why get_field()
called in WP theme doesn’t retrieve the same Post ID than the one retrieved from the Back Office?
You need to modify the where portion of the query. This means that in your filter above you need to add additional filters as described in this post https://adambalee.com/search-wordpress-by-custom-fields-without-a-plugin/
Update
I managed to make it filter based on 2 custom fields, but it is not searching by title now
function filter_products_by_sku( $args, $field, $post_id ) {
$the_search = $args['s'];
unset($args['s']);
$args['meta_query'] = array(
'relation' => 'OR',
array(
'key' => 'sku_number',
'value' => $the_search,
'compare' => 'LIKE',
),
array(
'key' => 'old_id',
'value' => $the_search,
'compare' => 'LIKE',
)
);
return $args;
}
add_filter('acf/fields/post_object/query/key=field_5f58a23b95d62', 'filter_products_by_sku', 10, 3);
As I stated before, when inserting data you must use the field keys, field names will not work where there is not already existing data saved to the field, which is what happens when you’re adding new posts.
For top level field (not in a group, repeater, flex field)
update_field('field_XYZ123', $value, $post_id)
for a repeater or a flex field
$value = array(
// each element of this array is a row in the repeater
array(
// each element of this row is a field key => value pair
'field_XXXXXXX' => 'value',
'field_YYYYYYY' => 'value'
)
);
// field_ZZZZZZZ is the repeater field key
update_field('field_ZZZZZZZ', $value, $post_id);
for a group field
$value = array(
// a group field is a repeater with a single row
// there is no nesting required for each row because of this
// the elements of this array are sub field key => value pairs
'field_XXXXXXX' => 'value',
'field_YYYYYYY' => 'value'
);
// field_ZZZZZZZ is the group field key
update_field('field_ZZZZZZZ', $value, $post_id);
If you have nested repeater, group and flex fields then you must create the nesting when updating the fields. It may be possible to use add_row() and update_sub_field(), but these would have the same restrictions of needing to use the field key for new data and it’s generally easier to just construct the arrays that are needed. But then again, I don’t generally insert data this way. If I’m inserting data it’s because I am building an import and I use WP All Import Pro with the ACF add on so that I don’t need to worry about these details.
The comment I made about deleting the cache is only relevant if you update a field and then want to get the updated value during the same page load unless you have some type of persistent cache installed that caches data across page loads.
The problem you have is that someone has already reordered the boxes. The first thing you need to do is find all of the user meta and delete it.
I would employ 2 things form here https://wordpress.stackexchange.com/questions/2474/disable-dragging-of-meta-boxes
1) Disable the boxes from being sorted in the first place. In a custom JS file that loads in the admin I add
(function($){
$(document).ready(function(e) {
$('.meta-box-sortables').sortable({
disabled: true
});
$('.postbox .hndle').css('cursor', 'pointer');
});
})(jQuery);
Then, in case that fails for some reason I add the following which prevents the saving of the order meta, priority of 0 causes my action to fire before the built in WP action.
// disable saving of metabox order
add_action('wp_ajax_meta-box-order', 'disable_meta_box_order_save', 0);
function disable_meta_box_order_save() {
wp_die(-1);
}
I am still not sure, may be this will work for you. You have to add your fields in first line and you have to multiple times for multiple checkboxes.
<?php $values = get_field('MYFIELD', $post->post_parent); if(in_array("CHECKBOX_NAME", $values )){ ?>
<?php get_template_part("template-parts/button-template-loop/button-patch-loop"); ?>
<? } ?>
Thanks Jonathan, this worked great for me when I have the “object” or “array” option selected:
<?php
$hdr_image = get_field('hdr_image');
?>
<?php if( !empty( $hdr_image ) ): ?>
<img src="<?php echo esc_url($hdr_image['sizes']['thumbnail']); ?>" alt="<?php echo esc_attr($hdr_image['alt']); ?>" class="img-responsive">
<?php endif ?>
Of course, you’ll have to change “thumbnail” to your desired default size or the custom size you registered on your functions.php
Thanks again 🙂
PS. It’s important to remember that if you registered a custom size after you uploaded an image, you’re going to have to regenerate your thumbnails.
Thanks Jonathan, this worked great for me when I have the “object” or “array” option selected:
<?php
$hdr_image = get_field('hdr_image');
?>
<?php if( !empty( $hdr_image ) ): ?>
<img src="<?php echo esc_url($hdr_image['sizes']['thumbnail']); ?>" alt="<?php echo esc_attr($hdr_image['alt']); ?>" class="img-responsive">
<?php endif ?>
Of course, you’ll have to change “thumbnail” to your desired default size or the custom size you registered on your functions.php
Thanks again 🙂
PS. Remember that if you registered the image size after you uploaded the image it’s probably not working because you have to regenerate the thumbnail images.
Forgive my ignorance, I am trying to study and understand more, in the meantime I rely on your help:
I have a sub-field called ‘feedback’ inserted into a ‘day’ repeater. I create several ‘days’ and I would like the end user to enter a comment in the ‘feedback’ field in frontend and press ‘submit’. This comment should be visible on the backend in the ‘feedback’ field.
I managed to do an acf_form with the ‘feedback’ field, the value is written in the db, but I don’t see it in the backend. And above all it is repeated the same for all instances of the repeater. How do I create unique comments for each instance?
thank you so much!
I read this post https://support.advancedcustomfields.com/forums/topic/getting-instance-and-sort-of-id-of-repeater-field/ and the related ones and managed to get a unique id for each ‘day’ that is repeated.
But how can I use this ID for the comment? how to make the comment bind to this id and not the post id?
John Huebner
I’ve done it the way you said but still did not work.
It is very important and critical for me. So, I will post chronological screen how I did it and I would be grateful if you check if it is correct.
Thank you very much in advance.
P.S. I applied it with Elementor Pro.
John Huebner
I’ve done with your way but still not working.
It it very important for me. So I will post screens how I’ve done it and please check if it is correct.
Thank you very much in advance.
P.S. I applied it with Elementor Pro.
I have post type called “brand” and taxonomy called “category_brand”. Under the “brand” post type I have a repeater field. That repeater field Includes two sub fields: number field called “grade”, and taxonomy field called “category” (the taxonomy display all the categories under “category_brand”)
it looks like this: the repeater field
In the taxonomy archive of “category_brand” I display only the “brands” of the current taxonomy.
The order of the posts need to be by the “grade” sub fields, (large to small number).
I’m troubling with getting the ‘meta_key’ from the grade field under the repeater. The thing is that I need to get the “grade” field only if it’s related to the current taxonomy – The “category” sub field in the repeater.
This is the code
$current_object=get_queried_object();
$current_object_tax= $current_object->taxonomy;
$current_object_tax_id= $current_object->term_id;
$post_args_current_tax = array(
'post_type' => 'brands',
'tax_query' => array(
array(
'taxonomy'=> $current_object_tax,
'field'=> 'term_id',
'terms' => $current_object_tax_id,
),
),
'posts_per_page' => -1,
'meta_key'=> 'categorygrade_0_grade',
'orderby'=> 'meta_value_num',
'order' => 'DESC',
);
$post_query_current_tax = new WP_Query($post_args_current_tax);
Right now this meta_key:’meta_key’=> ‘categorygrade_0_grade’, takes all the grades under the repeater and not only the grades that related to the current taxonomy. How can I get the grade only if it’s related to the current taxonomy in the repeater?
<quote>I’ve been working through two sites I had running Magic Fields. One I was able to convert, though it was difficult. The second proved to be too difficult to do completely. I got stuck on the way MF stores repeated image files, and I’m considering maybe just re-creating the image sections on those posts is the way to go.
I documented the processes I went through on my blog, including dead ends and short-cuts; maybe some of what I found could be helpful. It involved cloning the site, writing lots of SQL queries, and finally running some custom PHP code.</quote>
Exactly what I needed! You just saved me several hours. Thanks!
Hi,
I just migrated a Website from Drupal to WordPress using the FG Drupal to WP plugin and after some difficulties (process kept stopping and had to be resumed constantly), I succeeded. The problem is that yes, the plugin requires the use of Toolset Types, which I don’t want to use, I prefer ACF like most people around here.
So it works, but now I need to turn Toolset fields into ACF fields, and if I understand that I need to recreate all the fields in ACF, i don’t see how I can transfer the content of the Toolset fields to the new ACF ones.
In his message, @pixeline doesn’t say anything about that part, only to modify the template, but it looks like there’s a missing step between 3 and 4: move the Toolset data to ACF fields.
If @pixeline or @muzKore (or somebody else) can give me a hand here, I’d appreciate ☺️
Ch.
OK, I’m going to answer my own question. It took a little time, but you can do it. For now, I’ve edited the core files, but will make my own ACF field to not interfere with the base datetimepicker.
Two things to know:
1. The datetimepicker is an extension of the jQuery UI date picker. It has a known bug that will NOT allow the time to be set in inline mode. However, I have a fix for that.
2. To activate inline mode, you need to target a <div> or <span> as the target for the datetimepicker instead of the <input> tag.
So, step one is to update the render_field
method in the acf_field_date_and_time_picker.php
file and class.
Just to keep to the style of the existing code, I inserted a new DIV using the acf methods here:
$text_input = array(
'class' => 'input',
'value' => $display_value,
);
$inline_calendar = array(
'class' => 'calendar-inline input'
);
// html
?>
<div <?php acf_esc_attr_e( $div ); ?>>
<?php acf_hidden_input( $hidden_input ); ?>
<?php // acf_text_input( $text_input ); ?>
<div <?php acf_esc_attr_e( $inline_calendar ); ?>></div>
</div>
<?php
}
This will insert the div below the text input, and comment out the text input.
Next, update the acf-input.js
file to edit the javascript of the picker.
Note that the datetimepicker is an extension of the date picker. So, around line 5811 there will be a definition for the date_picker and it will declare the $inputText.
$inputText: function(){
return this.$('.calendar-inline');
// return this.$('input[type="text"]');
},
This should now return your .calendar-inline class instead of the <input> tag.
Lastly, a bit further down, in the date_time_picker section (not date_picker section) there is a declaration to add.newDateTimePicker on line 6031. We need to update that to update the calendar with the current time.
// add
acf.newDateTimePicker = function( $input, args ){
// bail ealry if no datepicker library
if( typeof $.timepicker === 'undefined' ) {
return false;
}
// defaults
args = args || {};
// NEW - Remember date/time
$date = args.altField[0].value;
// initialize (This wipes the datetime in inline mode)
$picker = $input.datetimepicker( args );
// update to current datetime with the value 2 lines above.
$picker.datetimepicker('setDate', (new Date($date)) );
// wrap the datepicker (only if it hasn't already been wrapped)
if( $('body > #ui-datepicker-div').exists() ) {
$('body > #ui-datepicker-div').wrap('<div class="acf-ui-datepicker" />');
}
};
We effectively store the datetime before we initialise the datetimepicker and then update it once it’s created.
Now you should have an embedded calendar.
Couple of gotchas:
1. Remember to hard-reload and clear cache to reload the new JS.
2. The acf-input.min.js gets loaded by default, you can test the acf-input.js by updating the /includes/assets.php
file and the enqueue_script location OR just define the constant SCRIPT_DEBUG
to use the non-minified version.
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.