I'm trying to get a list with all woocommerce attributes and values, but only those used for product variations (for example, I want to get "size" and "color" values, but not other attributes used only for information purposes like "fabric" or "weight").
I'm using this code:
$allAttributes = wc_get_attribute_taxonomies();
foreach ($allAttributes as $att) {
$wcAttribute = wc_get_attribute($att->attribute_id);
[...]
}
At this point, I want to check if this $wcAttribute is used for any product variation, to add it to my list or not, but I don't know how to proceed.
Any help?
I respond to myself, because I found a solution. Probably, it isn't the best solution, but it works (if someone has any better solution, I'll appreciate):
function getAllWCAttributes()
{
/* Format for attributes: ['attribute_id' => ['id', 'name', 'values'=>['id', 'name'] ] ]*/
$attributes = array();
$allAttributes = wc_get_attribute_taxonomies();
foreach ($allAttributes as $att) {
if (isAttributeUsedForVariations($att)) {
$wcAttTerms = get_terms('pa_' . $att->attribute_name);
$terms = array();
foreach ($wcAttTerms as $wcTerm) {
$terms[] = array(
'id' => $wcTerm->term_id,
'name' => $wcTerm->name
);
}
$attributes[$att->attribute_id] = array(
'id' => $att->attribute_id,
'name' => $att->attribute_label,
'values' => $terms
);
}
}
return $attributes;
}
function isAttributeUsedForVariations($attribute)
{
$terms = array();
$attTerms = get_terms('pa_' . $attribute->attribute_name);
foreach ($attTerms as $attTerm) {
$terms[] = $attTerm->slug;
}
$args = array(
'post_type' => 'product_variation',
'post_status' => 'publish',
'meta_query' => array(
array(
'key' => 'attribute_pa_' . $attribute->attribute_name,
'value' => $terms,
'compare' => 'IN'
)
)
);
$variationsQuery = new WP_Query($args);
return ($variationsQuery->post_count > 0)? true: false;
}
Documentation:
wc_get_attribute_taxonomies()
get_terms()
WP_Query
Related
I'm trying to use the WordPress REST API for custom posts and useing parameters to filter. I created the parameters course_no, course_cycles and course_type. Those are meta fields of the course posts.
I'm using the rest_course_query filter hook for that. That's the code:
// Add custom field filters for REST API
function chld_thm_post_meta_request_params( $args, $request ) {
$hasFilterCourseNo = false;
$hasFilterCourseCycles = false;
$hasFilterCourseType = false;
// meta query for course number
if ($request['course_no'] != null) {
$hasFilterCourseNo = true;
$courseNoMetaQuery = array(
'key' => 'course_no',
'value' => $request['course_no'],
'compare' => '='
);
}
// meta query for course cycles
if ($request['course_cycles'] != null) {
$hasFilterCourseCycles = true;
$courseCycleMetaQuery = array(
'relation' => 'OR'
);
foreach (explode(",", $request['course_cycles']) as $course_cycle) {
$currentCycle = array(
'key' => 'course_cycles',
'value' => serialize($course_cycle),
'compare' => 'LIKE'
);
array_push($courseCycleMetaQuery, $currentCycle);
}
}
// meta query for course type
if ($request['course_type'] != null) {
$hasFilterCourseType = true;
$courseTypeMetaQuery = array(
'key' => 'course_type',
'value' => $request['course_type'],
'compare' => '='
);
}
$meta_query_args = array(
'relation' => 'AND'
);
if ($hasFilterCourseNo == true) {
array_push( $meta_query_args, $courseNoMetaQuery);
}
if ($hasFilterCourseCycles == true) {
array_push( $meta_query_args, $courseCycleMetaQuery);
}
if ($hasFilterCourseType == true) {
array_push( $meta_query_args, $courseTypeMetaQuery);
}
$meta_query = array(
'meta_query' => $meta_query_args
);
$args = $args + $meta_query; // TODO looks like meta_query is not working here
return $args;
}
add_filter( 'rest_course_query', 'chld_thm_post_meta_request_params', 99, 2 );
Using this I can use the following request: wp-json/wp/v2/course?search=&per_page=100&course_type=non_subsidized
Unfortunately it's not filtering the course_type for non_subsidized here.
This creates a completely fine WP Query using meta_query.
'meta_query' =>
array (size=2)
'relation' => string 'AND' (length=3)
0 =>
array (size=3)
'key' => string 'course_type' (length=11)
'value' => string 'non_subsidized' (length=14)
'compare' => string '=' (length=1)
But for some reason the WordPress REST API doesn't acknowledge the meta_query parameter.
Using meta_key and meta_value instead of meta_query is working fine. But I can't combine different parameters using meta_key and meta_value, so I have to use meta_query.
Does anybody know, why this is not working in WordPress 5.7 and 5.8?
I found the problem. I added an additional meta_query for ordering the posts using pre_get_posts.
The meta_query was overwritten there. Instead of overwriting it, I merged the existing meta_query and now it's working.
$meta_query = $query->get('meta_query');
$meta_query_order = array(
'order_course_date' => array(
'key' => 'course_date_start',
'value' => date("Ymdhi"),
'compare' => '<='
)
);
if (is_array($meta_query)) {
$meta_query_new = array_merge($meta_query, $meta_query_order);
} else {
$meta_query_new = $meta_query_order;
}
$query->set('meta_query', $meta_query_new);
$query->set('orderby', 'order_course_date');
$query->set('order', 'ASC');
I have created woo-commerce product attributes programmatically by the following code:
$data = array(
'name' => 'My attribute',
'slug' => wc_sanitize_taxonomy_name(wp_unslash('My attribute')),
'type' => 'select',
'order_by' => 'menu_order',
'has_archives' => 1
);
wc_create_attribute( $data );
and this code adds attributes successfully and are visible to the list of woo-commerce in Products->Attributes, but after that, I tried adding some terms to them which are not affected to the attribute list by using following code:
wp_insert_term( 'term_1' ,'pa_'.$data['slug']);
also, I confirm that when I dump the result of var_dump(get_term_by('name','term_1','pa_'.$data['slug'])) I get result with term id,name,slug,term_taxonomy_id etc., but the problem it these terms are not visible on the woocommerce product attributes and so does on product editing page.
Because I've searched myself a lot before reaching out to a working solution that works for Woocommerce 3.8+, I give this answer in order others to get help on a really confusing topic such as Woocommerce Attributes.
I've created two methods/functions: createAttribute and createTerm based on the sample code that Woocomerce provides as an example: See code
function createAttribute(string $attributeName, string $attributeSlug): ?\stdClass {
delete_transient('wc_attribute_taxonomies');
\WC_Cache_Helper::incr_cache_prefix('woocommerce-attributes');
$attributeLabels = wp_list_pluck(wc_get_attribute_taxonomies(), 'attribute_label', 'attribute_name');
$attributeWCName = array_search($attributeSlug, $attributeLabels, TRUE);
if (! $attributeWCName) {
$attributeWCName = wc_sanitize_taxonomy_name($attributeSlug);
}
$attributeId = wc_attribute_taxonomy_id_by_name($attributeWCName);
if (! $attributeId) {
$taxonomyName = wc_attribute_taxonomy_name($attributeWCName);
unregister_taxonomy($taxonomyName);
$attributeId = wc_create_attribute(array(
'name' => $attributeName,
'slug' => $attributeSlug,
'type' => 'select',
'order_by' => 'menu_order',
'has_archives' => 0,
));
register_taxonomy($taxonomyName, apply_filters('woocommerce_taxonomy_objects_' . $taxonomyName, array(
'product'
)), apply_filters('woocommerce_taxonomy_args_' . $taxonomyName, array(
'labels' => array(
'name' => $attributeSlug,
),
'hierarchical' => FALSE,
'show_ui' => FALSE,
'query_var' => TRUE,
'rewrite' => FALSE,
)));
}
return wc_get_attribute($attributeId);
}
function createTerm(string $termName, string $termSlug, string $taxonomy, int $order = 0): ?\WP_Term {
$taxonomy = wc_attribute_taxonomy_name($taxonomy);
if (! $term = get_term_by('slug', $termSlug, $taxonomy)) {
$term = wp_insert_term($termName, $taxonomy, array(
'slug' => $termSlug,
));
$term = get_term_by('id', $term['term_id'], $taxonomy);
if ($term) {
update_term_meta($term->term_id, 'order', $order);
}
}
return $term;
}
So they can be used like:
createAttribute('Colors', 'my-colors');
createTerm('Red', 'my-red', 'my-colors', 10);
createTerm('Green', 'my-green', 'my-colors', 20);
createTerm('Blue', 'my-blue', 'my-colors', 30);
i use a Toolset plugin to make view on WP and they give us possibility to manipulate with API.
I try to add argument to my view but it doesn't work.
here is the function :
add_filter( 'wpv_filter_query', 'add_city_tax', 99, 3 );
function add_city_tax( $query_args, $view_settings, $view_id )
{
if($view_id == 7706)
{
$args = array(
'tax_query' => array
(
array
(
[taxonomy] => 'ville',
[field] => 'id',
[terms] => Array
(
[0] => 220
),
[operator] => 'IN'
),
[relation] => 'OR',
),
);
}
$query_args = new WP_Query( $args );
return $query_args;
}
the page make an error
The method you are declaring args is not correct. You should not create array like that. Please check following example.
function add_city_tax( $query_args, $view_settings, $view_id ) {
if($view_id == 7706) {
$args = array(
'tax_query' => array(
array(
'taxonomy' => 'ville',
'field' => 'id',
'terms' => array( 220 ),
'operator' => 'IN',
),
'relation' => 'OR',
),
);
}
$query_args = new WP_Query( $args );
return $query_args;
}
And here doc
Description
When displaying a View listing posts, this filter is applied to the arguments being generated by the View settings before they are passed to the WP_Query class.
Views filters - wpv_filter_query
Note that the filters that you can add to the View are also hooked here, each of them using a different priority that gets up to 100. To ensure that your filter runs after them, you would need to use a higher priority number.
Remember that the filter can take three parameters. If you pass more than one, you need to specify it in your code using the fourth argument:
1
add_filter( 'wpv_filter_query', 'my_callback_function', 99, 3 );
Arguments
array $query_args Τhe query arguments as in WP_Query.
array $view_settings The View settings.
int $view_id The View ID.
No it doesn't work like this.
i have tried like this :
function add_city_tax( $query_args, $view_settings, $view_id ) {
if($view_id == 7706) {
$args = array(
'tax_query' => array(
array(
'taxonomy' => 'ville',
'field' => 'id',
'terms' => array( 220 ),
'operator' => 'IN',
),
'relation' => 'AND',
),
);
}
$query_args[] = $args ;
$msg = '<pre>' . print_r($query_args, true) . '</pre>';
mail('franck#efficonex.fr', 'test', $msg);
return $query_args;
}
add_filter( 'wpv_filter_query', 'add_city_tax', 99, 3 );
But it is the same result without filter.
here is the example of api
//Return only posts from the current author when listing posts of type company:
add_filter( 'wpv_filter_query', 'prefix_show_only_current_author' );
function prefix_show_only_current_author( $query_args ) {
global $current_user;
$types = (array) $query_args['post_type'];
if ( !is_admin() && in_array( 'company', $types ) ) {
$query_args['author'] = empty( $current_user->ID ) ? -1 : $current_user->ID;
}
return $query_args;
}
I want my acf field "unique_field" in my custom post type "places" to be unique.
I used acf/validate_value documented here -> https://www.advancedcustomfields.com/resources/acf-validate_value/
https://support.advancedcustomfields.com/forums/topic/solved-check-if-value-already-exist-2/
I tried to put this on my functions.php but it doesn't work.
add_filter('acf/validate_value/name=unique_field', 'validate_unique_field_filter', 10, 4);
function validate_unique_field_filter($valid, $value, $field, $input) {
if (!$valid || $value == '') {
return $valid;
}
// query posts for the same value
global $post;
$args = array(
'post_type' => 'places',
'post__not_in' => array($post->ID),
'meta_query' => array(
array(
'key' => 'unique_field',
'value' => $value
)
)
);
$query = new WP_Query($args);
if (count($query->posts)) {
$valid = 'Place already exist';
}
return $valid;
}
Are there any mistakes? Please Advise. Thank you!
it is missing 'meta_key' => 'unique_field' in the meta_query array
the filter 'acf/validate_value/name=unique_field' should be 'acf/validate_value/key=field_unique_field'
I need to get all product in a category that match an attribute.
Here my code:
$title = isset($instance['title']) ? $instance['title'] : '';
$car_type = isset($instance['cartype']) ? $instance['cartype'] : 'usato';
$car_brand = isset($instance['carbrand']) ? $instance['carbrand'] : '';
$limit = isset($instance['limit']) ? $instance['limit'] : null;
$order = $instance['order'];
$carousel = $instance['carousel'];
$query_args = [
'post_type' => 'product',
'post_status' => 'publish',
'product_cat' => $car_type
];
// Ordino i risultati
if ($order == 'random') {
$query_args['orderby'] = 'random';
} else {
$query_args['orderby'] = 'name';
$query_args['order'] = $order;
}
// Devo limitare il numero di risultati?
if ($limit) {
$query_args['posts_per_page'] = $limit;
}
if ($car_brand != '') {
$query_args['tax_query'] = array(
array(
'key' => 'pa_marca',
'value' => 'nike',
'field' => 'slug',
'compare' => '='
)
);
}
The problem is that I always get 0 result even if there is a product with that category and that attribute.
How should I modify the query?
It looks you use tax_query instead of meta_query. tax_query is for taxonomie filter.
Try this:
$query_args['meta_query'] => array(
array(
'key' => 'pa_marca',
'value' => 'nike',
'compare' => '=',
),
);
WP_Query#Custom_Field_Parameters
Finally I get the solution, this is how you need to query on an attribute:
$query_args['tax_query'] = array(
array(
'key' => 'pa_brand',
'field' => 'slug',
'terms' => 'nike'
)
);
Note that in the key you need to add pa_ to your attribute name and you need to use terms to specify the value of your attribute.