Query to get Attributes based on Product Category selected in WooCommerce? - wordpress

I need to implement custom functionality like "Product filter by Attributes" widget works in woocommerce.
For example in Product category page:
In Parent Category like Clothing, it loads all the attributes filter (pa_color , pa_size).
Now, when you check sub-category of that parent category i.e., Hoodies. It gets filtered and loads only related attributes (pa_color).
Please suggest the query to achieve this requirement.

This is how I am getting the data as per my requirement :
$filter_raw = array();
$attrs_raw = wc_get_attribute_taxonomy_names(); // Getting data of attributes assign in backend.
$cat_name = get_term($request['category'], 'product_cat', ARRAY_A ); //Category data by category ID.
$args = array(
'category' => array($cat_name['slug'] )
);
foreach( wc_get_products($args) as $product ){
foreach( $product->get_attributes() as $attr_name => $attr ){
$filter_raw[] = $attr_name;
if(is_array($attr->get_terms())){
foreach( $attr->get_terms() as $term ){
$terms_raw[] = $term->name;
}
}
}
}
$filters = array_unique(array_intersect((array)$filter_raw,(array)$attrs_raw)); //Filtering the attributes used by products in particular category
if(is_array($filters)){
foreach ( $filters as $filter ){
$terms = get_terms( $filter );
if ( ! empty( $terms ) ) {
$return['items'][ $filter ] = array(
'id' => $filter,
'type' => 'checkbox',
'label' => $this->decode_html( wc_attribute_label( $filter ) ),
);
foreach ( $terms as $term ) {
if(in_array($term->name,$terms_raw)){ //Filtering the terms from attribute used by the products in a category and showing required result.
$return['items'][ $filter ]['values'][] = array(
'label' => $this->decode_html( $term->name ),
'value' => $term->slug,
);
}
}
}
}
}
print_r($return);

Related

WooCommerce to update newest group of attributes

I need to programmatically update a product attributes with the current value and found a very useful answer to do just that. However, it seems that in order for the attributes to be added, the terms must be defined first. So I added a wp_insert_term function to add new the terms before updating the attributes. The code works great but it keep appending the new attributes whereas it should only have newest value only. Please advice me if you have a solution.
$product_id = 11874;
$attributes_data = array(
array('name'=>'Size', 'options'=>array('S', 'L', 'XL', 'XXL'), 'visible' => 1, 'variation' => 1 ),
array('name'=>'Color', 'options'=>array('Red', 'Blue', 'Black', 'White'), 'visible' => 1, 'variation' => 1 )
);
if( sizeof($attributes_data) > 0 ){
$attributes = array(); // Initializing
// Loop through defined attribute data
foreach( $attributes_data as $key => $attribute_array ) {
if( isset($attribute_array['name']) && isset($attribute_array['options']) ){
// Clean attribute name to get the taxonomy
$taxonomy = 'pa_' . wc_sanitize_taxonomy_name( $attribute_array['name'] );
$option_term_ids = array(); // Initializing
// Loop through defined attribute data options (terms values)
foreach( $attribute_array['options'] as $option ){
if( !term_exists( $option, $taxonomy ) ){
wp_insert_term($option, $taxonomy);
}
// Save the possible option value for the attribute which will be used for variation later
wp_set_object_terms( $product_id, $option, $taxonomy, true );
// Get the term ID
$option_term_ids[] = get_term_by( 'name', $option, $taxonomy )->term_id;
}
}
// Loop through defined attribute data
$attributes[$taxonomy] = array(
'name' => $taxonomy,
'value' => $option_term_ids, // Need to be term IDs
'position' => $key + 1,
'is_visible' => $attribute_array['visible'],
'is_variation' => $attribute_array['variation'],
'is_taxonomy' => '1'
);
}
// Save the meta entry for product attributes
update_post_meta( $product_id, '_product_attributes', $attributes );
}

Woocommerce sync grouped product attributes with childrens

