This is the documentation for LemonStand V1, which has been discontinued. You can learn more and upgrade your store here.

LemonStand Version 1 Has Been Discontinued

This documentation is for LemonStand Version 1. LemonStand is now offered as a cloud-based eCommerce platform.
You can try the new LemonStand and learn about upgrading here.

Displaying a List of Products

There are at least 3 cases when you may want to display a list of products - a list of a categories products, a list of a custom group's products and a list of related products. That's why it is a good idea to place the code displaying a product list into a partial and render this partial when it is needed, passing a product collection as a parameter.

Start with creating a new partial. It doesn't matter what name you assign to it, but it is better if you assign some meaningful name, like shop:product_list.

To display a list of products, you should pass a variable, containing a list of products from outside page to the partial, as a parameter (please see the Displaying a full list of the category products section below for example of passing a list of products to the partial). In the partial code we assume what the variable $products is defined and passed to the partial. To output a list of products, use the standard foreach loop:

<ul>
  <? foreach ($products as $product): ?>
    <li>
      <h3><a href="<?=  $product->page_url('/product') ?>"><?= h($product->name) ?></a></h3>
      <p><?= h($product->short_description) ?></p>
    </li>
  <? endforeach ?>
</ul>
<ul>
  {% for product in products %}
    <li>
      <h3><a href="{{ product.page_url('/product') }}">{{ product.name }}</a></h3>
      <p>{{ product.short_description }}</p>
    </li>
  {% endfor %}
</ul>

The code creates links to the product page, using the page_url method of the Shop_Product class. In the example we suppose that products on your website have URLs like these: /product/product_1, /product/product_2. The base part of the URL (/product) - is what you pass to the page_url method as a method parameter. The remaining part (product_1, product_2) is added by the method and equals to a product's URL name.

You can also output a product image in the list. As products can have multiple images assigned to them and we need to output only a single image, we just display the first image, the one with with index 0 (zero). Also, it is always a good idea to check whether image exists, because you can forget to assign an image to some products. The following code snippet outputs a thumbnail, with width or height not greater than 130 pixels, of the first image of a product.

<?
  $image_url = $product->image_url(0, 130, 130);
  if ($image_url):
?>
  <img src="<?= $image_url ?>" alt="<?= h($product->name) ?>"/>
<? endif ?>
{% set image_url = product.image_url(0, 130, 130) %}
{% if image_url %}
  <img src="{{ image_url }}" alt="{{ product.name }}"/>
{% endif %}

The final product list code:

<ul>
  <? foreach ($products as $product): ?>
    <li>
      <h3><a href="<?=  $product->page_url('/product') ?>"><?= h($product->name) ?></a></h3>
      
      <?
        $image_url = $product->image_url(0, 130, 130);
        if ($image_url):
      ?>
        <img src="<?= $image_url ?>" alt="<?= h($product->name) ?>"/>
      <? endif ?>
      
      <p><?= h($product->short_description) ?></p>
    </li>
  <? endforeach ?>
</ul>
<ul>
  {% for product in products %}
    <li>
      <h3><a href="product.page_url('/product')">{{ product.name }}</a></h3>
      
      {% set image_url = product.image_url(0, 130, 130) %}
      {% if image_url %}
        <img src="{{ image_url }}" alt="{{ product.name }}"/>
      {% endif %}
      
      <p>{{ product.short_description }}</p>
    </li>
  {% endfor %}
</ul>

Displaying a full list of the category products

To output a list of category products, you can place the following code to the category page.

<? $this->render_partial('shop:product_list', array(
  'products'=>$category->list_products()->find_all()
)) ?>
{{ render_partial('shop:product_list', {
  'products': category.list_products().find_all()
}) }}

The list_products() method of the Shop_Category class returns a list of category products. The method accepts a number of parameters, which you can use for sorting a list of the category products. The result of this method is the Shop_Product object, which, in turns is a successor of the Db_ActiveRecord class. Thus the result can be used for further processing, for example for the paginating the product list, or for obtaining a collection of all products in the category. For displaying a full list of the category products we call the find_all() method, which returns a collection of the Shop_Product objects. Please read the Shop_Category class documentation for details about the list_products() method parameters. 

Displaying content of a custom product group

To display content of a custom product group you first should load the product group from the database. The best way to reffer a custom group is using its API code. Assuming you have a custom product group with API code "featured_products" you can find it with the following line of code:

$group = Shop_CustomGroup::create()->find_by_code('featured_products');
{% set group = method('Shop_CustomGroup', 'create').find_by_code(group_code) %}

After loading the group object, you can access its products by calling the list_products() method and passing its result to the partial. Example: 

<?
  $group = Shop_CustomGroup::create()->find_by_code($group_code);
  if ($group)
    $this->render_partial('shop:product_list', array('products'=>$group->list_products()));
  else 
    echo "<p>The product group ".$group_code." not found. Please create this group on the Shop/Products/Manage Product Groups page.</p>";
?>
{% set group = method('Shop_CustomGroup', 'create').find_by_code(group_code) %}
{% if group %}
  {{ render_partial('shop:product_list', {'products': group.list_products}) }}
{% else %}
  <p>The product group {{ group_code }} not found. Please create this group on the Shop/Products/Manage Product Groups page.</p>
{% endif %}

Paginating a product list

