Webtech, you should just have to change the post type to “product” or whatever woocommerce’s product post type is named.
$args = array(
'post_type' => array('product'), // post types you want to check
'posts_per_page' => -1
);
This is exactly what I’m looking for!
How would I modify it to apply to WooCommerce products?
Thanks!
I have copied content-product_cat.php to my theme Woocommerce folder and tried this answer
/**
* woocommerce_after_subcategory hook.
*
* @hooked woocommerce_template_loop_category_link_close - 10
*/
do_action( 'woocommerce_after_subcategory', $category ); ?>
<?php
$queried_object = get_queried_object();
$taxonomy = $queried_object->taxonomy;
$term_id = $queried_object->term_id;
$thumbnail = get_field('productdesc', $queried_object);
$thumbnail = get_field('productdesc', $taxonomy . '_' . $term_id);
?>
<?php the_field( 'productdesc', $queried_object ); ?>
But it doesnt help. Any help please!
WooCommerce Product Variations are *all* saved via a single POST request.
To differentiate between product variation fields, WooCommerce names each field field_name[variation_id]
so that it is accessible as $_POST['field_name'][$variation_id]
.
ACF field data is located in $_POST['acf'][...]
and can only have one of each field.
ACF’s acf()->input->save_post( $post_id )
method uses $_POST['acf']
data, so it cannot contain fields for another variation.
We need to allow duplicate ACF fields to exist within a single <form>
without having them overwrite each other’s value within $_POST['acf']
.
We can achieve this by renaming the field name prefix acf[...]
to acf_varation[variation_id][...]
and then set $_POST['acf']
to $_POST['acf_varation'][$variation_id]
when saving.
$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);
Ok, in way of an update, I’ve done a bit more investigation and discovered the following. Using <?php echo get_field('custom_bg', $product->ID); ?>
correctly displays the image from the custom field – YAY!
However, this only works on certain products! Right now, during testing, I only have two active Woocommerce products, with IDs 98 and 106. I’ve added some debug code to the page so I know what the current page ID is at any time. When I visit product 106, the debug code correctly shows 106, and the custom_bg field is displayed. And when I visit product 98 I see 98 in the debug code but no custom_bg field displays. What’s most perplexing is when I visit my Woocommerce Shop page, the debug code shows 98.
Is this expected behaviour? Is the ID clash what’s stopping the custom_bg field from displaying?
I’m going to add another product to see if it displays there…
Hi Michael,
Using a custom function hooked to the woocommerce_before_order_itemmeta action hook, you could make it possible to achieve what you are looking for:
add_action( 'woocommerce_before_order_itemmeta', 'storage_location_of_order_items', 10, 3 );
function storage_location_of_order_items( $item_id, $item, $product ){
// Only in backend Edit single Order pages
if( current_user_can('edit_shop_orders') ):
// The product ID (in WooCommerce 3+)
$product_id = $product->get_id();
// Get your ACF product value (replace the slug by yours below)
$acf_value = __('Stored in: ') . get_field( 'BinLocation', $product_id );
// Outputing the value of the "location storage" for this product item
echo '<div class="wc-order-item-custom"><strong>'. $acf_value .'</strong></div>';
endif;
}
HI @pawciak
I am afraid that is currently not possible using the ACF plugin.
You may consider checking out some third party plugins that may help.
Here is an example of a plugin for integrating ACF and WooCommerce
https://wordpress.org/plugins/acf-for-woocommerce/
No problem, just wanted to point in the right direction if you still had issues. The support forums were flooded with posts about plugins that broke when EC updated, WooCommerce, Yoast SEO, just to name a couple of big ones. Basically any plugin that used Select2 js library. I have no idea what the actual issue was, but I know they fixed it with the patch pretty quickly.
The first thing is that query changes like this should only be set on the main query. This is done in the second part, but not on the first.
function altered_search($query) {
if($query->is_admin) {
// hotfix - wordpress consider all ajax calls as is_admin call
// on fronend logged users could see only their items/events
// TODO: replace by filter where I can register all custom ajax actions/handlers
if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'get-items:getHeaderMapMarkers') {
return $query;
}
if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'get-items:retrieve') {
return $query;
}
// ADD THIS AND TEST
if (!$query->is_main_query()) {
return;
}
/* Display posts in admin for current user only */
$wp_user = wp_get_current_user();
if(isCityguideUser($wp_user->roles)){
$query->set('author', $wp_user->data->ID);
}
} else {
if($query->is_main_query()){
if (isset($_GET['s']) && empty($_GET['s'])){
$query->is_search = true;
}
// is woocommerce search
if(isset($query->query_vars['post_type']) && $query->query_vars['post_type'] == 'product'){
return $query;
}
$query = apply_filters( 'ait_alter_search_query', $query );
}
}
return $query;
}
Hi John,
thank you very much for your efforts, here is the hole part, hope you can help 🙂
/* CUSTOM CITYGUIDE FUNCTIONS */
function isCityguideUser($wp_roles = array()){
$result = false;
if(count($wp_roles) == 0){
$wp_user = wp_get_current_user();
$wp_roles = $wp_user->roles;
}
foreach ($wp_roles as $index => $role) {
if(strpos($role, 'cityguide_') !== false){
$result = true;
}
}
return $result;
}
/*****************************************************************************/
/****** PLEASE KEEP HERE ONLY CODE WHICH IS COMON FOR ALL GUIDE THEMES *******/
/******** CUSTOM pre_get_posts FILTERS ARE IN ait-custom-functions.php ********/
/*****************************************************************************/
function altered_search($query) {
if($query->is_admin) {
// hotfix - wordpress consider all ajax calls as is_admin call
// on fronend logged users could see only their items/events
// TODO: replace by filter where I can register all custom ajax actions/handlers
if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'get-items:getHeaderMapMarkers') {
return $query;
}
if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'get-items:retrieve') {
return $query;
}
/* Display posts in admin for current user only */
$wp_user = wp_get_current_user();
if(isCityguideUser($wp_user->roles)){
$query->set('author', $wp_user->data->ID);
}
} else {
if($query->is_main_query()){
if (isset($_GET['s']) && empty($_GET['s'])){
$query->is_search = true;
}
// is woocommerce search
if(isset($query->query_vars['post_type']) && $query->query_vars['post_type'] == 'product'){
return $query;
}
$query = apply_filters( 'ait_alter_search_query', $query );
}
}
return $query;
}
add_filter('pre_get_posts', 'altered_search');
By default, ACf Fields do not work with WooCommerce variations, as they are loaded dynamically, separate to the way normal post meta fields are loaded.
I posted my solution to the issue here, where I used a couple of actions and a filter to manually display and save matching ACF fields for variations.
I was able to add ACF fields to woocommerce product variations using only a couple of actions and a filter.
// Render fields at the bottom of variations - does not account for field group order or placement.
add_action( 'woocommerce_product_after_variable_attributes', function( $loop, $variation_data, $variation ) {
global $abcdefgh_i; // Custom global variable to monitor index
$abcdefgh_i = $loop;
// Add filter to update field name
add_filter( 'acf/prepare_field', 'acf_prepare_field_update_field_name' );
// Loop through all field groups
$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 ) {
// See if field Group has at least one post_type = Variations rule - does not validate other rules
if( $rule['param'] == 'post_type' && $rule['operator'] == '==' && $rule['value'] == 'product_variation' ) {
// Render field Group
acf_render_fields( $variation->ID, acf_get_fields( $acf_field_group ) );
break 2;
}
}
}
}
// Remove filter
remove_filter( 'acf/prepare_field', 'acf_prepare_field_update_field_name' );
}, 10, 3 );
// Filter function to update field names
function acf_prepare_field_update_field_name( $field ) {
global $abcdefgh_i;
$field['name'] = preg_replace( '/^acf\[/', "acf[$abcdefgh_i][", $field['name'] );
return $field;
}
// Save variation data
add_action( 'woocommerce_save_product_variation', function( $variation_id, $i = -1 ) {
// Update all fields for the current variation
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 );
Adding this code as is to your theme’s functions.php file should enable this functionality for all product variation field groups. The only drawback is that it doesn’t check for more complex rules, and the order and position of field groups are not taken into consideration.
John thanks for your valuable input. It’s true that I load them on page load for now, as I’m beta testing it right now.. Most probably, it will be a cron-job done in every 10-15 minutes when the project is up separate from the wordpress or woocommerce loop.
Right now, I’m planning to add if else function within the row addition.. I’ll parse the full code once it works perfectly 😉
Will the removal of the metabox cause any problems?
I code all my themes using only ACF, so it’s no problem for pages and posts, but what about WooCommerce? Isn’t WooCommerce using the built in metabox?
What are the downsides, if any, for disabling it by default?
@beee using save_post and update_post_meta doesn’t mean you’re wrong or doing it the wrong way, those are built in WordPress functions which might never ever change so I wouldn’t worry too much about it. I have an extension for WooCommerce which I still use some default WordPress functions instead of the WooCommerce ones and I know WooCommerce might update and deprecate their functions while WordPress core most likely wont.
Hi James
In this case, how shall we hide that tab or remove that tab if get_field('fieldname', $post_id);
is empty.
Sorry to bother you, I found the solution:
//adding new tab//
add_filter( 'woocommerce_product_tabs', 'product_tab' );
function product_tab( $tabs ) {
if ( get_field('fieldname', $post_id) ) {
$tabs[] = array(
'title' => 'Specifications',
'priority' => 15,
'callback' => 'show_content'
);
}
return $tabs;
}
function show_content() {
$downloads = get_field('fieldname', $post_id);
if( $downloads ):
echo get_field('fieldname', $post_id);
endif;
}
Oh ok, then this code won’t work because what this does is to display a banner image in the product Category page, as in website-url/product-category/computers, is different to what you want to do.
In this case, I’d use a plugin to add custom badges, I’ve used this one and it works ok.
Are you using WooCommerce? https://support.advancedcustomfields.com/forums/topic/relationship-user-field-cant-see-administrator-users/
@plinth Hi, This is what I have in my code today :
$bgimg = get_field('bg_img');
if(is_woocommerce()){
$bgimg = get_field('bg_img', 75);
}
So as time passed, I guess the is_woocommerce() replace the is_archive(MY-ARCHIVE-ID) and cehck if I’m on a woocommerce page.
Tell me if it solve your issue.
@trouille2 I’m having this issue too, but I can’t get your fix to work. The field I want to call is being used a bit like a featured image, and it lives in the header file. I’ve made a new header called ‘header-shop.php’ and I’m calling this on my Woocommerce shop page. However it’s not pulling in the correct field.
In your example above, how did you get the ‘MY-ARCHIVE-ID’? I know the page id, but not the archive id.
Thanks
Hi @avegas
Please change your code to:
add_filter( 'woocommerce_page_title', 'custom_title' );
function custom_title( $title ) {
$title = get_field("h1_title", "product_cat_" . $product_cat_object->term_id);
return $title;
}
I tried but there seems to be no way to make an ACF field group display inside a WooCommerce product data tab in admin. So I resorted to a jQuery hack. It’s “ugly” but it works. The short answer is:
$("#source").appendTo("#destination");
The long answer is, create a new custom product data tab as a placeholder:
// Register New Product Data Tab
add_filter( 'woocommerce_product_data_tabs', 'add_custom_product_data_tab' );
function add_custom_product_data_tab( $tabs ) {
$tabs['my-custom-tab'] = array(
'label' => 'Dates & Times',
'target' => 'my_custom_product_data',
);
return $tabs;
}
// Create Product Data Tab Content
add_action( 'woocommerce_product_data_panels', 'add_custom_product_data_fields' );
function add_custom_product_data_fields() {
echo '<div id="my_custom_product_data" class="panel woocommerce_options_panel"></div>';
}
Then add some JS & CSS to admin:
// Add JS & CSS to move and style ACF fields inside Product Data Tab
function admin_style() {
wp_enqueue_script('admin-script', get_template_directory_uri() . '/js/admin.js', array( 'jquery' ) );
wp_enqueue_style('admin-styles', get_template_directory_uri().'/css/style-admin.css');
}
add_action('admin_enqueue_scripts', 'admin_style');
My ‘admin.js’ file script looks like this:
jQuery(document).ready(function($) {
$("#acf-group_5988b10b578ea").appendTo("#my_custom_product_data");
});
And my ‘admin-style.css’ file looks like this:
#my_custom_product_data {
padding: 13px;
}
#my_custom_product_data .acf-label {
margin: 0;
}
#my_custom_product_data .acf-label label {
font-weight: 400;
font-size: 12px;
}
All this does is move the ACF field group from one div to another using jQuery and adds some CSS to iron out some ACF and WOO style conflicts (i.e. make the ACF panel look more like the WOO-native panels)
Thanks @john huebner
I did try that but in the end had to leave this option. Once the main WooCommerce form was triggered, it would then come up with a leave this page error, I assume it’s because I had the ACF form as well
Many thanks for your reply though
Thanks for the reply @hube2. I’m getting that value from a field in the backend that is a drop-down selector. This selects from a post type called ‘Sidebars’. The idea is that you can create any number of sidebars, add content into them, then add them onto any page from the drop-down. As I mentioned, this works 100% on any standard page outside of Woocommerce.
In answer to your second question, the example I pasted above is in the generic sidebar.php file which is pulled into all page templates. It’s not wrapped in any kind of post loop.
Thanks
I did experiment:
– fresh install, latest versions of components – WP 4.7.5, Woocommerce 3.0.7 and ACF 5.5.14;
– extremely minimal theme, with empty index.php, empty style.css, and function.php file with content for creating custom product type:
// initial actions
function custom_init() {
// add custom product type term
add_custom_product_type_term();
// custom product type class
class WC_Product_Test extends WC_Product {
public function __construct($product) {
$this->product_type = 'test';
parent::__construct($product);
}
}
}
add_action('init', 'custom_init');
// add custom product type to product type selector
function custom_product_type_selector ($types) {
$types['test'] = 'Test';
return $types;
}
add_filter('product_type_selector', 'custom_product_type_selector');
// add custom product type term
function add_custom_product_type_term() {
$product_types_existing = get_terms(array(
'taxonomy' => 'product_type'
,'hide_empty' => false
));
$exists = false;
foreach ($product_types_existing as $pte)
if ($pte->slug == 'test')
$exists = true;
if (!$exists)
wp_insert_term('test', 'product_type');
}
– two product categories (‘Category 1’ and ‘Category 2’) and two tags (‘Tag 1’ and ‘Tag 2’);
– field group created, for post type ‘product’ with product_type ‘test’;
– field group created, for post type ‘product’ with tag ‘Tag 1’;
I run same actions:
1. Creating / editing product: on product type ‘Test’ select / deselect, corresponding acf group doesn’t appears / disappears.
No PHP errors logged. Console shows nothing.
2. Creating / editing product: on adding / removing tag ‘Tag1’, corresponding acf group doesn’t appears / disappears.
No PHP errors logged. Console shows nothing.
3. Editing product with type ‘test’, acf group is visible. Selecting / deselecting product categories causes acf group disappearing.
Initial state – both categories are selected.
After one category deselected, ajax fires with form data:
post_id:668
post_taxonomy[]:
post_taxonomy[]:15
action:acf/post/get_field_groups
exists[]:group_593352f539930
exists[]:group_58a595ba1534b
nonce:55b5acd041
Response:
{"success":true,"data":[]}
After one category selected, ajax fires with form data:
post_id:668
post_taxonomy[]:
post_taxonomy[]:15
post_taxonomy[]:16
action:acf/post/get_field_groups
nonce:55b5acd041
Response:
{"success":true,"data":[]}
After other category deselected, ajax fires with form data:
post_id:668
post_taxonomy[]:
post_taxonomy[]:16
action:acf/post/get_field_groups
nonce:55b5acd041
Response:
{"success":true,"data":[]}
Disappearing of acf groups, when adding / removing product image, or adding / removing tag – such behavior is not observed yet.
So for the moment the biggest issue still exists, and it seems, that ajax call with action ‘acf/post/get_field_groups’ causes the problem. Am I right?
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.