Woocommerce sync grouped product attributes with childrens - wordpress

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.

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

How to programmatically set the product attribute variation price in woocommerce?

I have a product attribute variation which has options of -
small - $20
medium - $25
large - $30
Since all the products in the store has the same price for this variations.
How to set the price for the attribute values programmatically?
3 attribute variation buttons are show on product page when I add them as variations.
How to change the price of product when "small" option is selected programmatically instead of setting price in variation options in admin panel.
As Per our understanding to want to add products with different sizes and different prices.
There is 2 way:
1. You can add from woocommerece dashboard like this:
https://www.ostraining.com/blog/woocommerce/product-variations/
You can add programmatically like this:
function insert_product ($product_data)
{
$post = array( // Set up the basic post data to insert for our product
'post_author' => 1,
'post_content' => $product_data['description'],
'post_status' => 'publish',
'post_title' => $product_data['name'],
'post_parent' => '',
'post_type' => 'product'
);
$post_id = wp_insert_post($post); // Insert the post returning the new post id
if (!$post_id) // If there is no post id something has gone wrong so don't proceed
{
return false;
}
update_post_meta($post_id, '_sku', $product_data['sku']); // Set its SKU
update_post_meta( $post_id,'_visibility','visible'); // Set the product to visible, if not it won't show on the front end
wp_set_object_terms($post_id, $product_data['categories'], 'product_cat'); // Set up its categories
wp_set_object_terms($post_id, 'variable', 'product_type'); // Set it to a variable product type
insert_product_attributes($post_id, $product_data['available_attributes'], $product_data['variations']); // Add attributes passing the new post id, attributes & variations
insert_product_variations($post_id, $product_data['variations']); // Insert variations passing the new post id & variations
}
function insert_product_attributes ($post_id, $available_attributes, $variations)
{
foreach ($available_attributes as $attribute) // Go through each attribute
{
$values = array(); // Set up an array to store the current attributes values.
foreach ($variations as $variation) // Loop each variation in the file
{
$attribute_keys = array_keys($variation['attributes']); // Get the keys for the current variations attributes
foreach ($attribute_keys as $key) // Loop through each key
{
if ($key === $attribute) // If this attributes key is the top level attribute add the value to the $values array
{
$values[] = $variation['attributes'][$key];
}
}
}
$values = array_unique($values); // Filter out duplicate values
wp_set_object_terms($post_id, $values, 'pa_' . $attribute);
}
$product_attributes_data = array(); // Setup array to hold our product attributes data
foreach ($available_attributes as $attribute) // Loop round each attribute
{
$product_attributes_data['pa_'.$attribute] = array( // Set this attributes array to a key to using the prefix 'pa'
'name' => 'pa_'.$attribute,
'value' => '',
'is_visible' => '1',
'is_variation' => '1',
'is_taxonomy' => '1'
);
}
update_post_meta($post_id, '_product_attributes', $product_attributes_data); // Attach the above array to the new posts meta data key '_product_attributes'
}
function insert_product_variations ($post_id, $variations)
{
foreach ($variations as $index => $variation)
{
$variation_post = array( // Setup the post data for the variation
'post_title' => 'Variation #'.$index.' of '.count($variations).' for product#'. $post_id,
'post_name' => 'product-'.$post_id.'-variation-'.$index,
'post_status' => 'publish',
'post_parent' => $post_id,
'post_type' => 'product_variation',
'guid' => home_url() . '/?product_variation=product-' . $post_id . '-variation-' . $index
);
$variation_post_id = wp_insert_post($variation_post); // Insert the variation
foreach ($variation['attributes'] as $attribute => $value) // Loop through the variations attributes
{
$attribute_term = get_term_by('name', $value, 'pa_'.$attribute); // We need to insert the slug not the name into the variation post meta
update_post_meta($variation_post_id, 'attribute_pa_'.$attribute, $attribute_term->slug);
}
update_post_meta($variation_post_id, '_price', $variation['price']);
update_post_meta($variation_post_id, '_regular_price', $variation['price']);
}
}
function insert_products ($products)
{
if (!empty($products)) // No point proceeding if there are no products
{
array_map('insert_product', $products); // Run 'insert_product' function from above for each product
}
}
$json = file_get_contents('product-data.json'); // Get json from sample file
// $products_data = json_decode($json_file, true); // Decode it into an array
echo json_last_error();
// if(get_magic_quotes_gpc()){
// $d = stripslashes($json);
// }else{
// $d = $json;
// }
$d = json_decode($d,true);
$products_data = json_decode( preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $json), true );
echo "<h1>json</h1>";
echo "<pre>";
print_r($json);
echo "</pre>";
echo "<h1>Product data</h1>";
echo "<pre>";
var_dump($products_data);
echo "</pre>";
insert_products($products_data);
Where $product_data sample:
$product_data = array(
'sku' => '123SKU',
'categories' => array('size', 'color'),
'available_attributes' => array('size', 'color'),
'variations' => array(
'size' => array(
'attributes' => array( 'XL', 'M', 'S' ),
),
'color' => array(
'attributes' => array( 'Blue', 'Red', 'Green' )
)
)
)
insert_products($products_data);
Note: You can create product-data.json and import product or you can create $product_data = (); and set on insert_products() function.
For Aditional Info:
You can also check this URL for more info https://newbedev.com/create-programmatically-a-woocommerce-product-variation-with-new-attribute-values