Product pagination allows you to split a large product list into pages. To output a single page of products, you need to know the following:

  • What is current page index? Page index determines an zero-based index of a currently opened page.
  • How many products each page should contain?
  • What is base URL of a page?

All these parameters will be passed to the product list partial from outside, because it is a good practice to develop universal partials which could be used in different places of your website. To prepare a paginated list of products, place the following code to the top of the product list partial code:

<?
  if (isset($paginate) && $paginate)
  {
    $page_index = isset($page_index) ? $page_index-1 : 0;
    $records_per_page = isset($records_per_page) ? $records_per_page : 3;
    $pagination = $products->paginate($page_index, $records_per_page);
  }
  else
    $pagination = null;

  $products = $products instanceof Db_ActiveRecord ? $products->find_all() : $products;
?>
{% if paginate %}
  {% set page_index = page_index is null ? 0 : page_index-1 %}
  {% set records_per_page = records_per_page is null ? 3 : records_per_page %}
  {% set pagination = products.paginate(page_index, records_per_page) %}
{% else %}
  {% set pagination = null %}
{% endif %}

{% set products = products is instance_of('Shop_Product')  ? products.find_all() : products %}

This code snippet check whether the $paginate variable exists and if its value is true. If so, the code initializes the $page_index, $records_per_page variables and $pagination object. The $paginate variable is reserved for turning the pagination feature on and off.

The tricky code in the end of the snippet makes the code more dynamic. If the $products variable passed to the partial is an instance of the Db_ActiveRecord class, the code calls its find_all() method, which returns a product collection.

Now, we need to customize the product list displaying code on the category page:

<? $this->render_partial('shop:product_list', array(
  'products'=>$category->list_products(),
  'records_per_page'=>5,
  'paginate'=>true,
  'pagination_base_url'=>$category->page_url('category'),
  'page_index'=>$this->request_param(1, 0)
)) ?>
{{ render_partial('shop:product_list', {
  'products': category.list_products(),
  'records_per_page': 5,
  'paginate': true,
  'pagination_base_url': category.page_url('category'),
  'page_index': request_param(1, 0)
}) }}

First, notice the value passed to the proaducts parameter. We do not call the find_all() method on the result of the category list_products() method this time, because now we want the product list partial to paginate the product list before displaying it.

The page_index parameter represents an index of a currently open page. Page index is passed through the URL. To read values from URL you use method request_param() of the controller object. This method has 2 parameters - an index of the URL segment to return and a default value to return if the index does not exist. For category pages, page index follows the category URL name, like this: http://yoursite.com/category/computers/2 - the category URL name is "computers", the page is 2. To load the page index value from the URL you need to use the following code: $this->request_param(1, 0). This code returns a value of the URL parameter with index 1. If the index is not present, the code return 0. Indexes are zero-based. For category pages a parameter with index 0 represents the category URL name, so we need to load a parameter with index 1.

The pagination_base_url parameter will be used in the following chapter.

Using nested category URLs

The nested category URLs support is disabled by default. You can enable category nesting on System/Settings/eCommerce Settings page. When the feature is enabled, category page URLs can have different number of segments (parameters) and loading the page index from the second URL parameter will not work for categories which have URLs with more than one segment, like men/jumpers. The request_param() method supports negative values of the first parameters, allowing you to load parameters from the end of the URL. If you need to get the last URL parameter, call $this->request_param(-1, 0). Updated pagination setup for nested category URLs: 

<? $this->render_partial('shop:product_list', array(
  'products'=>$category->list_products(),
  'records_per_page'=>5,
  'paginate'=>true,
  'pagination_base_url'=>$category->page_url('category'),
  'page_index'=>$this->request_param(-1, 0)
)) ?>
{{ render_partial('shop:product_list', {
  'products': category.list_products(),
  'records_per_page': 5,
  'paginate': true,
  'pagination_base_url': category.page_url('category'),
  'page_index': request_param(-1, 0)
}) }}

Displaying links to other pages

Obviously, you will want to output a list of links to other pages. You can do it, using the $pagination object obtained with $products->paginate() method call. $pagination object is an instance of the Phpr_Pagination class and it contains all pagination-related information. The way you output the page list is not limited with any restrictions. Let's output the page list in format like this:

It is better if you create a separate partial for displaying the pagination markup, because you may need to use pagination not only on a products page, but also on any other page (a list of customer orders, for example). Create a new partial and assign some name to it, for example "pagination". To output a list of links the partial will accept 2 parameters - the pagination object and a base URL of pages. Base URL is a page URL without a page index in the end. For example, if you display a list of a category products, your base URL could be /category/computers. An URL of a specific page could be /category/computers/2.

The following code outputs a pagination markup exactly like displayed on the image above. You can customize the code if it is needed.

The optional $suffix parameter can be used for cases when you need to pass some extra parameters in the URL after the page index. In the Demo website we use the $suffix parameter for passing the search string through the URL.

Now you can output the pagination markup below the product list in the product list partial. Just render the partial we just created:

<?
if ($pagination)
  $this->render_partial('pagination', array('pagination'=>$pagination, 'base_url'=>$pagination_base_url));
?>
{% if pagination %}
  render_partial('pagination', {'pagination': pagination, 'base_url': pagination_base_url})
{% endif %}

See also:

Next: Displaying a List of Grouped Products
Previous: Products
Return to Products