I'm working on a custom WooCommerce powered ecommerce store where I want if I could get an images upload field that allows me to upload multiple images inside each variation (mostly for color variations, to change default gallery images when a color variation is selected).
Currently, I am focusing on at least achieving this in backend.
There are multiple plugins available to get that result, but they have limitations on free and I don't have budget to buy any. Also, I want to keep my theme lite and easily accessible to customize and code.
I downloaded some of those plugins and some other StackOverflow answers and came up with this code. But this does not seem to be working in backend at all.
add_action( 'woocommerce_product_after_variable_attributes', 'wc_variation_gallery_images', 10, 3 );
add_action( 'woocommerce_save_product_variation', 'wc_save_variation_gallery_images', 10, 2 );
function wc_variation_gallery_images( $loop, $variation_data, $variation ) {
$variation_id = $variation->ID;
$variation_gallery_images = get_post_meta( $variation_id, 'variation_gallery_images', true ); ?>
<div class="gallery-images-wrapper">
<?php
foreach ( $variation_gallery_images as $gallery_image_id ):
$image = wp_get_attachment_image_src( $gallery_image_id ); ?>
<li class="gallery-image">
<img src="<?php echo esc_url( $image[ 0 ] ) ?>">
<input type="hidden" name="variation_gallery[<?php echo esc_attr( $variation_id ) ?>][]" value="<?php echo esc_attr( $gallery_image_id ) ?>">
</li>
<?php endforeach; ?>
</div>
<?php }
function wc_save_variation_gallery_images( $variation_id, $loop ) {
if ( isset( $_POST['variation_gallery'] ) ) {
if ( isset( $_POST['variation_gallery'][ $variation_id ] ) ) {
$gallery_image_ids = array_map( 'absint', $_POST['variation_gallery'][ $variation_id ] );
update_post_meta( $variation_id, 'variation_gallery_images', $gallery_image_ids );
}
else {
delete_post_meta( $variation_id, 'variation_gallery_images' );
}
}
else {
delete_post_meta( $variation_id, 'variation_gallery_images' );
}
}
Maybe, I have done something wrong with the code and that is the reason why I am not able to make it work. Can you please help me make this work. All I want is, to be able to upload multiple gallery images per variation. By default, there is only one featured image allowed per variation.
All I want is, to be able to upload multiple gallery images per variation. By default, there is only one featured image allowed per variation.
Related
I am adding a custom field to woocommerce product variations to attach additional product categories to product variations. Everything works, during the save process the terms are updated in wp_term_relationships table however, a bit later in the save operation the terms are overwritten again with the parent product ones.
I am using the following code:
add_action( 'woocommerce_save_product_variation', 'save_custom_field_variations', 99, 2 );
function save_custom_field_variations( $variation_id, $i ) {
$custom_categories = $_POST['variation_product_cat'][$variation_id];
if ( isset( $custom_categories ) && !empty( $custom_categories )) {
wp_set_post_terms( $variation_id, $custom_categories, 'product_cat' );
}
}
I have also tried a different hook with the same result:
add_action( 'woocommerce_update_product', 'save_custom_field_variations_2', 99, 1 );
function save_custom_field_variations_2( $post_id ) {
foreach($_POST['variation_product_cat'] as $variation_id => $custom_categories)
if ( isset( $custom_categories ) && !empty( $custom_categories )) {
$response = wp_set_post_terms( $variation_id, $custom_categories, 'product_cat' );
}
}
Any tips on what process is overwriting my changes are very welcome!
Turns out it was one of the plugins that was overwriting the changes (found out by disabling all and then enabling them one by one)
Shipping rates are calculated using product weight and dimension on my Woocommerce website. However, my inventory system only uses product weight for shipping rates. Because of this, new products synchronized from the inventory system to the website generally don't have dimensions.
After a few tests, I found that adding a length, width and height of .001 to products on the site generates the most accurate shipping rates.
I need to write a function that sets product dimensions to .001 if they're empty at the point of creation.
Here is what I've attempted:
function add_default_dimension_if_empty( $meta_id, $post_id, $meta_key, $meta_value ) {
if ( $meta_key == '_edit_lock' ) {
if ( get_post_type( $post_id ) == 'product' ) {
//get product
$product = wc_get_product( $post_id );
$newDim = .001;
if($product->has_dimensions()){
if(empty( $product->get_length() )){
update_post_meta($post_id, '_length', $newDim);
}
if(empty( $product->get_width() )){
update_post_meta($post_id, '_width', $newDim);
}
if(empty( $product->get_height() )){
update_post_meta($post_id, '_height', $newDim);
}
}
}
}
}
add_action( 'added_post_meta', 'add_default_dimension_if_empty', 10, 4 );
add_action( 'updated_post_meta', 'add_default_dimension_if_empty', 10, 4 );
I used the structure from this article, but it doesn't seem to work. Any thoughts?
Your code is fine just need to change one condition which check the dimension is exist or not.
Replace if($product->has_dimensions()) line with following
$dimensions = $product->get_dimensions();
if(! empty( $dimensions ))
This will work for you.
I made a new post type named "sub_products" containing the meta tag "unit_price".
After assigning a new field for every Woocommerce product containing a list of all the "sub_products" posts, the goal was to update every product price based on the selected "sub_products" meta "unit_price".
function kulcskron_edit_post( $p1, $p2 )
{
if ( !is_admin() )
return;
if ( get_post_type() != 'product' )
return;
$sub_product_ids = $p2->get_meta( 'sub_products' );
if ( empty($sub_product_ids) )
return;
$product_regular_price = 0;
foreach ( $sub_product_ids as $id )
$product_regular_price += get_post_meta( $id, 'unit_price', true );
if ( $p1 == $product_regular_price )
return;
$p2->set_regular_price( $product_regular_price );
$p2->save();
}
add_action( 'woocommerce_product_get_price', 'kulcskron_edit_post', 10, 2 );
I tried every possible hook to make this work:
add_action( 'the_post', 'kulcskron_edit_post', 9, 1 );
add_action( 'edit_post', 'kulcskron_edit_post', 10, 2 );
add_action( 'pre_get_posts', 'kulcskron_edit_post' );
add_action( 'save_post', 'kulcskron_edit_post' );
This code updates the price but in a strange way:
Admin single product edit view: The price is not updated right away, just after I revisit the edit screen.
Admin product listing view: Every price is 0.
Front-end product page view: The displayed price is 0.
How do I update the product price based on the assigned "sub_products" "unit_price" post meta when a single product is saved in admin view?
You may use the hook "woocommefrce_get_price_html" it should work
I managed to solve the price update problem.
I used the save_post action:
save_post is an action triggered whenever a post or page is created or updated, which could be from an import, post/page edit form, xmlrpc, or post by email.
The final code:
function kulcskron_update_product( $product_obj )
{
if ( !is_admin() )
return;
if ( get_post_type() != 'product' )
return;
$product = wc_get_product( $product_obj );
if ( !$product->meta_exists( 'sub_products' ) )
return;
$sub_product_ids = $product->get_meta( 'sub_products' );
if ( empty($sub_product_ids) )
return;
_update_product_price( $product_obj, $sub_product_ids );
}
add_action( 'save_post', 'kulcskron_update_product' );
And for the sake of completeness here is the rest of code:
function _update_product_price( $product_obj, $sub_product_ids )
{
$product = wc_get_product( $product_obj );
$product_regular_price = 0;
foreach ( $sub_product_ids as $id )
$product_regular_price += get_post_meta( $id, 'kulcskron_unit_price', true );
$product->set_regular_price( $product_regular_price );
$product->set_price( $product_regular_price );
$product->save();
}
This way basically everything can be edited and updated. Example:
function _update_product_stock( $product_obj, $sub_product_ids )
{
$product = wc_get_product( $product_obj );
$sub_product_stocks = array();
foreach ( $sub_product_ids as $id )
$sub_product_stocks[] = get_post_meta( $id, 'kulcskron_free_stock_quantity', true );
$product->set_manage_stock( true );
$product->set_stock_quantity( min($sub_product_stocks) );
$product->save();
}
I would love to post a link to all the methods to edit a product but I have no rep for that.
But sadly this is not all...
In order to fully update the price, we need to filter the price HTML to return the newly updated price.
function kulcskron_price_html( $priceHtml, $product )
{
$symbol = get_woocommerce_currency_symbol();
$price = $product->get_regular_price();
$html = '<span class="woocommerce-Price-amount amount">'. $price .' <span class="woocommerce-Price-currencySymbol">'. $symbol .'</span></span>';
return $html;
};
add_filter( 'woocommerce_get_price_html', 'kulcskron_price_html', 10, 2 );
A little backstory. We need to sync all the products from an external database through an XML file. But there is a catch, the XML file only contains product parts and they are not displayed, searched, filtered and certainly can't be ordered individually. None of the Woocommerce build in functionality meet these requirements.
In order to solve this, I registered a new post type and imported all the product parts into this newly created post type. After that, I registered a new field for every WC Product with the Advanced Custom Fields plugin.
It looks like this:
Newly registered custom post type with the custom fields
The code above makes easy to update the WC Products (e.g. Prices) based on the selected Sub products.
I know this is not a woocommerce related websites, I tried the official forum, but no reply in 3 days. I spent a day or more with this, so I hope you can help.
I created a custom wp_query for the products. These products has a custom field (custom_price). I would like to override the prices in the query with the values of the custom fields.
I saw questions here about this, but I'm very new in php/wordpress. I really appreciate your help.
My query:
<?php woocommerce_product_loop_start(); ?>
<?php
if(is_front_page()){
$args = array(
'post_type' => 'product',
'posts_per_page' => 6,
'meta_key' => '_featured',
'meta_value' => 'yes'
);
$query = new WP_Query( $args );
if ( $query->have_posts() ) {
while ( $query->have_posts() ) {
$query->the_post();
wc_get_template_part( 'content', 'product' );
}
}
wp_reset_query();
}
?>
<?php woocommerce_product_loop_end(); ?>
If you just want to change the price that is displayed, then you can implement the filters woocommerce_price_html, woocommerce_sale_price_html, woocommerce_cart_item_price_html. This will result in the displayed price being whatever you would like, however the actual price in the cart used for calculating tax, shipping, totals, etc will be based on the "real" price.
// the HTML that is displayed on the product pages
function my_price_html( $html, $_product ) {
// if this is a variation we want the variation ID probably?
$id = isset($_product->variation_id) ? $_product->variation_id : $_product->id;
$custom_price = get_post_meta( $id, 'custom_price', true );
$custom_price_html = "<b>$custom_price</b>"; // just an example of HTML
return $custom_price_html;
}
add_filter( 'woocommerce_price_html', 'my_price_html', 10, 2 );
add_filter( 'woocommerce_sale_price_html', 'my_price_html', 10, 2 );
// the HTML that is displayed on the cart
function my_cart_item_price_html( $html, $cart_item, $cart_item_key ) {
$id = $cart_item['data']->id;
$custom_price = get_post_meta( $id, 'custom_price', true );
$custom_price_html = "<b>$custom_price</b>"; // just an example of HTML
return $custom_price_html;
}
add_filter( 'woocommerce_cart_item_price_html', 'my_cart_item_price_html', 10, 3 );
You will need to implement other filters/actions if you want to actually affect the item price, the above just affects the display. A better option might be to implement an action for save_post or update_post_meta that updates the WooCommerce product price when the custom field value changes (assuming you are using the codex to update this value).
I found some custom fields turorial for WP and Woocommerce. So I played a bit with that. It all works ok, but I tried to customize part that saves values during checkbox checking, and unfortunately I'm not able to finish that. This is what I'm trying, piece of code in functions.php:
// Custom field for price labels
// Display Fields
add_action(
'woocommerce_product_options_general_product_data',
'woo_add_custom_general_fields' );
// Save Fields
add_action(
'woocommerce_process_product_meta',
'woo_add_custom_general_fields_save' );
function woo_add_custom_general_fields() {
global $woocommerce, $post;
// Checkbox
woocommerce_wp_checkbox(
array(
'id' => '_primer',
'wrapper_class' => '',
'label' => __('Primer', 'woocommerce' ),
'description' => __( 'Check me!', 'woocommerce' )
)
);
}
function woo_add_custom_general_fields_save( $post_id ){
// Checkbox_1
$woocommerce_checkbox_primer = isset( $_POST['_primer'] ) ? 'yes' : '';
update_post_meta( $post_id, '_primer', $woocommerce_checkbox_primer );
}
...and then this peace of code in single-product.php
<span><?php echo get_post_meta( get_the_ID(), '_primer', true ); ?></span>
So when this is implemented I have one big "yes" on single product page, but what I want to get is image instead of that "yes", so if checkbox is checked to show image on single product page, and to save that selection in database. I hope I was clear enough, and thanks in advance.
I'm not 100% sure that I understand but it sounded like you wanted to show an image conditionally if the checkbox was true in the backend
if( 'yes' == get_post_meta( get_the_ID(), '_primer', true ) ) { ?>
<img src="your-image.png"/>
<?php }