To achieve this, i have written 2 functions one for grouped product save and another for child product save.
1 - Adding all child attributes to the grouped product on grouped product save:
add_action('woocommerce_after_product_object_save', 'nd_update_group_product_attributes_before_save_func', 9993, 2);
function nd_update_group_product_attributes_before_save_func($product, $data_store) {
// echo 'has category <pre>';var_dump($product); echo '</pre>';die;
// exit if not the target post type
if ('product' !== $product->post_type) {
return;
}
// $product_type = $product->get_type();
$product_type = $product->post_type;
if ($product->is_type('grouped')) {
$group_product_id = $product->get_id();
nd_sync_child_attribute_to_group($group_product_id, 'pa_bedrooms');
}
}
function nd_sync_child_attribute_to_group($group_product_id, $attribute_slug){
$group_product = wc_get_product($group_product_id);
$child_product_ids = $group_product->get_children();
$all_child_attributes = array();
if($child_product_ids){
foreach ($child_product_ids as $child_product_id) {
$child_product = wc_get_product($child_product_id);
$child_attributes = wc_get_product_terms( $child_product_id, $attribute_slug, array( 'fields' => 'names' ) );
$all_child_attributes = array_unique(array_merge($all_child_attributes, $child_attributes));
}
}
if ($all_child_attributes) {
$group_attributes = wc_get_product_terms( $group_product_id, $attribute_slug, array( 'fields' => 'names' ) );
if($group_attributes){
wp_remove_object_terms( $group_product_id, $group_attributes, $attribute_slug );
}
foreach ($all_child_attributes as $attr) {
wp_set_object_terms($group_product_id, $attr, $attribute_slug, true);
}
}
}
2 - Adding all child attributes to the grouped product on child product save by triggering grouped product save.
add_action('woocommerce_update_product', 'nd_update_group_product_attributes_on_child_update', 1002, 2);
function nd_update_group_product_attributes_on_child_update($product_id) {
$product = wc_get_product( $product_id );
// exit if not the target post type
if ( !$product->is_type('simple') || !has_term( 'home-design-floor-plans', 'product_cat' , $product_id )) {
return;
}
if ( $product->is_type('simple') ) {
$children_id = $product->get_id();
$group_args = array(
'post_type' => 'product',
'meta_query' => array(
array(
'key' => '_children',
'value' => 'i:' . $product->get_id() . ';',
'compare' => 'LIKE',
)
),
'fields' => 'ids' // THIS LINE FILTERS THE SELECT SQL
);
$parent_ids = get_posts( $group_args );
if($parent_ids){
foreach ($parent_ids as $parent_grouped_id){
if($parent_grouped_id){
$parent_product = wc_get_product( $parent_grouped_id );
if($parent_product){
$parent_product->save();
}
}
}
}
}
}
I have an issue with this once I add an attribute value to a grouped product, it was not showing on the admin area group product edit > attributes.
Is there anything I missed or is there any better way to achieve this?
All I want is to sync child product attributes to parent i.e. group product.

How to Populate a Drop-down field in WP

I have a gravity form form on my WP site and I recently changed a free text field into a drop down field.
The website is a store which hold several categories of goods and I want my drop-down to show the user all the possible categories he can choose from.
Please assist in how to "pull" the categories into the drop-down list.
Thanks in advance.
You can do using some filters of gravity form, code is following
// Here 1 is form id
add_filter( 'gform_pre_render_1', 'populate_category' );
add_filter( 'gform_pre_validation_1', 'populate_category' );
add_filter( 'gform_pre_submission_filter_1', 'populate_category' );
add_filter( 'gform_admin_pre_render_1', 'populate_category' );
function populate_category( $form ) {
foreach ( $form['fields'] as &$field ) {
if ( $field->type != 'select' || strpos( $field->cssClass, 'populate-category' ) === false ) {
continue;
}
// Get category list
$categories = get_categories( array(
'orderby' => 'name',
'order' => 'ASC'
) );
$choices = array();
foreach( $categories as $category ) {
$choices[] = array( 'text' => $category->name, 'value' => $category->name );
}
$field->placeholder = 'Select a Category';
$field->choices = $choices;
}
return $form;
}
This is working perfectly its tested code.

Show all terms excluding the current page

The following lists all of the terms, can I get help revising it so that it shows all terms except the the active/current page? Thank you.
$terms = get_terms( 'topics', array(
'orderby' => 'name',
'order' => 'ASC',
));
if ( ! empty( $terms ) ){
foreach ( $terms as $term ) {
$term_thumb = get_field('image', $term);
echo '<li><img src="' .$term_thumb['url']. '"><span class="model">'.$term->name .'</span></li>';
}
}
You can do something like this:
// create an empty array holder
$current_tax_ids = array();
// get the post terms
$current_tax = get_the_terms( $post->ID, 'topics' );
// creating loop to insert ids
foreach( $current_tax as $tax ) {
$current_tax_ids[] = $tax->term_id;
}
$args = array(
'taxonomy' => 'topics',
'hide_empty' => 0,
'exclude' => $current_tax_ids // exclude the terms
);
// get all the terms
$all_terms = get_terms($args);
// now do whatever you want
so if you follow my comments it should be clear, but basically you want to get the current post terms and store the id in an array, then simply exclude the ids when you do get_terms .

