Support

Account

Home Forums Backend Issues (wp-admin) ACF on product variations: almost works

Solving

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()?

  • Hi @exnihilo_maxime

    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

  • @johnw6761,

    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 );

  • @johnw6761,

    This sounds weird. It’s like if acf() function was not existing or there was no input property. Sure ACF is activated?

  • @exnihilo_maxime

    Haha yes definitely activated, im pretty stupid but not that stupid lol.

    I did see on another thread someone else having the same issue.

  • @johnw6761

    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?

  • @johnw6761

    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.

  • @penskyc @alicinaroglu

    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”

Viewing 25 posts - 1 through 25 (of 29 total)

The topic ‘ACF on product variations: almost works’ is closed to new replies.