Author: Dawid Adach
Shop page
Now you know how to adjust WooCommerce templates to customize your shop. In this tutorial, we will learn how to style our main shop page (/shop/
) which lists all of our products. Since you know how to edit templates you can achieve this by adjusting archive-product.php
. Note: if you want to use that you have to remove the woocommerce.php
file from your theme directory. Otherwise, the template will be ignored. This is one of the exceptions in WC described in the WC docs.
Warning
If your theme has a
woocommerce.php
file, you will be unable to override thewoocommerce/archive-product.php
custom template in your theme, aswoocommerce.php
has priority over other template files. This is intended to prevent display issues.
However, I want to show you the other way to achieve the same effect. In this scenario, we will use woocommerce.php
and write our custom functions to loop through the products. This is a more complex technique however it gives you total control over each and every element on the page.
- Update the existing code of
woocommerce.php
with the following - Visit the
mydomain.com/shop/
page - Adjust your heading and meta description
- You might notice that we have added an condition — it's required to make sure that the product page remains displayed correctly using templates.
- Now let's add a custom loop to our theme. Add following code below
<header></header>
- Refresh the page:
- As you have noticed we have added both category and search placeholders within a bar (we will learn how to make them work in later lessons). But what is most important is that we have added a custom loop for our products.
- We are looking for posts whose type is product and we limit our results to six per page. We have also used a $paged parameter which tells us which page we are currently browsing. We will learn more about that in later lessons about pagination. In the next lines we are fetching the product info:
- Like product image, regular and sale price as well as first category (product can be assigned to more than one category, in this scenario we are interested only in the first one). Then finally, like we did in our blog tutorial we are displaying every product in a loop using "naked" cards
- Except for custom fields, like the price we are using default WP functions for posts like
the_title()
. You can learn more about them in the previous lessons on how to build WP Blog theme. - One of the interesting parts to notice is that we are dynamically creating an Add to cart url:
- Also like we did in our Blog before, we have a function which adds new row every 3 columns checking the remainder (of division)
<?php get_header();
require_once('components/navbar.inc.php');
if ( !is_shop()) {
woocommerce_content();
} else {
?>
<!--Main Navigation-->
<header>
<!-- Intro -->
<div class="card card-intro blue-gradient mb-4">
<div class="card-body white-text rgba-black-light text-center pt-5 pb-4">
<!--Grid row-->
<div class="row d-flex justify-content-center">
<!--Grid column-->
<div class="col-md-6">
<h1 class="font-weight-bold mb-4">Website Name</h1>
<p class="lead mb-4">Lorem ipsum dolor sit amet consectetur adipisicing elit. Deleniti ad impedit corporis ratione facere?
Cupiditate unde aliquid reiciendis animi, quas inventore, praesentium neque voluptatem, iusto
perferendis placeat similique dolor eum?
</p>
</div>
<!--Grid column-->
</div>
<!--Grid row-->
</div>
</div>
<!-- Intro -->
</header>
<!--Main Navigation-->
<?php
} // end else (if single-product)
get_footer();
?>

<!--Main layout-->
<main>
<div class="container">
<!--Section: Dynamic Content Wrapper-->
<section>
<div class="dynamic-content"></div>
</section>
<!--Section: Dynamic Content Wrapper-->
<!--Section: Products-->
<section class="text-center">
<!--Navbar-->
<nav class="navbar navbar-expand-lg navbar-dark info-color-dark mt-3 mb-5">
<!-- Navbar brand -->
<span class="navbar-brand">Categories:</span>
<!-- Collapse button -->
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#basicExampleNav" aria-controls="basicExampleNav"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<!-- Collapsible content -->
<div class="collapse navbar-collapse" id="basicExampleNav">
<!-- Links -->
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">All
<span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Cat 1</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Cat 2</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Cat 3</a>
</li>
</ul>
<!-- Links -->
<form class="form-inline">
<div class="md-form mt-0">
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
</div>
<button class="btn btn-outline-white btn-md my-2 my-sm-0 ml-3" type="submit"><i class="fas fa-search"></i></button>
</form>
</div>
<!-- Collapsible content -->
</nav>
<!--/.Navbar-->
<!--Grid row-->
<div class="row wow fadeIn">
<?php
// Define custom query parameters
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$args = array(
'post_type' => 'product',
'posts_per_page' => 6,
'paged' => $paged
);
$counter = 1;
$loop = new WP_Query( $args );
if ( $loop->have_posts() ) {
while ( $loop->have_posts() ) : $loop->the_post();
?>
<!--Grid column-->
<div class="col-lg-4 col-md-12 mb-4">
<!-- Product Card naked -->
<div class="card-naked">
<!--Featured image-->
<div class="view overlay hm-white-slight rounded mb-3">
<?php
$image = wp_get_attachment_image_src( get_post_thumbnail_id( $loop->post->ID ), 'single-post-thumbnail' );
$regular_price = get_post_meta( get_the_ID(), '_regular_price', true);
$sale_price = get_post_meta( get_the_ID(), '_sale_price', true);
$terms = get_the_terms( $post->ID, 'product_cat' );
foreach ($terms as $term) {
$product_cat_name = $term->name;
$product_cat_id = $term->term_id;
break;
}
?>
<img src="<?php echo $image[0]; ?>" class="img-fluid" data-id="<?php echo $loop->post->ID; ?>">
<a href ="<?php echo get_permalink() ?>">
<div class="mask"></div>
</a>
</div>
<!--Content-->
<h6 class="mb-3">
<a href="<?php echo esc_url( get_term_link( $product_cat_id, 'product_cat' ) ); ?>">
<span class="badge purple mr-1"><?php echo $product_cat_name ?></span>
</a>
</h6>
<h5 class="mb-3">
<strong><?php the_title() ?></strong>
</h5>
<p>
<?php if($sale_price) {
?>
<span class="mr-1">
<del><?php echo "$" . $regular_price; ?></del>
</span>
<?php
}
?>
<span>
<?php
echo "$";
echo ($sale_price) ? $sale_price : $regular_price;
?></span>
</p>
<a href="<?php echo get_permalink(wc_get_page_id( 'cart' )) . "?add-to-cart=" . get_the_ID() ; ?> " class="btn btn-info btn-sm" data-toggle="tooltip" data-placement="left" title="Add to cart">
<i class="fas fa-shopping-cart"></i>
</a>
<a href="<?php echo get_permalink() ?>" class="btn btn-info btn-sm">Details</a>
</div>
<!-- Product Card naked -->
</div>
<!--Grid column-->
<?php
if ($counter % 3 == 0) {
?>
</div>
<!--Grid row-->
<!--Grid dynamic row-->
<div class="row wow fadeIn">
<?php
}
$counter++;
endwhile;
} else {
echo __( 'No products found' );
}
// Custom query loop pagination
?>
</div>
<!--Grid row-->
</section>
<!--Section: Products-->
</div>
</main>
<!--Main layout-->