List authors that have written certain number of posts in category/tags in Wordpress

I'm struggling to get the list of authors on the category page. I need to list the authors who have written at least 5 articles in that category.
I need something like this in tags also.
Any idea how to do this in wordpress?
Its only possible with a custom SQL query so here is a simple function which should return an array with user id's of users with at least $n posts in the current term archive, which means it should work in categories, tags and custom taxonomies
function get_authors_with($num = 5){
global $wpdb;
$term_slug = get_query_var( 'term' );
$taxonomyName = get_query_var( 'taxonomy' );
$current_term = get_term_by( 'slug', $term_slug, $taxonomyName );
$sub_q = $wpdb->prepare("SELECT * FROM $wpdb->posts
INNER JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id)
INNER JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)
WHERE ($wpdb->term_taxonomy.term_id = %s
AND $wpdb->term_taxonomy.taxonomy = '%s'
AND $wpdb->posts.post_type = 'post'
AND $wpdb->posts.post_status = 'publish')",
$current_term->term_id,
$taxonomyName
);
$sql = $wpdb->prepare("SELECT $wpdb->posts.post_author, FROM (%s)
GROUP BY $wpdb->posts.post_author
HAVING count(*) > %s",
$sub_q,
$num
);
return $wpdb->get_results($sql);
}
Try this.
function list_author_in_this_cat ($with) {
if (is_category()) {
$current_category = get_query_var('cat');
$args = array(
'numberposts' => -1,
'category' => $current_category,
'orderby' => 'author',
'order' => 'ASC'
);
} else {
$tag_id = get_query_var('tag_id');
$args = array(
'numberposts' => -1,
'tag__in' => $tag_id,
'orderby' => 'author',
'order' => 'ASC'
);
}
$cat_posts = get_posts($args);
$author_id_array = array();
$user_posts = array();
foreach( $cat_posts as $cat_post ):
$user_posts[$cat_post->post_author][] = $cat_post->ID;
endforeach;
foreach( $user_posts as $key => $user_post ):
$user_post = array_unique($user_post);
$count_user_posts[$key] = count($user_post);
if ($count_user_posts[$key] >= $with) {
$author_id_array[] = $key;
}
endforeach;
return $author_id_array; }
In your theme files, place this code wherever you want the list of authors to be displayed:
if (is_category() || is_tag()) {
$at_least = 5; // at least 5 articles in current category or tags
$author_array = list_author_in_this_cat ($at_least);
foreach (array_slice($author_array, 0, 4) as $author) : // limit 4 results
$name = get_userdata($author)->display_name;
$link = get_userdata($author)->user_login;
echo "<a href='/author/".$link."'>".$name."</a>\n";
endforeach;
}
Add the following code to your theme's function.php
function get_authors_in_category ( $category_id, $min_posts ) {
$posts = get_posts( array( 'numberposts' => 1000, 'category' => $category_id ) );
$author_count = array();
foreach ($posts as $post) {
if( array_key_exists( get_the_author_meta( 'display_name', $post->post_author ), $author_count ) ) {
$author_count[get_the_author_meta( 'display_name', $post->post_author )]++;
} else { $author_count[get_the_author_meta( 'display_name', $post->post_author )] = 1; }
}
$authors = array();
foreach ( $author_count as $author_name => $count ) {
if ( $min_posts <= $count ) {
$authors[] = $author_name;
}
return $authors;
}
This function as you can see returns an array of authors who have a minimum number of posts in a category. Category ID has to be passed, this can be obtained using the wordpress function get_cat_ID.
You can call this function from any where in the theme and display the authors as you wish.
Note: This is a more resource intensive than the custom SQL functions. Also this function might have some errors, I typed it here and didn't test it.
I did some simple coding with query post method.,
<?php
$cur_cat_id = get_cat_id(single_cat_title("",false));
$posts=query_posts("cat=$cur_cat_id&order=ASC");
foreach($posts as $post){
$number_of_posts = number_format_i18n(get_the_author_posts($post->post_author));
if($number_of_posts>5)
{
echo the_author_meta('user_nicename',$post->post_author)."(".number_format_i18n(get_the_author_posts($post->post_author)).")<br>";
}
}
?>
I think this may help you to resolve your problem.

Resources