WooCommerce apply coupon depends of cart line item quantity

After long looking, I was not able to find any proper code how would be possible to apply coupon for a cart line items. Lets say customer added some product quantity of 10, my selected coupon should be applied for that product. If he adds another product with quantity more than 10, again same coupon should to be applied for that product.
Any assistance here?
I was able to find something similar but this only works for specific products id, any assistance how to update this code to go through each cart products ,check their quantities and apply coupon for products which quantity is 10 or more?
Reference for similar code but only for specific products:
Conditionally apply coupons automatically for specific Product IDs and quantities
Image example:
tried to create a custom solution for my question below. And did it in some way, not sure if this is proper and good option, but it at least work for me as exactly I need. This creates a separate coupon for every product in a shop (if newly product added it creates an unique coupon for it as well). Coupons is applied automatically per cart line item, if product quantity is 10 or more in a cart. It gives a 10% discount for that product. Code as per below, maybe for someone will be useful as I couldn't find any plugins or codes to work like this anywhere...
$args = array(
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'asc',
'post_type' => 'shop_coupon',
'post_status' => 'publish',
);
$all_coupons = get_posts( $args );
// Loop through the available coupons
foreach ( $all_coupons as $coupon ) {
// Get the name for each coupon and add to the previously created array
$coupon_name = $coupon->post_title;
}
foreach ($all_coupons as $coupon) {
$coupons_array[] = $coupon->post_title;
}
$all_ids = get_posts( array(
'post_type' => 'product',
'numberposts' => -1,
'post_status' => 'publish',
'fields' => 'ids',
) );
foreach ( $all_ids as $id ) {
$product_id_array[] = $id;
}
// Get values from arr2 and arr1 unique
$output = array_merge(array_diff($coupons_array, $product_id_array), array_diff($product_id_array, $coupons_array));
function coupon_exists($coupon_code) {
global $wpdb;
$sql = $wpdb->prepare( "SELECT post_name FROM $wpdb->posts WHERE post_type = 'shop_coupon' AND post_name = '%s'", $coupon_code );
$coupon_codes = $wpdb->get_results($sql);
if (count($coupon_codes)> 0) {
return true;
}
else {
return false;
}
}
foreach ($output as $o) {
if (is_numeric($o)) {
if (!coupon_exists($o)) {
generate_coupon($o);
}
}
}
function generate_coupon($coupon_code){
$coupon = new WC_Coupon();
$coupon->set_code($coupon_code);
//the coupon discount type can be 'fixed_cart', 'percent' or 'fixed_product', defaults to 'fixed_cart'
$coupon->set_discount_type('percent_product');
//the discount amount, defaults to zero
$coupon->set_amount(10);
$coupon->set_individual_use(false);
$coupon->set_product_ids(array($coupon_code));
//save the coupon
$coupon->save();
return $coupon_code;
}
add_action( 'woocommerce_before_cart', 'conditional_auto_add_coupons' );
function conditional_auto_add_coupons() {
$all_ids = get_posts( array(
'post_type' => 'product',
'numberposts' => -1,
'post_status' => 'publish',
'fields' => 'ids',
) );
if ( !WC()->cart->is_empty() ){
// First cart loop: Counting number of subactegory items in cart
foreach ( $all_ids as $id ){
foreach ( WC()->cart->get_cart() as $cart_item ){
if( $id == $cart_item['data']->id ){
if( 10 <= $cart_item['quantity'] ){
WC()->cart->add_discount( $id );
//wc_add_notice( __( 'Discount of <strong>10%</strong> for quantity.', 'theme_domain' ), 'success' );
}else{
WC()->cart->remove_coupon( $id );
//wc_add_notice( __( 'Discount of <strong>10%</strong> due to low quantity removed.', 'theme_domain' ), 'success' );}
}
}
}
}
}
}

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

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

Hide specific category in listings

