Skip to content

Commit

Permalink
Initial commit of pre-alpha module
Browse files Browse the repository at this point in the history
  • Loading branch information
madmatt committed Sep 24, 2019
0 parents commit cee9b3f
Show file tree
Hide file tree
Showing 10 changed files with 322 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/composer.lock
/resources
/vendor
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Shop Front Module

An extension to the [SilverShop module](https://github.com/silvershop/) that provides a custom page type for a 'shop front'. The shop front allows a CMS author to create 'sections', each of which can contain arbitrary products (or a product category).

## Maintainer Contact

* [madmatt](https://github.com/madmatt/)

## Requirements

* silvershop/core: ^3

## Installation Instructions

* Install via composer: `composer require silvershop/shopfront`
* Run `vendor/bin/sake dev/build flush=1` to add the new page types
* Create a new 'Shop Front page' in the CMS, define your sections and add products to each one
* The module ships with a super basic template that you are expected to override in your own theme:
* Create a new file under `themes/<your_theme>/templates/SilverShop/ShopFront/Page/Layout/ShopFrontPage.ss`
* Add your custom styles and classes to this file, using the existing file as an example
6 changes: 6 additions & 0 deletions _config/extensions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
name: shopfront-extensions
---
SilverShop\Page\Product:
extensions:
- SilverShop\ShopFront\Extension\ProductSection
51 changes: 51 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"name": "silvershop/shopfront",
"description": "Provides a 'shopfront' page type that can be used to display products or product categories.",
"license": "BSD-2-Clause",
"type": "silverstripe-vendormodule",
"homepage": "http://silvershop.github.io/",
"minimum-stability": "dev",

"support": {
"source": "https://github.com/silvershop/silvershop-shopfront",
"issues": "https://github.com/silvershop/silvershop-shopfront/issues"
},

"require": {
"silvershop/core": "^3",
"unclecheese/display-logic": "^2",
"symbiote/silverstripe-gridfieldextensions": "^3"
},

"require-dev": {
"squizlabs/php_codesniffer": "^3"
},

"autoload": {
"psr-4": {
"SilverShop\\ShopFront\\": "src/"
}
},

"keywords": [
"silverstripe",
"shop",
"shopfront"
],

"authors": [
{
"name": "madmatt",
"homepage": "https://github.com/madmatt"
},

{
"name": "SilverShop Contributors",
"homepage": "https://github.com/silvershop/silvershop-shopfront/graphs/contributors"
}
],

"scripts": {
"lint": "vendor/bin/phpcs src/"
}
}
17 changes: 17 additions & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0"?>
<ruleset name="SS4">
<description>Coding standard for SilverStripe 4.x</description>

<!-- Don't sniff third party libraries -->
<exclude-pattern>*/vendor/*</exclude-pattern>

<!-- Show progress and output sniff names on violation, and add colours -->
<arg value="sp"/>
<arg name="colors"/>

<!-- Use PSR-2 as a base standard -->
<rule ref="PSR2">
<!-- Allow non camel cased method names -->
<exclude name="PSR1.Methods.CamelCapsMethodName.NotCamelCaps"/>
</rule>
</ruleset>
25 changes: 25 additions & 0 deletions src/Controller/ShopFrontPageController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace SilverShop\ShopFront\Controller;

use PageController;
use SilverShop\ShopFront\Model\ShopFrontSection;
use SilverStripe\ORM\DataList;

class ShopFrontPageController extends PageController
{
/**
* Returns only the list of ShopFrontSection objects that are suitable for display (aren't hidden), optionally
* overloaded by other extensions to return a differently filtered list of objects.
*
* @return DataList<ShopFrontSection>|null
*/
public function SectionsForDisplay(): ?DataList
{
$sections = $this->data()->Sections()->filter('HideFromDisplay', 0)->sort('Sort ASC');

$this->extend('updateSectionsForDisplay', $sections);

return $sections;
}
}
13 changes: 13 additions & 0 deletions src/Extension/ProductSection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace SilverShop\ShopFront\Extension;

use SilverShop\ShopFront\Model\ShopFrontSection;
use SilverStripe\ORM\DataExtension;

class ProductSection extends DataExtension
{
private static $belongs_many_many = [
'Sections' => ShopFrontSection::class
];
}
112 changes: 112 additions & 0 deletions src/Model/ShopFrontSection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?php

namespace SilverShop\ShopFront\Model;

use Page;
use SilverShop\Page\ProductCategory;
use SilverShop\ShopFront\Page\ShopFrontPage;
use SilverStripe\Forms\CheckboxField;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor;
use SilverStripe\Forms\HTMLEditor\HTMLEditorField;
use SilverStripe\Forms\LiteralField;
use SilverStripe\Forms\TextField;
use SilverStripe\Forms\TreeDropdownField;
use SilverStripe\ORM\DataList;
use SilverStripe\ORM\DataObject;
use UncleCheese\DisplayLogic\Forms\Wrapper;

class ShopFrontSection extends DataObject
{
private static $table_name = 'ShopFrontSection';

private static $db = [
'Title' => 'Varchar(200)',
'Content' => 'HTMLText',
'HideFromDisplay' => 'Boolean',
'Sort' => 'Int',
];

private static $has_one = [
'ShopFront' => ShopFrontPage::class, // Parent relationship - indicates which shopfront page this section is on
'ProductCategory' => ProductCategory::class,
];

private static $many_many = [
'Products' => Page::class
];

private static $many_many_extraFields = [
'Products' => [
'Sort' => 'Int'
]
];

private static $indexes = [
'Sort' => true,
];

private static $summary_fields = [
'Title',
'HideFromDisplay.Nice'
];

public function getCMSFields()
{
$gridField = Wrapper::create(
new GridField(
'Products',
'Products (if no category is set)',
$this->Products(),
GridFieldConfig_RelationEditor::create()
)
);

$fields = new FieldList([
new TextField('Title'),
new CheckboxField('HideFromDisplay', 'Hide this section from display on the website'),
new HTMLEditorField('Content')
]);

if ($this->isInDB() && $this->ShopFront()) {
$productCategoryField = TreeDropdownField::create(
'ProductCategoryID',
'Product Category',
ProductCategory::class
);

$productCategoryField->setTreeBaseID($this->ShopFront()->ID)->setTitle('DisplayLogicWrap');
$fields->push(Wrapper::create($productCategoryField));
$fields->push($gridField);
} else {
$helperField = LiteralField::create(
'ProductSelectionHelper',
'<h3>You can select products to be displayed in this section once you have saved for the first '
. 'time.</h3>'
);

$fields->push($helperField);
}

$this->extend('updateCMSFields', $fields);
return $fields;
}

/**
* Returns a {@link DataList} of {@link Products} to include in the section.
*
* If the section is attached to a category, it pulls all the products from
* that category, otherwise uses the products attached.
*
* @return DataList
*/
public function Products()
{
if ($this->ProductCategoryID) {
return Page::get()->filter('ParentID', $this->ProductCategoryID);
}

return $this->getManyManyComponents('Products');
}
}
45 changes: 45 additions & 0 deletions src/Page/ShopFrontPage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace SilverShop\ShopFront\Page;

use Page;
use SilverShop\ShopFront\Controller\ShopFrontPageController;
use SilverShop\ShopFront\Model\ShopFrontSection;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor;
use Symbiote\GridFieldExtensions\GridFieldOrderableRows;

/**
* Class ShopFrontPage
* @package SilverShop\ShopFront\Page
*
* A page type that allows the creation of multiple 'sections', each of which that can contain multiple products or
* product categories (actually just any page object).
*/
class ShopFrontPage extends Page
{
private static $controller_name = ShopFrontPageController::class;

private static $has_many = [
'Sections' => ShopFrontSection::class
];

private static $owns = ['Sections'];

private static $cascade_duplicates = ['Sections'];

private static $cascade_deletes = ['Sections'];

public function getCMSFields()
{
$fields = parent::getCMSFields();

$config = GridFieldConfig_RecordEditor::create();
$config->addComponent(new GridFieldOrderableRows('Sort'));

$grid = GridField::create('Sections', 'Sections', $this->Sections(), $config);
$fields->addFieldToTab('Root.Main', $grid);

return $fields;
}
}
30 changes: 30 additions & 0 deletions templates/SilverShop/ShopFront/Page/Layout/ShopFrontPage.ss
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<%--
This template is intended to be used as an example only,
and would generally be overridden within your own project
--%>

<% if $SectionsForDisplay %>
<div class="shopfront-page">
<h1>$Title</h1>

<% loop $SectionsForDisplay %>
<div class="shopfront-section">
<h2 class="shopfront-section-title">$Title</h2>
<div class="shopfront-section-products">
<ul>
<% loop $Products %>
<% if $canView %>
<li class="product">
<h3><a href="$Link">$Title</a></h3>
<% if $Image %>
<a href="$Link"><img src="$Image.Link" /></a>
<% end_if %>
</li>
<% end_if %>
<% end_loop %>
</ul>
</div>
</div>
<% end_loop %>
</div>
<% end_if %>

0 comments on commit cee9b3f

Please sign in to comment.