Home › Forums › Backend Issues (wp-admin) › ACF on product variations: almost works
Hi,
I managed to add custom fields to product variations with the piece of code bellow. Problem is variations are dynamically loaded when editing a product. Thus, even if custom fields are rendered the right way in the admin interface, JavaScript events are not attached to these fields, making things like gallery or image selector not to work or repeater not to react when trying to add a new entry.
I would like to know if you know about a fix or workaround to make this work?
Thanks.
Code :
$GLOBALS['wc_loop_variation_id'] = null;
function is_field_group_for_variation($field_group, $variation_data, $variation_post) {
return (preg_match( '/Variation/i', $field_group['title'] ) == true);
}
add_action( 'woocommerce_product_after_variable_attributes', function( $loop_index, $variation_data, $variation_post ) {
$GLOBALS['wc_loop_variation_id'] = $variation_post->ID;
foreach ( acf_get_field_groups() as $field_group ) {
if ( is_field_group_for_variation( $field_group, $variation_data, $variation_post ) ) {
acf_render_fields( $variation_post->ID, acf_get_fields( $field_group ) );
}
}
$GLOBALS['wc_loop_variation_id'] = null;
}, 10, 3 );
add_action( 'woocommerce_save_product_variation', function( $variation_id, $loop_index ) {
if ( !isset( $_POST['acf_variation'][$variation_id] ) ) {
return;
}
$_POST['acf'] = $_POST['acf_variation'][$variation_id];
acf()->input->save_post( $variation_id );
}, 10, 2 );
add_filter( 'acf/prepare_field', function ( $field ) {
if ( !$GLOBALS['wc_loop_variation_id'] ) {
return $field;
}
$field['name'] = preg_replace( '/^acf\[/', 'acf_variation[' . $GLOBALS['wc_loop_variation_id'] . '][', $field['name'] );
return $field;
}, 10, 1);
Found a solution for ACF fields requiring events to be attached.
In your php code, add the following:
function xxx_admin_head_post() {
global $post_type;
if ($post_type === 'product') {
wp_register_script( 'xxx-acf-variation', get_template_directory_uri() . '/js/acf-variation.js', array(
'jquery-core',
'jquery-ui-core'
), '1.1.0',
true ); // Custom scripts
wp_enqueue_script( 'xxx-acf-variation' ); // Enqueue it!
}
}
/* actions fired when adding/editing posts or pages */
/* admin_head-(hookname) */
add_action( 'admin_head-post.php', 'xxx_admin_head_post' );
add_action( 'admin_head-post-new.php', 'xxx_admin_head_post' );
Create js/acf-variation.js with the following code:
jQuery(document).ready(function($) {
$( '#woocommerce-product-data' ).on( 'woocommerce_variations_loaded', function(){
acf.doAction('ready');
});
});
Oups! “woocommerce_save_product_variation” action does not work properly.
Replace with:
add_action( 'woocommerce_save_product_variation', function( $variation_id, $loop_index ) {
if ( !isset( $_POST['acf_variation'][$variation_id] ) ) {
return;
}
if ( ! empty( $_POST['acf_variation'][$variation_id] ) && is_array( $fields = $_POST['acf_variation'][$variation_id] ) ) {
foreach ( $fields as $key => $val ) {
update_field( $key, $val, $variation_id );
}
}
}, 10, 2 );
For some reason, when trying to use get_fields($variation_id) later (for example on front-end), you won’t be able to get the saved fields.
This is quiet weird as update_field
use to store fields seems to do the job the right way. Custom fields are saved in postmeta
table : both field_name and _field_name are saves, the first with field value, the second with field key. Furthermore, these fields are restored the right way when editing product variations.
For now, I have to use get_field('field_name', $variation_id)
to get data.
I like to switch between product specs, when i change product variation.
I should be nice if it is below the Description of Woocommerce.
For example see Philips Lighting website.
I want the specs of a LED Light switching when i change variation.
Per lamp another specs below of the Description or a Tab.
A table with with specs, copy and paste.
Problem: When i make Product Type is Equal to Product Variation (WYSIWYG Editor). I don’t see the Editor at the Product Variation position.
@exnihilo_maxime I can add the fields but I cant save the data that I put in them. I just get an infinite spinner and the below error in the console:
wp-admin/admin-ajax.php 500 (Internal Server Error)
Any suggestions would be really appreciated.
Thanks
John
Hi @johnw6761.
If you have a 500 internal server error, either there is a syntax error or something wrong occurs in the code (ex. trying to access a property on a non-objet variable).
Could you please see if you find an error message in the latest fatal-errors-YYYY-MM-DD-*.log located in ./wp-content/uploads/wc-logs. Else, it won’t help much.
Thanks.
—
Maxime.
Hi @exnihilo_maxime .
Thank you very much for your reply.
This is the error shown in the logs:
2019-09-17T07:57:27+00:00 CRITICAL Uncaught Error: Call to a member function save_post() on null in /home/customer/www/nevelli.creativepatricktesting.co.uk/public_html/wp-content/themes/nevelli/functions/theme-support.php:148
Stack trace:
#0 /home/customer/www/nevelli.creativepatricktesting.co.uk/public_html/wp-includes/class-wp-hook.php(286): {closure}(22, 0)
#1 /home/customer/www/nevelli.creativepatricktesting.co.uk/public_html/wp-includes/class-wp-hook.php(310): WP_Hook->apply_filters('', Array)
#2 /home/customer/www/nevelli.creativepatricktesting.co.uk/public_html/wp-includes/plugin.php(465): WP_Hook->do_action(Array)
#3 /home/customer/www/nevelli.creativepatricktesting.co.uk/public_html/wp-content/plugins/woocommerce/includes/admin/meta-boxes/class-wc-meta-box-product-data.php(532): do_action('woocommerce_sav...', 22, 0)
#4 /home/customer/www/nevelli.creativepatricktesting.co.uk/public_html/wp-content/plugins/woocommerce/includes/class-wc-ajax.php(2084): WC_Meta_Box_Product_Data::save_variations(14, Object(WP_Post))
#5 /home/customer/www/ in /home/customer/www/nevelli.creativepatricktesting.co.uk/public_html/wp-content/themes/nevelli/functions/theme-support.php on line 148
Hi @johnw6761,
I guess you are trying to call save_post() on $post or some other variable name. Make sure this variable exists. Maybe is $post (or other name) global. Did you try global $post;
before you call save_post()?
Im not sure i just used your code at the top of the page? I didnt add anything else? Was I supposed to?
Thanks
John
Could you please copy-paste code in nevelli/functions/theme-support.php around line 148?
@exnihilo_maxime This is the whole code I am using
$GLOBALS['wc_loop_variation_id'] = null;
function is_field_group_for_variation($field_group, $variation_data, $variation_post) {
return (preg_match( '/Variation/i', $field_group['title'] ) == true);
}
add_action( 'woocommerce_product_after_variable_attributes', function( $loop_index, $variation_data, $variation_post ) {
$GLOBALS['wc_loop_variation_id'] = $variation_post->ID;
foreach ( acf_get_field_groups() as $field_group ) {
if ( is_field_group_for_variation( $field_group, $variation_data, $variation_post ) ) {
acf_render_fields( $variation_post->ID, acf_get_fields( $field_group ) );
}
}
$GLOBALS['wc_loop_variation_id'] = null;
}, 10, 3 );
add_action( 'woocommerce_save_product_variation', function( $variation_id, $loop_index ) {
if ( !isset( $_POST['acf_variation'][$variation_id] ) ) {
return;
}
$_POST['acf'] = $_POST['acf_variation'][$variation_id];
acf()->input->save_post( $variation_id );
}, 10, 2 );
add_filter( 'acf/prepare_field', function ( $field ) {
if ( !$GLOBALS['wc_loop_variation_id'] ) {
return $field;
}
$field['name'] = preg_replace( '/^acf\[/', 'acf_variation[' . $GLOBALS['wc_loop_variation_id'] . '][', $field['name'] );
return $field;
}, 10, 1);
and this is line 148
acf()->input->save_post( $variation_id );
This sounds weird. It’s like if acf()
function was not existing or there was no input
property. Sure ACF is activated?
Haha yes definitely activated, im pretty stupid but not that stupid lol.
I did see on another thread someone else having the same issue.
Ha ha! 🙂 We never know. Well, strange issue. ACF being activated, the issue must be about input property. Did you try to print_r
or var_dump
it to see what’s in it?
I missed the essential point: what to examine. Try to display what’s in acf()->input
Any updates on this @exnihilo_maxime ? Did you come up with a “final” solution by chance?
@johnw6761 @dekket you should replace the line
acf()->input->save_post( $variation_id );
with:
do_action( 'acf/save_post', $variation_id );
works for me, and looks like that is how it works behind the systems.
Hi, is there any update or news about repeater field ?
i was able to save normal fields to product variation but when i create repeater field it doesnt save the value, here is my code;
add_filter('acf/location/rule_values/post_type', 'acf_location_rule_values_Post');
function acf_location_rule_values_Post( $choices ) {
$choices['product_variation'] = 'Product Variation';
return $choices;
}
add_action( 'woocommerce_product_after_variable_attributes', function( $loop, $variation_data, $variation ) {
global $abcdefgh_i;
$abcdefgh_i = $loop;
add_filter( 'acf/prepare_field', 'acf_prepare_field_update_field_name' );
$acf_field_groups = acf_get_field_groups();
foreach( $acf_field_groups as $acf_field_group ) {
foreach( $acf_field_group['location'] as $group_locations ) {
foreach( $group_locations as $rule ) {
if( $rule['param'] == 'post_type' && $rule['operator'] == '==' && $rule['value'] == 'product_variation' ) {
acf_render_fields( $variation->ID, acf_get_fields( $acf_field_group ) );
break 2;
}
}
}
}
remove_filter( 'acf/prepare_field', 'acf_prepare_field_update_field_name' );
}, 10, 3 );
function acf_prepare_field_update_field_name( $field ) {
global $abcdefgh_i;
$field['name'] = preg_replace( '/^acf\[/', "acf[$abcdefgh_i][", $field['name'] );
return $field;
}
add_action( 'woocommerce_save_product_variation', function( $variation_id, $i = -1 ) {
if ( ! empty( $_POST['acf'] ) && is_array( $_POST['acf'] ) && array_key_exists( $i, $_POST['acf'] ) && is_array( ( $fields = $_POST['acf'][ $i ] ) ) ) {
foreach ( $fields as $key => $val ) {
update_field( $key, $val, $variation_id );
}
}
}, 10, 2 );
function xxx_admin_head_post() {
global $post_type;
if ($post_type === 'product') {
wp_register_script( 'xxx-acf-variation', get_template_directory_uri() . '/inc/ss.js', array(
'jquery-core',
'jquery-ui-core'
), '1.1.0',
true ); // Custom scripts
wp_enqueue_script( 'xxx-acf-variation' ); // Enqueue it!
}
}
/* actions fired when adding/editing posts or pages */
/* admin_head-(hookname) */
add_action( 'admin_head-post.php', 'xxx_admin_head_post' );
add_action( 'admin_head-post-new.php', 'xxx_admin_head_post' );
Hi @onoweb , can you look my code or do you have any suggestion about that ? Thanks in advance.
Hello,
Any update here in regards to repeater fields? Everything appears to be working, but when the product page is reloaded the repeater entries appear to not have been saved or not pulling in.
I ran into the same problem. I fixed it bay changing the woocommerce_save_product_variation function to:
add_action('woocommerce_save_product_variation', function ($variation_id, $i = -1) {
if (!empty($_POST['acf']) && is_array($_POST['acf']) && array_key_exists($i, $_POST['acf']) && is_array(($fields = $_POST['acf'][$i]))) {
$unique_updates = array();
foreach ($fields as $key => $val) {
if (is_array($val)) {
// repeater fields need to be parsed separately
foreach ($val as $repeater_key => $repeater_val) {
if (!array_key_exists($repeater_key, $unique_updates) || !empty($repeater_val)) {
$unique_updates[$repeater_key] = $repeater_val;
}
}
} else {
// non-repeater fields can be parsed normally
// The repeater fields are repeated here, but empty. This causes the repeater that was updated above to be cleared
if (!array_key_exists($key, $unique_updates) || !empty($val)) {
$unique_updates[$key] = $val;
}
}
}
// Only update each field once
foreach ($unique_updates as $key => $val) {
update_field($key, $val, $variation_id);
}
}
}, 10, 2);
The problem was that the repeater fields were in the fields array twice. The first time would set it, but the second would clear the repeater again. So I just made sure that each field was only updated once
Hi!
Some who know what i’m doing wrong?
Can’t get the custom tab or field to display for each specific variation, when i choose the variants color and size, the unique description appears, not the tab and field.
It’s unique product User manual links foreach.
Variation custom field code is from this forum and works so far!
Problem is to display when specific variation is active or not, and to hide and display the “Downloads” tab window, when there is or not a download file link in the wysiwyg editor field?
add_filter('acf/location/rule_values/post_type', 'acf_location_rule_values_Post');
function acf_location_rule_values_Post( $choices ) {
$choices['product_variation'] = 'Product Variation';
return $choices;
}
add_action( 'woocommerce_product_after_variable_attributes', function( $loop, $variation_data, $variation ) {
global $abcdefgh_i;
$abcdefgh_i = $loop;
add_filter( 'acf/prepare_field', 'acf_prepare_field_update_field_name' );
$acf_field_groups = acf_get_field_groups();
foreach( $acf_field_groups as $acf_field_group ) {
foreach( $acf_field_group['location'] as $group_locations ) {
foreach( $group_locations as $rule ) {
if( $rule['param'] == 'post_type' && $rule['operator'] == '==' && $rule['value'] == 'product_variation' ) {
acf_render_fields( $variation->ID, acf_get_fields( $acf_field_group ) );
break 2;
}
}
}
}
remove_filter( 'acf/prepare_field', 'acf_prepare_field_update_field_name' );
}, 10, 3 );
function acf_prepare_field_update_field_name( $field ) {
global $abcdefgh_i;
$field['name'] = preg_replace( '/^acf\[/', "acf[$abcdefgh_i][", $field['name'] );
return $field;
}
add_action( 'woocommerce_save_product_variation', function( $variation_id, $i = -1 ) {
if ( ! empty( $_POST['acf'] ) && is_array( $_POST['acf'] ) && array_key_exists( $i, $_POST['acf'] ) && is_array( ( $fields = $_POST['acf'][ $i ] ) ) ) {
foreach ( $fields as $key => $val ) {
update_field( $key, $val, $variation_id );
}
}
}, 10, 2 );
function xxx_admin_head_post() {
global $post_type;
if ($post_type === 'product') {
wp_register_script( 'xxx-acf-variation', get_template_directory_uri() . '/inc/ss.js', array(
'jquery-core',
'jquery-ui-core'
), '1.1.0',
true ); // Custom scripts
wp_enqueue_script( 'xxx-acf-variation' ); // Enqueue it!
}
}
/* actions fired when adding/editing posts or pages */
/* admin_head-(hookname) */
add_action( 'admin_head-post.php', 'xxx_admin_head_post' );
add_action( 'admin_head-post-new.php', 'xxx_admin_head_post' );
Showing the tab:
/* Create Technical details tab */
//adding new tab//
add_filter( 'woocommerce_product_tabs', 'product_tab' );
function product_tab( $tabs ) {
if ( get_field('downloads', $post_id) ) {
$tabs[] = array(
'title' => 'Downloads',
'priority' => 15,
'callback' => 'show_content'
);
}
return $tabs;
}
function show_content() {
$downloads = get_field('downloads', $post_id);
if( $downloads ):
echo get_field('downloads', $post_id);
endif;
}
The settings in the ACF – admin panel is this as attached images below:
the name “Vare” = “Product”
The topic ‘ACF on product variations: almost works’ is closed to new replies.
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.