How can I assign multiple images to a product in WooCommerce?
I've tried:
update_post_meta( $post_id, '_product_image_gallery', $image_id);
but it assigns only one image. When I use an array, it does not work:
update_post_meta( $post_id, '_product_image_gallery', array($image_id,$image_id2));
If you have multiple images that need to be assigned to a product, you will need to assign one image as the featured image/thumbnail, and then assign the rest of the images as the product gallery thumbnails.
Below is a quick function that can achieve this for you:
function so_upload_all_images_to_product($product_id, $image_id_array) {
//take the first image in the array and set that as the featured image
set_post_thumbnail($product_id, $image_id_array[0]);
//if there is more than 1 image - add the rest to product gallery
if(sizeof($image_id_array) > 1) {
array_shift($image_id_array); //removes first item of the array (because it's been set as the featured image already)
update_post_meta($product_id, '_product_image_gallery', implode(',',$image_id_array)); //set the images id's left over after the array shift as the gallery images
}
}
Assuming you have an array of image id's, and the id of the product that you want to attach the images to, you can call the function above like this:
$images = array(542, 547, 600, 605); //array of image id's
so_upload_all_images_to_product($product_id, $images);
If you are working with a massive array of product images, or you are very serious about micro-optimisation, you can use a combination of array_reverse and array_pop instead of array_shift.
Try like this:
update_post_meta( $post_id, '_product_image_gallery', $image_id.",". $image_id2);
Example to complete:
$images_ids = array();
$images_meta = "";
foreach ($images_ids as $im_id) {
if (is_null(get_post_meta($post_id,"_product_image_gallery")))
add_post_meta($post_id,"_product_image_gallery",$im_id);
else {
$images_meta = get_post_meta($post_id,"_product_image_gallery",true);
update_post_meta($post_id,"_product_image_gallery",$images_meta.",".$im_id);
}
Here is a little wrapper for this job. It accepts only one attachment and adds it either as the base image or adds to the gallery if the product has a base image already.
/**
* #param $product WC_Product|WP_Post
* #param $attachmentId int
*/
function setOrAddImageToProduct($product, $attachmentId)
{
if(!has_post_thumbnail($product->ID)) {
set_post_thumbnail( $product, $attachmentId );
} else {
$gallery = get_post_meta($product->ID, '_product_image_gallery');
if(!empty($gallery)) {
$galleryItems = explode(",", $gallery);
$galleryItems[] = $attachmentId;
} else {
$galleryItems = [$attachmentId];
}
update_post_meta($product->ID, '_product_image_gallery', join(',', $galleryItems));
}
//Adds connection to the product for the media view
$attachment = get_post( $attachmentId );
$attachment->post_parent = $product->ID;
wp_update_post( $attachment );
}
This code will upload multiple images in product gallery
foreach ($files['name'] as $key => $value) {
if ($files['name'][$key]) {
$file = array(
'name' => $files['name'][$key],
'type' => $files['type'][$key],
'tmp_name' => $files['tmp_name'][$key],
'error' => $files['error'][$key],
'size' => $files['size'][$key]
);
$_FILES = array ("my_file_upload" => $file);
$newupload = my_handle_attachment( "my_file_upload", $post_id);
}
$attach_newupload_ids[]=$newupload;
}
$attach_ids=implode(',',$attach_newupload_ids);
if($attach_ids){
update_post_meta( $post_id, '_product_image_gallery', $attach_ids);
}
This code will update the product gallery when a new image is loaded to the product. I', using it in a React app that uses wp as back-end, the new image is loaded trough the app and then the hook "add action" triggers the code that includes the image into the product gallery.
I use this code in the functions.php file:
<?php
add_action( 'add_attachment', 'auto_on_upload' );
function auto_on_upload( $attachment_id ) {
$parent = get_post_ancestors( $attachment_id );
$images = get_attached_media('', $parent[0]);
foreach( $images as $key => $image) {
$images_array[] = $key;
};
$images_array[] = $attachment_id;
update_post_meta($parent[0], '_product_image_gallery', implode(',', $images_array));
}
?>
Related
I tried this way, but it's still cannot generate a product image at the metabox.
add_filter( 'woocommerce_placeholder_img_src',
'growdev_custom_woocommerce_placeholder', 10 );
function growdev_custom_woocommerce_placeholder( $image_url ) {
$product = new WC_Product( get_the_ID());
$attachment_ids = $product->get_gallery_image_ids();
if ( is_array( $attachment_ids ) && !empty($attachment_ids) ) {
$first_image_url = wp_get_attachment_url( $attachment_ids[0] );
$image_url = $first_image_url; // change this to the URL to your custom placeholder
return $image_url;
} // No images found
else {
$image_url = 'https://...jpg';
return $image_url;
// #TODO
}
}
I searched on Google and there is no way to use the first image set as product image from product galleries automatically.
I have a post_save hook that manages setting the title of a particular post type. Within that logic I need to retrieve the post's categories. However, the categories are not yet saved at the time the post_save triggers for the first save of a new post.
add_action('save_post', 'save_report');
function save_report($post_id) {
$data = get_post($post_id, ARRAY_A);
if($data['post_type'] == 'report') {
$date = get_post_meta($post_id)['date'][0];
// I need to get the category of the post on the first time the post is saved
// $categories only gets a value AFTER the first save
$categories = get_the_terms($post_id, 'report_type');
$cat_string = '';
foreach($categories as $value) {
$cat_string .= $value->slug;
}
$new_title = date('m/d/Y', strtotime($date)).' '.$cat_string;
remove_action('save_post', 'save_report');
wp_update_post(array(
'ID' => $post_id,
'post_title' => $new_title
));
add_action('save_post', 'save_report');
}
}
Because of this, I have to save the post twice to get it to change the title to what I want. Is it possible to get the new category of the post as it is being saved like this?
Not quite sure what you're using the categories for after the fact, but you can just retrieve them after the wp_update_post runs.
add_action('save_post', 'save_report');
function save_report($post_id) {
$data = get_post($post_id, ARRAY_A);
if($data['post_type'] == 'report') {
$date = get_post_meta($post_id)['date'][0];
$new_title = date('m/d/Y', strtotime($date)).' '.$cat_string;
remove_action('save_post', 'save_report');
/*
* return the updated post ID (which is the same really as your
* initial ID, so you could just use that. But for demonstration it helps
* to see it logically.)
*/
$updated_post_id = wp_update_post(array(
'ID' => $post_id,
'post_title' => $new_title
));
$categories = get_the_terms($updated_post_id, 'report_type');
$cat_string = '';
foreach($categories as $value) {
$cat_string .= $value->slug;
}
add_action('save_post', 'save_report');
}
}
An alternative, if you're both creating and updating posts programatically is to use wp_insert_post, which covers both new creation (if you don't pass an ID), and updating (if you do pass an ID).
You could also create a separate function to retrieve IDs that you could use with any number of other functions you run.
function retrieve_report_cats($post_id) {
cats_list = array();
$categories = get_the_terms($post_id, 'report_type');
foreach($categories as $value) {
$cat = $value->slug;
$cats_list[] = $cat;
}
return $cats_list;
}
I want to add an additional menu consisting only of the product category images. I'm using woocommerce. I would like it to be centered in the middle of the page and drop down. What kind of short code does this require? I've tried using Mega Menu plugin but it only alters my primary menu.
Thanks!
I don't think there is a direct way for that, You can use this code to get an array of the categories images URLs, You can use the "woocommerce_before_shop_loop" action then, loop over the array and put the images in the HTML form you like.
add_action( 'woocommerce_before_shop_loop', function() {
$categories = get_terms( 'product_cat' );
$categories_thumbnails_urls = [];
foreach ( $categories as $category ) {
$thumbnail_id = get_woocommerce_term_meta( $category->term_id, 'thumbnail_id', true );
$thumbnail_url = wp_get_attachment_url( $thumbnail_id );
if ( empty( $thumbnail_url ) ) {
continue;
}
$categories_thumbnails_urls[] = $thumbnail_url;
}
foreach ( $categories_thumbnails_urls as $cat_thumb_url ) {
// ...
}
});
I have a wordpress website where customers make an image with text and icons, once processed thru woocommerce and payed for that image name 12345.png is saved as Customer_product_image
function add_order_item_meta($item_id, $values) {
$key = 'customer_product_image'; // Define your key here
$value = $values['user_img']; // Get your value here
woocommerce_add_order_item_meta($item_id, $key, $value);
}
And i works great, but now i'm banning my head against the wall! When the purchased image is displayed on the Order admin detail page, it shows up as CUSTOMER_PRODUCT_IMAGE: 1234.png how on earth would i go about wrapping that within an image tag so the image is displayed there?
I've searched high and low on google but haven't been able to find anything, its probably that i dont know what do actually search for....
This did the trick for me!
First i added this snippet for removing the custom meta item on order detail render:
add_filter( 'woocommerce_hidden_order_itemmeta', 'hide_order_item_meta_fields' );
function hide_order_item_meta_fields( $fields ) {
$fields[] = 'current_view';
$fields[] = 'custom_image';//Add all meta keys to this array,so that it will not be displayed in order meta box
return $fields;
}
second i added it back with this, and with the desired text and image tag:
add_action( 'woocommerce_after_order_itemmeta', 'order_meta_customized_display',10, 3 );
function order_meta_customized_display( $item_id, $item, $product ){
$all_meta_data=get_metadata( 'order_item', $item_id, "", "");
$useless = array(
"_qty","_tax_class","_variation_id","_product_id","_line_subtotal","_line_total","_line_subtotal_tax","_line_tax","_line_tax_data"
);// Add key values that you want to ignore
$customized_array= array();
foreach($all_meta_data as $data_meta_key => $value) {
if(!in_array($data_meta_key,$useless)){
$newKey = ucwords(str_replace('_'," ",$data_meta_key ));//To remove underscrore and capitalize
$customized_array[$newKey]=ucwords(str_replace('_'," ",$value[0])); // Pushing each value to the new array
}
}
if (!empty($customized_array)) {
foreach($customized_array as $data_meta_key => $value){
echo "<div class='product_container'><span>Produkt Billede: </span><img src='".wp_upload_dir()['baseurl'].'/flapper/'. $value ."' /> </div>";
}
}
}
i found the answer to this question on this page
You can use the filter woocommerce_order_item_display_meta_value to output the image. Place this code in your functions.php file, you'll need to modify the src attribute of the img tag to include the appropriate URL before the filename value. You can also modify the display label with the filter woocommerce_order_item_display_meta_key
add_filter( 'woocommerce_order_item_display_meta_value', 'modify_order_item_display_value' , 10, 3 );
function modify_order_item_display_value( $display_value, $meta, $wc_order_item ) {
$meta_data = $meta->get_data();
if( $meta_data['key'] === 'customer_product_image' ) {
return '<img src="' . $meta_data['value'] . '">';
}
return $display_value;
}
add_filter('woocommerce_order_item_display_meta_key', 'modify_order_item_display_key', 10, 3);
function modify_order_item_display_key( $display_key, $meta, $wc_order_item ) {
$meta_data = $meta->get_data();
if( $meta_data['key'] === 'customer_product_image' ) {
return 'Customer Image';
}
return $display_key;
}
This is a self Q&A.
How do you modify the text/html that appears in the output of a wp_nav_menu? For example, I wanted to add the featured image for pages and categories.
You see examples of doing this with a custom walker, but the code is very complex to do for small changes. Surely there is a way to do it with a filter?
This is the code I came up with thanks to some help from a Wordpress StackOverflow answer that I can't find anymore (please comment with a link if you find it).
First you need to add the filter to the specific menu (you could add it to all menus if you want - just use the add_filter line by itself).
// Add filter to specific menus
add_filter('wp_nav_menu_args', 'add_filter_to_menus');
function add_filter_to_menus($args) {
// You can test agasint things like $args['menu'], $args['menu_id'] or $args['theme_location']
if( $args['theme_location'] == 'header_menu') {
add_filter( 'wp_setup_nav_menu_item', 'filter_menu_items' );
}
return $args;
}
Then you need to build out the code to get the post or category ID from the $item object passed to the filter. It's not as easy as you'd expect, as $item doesn't contain the underlying post/category ID, just the menu item ID. So I use the URL's to do a reverse lookup of the IDs.
This won't work for tags used in a menu, or custom taxonomys. I only needed it for categories, so this is all I built.
// Filter menu
function filter_menu_items($item) {
if( $item->type == 'taxonomy') {
// For category menu items
$cat_base = get_option('category_base');
if( empty($cat_base) ) {
$cat_base = 'category';
}
// Get the path to the category (excluding the home and category base parts of the URL)
$cat_path = str_replace(home_url().'/'.$cat_base, '', $item->url);
// Get category and image ID
$cat = get_category_by_path($cat_path, true);
$thumb_id = get_term_meta($cat->term_id, '_term_image_id', true); // I'm using the 'Simple Term Meta' plugin to store an attachment ID as the featured image
} else {
// Get post and image ID
$post_id = url_to_postid( $item->url );
$thumb_id = get_post_thumbnail_id( $post_id );
}
if( !empty($thumb_id) ) {
// Make the title just be the featured image.
$item->title = wp_get_attachment_image( $thumb_id, 'poster');
}
return $item;
}
And then you want to remove the filter that you applied at the beginning, so that the next menu processed doesn't use the same HTML as defined above in filter_menu_items().
// Remove filters
add_filter('wp_nav_menu_items','remove_filter_from_menus', 10, 2);
function remove_filter_from_menus( $nav, $args ) {
remove_filter( 'wp_setup_nav_menu_item', 'filter_menu_items' );
return $nav;
}
Modified Drew Baker answer. It works without plugins, also if there is no category with current slug it checks for woocommerce product category ('product_cat').
functions.php
// Add filter to specific menus
add_filter('wp_nav_menu_args', 'add_filter_to_menus');
function add_filter_to_menus($args) {
// You can test agasint things like $args['menu'], $args['menu_id'] or $args['theme_location']
if( $args['theme_location'] == 'menu-header') {
add_filter( 'wp_setup_nav_menu_item', 'filter_menu_items' );
}
return $args;
}
// Filter menu
function filter_menu_items($item) {
if( $item->type == 'taxonomy') {
// Get category and image ID
$slug = pathinfo( $item->url, PATHINFO_BASENAME );
$cat = get_term_by( 'slug', $slug, 'category' );
// If there is no standard category try getting product category
if( !$cat ) {
$cat = get_term_by( 'slug', $slug, 'product_cat' );
}
$thumb_id = get_term_meta($cat->term_id, 'thumbnail_id', true);
} else {
// Get post and image ID
$post_id = url_to_postid( $item->url );
$thumb_id = get_post_thumbnail_id( $post_id );
}
if( !empty($thumb_id) ) {
// Make the title just be the featured image.
$item->title = wp_get_attachment_image( $thumb_id, 'poster');
// Display image + title example
// $item->title = wp_get_attachment_image( $thumb_id, 'poster').$item->title;
}
return $item;
}
// Remove filters
add_filter('wp_nav_menu_items','remove_filter_from_menus', 10, 2);
function remove_filter_from_menus( $nav, $args ) {
remove_filter( 'wp_setup_nav_menu_item', 'filter_menu_items' );
return $nav;
}