I found a possibly unstable solution but it seems to work so far without any kind of notices or errors ( as of yet ). It takes advantage of both the relationship query hook to set a specific flag and the posts_clauses
hook to join the postmeta table and search on that. The SQL solution was found via Iconic WP blog post of a similar nature.
/**
* Product relationship field - include searching SKU
*
* @param Array $args
* @param Array $field
* @param Integer $post_id
*
* @return $args
*/
function prefix_product_relationship_query_mods( $args, $field, $post_id ) {
$args['post_status'] = 'publish';
if( ! empty( $args['s'] ) ) {
$args['acf_sku_search'] = true;
}
return $args;
}
add_filter( 'acf/fields/relationship/query/name=field_name', 'prefix_product_relationship_query_mods', 10, 3 );
/**
* Modify the query clauses to search on the postmeta table when asked to :)
*
* @param Array $clauses
* @param WP_Query $query
*
* @return Array $clauses
*/
function prefix_acf_relationship_search_sku( $clauses, $query ) {
global $wpdb;
if( $query->get( 'acf_sku_search', false ) ) {
$clauses['join'] = " LEFT JOIN {$wpdb->postmeta} ON {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id ";
$clauses['where'] = preg_replace(
"/\(\s*{$wpdb->posts}.post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
"({$wpdb->posts}.post_title LIKE $1) OR ({$wpdb->postmeta}.meta_key = '_sku' AND {$wpdb->postmeta}.meta_value LIKE $1)",
$clauses['where']
);
$query->set( 'acf_sku_search', false ); // Set to false just in case.
}
return $clauses;
}
add_filter( 'posts_clauses', 'prefix_acf_relationship_search_sku', 10, 2 );
Thanks very much for your help. Your explanation helped me to understand how hooks work.
It’s actually on the archive page I want to add the ACF so in content-product.php using ‘woocommerce_after_shop_loop_item_title’ should have worked, but my theme (Astra) also seems to be influencing that area, so in the end I hid the title using the theme customiser and then in functions.php
/**
* ADD THE ACF DESCRIPTOR BY REMOVING THE FUNCTION AND REPLACING IT WITH OUR OWN - YOU MUST ALSO HIDE THE TITLE IN ASTRA CUSTOMISER
*/
function sly_switch_loop_title(){
remove_action( 'woocommerce_shop_loop_item_title', 'woocommerce_template_loop_product_title', 10 );
add_action( 'woocommerce_after_shop_loop_item_title', 'sly_template_loop_product_title', 15 );
}
add_action( 'woocommerce_before_shop_loop_item', 'sly_switch_loop_title' );
function sly_template_loop_product_title() {
echo '<h4 class="sly-custom-shop-list-title">' . get_the_title() . '</h4>';
echo get_field( 'descriptor' );
}
WooCommerce has _a literal ton_ of hooks to use. If you open up the plugin folder ( plugins/woocommerce/templates ) you can open up those files and see just how many you can hook into.
The one you’re looking for is in the content-single-product.php
file:
/**
* Display value after single product titles
*
* @return void
*/
function prefix_after_title() {
echo get_field( 'after_title' );
}
add_action( 'woocommerce_single_product_summary', 'prefix_after_title', 6 );
We need the priority of 6 because the file linked above shows that the title is prioritized at 5. If we wanted to display this before the title we would need to change the priority to something before 5.
Same here. I haven’t found a solution yet.
Looks like I’ll have to add it manually. It would be pretty powerful though, to add ACF fields to any WooCommerce email template easily.
Yea sure no problem. I have created several categories with woocommerce. And i linked them with ACF like this:
https://i.imgur.com/k4p1Q7J.png
However when i go to one of these cats, i don’t see the extra fields, i have saved the post like you said. Also at the bottom of the category page there is nothing, it does show some general fields i added to the woocommerce categories with these settings:
https://i.imgur.com/oTzI5rm.png
However these are general fields i need to fill. Those categories are different from the rest and need some additional fields.
Hope i clarified it enough, otherwise just let me know 🙂
I understood. Do you use the ACF for WooCommerce plugin? This can be a problem with the ACF for WooCommerce plugin?
I need to show custom fields in the WooCommerce account and send user data by email.
I got it working using the Wysiwyg Editor to upload the image instead. Thanks for your help.
The final code is
add_action('woocommerce_single_product_summary','finish_image',22);
function finish_image() {
$terms = get_the_terms( $post->ID , 'pa_metal-finish' );
if($terms) {
foreach( $terms as $term ) {
echo '<b>Finish: </b>'. get_field('finish_img', 'pa_metal-finish'.'_'.$term->term_id);
}
}
}
With use of the Wysiwyg Editor for image upload
Sorry I just realized I should have added it as a code
add_action('woocommerce_single_product_summary',"finish_image",22);
function finish_image() {
$terms = get_the_terms( $post->ID , 'pa_metal-finish' );
if($terms) {
foreach( $terms as $term ) {
echo '<b>Finish:</b>'. '<img src= '<?php get_field('finish_img', 'pa_metal-finish'. '_' .$term->term_id);' ?>' />'
}
}
}
I am so close, keep coming up with a parce error. What am I doing wrong here? I know it has something to do with the IMG SRC and quotes
add_action(‘woocommerce_single_product_summary’,”finish_image”,22);
function finish_image() {
$terms = get_the_terms( $post->ID , ‘pa_metal-finish’ );
if($terms) {
foreach( $terms as $term ) {
echo ‘<b>Finish:</b>’. ‘term_id);’ ?>’ />’
}
}
}
Making progress I know have the code working, only shows url still though. need to look though the document above
add_action(‘woocommerce_single_product_summary’,”finish_image”,22);
function finish_image() {
$terms = get_the_terms( $post->ID , ‘pa_metal-finish’ );
if($terms) {
foreach( $terms as $term ) {
echo ‘<b>Finish:</b>’. get_field(‘finish_img’, ‘pa_metal-finish’. ‘_’ .$term->term_id);
}
}
}
I am close though
I have gotten the image url to show back up if I give the full path to a single Attribute.
add_action(‘woocommerce_single_product_summary’,”finish_image”,22);
function finish_image() {
echo ‘<b>Finish:</b>’. get_field(‘finish_img’, ‘pa_metal-finish_79’);
}
But I need the code to search though the metal finish attributes to find the one that applies to that Item.
I know its something like the post found here.
https://support.advancedcustomfields.com/forums/topic/get-field-from-woocommerce-attribute-taxonomy/
but I cant seem to quite figure it out, do you have any insite?
Well I have done some research and have almost got the code working. Currently the code looks like this
add_action(‘woocommerce_single_product_summary’,”finish_image”,22);
function finish_image() {
echo ‘<b>Finish:</b>’ .get_field(‘finish_img’, $product_id);
}
For some reason the image will not show, It just shows the text “array”(not the setting the actual word array). If I change it to URL, It shows the right url and if I change it to Image ID it show the right id.
After playing with the settings more, I can no longer get anything to come up, please help!
Thanks
Jake
When working with WC you more than likely need to use one of their action hooks to show the field where you want it shown on the product page. https://docs.woocommerce.com/wc-apidocs/hook-docs.html
In your action you need to get/show the value by passing ACF the product ID (Post ID), example: get_field('your-field-name', $product_id);
Some of the action hooks pass the product ID and in other cases you’ll need to figure out how to get the ID.
Sooooo…y’all were super helpful before and I was able to apply this filtering to another website as well. All was going swimmingly until the client asked for one more level of sorting, and I’m tearing my hair out trying to figure this out.
So, this is for a choral group. They’re wanting to display all their past seasons, sorted by year/season, and then by performance date (performances are actually individual products in WooCommerce). Sorting by the ACF meta fields is going fine. But within each year, they also want to break it out to sorting all the concerts assigned the ‘cantata-series’ product category, and the ‘masterworks-series’ product category. So, a typical listing would look something like:
2017-2018 SEASON
Cantata Series
* Concert Date 1
* Concert Date 2
Masterworks Series
* Concert Date 1
* Concert Date 2
2016-2017 SEASON
Cantata Series
* Concert Date 1
* Concert Date 2
Masterworks Series
* Concert Date 1
* Concert Date 2
etc. etc. etc.
I was doing fine when it was just sorting by season and then by date. But adding in sorting by category is just throwing me. I can get it to display the correct series before each and every date it applies to, but that’s not right.
Here’s my code right now (not working)
$season_args = array(
'numberposts' => -1,
'post_type' => 'product',
'product_cat' => 'past, cantata-series, masterworks-series',
'meta_query' => array(
'season_clause' => array(
'key' => 'select_season',
'compare' => 'EXISTS',
),
'date_clause' => array(
'key' => 'date',
'compare' => 'EXISTS',
)
),
'orderby' => array(
'season_clause' => 'ASC',
'date_clause' => 'ASC'
)
);
$the_query = new WP_Query($season_args);
if ($the_query->have_posts()) {
// variables to hold values from previous post
$last_season = '';
$last_date = '';
while ($the_query->have_posts()) {
$the_query->the_post();
// get season and compare it to the previous post
$this_season = get_field('select_season');
if ($this_season != $last_season) {
// the season has changed
if ($last_season != '') {
// close the post UL, season DIV, and season DIV that we'll open next
// this will be skipped if this is the first post
// because $last_season will be empty
echo '</div><!-- .season -->';
} ?>
<div class="season">
<h2><?php echo $this_season->post_title; ?></h2>
<?php // clear $last_season
$last_season = '';
// set $last_season to $this_season
$last_season = $this_season; ?>
<?php if ( has_term( 'cantata-series', 'product_cat' ) ) { ?>
<h3>Cantata Series</h3>
<?php }
} // end if new season
// get the date and compare to previous post
$this_date = get_field('date', false, false);
$this_date = new DateTime($this_date); ?>
<?php if ( has_term( 'cantata-series', 'product_cat' ) ) { ?>
<li><?php echo $this_date->format('M j Y'); ?> - <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li> <?php } ?>
<?php } // end while have posts
} // end if have_posts
wp_reset_query();
Thanks in advance.
~Laura
Here is the action and filter I’m using to show on product page and the cart:
function save_my_custom_product_field( $cart_item_data, $product_id ) {
$custom_field_value = get_field( 'install_fee', $product_id, true );
if( !empty( $custom_field_value ) )
{
$cart_item_data['install_fee'] = $custom_field_value;
// below statement make sure every add to cart action as unique line item
$cart_item_data['unique_key'] = md5( microtime().rand() );
}
return $cart_item_data;
}
add_filter( 'woocommerce_get_item_data', 'render_meta_on_cart', 10, 2 );
function render_meta_on_cart( $cart_data, $cart_item ) {
$custom_items = array();
// Woo 2.4.2 updates
if( !empty( $cart_data ) ) {
$custom_items = $cart_data;
}
if( isset( $cart_item['install_fee'] ) ) {
$custom_items[] = array( "name" => "Install Fee $", "value" => $cart_item['install_fee'] );
}
return $custom_items;
}
If the field group did not exist before the import then you can’t make these fields appear by creating a new field group.
And it appears that the fields were not imported to the taxonomy/terms but were imported to the posts. This is why the values do not appear when editing the product category. Since these values are not associated with the term you cannot make them appear in the admin. Quite honestly, I don’t know how they are appearing in the front end.
Importing into a term is a special process http://www.wpallimport.com/documentation/taxonomies/import-taxonomy-meta/
in your code
global $woocommerce, $woocommerce_loop, $product;
$category = get_queried_object();
$ct = $category->name;
$catid = $category->term_id;
the_field('description', $catid); ?>
the value of $catid
is wrong. In order to get a value from a field for the term it would need to be the_field('description', 'term_'.$catid);
so what you are actually seeing on the front end is the values in post meta that are related to a post with the ID that is equal to whatever that the ID of the term is.
There really isn’t an easy solution to this if there is a solution at all. If there is I can’t think of one.
Then this is probably what you want https://docs.woocommerce.com/document/editing-product-data-tabs/
Have you looked at this https://wisdmlabs.com/blog/add-custom-tab-woocommerce-product-page/
Hi James, thanks for looking into this. On further investigation it seems to be a conflict with Woocommerce. The bug does not appear without Woocommerce installed and active, so the steps to reproduce are…
1) install fresh WordPress
2) install ACF Pro
3) install Woocommerce
4) add ACF wysiwyg field to pages
5) add an embeddable youtube video URL to the wysiwyg field on a page (video appears)
6) Save page
Now when you navigate away you get “Changes you made may not be saved.”. Sometimes you have to click on the page (say, to close the ‘page updated’ message) to get the ‘unsaved changes’ message when navigating away, but other times it appears just by reloading via browser address bar.
Disable woocomemrce and the problem goes away. Add the youtube URL to the main content rather than the ACF wysiwyg and the problem does not occur (this only occurs with auto embed URLs in the ACF wysiwyg).
In fact, it needs some additional code to work like a charm :
add_filter('acf/location/rule_match/woocommerce_category', 'acf_location_rules_match_woocommerce_category', 10, 3);
function acf_location_rules_match_woocommerce_category( $match, $rule, $options )
{
global $post;
$terms = get_the_terms( $post->ID, 'product_cat' );
$selected_category = (string) $rule['value'];
if ( $terms && ! is_wp_error( $terms ) ) {
if ( $rule['operator'] == "==" ) {
foreach ( $terms as $term ) {
$match = ( $term->name == $selected_category );
}
} elseif ( $rule['operator'] == "!=" ) {
foreach ( $terms as $term ) {
$match = ( $term->name != $selected_category );
}
}
}
return $match;
}
Hi guys
Thanks for the question. I’m currently working on GDPR documentation and would love to get your input too!
To answer your question, yes, I believe that the ACF plugin is GDPR ready.
The plugin does not collect or process any personal data when installed on a WP website.
The only time when data is collect is when an ACF PRO license is activated. We outline this in our privacy policy:
Usage Information: We collect information about your usage of our Services. For example, we collect information to authenticate a license activation or plugin update. We use this information to, for example, provide our Services to you, as well as get insights on how people use our Services, so we can make our Services better. This information includes the versions of ACF and WP installed, website name, website URL, website language and timezone.
As for the ACF website, we use WooCommerce to handle all store functionality, so there is definitely some personal information stored such as name, email, etc. Please note that we use both PayPal and Stripe to handle payment information – we don’t store any of this.
We use Mailchimp as our email marketing tool, which from what I have read are adding in GDRP settings and sugest sending out a campaign to get people to re ‘opt-in’ for marketing material.
Please feel free to comment below and let me know how you feel about the above, or if you have any advice, concerns or questions.
Once question I am asking, is does ACF require any changes to the ‘Enter License Key’ panel on the ‘Custom Fields > Updates’ page to confirm and acknowledge the specific data to be sent.
Is this going too far, or is this what GDPR is asking for?
Thanks
Elliot
Sorry I didn’t get back to you sooner. I’m not really sure what it is that WooCommerce (WC) is doing here. I think that it can either be showing a product or a sub category as a “shop_loop_item”
You’re also saying this is a category page, but the page starts with global $product;
which would indicate a product page and not a category page. From what I can tell looking at the code you posted you are editing the file that shows products in a loop content-product.php, WC uses a different template for showing sub categories content-product_cat.php. So I’m not really sure what you doing.
FWIW, I kept at it and built my own solution. I need to do another re-read of the documentation page to make sure I’m using both hooks correctly, but it at least works for now.
// Add WooCommerce 'Shop' location rule value
// https://www.advancedcustomfields.com/resources/custom-location-rules/
add_filter('acf/location/rule_values/page_type', 'dc_acf_location_rules_values_woo_shop');
function dc_acf_location_rules_values_woo_shop($choices){
$choices[ 'woo-shop-page' ] = 'WooCommerce Shop Page';
return $choices;
}
// Add WooCommerce 'Shop' location rule match
add_filter('acf/location/rule_match/page_type', 'dc_acf_location_rules_match_woo_shop', 10, 3);
function dc_acf_location_rules_match_woo_shop($match, $rule, $options){
if(is_admin() && $rule['value'] == 'woo-shop-page'){
$post_id = $options['post_id'];
$woo_shop_id = get_option( 'woocommerce_shop_page_id' );
if($rule['operator'] == "=="){
$match = $post_id == $woo_shop_id;
}elseif($rule['operator'] == "!="){
$match = $post_id != $woo_shop_id;
}
}
return $match;
}
This stops the woocommerce loop rendering. It seems to break at:
$child_terms = get_terms($args);
What i’m trying to achieve is that each sub category has a colour. This is defined with the ACF colour picker. That then creates an inline style which gives each subcategory a border, defines button colours etc etc.
The $term = get_queried_object(); works fine inside the woocommerce product loop when viewing the sub category and children of it, but not on the parent, which would essentially show a number of sub categories with there own colours defined by the ACF field.
So this is my current loop thats working on sub categories to help explain better.
global $product;
// Ensure visibility
if ( empty( $product ) || ! $product->is_visible() ) {
return;
}
// Colour Picker Setup
$term = get_queried_object();
$color = get_field('course_colour', $term); // Get ACF Field
//echo $color;
$remove = substr($color, 0, -1); // RGBA for opacity block over image, remove last )
$opacity = $remove . '.8)'; // RGBA for opacity block over image, add .5) to straing
$chop = substr($color, 0, -3); // For inline styles, we need to remove the alpha value
$border = $chop . ')'; // add closing bracket to inline style
//echo $opacity;
?>
<div class="col-md-4">
<div class="product-img">
<?php
/**
* woocommerce_before_shop_loop_item hook.
*
* @hooked woocommerce_template_loop_product_link_open - 10
*/
do_action( 'woocommerce_before_shop_loop_item' );
/**
* woocommerce_before_shop_loop_item_title hook.
*
* @hooked woocommerce_show_product_loop_sale_flash - 10
* @hooked woocommerce_template_loop_product_thumbnail - 10
*/
do_action( 'woocommerce_before_shop_loop_item_title' );
?>
<div class="overlay" style="background-color: <?php echo $opacity; ?>"></div>
</div>
<div class="product-box" style="color: <?php echo $border; ?> !important; border-style: solid; border-width: 4px; border-color: <?php echo $border; ?>">
<div class="type" style="background: <?php echo $border; ?> ">AQA/WJEC LEVEL 3</div>
<?php
/**
* woocommerce_shop_loop_item_title hook.
*
* @hooked woocommerce_template_loop_product_title - 10
*/
do_action( 'woocommerce_shop_loop_item_title' );
?>
<div class="row">
<div class="col-md-6">
<?php
/**
* woocommerce_after_shop_loop_item hook.
*
* @hooked woocommerce_template_loop_product_link_close - 5
* @hooked woocommerce_template_loop_add_to_cart - 10
*/
do_action( 'woocommerce_after_shop_loop_item' );
?>
</div>
<div class="col-md-6">
<?php echo do_shortcode("[ti_wishlists_addtowishlist]"); ?>
</div>
</div>
</div>
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.