---
title: "Elementor Widget Part 4: WooCommerce Product Integration"
description: "# Introduction This part connects the widget to WooCommerce products. We’ll query products, display their images and prices, and build a basic grid…"
url: "https://sajdoko.com/blog/elementor-widget-part-4-woocommerce-product-integration/"
language: "en"
content_signal: "ai-train=no, search=yes, ai-input=yes"
---
# Elementor Widget Part 4: WooCommerce Product Integration

 13 November 2025·8 minutes read·[Development](https://sajdoko.com/blog/category/development/)     

## [#](#introduction) Introduction

 

This part connects the widget to WooCommerce products. We’ll query products, display their images and prices, and build a basic grid layout.

 

## [#](#learning-objectives) Learning Objectives

 

By the end of this tutorial, you will:

 

- Query WooCommerce products using WP_Query
- Build query arguments based on widget settings
- Access product data using WooCommerce API
- Display product titles, prices, and images
- Work with product taxonomies
- Create a basic product grid layout
- Handle products with no results

 

## [#](#step-1%3A-understanding-wp_query-for-products) Step 1: Understanding WP_Query for Products

 

WooCommerce products are a custom post type called `product`. We use WordPress’s `WP_Query` to retrieve them.

 

### [#](#basic-product-query-structure) Basic Product Query Structure

 

```
$args = [
    'post_type' => 'product',
    'posts_per_page' => 9,
    'post_status' => 'publish',
];

$query = new WP_Query( $args );
```

 

### [#](#common-query-parameters) Common Query Parameters

 

- **post_type**: Must be ‘product’ for WooCommerce products
- **posts_per_page**: Number of products to retrieve
- **orderby**: How to sort (date, title, price, etc.)
- **order**: ASC or DESC
- **tax_query**: Filter by categories, tags, or attributes
- **post_status**: Usually ‘publish’ for public products

 

## [#](#step-2%3A-update-the-render()-method) Step 2: Update the render() Method

 

Replace the placeholder `render()` method in `collection-products-widget.php` with a proper product query:

 

```
<?php
protected function render() {
    $settings = $this->get_settings_for_display();

    // Build query arguments
    $args = [
        'post_type' => 'product',
        'posts_per_page' => $settings['products_per_page'],
        'orderby' => $settings['orderby'],
        'order' => $settings['order'],
        'post_status' => 'publish',
    ];

    // Add category filter if specified
    if ( ! empty( $settings['category'] ) ) {
        $args['tax_query'] = [
            [
                'taxonomy' => 'product_cat',
                'field' => 'term_id',
                'terms' => $settings['category'],
            ],
        ];
    }

    // Execute query
    $query = new WP_Query( $args );

    // Check if products found
    if ( $query->have_posts() ) {
        ?>
        <div class="collection-products-wrapper">
            <div class="collection-products-grid">
                <?php
                while ( $query->have_posts() ) {
                    $query->the_post();
                    global $product;

                    // We'll add product display code here
                    ?>
                    <div class="collection-product-item">
                        <h3><?php the_title(); ?></h3>
                    </div>
                    <?php
                }
                ?>
            </div>
        </div>
        <?php
        wp_reset_postdata();
    } else {
        echo '<p>' . __( 'No products found.', 'hello-biz-child' ) . '</p>';
    }
}
```

 

**Code Explanation:**

 

- **Build Arguments**: Create array based on widget settings
- **Tax Query**: Filter by categories if user selected any
- **WP_Query**: Execute the query
- **The Loop**: Iterate through results with `have_posts()` and `the_post()`
- **global $product**: Access WooCommerce product object
- **wp_reset_postdata()**: Reset query data after loop (important!)

 

## [#](#step-3%3A-accessing-product-data) Step 3: Accessing Product Data

 

WooCommerce provides rich product data through the `$product` object. Let’s explore common methods:

 

### [#](#common-product-methods) Common Product Methods

 

```
global $product;

// Basic info
$product->get_id();                    // Product ID
$product->get_name();                  // Product name
$product->get_title();                 // Product title
$product->get_permalink();             // Product URL

// Pricing
$product->get_price();                 // Current price
$product->get_regular_price();         // Regular price
$product->get_sale_price();            // Sale price
$product->get_price_html();            // Formatted price HTML

// Images
$product->get_image();                 // Featured image HTML
$product->get_image_id();              // Featured image ID
get_the_post_thumbnail_url( $id );     // Image URL

// Product types
$product->is_type( 'simple' );         // Is simple product
$product->is_type( 'variable' );       // Is variable product
$product->is_on_sale();                // Is on sale

// Variations
$product->get_variation_attributes();  // For variable products
```

 

## [#](#step-4%3A-display-product-information) Step 4: Display Product Information

 

Update the product loop to display complete product information:

 

```
<?php
while ( $query->have_posts() ) {
    $query->the_post();
    global $product;

    $product_id = get_the_ID();
    ?>
    <div class="collection-product-item">
        <a href="<?php echo esc_url( get_permalink() ); ?>" class="collection-product-link">
            <div class="collection-product-image">
                <?php
                $image_url = get_the_post_thumbnail_url( $product_id, 'full' );
                if ( $image_url ) :
                ?>
                    <img src="<?php echo esc_url( $image_url ); ?>"
                         alt="<?php echo esc_attr( get_the_title() ); ?>">
                <?php endif; ?>
            </div>
        </a>
        
        <div class="collection-product-info">
            <div class="collection-product-info-left">
                <h3 class="collection-product-title">
                    <a href="<?php echo esc_url( get_permalink() ); ?>">
                        <?php the_title(); ?>
                    </a>
                </h3>
            </div>
            
            <div class="collection-product-price">
                <?php echo $product->get_price_html(); ?>
            </div>
        </div>
    </div>
    <?php
}
```

 

**Code Explanation:**

 

- **Product Link**: Wraps image in link to product page
- **Product Image**: Displays featured image
- **esc_url()**: Sanitizes URLs
- **esc_attr()**: Sanitizes attributes
- **get_price_html()**: Displays formatted price with currency

 

## [#](#step-5%3A-add-basic-grid-css) Step 5: Add Basic Grid CSS

 

Create `wp-content/themes/hello-biz-child/css/collection.css`:

 

```
/* Collection Products Grid */
.collection-products-wrapper {
    width: 100%;
    max-width: 100%;
}

.collection-products-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
    width: 100%;
}

.collection-product-item {
    position: relative;
}

.collection-product-link {
    display: block;
    text-decoration: none;
    color: inherit;
}

.collection-product-image {
    position: relative;
    width: 100%;
    padding-bottom: 100%; /* Square aspect ratio */
    overflow: hidden;
    background: #f5f5f5;
}

.collection-product-image img {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.collection-product-info {
    padding: 15px 0;
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 15px;
}

.collection-product-info-left {
    flex: 1;
}

.collection-product-title {
    margin: 0;
    font-size: 14px;
    font-weight: 400;
    line-height: 1.4;
}

.collection-product-title a {
    color: #333;
    text-decoration: none;
}

.collection-product-title a:hover {
    color: #000;
}

.collection-product-price {
    font-size: 14px;
    color: #333;
    white-space: nowrap;
}

/* Responsive */
@media (max-width: 768px) {
    .collection-products-grid {
        grid-template-columns: 1fr;
    }
}
```

 

## [#](#step-6%3A-enqueue-the-css-file) Step 6: Enqueue the CSS File

 

Add this function to `collection-products-register.php`:

 

```
/**
 * Load widget styles.
 *
 * @return void
 */
function collection_products_widget_styles() {
    wp_enqueue_style(
        'collection-products-widget-style',
        get_stylesheet_directory_uri() . '/css/collection.css',
        [],
        HELLO_BIZ_CHILD_VERSION
    );
}
add_action( 'wp_enqueue_scripts', 'collection_products_widget_styles', 20 );
```

 

## [#](#step-7%3A-test-product-display) Step 7: Test Product Display

 

1. Edit your test page in Elementor
2. The widget should now display products in a grid
3. Try different settings: - Change products per page - Change order by - Select specific categories
4. View the page on the frontend to see the live result

 

*WooCommerce products displayed in the admin*

 

## [#](#step-8%3A-handle-special-cases) Step 8: Handle Special Cases

 

### [#](#handle-products-without-images) Handle Products Without Images

 

Update the image display code:

 

```
<div class="collection-product-image">
    <?php
    $image_url = get_the_post_thumbnail_url( $product_id, 'full' );
    if ( $image_url ) :
    ?>
        <img src="<?php echo esc_url( $image_url ); ?>"
             alt="<?php echo esc_attr( get_the_title() ); ?>">
    <?php else : ?>
        <div class="no-image-placeholder">
            <span><?php _e( 'No Image', 'hello-biz-child' ); ?></span>
        </div>
    <?php endif; ?>
</div>
```

 

Add to CSS:

 

```
.no-image-placeholder {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f0f0f0;
    color: #999;
}
```

 

### [#](#handle-variable-products) Handle Variable Products

 

Check if product is variable and show starting price:

 

```
<div class="collection-product-price">
    <?php
    if ( $product->is_type( 'variable' ) ) {
        echo __( 'From ', 'hello-biz-child' );
    }
    echo $product->get_price_html();
    ?>
</div>
```

 

## [#](#complete-render()-method) Complete render() Method

 

Here’s the complete `render()` method with all improvements:

 

```
<?php
protected function render() {
    $settings = $this->get_settings_for_display();

    $args = [
        'post_type' => 'product',
        'posts_per_page' => $settings['products_per_page'],
        'orderby' => $settings['orderby'],
        'order' => $settings['order'],
        'post_status' => 'publish',
    ];

    // Add category filter
    if ( ! empty( $settings['category'] ) ) {
        $args['tax_query'] = [
            [
                'taxonomy' => 'product_cat',
                'field' => 'term_id',
                'terms' => $settings['category'],
            ],
        ];
    }

    $query = new WP_Query( $args );

    if ( $query->have_posts() ) {
        ?>
        <div class="collection-products-wrapper">
            <div class="collection-products-grid">
                <?php
                while ( $query->have_posts() ) {
                    $query->the_post();
                    global $product;

                    $product_id = get_the_ID();
                    ?>
                    <div class="collection-product-item">
                        <a href="<?php echo esc_url( get_permalink() ); ?>" class="collection-product-link">
                            <div class="collection-product-image">
                                <?php
                                $image_url = get_the_post_thumbnail_url( $product_id, 'full' );
                                if ( $image_url ) :
                                ?>
                                    <img src="<?php echo esc_url( $image_url ); ?>"
                                         alt="<?php echo esc_attr( get_the_title() ); ?>">
                                <?php else : ?>
                                    <div class="no-image-placeholder">
                                        <span><?php _e( 'No Image', 'hello-biz-child' ); ?></span>
                                    </div>
                                <?php endif; ?>
                            </div>
                        </a>
                        
                        <div class="collection-product-info">
                            <div class="collection-product-info-left">
                                <h3 class="collection-product-title">
                                    <a href="<?php echo esc_url( get_permalink() ); ?>">
                                        <?php the_title(); ?>
                                    </a>
                                </h3>
                            </div>
                            
                            <div class="collection-product-price">
                                <?php echo $product->get_price_html(); ?>
                            </div>
                        </div>
                    </div>
                    <?php
                }
                ?>
            </div>
        </div>
        <?php
        wp_reset_postdata();
    } else {
        echo '<p>' . __( 'No products found.', 'hello-biz-child' ) . '</p>';
    }
}
```

 

## [#](#common-issues-and-solutions) Common Issues and Solutions

 

### [#](#issue-1%3A-products-not-showing) Issue 1: Products Not Showing

 

**Solutions:**

 

- Verify you have published products in WooCommerce
- Check that product visibility is set to “Catalog and search”
- Ensure products are in the selected categories
- Check `post_status` is ‘publish’

 

### [#](#issue-2%3A-wrong-products-showing) Issue 2: Wrong Products Showing

 

**Solutions:**

 

- Verify `orderby` and `order` settings
- Check category filter is working correctly
- Ensure no other plugins are filtering the query

 

### [#](#issue-3%3A-images-not-displaying) Issue 3: Images Not Displaying

 

**Solutions:**

 

- Verify products have featured images set
- Check image URLs in browser console
- Ensure file permissions are correct
- Try regenerating thumbnails

 

### [#](#issue-4%3A-prices-not-showing-correctly) Issue 4: Prices Not Showing Correctly

 

**Solutions:**

 

- Ensure WooCommerce currency settings are configured
- Verify products have prices set
- Check for theme conflicts with price display

 

## [#](#summary) Summary

 

You’ve successfully integrated WooCommerce products into your widget:

 

- Query products with WP_Query
- Access product data via WooCommerce API
- Display product images, titles, and prices
- Handle products without images
- Create responsive grid layout
- Added basic styling

 

## [#](#what%E2%80%99s-next%3F) What’s Next?

 

In Part 5: Implementing Custom Product Meta Fields, we’ll:

 

- Add custom collection image field to products
- Integrate WordPress media library uploader
- Add product orientation field
- Save and retrieve custom meta data
- Update frontend to display custom images

 

---

 

**Previous:** [← Part 3: Building the Basic Widget Structure](https://sajdoko.com/blog/elementor-widget-part-3-building-the-basic-widget-structure/)  
 **Next:** Part 5: Implementing Custom Product Meta Fields →

  

- [Code](https://sajdoko.com/blog/category/wordpress/code/)
- [Development](https://sajdoko.com/blog/category/development/)
- [Elementor](https://sajdoko.com/blog/category/wordpress/elementor/)
- [WooCommerce](https://sajdoko.com/blog/category/wordpress/woocommerce/)
- [WordPress](https://sajdoko.com/blog/category/wordpress/)
- [Elementor Widget](https://sajdoko.com/blog/tag/elementor-widget/)

   

## Have a project in mind?

 

Write to us and we come back with a concrete estimate within one working day.

  [Contact us →](https://sajdoko.com/contact/)     

## Leave a comment [Cancel](https://sajdoko.com/blog/elementor-widget-part-4-woocommerce-product-integration/?format=markdown#respond)

      

## Recent Posts

- [Web and Software Development Costs in Albania: The International Buyer’s Strategic Guide](https://sajdoko.com/blog/website-costs-in-albania-international-perspective/)
- [Scaling WooCommerce Performance: Eliminating High-Traffic Checkout Bottlenecks](https://sajdoko.com/blog/scaling-woocommerce-performance-checkout-bottlenecks/)
- [The Hidden Cost of Cheap or “Free” Websites: Why €100 Web Design Costs €3,000 Later](https://sajdoko.com/blog/the-hidden-cost-of-cheap-or-free-websites/)
- [Building High-Concurrency Tour Booking Engines: Architecture Beyond Generic Plugins](https://sajdoko.com/blog/building-high-concurrency-tour-booking-engines/)
- [WordPress Malware Removal and Security Hardening: The Complete Emergency Recovery Guide](https://sajdoko.com/blog/wordpress-malware-removal-and-security-hardening/)

## Recent Comments

1. Alvaro on [Optimizing and Extending the Livewire Product Filter – Part 4](https://sajdoko.com/blog/optimizing-and-extending-the-livewire-product-filter/#comment-4)
2. [sajdoko](https://sajdoko.com) on [How to Set Up WordPress on localhost Using XAMPP: A Step-by-Step Guide](https://sajdoko.com/blog/how-to-install-wordpress-on-localhost-using-xampp-step-by-step-guide/#comment-3)
3. Roshni on [How to Set Up WordPress on localhost Using XAMPP: A Step-by-Step Guide](https://sajdoko.com/blog/how-to-install-wordpress-on-localhost-using-xampp-step-by-step-guide/#comment-2)