I'm working on a Wordpress theme. The theme is Classifieds theme from premiumpress. The theme has a shortcode to list all the listings. The corresponding shortcode is [LISTINGS].
The function for the shortcode is as follows
/* =============================================================================
[LISTINGS] - SHORTCODE
========================================================================== */
function wlt_page_listings( $atts, $content = null ) {
global $userdata, $wpdb, $CORE; $STRING = ""; $extra=""; $i=1; $stopcount = 4;
extract( shortcode_atts( array( 'query' => '', 'show' => '', 'type' => '', 'cat' => '', 'orderby' => '', 'order' => '', 'grid' => "no", 'featuredonly' => "no"), $atts ) );
// SETUP DEFAULTS
if(!isset($atts['show']) || (isset($atts['show']) && $atts['show'] == "") ){ $atts['show'] = 5; }
if($atts['type'] == ""){ $atts['type'] = THEME_TAXONOMY.'_type'; }
if($atts['orderby'] == ""){ $atts['orderby'] = "post_title"; }
if($atts['order'] == ""){ $atts['order'] = "desc"; }
// DEFAULT FOR LIST STYLE
if($grid == "yes"){
$sstyle = "grid_style";
$STRING .= '<script language="javascript">jQuery(window).load(function() { equalheight(\'.grid_style .item .thumbnail\');});</script>';
}else{
$sstyle = "list_style";
}
$query= str_replace("#038;","&",$query);
if(strlen($query) > 1){
// ADD ON POST TYPE FOR THOSE WHO FORGET
if(strpos($query,'post_type') == false){
$args = $query ."&post_type=".THEME_TAXONOMY."_type";
}else{
$args = $query;
}
}elseif($featuredonly == "yes"){
$args = array('posts_per_page' => $atts['show'],
'post_type' => $atts['type'], 'orderby' => $atts['orderby'], 'order' => $atts['order'],
'meta_query' => array (
array (
'key' => 'featured',
'value' => 'yes',
)
)
);
}else{
/*** default string ***/
$args = array('posts_per_page' => $atts['show'], 'post_type' => $atts['type'], 'orderby' => $atts['orderby'], 'order' => $atts['order'] );
}
/*** custom category ***/
if(strlen($atts['cat']) > 1){
$args = array('tax_query' => array( array( 'taxonomy' => str_replace("_type","",$atts['type']) ,'field' => 'term_id','terms' => array( $atts['cat'] ))), 'posts_per_page' => $atts['show'] );
}
// BUILD QUERY
$the_query = new WP_Query( hook_custom_queries($args) );
if ( $the_query->have_posts() ) {
$STRING .= '<div class="_searchresultsdata"><div class="wlt_search_results row '.$sstyle.'">';
while ( $the_query->have_posts() ) { $the_query->the_post(); $post = get_post();
$STRING .= '<div class="item '.hook_gallerypage_item_class('col-md-4').$CORE->FEATURED($post->ID).'">'.hook_item_cleanup(hook_gallerypage_item($CORE->ITEM_CONTENT($post))).'</div>';
}
$STRING .= '</div></div><div class="clearfix"></div>';
}
// END QUERY
wp_reset_postdata();
return $STRING;
}
add_shortcode( 'LISTINGS', array($this,'wlt_page_listings') );
The shortcode does not have an attribute to hide certain categories. I need to display all listings, except the ones in wedding category, which is a custom taxonomy. Is there any way to do that with the above code?
Will something like this work?
if ( is_tax( 'listing', 'wedding' ) ) {
do not display the wedding listings and display the rest}
Any suggestions?
EDITS:
This my online site url : http://webzer.comxa.com/
The main page shows the all the products.I like to have all but not one that is from wedding category coz i have separate page to list wedding category.
i have tried this where 51 is the page id of my home store page
if ( is_page( 51 ) && is_tax( 'listing', 'wedding' ) ) {
?><style>.caption {display:none!important;}</style>
<?php } ?>
this also didn't work
Consider this :
change
function wlt_page_listings( $atts, $content = null ) {
to
function wlt_page_listings( $atts, $content = null, $exclude=array(99) ) { // 99 is wedding cat id
where $exclude is an optional array of excluded cat names (99 in there for ease of testing/use)
Then in the
while ( $the_query->have_posts() ) {
add something like this:
$post = get_post(); // get post obj, will use the ID attr
$cats = wp_get_post_categories( $post->ID )); // returns array of IDs for all cats
foreach($exclude as $x){ // loop on the excluded cat ids
if(in_array($x, $cats))continue; // if excluded skip
}
http://codex.wordpress.org/Function_Reference/wp_get_post_categories
I think this will work or at least got you close.
display:none is bad mojo as the content will still be in your source code for others to see.
I hope I addressed the problem correctly for you, cheers.

Resources