Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

We've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

E-Commerce Modules /

Discuss about the various e-commerce modules available:
Ecommerce, SS Shop, SilverCart and SwipeStripe
Alternatively, have a look the shared mailinglist.

Moderators: martimiz, Nicolaas, Sean, Ed, frankmullenger, biapar, Willr, Ingo, Jedateach, swaiba

Blank Page Product Problems :O


Go to End


8 Posts   1966 Views

Avatar
ambient

Community Member, 130 Posts

3 May 2011 at 11:10pm

Hi All :)

I'm using the ecommerce module as a portfolio for recent work so I don't have a need for an individual product page.
Except when the search function is used it can bring up one of the product pages. So I formatted the individual product page in the event of someone getting to it through the search function.

But now after working on different areas of the site the individual product pages come up as blank pages :O

I have not been able to figure out what change I made that might be causing this and Firebug isn't showing any errors.

I'm at a loss with this so I'm hoping someone out there in SilverStripe land might be able to tell me what I did wrong and how I might fix it.

Any help with this is much appreciated, thanks :)

Avatar
ambient

Community Member, 130 Posts

3 May 2011 at 11:19pm

I tried attaching Product.php and ProductGroup.php to the last post but it came back with a server error so here they are :)

Product.php

<?php
/**
 * This is a standard Product page-type with fields like
 * Price, Weight, Model/Author and basic management of
 * groups.
 * 
 * It also has an associated Product_OrderItem class,
 * an extension of OrderItem, which is the mechanism
 * that links this page type class to the rest of the
 * eCommerce platform. This means you can add an instance
 * of this page type to the shopping cart.
 * 
 * @package ecommerce
 */
class Product extends Page {
	
	public static $db = array(
		
		'WebLink' => 'Varchar(30)',
		'DateAdded' => 'Date',
		'Testimonial' => 'HTMLText',
	);
	
	public static $has_one = array(
		'Image' => 'Product_Image'
	);
	
	public static $has_many = array(
		'Variations' => 'ProductVariation'
	);
	
	public static $many_many = array(
		'ProductGroups' => 'ProductGroup'
	);
	
	public static $belongs_many_many = array();
	
	public static $singular_name = 'Product';
	
	public static $plural_name = 'Products';
	
	static $default_parent = 'ProductGroup';
	
	static $default_sort = 'Title ASC';
	
	static $add_action = 'a Product Page';
	
	static $icon = 'ecommerce/images/icons/package';
	
	
	
	function getCMSFields() {
		$fields = parent::getCMSFields();

		// Standard product detail fields
		
		
		$fields->addFieldToTab('Root.Content.Main',new TextField('WebLink'),'Content');
		$fields->addFieldToTab('Root.Content.Main',new HtmlEditorField('Testimonial'),'Content');
		
		$datefield = new DateField('DateAdded');
		$datefield->setConfig('showcalendar', true);
		$datefield->setConfig('showdropdown', true);
		$datefield->setConfig('dateformat', 'dd/MM/YYYY');
		$fields->addFieldToTab('Root.Content.Main', $datefield, 'Content');
		
		
				
		if(!$fields->dataFieldByName('Image')) {
			$fields->addFieldToTab('Root.Content.Images', new ImageField('Image', _t('Product.IMAGE', 'Product Image')));
		}
		
		

		// Flags for this product which affect it's behaviour on the site
		
		
		$fields->addFieldsToTab(
			'Root.Content.Product Groups',
			array(
				new HeaderField(_t('Product.ALSOAPPEARS', 'This product also appears in the following groups')),
				$this->getProductGroupsTable()
			)
		);
		
		
		
		return $fields;
	}
	
	function getVariationsTable() {
		$singleton = singleton('ProductVariation');
		$query = $singleton->buildVersionSQL("`ProductID` = '{$this->ID}'");
		$variations = $singleton->buildDataObjectSet($query->execute());
		$filter = $variations ? "`ID` IN ('" . implode("','", $variations->column('RecordID')) . "')" : "`ID` < '0'";
		//$filter = "`ProductID` = '{$this->ID}'";
		
		
	}
	
