Jump to content
Latest News: (loading..)
frankl

Remove Product Schema from form on product_info.php

Recommended Posts

Currently product schema is spread throughout the product_info.php page as microdata, including in and out of the form. Using LD-JSON we can bring all the markup together as a header tag module, making it easy to update or alter.

 

I have attached a header tag module ht_product_schema.php, language file, and a revised product_info.php with microdata removed.

 

Just upload and turn on header tag module Modules -> Header Tags -> Install Module -> Product Schema meta Tags

 

(upload will overwrite existing product_info.php file!)

 

Test -> Structured Data Testing Tool

 

Thoughts?

ht_product_schema.zip


Let's make things easier for new osCommerce users http://forums.oscommerce.com/topic/402638-discussion-about-hard-coded-database-tables/?p=1718900  Getting there with osCommerce 2.4! :thumbsup:

Share this post


Link to post
Share on other sites

IIRC we were talking about something similar on a thread here or at git hub, a while back.  At that time, I got as far as testing something hard-coded into product_info, then gave up when reallife got in the way.  I should still have that hard-coded stuff somewhere, between your code and mine (and anyone else who wants to have an input, of course), perhaps we can come up with something to patch into Core.

 

Doing this would also simplify the upcoming modular product_info stuff...

 

Nice work @@frankl, thankyou for helping move osC forward all the time. 


This is a signature that appears on all my posts.  
IF YOU MAKE A POST REQUESTING HELP...please state the exact version
of osCommerce that you are using. THANKS

 
Get the latest current code (community-supported responsive 2.3.4.1BS Edge) here

 

Share this post


Link to post
Share on other sites

Ok, that took some hunting down, here is as far as I got (I've cleaned it up a little bit).

 

 

$schema_product = array("@context"                       =>  "http://schema.org",
                        "@type"                          => "Product",
                        "name"                           => "product name",
                        "image"                          => "product image url",
                        "description"                    => "product description",
                        "mpn"                            => "product model",
                        "gtin13"                         => "product gtin");
                        
$schema_product['offers'] = array("@type"                => "Offer",
                                  "priceCurrency"        => "CUR CODE",
                                  "price"                => "xx.yy",
                                  "priceValidUntil"      => "date",
                                  "availability"         => "date");
$schema_product['offers']['seller'] = array("@type"      => "Organization",
                                            "name"       => "store name");
                                                                              
$schema_product['manufacturer'] = array("@type"          => "Organization",
                                        "name"           => "product manufacturer");
                                        
$schema_product['aggregateRating'] = array("@type"       => "AggregateRating",
                                           "ratingValue" => "x",
                                           "reviewCount" => "y");

 

Putting the data into arrays like this, make it easier to add in (or remove) data programmatically as needed...


This is a signature that appears on all my posts.  
IF YOU MAKE A POST REQUESTING HELP...please state the exact version
of osCommerce that you are using. THANKS

 
Get the latest current code (community-supported responsive 2.3.4.1BS Edge) here

 

Share this post


Link to post
Share on other sites

OK...this UNTESTED. Anyone with mad-skillz feel free to hack at it.

This is attempt v1.0, and is up for testing, tweaking and most importantly comments of relevance.

 

Using Franks module. Replace the execute function as so:

 

    function execute() {
      global $PHP_SELF, $oscTemplate, $product_check, $languages_id, $currency, $currencies;

      if ($product_check['total'] > 0) {        
        $product_info_query = tep_db_query("select p.products_id, pd.products_name, pd.products_description, p.products_model, p.manufacturers_id, p.products_image, p.products_price, p.products_quantity, p.products_tax_class_id, p.products_date_available, p.products_gtin from products p, products_description pd where p.products_id = '" . (int)$_GET['products_id'] . "' and p.products_status = '1' and p.products_id = pd.products_id and pd.language_id = '" . (int)$languages_id . "'");

        if ( tep_db_num_rows($product_info_query) ) {
          $product_info = tep_db_fetch_array($product_info_query);  
          
          $products_image = $product_info['products_image'];
          $pi_query = tep_db_query("select image from products_images where products_id = '" . (int)$product_info['products_id'] . "' order by sort_order limit 1");
          if ( tep_db_num_rows($pi_query) ) {
            $pi = tep_db_fetch_array($pi_query);
            $products_image = $pi['image'];
          }
          
          $schema_product = array("@context"                         => "http://schema.org",
                                  "@type"                            => "Product",
                                  "name"                             => tep_db_output($product_info['products_name']),
                                  "image"                            => tep_href_link('images/' . $products_image, '', 'NONSSL', false, false),
                                  "description"                      => substr(trim(preg_replace('/\s\s+/', ' ', strip_tags($product_info['products_description']))), 0, 197) . '...');
                                  
          if (tep_not_null($product_info['products_model'])) {
            $schema_product['mpn']                                   = tep_db_output($product_info['products_model']);
          }
          
          if (tep_not_null($product_info['products_gtin'])) {
            $schema_product['gtin' .  MODULE_CONTENT_PRODUCT_INFO_GTIN_LENGTH] = tep_db_output(substr($product_info['products_gtin'], 0-MODULE_CONTENT_PRODUCT_INFO_GTIN_LENGTH));
          }
          
          $schema_product['offers'] = array("@type"                  => "Offer",
                                            "priceCurrency"          => $currency);
                                            
          if ($new_price = tep_get_products_special_price($product_info['products_id'])) {
            $products_price = $currencies->display_raw($new_price, tep_get_tax_rate($product_info['products_tax_class_id']));
          } else {
            $products_price = $currencies->display_raw($product_info['products_price'], tep_get_tax_rate($product_info['products_tax_class_id']));
          }          
          
          $schema_product['offers']['price'] = $products_price;
          
          $specials_expiry_query = tep_db_query("select expires_date from specials where products_id = '" . (int)$product_info['products_id'] . "' and status = 1");
if ( tep_db_num_rows($specials_expiry_query) ) {
            $specials_expiry = tep_db_fetch_array($specials_expiry_query); 
            
            $schema_product['offers']['priceValidUntil'] = $specials_expiry['expires_date'];
          }
          
          $availability = ( $product_info['products_quantity'] > 0 ) ? MODULE_HEADER_TAGS_PRODUCT_SCHEMA_TEXT_IN_STOCK : MODULE_HEADER_TAGS_PRODUCT_SCHEMA_TEXT_OUT_OF_STOCK;
          $schema_product['offers']['availability'] = $availability;          
                                            
          $schema_product['offers']['seller'] = array("@type"        => "Organization",
                                                      "name"         => STORE_NAME);
                                                                              
          $manufacturers_name_query = tep_db_query("select manufacturers_name from manufacturers where manufacturers_id='" . (int)$product_info['manufacturers_id'] . "'");
     if ( tep_db_num_rows($manufacturers_name_query) ) {
            $manufacturers_name = tep_db_fetch_array($manufacturers_name_query);
            $schema_product['manufacturer'] = array("@type"          => "Organization",
                                                    "name"           => tep_db_output($manufacturers_name['manufacturers_name']));
          }
                                        
          $average_query = tep_db_query("select AVG(r.reviews_rating) as average, COUNT(r.reviews_rating) as count from reviews r where r.products_id = '" . (int)$product_info['products_id'] . "' and r.reviews_status = 1");
     $average = tep_db_fetch_array($average_query);
     if ( $average['count'] > 0 ) {
            $schema_product['aggregateRating'] = array("@type"       => "AggregateRating",
                                                       "ratingValue" => (int)$average['average'],
                                                       "reviewCount" => (int)$average['count']);
          }
          
          // place a HOOK here
          // allows to update $schema_product array 
          // with no core changes...
          // untested, uncoded
          
          $data = json_encode($schema_product);

          $oscTemplate->addBlock('<script type="application/ld+json">' . $data . '</script>', $this->group);
        }
      }
    }
Why so much complicated code? It creates an array of data ready to be used.

It is so incredibly simple to manipulate arrays of data...

 

Imagine:

 

// place a HOOK here
A hook there which allows a user to simple upload a file into a directory. This new file adds in extra data to the array, let's say that in your shop you use the Core SEO which has the ability to have a different SEO name for a product. 1 hook file writing that data as https://schema.org/alternateName and upload...it's working. Set and forget.

 

PLEASE NOTE:

My code is UNTESTED and is subject to change or filed under B for Bin.

This is what I was working on months back, plugged into Franks Module.

Edited by burt
added global, updated sql for gtin

This is a signature that appears on all my posts.  
IF YOU MAKE A POST REQUESTING HELP...please state the exact version
of osCommerce that you are using. THANKS

 
Get the latest current code (community-supported responsive 2.3.4.1BS Edge) here

 

Share this post


Link to post
Share on other sites

It's also possible to use the javascript array values to add to the html page (via javascript). This is how the breadcrumb links are shown on the Live Sites website, source at:

 

https://github.com/haraldpdl/website_sites/blob/master/osCommerce/OM/Custom/Site/Sites/Module/Template/Widget/breadcrumb_nav/Controller.php

 

This can save multiple queries or loops.


:heart:, osCommerce

Share this post


Link to post
Share on other sites

I have the product info as json-ld in a header tag, but it uses a product(info) class.

I have tried this way to safe on queries.

Must say, I like the added flexibility that the integrated hook brings.


KEEP CALM AND CARRY ON
FYI Upgrade to the highest PHP version you can( PHP 5.5/5.6 or 7.1  and get big performance improvements for free)

But be aware php 5.5 is more strict about things.
UTF8-without BOM, no extra spaces allowed at the beginning or end of your php file, or your redirects wont work.
No double declarations of functions allowed - used to slip through the cracks ...

 

Find the most frequent unique errors to fix:

grep "PHP" php_error_log.txt | sed "s/^.* PHP/PHP/g" |grep "line" |sort | uniq -c | sort -r > counterrors.txt

Share this post


Link to post
Share on other sites

OK...this UNTESTED. Anyone with mad-skillz feel free to hack at it.

This is attempt v1.0, and is up for testing, tweaking and most importantly comments of relevance.

 

Using Franks module. Replace the execute function as so:

 

    function execute() {
      global $PHP_SELF, $oscTemplate, $product_check, $languages_id, $currency, $currencies;

      if ($product_check['total'] > 0) {        
        $product_info_query = tep_db_query("select p.products_id, pd.products_name, pd.products_description, p.products_model, p.manufacturers_id, p.products_image, p.products_price, p.products_quantity, p.products_tax_class_id, p.products_date_available, p.products_gtin from products p, products_description pd where p.products_id = '" . (int)$_GET['products_id'] . "' and p.products_status = '1' and p.products_id = pd.products_id and pd.language_id = '" . (int)$languages_id . "'");

        if ( tep_db_num_rows($product_info_query) ) {
          $product_info = tep_db_fetch_array($product_info_query);  
          
          $products_image = $product_info['products_image'];
          $pi_query = tep_db_query("select image from products_images where products_id = '" . (int)$product_info['products_id'] . "' order by sort_order limit 1");
          if ( tep_db_num_rows($pi_query) ) {
            $pi = tep_db_fetch_array($pi_query);
            $products_image = $pi['image'];
          }
          
          $schema_product = array("@context"                         => "http://schema.org",
                                  "@type"                            => "Product",
                                  "name"                             => tep_db_output($product_info['products_name']),
                                  "image"                            => tep_href_link('images/' . $products_image, '', 'NONSSL', false, false),
                                  "description"                      => substr(trim(preg_replace('/\s\s+/', ' ', strip_tags($product_info['products_description']))), 0, 197) . '...');
                                  
          if (tep_not_null($product_info['products_model'])) {
            $schema_product['mpn']                                   = tep_db_output($product_info['products_model']);
          }
          
          if (tep_not_null($gtin['products_gtin'])) {
            $schema_product['gtin' .  MODULE_CONTENT_PRODUCT_INFO_GTIN_LENGTH] = tep_db_output(substr($product_info['products_gtin'], 0-MODULE_CONTENT_PRODUCT_INFO_GTIN_LENGTH));
          }
          
          $schema_product['offers'] = array("@type"                  => "Offer",
                                            "priceCurrency"          => $currency);
                                            
          if ($new_price = tep_get_products_special_price($product_info['products_id'])) {
            $products_price = $currencies->display_raw($new_price, tep_get_tax_rate($product_info['products_tax_class_id']));
          } else {
            $products_price = $currencies->display_raw($product_info['products_price'], tep_get_tax_rate($product_info['products_tax_class_id']));
          }          
          
          $schema_product['offers']['price'] = $products_price;
          
          $specials_expiry_query = tep_db_query("select expires_date from specials where products_id = '" . (int)$product_info['products_id'] . "' and status = 1");
if ( tep_db_num_rows($specials_expiry_query) ) {
            $specials_expiry = tep_db_fetch_array($specials_expiry_query); 
            
            $schema_product['offers']['priceValidUntil'] = $specials_expiry['expires_date'];
          }
          
          $availability = ( $product_info['products_quantity'] > 0 ) ? MODULE_HEADER_TAGS_PRODUCT_SCHEMA_TEXT_IN_STOCK : MODULE_HEADER_TAGS_PRODUCT_SCHEMA_TEXT_OUT_OF_STOCK;
          $schema_product['offers']['availability'] = $availability;          
                                            
          $schema_product['offers']['seller'] = array("@type"        => "Organization",
                                                      "name"         => STORE_NAME);
                                                                              
          $manufacturers_name_query = tep_db_query("select manufacturers_name from manufacturers where manufacturers_id='" . (int)$product_info['manufacturers_id'] . "'");
     if ( tep_db_num_rows($manufacturers_name_query) ) {
            $manufacturers_name = tep_db_fetch_array($manufacturers_name_query);
            $schema_product['manufacturer'] = array("@type"          => "Organization",
                                                    "name"           => tep_db_output($manufacturers_name['manufacturers_name']));
          }
                                        
          $average_query = tep_db_query("select AVG(r.reviews_rating) as average, COUNT(r.reviews_rating) as count from reviews r where r.products_id = '" . (int)$product_info['products_id'] . "' and r.reviews_status = 1");
     $average = tep_db_fetch_array($average_query);
     if ( $average['count'] > 0 ) {
            $schema_product['aggregateRating'] = array("@type"       => "AggregateRating",
                                                       "ratingValue" => (int)$average['average'],
                                                       "reviewCount" => (int)$average['count']);
          }
          
          // place a HOOK here
          // allows to update $schema_product array 
          // with no core changes...
          // untested, uncoded
          
          $data = json_encode($schema_product);

          $oscTemplate->addBlock('<script type="application/ld+json">' . $data . '</script>', $this->group);
        }
      }
    }
Why so much complicated code? It creates an array of data ready to be used.

It is so incredibly simple to manipulate arrays of data...

 

Imagine:

 

// place a HOOK here
A hook there which allows a user to simple upload a file into a directory. This new file adds in extra data to the array, let's say that in your shop you use the Core SEO which has the ability to have a different SEO name for a product. 1 hook file writing that data as https://schema.org/alternateName and upload...it's working. Set and forget.

 

PLEASE NOTE:

My code is UNTESTED and is subject to change or filed under B for Bin.

This is what I was working on months back, plugged into Franks Module.

 

 

 

A much better approach than my sloppy attempt! This code tested fine Gary, apart from the line

if (tep_not_null($gtin['products_gtin'])) {

which should be

if (tep_not_null($product_info['products_gtin'])) {

See results at Structured Data Testing Tool - Out of stock item, Product on special with expiry date, Product with GTIN, Product with reviews

 

This is what it looks like in the source code, I wasn't sure if it would work all run together like this, but it vaidates correctly :)

<script type="application/ld+json">{"@context":"http:\/\/schema.org","@type":"Product","name":"Matrox G200 MMS","image":"https:\/\/www.tonerpak.com.au\/edge3\/images\/matrox\/mg200mms.gif","description":"Reinforcing its position as a multi-monitor trailblazer, Matrox Graphics Inc. has once again developed the most flexible and highly advanced solution in the industry. Introducing the new Matrox G20...","mpn":"MG200MMS","gtin13":"2345678910111","offers":{"@type":"Offer","priceCurrency":"USD","price":"299.99","availability":"http:\/\/schema.org\/OutOfStock","seller":{"@type":"Organization","name":"TestEdge2"}},"manufacturer":{"@type":"Organization","name":"Matrox"}}</script>

Let's make things easier for new osCommerce users http://forums.oscommerce.com/topic/402638-discussion-about-hard-coded-database-tables/?p=1718900  Getting there with osCommerce 2.4! :thumbsup:

Share this post


Link to post
Share on other sites

This could be the perfect opportunity to finally get a product class integrated into core...

This module could be the first use of it.

 

Thoughts?


This is a signature that appears on all my posts.  
IF YOU MAKE A POST REQUESTING HELP...please state the exact version
of osCommerce that you are using. THANKS

 
Get the latest current code (community-supported responsive 2.3.4.1BS Edge) here

 

Share this post


Link to post
Share on other sites

I'll liaise with the team to find out what plans are in store for 2.4.

Would be good to have the same class in both 2.4 and Community 234r


This is a signature that appears on all my posts.  
IF YOU MAKE A POST REQUESTING HELP...please state the exact version
of osCommerce that you are using. THANKS

 
Get the latest current code (community-supported responsive 2.3.4.1BS Edge) here

 

Share this post


Link to post
Share on other sites

@@burt

 

 

Yes :) - Could be of great use. I think @@wHiTeHaT allready backported V3.0 product class ... Can not find it right now ...

 

@@wHiTeHaT - wondering if you can remember doing this??


This is a signature that appears on all my posts.  
IF YOU MAKE A POST REQUESTING HELP...please state the exact version
of osCommerce that you are using. THANKS

 
Get the latest current code (community-supported responsive 2.3.4.1BS Edge) here

 

Share this post


Link to post
Share on other sites

@@burt, yes i remember.

But that class uses the variants system as attributes (better maintaining/adding/create variants).

 

Advantages:

advantage is that when you require a new type of variant like a product color selection, it can be written as a drop in file and choose to install this new attribute(variant) type.

or imagine a dimension or weight attribute that calculates the price.

 

Disadvantage :

-no converter from old to new attributes system

-requires also usage of a new shoppingcart class that treaths products as items

-requires new table for products with several new fields.

One 2 of these fields is to determine the product has attributes.

1 field (parent_id, also known from the categories table calculates if the product is a parent ( 0 ) or has variants( parent_id = primary product_id).

 

overall conclusion, changing to the backported class seems an improvement but it has drastic changes to front-end/back-end and database tables/fields.

Share this post


Link to post
Share on other sites

I don't think we ever came to a consensus regarding a product_info class that is workable and simple...

I'll take a closer look at 2.4 and see what is being done there regarding a product class and report back.


This is a signature that appears on all my posts.  
IF YOU MAKE A POST REQUESTING HELP...please state the exact version
of osCommerce that you are using. THANKS

 
Get the latest current code (community-supported responsive 2.3.4.1BS Edge) here

 

Share this post


Link to post
Share on other sites

This is a signature that appears on all my posts.  
IF YOU MAKE A POST REQUESTING HELP...please state the exact version
of osCommerce that you are using. THANKS

 
Get the latest current code (community-supported responsive 2.3.4.1BS Edge) here

 

Share this post


Link to post
Share on other sites
Posted (edited)
On 3-3-2017 at 12:11 PM, burt said:

I don't think we ever came to a consensus regarding a product_info class that is workable and simple...

 

It will not get any better:
 

<?php


class Product {


protected $_data = array();

    function __construct($id) {
      
	  global $languages_id;
	    
		if ( tep_not_null($id) ){
          $product_data_query = tep_db_query("select products_id as id, products_quantity as quantity, products_price as price, products_model as model, products_gtin as gtin, products_tax_class_id as tax_class_id, products_weight as weight, products_date_added as date_added, manufacturers_id from products where products_id = '" . (int)$id . "' and products_status = '1' ");
			
			$product_data = tep_db_fetch_array($product_data_query);
			$this->_data = $product_data;
            $this->_data['master_id'] = $product_data['id'];
            
			if ( $product_data !== false && !empty($this->_data) ) {
              
				$product_info_query = tep_db_query("select products_name as name, products_description as description, products_url as url from products_description where products_id = '" . $this->_data['master_id'] . "' and language_id = '" . (int)$languages_id . "'");
				$product_info = tep_db_fetch_array($product_info_query);
				
				$this->_data = array_merge($this->_data, $product_info);			  
		    }
			
			if ( !empty($this->_data) ) {
				
				$product_images_query = tep_db_query("select id, image, default_flag from products_images where products_id = '" . $this->_data['master_id'] . "' order by sort_order");
				$product_images = tep_db_fetch_array($product_images_query);
				
				$this->_data['images'] = $product_images;						
			}

			if ( !empty($this->_data) ) {
				
				$product_category_query = tep_db_query("select categories_id from products_to_categories where products_id = '" . $this->_data['master_id'] . "' limit 1");
				$product_category = tep_db_fetch_array($product_images_query);
				
				$this->_data['category_id'] = $product_category;						
			
			//under developement
				$products_attributes_query = tep_db_query("select count(*) as total from products_options popt, products_attributes patrib where patrib.products_id='" . $this->_data['master_id'] . "' and patrib.options_id = popt.products_options_id and popt.language_id = '" . (int)$languages_id . "'");
				$products_attributes = tep_db_fetch_array($products_attributes_query);
				if ($products_attributes['total'] > 0) {
					$this->_data['attributes'] = $products_attributes['total'];
				
					$OSCOM_Currencies = new currencies();
					$OSCOM_ShoppingCart = new shoppingCart();

					$products_options_name_query = tep_db_query("select distinct popt.products_options_id, popt.products_options_name from products_options popt, products_attributes patrib where patrib.products_id='" . $this->_data['master_id'] . "' and patrib.options_id = popt.products_options_id and popt.language_id = '" . (int)$languages_id . "' order by popt.products_options_name");
					while ($products_options_data = tep_db_fetch_array($products_options_name_query)) {
						$this->_data['products_options_id'] = $products_options_data['products_options_id'];
						$this->_data['products_options_name'] = $products_options_data['products_options_name'];
						
						$products_options_query = tep_db_query("select pov.products_options_values_id, pov.products_options_values_name, pa.options_values_price, pa.price_prefix from products_attributes pa, products_options_values pov where pa.products_id = '" . $this->_data['master_id'] . "' and pa.options_id = '" . (int)$products_options_data['products_options_id'] . "' and pa.options_values_id = pov.products_options_values_id and pov.language_id = '" . (int)$languages_id . "'");
						while ($products_options = tep_db_fetch_array($products_options_query)) {
							$this->_data['attributes_options'][] = array('id' => $products_options['products_options_values_id'], 'text' => $products_options['products_options_values_name']);
							if ($products_options['options_values_price'] != '0') {
								$this->_data['attributes_options'][sizeof($this->_data['attributes_options'])-1]['text'] .= ' (' . $products_options['price_prefix'] . $OSCOM_Currencies->display_price($products_options['options_values_price'], tep_get_tax_rate($this->_data['tax_class_id'])) .') ';
							}
						}
					}
					if (is_string($this->_data['master_id']) && isset($OSCOM_ShoppingCart->contents[$this->_data['master_id']]['attributes'][$this->_data['products_options_id']])) {
					  $selected_attribute = $OSCOM_ShoppingCart->contents[$this->_data['master_id']]['attributes'][$this->_data['products_options_id']];
					} else {
					  $selected_attribute = false;
					}
				}				
			//under developement				
				
				$product_reviews_query = tep_db_query("select avg(reviews_rating) as rating from reviews where products_id = '" . $this->_data['master_id'] . "' and reviews_status = '1'");
				$product_reviews = tep_db_fetch_array($product_reviews_query);
				
                $this->_data['reviews_average_rating'] = round($product_reviews['rating']);
			}			
		}
	}

    public function getData($key = null) {
		
		if ( isset($this->_data[$key]) ) {
			
			return $this->_data[$key];
		}
		
		return $this->_data;
    }

    public function getID() {
		return $this->_data['id'];
    }
    public function getTitle() {
		return $this->_data['name'];
    }

    public function getDescription() {
		return $this->_data['description'];
    }

    public function hasModel() {
		return (isset($this->_data['model']) && !empty($this->_data['model']));
    }

    public function getModel() {
		return $this->_data['model'];
    }
    public function hasGtin() {
		return (isset($this->_data['gtin']) && !empty($this->_data['gtin']));
    }

    public function getGtin() {
		return $this->_data['gtin'];
    }	
    public function getPrice($with_special = false) {
		$OSCOM_Specials = new Specials();
		$OSCOM_Currencies = new currencies();
		if ( ($with_special === true) && ($new_price = $OSCOM_Specials->getPrice($this->_data['id'])) ) {
			$price = $OSCOM_Currencies->display_raw($new_price, tep_get_tax_rate($this->_data['tax_class_id']));
		} else {

			$price = $OSCOM_Currencies->display_raw($this->_data['price'], tep_get_tax_rate($this->_data['tax_class_id']));
        }
		return $price;
    }
	
    public function getPriceFormated($with_special = false) {
		$OSCOM_Specials = new Specials();
		$OSCOM_Currencies = new currencies();
		if ( ($with_special === true) && ($new_price = $OSCOM_Specials->getPrice($this->_data['id'])) ) {
			$price = '<s>' . $OSCOM_Currencies->display_price($this->_data['price'], tep_get_tax_rate($this->_data['tax_class_id'])) . '</s> <span class="productSpecialPrice">' . $OSCOM_Currencies->display_price($new_price, tep_get_tax_rate($this->_data['tax_class_id'])) . '</span>';
		} else {

			$price = $OSCOM_Currencies->display_price($this->_data['price'], $this->_data['tax_class_id']);
        }
		
		return $price;
    }
	
    public function getQuantity() {
		return $this->_data['quantity'];
    }
	
	public function getWeight() {      
		return $this->_data['weight'];
	}	
	
	
    public function hasManufacturer() {
		return ( $this->_data['manufacturers_id'] > 0 );
    }

    public function getManufacturer() {
		
		$OSCOM_Manufacturer = new Manufacturer($this->_data['manufacturers_id']);

		return $OSCOM_Manufacturer->getTitle();
    }

    public function getManufacturerID() {
		return $this->_data['manufacturers_id'];
    }

    public function getCategoryID() {
		return $this->_data['category_id'];
    }

    public function getImages() {
		foreach ( $this->_data['images'] as $image ) {
		    return $this->_data['images'];
		}
    }

    public function hasImage() {
		$images = $this->_data['images'];
		foreach ( $images as $image ) {
			if ( $image['default_flag'] == '1' ) {
				return true;
			}
		}
    }

    public function getImage() {
      
		//$images = $this->_data['images'];
		//foreach ( $images as $image ) {
			if ( $this->_data['images']['default_flag'] == '1' ) {
				return $this->_data['images']['image'];
			}
		//}
    }

    public function getDateAvailable() {
		// HPDL
		return false; //$this->_data['date_available'];
    }

    public function getDateAdded() {
		return $this->_data['date_added'];
    }
	
    public function hasAttribute($code) {
		return isset($this->_data['attributes'][$code]);
    }

    public function getAttribute($code) {
		if ( !class_exists('osC_ProductAttributes_' . $code) ) {
			if ( file_exists(DIR_FS_CATALOG . 'includes/modules/product_attributes/' . basename($code) . '.php') ) {
				include(DIR_FS_CATALOG . 'includes/modules/product_attributes/' . basename($code) . '.php');
			}
		}

		if ( class_exists('osC_ProductAttributes_' . $code) ) {
			return call_user_func(array('osC_ProductAttributes_' . $code, 'getValue'), $this->_data['attributes'][$code]);
		}
    }	
	
	public function incrementCounter() {
		tep_db_query("update products_description set products_viewed = products_viewed+1 where products_id = '" . Products::getProductID($this->_data['id']) . "' and language_id = '" . (int)$languages_id . "'");
	}
    public function numberOfImages() {
		return count($this->_data['images']);
    }
}
?>

Usage in content modules/boxes (NOT PRODUCT_INFO)
 

<?php
/*
  $Id$

  osCommerce, Open Source E-Commerce Solutions
  http://www.oscommerce.com

  Copyright (c) 2016 osCommerce

  Released under the GNU General Public License
*/

  class cm_i_new_products {
    var $code;
    var $group;
    var $title;
    var $description;
    var $sort_order;
    var $enabled = false;

    function __construct() {
      $this->code = get_class($this);
      $this->group = basename(dirname(__FILE__));

      $this->title = MODULE_CONTENT_NEW_PRODUCTS_TITLE;
      $this->description = MODULE_CONTENT_NEW_PRODUCTS_DESCRIPTION;
      $this->description .= '<div class="secWarning">' . MODULE_CONTENT_BOOTSTRAP_ROW_DESCRIPTION . '</div>';

      if ( defined('MODULE_CONTENT_NEW_PRODUCTS_STATUS') ) {
        $this->sort_order = MODULE_CONTENT_NEW_PRODUCTS_SORT_ORDER;
        $this->enabled = (MODULE_CONTENT_NEW_PRODUCTS_STATUS == 'True');
      }
    }

    function execute() {
      global $oscTemplate, $new_products_category_id, $languages_id, $currencies, $PHP_SELF, $currency;
       $data = array();
     
      $content_width = MODULE_CONTENT_NEW_PRODUCTS_CONTENT_WIDTH;
      $product_width = MODULE_CONTENT_NEW_PRODUCTS_DISPLAY_EACH;
      $OSCOM_Category = new Category();
      
		if ( $OSCOM_Category->getID() < 1 ) {
			$new_products_query = tep_db_query("select products_id from products where products_status = '1' order by products_date_added desc limit " . (int)MODULE_CONTENT_NEW_PRODUCTS_MAX_DISPLAY);
		} else {
            $new_products_query = tep_db_query("select distinct p2c.products_id from products p, products_to_categories p2c, categories c where c.parent_id = '" . $OSCOM_Category->getID() . "' and c.categories_id = p2c.categories_id and p2c.products_id = p.products_id and p.products_status = '1' order by p.products_date_added desc limit " . (int)MODULE_CONTENT_NEW_PRODUCTS_MAX_DISPLAY);
		}
      
      $num_new_products = tep_db_num_rows($new_products_query);

		if ($num_new_products > 0) {
			  
			while ($new_products = tep_db_fetch_array($new_products_query)) {
				$OSCOM_Product = new Product($new_products['products_id']);
				$OSCOM_Image = new Image();
				$data[$OSCOM_Product->getID()] = $OSCOM_Product->getData();
				$data[$OSCOM_Product->getID()]['display_price'] = $OSCOM_Product->getPriceFormated(true);
				$data[$OSCOM_Product->getID()]['display_image'] = $OSCOM_Product->getImage();
				$data[$OSCOM_Product->getID()]['display_manufacturer'] = $OSCOM_Product->getManufacturer();
			}
			ob_start();
			include('includes/modules/content/' . $this->group . '/templates/new_products.php');
			$template = ob_get_clean(); 
			
			$oscTemplate->addContent($template, $this->group);
		}
    }

    function isEnabled() {
      return $this->enabled;
    }

    function check() {
      return defined('MODULE_CONTENT_NEW_PRODUCTS_STATUS');
    }

    function install() {
      tep_db_query("insert into configuration (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Enable New Products Module', 'MODULE_CONTENT_NEW_PRODUCTS_STATUS', 'True', 'Do you want to enable this module?', '6', '1', 'tep_cfg_select_option(array(\'True\', \'False\'), ', now())");
      tep_db_query("insert into configuration (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Content Width', 'MODULE_CONTENT_NEW_PRODUCTS_CONTENT_WIDTH', '12', 'What width container should the content be shown in? (12 = full width, 6 = half width).', '6', '2', 'tep_cfg_select_option(array(\'12\', \'11\', \'10\', \'9\', \'8\', \'7\', \'6\', \'5\', \'4\', \'3\', \'2\', \'1\'), ', now())");
      tep_db_query("insert into configuration (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Maximum Display', 'MODULE_CONTENT_NEW_PRODUCTS_MAX_DISPLAY', '6', 'Maximum Number of products that should show in this module?', '6', '3', now())");
      tep_db_query("insert into configuration (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Product Width', 'MODULE_CONTENT_NEW_PRODUCTS_DISPLAY_EACH', '3', 'What width container should each product be shown in? (12 = full width, 6 = half width).', '6', '4', 'tep_cfg_select_option(array(\'12\', \'11\', \'10\', \'9\', \'8\', \'7\', \'6\', \'5\', \'4\', \'3\', \'2\', \'1\'), ', now())");
      tep_db_query("insert into configuration (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Sort Order', 'MODULE_CONTENT_NEW_PRODUCTS_SORT_ORDER', '300', 'Sort order of display. Lowest is displayed first.', '6', '5', now())");
    }

    function remove() {
      tep_db_query("delete from configuration where configuration_key in ('" . implode("', '", $this->keys()) . "')");
    }

    function keys() {
      return array('MODULE_CONTENT_NEW_PRODUCTS_STATUS', 'MODULE_CONTENT_NEW_PRODUCTS_CONTENT_WIDTH', 'MODULE_CONTENT_NEW_PRODUCTS_MAX_DISPLAY', 'MODULE_CONTENT_NEW_PRODUCTS_DISPLAY_EACH', 'MODULE_CONTENT_NEW_PRODUCTS_SORT_ORDER');
    }
  }

New products template:
 

<?php
/*
  $Id$

  osCommerce, Open Source E-Commerce Solutions
  http://www.oscommerce.com

  Copyright (c) 2016 osCommerce

  Released under the GNU General Public License
*/

$content = '<div class="col-sm-'.$content_width.' new-products">';
$content .= '	<h3>' . sprintf(MODULE_CONTENT_NEW_PRODUCTS_HEADING, strftime('%B')) . '</h3>';

	foreach ( $data as $product ) {				
		$content .= '<div class="col-sm-'. $product_width.'">';
		$content .= '	<div class="thumbnail equal-height">';			
		$content .= '		Name: <a href="' .  tep_href_link('product_info.php', 'products_id=' . $product['master_id']) . '">' . $product['name'] . '</a><br/> Rating: ' . tep_draw_stars($product['reviews_average_rating']);
		$content .= '		<a href="' .  tep_href_link('product_info.php', 'products_id=' . $product['master_id']) . '">' . $OSCOM_Image->show($product['display_image'], $product['name']) . '</a>';
		$content .= '		<p> Price: ' . $product['display_price'] .  '</p>';
		if( isset($product['model']) && !empty($product['model']) ){
		$content .= '		<p> Model: ' . $product['model'] .  '</p>';
		}
		if( isset($product['gtin']) && !empty($product['gtin']) ){
		$content .= '		<p> gTin: ' . $product['gtin'] .  '</p>';
        }		
		if( $product['manufacturers_id'] > 0 ){
		$content .= '		<p> Manufacturer: ' . $product['display_manufacturer'] .  '</p>';
		}
		if( $product['attributes'] > 0 ){
		 $content .= '<strong>' . $product['products_options_name'] . ':' . '</strong><br />' . tep_draw_pull_down_menu('id[' . $product['products_options_id'] . ']', $product['attributes_options'], $selected_attribute, 'style="width: 200px;"') . '<br />';
		}
		$content .= '	</div>';
		$content .= '</div>';       
	}	
  
$content .= '</div>';
echo  $content;

Keep in mind i also made a class

For images.
For manufacturers
For category (not categories).
For Specials
For Curencies

The work what needs to be done is refer all instances to each of above to usage of classes.
if not do it, the work on it will be useless and underestimated the principe of class usage.

Edited by wHiTeHaT

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×