I created the requested Linked Products contribution:
http://www.opencart.com/index.php?route ... ion_id=112
The above link is simply a zipped version of a text file with a list of instructions of what code to add to which files to make it all work. I will copy that same text here, which lists all the installation steps and explains why I chose this method of installation:
Related Products Feature, version 1.x
With this contribution you can define one or more related products for each product. For example, suppose you are selling a blue men's shirt, then you can define a red tie and gold cuff links as related products. These two products will then automatically be listed with the shirt as recommended mathing products to buy. The links work both ways, so in this example the blue shirt will also automatically be shown as recommended matching product with the red tie and the gold cuff links.
In the Admin, when you edit or create a new product a new tab "Related" is shown. There you will see a list of all products except the current product. Any one or more of those products can be checked to indicate it as a related product. A problem with this is that it might not work well with a store with a large number of products (say a few hundred or more), because this will make the product list very long and therefore it may be difficult to scroll to the products you want to check.
This contribution is based in part on the Related Products module
http://forum.opencart0.com/index.php/topic,2160.0.html by Mike for version 0.7.9-RC3, which in turn was an update of the contribution
http://forum.opencart0.com/index.php/topic,1244.0.html by Jarek.
Most contributions/modules are presented as a collection of files to overwrite. The problem with that is that this makes those contributions become outdated very fast. For example, I am using version 1.1.8 while at this time the latest downloadable version of OpenCart is 1.2.5. So if someone with 1.2.5 installed overwrote certain files containing my contribution based on 1.1.8 files, that would create a problem because parts of the files might introduce old bugs which had been fixed or they might be incompatible with 1.2.5. Or suppose you have made your own changes in some files. Then you would have to redo all those changes in the files being overwritten.
For these reasons, I am presenting my contribution not in the form of complete files to be overwritten, but in the form of an instruction list of what to change in which files. That way newer file versions, and your own hacks, will not be overwritten. You will only add new things without modifying all the rest, so that there is much less risk of introducing old bugs or incompatibilities. Also, if at a later time you need to port this contribution to a future big version update, say 2.x, it will be much easier to do based on a list of instructions instead of a collection of files. Of course I hope this contribution will be added to the core, to prevent this porting problem all together :-)
This method also makes it easier for you to see what exactly is being changed or added, so it will be easier for the programmers under you to make adaptions or improvements to this contribution if you wish.
Here are the installation instructions in 10 steps:
***************
A. The Database
***************
1.Create the following new table:
CREATE TABLE `related_products` (
`product_id` int(11) NOT NULL,
`related_product_id` int(11) NOT NULL,
PRIMARY KEY (`product_id`,`related_product_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
************
B. The Admin
************
2.Add the following sections of code to admin/model/catalog/product.php:
At the end of the function addProduct you see the line:
Code: Select all
$this->cache->delete('product'); [approximately line 60]
just before that line add:
Code: Select all
if (isset($data['related'])) {
foreach ($data['related'] as $related_product_id) {
$this->db->query("INSERT INTO related_products SET product_id = '" . (int)$product_id . "', related_product_id = '" . (int)$related_product_id . "'");
$this->db->query("INSERT INTO related_products SET related_product_id = '" . (int)$product_id . "', product_id = '" . (int)$related_product_id . "'");
}
}
At the end of the function editProduct you see the line:
Code: Select all
$this->cache->delete('product'); [approximately line 133]
just before that line add:
Code: Select all
$this->db->query("DELETE FROM related_products WHERE product_id = '" . (int)$product_id . "'");
$this->db->query("DELETE FROM related_products WHERE related_product_id = '" . (int)$product_id . "'");
if (isset($data['related'])) {
foreach ($data['related'] as $related_product_id) {
$this->db->query("INSERT INTO related_products SET product_id = '" . (int)$product_id . "', related_product_id = '" . (int)$related_product_id . "'");
$this->db->query("INSERT INTO related_products SET related_product_id = '" . (int)$product_id . "', product_id = '" . (int)$related_product_id . "'");
}
}
At the end of the function deleteProduct you see the line:
Code: Select all
$this->cache->delete('product'); [approximately line 148]
just before that line add:
Code: Select all
$this->db->query("DELETE FROM related_products WHERE product_id = '" . (int)$product_id . "'");
$this->db->query("DELETE FROM related_products WHERE related_product_id = '" . (int)$product_id . "'");
Between the functions getProductDescriptions and getProductOptions [approximately at line 224] add:
Code: Select all
public function CheckRelated($product_id1, $product_id2) {
if (!$product_id1 || !$product_id2) {
return FALSE;
}
$query = $this->db->query("select * from related_products WHERE product_id = '" . (int)$product_id1 . "' AND related_product_id = '" . (int)$product_id2 . "'");
if ($query->rows) {
return TRUE;
}
else {
return FALSE;
}
}
3.Add the following sections of code to admin/controller/catalog/product.php:
After the line:
Code: Select all
$this->data['entry_discount'] = $this->language->get('entry_discount'); [approximately line 381]
add the line:
Code: Select all
$this->data['entry_related'] = $this->language->get('entry_related');
After the line:
Code: Select all
$this->data['tab_category'] = $this->language->get('tab_category'); [approximately line 397]
add the line:
Code: Select all
$this->data['tab_related'] = $this->language->get('tab_related');
At the end of the function getForm you see the line:
Code: Select all
$this->render(); [approximately line 623]
just before that line add:
Code: Select all
$results = $this->model_catalog_product->getProducts();
foreach ($results as $result) {
if (isset($this->request->get['product_id'])) {
$related=$this->model_catalog_product->CheckRelated($this->request->get['product_id'], $result['product_id']);
}
else {
$related=FALSE;
}
$this->data['products'][] = array(
'product_id' => $result['product_id'],
'name' => $result['name'],
'model' => $result['model'],
'status' => ($result['status'] ? $this->language->get('text_enabled') : $this->language->get('text_disabled')),
'sort_order' => $result['sort_order'],
'delete' => in_array($result['product_id'], (array)@$this->request->post['delete']),
'action' => $action,
'related' => $related
);
}
4.Add the following sections of code to admin/view/template/catalog/product_form.tpl:
In line 15, right after:
Code: Select all
<a tab="#tab_category"><?php echo $tab_category; ?></a>
and just before:
add:
Code: Select all
<a tab="#tab_related"><?php echo $tab_related; ?></a>
Just before:
add:
Code: Select all
<div id="tab_related" class="page"><?php echo $entry_related; ?><br />
<div class="scrollbox">
<?php $class = 'odd'; ?>
<?php foreach ($products as $product) { ?>
<?php if (!isset($this->request->get['product_id']) || $this->request->get['product_id'] != $product['product_id']) { ?>
<?php $class = ($class == 'even' ? 'odd' : 'even'); ?>
<div class="<?php echo $class; ?>">
<?php if ($product['related']) { ?>
<input type="checkbox" name="related[]" value="<?php echo $product['product_id']; ?>" checked="checked" />
<?php } else { ?>
<input type="checkbox" name="related[]" value="<?php echo $product['product_id']; ?>" />
<?php } ?>
<?php echo $product['name']; ?>
</div>
<?php } ?>
<?php } ?>
</div></div>
If you have installed my previous contribution "Product Copy Feature, version 1.1.8", see
http://forum.opencart.com/viewtopic.php?f=23&t=3315 then the line above:
should be changed to:
Code: Select all
<?php $class = 'odd'; global $action; ?>
and the line above:
Code: Select all
<?php if (!isset($this->request->get['product_id']) || $this->request->get['product_id'] != $product['product_id']) { ?>
should be changed to:
Code: Select all
<?php if (!isset($this->request->get['product_id']) || $action->method=="insert" || $this->request->get['product_id'] != $product['product_id']) { ?>
5.Add the following code to admin/language/english/english.php:
After the line:
Code: Select all
$_['tab_update'] = 'Update'; [approximately line 70]
add:
6.Add the following code to admin/language/english/catalog/product.php:
After the line:
Code: Select all
$_['entry_download'] = 'Downloads:'; [approximately line 39]
add:
Code: Select all
$_['entry_related'] = 'Recommended matching products:';
******************
C. The Store Front
******************
7.Add the following code to catalog/model/catalog/product.php:
Between the functions getPopularProducts and updateViewed [approximately at line 96] add:
Code: Select all
public function getRelatedProducts($product_id) {
$query = $this->db->query("SELECT * FROM (product p LEFT JOIN product_description pd ON (p.product_id = pd.product_id) LEFT JOIN image i ON (p.image_id = i.image_id)) JOIN related_products rp ON (p.product_id = rp.product_id) WHERE p.status = '1' AND pd.language_id = '" . (int)$this->language->getId() . "' AND p.date_available <= NOW() AND p.status = '1' AND rp.related_product_id = '" . (int)$product_id . "' ORDER BY p.viewed DESC");
$product = $query->rows;
return $product;
}
8.Add the following sections of code to catalog/controller/product/product.php:
After the line:
Code: Select all
$this->data['text_note'] = $this->language->get('text_note'); [approximately line 121]
add the lines:
Code: Select all
$this->data['text_related'] = $this->language->get('text_related');
$this->data['text_no_related'] = $this->language->get('text_no_related');
After the line:
Code: Select all
$this->model_catalog_product->updateViewed($this->request->get['product_id']); [approximately line 193]
add the code:
Code: Select all
$this->data['products'] = array();
$results = $this->model_catalog_product->getRelatedProducts($this->request->get['product_id']);
foreach ($results as $result) {
$rating = $this->model_catalog_review->getAverageRating($result['product_id']);
$this->data['products'][] = array(
'name' => $result['name'],
'model' => $result['model'],
'rating' => $rating,
'stars' => sprintf($this->language->get('text_stars'), $rating),
'thumb' => HelperImage::resize($result['filename'], 120, 120),
'price' => $this->currency->format($this->tax->calculate($result['price'], $result['tax_class_id'], $this->config->get('config_tax'))),
'href' => $this->url->http('product/product&product_id=' . $result['product_id'])
);
}
9.Add the following code to catalog/view/template/product/product.tpl:
Just before the lines:
Code: Select all
</div> [approximately line 229]
<div class="bottom"></div> [approximately line 231]
add the following lines:
Code: Select all
<div class="heading"><?php echo $text_related; ?></div>
<?php if (!sizeof($products)) {
echo "<p>$text_no_related</p>";
}?>
<table class="list">
<?php for ($i = 0; $i < sizeof($products); $i = $i + 4) { ?>
<tr>
<?php for ($j = $i; $j < ($i + 4); $j++) { ?>
<td width="25%"><?php if (isset($products[$j])) { ?>
<a href="<?php echo $products[$j]['href']; ?>"><img src="<?php echo $products[$j]['thumb']; ?>" title="<?php echo $products[$j]['name']; ?>" alt="<?php echo $products[$j]['name']; ?>" /></a><br />
<a href="<?php echo $products[$j]['href']; ?>"><?php echo $products[$j]['name']; ?></a><br />
<span style="color: #999; font-size: 11px;"><?php echo $products[$j]['model']; ?></span><br />
<span style="color: #900; font-weight: bold;"><?php echo $products[$j]['price']; ?></span><br />
<?php if ($products[$j]['rating']) { ?>
<img src="catalog/view/image/stars_<?php echo $products[$j]['rating'] . '.png'; ?>" alt="<?php echo $products[$j]['stars']; ?>" />
<?php } ?>
<?php } ?></td>
<?php } ?>
</tr>
<?php } ?>
</table>
10.Add the following code to catalog/language/english/product/product.php:
After the line:
Code: Select all
$_['text_success'] = 'Thank you for your review. It has been submitted to the webmaster for approval.'; [approximately line 19]
add the lines:
Code: Select all
$_['text_related'] = 'Recommended matching products to buy';
$_['text_no_related'] = 'No recommendations';
I created the above list of instructions by tracing back the changes I made to get this working correctly. If this does not work for you, then please check that you made all the correct changes. If that does not solve the problem, then perhaps I made some mistake writing these instructions. In that case please let me know what problem or error you get, and I will correct it.
Questions, comments? Email me at
henry@sturman.net
March 30, 2009