	protected function getProductGroupsTable() {
		$tableField = new ManyManyComplexTableField(
			$this,
			'ProductGroups',
			'ProductGroup',
			array(
				'Title' => 'Product Group Page Title'
			)
		);
		
		$tableField->setPageSize(12);
		$tableField->setPermissions(array());
		
		//TODO: use a tree structure for selecting groups
		//$field = new TreeMultiselectField('ProductGroups','Product Groups','ProductGroup'); 
		
		return $tableField;
	}
	/**
	 * Enables developers to completely turning off the ability to purcahse products.
	 */
	
	
	/**
	 * Recaulculates the number sold for all products. This should be run as a cron job perhaps daily.
	 */
	
	//passing on shopping cart links ...is this necessary?? ...why not just pass the cart?
	
	
	/**
	 * When the ecommerce module is first installed, and db/build
	 * is invoked, create some default records in the database.
	 */
	
	
}

class Product_Controller extends Page_Controller {
	
	function init() {
		parent::init();
		Requirements::themedCSS('Product');
		Requirements::themedCSS('ProductGroup');
		
	}
	
}

class Product_Image extends Image {

	public static $db = array();
	
	public static $has_one = array();
	
	public static $has_many = array();
	
	public static $many_many = array();
	
	public static $belongs_many_many = array();
	
	//default image sizes
	protected static $thumbnail_width = 225;
	protected static $thumbnail_height = 150;
	
	protected static $content_image_width = 225;
	
	protected static $large_image_width = 600;
	
	function set_thumbnail_size($width = 225, $height = 150){
		self::$thumbnail_width = $width;
		self::$thumbnail_height = $height;
	}
	
	function set_content_image_width($width = 200){
		self::$content_image_width = $width;
	}
	
	function set_large_image_width($width = 600){
		self::$large_image_width = $width;
	}
	
	function generateThumbnail($gd) {
		$gd->setQuality(80);
		return $gd->paddedResize(self::$thumbnail_width,self::$thumbnail_height);
	}
	
	function generateContentImage($gd) {
		$gd->setQuality(90);
		return $gd->resizeByWidth(self::$content_image_width);
	}
	
	function generateLargeImage($gd) {
		$gd->setQuality(90);
		return $gd->resizeByWidth(self::$large_image_width);
	}
	
}
class Product_OrderItem extends OrderItem {
	
	protected $_productID;
	
	protected $_productVersion;
	
	static $db = array(
		'ProductVersion' => 'Int'
	);
	
	static $has_one = array(
		'Product' => 'Product'
	);
	
	
	
}
?>

******************************************************

ProductGroup.php

<?php
 /**
  * Product Group is a 'holder' for Products within the CMS
  * It contains functions for versioning child products
  * 
  * @package ecommerce
  */
class ProductGroup extends Page {
	
	public static $db = array(
		'ChildGroupsPermission' => "Enum('Show Only Featured Products,Show All Products')"
	);
	
	public static $has_one = array();
	
	public static $has_many = array();
	
	public static $many_many = array();
	
	public static $belongs_many_many = array(
		'Products' => 'Product'
	);
	
	public static $defaults = array();
	
	public static $casting = array();
	
	static $default_child = 'Product';
	
	static $add_action = 'a Product Group Page';
	
	static $icon = 'cms/images/treeicons/folder';
	
	static $include_child_groups = true;
	static $page_length = 12;
	static $must_have_price = false;	
	
	//TODO: allow grouping multiple sort fields under one 'sort option', and allow choosing direction of each
	static $sort_options = array(
		//'Title' => 'Web Design',		
		//'Price' => 'Logo/Branding',
		//'NumberSold' => 'Testimonials'
		//'Featured' => 'Featured',
		//'Weight' => 'Weight'
		'DateAdded' => 'Latest'
	);
	
	static $featured_products_permissions = array(
		'Show Only Featured Products',
		'Show All Products'
	);
	
	static $non_featured_products_permissions = array(
		'Show All Products'
	);
	
	
	function set_page_length($length){
		self::$page_length = $length;
	}
	