<?php
// Define custom query parameters
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$args = array(
'post_type' => 'product',
'posts_per_page' => 6,
'paged' => $paged
);
$loop = new WP_Query( $args );
$counter = 1;
if ( $loop->have_posts() ) {
while ( $loop->have_posts() ) : $loop->the_post();
?>
<?php
$image = wp_get_attachment_image_src( get_post_thumbnail_id( $loop->post->ID ), 'single-post-thumbnail' );
$regular_price = get_post_meta( get_the_ID(), '_regular_price', true);
$sale_price = get_post_meta( get_the_ID(), '_sale_price', true);
$terms = get_the_terms( $post->ID, 'product_cat' );
foreach ($terms as $term) {
$product_cat_name = $term->name;
$product_cat_id = $term->term_id;
break;
}
?>
<!-- Product Card naked -->
<div class="card-naked">
<!--Featured image-->
<div class="view overlay hm-white-slight rounded mb-3">
<?php
$image = wp_get_attachment_image_src( get_post_thumbnail_id( $loop->post->ID ), 'single-post-thumbnail' );
$regular_price = get_post_meta( get_the_ID(), '_regular_price', true);
$sale_price = get_post_meta( get_the_ID(), '_sale_price', true);
$terms = get_the_terms( $post->ID, 'product_cat' );
foreach ($terms as $term) {
$product_cat_name = $term->name;
$product_cat_id = $term->term_id;
break;
}
?>
<img src="<?php echo $image[0]; ?>" class="img-fluid" data-id="<?php echo $loop->post->ID; ?>">
<a href ="<?php echo get_permalink() ?>">
<div class="mask"></div>
</a>
</div>
<!--Content-->
<h6 class="mb-3">
<a href="<?php echo esc_url( get_term_link( $product_cat_id, 'product_cat' ) ); ?>">
<span class="badge purple mr-1"><?php echo $product_cat_name ?></span>
</a>
</h6>
<h5 class="mb-3">
<strong><?php the_title() ?></strong>
</h5>
<p>
<?php if($sale_price) {
?>
<span class="mr-1">
<del><?php echo "$" . $regular_price; ?></del>
</span>
<?php
}
?>
<span>
<?php
echo "$";
echo ($sale_price) ? $sale_price : $regular_price;
?></span>
</p>
<a href="<?php echo get_permalink(wc_get_page_id( 'cart' )) . "?add-to-cart=" . get_the_ID() ; ?> " class="btn btn-info btn-sm" data-toggle="tooltip" data-placement="left" title="Add to cart">
<i class="fas fa-shopping-cart"></i>
</a>
<a href="<?php echo get_permalink() ?>" class="btn btn-info btn-sm">Details</a>
</div>
<a href="<?php echo get_permalink(wc_get_page_id( 'cart' )) . "?add-to-cart=" . get_the_ID() ; ?> " class="btn btn-info btn-sm" data-toggle="tooltip" data-placement="left" title="Add to cart">
<i class="fas fa-shopping-cart"></i>
</a>
if ($counter % 3 == 0) {
?>
</div>
<!--Grid row-->
<!--Grid dynamic row-->
<div class="row wow fadeIn">
<?php
}
Our product page is now working and fully operational. In future lessons we will learn how to use and add pagination to display more products.
Previous lesson Download Live preview
Spread the word:
