Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Woocommerce Displaying Products With Product Images

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.

like image 344
Jeffrey Jenkinson Avatar asked Nov 13 '22 10:11

Jeffrey Jenkinson


1 Answers

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.

like image 139
Jeffrey Jenkinson Avatar answered Nov 15 '22 06:11

Jeffrey Jenkinson