	function set_must_have_price($must = true){
		self::$must_have_price = $must;
	}
	
	function set_sort_options(array $options){
		self::$sort_options = $options;
	}
	
	function get_sort_options(){
		return self::$sort_options;
	}
	
	function getCMSFields() {
		$fields = parent::getCMSFields();
		
		if(self::$include_child_groups === 'custom'){
			$fields->addFieldToTab(
				'Root.Content',
				new Tab(
					'Child Groups',
					new HeaderField('How should products be presented in the child groups?'),
					new DropdownField(
	  					'ChildGroupsPermission',
	  					'Permission',
	  					$this->dbObject('ChildGroupsPermission')->enumValues(),
	  					'',
	  					null,
	  					'Don\'t Show Any Products'
					)
				)
			);
		}
		
		return $fields;
	}
	
	/**
	 * Returns the shopping cart.
	 * @todo Does HTTP::set_cache_age() still need to be set here?
	 * 
	 * @return Order
	 */
	function Cart() {
		HTTP::set_cache_age(0);
		return ShoppingCart::current_order();
	}
	
	
	/**
	 * Retrieve a set of products, based on the given parameters. Checks get query for sorting and pagination.
	 * 
	 * @param string $extraFilter Additional SQL filters to apply to the Product retrieval
	 * @param array $permissions 
	 * @return DataObjectSet
	 */
	function ProductsShowable($extraFilter = '', $permissions = array("Show All Products")) { //TODO: re-introduce custom permissions, if wanted
		$filter = ""; //
		$join = "";
		
		if($extraFilter) $filter.= " AND $extraFilter";
		if(self::$must_have_price) $filter .= " AND Price > 0";
		
		$limit = (isset($_GET['start']) && (int)$_GET['start'] > 0) ? (int)$_GET['start'].",".self::$page_length : "0,".self::$page_length;
		$sort = (isset($_GET['sortby'])) ? Convert::raw2sql($_GET['sortby']) : "DateAdded DESC,Title";
		
		//hard coded sort configuration //TODO: make these custom
		if($sort == "DateAdded") $sort .= " DESC";
		
		$groupids = array($this->ID);
		
		if(self::$include_child_groups && $childgroups = $this->ChildGroups(true))
			$groupids = array_merge($groupids,$childgroups->map('ID','ID'));
		
		$groupidsimpl = implode(',',$groupids);
		
		$join = $this->getManyManyJoin('Products','Product');
		$multicatfilter = $this->getManyManyFilter('Products','Product');
		
		//TODO: get products that appear in child groups (make this optional)
		
		$products = DataObject::get('Product',"(ParentID IN ($groupidsimpl) OR $multicatfilter) $filter",$sort,$join,$limit);
		
		$allproducts = DataObject::get('Product',"ParentID IN ($groupidsimpl) $filter","",$join);
		if($allproducts) $products->TotalCount = $allproducts->Count(); //add total count to returned data for 'showing x to y of z products'
		if($products) $products->removeDuplicates();
		return $products;
	}
	
	/** 
	 * Return children ProductGroup pages of this group.
	 * @return DataObjectSet
	 */
	function ChildGroups($recursive = false) {
		if($recursive){
			if($children = DataObject::get('ProductGroup', "`ParentID` = '$this->ID'")){
				$output = unserialize(serialize($children));
				foreach($children as $group){
					$output->merge($group->ChildGroups($recursive));
				}
				return $output;							
			}
			return null;
		}else{
			return DataObject::get('ProductGroup', "`ParentID` = '$this->ID'");
		}
	}

	
	/**
	 * Recursively generate a product menu.
	 * @return DataObjectSet
	 */
	function GroupsMenu() {
		if($parent = $this->Parent()) {
			return $parent instanceof ProductGroup ? $parent->GroupsMenu() : $this->ChildGroups();
		} else {
			return $this->ChildGroups();
		}
	}

