I have a wordpress site running the wordpress plugin WooCommerce. Because of the sheer volume of products this site is handling we have been managing the product list outside of the site and uploading it. A lot of the products don't have images yet but they have a hard coded image url so we can add them when we get them. To get around broken images I just do a little search for the image size and if I can't find it and replace it with a placeholder.
$src = wp_get_attachment_image_src( get_post_thumbnail_id($post->ID), $size);
if (#getimagesize($src[0])) {
//display product image
} else {
//display placeholder image
}
This is working fine in most cases but now I am working on displaying the products in a category. I want to display all the products with images first and then display the products without images. The problem is once the loop starts if I exclude products without images it will loop through the first 12 products and only display a subset of the 12 that have images. What I want it to do is keep looping until I have 12 products with images (if there are 12 products with images).
This is what I have right now that doesn't work.
<?php if ( have_posts() ) : ?>
<ul class="products">
<?php while ( have_posts() ) : the_post(); ?>
<?php
$src = wp_get_attachment_image_src( get_post_thumbnail_id($post->ID), $size);
if (#getimagesize($src[0])) {
woocommerce_get_template_part( 'content', 'product' );
}
?>
<?php endwhile; // end of the loop. ?>
</ul>
<?php endif; ?>
Possible logical solutions that I have been unable to code would be to ignore some product while in the loop (so it would make another run if there is no image) or somehow code my query as part of the requirement of the loop i.e. pit it in the $args?
Any help would be greatly appreciated.
I have managed to find a workable solution to my problem. It was just impossible to list the products through separate loops without making a mess of pagination. So the logical step was to use the loop and essentially order the products based on whether or not the image exists. This creates a new problem because the Wordpress ordering cannot determine whether the image link points to a file or not.
You can however set a "Menu order" for a product in woocommerce. Then if you set "Default product sorting" to "Default sorting" under "Woocommerce -> Settings -> Catalog" it will use this menu order to order the products in a catalog view.
Great! But I still have 17000 products and I need to specify a Menu order for each. There was no way I could do this using the native woocommerce tools it would have taken weeks. So I decided to write a little plugin to change the "Menu order" of each product based on whether the image exists or not.
Here is the function used to write to the post database:
/**
* This function sets the value of the menu_order of a product to 0 if the product contains an image and 1 if it does not
* #param {int} $offset this is the start number for the batch
* #param {int} $batch The number of products to process in the batch
*/
function setProductMenuOrder($offset, $batch) {
global $post;
$number_completed = 0;
//define the arguments to be used in the loop
$args = array( 'post_type' => 'product','offset' => $offset, 'numberposts' => $batch );
$myposts = get_posts( $args );
foreach( $myposts as $post ) : setup_postdata($post);
$src = wp_get_attachment_image_src( get_post_thumbnail_id($post->ID)); //getting image source
//define post to be updated
$my_post = array();
$my_post['ID'] = $post->ID;
if (#getimagesize($src[0])) { //if image source points to actual image menu order is set to 0
$my_post['menu_order'] = '0';
wp_update_post( $my_post ); //Update the post into the database
$number_completed+=1;
} else { //if it doesn't menu order is set to 1
$my_post['menu_order'] = '1';
wp_update_post( $my_post ); //Update the post into the database
$number_completed+=1;
}
endforeach;
echo '<p>Number of products edited: <strong>'.$number_completed.'</strong>.</p>';
}
I since I have so many products my plugin processes them in smaller batches. I am managing a batch of around 2000 products at a time without failing. I did have to adjust my php memory limit in config.php
define('WP_MAX_MEMORY_LIMIT', '256M');
I still wonder if there might be an easier way of accomplishing this but for the time being this solution will suffice.
Related
I have around 2000 products which has no tags. Now i want to update tag for those products. I want to set post_title=tag for all 2000 products.
Below code works for a product to set CUSTOM TAG to PRODUCT
wp_set_object_terms($productID, array('product_tag1','product_tag2','product_tag3'), 'product_tag');
Instead of complicating the work from front end for each product.
Can someone please guide me how to set post_title=tag using php for all my products.
You can loop through your products and assign the tags, maybe something like this:
Update:
If you want to just add a tag to posts which dont have any existing tags, you could do something like this:
<?php
add_action('init', 'add_tags_products');
function add_tags_products()
{
$args = array(
'post_type' => 'products', // your product post type
'posts_per_page' => - 1,
);
$posts = get_posts($args);
foreach ($posts as $post):
setup_postdata($post);
// get the title of the post
$title = get_the_title($post->ID);
// check to see if the post has any tags
if( ! has_term( '', 'product_tag', $post->ID ) ) :
// create the term
wp_set_object_terms($post->ID, array($title), 'product_tag');
endif;
wp_reset_postdata();
endforeach;
}
Paste the above code in your index.php file for testing and visit the site, and after all the tags are set, remove it. Also backup first in case something happens.
I'm making my first theme and everything is progressing real fast thanks to all the assistance offered by The Loop and WooCommerce's SDK. Then today I spent an entire day failing to do something as simple as showing an image... After an entire day of struggling the only things I managed to learn is that WP seems to offer NO means for fetching a category's image and MANY people have asked this question for many years and STILL I can't find a way to ACTUALLY do it...
:(
What I want to do is create a slider above my store that shows the images of a curated selection of shop categories. I want to be able to enter a list of term names and based on that my function should generate links to the product categories in the form of the category's image.
Sounds simple... turns out, it's nowhere near CLOSE to simple... Before you go off and mark this as a duplicate question, let me explain why I am asking it...
Some of the solutions I have found require that I know the term's IDs, not the tern name. Some say "Get the id's using a custom term search" but doesn't explain how. I know how to do custom taxonumy based queries for posts but not for terms. the documentation confuses me in terms of what values to pass to query terms :(
Other solutions require that I first find a product of a specific category and then find the product's category image working backwards from there (????)
Then of course there is the default answer people love to give for everything: "Oh you are designing your own theme and want to show category icons? Simple, just download a plugin to do that for you". Now why didn't I think of just including someone else's plugin into my theme? (facepalm)
Other answers just show how to print the list of term names but nothing so far has been able to let me do what should have been been as simple as this:
$categories = array("software", "plugins", "merch");
foreach($categories as $cat) {
$term_id = get_term_id($cat);
$term_image = get_term_featured_image($term_id);
echo '<img src="'.$term_image.'">;
}
First problem with getting the term is that the wordpress function to get the term id only works on the category taxonomy but I need to query WooCommerce's product_cat taxonomy. Secondly there doesn't seem to be an option to fetch the thumbnail/featured image even if you HAVE an id. So now what?
So I went low level and started querying the tables directly using $wpdb and I determine the term I am after has term_id 94. I query the termmeta table for the thumbnail's post ID and I find it is 905. Now I turn to my posts table and find.... there IS no post entry 905! WTF? So I do this for two more categories and find the same thing. Finding the image's id results in nothing being returned from the attempt at extracting the post's attachments since there IS no post matching the image's id...
Why is this so darned hard? WordPress makes everything else so incredibly simple yet this simple sounding task seems to be near impossible to do... so now that you see I have Googled this to death and struggled my backside off already, I am asking this question out of desperation:
How do I take an array of product_cat term names and convert that into an array of url's to display the category's image?
Thanks
The shortest way is to use woocommerce_subcategory_thumbnail() dedicated function:
$product_categories = array("software", "plugins", "merch");
// Loop through the product categories
foreach( $product_categories as $category ) {
// Get the WP_term object
$term = get_term_by( 'slug', sanitize_title( $category ), 'product_cat' );
// Get the term link (if needed)
$term_link = get_term_link( $term, 'product_cat' );
// Display the product category thumbnail
woocommerce_subcategory_thumbnail( $term );
}
The other step by step way, that will display the linked product category image with its name:
$product_categories = array("software", "plugins", "merch");
// Loop through the product categories
foreach( $product_categories as $category ) {
// Get the WP_term object
$term = get_term_by( 'slug', sanitize_title( $category ), 'product_cat' );
// Get the term link (if needed)
$term_link = get_term_link( $term, 'product_cat' );
// Get the thumbnail Id
$thumbnail_id = (int) get_woocommerce_term_meta( $term->term_id, 'thumbnail_id', true );
if( $thumbnail_id > 0 ) {
// Get the attchement image Url
$term_img = wp_get_attachment_url( $thumbnail_id );
// Formatted thumbnail html
$img_html = '<img src="' . $term_img . '">';
} else {
$img_html = '';
}
echo '' . $img_html . $term->name . '<br>';
}
Both works…
To get all product categories WP_Term objects and display them with their thumbnails:
// Get all product categories
$product_category_terms = get_terms( array(
'taxonomy' => "product_cat",
'hide_empty' => 1,
));
foreach($product_category_terms as $term){
// Get the term link (if needed)
$term_link = get_term_link( $term, 'product_cat' );
## -- Output Example -- ##
// The link (start)
echo '<a href="' . $term_link . '" style="display:inline-block; text-align:center; margin-bottom: 14px;">';
// Display the product category thumbnail
woocommerce_subcategory_thumbnail( $term );
// Display the term name
echo $term->name;
// Link close
echo '</a>';
}
My Woocommerce website shows 3 columns of products in every loop page.
I'm making some custom landing page where i want to show the loop of products in 4 column instead of 3.
I tryed with this code inside function.php:
add_filter('loop_shop_columns', 'loop_columns');
if (!function_exists('loop_columns')); {
function loop_columns() {
if (is_page(91040)){
return 4;
}else{
return 3;
}
}
}
without success.
Is there a way to have in a single or specific page a different number of column compared to the others?
If you are using woothemes theme or any other theme which is already utlisiing the loop_columns filter, then you need to override that with two things, by removing the if !function exit condition, and also adding pririty to filter high enough like 999 so it is applied at the last:
e.g.
// Override theme default specification for product # per row
function loop_columns() {
return 5; // 5 products per row
}
add_filter('loop_shop_columns', 'loop_columns', 999);
You may adjust the function as per you needs like adding page template conditional as you have in your original code.
Source:
https://docs.woothemes.com/document/change-number-of-products-per-row/ Second headline
I solved the issue. The problem was in the is_page function. It can't get the correct ID so i have found a workaround:
function loop_columns() {
global $woocommerce;
$url = explode('?', 'http://'.$_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]);
$ID = url_to_postid($url[0]);
if ($ID == 91040){
return 4;
}else{
return 3;
}
}
add_filter('loop_shop_columns', 'loop_columns', 999);
I spent a lot of brain matter trying to control the number of columns in a custom template. I am new to WooCommerce and Wordpress so am on a learngin curve. However, I started off with:
<ul class="products">
<?php
$args = array(
'post_type' => 'product',
'posts_per_page' => 12
);
$loop = new WP_Query( $args );
if ( $loop->have_posts() ) {
while ( $loop->have_posts() ) : $loop->the_post();
wc_get_template_part( 'content', 'product' );
endwhile;
} else {
echo __( 'No products found' );
}
wp_reset_postdata();
?>
</ul><!--/.products-->
When applied as a template it gave me a custom loop that I could fiddle with. However, from there I wanted 5 columns and just could not figure it out. I tried all the things Google could throw up such as filers and such. However, I finally discovered that the above snippet starts off with the
<ul class="products">
tag. All I did was dd the appropriate colum class:
<ul class="products columns-5">
This might require additional thinking regarding the responsive aspects, but it crosses the immediate barrier of controlling columns with that snippet. However, it does actually seem to respond quite well.
I'm trying to make a Google product feed from Woocommerce - the available plugins to do this don't support product variations, which is a bit of a nuisance.
I'm working on a clothing shop with multiple sizes and colours of item, so it's required that the Google product feed should list all available size/colour combinations, and as it's doing stock control for each variation, there is no point listing the Size 10 White as in stock when all we really have left is Size 14 Brown.
So, I reckon what I need to do is create a product feed that runs a loop for each product, then inside that loop, runs a nested loop for each variation? It's a bit slow, so please suggest a better way if there is one! At least it will only have to run once a month.
Here's what I have so far:
<?php
// First get the main product details.
$args = array( 'post_type' => 'product', 'posts_per_page' => 999 );
$loop = new WP_Query( $args );
while ( $loop->have_posts() ) : $loop->the_post(); global $product;
// Now do a second nested loop to get the variations.
$args2 = array( 'post_type' => 'product_variation', 'post_parent' =>'$id');
$variationloop = new WP_Query( $args2 );
while ( $variationloop->have_posts() ) : $variationloop->the_post();
// get the parent of each variation so we can use $parent (is this necessary???)
$parent = get_post($post->post_parent);
?>
I feel that really having done the first loop, I should be able to call things from that, but once the second, variation loop is done, I don't seem to be able to refer to anything within the first, product loop. Hence get_post($post->post_parent)
And then I do the feed. So far this seems to work:
<item>
<title><?php echo $parent->post_title;?></title>
<link>http://mysite.com/shop/<?php echo $parent->post_name;?></link>
<g:image_link><?php echo wp_get_attachment_url( get_post_thumbnail_id() ) ?></g:image_link>
<g:price><?php echo $product->price ?></g:price>
<g:condition>New</g:condition>
<g:id><?php echo $id; ?></g:id>
<g:availability><?php echo $product->is_in_stock() ? get_option('product_in_stock') : get_option('product_out_stock'); ?></g:availability>
<g:brand>My Brandname</g:brand>
<g:product_type>Clothing & Accessories > Clothing > Swimwear</g:product_type>
<g:google_product_category>Clothing & Accessories > Clothing > Swimwear</g:google_product_category>
<g:shipping_weight><?php echo $product->get_weight();?></g:shipping_weight>
<g:mpn><?php echo $product->get_sku(); ?></g:mpn>
<?php if (get_option('rss_use_excerpt')) : ?>
<description><![CDATA[<?php echo $parent->post_excerpt; ?>]]></description>
<?php else : ?>
<description><![CDATA[<?php echo $parent->post_excerpt; ?>]]></description>
<?php endif; ?>
Only this is incomplete - I'm not sure how to get at all the elements that I need. In particular, how do I retrieve the variation size and colour, which are in a different table?
I managed to get this working, so am leaving details in case it's useful to anyone.
As per brasofilo's suggestion, I removed the second loop. Then I got the variations like this, checking with meta_compare to see that they were in stock.
$args = array( 'post_type' => 'product_variation', 'post_count' =>'9999','meta_key' => '_stock', 'meta_value' => '0', 'meta_compare' => '>');
$variationloop = new WP_Query( $args );
while ( $variationloop->have_posts() ) : $variationloop->the_post();
// get the parent of each variation, so you can refer to things like product description that are set per-product not per-variation.
$parent = get_post($post->post_parent);
// is the parent product live?
if ($parent->post_status=="publish")
{
Then I got the colours, sizes, photos etc like this:
$colour= get_post_meta($id, 'attribute_pa_colour', true);
$size= get_post_meta($id, 'attribute_pa_size', true);
$price= get_post_meta($id, '_price', true);
$thephoto= get_post_meta($id, '_thumbnail_id', true); // get photo associated with this variation
$image_attributes =wp_get_attachment_image_src($thephoto, 'large');
Note that the exact name of the attributes will depend what you called that attribute when you set up your variations
Then I just echoed out the values:
post_title;?> - Size
http://mywebsite.com/shop/post_name;?>
ID; ?>
post_excerpt); ?>
GBP
I hope that is helpful to someone!
There is a great free plugin for woocommerce product feed which also support product variation. https://wordpress.org/plugins/webappick-product-feed-for-woocommerce/
This premium plugin developed by ELEX supports even variations. Hope this helps those who are still looking for Google Product Feed integration for WooCommerce which supports Product Variations.
https://elextensions.com/plugin/woocommerce-google-product-feed-plugin/
Hi I'm working on a project where I need to display a set of products on a page that are within a certain category of those products. I am establishing these categories by using the actual "Categories" functionality found in Wordpress. Then the plan is to create the actual products themselves as "Posts" that will be output put into a specific format. I will assign each product (post) to a category that I have created and chosen.
The problem is that I will have several different pages of categories, and those pages need to call the specific categories that I assign to those pages. So I'm thinking that I could create a condition in my template that determines whether or not the "Pagename" is equal to "Categoryname". Then if the condition is true, I would tell Wordpress to display the posts in the category that is output.
This is very difficult for me to wrap my mind around. I have successfully been able to get the pagename and the category name as a string, shown below. But I don't know how to create a way to set them equal to each other, then display the posts in the category that is output.
<?php
$pagename = get_query_var('pagename');
if ( !$pagename && $id > 0 ) {
$post = $wp_query->get_queried_object();
$pagename = $post->post_name;
echo $pagename;
}
rewind_posts();
$page = (get_query_var('paged')) ? get_query_var('paged') : 1; query_posts("cat=&showposts=10&paged=$page");
while ( have_posts() ) : the_post();
$category = get_the_category();
if($category[0]){
echo '<p>'.$category[0]->cat_name.'</p>';
}
get_template_part( 'content', get_post_format() );
endwhile;
simplemarket_pagination();
?>
Wouldn't you just use the category.php template?
I'm not sure I understand the need for having these be on Pages rather than Category Pages, per se.