	/**
	 * Automatically creates some ProductGroup pages in
	 * the CMS when the database builds if there hasn't
	 * been any set up yet.
	 */
	function requireDefaultRecords() {
		parent::requireDefaultRecords();
		
		if(!DataObject::get_one('ProductGroup')) {
			$page1 = new ProductGroup();
			$page1->Title = 'Products';
			$page1->Content = "
				<p>This is the top level products page, it uses the <em>product group</em> page type, and it allows you to show your products checked as 'featured' on it. It also allows you to nest <em>product group</em> pages inside it.</p>
				<p>For example, you have a product group called 'DVDs', and inside you have more product groups like 'sci-fi', 'horrors' or 'action'.</p>
				<p>In this example we have setup a main product group (this page), with a nested product group containing 2 example products.</p>
			";
			$page1->URLSegment = 'products';
			$page1->writeToStage('Stage');
			$page1->publish('Stage', 'Live');
			DB::alteration_message('Product group page \'Products\' created', 'created');
			
			$page2 = new ProductGroup();
			$page2->Title = 'Example product group';
			$page2->Content = '<p>This is a nested <em>product group</em> within the main <em>product group</em> page. You can add a paragraph here to describe what this product group is about, and what sort of products you can expect to find in it.</p>';
			$page2->URLSegment = 'example-product-group';
			$page2->ParentID = $page1->ID;
			$page2->writeToStage('Stage');
			$page2->publish('Stage', 'Live');
			DB::alteration_message('Product group page \'Example product group\' created', 'created');
		}
	}
	
}
class ProductGroup_Controller extends Page_Controller {

	function init() {
		parent::init();

		Requirements::themedCSS('ProductGroup');
		Requirements::themedCSS('Cart');
	}
	
	/**
	 * Return the products for this group.
	 */
	public function Products(){
		return $this->ProductsShowable();
	}
	
	/**
	 * Return products that are featured, that is products that have "FeaturedProduct = 1"
	 */
	function FeaturedProducts() {
		return $this->ProductsShowable("`FeaturedProduct` = 1");
	}
	
	/**
	 * Return products that are not featured, that is products that have "FeaturedProduct = 0"
	 */
	function NonFeaturedProducts() {
		return $this->ProductsShowable("`FeaturedProduct` = 0");
	}
	
		/**
	 * Provides a dataset of links for sorting products.
	 */
	

}
?>

Avatar
inCharge

Community Member, 102 Posts

4 May 2011 at 3:36am

This is general SilverStripe debugging advice.

In php.ini make sure you have...

display_errors = on

...OR if you can't edit php.ini because the site is on shared hosting, or on a production server and you don't want to affect other live sites, add this to _config.php...

ini_set("display_errors","1");

...ALSO, add this to _config.php...

SS_Log::add_writer(new SS_LogFileWriter('../silverstripe-log/silverstripe.log'), SS_Log::NOTICE);

...then errors and warnings are logged, and you can add debug messages to your php code like this...

SS_Log::log( New Exception('Your message here!'), SS_Log::NOTICE );

Hope this helps you track down the problem.

Avatar
ambient

Community Member, 130 Posts

4 May 2011 at 5:41am

Thanks inCharge, unfortunately the only errors here are human errors on my part.

I believe it's something I've changed or did in the code thats causing it to go to a blank page. No actual errors show up.

Avatar
ambient

Community Member, 130 Posts

6 May 2011 at 3:17am

:( Nobody with any ideas why the product page would be blank when there are no errors?

Avatar
Jedateach

Forum Moderator, 238 Posts

6 May 2011 at 8:52am

Do you have your own Product.ss in the wrong place?

Avatar
ambient

Community Member, 130 Posts

6 May 2011 at 10:09am

Edited: 06/05/2011 10:15am

Hi Jedateach,

My Product.ss is in the ecommerce\templates\Layout folder

The products show on the group page e.g 'paintings/' but nothing shows on their individual page e.g. paintings/oil-1/

Avatar
ambient

Community Member, 130 Posts

7 May 2011 at 5:49am

If I delete Product.php and refresh a product page the text content for the page shows (specified in Product.ss, no Page.ss stuff like the nav shows).

But then the page goes blank again when I put Product.php back. It's still searchable from the search box. I'm not very good at this but it seems weird to me?