Website: Product Configurator and Bootstrap 4 (#15965)

- Refactored Homepage with customisable Hero Section
- New Homepage Section to add content on Homepage as cards or using Custom HTML
- Products page at "/all-products" with customisable filters
- Item Configure dialog to find an Item Variant filtered by attribute values
- Contact Us dialog on Item page
- Customisable Item page content using the Website Content field
diff --git a/erpnext/config/website.py b/erpnext/config/website.py
index 59e7d40..d31b057 100644
--- a/erpnext/config/website.py
+++ b/erpnext/config/website.py
@@ -13,6 +13,16 @@
 				},
 				{
 					"type": "doctype",
+					"name": "Homepage Section",
+					"description": _("Add cards or custom sections on homepage"),
+				},
+				{
+					"type": "doctype",
+					"name": "Products Settings",
+					"description": _("Settings for website product listing"),
+				},
+				{
+					"type": "doctype",
 					"name": "Shopping Cart Settings",
 					"label": _("Shopping Cart Settings"),
 					"description": _("Settings for online shopping cart such as shipping rules, price list etc."),
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index a6876ac..d28666c 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -22,7 +22,8 @@
 
 doctype_js = {
 	"Communication": "public/js/communication.js",
-	"Event": "public/js/event.js"
+	"Event": "public/js/event.js",
+	"Website Theme": "public/js/website_theme.js"
 }
 
 welcome_email = "erpnext.setup.utils.welcome_email"
diff --git a/erpnext/hr/doctype/job_opening/job_opening.py b/erpnext/hr/doctype/job_opening/job_opening.py
index 4fc2ac1..00883d7 100644
--- a/erpnext/hr/doctype/job_opening/job_opening.py
+++ b/erpnext/hr/doctype/job_opening/job_opening.py
@@ -53,3 +53,26 @@
 def get_list_context(context):
 	context.title = _("Jobs")
 	context.introduction = _('Current Job Openings')
+	context.get_list = get_job_openings
+
+def get_job_openings(doctype, txt=None, filters=None, limit_start=0, limit_page_length=20, order_by=None):
+	fields = ['name', 'status', 'job_title', 'description']
+
+	filters = filters or {}
+	filters.update({
+		'status': 'Open'
+	})
+
+	if txt:
+		filters.update({
+			'job_title': ['like', '%{0}%'.format(txt)],
+			'description': ['like', '%{0}%'.format(txt)]
+		})
+
+	return frappe.get_all(doctype,
+		filters,
+		fields,
+		start=limit_start,
+		page_length=limit_page_length,
+		order_by=order_by
+	)
diff --git a/erpnext/hr/doctype/job_opening/templates/job_opening_row.html b/erpnext/hr/doctype/job_opening/templates/job_opening_row.html
new file mode 100644
index 0000000..5da8cc8
--- /dev/null
+++ b/erpnext/hr/doctype/job_opening/templates/job_opening_row.html
@@ -0,0 +1,9 @@
+<div class="my-5">
+	<h3>{{ doc.job_title }}</h3>
+	<p>{{ doc.description }}</p>
+	<div>
+		<a class="btn btn-primary"
+		href="/job_application?new=1&job_title={{ doc.name }}">
+		{{ _("Apply Now") }}</a>
+	</div>
+</div>
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index b7e673d..cb1e77c 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -577,6 +577,7 @@
 erpnext.patches.v11_0.update_delivery_trip_status
 erpnext.patches.v11_0.set_missing_gst_hsn_code
 erpnext.patches.v11_0.rename_bom_wo_fields
+erpnext.patches.v12_0.set_default_homepage_type
 erpnext.patches.v11_0.rename_additional_salary_component_additional_salary
 erpnext.patches.v11_0.renamed_from_to_fields_in_project
 erpnext.patches.v11_0.add_permissions_in_gst_settings
@@ -584,5 +585,4 @@
 execute:frappe.delete_doc('DocType', 'Notification Control')
 erpnext.patches.v11_0.remove_barcodes_field_from_copy_fields_to_variants
 erpnext.patches.v12_0.set_task_status
-erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019
 erpnext.patches.v11_0.make_italian_localization_fields # 01-03-2019
diff --git a/erpnext/patches/v12_0/add_variant_of_in_item_attribute_table.py b/erpnext/patches/v12_0/add_variant_of_in_item_attribute_table.py
new file mode 100644
index 0000000..bc61190
--- /dev/null
+++ b/erpnext/patches/v12_0/add_variant_of_in_item_attribute_table.py
@@ -0,0 +1,8 @@
+import frappe
+
+def execute():
+    frappe.db.sql('''
+        UPDATE `tabItem Variant Attribute` t1
+        INNER JOIN `tabItem` t2 ON t2.name = t1.parent
+        SET t1.variant_of = t2.variant_of
+    ''')
diff --git a/erpnext/patches/v12_0/set_default_homepage_type.py b/erpnext/patches/v12_0/set_default_homepage_type.py
new file mode 100644
index 0000000..241e4b9
--- /dev/null
+++ b/erpnext/patches/v12_0/set_default_homepage_type.py
@@ -0,0 +1,4 @@
+import frappe
+
+def execute():
+	frappe.db.set_value('Homepage', 'Homepage', 'hero_section_based_on', 'Default')
\ No newline at end of file
diff --git a/erpnext/portal/doctype/homepage/homepage.js b/erpnext/portal/doctype/homepage/homepage.js
index 0b07814..ca34d69 100644
--- a/erpnext/portal/doctype/homepage/homepage.js
+++ b/erpnext/portal/doctype/homepage/homepage.js
@@ -11,7 +11,12 @@
 	},
 
 	refresh: function(frm) {
-
+		frm.add_custom_button(__('Set Meta Tags'), () => {
+			frappe.utils.set_meta_tag('home');
+		});
+		frm.add_custom_button(__('Customize Homepage Sections'), () => {
+			frappe.set_route('List', 'Homepage Section', 'List');
+		});
 	},
 });
 
diff --git a/erpnext/portal/doctype/homepage/homepage.json b/erpnext/portal/doctype/homepage/homepage.json
index 81433b1..ad27278 100644
--- a/erpnext/portal/doctype/homepage/homepage.json
+++ b/erpnext/portal/doctype/homepage/homepage.json
@@ -1,5 +1,7 @@
 {
  "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
  "allow_import": 0,
  "allow_rename": 0,
  "autoname": "",
@@ -10,18 +12,24 @@
  "doctype": "DocType",
  "document_type": "Setup",
  "editable_grid": 0,
+ "engine": "InnoDB",
  "fields": [
   {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
+   "columns": 0,
    "fieldname": "company",
    "fieldtype": "Link",
    "hidden": 0,
    "ignore_user_permissions": 0,
    "ignore_xss_filter": 0,
    "in_filter": 0,
-   "in_list_view": 0,
+   "in_global_search": 0,
+   "in_list_view": 1,
+   "in_standard_filter": 0,
    "label": "Company",
    "length": 0,
    "no_copy": 0,
@@ -31,24 +39,63 @@
    "print_hide": 0,
    "print_hide_if_no_value": 0,
    "read_only": 0,
+   "remember_last_selected_value": 0,
    "report_hide": 0,
    "reqd": 1,
    "search_index": 0,
    "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
   },
   {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
-   "fieldname": "title",
-   "fieldtype": "Data",
+   "columns": 0,
+   "fieldname": "hero_section_based_on",
+   "fieldtype": "Select",
    "hidden": 0,
    "ignore_user_permissions": 0,
    "ignore_xss_filter": 0,
    "in_filter": 0,
+   "in_global_search": 0,
    "in_list_view": 0,
-   "label": "TItle",
+   "in_standard_filter": 0,
+   "label": "Hero Section Based On",
+   "length": 0,
+   "no_copy": 0,
+   "options": "Default\nSlideshow\nHomepage Section",
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "column_break_2",
+   "fieldtype": "Column Break",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
    "length": 0,
    "no_copy": 0,
    "permlevel": 0,
@@ -56,16 +103,88 @@
    "print_hide": 0,
    "print_hide_if_no_value": 0,
    "read_only": 0,
+   "remember_last_selected_value": 0,
    "report_hide": 0,
    "reqd": 0,
    "search_index": 0,
    "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
   },
   {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
+   "columns": 0,
+   "depends_on": "",
+   "fieldname": "title",
+   "fieldtype": "Data",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Title",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "depends_on": "",
+   "fieldname": "section_break_4",
+   "fieldtype": "Section Break",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Hero Section",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "depends_on": "eval:doc.hero_section_based_on === 'Default'",
    "description": "Company Tagline for website homepage",
    "fieldname": "tag_line",
    "fieldtype": "Data",
@@ -73,7 +192,9 @@
    "ignore_user_permissions": 0,
    "ignore_xss_filter": 0,
    "in_filter": 0,
-   "in_list_view": 0,
+   "in_global_search": 0,
+   "in_list_view": 1,
+   "in_standard_filter": 0,
    "label": "Tag Line",
    "length": 0,
    "no_copy": 0,
@@ -82,16 +203,22 @@
    "print_hide": 0,
    "print_hide_if_no_value": 0,
    "read_only": 0,
+   "remember_last_selected_value": 0,
    "report_hide": 0,
    "reqd": 1,
    "search_index": 0,
    "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
   },
   {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
+   "columns": 0,
+   "depends_on": "eval:doc.hero_section_based_on === 'Default'",
    "description": "Company Description for website homepage",
    "fieldname": "description",
    "fieldtype": "Text",
@@ -99,7 +226,9 @@
    "ignore_user_permissions": 0,
    "ignore_xss_filter": 0,
    "in_filter": 0,
-   "in_list_view": 0,
+   "in_global_search": 0,
+   "in_list_view": 1,
+   "in_standard_filter": 0,
    "label": "Description",
    "length": 0,
    "no_copy": 0,
@@ -108,23 +237,133 @@
    "print_hide": 0,
    "print_hide_if_no_value": 0,
    "read_only": 0,
+   "remember_last_selected_value": 0,
    "report_hide": 0,
    "reqd": 1,
    "search_index": 0,
    "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
   },
   {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
+   "columns": 0,
+   "depends_on": "eval:doc.hero_section_based_on === 'Default'",
+   "fieldname": "hero_image",
+   "fieldtype": "Attach Image",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Hero Image",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "depends_on": "eval:doc.hero_section_based_on === 'Slideshow'",
+   "description": "",
+   "fieldname": "slideshow",
+   "fieldtype": "Link",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Homepage Slideshow",
+   "length": 0,
+   "no_copy": 0,
+   "options": "Website Slideshow",
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "depends_on": "eval:doc.hero_section_based_on === 'Homepage Section'",
+   "fieldname": "hero_section",
+   "fieldtype": "Link",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Homepage Section",
+   "length": 0,
+   "no_copy": 0,
+   "options": "Homepage Section",
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "depends_on": "",
    "fieldname": "products_section",
    "fieldtype": "Section Break",
    "hidden": 0,
    "ignore_user_permissions": 0,
    "ignore_xss_filter": 0,
    "in_filter": 0,
+   "in_global_search": 0,
    "in_list_view": 0,
+   "in_standard_filter": 0,
    "label": "Products",
    "length": 0,
    "no_copy": 0,
@@ -133,16 +372,21 @@
    "print_hide": 0,
    "print_hide_if_no_value": 0,
    "read_only": 0,
+   "remember_last_selected_value": 0,
    "report_hide": 0,
    "reqd": 0,
    "search_index": 0,
    "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
   },
   {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
+   "columns": 0,
    "default": "/products",
    "fieldname": "products_url",
    "fieldtype": "Data",
@@ -150,7 +394,9 @@
    "ignore_user_permissions": 0,
    "ignore_xss_filter": 0,
    "in_filter": 0,
+   "in_global_search": 0,
    "in_list_view": 0,
+   "in_standard_filter": 0,
    "label": "URL for \"All Products\"",
    "length": 0,
    "no_copy": 0,
@@ -159,16 +405,21 @@
    "print_hide": 0,
    "print_hide_if_no_value": 0,
    "read_only": 0,
+   "remember_last_selected_value": 0,
    "report_hide": 0,
    "reqd": 0,
    "search_index": 0,
    "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
   },
   {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
+   "columns": 0,
    "description": "Products to be shown on website homepage",
    "fieldname": "products",
    "fieldtype": "Table",
@@ -176,7 +427,9 @@
    "ignore_user_permissions": 0,
    "ignore_xss_filter": 0,
    "in_filter": 0,
+   "in_global_search": 0,
    "in_list_view": 0,
+   "in_standard_filter": 0,
    "label": "Products",
    "length": 0,
    "no_copy": 0,
@@ -186,14 +439,17 @@
    "print_hide": 0,
    "print_hide_if_no_value": 0,
    "read_only": 0,
+   "remember_last_selected_value": 0,
    "report_hide": 0,
    "reqd": 0,
    "search_index": 0,
    "set_only_once": 0,
+   "translatable": 0,
    "unique": 0,
    "width": "40px"
   }
  ],
+ "has_web_view": 0,
  "hide_heading": 0,
  "hide_toolbar": 0,
  "idx": 0,
@@ -203,7 +459,7 @@
  "issingle": 1,
  "istable": 0,
  "max_attachments": 0,
- "modified": "2016-08-29 01:28:00.961623",
+ "modified": "2019-03-02 23:12:59.676202",
  "modified_by": "Administrator",
  "module": "Portal",
  "name": "Homepage",
@@ -212,7 +468,6 @@
  "permissions": [
   {
    "amend": 0,
-   "apply_user_permissions": 0,
    "cancel": 0,
    "create": 1,
    "delete": 1,
@@ -232,7 +487,6 @@
   },
   {
    "amend": 0,
-   "apply_user_permissions": 0,
    "cancel": 0,
    "create": 1,
    "delete": 1,
@@ -254,8 +508,11 @@
  "quick_entry": 0,
  "read_only": 0,
  "read_only_onload": 0,
+ "show_name_in_global_search": 0,
  "sort_field": "modified",
  "sort_order": "DESC",
  "title_field": "company",
- "track_seen": 0
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
 }
\ No newline at end of file
diff --git a/erpnext/portal/doctype/homepage/homepage.py b/erpnext/portal/doctype/homepage/homepage.py
index f8f73fd..4e4d477 100644
--- a/erpnext/portal/doctype/homepage/homepage.py
+++ b/erpnext/portal/doctype/homepage/homepage.py
@@ -9,8 +9,6 @@
 
 class Homepage(Document):
 	def validate(self):
-		if not self.products:
-			self.setup_items()
 		if not self.description:
 			self.description = frappe._("This is an example website auto-generated from ERPNext")
 		delete_page_cache('home')
diff --git a/erpnext/portal/doctype/homepage/test_homepage.py b/erpnext/portal/doctype/homepage/test_homepage.py
new file mode 100644
index 0000000..b262c46
--- /dev/null
+++ b/erpnext/portal/doctype/homepage/test_homepage.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+from frappe.tests.test_website import set_request
+from frappe.website.render import render
+
+class TestHomepage(unittest.TestCase):
+	def test_homepage_load(self):
+		set_request(method='GET', path='home')
+		response = render()
+
+		self.assertEquals(response.status_code, 200)
+
+		html = frappe.safe_decode(response.get_data())
+		self.assertTrue('<section class="hero-section' in html)
diff --git a/erpnext/portal/doctype/homepage_section/__init__.py b/erpnext/portal/doctype/homepage_section/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/portal/doctype/homepage_section/__init__.py
diff --git a/erpnext/portal/doctype/homepage_section/homepage_section.js b/erpnext/portal/doctype/homepage_section/homepage_section.js
new file mode 100644
index 0000000..68859eb
--- /dev/null
+++ b/erpnext/portal/doctype/homepage_section/homepage_section.js
@@ -0,0 +1,6 @@
+// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Homepage Section', {
+
+});
diff --git a/erpnext/portal/doctype/homepage_section/homepage_section.json b/erpnext/portal/doctype/homepage_section/homepage_section.json
new file mode 100644
index 0000000..0692126
--- /dev/null
+++ b/erpnext/portal/doctype/homepage_section/homepage_section.json
@@ -0,0 +1,336 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 1,
+ "autoname": "Prompt",
+ "beta": 0,
+ "creation": "2019-02-10 19:42:35.809238",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "section_based_on",
+   "fieldtype": "Select",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Section Based On",
+   "length": 0,
+   "no_copy": 0,
+   "options": "Cards\nCustom HTML",
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "collapsible_depends_on": "",
+   "columns": 0,
+   "depends_on": "eval:doc.section_based_on === 'Cards'",
+   "fieldname": "section_cards_section",
+   "fieldtype": "Section Break",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Section Cards",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "depends_on": "",
+   "fieldname": "section_cards",
+   "fieldtype": "Table",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Section Cards",
+   "length": 0,
+   "no_copy": 0,
+   "options": "Homepage Section Card",
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "collapsible_depends_on": "",
+   "columns": 0,
+   "default": "3",
+   "depends_on": "",
+   "description": "Number of columns for this section. 3 cards will be shown per row if you select 3 columns.",
+   "fieldname": "no_of_columns",
+   "fieldtype": "Select",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Number of Columns",
+   "length": 0,
+   "no_copy": 0,
+   "options": "1\n2\n3\n4\n6",
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "collapsible_depends_on": "",
+   "columns": 0,
+   "depends_on": "eval:doc.section_based_on === 'Custom HTML'",
+   "fieldname": "custom_html_section",
+   "fieldtype": "Section Break",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Custom HTML",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "depends_on": "",
+   "description": "Use this field to render any custom HTML in the section.",
+   "fieldname": "section_html",
+   "fieldtype": "Code",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Section HTML",
+   "length": 0,
+   "no_copy": 0,
+   "options": "HTML",
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "section_break_7",
+   "fieldtype": "Section Break",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "description": "Order in which sections should appear. 0 is first, 1 is second and so on.",
+   "fieldname": "section_order",
+   "fieldtype": "Int",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Section Order",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2019-03-04 23:52:31.290468",
+ "modified_by": "Administrator",
+ "module": "Portal",
+ "name": "Homepage Section",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "amend": 0,
+   "cancel": 0,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "if_owner": 0,
+   "import": 0,
+   "permlevel": 0,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "set_user_permissions": 0,
+   "share": 1,
+   "submit": 0,
+   "write": 1
+  }
+ ],
+ "quick_entry": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/portal/doctype/homepage_section/homepage_section.py b/erpnext/portal/doctype/homepage_section/homepage_section.py
new file mode 100644
index 0000000..1ed7030
--- /dev/null
+++ b/erpnext/portal/doctype/homepage_section/homepage_section.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe.model.document import Document
+from frappe.utils import cint
+
+class HomepageSection(Document):
+	@property
+	def column_value(self):
+		return cint(12 / cint(self.no_of_columns or 3))
diff --git a/erpnext/portal/doctype/homepage_section/test_homepage_section.py b/erpnext/portal/doctype/homepage_section/test_homepage_section.py
new file mode 100644
index 0000000..c52b7a9
--- /dev/null
+++ b/erpnext/portal/doctype/homepage_section/test_homepage_section.py
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+from bs4 import BeautifulSoup
+from frappe.tests.test_website import set_request
+from frappe.website.render import render
+
+class TestHomepageSection(unittest.TestCase):
+	def test_homepage_section_card(self):
+		try:
+			frappe.get_doc({
+				'doctype': 'Homepage Section',
+				'name': 'Card Section',
+				'section_based_on': 'Cards',
+				'section_cards': [
+					{'title': 'Card 1', 'subtitle': 'Subtitle 1', 'content': 'This is test card 1', 'route': '/card-1'},
+					{'title': 'Card 2', 'subtitle': 'Subtitle 2', 'content': 'This is test card 2', 'image': 'test.jpg'},
+				],
+				'no_of_columns': 3
+			}).insert()
+		except frappe.DuplicateEntryError:
+			pass
+
+		set_request(method='GET', path='home')
+		response = render()
+
+		self.assertEquals(response.status_code, 200)
+
+		html = frappe.safe_decode(response.get_data())
+
+		soup = BeautifulSoup(html, 'html.parser')
+		sections = soup.find('main').find_all('section')
+		self.assertEqual(len(sections), 3)
+
+		homepage_section = sections[2]
+		self.assertEqual(homepage_section.h3.text, 'Card Section')
+
+		cards = homepage_section.find_all(class_="card")
+
+		self.assertEqual(len(cards), 2)
+		self.assertEqual(cards[0].h5.text, 'Card 1')
+		self.assertEqual(cards[0].a['href'], '/card-1')
+		self.assertEqual(cards[1].p.text, 'Subtitle 2')
+		self.assertEqual(cards[1].find(class_='website-image-lazy')['data-src'], 'test.jpg')
+
+		# cleanup
+		frappe.db.rollback()
+
+	def test_homepage_section_custom_html(self):
+		frappe.get_doc({
+			'doctype': 'Homepage Section',
+			'name': 'Custom HTML Section',
+			'section_based_on': 'Custom HTML',
+			'section_html': '<div class="custom-section">My custom html</div>',
+		}).insert()
+
+		set_request(method='GET', path='home')
+		response = render()
+
+		self.assertEquals(response.status_code, 200)
+
+		html = frappe.safe_decode(response.get_data())
+
+		soup = BeautifulSoup(html, 'html.parser')
+		sections = soup.find('main').find_all(class_='custom-section')
+		self.assertEqual(len(sections), 1)
+
+		homepage_section = sections[0]
+		self.assertEqual(homepage_section.text, 'My custom html')
+
+		# cleanup
+		frappe.db.rollback()
diff --git a/erpnext/portal/doctype/homepage_section_card/__init__.py b/erpnext/portal/doctype/homepage_section_card/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/portal/doctype/homepage_section_card/__init__.py
diff --git a/erpnext/portal/doctype/homepage_section_card/homepage_section_card.json b/erpnext/portal/doctype/homepage_section_card/homepage_section_card.json
new file mode 100644
index 0000000..9092b26
--- /dev/null
+++ b/erpnext/portal/doctype/homepage_section_card/homepage_section_card.json
@@ -0,0 +1,203 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2019-02-10 19:39:02.734686",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "title",
+   "fieldtype": "Data",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 1,
+   "in_standard_filter": 0,
+   "label": "Title",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 1,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "subtitle",
+   "fieldtype": "Data",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Subtitle",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "image",
+   "fieldtype": "Attach Image",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Image",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "content",
+   "fieldtype": "Text",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Content",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "route",
+   "fieldtype": "Data",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 1,
+   "in_standard_filter": 0,
+   "label": "Route",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2019-02-10 20:11:41.040716",
+ "modified_by": "Administrator",
+ "module": "Portal",
+ "name": "Homepage Section Card",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/portal/doctype/homepage_section_card/homepage_section_card.py b/erpnext/portal/doctype/homepage_section_card/homepage_section_card.py
new file mode 100644
index 0000000..bd17279
--- /dev/null
+++ b/erpnext/portal/doctype/homepage_section_card/homepage_section_card.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe.model.document import Document
+
+class HomepageSectionCard(Document):
+	pass
diff --git a/erpnext/portal/doctype/products_settings/products_settings.js b/erpnext/portal/doctype/products_settings/products_settings.js
index 7a57aba..b68b5d7 100644
--- a/erpnext/portal/doctype/products_settings/products_settings.js
+++ b/erpnext/portal/doctype/products_settings/products_settings.js
@@ -3,6 +3,17 @@
 
 frappe.ui.form.on('Products Settings', {
 	refresh: function(frm) {
+		frappe.model.with_doctype('Item', () => {
+			const item_meta = frappe.get_meta('Item');
 
+			const valid_fields = item_meta.fields.filter(
+				df => ['Link', 'Table MultiSelect'].includes(df.fieldtype) && !df.hidden
+			).map(df => ({ label: df.label, value: df.fieldname }));
+
+			const field = frappe.meta.get_docfield("Website Filter Field", "fieldname", frm.docname);
+			field.fieldtype = 'Select';
+			field.options = valid_fields;
+			frm.fields_dict.filter_fields.grid.refresh();
+		});
 	}
 });
diff --git a/erpnext/portal/doctype/products_settings/products_settings.json b/erpnext/portal/doctype/products_settings/products_settings.json
index 69abae1..2cf8431 100644
--- a/erpnext/portal/doctype/products_settings/products_settings.json
+++ b/erpnext/portal/doctype/products_settings/products_settings.json
@@ -1,255 +1,389 @@
 {
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "beta": 0, 
- "creation": "2016-04-22 09:11:55.272398", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 0, 
- "engine": "InnoDB", 
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2016-04-22 09:11:55.272398",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 0,
+ "engine": "InnoDB",
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "description": "If checked, the Home page will be the default Item Group for the website", 
-   "fieldname": "home_page_is_products", 
-   "fieldtype": "Check", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Home Page is Products", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "description": "If checked, the Home page will be the default Item Group for the website",
+   "fieldname": "home_page_is_products",
+   "fieldtype": "Check",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Home Page is Products",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break_3", 
-   "fieldtype": "Column Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "column_break_3",
+   "fieldtype": "Column Break",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "products_as_list", 
-   "fieldtype": "Check", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Show Products as a List", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "show_availability_status",
+   "fieldtype": "Check",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Show Availability Status",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "show_availability_status", 
-   "fieldtype": "Check", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Show Availability Status", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "section_break_5",
+   "fieldtype": "Section Break",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Product Page",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "section_break_5", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "default": "6",
+   "fieldname": "products_per_page",
+   "fieldtype": "Int",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Products per Page",
+   "length": 0,
+   "no_copy": 0,
+   "options": "",
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "default": "6", 
-   "fieldname": "products_per_page", 
-   "fieldtype": "Int", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Products per Page", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "enable_field_filters",
+   "fieldtype": "Check",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Enable Field Filters",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "depends_on": "enable_field_filters",
+   "fieldname": "filter_fields",
+   "fieldtype": "Table",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Item Fields",
+   "length": 0,
+   "no_copy": 0,
+   "options": "Website Filter Field",
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "enable_attribute_filters",
+   "fieldtype": "Check",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Enable Attribute Filters",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "depends_on": "enable_attribute_filters",
+   "fieldname": "filter_attributes",
+   "fieldtype": "Table",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Attributes",
+   "length": 0,
+   "no_copy": 0,
+   "options": "Website Attribute",
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "hide_variants",
+   "fieldtype": "Check",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Hide Variants",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
   }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "idx": 0, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 0, 
- "issingle": 1, 
- "istable": 0, 
- "max_attachments": 0, 
- "modified": "2018-08-14 17:59:58.473100", 
- "modified_by": "Administrator", 
- "module": "Portal", 
- "name": "Products Settings", 
- "name_case": "", 
- "owner": "Administrator", 
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 1,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2019-03-07 19:18:31.822309",
+ "modified_by": "Administrator",
+ "module": "Portal",
+ "name": "Products Settings",
+ "name_case": "",
+ "owner": "Administrator",
  "permissions": [
   {
-   "amend": 0, 
-   "apply_user_permissions": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 0, 
-   "role": "Website Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
+   "amend": 0,
+   "cancel": 0,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 0,
+   "if_owner": 0,
+   "import": 0,
+   "permlevel": 0,
+   "print": 1,
+   "read": 1,
+   "report": 0,
+   "role": "Website Manager",
+   "set_user_permissions": 0,
+   "share": 1,
+   "submit": 0,
    "write": 1
   }
- ], 
- "quick_entry": 1, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "show_name_in_global_search": 0, 
- "sort_field": "modified", 
- "sort_order": "DESC", 
- "track_changes": 1, 
- "track_seen": 0
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
 }
\ No newline at end of file
diff --git a/erpnext/portal/doctype/products_settings/products_settings.py b/erpnext/portal/doctype/products_settings/products_settings.py
index f17ae9f..82afebf 100644
--- a/erpnext/portal/doctype/products_settings/products_settings.py
+++ b/erpnext/portal/doctype/products_settings/products_settings.py
@@ -5,6 +5,7 @@
 from __future__ import unicode_literals
 import frappe
 from frappe.utils import cint
+from frappe import _
 from frappe.model.document import Document
 
 class ProductsSettings(Document):
@@ -14,6 +15,26 @@
 			website_settings.home_page = 'products'
 			website_settings.save()
 
+		self.validate_field_filters()
+		self.validate_attribute_filters()
+
+	def validate_field_filters(self):
+		if not (self.enable_field_filters and self.filter_fields): return
+
+		item_meta = frappe.get_meta('Item')
+		valid_fields = [df.fieldname for df in item_meta.fields if df.fieldtype in ['Link', 'Table MultiSelect']]
+
+		for f in self.filter_fields:
+			if f.fieldname not in valid_fields:
+				frappe.throw(_('Filter Fields Row #{0}: Fieldname <b>{1}</b> must be of type "Link" or "Table MultiSelect"').format(f.idx, f.fieldname))
+
+	def validate_attribute_filters(self):
+		if not (self.enable_attribute_filters and self.filter_attributes): return
+
+		# if attribute filters are enabled, hide_variants should be disabled
+		self.hide_variants = 0
+
+
 def home_page_is_products(doc, method):
 	'''Called on saving Website Settings'''
 	home_page_is_products = cint(frappe.db.get_single_value('Products Settings', 'home_page_is_products'))
diff --git a/erpnext/portal/doctype/website_attribute/__init__.py b/erpnext/portal/doctype/website_attribute/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/portal/doctype/website_attribute/__init__.py
diff --git a/erpnext/portal/doctype/website_attribute/website_attribute.json b/erpnext/portal/doctype/website_attribute/website_attribute.json
new file mode 100644
index 0000000..2874dc4
--- /dev/null
+++ b/erpnext/portal/doctype/website_attribute/website_attribute.json
@@ -0,0 +1,76 @@
+{
+ "allow_copy": 0, 
+ "allow_events_in_timeline": 0, 
+ "allow_guest_to_view": 0, 
+ "allow_import": 0, 
+ "allow_rename": 0, 
+ "beta": 0, 
+ "creation": "2019-01-01 13:04:54.479079", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "", 
+ "editable_grid": 1, 
+ "engine": "InnoDB", 
+ "fields": [
+  {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "attribute", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Attribute", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Item Attribute", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }
+ ], 
+ "has_web_view": 0, 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "idx": 0, 
+ "image_view": 0, 
+ "in_create": 0, 
+ "is_submittable": 0, 
+ "issingle": 0, 
+ "istable": 1, 
+ "max_attachments": 0, 
+ "modified": "2019-01-01 13:04:59.715572", 
+ "modified_by": "Administrator", 
+ "module": "Portal", 
+ "name": "Website Attribute", 
+ "name_case": "", 
+ "owner": "Administrator", 
+ "permissions": [], 
+ "quick_entry": 1, 
+ "read_only": 0, 
+ "read_only_onload": 0, 
+ "show_name_in_global_search": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC", 
+ "track_changes": 1, 
+ "track_seen": 0, 
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/portal/doctype/website_attribute/website_attribute.py b/erpnext/portal/doctype/website_attribute/website_attribute.py
new file mode 100644
index 0000000..b8b667a
--- /dev/null
+++ b/erpnext/portal/doctype/website_attribute/website_attribute.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe.model.document import Document
+
+class WebsiteAttribute(Document):
+	pass
diff --git a/erpnext/portal/doctype/website_filter_field/__init__.py b/erpnext/portal/doctype/website_filter_field/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/portal/doctype/website_filter_field/__init__.py
diff --git a/erpnext/portal/doctype/website_filter_field/website_filter_field.json b/erpnext/portal/doctype/website_filter_field/website_filter_field.json
new file mode 100644
index 0000000..67c0d0a
--- /dev/null
+++ b/erpnext/portal/doctype/website_filter_field/website_filter_field.json
@@ -0,0 +1,76 @@
+{
+ "allow_copy": 0, 
+ "allow_events_in_timeline": 0, 
+ "allow_guest_to_view": 0, 
+ "allow_import": 0, 
+ "allow_rename": 0, 
+ "beta": 0, 
+ "creation": "2018-12-31 17:06:08.716134", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "", 
+ "editable_grid": 1, 
+ "engine": "InnoDB", 
+ "fields": [
+  {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "fieldname", 
+   "fieldtype": "Data", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Fieldname", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }
+ ], 
+ "has_web_view": 0, 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "idx": 0, 
+ "image_view": 0, 
+ "in_create": 0, 
+ "is_submittable": 0, 
+ "issingle": 0, 
+ "istable": 1, 
+ "max_attachments": 0, 
+ "modified": "2019-01-01 18:26:11.550380", 
+ "modified_by": "Administrator", 
+ "module": "Portal", 
+ "name": "Website Filter Field", 
+ "name_case": "", 
+ "owner": "Administrator", 
+ "permissions": [], 
+ "quick_entry": 1, 
+ "read_only": 0, 
+ "read_only_onload": 0, 
+ "show_name_in_global_search": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC", 
+ "track_changes": 1, 
+ "track_seen": 0, 
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/portal/doctype/website_filter_field/website_filter_field.py b/erpnext/portal/doctype/website_filter_field/website_filter_field.py
new file mode 100644
index 0000000..2aa8a6f
--- /dev/null
+++ b/erpnext/portal/doctype/website_filter_field/website_filter_field.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe.model.document import Document
+
+class WebsiteFilterField(Document):
+	pass
diff --git a/erpnext/portal/product_configurator/__init__.py b/erpnext/portal/product_configurator/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/portal/product_configurator/__init__.py
diff --git a/erpnext/portal/product_configurator/item_variants_cache.py b/erpnext/portal/product_configurator/item_variants_cache.py
new file mode 100644
index 0000000..cd557b5
--- /dev/null
+++ b/erpnext/portal/product_configurator/item_variants_cache.py
@@ -0,0 +1,94 @@
+import frappe
+
+class ItemVariantsCacheManager:
+	def __init__(self, item_code):
+		self.item_code = item_code
+
+	def get_item_variants_data(self):
+		val = frappe.cache().hget('item_variants_data', self.item_code)
+
+		if not val:
+			self.build_cache()
+
+		return frappe.cache().hget('item_variants_data', self.item_code)
+
+
+	def get_attribute_value_item_map(self):
+		val = frappe.cache().hget('attribute_value_item_map', self.item_code)
+
+		if not val:
+			self.build_cache()
+
+		return frappe.cache().hget('attribute_value_item_map', self.item_code)
+
+
+	def get_item_attribute_value_map(self):
+		val = frappe.cache().hget('item_attribute_value_map', self.item_code)
+
+		if not val:
+			self.build_cache()
+
+		return frappe.cache().hget('item_attribute_value_map', self.item_code)
+
+
+	def get_optional_attributes(self):
+		val = frappe.cache().hget('optional_attributes', self.item_code)
+
+		if not val:
+			self.build_cache()
+
+		return frappe.cache().hget('optional_attributes', self.item_code)
+
+
+	def build_cache(self):
+		parent_item_code = self.item_code
+
+		attributes = [a.attribute for a in frappe.db.get_all('Item Variant Attribute',
+			{'parent': parent_item_code}, ['attribute'], order_by='idx asc')
+		]
+
+		item_variants_data = frappe.db.get_all('Item Variant Attribute',
+			{'variant_of': parent_item_code}, ['parent', 'attribute', 'attribute_value'],
+			order_by='parent',
+			as_list=1
+		)
+
+		attribute_value_item_map = frappe._dict({})
+		item_attribute_value_map = frappe._dict({})
+
+		for row in item_variants_data:
+			item_code, attribute, attribute_value = row
+			# (attr, value) => [item1, item2]
+			attribute_value_item_map.setdefault((attribute, attribute_value), []).append(item_code)
+			# item => {attr1: value1, attr2: value2}
+			item_attribute_value_map.setdefault(item_code, {})[attribute] = attribute_value
+
+		optional_attributes = set()
+		for item_code, attr_dict in item_attribute_value_map.items():
+			for attribute in attributes:
+				if attribute not in attr_dict:
+					optional_attributes.add(attribute)
+
+		frappe.cache().hset('attribute_value_item_map', parent_item_code, attribute_value_item_map)
+		frappe.cache().hset('item_attribute_value_map', parent_item_code, item_attribute_value_map)
+		frappe.cache().hset('item_variants_data', parent_item_code, item_variants_data)
+		frappe.cache().hset('optional_attributes', parent_item_code, optional_attributes)
+
+	def clear_cache(self):
+		keys = ['attribute_value_item_map', 'item_attribute_value_map', 'item_variants_data', 'optional_attributes']
+
+		for key in keys:
+			frappe.cache().hdel(key, self.item_code)
+
+
+def build_cache(item_code):
+	frappe.cache().hset('item_cache_build_in_progress', item_code, 1)
+	print('ItemVariantsCacheManager: Building cache for', item_code)
+	i = ItemVariantsCacheManager(item_code)
+	i.build_cache()
+	frappe.cache().hset('item_cache_build_in_progress', item_code, 0)
+
+def enqueue_build_cache(item_code):
+	if frappe.cache().hget('item_cache_build_in_progress', item_code):
+		return
+	frappe.enqueue(build_cache, item_code=item_code, queue='short')
diff --git a/erpnext/portal/product_configurator/test_product_configurator.py b/erpnext/portal/product_configurator/test_product_configurator.py
new file mode 100644
index 0000000..a534e5f
--- /dev/null
+++ b/erpnext/portal/product_configurator/test_product_configurator.py
@@ -0,0 +1,84 @@
+from __future__ import unicode_literals
+
+from bs4 import BeautifulSoup
+import frappe, unittest
+from frappe.tests.test_website import set_request, get_html_for_route
+from frappe.website.render import render
+from erpnext.portal.product_configurator.utils import get_products_for_website
+from erpnext.stock.doctype.item.test_item import make_item_variant
+
+test_dependencies = ["Item"]
+
+class TestProductConfigurator(unittest.TestCase):
+	def setUp(self):
+		self.create_variant_item()
+
+	def test_product_list(self):
+		template_items = frappe.get_all('Item', {'show_in_website': 1})
+		variant_items = frappe.get_all('Item', {'show_variant_in_website': 1})
+
+		products_settings = frappe.get_doc('Products Settings')
+		products_settings.enable_field_filters = 1
+		products_settings.append('filter_fields', {'fieldname': 'item_group'})
+		products_settings.append('filter_fields', {'fieldname': 'stock_uom'})
+		products_settings.save()
+
+		html = get_html_for_route('all-products')
+
+		soup = BeautifulSoup(html, 'html.parser')
+		products_list = soup.find(class_='products-list')
+		items = products_list.find_all(class_='card')
+		self.assertEqual(len(items), len(template_items + variant_items))
+
+		items_with_item_group = frappe.get_all('Item', {'item_group': '_Test Item Group Desktops', 'show_in_website': 1})
+		variants_with_item_group = frappe.get_all('Item', {'item_group': '_Test Item Group Desktops', 'show_variant_in_website': 1})
+
+		# mock query params
+		frappe.form_dict = frappe._dict({
+			'field_filters': '{"item_group":["_Test Item Group Desktops"]}'
+		})
+		html = get_html_for_route('all-products')
+		soup = BeautifulSoup(html, 'html.parser')
+		products_list = soup.find(class_='products-list')
+		items = products_list.find_all(class_='card')
+		self.assertEqual(len(items), len(items_with_item_group + variants_with_item_group))
+
+
+	def test_get_products_for_website(self):
+		items = get_products_for_website(attribute_filters={
+			'Test Size': ['Medium']
+		})
+		self.assertEqual(len(items), 1)
+
+
+	def create_variant_item(self):
+		if not frappe.db.exists('Item', '_Test Variant Item 1'):
+			frappe.get_doc({
+				"description": "_Test Variant Item 12",
+				"doctype": "Item",
+				"is_stock_item": 1,
+				"variant_of": "_Test Variant Item",
+				"item_code": "_Test Variant Item 1",
+				"item_group": "_Test Item Group",
+				"item_name": "_Test Variant Item 1",
+				"stock_uom": "_Test UOM",
+				"item_defaults": [{
+					"company": "_Test Company",
+					"default_warehouse": "_Test Warehouse - _TC",
+					"expense_account": "_Test Account Cost for Goods Sold - _TC",
+					"buying_cost_center": "_Test Cost Center - _TC",
+					"selling_cost_center": "_Test Cost Center - _TC",
+					"income_account": "Sales - _TC"
+				}],
+				"attributes": [
+					{
+						"attribute": "Test Size",
+						"attribute_value": "Medium"
+					}
+				],
+				"show_variant_in_website": 1
+			}).insert()
+
+
+	def tearDown(self):
+		frappe.db.rollback()
\ No newline at end of file
diff --git a/erpnext/portal/product_configurator/utils.py b/erpnext/portal/product_configurator/utils.py
new file mode 100644
index 0000000..3594bc4
--- /dev/null
+++ b/erpnext/portal/product_configurator/utils.py
@@ -0,0 +1,402 @@
+import frappe
+from erpnext.portal.product_configurator.item_variants_cache import ItemVariantsCacheManager
+
+def get_field_filter_data():
+	product_settings = get_product_settings()
+	filter_fields = [row.fieldname for row in product_settings.filter_fields]
+
+	meta = frappe.get_meta('Item')
+	fields = [df for df in meta.fields if df.fieldname in filter_fields]
+
+	filter_data = []
+	for f in fields:
+		doctype = f.get_link_doctype()
+
+		# apply enable/disable filter
+		meta = frappe.get_meta(doctype)
+		filters = {}
+		if meta.has_field('enabled'):
+			filters['enabled'] = 1
+		if meta.has_field('disabled'):
+			filters['disabled'] = 0
+
+		values = [d.name for d in frappe.get_all(doctype, filters)]
+		filter_data.append([f, values])
+
+	return filter_data
+
+
+def get_attribute_filter_data():
+	product_settings = get_product_settings()
+	attributes = [row.attribute for row in product_settings.filter_attributes]
+	attribute_docs = [
+		frappe.get_doc('Item Attribute', attribute) for attribute in attributes
+	]
+
+	# mark attribute values as checked if they are present in the request url
+	if frappe.form_dict:
+		for attr in attribute_docs:
+			if attr.name in frappe.form_dict:
+				value = frappe.form_dict[attr.name]
+				if value:
+					enabled_values = value.split(',')
+				else:
+					enabled_values = []
+
+				for v in enabled_values:
+					for item_attribute_row in attr.item_attribute_values:
+						if v == item_attribute_row.attribute_value:
+							item_attribute_row.checked = True
+
+	return attribute_docs
+
+
+def get_products_for_website(field_filters=None, attribute_filters=None, search=None):
+
+	if attribute_filters:
+		item_codes = get_item_codes_by_attributes(attribute_filters)
+		items_by_attributes = get_items([['name', 'in', item_codes]])
+
+	if field_filters:
+		items_by_fields = get_items_by_fields(field_filters)
+
+	if attribute_filters and not field_filters:
+		return items_by_attributes
+
+	if field_filters and not attribute_filters:
+		return items_by_fields
+
+	if field_filters and attribute_filters:
+		items_intersection = []
+		item_codes_in_attribute = [item.name for item in items_by_attributes]
+
+		for item in items_by_fields:
+			if item.name in item_codes_in_attribute:
+				items_intersection.append(item)
+
+		return items_intersection
+
+	if search:
+		return get_items(search=search)
+
+	return get_items()
+
+
+@frappe.whitelist(allow_guest=True)
+def get_products_html_for_website(field_filters=None, attribute_filters=None):
+	field_filters = frappe.parse_json(field_filters)
+	attribute_filters = frappe.parse_json(attribute_filters)
+
+	items = get_products_for_website(field_filters, attribute_filters)
+	html = ''.join(get_html_for_items(items))
+
+	if not items:
+		html = frappe.render_template('erpnext/www/all-products/not_found.html', {})
+
+	return html
+
+
+def get_item_codes_by_attributes(attribute_filters, template_item_code=None):
+	items = []
+
+	for attribute, values in attribute_filters.items():
+		attribute_values = values
+
+		if not attribute_values: continue
+
+		wheres = []
+		query_values = []
+		for attribute_value in attribute_values:
+			wheres.append('( attribute = %s and attribute_value = %s )')
+			query_values += [attribute, attribute_value]
+
+		attribute_query = ' or '.join(wheres)
+
+		if template_item_code:
+			variant_of_query = 'AND t2.variant_of = %s'
+			query_values.append(template_item_code)
+		else:
+			variant_of_query = ''
+
+		query = '''
+			SELECT
+				t1.parent
+			FROM
+				`tabItem Variant Attribute` t1
+			WHERE
+				1 = 1
+				AND (
+					{attribute_query}
+				)
+				AND EXISTS (
+					SELECT
+						1
+					FROM
+						`tabItem` t2
+					WHERE
+						t2.name = t1.parent
+						{variant_of_query}
+				)
+			GROUP BY
+				t1.parent
+			ORDER BY
+				NULL
+		'''.format(attribute_query=attribute_query, variant_of_query=variant_of_query)
+
+		item_codes = set([r[0] for r in frappe.db.sql(query, query_values)])
+		items.append(item_codes)
+
+	res = list(set.intersection(*items))
+
+	return res
+
+
+@frappe.whitelist(allow_guest=True)
+def get_attributes_and_values(item_code):
+	'''Build a list of attributes and their possible values.
+	This will ignore the values upon selection of which there cannot exist one item.
+	'''
+	item_cache = ItemVariantsCacheManager(item_code)
+	item_variants_data = item_cache.get_item_variants_data()
+
+	attributes = get_item_attributes(item_code)
+	attribute_list = [a.attribute for a in attributes]
+
+	valid_options = {}
+	for item_code, attribute, attribute_value in item_variants_data:
+		if attribute in attribute_list:
+			valid_options.setdefault(attribute, set()).add(attribute_value)
+
+	for attr in attributes:
+		attr['values'] = valid_options.get(attr.attribute, [])
+
+	return attributes
+
+
+@frappe.whitelist(allow_guest=True)
+def get_next_attribute_and_values(item_code, selected_attributes):
+	'''Find the count of Items that match the selected attributes.
+	Also, find the attribute values that are not applicable for further searching.
+	If less than equal to 10 items are found, return item_codes of those items.
+	If one item is matched exactly, return item_code of that item.
+	'''
+	selected_attributes = frappe.parse_json(selected_attributes)
+
+	item_cache = ItemVariantsCacheManager(item_code)
+	item_variants_data = item_cache.get_item_variants_data()
+
+	attributes = get_item_attributes(item_code)
+	attribute_list = [a.attribute for a in attributes]
+	filtered_items = get_items_with_selected_attributes(item_code, selected_attributes)
+
+	next_attribute = None
+
+	for attribute in attribute_list:
+		if attribute not in selected_attributes:
+			next_attribute = attribute
+			break
+
+	valid_options_for_attributes = frappe._dict({})
+
+	for a in attribute_list:
+		valid_options_for_attributes[a] = set()
+
+		selected_attribute = selected_attributes.get(a, None)
+		if selected_attribute:
+			# already selected attribute values are valid options
+			valid_options_for_attributes[a].add(selected_attribute)
+
+	for row in item_variants_data:
+		item_code, attribute, attribute_value = row
+		if item_code in filtered_items and attribute not in selected_attributes and attribute in attribute_list:
+			valid_options_for_attributes[attribute].add(attribute_value)
+
+	optional_attributes = item_cache.get_optional_attributes()
+	exact_match = []
+	# search for exact match if all selected attributes are required attributes
+	if len(selected_attributes.keys()) >= (len(attribute_list) - len(optional_attributes)):
+		item_attribute_value_map = item_cache.get_item_attribute_value_map()
+		for item_code, attr_dict in item_attribute_value_map.items():
+			if item_code in filtered_items and set(attr_dict.keys()) == set(selected_attributes.keys()):
+				exact_match.append(item_code)
+
+	filtered_items_count = len(filtered_items)
+
+	# get product info if exact match
+	from erpnext.shopping_cart.product_info import get_product_info_for_website
+	if exact_match:
+		data = get_product_info_for_website(exact_match[0])
+		product_info = data.product_info
+		if not data.cart_settings.show_price:
+			product_info = None
+	else:
+		product_info = None
+
+	return {
+		'next_attribute': next_attribute,
+		'valid_options_for_attributes': valid_options_for_attributes,
+		'filtered_items_count': filtered_items_count,
+		'filtered_items': filtered_items if filtered_items_count < 10 else [],
+		'exact_match': exact_match,
+		'product_info': product_info
+	}
+
+
+def get_items_with_selected_attributes(item_code, selected_attributes):
+	item_cache = ItemVariantsCacheManager(item_code)
+	attribute_value_item_map = item_cache.get_attribute_value_item_map()
+
+	items = []
+	for attribute, value in selected_attributes.items():
+		items.append(set(attribute_value_item_map[(attribute, value)]))
+
+	return set.intersection(*items)
+
+
+def get_items_by_fields(field_filters):
+	meta = frappe.get_meta('Item')
+	filters = []
+	for fieldname, values in field_filters.items():
+		if not values: continue
+
+		_doctype = 'Item'
+		_fieldname = fieldname
+
+		df = meta.get_field(fieldname)
+		if df.fieldtype == 'Table MultiSelect':
+			child_doctype = df.options
+			child_meta = frappe.get_meta(child_doctype)
+			fields = child_meta.get("fields", { "fieldtype": "Link", "in_list_view": 1 })
+			if fields:
+				_doctype = child_doctype
+				_fieldname = fields[0].fieldname
+
+		if len(values) == 1:
+			filters.append([_doctype, _fieldname, '=', values[0]])
+		else:
+			filters.append([_doctype, _fieldname, 'in', values])
+
+	return get_items(filters)
+
+
+def get_items(filters=None, search=None):
+	start = frappe.form_dict.start or 0
+	products_settings = get_product_settings()
+	page_length = products_settings.products_per_page
+
+	filters = filters or []
+	# convert to list of filters
+	if isinstance(filters, dict):
+		filters = [['Item', fieldname, '=', value] for fieldname, value in filters.items()]
+
+	show_in_website_condition = ''
+	if products_settings.hide_variants:
+		show_in_website_condition = get_conditions({'show_in_website': 1 }, 'and')
+	else:
+		show_in_website_condition = get_conditions([
+			['show_in_website', '=', 1],
+			['show_variant_in_website', '=', 1]
+		], 'or')
+
+	search_condition = ''
+	if search:
+		search = '%{}%'.format(search)
+		or_filters = [
+			['name', 'like', search],
+			['item_name', 'like', search],
+			['description', 'like', search],
+			['item_group', 'like', search]
+		]
+		search_condition = get_conditions(or_filters, 'or')
+
+	filter_condition = get_conditions(filters, 'and')
+
+	where_conditions = ' and '.join(
+		[condition for condition in [show_in_website_condition, search_condition, filter_condition] if condition]
+	)
+
+	left_joins = []
+	for f in filters:
+		if len(f) == 4 and f[0] != 'Item':
+			left_joins.append(f[0])
+
+	left_join = ' '.join(['LEFT JOIN `tab{0}` on (`tab{0}`.parent = `tabItem`.name)'.format(l) for l in left_joins])
+
+	results = frappe.db.sql('''
+		SELECT
+			`tabItem`.`name`, `tabItem`.`item_name`,
+			`tabItem`.`website_image`, `tabItem`.`image`,
+			`tabItem`.`web_long_description`, `tabItem`.`description`,
+			`tabItem`.`route`
+		FROM
+			`tabItem`
+		{left_join}
+		WHERE
+			{where_conditions}
+		GROUP BY
+			`tabItem`.`name`
+		ORDER BY
+			`tabItem`.`weightage` DESC
+		LIMIT
+			{page_length}
+		OFFSET
+			{start}
+	'''.format(
+			where_conditions=where_conditions,
+			start=start,
+			page_length=page_length,
+			left_join=left_join
+		)
+	, as_dict=1)
+
+	for r in results:
+		r.description = r.web_long_description or r.description
+		r.image = r.website_image or r.image
+
+	return results
+
+
+def get_conditions(filter_list, and_or='and'):
+	from frappe.model.db_query import DatabaseQuery
+
+	if not filter_list:
+		return ''
+
+	conditions = []
+	DatabaseQuery('Item').build_filter_conditions(filter_list, conditions, ignore_permissions=True)
+	join_by = ' {0} '.format(and_or)
+
+	return '(' + join_by.join(conditions) + ')'
+
+# utilities
+
+def get_item_attributes(item_code):
+	attributes = frappe.db.get_all('Item Variant Attribute',
+		fields=['attribute'],
+		filters={
+			'parenttype': 'Item',
+			'parent': item_code
+		},
+		order_by='idx asc'
+	)
+
+	optional_attributes = ItemVariantsCacheManager(item_code).get_optional_attributes()
+
+	for a in attributes:
+		if a.attribute in optional_attributes:
+			a.optional = True
+
+	return attributes
+
+def get_html_for_items(items):
+	html = []
+	for item in items:
+		html.append(frappe.render_template('erpnext/www/all-products/item_row.html', {
+			'item': item
+		}))
+	return html
+
+def get_product_settings():
+	doc = frappe.get_cached_doc('Products Settings')
+	doc.products_per_page = doc.products_per_page or 20
+	return doc
diff --git a/erpnext/public/build.json b/erpnext/public/build.json
index c34eef2..60e72da 100644
--- a/erpnext/public/build.json
+++ b/erpnext/public/build.json
@@ -11,7 +11,7 @@
         "public/js/shopping_cart.js"
     ],
 	"css/erpnext-web.css": [
-		"public/less/website.less"
+        "public/scss/website.scss"
 	],
     "js/marketplace.min.js": [
         "public/js/hub/marketplace.js"
diff --git a/erpnext/public/js/shopping_cart.js b/erpnext/public/js/shopping_cart.js
index 7755141..5a05268 100644
--- a/erpnext/public/js/shopping_cart.js
+++ b/erpnext/public/js/shopping_cart.js
@@ -48,6 +48,7 @@
 				args: {
 					item_code: opts.item_code,
 					qty: opts.qty,
+					additional_notes: opts.additional_notes !== undefined ? opts.additional_notes : undefined,
 					with_items: opts.with_items || 0
 				},
 				btn: opts.btn,
@@ -94,11 +95,12 @@
 		}
 	},
 
-	shopping_cart_update: function(item_code, newVal, cart_dropdown) {
+	shopping_cart_update: function({item_code, qty, cart_dropdown, additional_notes}) {
 		frappe.freeze();
 		shopping_cart.update_cart({
-			item_code: item_code,
-			qty: newVal,
+			item_code,
+			qty,
+			additional_notes,
 			with_items: 1,
 			btn: this,
 			callback: function(r) {
@@ -131,7 +133,7 @@
 			}
 			input.val(newVal);
 			var item_code = input.attr("data-item-code");
-			shopping_cart.shopping_cart_update(item_code, newVal, true);
+			shopping_cart.shopping_cart_update({item_code, qty: newVal, cart_dropdown: true});
 			return false;
 		});
 
diff --git a/erpnext/public/js/templates/address_list.html b/erpnext/public/js/templates/address_list.html
index 2379ef6..0bc86ed 100644
--- a/erpnext/public/js/templates/address_list.html
+++ b/erpnext/public/js/templates/address_list.html
@@ -9,7 +9,7 @@
             <span class="text-muted">({%= __("Shipping") %})</span>{% } %}
 
         <a href="#Form/Address/{%= encodeURIComponent(addr_list[i].name) %}"
-            class="btn btn-default btn-xs pull-right"
+            class="btn btn-light btn-xs pull-right"
 				style="margin-top:-3px; margin-right: -5px;">
             {%= __("Edit") %}</a>
     </p>
@@ -19,5 +19,5 @@
 {% if(!addr_list.length) { %}
 <p class="text-muted small">{%= __("No address added yet.") %}</p>
 {% } %}
-<p><button class="btn btn-xs btn-default btn-address">{{ __("New Address") }}</button></p>
+<p><button class="btn btn-xs btn-light btn-address">{{ __("New Address") }}</button></p>
 
diff --git a/erpnext/public/js/templates/contact_list.html b/erpnext/public/js/templates/contact_list.html
index 893b4e0..2144893 100644
--- a/erpnext/public/js/templates/contact_list.html
+++ b/erpnext/public/js/templates/contact_list.html
@@ -10,7 +10,7 @@
 			 <span class="text-muted">&ndash; {%= contact_list[i].designation %}</span>
 			{% } %}
 			<a href="#Form/Contact/{%= encodeURIComponent(contact_list[i].name) %}"
-				class="btn btn-xs btn-default pull-right"
+				class="btn btn-xs btn-light pull-right"
 				style="margin-top:-3px; margin-right: -5px;">
 				{%= __("Edit") %}</a>
 		</p>
@@ -33,6 +33,6 @@
 {% if(!contact_list.length) { %}
 <p class="text-muted small">{%= __("No contacts added yet.") %}</p>
 {% } %}
-<p><button class="btn btn-xs btn-default btn-contact">
+<p><button class="btn btn-xs btn-light btn-contact">
 	{{ __("New Contact") }}</button>
 </p>
\ No newline at end of file
diff --git a/erpnext/public/js/website_theme.js b/erpnext/public/js/website_theme.js
new file mode 100644
index 0000000..6c7edfa
--- /dev/null
+++ b/erpnext/public/js/website_theme.js
@@ -0,0 +1,17 @@
+// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
+// MIT License. See license.txt
+
+frappe.ui.form.on('Website Theme', {
+	apply_custom_theme(frm) {
+		let custom_theme = frm.doc.custom_theme;
+		custom_theme = custom_theme.split('\n');
+		if (
+			frm.doc.apply_custom_theme
+				&& custom_theme.length === 2
+				&& custom_theme[1].includes('frappe/public/scss/website')
+		) {
+			frm.set_value('custom_theme',
+				`$primary: #7575ff;\n@import "frappe/public/scss/website";\n@import "erpnext/public/scss/website";`);
+		}
+	}
+});
diff --git a/erpnext/public/less/products.less b/erpnext/public/less/products.less
new file mode 100644
index 0000000..79f57b3
--- /dev/null
+++ b/erpnext/public/less/products.less
@@ -0,0 +1,69 @@
+@import "variables.less";
+
+.products-list .product-image {
+	display: inline-block;
+	width: 160px;
+	height: 160px;
+	object-fit: contain;
+	margin-right: 1rem;
+}
+
+.product-image.no-image {
+	display: flex;
+	justify-content: center;
+	align-items: center;
+	font-size: 3rem;
+	color: var(--gray);
+	background: var(--light);
+}
+
+.product-image a {
+	text-decoration: none;
+}
+
+.filter-options {
+	max-height: 300px;
+	overflow: auto;
+}
+
+.item-slideshow-image {
+	height: 3rem;
+	width: 3rem;
+	object-fit: contain;
+	padding: 0.5rem;
+	border: 1px solid @border-color;
+	border-radius: 4px;
+	cursor: pointer;
+
+	&:hover, &.active {
+		border-color: var(--primary);
+	}
+}
+
+.address-card {
+	cursor: pointer;
+	position: relative;
+
+	.check {
+		display: none;
+	}
+
+	&.active {
+		border-color: var(--primary);
+
+		.check {
+			display: inline-flex;
+		}
+	}
+}
+
+.check {
+	display: inline-flex;
+    padding: 0.25rem;
+    background: var(--primary);
+    color: white;
+    border-radius: 50%;
+	font-size: 12px;
+	width: 24px;
+	height: 24px;
+}
\ No newline at end of file
diff --git a/erpnext/public/less/website.less b/erpnext/public/less/website.less
index 0518b26..57a0a33 100644
--- a/erpnext/public/less/website.less
+++ b/erpnext/public/less/website.less
@@ -245,10 +245,10 @@
 	}
 }
 
-.number-spinner {
-	width:100px;
-	margin-top:5px;
-}
+// .number-spinner {
+// 	width:100px;
+// 	margin-top:5px;
+// }
 
 .cart-btn {
 	border-color: #ccc;
@@ -361,3 +361,24 @@
 		border-color: @brand-primary;
 	}
 }
+
+.item-slideshow-image {
+	height: 3rem;
+	width: 3rem;
+	object-fit: contain;
+	padding: 0.5rem;
+	border: 1px solid @border-color;
+	border-radius: 4px;
+	cursor: pointer;
+
+	&:hover, &.active {
+		border-color: @brand-primary;
+	}
+}
+
+.section-products {
+	.card-img-top {
+		max-height: 300px;
+		object-fit: contain;
+	}
+}
\ No newline at end of file
diff --git a/erpnext/public/node_modules b/erpnext/public/node_modules
new file mode 120000
index 0000000..903b09c
--- /dev/null
+++ b/erpnext/public/node_modules
@@ -0,0 +1 @@
+/Users/netchampfaris/frappe-bench/apps/erpnext/node_modules
\ No newline at end of file
diff --git a/erpnext/public/scss/website.scss b/erpnext/public/scss/website.scss
new file mode 100644
index 0000000..002498f
--- /dev/null
+++ b/erpnext/public/scss/website.scss
@@ -0,0 +1,53 @@
+@import "frappe/public/scss/variables";
+
+.product-image img {
+	min-height: 20rem;
+	max-height: 30rem;
+}
+
+.filter-options {
+	max-height: 300px;
+	overflow: auto;
+}
+
+.item-slideshow-image {
+	height: 3rem;
+	width: 3rem;
+	object-fit: contain;
+	padding: 0.5rem;
+	border: 1px solid $border-color;
+	border-radius: 4px;
+	cursor: pointer;
+
+	&:hover, &.active {
+		border-color: $primary;
+	}
+}
+
+.address-card {
+	cursor: pointer;
+	position: relative;
+
+	.check {
+		display: none;
+	}
+
+	&.active {
+		border-color: $primary;
+
+		.check {
+			display: inline-flex;
+		}
+	}
+}
+
+.check {
+	display: inline-flex;
+    padding: 0.25rem;
+    background: $primary;
+    color: white;
+    border-radius: 50%;
+	font-size: 12px;
+	width: 24px;
+	height: 24px;
+}
diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json
index 2eaa727..118c333 100644
--- a/erpnext/selling/doctype/quotation_item/quotation_item.json
+++ b/erpnext/selling/doctype/quotation_item/quotation_item.json
@@ -1,18 +1,18 @@
 {
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "",
- "beta": 0,
- "creation": "2013-03-07 11:42:57",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "allow_copy": 0, 
+ "allow_events_in_timeline": 0, 
+ "allow_guest_to_view": 0, 
+ "allow_import": 0, 
+ "allow_rename": 0, 
+ "autoname": "", 
+ "beta": 0, 
+ "creation": "2013-03-07 11:42:57", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "Document", 
+ "editable_grid": 1, 
+ "engine": "InnoDB", 
  "fields": [
   {
    "allow_bulk_edit": 0,
@@ -1934,32 +1934,96 @@
    "translatable": 0,
    "unique": 0,
    "width": "150px"
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 1, 
+   "columns": 0, 
+   "fieldname": "shopping_cart_section", 
+   "fieldtype": "Section Break", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Shopping Cart", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "additional_notes", 
+   "fieldtype": "Text", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Additional Notes", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
   }
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "menu_index": 0,
- "modified": "2019-02-18 18:57:25.277633",
- "modified_by": "Administrator",
- "module": "Selling",
- "name": "Quotation Item",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
+ ], 
+ "has_web_view": 0, 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "idx": 1, 
+ "image_view": 0, 
+ "in_create": 0, 
+ "is_submittable": 0, 
+ "issingle": 0, 
+ "istable": 1, 
+ "max_attachments": 0, 
+ "menu_index": 0, 
+ "modified": "2019-01-09 17:49:41.606821", 
+ "modified_by": "Administrator", 
+ "module": "Selling", 
+ "name": "Quotation Item", 
+ "owner": "Administrator", 
+ "permissions": [], 
+ "quick_entry": 0, 
+ "read_only": 0, 
+ "read_only_onload": 0, 
+ "show_name_in_global_search": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC", 
+ "track_changes": 1, 
+ "track_seen": 0, 
  "track_views": 0
-}
+}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py
index 527bed2..0395d1d 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -71,8 +71,7 @@
 			"items": get_product_list_for_group(product_group = self.name, start=start,
 				limit=context.page_length + 1, search=frappe.form_dict.get("search")),
 			"parents": get_parent_item_groups(self.parent_item_group),
-			"title": self.name,
-			"products_as_list": cint(frappe.db.get_single_value('Website Settings', 'products_as_list'))
+			"title": self.name
 		})
 
 		if self.slideshow:
@@ -119,7 +118,7 @@
 	for item in data:
 		set_product_info_for_website(item)
 
-	return [get_item_for_list_in_html(r) for r in data]
+	return data
 
 def get_child_groups_for_list_in_html(item_group, start, limit, search):
 	search_filters = None
@@ -141,7 +140,7 @@
 		limit = limit
 	)
 
-	return [get_item_for_list_in_html(r) for r in data]
+	return data
 
 def adjust_qty_for_expired_items(data):
 	adjusted_data = []
@@ -172,9 +171,7 @@
 	context["show_availability_status"] = cint(frappe.db.get_single_value('Products Settings',
 		'show_availability_status'))
 
-	products_template = 'templates/includes/products_as_grid.html'
-	if cint(frappe.db.get_single_value('Products Settings', 'products_as_list')):
-		products_template = 'templates/includes/products_as_list.html'
+	products_template = 'templates/includes/products_as_list.html'
 
 	return frappe.get_template(products_template).render(context)
 
@@ -188,15 +185,20 @@
 
 
 def get_parent_item_groups(item_group_name):
+	base_parents = [
+		{"name": frappe._("Home"), "route":"/"},
+		{"name": frappe._("All Products"), "route":"/all-products"},
+	]
 	if not item_group_name:
-		return [{"name": frappe._("Home"), "route":"/"}]
+		return base_parents
+
 	item_group = frappe.get_doc("Item Group", item_group_name)
 	parent_groups = frappe.db.sql("""select name, route from `tabItem Group`
 		where lft <= %s and rgt >= %s
 		and show_in_website=1
 		order by lft asc""", (item_group.lft, item_group.rgt), as_dict=True)
 
-	return 	[{"name": frappe._("Home"), "route":"/"}] + parent_groups
+	return base_parents + parent_groups
 
 def invalidate_cache_for(doc, item_group=None):
 	if not item_group:
diff --git a/erpnext/setup/setup_wizard/operations/default_website.py b/erpnext/setup/setup_wizard/operations/default_website.py
index 8ca213b..38b5c14 100644
--- a/erpnext/setup/setup_wizard/operations/default_website.py
+++ b/erpnext/setup/setup_wizard/operations/default_website.py
@@ -45,7 +45,7 @@
 		website_settings.append("top_bar_items", {
 			"doctype": "Top Bar Item",
 			"label": _("Products"),
-			"url": "/products"
+			"url": "/all-products"
 		})
 		website_settings.save()
 
diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py
index 7eb1614..8e8c79c 100644
--- a/erpnext/shopping_cart/cart.py
+++ b/erpnext/shopping_cart/cart.py
@@ -45,7 +45,8 @@
 			for address in addresses],
 		"billing_addresses": [{"name": address.name, "display": address.display}
 			for address in addresses],
-		"shipping_rules": get_applicable_shipping_rules(party)
+		"shipping_rules": get_applicable_shipping_rules(party),
+		"cart_settings": frappe.get_cached_doc("Shopping Cart Settings")
 	}
 
 @frappe.whitelist()
@@ -83,7 +84,14 @@
 	return sales_order.name
 
 @frappe.whitelist()
-def update_cart(item_code, qty, with_items=False):
+def request_for_quotation():
+	quotation = _get_cart_quotation()
+	quotation.flags.ignore_permissions = True
+	quotation.submit()
+	return quotation.name
+
+@frappe.whitelist()
+def update_cart(item_code, qty, additional_notes=None, with_items=False):
 	quotation = _get_cart_quotation()
 
 	empty_card = False
@@ -101,10 +109,12 @@
 			quotation.append("items", {
 				"doctype": "Quotation Item",
 				"item_code": item_code,
-				"qty": qty
+				"qty": qty,
+				"additional_notes": additional_notes
 			})
 		else:
 			quotation_items[0].qty = qty
+			quotation_items[0].additional_notes = additional_notes
 
 	apply_cart_settings(quotation=quotation)
 
@@ -140,6 +150,45 @@
 
 	return frappe.render_template('templates/includes/cart/cart_dropdown.html', context)
 
+
+@frappe.whitelist()
+def add_new_address(doc):
+	doc = frappe.parse_json(doc)
+	doc.update({
+		'doctype': 'Address'
+	})
+	address = frappe.get_doc(doc)
+	address.save(ignore_permissions=True)
+
+	return address
+
+@frappe.whitelist(allow_guest=True)
+def create_lead_for_item_inquiry(lead, subject, message):
+	lead = frappe.parse_json(lead)
+	lead_doc = frappe.new_doc('Lead')
+	lead_doc.update(lead)
+	lead_doc.set('lead_owner', '')
+
+	try:
+		lead_doc.save(ignore_permissions=True)
+	except frappe.exceptions.DuplicateEntryError:
+		frappe.clear_messages()
+		lead_doc = frappe.get_doc('Lead', {'email_id': lead['email_id']})
+
+	lead_doc.add_comment('Comment', text='''
+		<div>
+			<h5>{subject}</h5>
+			<p>{message}</p>
+		</div>
+	'''.format(subject=subject, message=message))
+
+	return lead_doc
+
+
+@frappe.whitelist()
+def get_terms_and_conditions(terms_name):
+	return frappe.db.get_value('Terms and Conditions', terms_name, 'terms')
+
 @frappe.whitelist()
 def update_cart_address(address_fieldname, address_name):
 	quotation = _get_cart_quotation()
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json
index 724c1e9..e6b47a6 100644
--- a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json
+++ b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.json
@@ -1,641 +1,683 @@
 {
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "beta": 0, 
- "creation": "2013-06-19 15:57:32", 
- "custom": 0, 
- "description": "Default settings for Shopping Cart", 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "System", 
- "editable_grid": 0, 
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2013-06-19 15:57:32",
+ "custom": 0,
+ "description": "Default settings for Shopping Cart",
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "System",
+ "editable_grid": 0,
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "enabled", 
-   "fieldtype": "Check", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Enable purchase of items via the website", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "enabled",
+   "fieldtype": "Check",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 1,
+   "in_standard_filter": 0,
+   "label": "Enable Shopping Cart",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "description": "", 
-   "fieldname": "display_settings", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Display Settings", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "depends_on": "",
+   "description": "",
+   "fieldname": "display_settings",
+   "fieldtype": "Section Break",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Display Settings",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "description": "", 
-   "fieldname": "show_attachments", 
-   "fieldtype": "Check", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Show Public Attachments", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "depends_on": "",
+   "description": "",
+   "fieldname": "show_attachments",
+   "fieldtype": "Check",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Show Public Attachments",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "depends_on": "eval:doc.enabled==0", 
-   "description": "", 
-   "fieldname": "show_price", 
-   "fieldtype": "Check", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Show Price", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "depends_on": "",
+   "description": "",
+   "fieldname": "show_price",
+   "fieldtype": "Check",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Show Price",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break_5", 
-   "fieldtype": "Column Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "show_stock_availability",
+   "fieldtype": "Check",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Show Stock Availability",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "show_stock_availability", 
-   "fieldtype": "Check", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Show Stock Availability", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "show_configure_button",
+   "fieldtype": "Check",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Show Configure Button",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "depends_on": "show_stock_availability", 
-   "fieldname": "show_quantity_in_website", 
-   "fieldtype": "Check", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Show Stock Quantity", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "show_contact_us_button",
+   "fieldtype": "Check",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Show Contact Us Button",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "section_break_2", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "depends_on": "show_stock_availability",
+   "fieldname": "show_quantity_in_website",
+   "fieldtype": "Check",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Show Stock Quantity",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "company", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Company", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Company", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 1, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "depends_on": "enabled",
+   "fieldname": "section_break_2",
+   "fieldtype": "Section Break",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "description": "Prices will not be shown if Price List is not set", 
-   "fieldname": "price_list", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Price List", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Price List", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "depends_on": "",
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 1,
+   "in_standard_filter": 0,
+   "label": "Company",
+   "length": 0,
+   "no_copy": 0,
+   "options": "Company",
+   "permlevel": 0,
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 1,
+   "report_hide": 0,
+   "reqd": 1,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break_4", 
-   "fieldtype": "Column Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "description": "Prices will not be shown if Price List is not set",
+   "fieldname": "price_list",
+   "fieldtype": "Link",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Price List",
+   "length": 0,
+   "no_copy": 0,
+   "options": "Price List",
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "description": "", 
-   "fieldname": "default_customer_group", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 1, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Default Customer Group", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Customer Group", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "column_break_4",
+   "fieldtype": "Column Break",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "quotation_series", 
-   "fieldtype": "Select", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Quotation Series", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "description": "",
+   "fieldname": "default_customer_group",
+   "fieldtype": "Link",
+   "hidden": 0,
+   "ignore_user_permissions": 1,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Default Customer Group",
+   "length": 0,
+   "no_copy": 0,
+   "options": "Customer Group",
+   "permlevel": 0,
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 1,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 1, 
-   "collapsible_depends_on": "eval:doc.enable_checkout", 
-   "columns": 0, 
-   "fieldname": "section_break_8", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Checkout Settings", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "quotation_series",
+   "fieldtype": "Select",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Quotation Series",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 1,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "enable_checkout", 
-   "fieldtype": "Check", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Enable Checkout", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 1,
+   "collapsible_depends_on": "eval:doc.enable_checkout",
+   "columns": 0,
+   "depends_on": "enabled",
+   "fieldname": "section_break_8",
+   "fieldtype": "Section Break",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Checkout Settings",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "default": "Orders", 
-   "description": "After payment completion redirect user to selected page.", 
-   "fieldname": "payment_success_url", 
-   "fieldtype": "Select", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Payment Success Url", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "\nOrders\nInvoices\nMy Account", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "collapsible_depends_on": "",
+   "columns": 0,
+   "depends_on": "",
+   "fieldname": "enable_checkout",
+   "fieldtype": "Check",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Enable Checkout",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break_11", 
-   "fieldtype": "Column Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "default": "Orders",
+   "description": "After payment completion redirect user to selected page.",
+   "fieldname": "payment_success_url",
+   "fieldtype": "Select",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Payment Success Url",
+   "length": 0,
+   "no_copy": 0,
+   "options": "\nOrders\nInvoices\nMy Account",
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "payment_gateway_account", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Payment Gateway Account", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Payment Gateway Account", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "column_break_11",
+   "fieldtype": "Column Break",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "payment_gateway_account",
+   "fieldtype": "Link",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Payment Gateway Account",
+   "length": 0,
+   "no_copy": 0,
+   "options": "Payment Gateway Account",
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
    "unique": 0
   }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "icon": "fa fa-shopping-cart", 
- "idx": 1, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 0, 
- "issingle": 1, 
- "istable": 0, 
- "max_attachments": 0, 
- "modified": "2018-05-31 03:11:58.911732", 
- "modified_by": "sushant@digithinkit.com", 
- "module": "Shopping Cart", 
- "name": "Shopping Cart Settings", 
- "owner": "Administrator", 
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "icon": "fa fa-shopping-cart",
+ "idx": 1,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 1,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2019-01-26 13:54:24.575322",
+ "modified_by": "Administrator",
+ "module": "Shopping Cart",
+ "name": "Shopping Cart Settings",
+ "owner": "Administrator",
  "permissions": [
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 0, 
-   "email": 1, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 0, 
-   "role": "Website Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
+   "amend": 0,
+   "cancel": 0,
+   "create": 1,
+   "delete": 0,
+   "email": 1,
+   "export": 0,
+   "if_owner": 0,
+   "import": 0,
+   "permlevel": 0,
+   "print": 1,
+   "read": 1,
+   "report": 0,
+   "role": "Website Manager",
+   "set_user_permissions": 0,
+   "share": 1,
+   "submit": 0,
    "write": 1
   }
- ], 
- "quick_entry": 0, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "show_name_in_global_search": 0, 
- "sort_order": "ASC", 
- "track_changes": 0, 
- "track_seen": 0
-}
+ ],
+ "quick_entry": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_order": "ASC",
+ "track_changes": 0,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/shopping_cart/product_info.py b/erpnext/shopping_cart/product_info.py
index 3af5afa..f9a45ce 100644
--- a/erpnext/shopping_cart/product_info.py
+++ b/erpnext/shopping_cart/product_info.py
@@ -41,10 +41,10 @@
 			if item:
 				product_info["qty"] = item[0].qty
 
-	return {
+	return frappe._dict({
 		"product_info": product_info,
 		"cart_settings": cart_settings
-	}
+	})
 
 def set_product_info_for_website(item):
 	"""set product price uom for website"""
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index 3749601..6c30d00 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -180,6 +180,10 @@
 		if (frm.doc.default_warehouse && !frm.doc.website_warehouse){
 			frm.set_value("website_warehouse", frm.doc.default_warehouse);
 		}
+	},
+
+	set_meta_tags(frm) {
+		frappe.utils.set_meta_tag(frm.doc.route);
 	}
 });
 
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index b637573..25c7f44 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -1,7 +1,7 @@
 {
  "allow_copy": 0,
  "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
+ "allow_guest_to_view": 1,
  "allow_import": 1,
  "allow_rename": 1,
  "autoname": "field:item_code",
@@ -3865,6 +3865,39 @@
    "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
+   "fieldname": "set_meta_tags",
+   "fieldtype": "Button",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Set Meta Tags",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
    "collapsible": 1,
    "collapsible_depends_on": "website_specifications",
    "columns": 0,
@@ -4001,6 +4034,39 @@
    "bold": 0,
    "collapsible": 0,
    "columns": 0,
+   "description": "You can use any valid Bootstrap 4 markup in this field. It will be shown on your Item Page.",
+   "fieldname": "website_content",
+   "fieldtype": "HTML Editor",
+   "hidden": 0,
+   "ignore_user_permissions": 0,
+   "ignore_xss_filter": 0,
+   "in_filter": 0,
+   "in_global_search": 0,
+   "in_list_view": 0,
+   "in_standard_filter": 0,
+   "label": "Website Content",
+   "length": 0,
+   "no_copy": 0,
+   "permlevel": 0,
+   "precision": "",
+   "print_hide": 0,
+   "print_hide_if_no_value": 0,
+   "read_only": 0,
+   "remember_last_selected_value": 0,
+   "report_hide": 0,
+   "reqd": 0,
+   "search_index": 0,
+   "set_only_once": 0,
+   "translatable": 0,
+   "unique": 0
+  },
+  {
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
    "fieldname": "total_projected_qty",
    "fieldtype": "Float",
    "hidden": 1,
@@ -4194,7 +4260,7 @@
    "unique": 0
   }
  ],
- "has_web_view": 0,
+ "has_web_view": 1,
  "hide_heading": 0,
  "hide_toolbar": 0,
  "icon": "fa fa-tag",
@@ -4206,7 +4272,7 @@
  "issingle": 0,
  "istable": 0,
  "max_attachments": 1,
- "modified": "2019-02-16 17:43:56.039611",
+ "modified": "2019-03-08 11:47:59.269724",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Item",
@@ -4377,4 +4443,4 @@
  "track_changes": 1,
  "track_seen": 0,
  "track_views": 0
-}
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 5669552..2dcecb9 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -9,11 +9,11 @@
 import frappe
 import copy
 from erpnext.controllers.item_variant import (ItemVariantExistsError,
-        copy_attributes_to_variant, get_variant, make_variant_item_code, validate_item_variant_attributes)
+		copy_attributes_to_variant, get_variant, make_variant_item_code, validate_item_variant_attributes)
 from erpnext.setup.doctype.item_group.item_group import (get_parent_item_groups, invalidate_cache_for)
 from frappe import _, msgprint
 from frappe.utils import (cint, cstr, flt, formatdate, get_timestamp, getdate,
-                          now_datetime, random_string, strip)
+						  now_datetime, random_string, strip)
 from frappe.utils.html_utils import clean_html
 from frappe.website.doctype.website_slideshow.website_slideshow import \
 	get_slideshow
@@ -40,7 +40,7 @@
 	website = frappe._dict(
 		page_title_field="item_name",
 		condition_field="show_in_website",
-		template="templates/generators/item.html",
+		template="templates/generators/item/item.html",
 		no_cache=1
 	)
 
@@ -160,7 +160,7 @@
 		'''Add a new price'''
 		if not price_list:
 			price_list = (frappe.db.get_single_value('Selling Settings', 'selling_price_list')
-                    	or frappe.db.get_value('Price List', _('Standard Selling')))
+						or frappe.db.get_value('Price List', _('Standard Selling')))
 		if price_list:
 			item_price = frappe.get_doc({
 				"doctype": "Item Price",
@@ -199,7 +199,7 @@
 	def make_route(self):
 		if not self.route:
 			return cstr(frappe.db.get_value('Item Group', self.item_group,
-                    'route')) + '/' + self.scrub((self.item_name if self.item_name else self.item_code) + '-' + random_string(5))
+					'route')) + '/' + self.scrub((self.item_name if self.item_name else self.item_code) + '-' + random_string(5))
 
 	def validate_website_image(self):
 		"""Validate if the website image is a public file"""
@@ -222,7 +222,7 @@
 		if not file_doc:
 			if not auto_set_website_image:
 				frappe.msgprint(_("Website Image {0} attached to Item {1} cannot be found")
-                                    .format(self.website_image, self.name))
+									.format(self.website_image, self.name))
 
 			self.website_image = None
 
@@ -313,6 +313,8 @@
 		self.set_variant_context(context)
 		self.set_attribute_context(context)
 		self.set_disabled_attributes(context)
+		self.set_metatags(context)
+		self.set_shopping_cart_data(context)
 
 		return context
 
@@ -323,8 +325,8 @@
 			# load variants
 			# also used in set_attribute_context
 			context.variants = frappe.get_all("Item",
-                 filters={"variant_of": self.name, "show_variant_in_website": 1},
-                 order_by="name asc")
+				 filters={"variant_of": self.name, "show_variant_in_website": 1},
+				 order_by="name asc")
 
 			variant = frappe.form_dict.variant
 			if not variant and context.variants:
@@ -335,7 +337,7 @@
 				context.variant = frappe.get_doc("Item", variant)
 
 				for fieldname in ("website_image", "web_long_description", "description",
-                                        "website_specifications"):
+										"website_specifications"):
 					if context.variant.get(fieldname):
 						value = context.variant.get(fieldname)
 						if isinstance(value, list):
@@ -358,8 +360,12 @@
 			# load attributes
 			for v in context.variants:
 				v.attributes = frappe.get_all("Item Variant Attribute",
-                      fields=["attribute", "attribute_value"],
+					  fields=["attribute", "attribute_value"],
 					  filters={"parent": v.name})
+				# make a map for easier access in templates
+				v.attribute_map = frappe._dict({})
+				for attr in v.attributes:
+					v.attribute_map[attr.attribute] = attr.attribute_value
 
 				for attr in v.attributes:
 					values = attribute_values_available.setdefault(attr.attribute, [])
@@ -431,6 +437,31 @@
 				if not find_variant(combination):
 					context.disabled_attributes.setdefault(attr.attribute, []).append(combination[-1])
 
+	def set_metatags(self, context):
+		context.metatags = frappe._dict({})
+
+		safe_description = frappe.utils.to_markdown(self.description)
+
+		context.metatags.url = frappe.utils.get_url() + '/' + context.route
+
+		if context.website_image:
+			if context.website_image.startswith('http'):
+				url = context.website_image
+			else:
+				url = frappe.utils.get_url() + context.website_image
+			context.metatags.image = url
+
+		context.metatags.description = safe_description[:300]
+
+		context.metatags.title = self.item_name or self.item_code
+
+		context.metatags['og:type'] = 'product'
+		context.metatags['og:site_name'] = 'ERPNext'
+
+	def set_shopping_cart_data(self, context):
+		from erpnext.shopping_cart.product_info import get_product_info_for_website
+		context.shopping_cart = get_product_info_for_website(self.name)
+
 	def add_default_uom_in_conversion_factor_table(self):
 		uom_conv_list = [d.uom for d in self.get("uoms")]
 		if self.stock_uom not in uom_conv_list:
@@ -533,7 +564,7 @@
 				warehouse += [d.get("warehouse")]
 			else:
 				frappe.throw(_("Row {0}: An Reorder entry already exists for this warehouse {1}")
-                                    .format(d.idx, d.warehouse), DuplicateReorderRows)
+									.format(d.idx, d.warehouse), DuplicateReorderRows)
 
 			if d.warehouse_reorder_level and not d.warehouse_reorder_qty:
 				frappe.throw(_("Row #{0}: Please set reorder quantity").format(d.idx))
@@ -553,7 +584,7 @@
 	def update_item_price(self):
 		frappe.db.sql("""update `tabItem Price` set item_name=%s,
 			item_description=%s, brand=%s where item_code=%s""",
-                    (self.item_name, self.description, self.brand, self.name))
+					(self.item_name, self.description, self.brand, self.name))
 
 	def on_trash(self):
 		super(Item, self).on_trash()
@@ -575,7 +606,7 @@
 			new_properties = [cstr(d) for d in frappe.db.get_value("Item", new_name, field_list)]
 			if new_properties != [cstr(self.get(fld)) for fld in field_list]:
 				frappe.throw(_("To merge, following properties must be same for both items")
-                                    + ": \n" + ", ".join([self.meta.get_label(fld) for fld in field_list]))
+									+ ": \n" + ", ".join([self.meta.get_label(fld) for fld in field_list]))
 
 	def after_rename(self, old_name, new_name, merge):
 		if self.route:
@@ -598,7 +629,7 @@
 					item_wise_tax_detail.pop(old_name)
 
 					frappe.db.set_value(dt, d.name, "item_wise_tax_detail",
-                                            json.dumps(item_wise_tax_detail), update_modified=False)
+											json.dumps(item_wise_tax_detail), update_modified=False)
 
 	def set_last_purchase_rate(self, new_name):
 		last_purchase_rate = get_last_purchase_details(new_name).get("base_rate", 0)
@@ -626,7 +657,7 @@
 		self.set("website_specifications", [])
 		if self.item_group:
 			for label, desc in frappe.db.get_values("Item Website Specification",
-                                           {"parent": self.item_group}, ["label", "description"]):
+										   {"parent": self.item_group}, ["label", "description"]):
 				row = self.append("website_specifications")
 				row.label = label
 				row.description = desc
@@ -700,7 +731,7 @@
 
 	def update_variants(self):
 		if self.flags.dont_update_variants or \
-                        frappe.db.get_single_value('Item Variant Settings', 'do_not_update_variants'):
+						frappe.db.get_single_value('Item Variant Settings', 'do_not_update_variants'):
 			return
 		if self.has_variants:
 			variants = frappe.db.get_all("Item", fields=["item_code"], filters={"variant_of": self.name})
@@ -751,7 +782,7 @@
 			template_uom = frappe.db.get_value("Item", self.variant_of, "stock_uom")
 			if template_uom != self.stock_uom:
 				frappe.throw(_("Default Unit of Measure for Variant '{0}' must be same as in Template '{1}'")
-                                    .format(self.stock_uom, template_uom))
+									.format(self.stock_uom, template_uom))
 
 	def validate_uom_conversion_factor(self):
 		if self.uoms:
@@ -783,10 +814,14 @@
 			variant = get_variant(self.variant_of, args, self.name)
 			if variant:
 				frappe.throw(_("Item variant {0} exists with same attributes")
-                                    .format(variant), ItemVariantExistsError)
+									.format(variant), ItemVariantExistsError)
 
 			validate_item_variant_attributes(self, args)
 
+			# copy variant_of value for each attribute row
+			for d in self.attributes:
+				d.variant_of = self.variant_of
+
 
 def get_timeline_data(doctype, name):
 	'''returns timeline data based on stock ledger entry'''
@@ -866,18 +901,18 @@
 		limit 1""", (item_code, cstr(doc_name)), as_dict=1)
 
 	purchase_order_date = getdate(last_purchase_order and last_purchase_order[0].transaction_date
-                               or "1900-01-01")
+							   or "1900-01-01")
 	purchase_receipt_date = getdate(last_purchase_receipt and
-                                 last_purchase_receipt[0].posting_date or "1900-01-01")
+								 last_purchase_receipt[0].posting_date or "1900-01-01")
 
 	if (purchase_order_date > purchase_receipt_date) or \
-                (last_purchase_order and not last_purchase_receipt):
+				(last_purchase_order and not last_purchase_receipt):
 		# use purchase order
 		last_purchase = last_purchase_order[0]
 		purchase_date = purchase_order_date
 
 	elif (purchase_receipt_date > purchase_order_date) or \
-                (last_purchase_receipt and not last_purchase_order):
+				(last_purchase_receipt and not last_purchase_order):
 		# use purchase receipt
 		last_purchase = last_purchase_receipt[0]
 		purchase_date = purchase_receipt_date
@@ -907,7 +942,7 @@
 	invalidate_cache_for(doc, doc.item_group)
 
 	website_item_groups = list(set((doc.get("old_website_item_groups") or [])
-                                + [d.item_group for d in doc.get({"doctype": "Website Item Group"}) if d.item_group]))
+								+ [d.item_group for d in doc.get({"doctype": "Website Item Group"}) if d.item_group]))
 
 	for item_group in website_item_groups:
 		invalidate_cache_for(doc, item_group)
@@ -915,6 +950,22 @@
 	if doc.get("old_item_group") and doc.get("old_item_group") != doc.item_group:
 		invalidate_cache_for(doc, doc.old_item_group)
 
+	invalidate_item_variants_cache_for_website(doc)
+
+
+def invalidate_item_variants_cache_for_website(doc):
+	from erpnext.portal.product_configurator.item_variants_cache import ItemVariantsCacheManager
+
+	item_code = None
+	if doc.has_variants and doc.show_in_website:
+		item_code = doc.name
+	elif doc.variant_of and frappe.db.get_value('Item', doc.variant_of, 'show_in_website'):
+		item_code = doc.variant_of
+
+	if item_code:
+		item_cache = ItemVariantsCacheManager(item_code)
+		item_cache.clear_cache()
+
 
 def check_stock_uom_with_bin(item, stock_uom):
 	if stock_uom == frappe.db.get_value("Item", item, "stock_uom"):
@@ -922,7 +973,7 @@
 
 	matched = True
 	ref_uom = frappe.db.get_value("Stock Ledger Entry",
-                               {"item_code": item}, "stock_uom")
+							   {"item_code": item}, "stock_uom")
 
 	if ref_uom:
 		if cstr(ref_uom) != cstr(stock_uom):
@@ -931,7 +982,7 @@
 		bin_list = frappe.db.sql("select * from tabBin where item_code=%s", item, as_dict=1)
 		for bin in bin_list:
 			if (bin.reserved_qty > 0 or bin.ordered_qty > 0 or bin.indented_qty > 0
-                                or bin.planned_qty > 0) and cstr(bin.stock_uom) != cstr(stock_uom):
+								or bin.planned_qty > 0) and cstr(bin.stock_uom) != cstr(stock_uom):
 				matched = False
 				break
 
diff --git a/erpnext/stock/doctype/item/test_records.json b/erpnext/stock/doctype/item/test_records.json
index b09a3c0..6c1a559 100644
--- a/erpnext/stock/doctype/item/test_records.json
+++ b/erpnext/stock/doctype/item/test_records.json
@@ -309,7 +309,8 @@
        "warehouse_reorder_level": 20,
        "warehouse_reorder_qty": 20
       }
-  ]
+  ],
+  "show_in_website": 1
  },
  {
   "description": "_Test Item 1",
diff --git a/erpnext/stock/doctype/item_attribute/item_attribute.js b/erpnext/stock/doctype/item_attribute/item_attribute.js
new file mode 100644
index 0000000..f253e22
--- /dev/null
+++ b/erpnext/stock/doctype/item_attribute/item_attribute.js
@@ -0,0 +1,6 @@
+// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Item Attribute', {
+
+});
diff --git a/erpnext/stock/doctype/item_attribute/item_attribute.json b/erpnext/stock/doctype/item_attribute/item_attribute.json
index 4b23cf0..2fbff4e 100644
--- a/erpnext/stock/doctype/item_attribute/item_attribute.json
+++ b/erpnext/stock/doctype/item_attribute/item_attribute.json
@@ -1,212 +1,294 @@
 {
  "allow_copy": 0, 
+ "allow_events_in_timeline": 0, 
+ "allow_guest_to_view": 0, 
  "allow_import": 1, 
  "allow_rename": 1, 
  "autoname": "field:attribute_name", 
+ "beta": 0, 
  "creation": "2014-09-26 03:49:54.899170", 
  "custom": 0, 
  "docstatus": 0, 
  "doctype": "DocType", 
  "document_type": "Setup", 
+ "editable_grid": 0, 
  "fields": [
   {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
+   "columns": 0, 
    "fieldname": "attribute_name", 
    "fieldtype": "Data", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
    "in_filter": 0, 
+   "in_global_search": 0, 
    "in_list_view": 1, 
+   "in_standard_filter": 0, 
    "label": "Attribute Name", 
    "length": 0, 
    "no_copy": 0, 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
    "read_only": 0, 
+   "remember_last_selected_value": 0, 
    "report_hide": 0, 
    "reqd": 1, 
    "search_index": 0, 
    "set_only_once": 0, 
-   "unique": 0
+   "translatable": 0, 
+   "unique": 1
   }, 
   {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
+   "columns": 0, 
    "default": "0", 
    "fieldname": "numeric_values", 
    "fieldtype": "Check", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
    "in_filter": 0, 
+   "in_global_search": 0, 
    "in_list_view": 0, 
+   "in_standard_filter": 0, 
    "label": "Numeric Values", 
    "length": 0, 
    "no_copy": 0, 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
    "read_only": 0, 
+   "remember_last_selected_value": 0, 
    "report_hide": 0, 
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
+   "columns": 0, 
    "depends_on": "numeric_values", 
    "fieldname": "section_break_4", 
    "fieldtype": "Section Break", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
    "in_filter": 0, 
+   "in_global_search": 0, 
    "in_list_view": 0, 
+   "in_standard_filter": 0, 
    "length": 0, 
    "no_copy": 0, 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
    "read_only": 0, 
+   "remember_last_selected_value": 0, 
    "report_hide": 0, 
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
+   "columns": 0, 
    "depends_on": "", 
    "fieldname": "from_range", 
    "fieldtype": "Float", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
    "in_filter": 0, 
+   "in_global_search": 0, 
    "in_list_view": 0, 
+   "in_standard_filter": 0, 
    "label": "From Range", 
    "length": 0, 
    "no_copy": 0, 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
    "read_only": 0, 
+   "remember_last_selected_value": 0, 
    "report_hide": 0, 
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
+   "columns": 0, 
    "depends_on": "", 
    "fieldname": "increment", 
    "fieldtype": "Float", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
    "in_filter": 0, 
+   "in_global_search": 0, 
    "in_list_view": 0, 
+   "in_standard_filter": 0, 
    "label": "Increment", 
    "length": 0, 
    "no_copy": 0, 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
    "read_only": 0, 
+   "remember_last_selected_value": 0, 
    "report_hide": 0, 
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
+   "columns": 0, 
    "fieldname": "column_break_8", 
    "fieldtype": "Column Break", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
    "in_filter": 0, 
+   "in_global_search": 0, 
    "in_list_view": 0, 
+   "in_standard_filter": 0, 
    "length": 0, 
    "no_copy": 0, 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
    "read_only": 0, 
+   "remember_last_selected_value": 0, 
    "report_hide": 0, 
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
+   "columns": 0, 
    "depends_on": "", 
    "fieldname": "to_range", 
    "fieldtype": "Float", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
    "in_filter": 0, 
+   "in_global_search": 0, 
    "in_list_view": 0, 
+   "in_standard_filter": 0, 
    "label": "To Range", 
    "length": 0, 
    "no_copy": 0, 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
    "read_only": 0, 
+   "remember_last_selected_value": 0, 
    "report_hide": 0, 
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
+   "columns": 0, 
    "depends_on": "eval: !doc.numeric_values", 
    "fieldname": "section_break_5", 
    "fieldtype": "Section Break", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
    "in_filter": 0, 
+   "in_global_search": 0, 
    "in_list_view": 0, 
+   "in_standard_filter": 0, 
    "length": 0, 
    "no_copy": 0, 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
    "read_only": 0, 
+   "remember_last_selected_value": 0, 
    "report_hide": 0, 
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
+   "columns": 0, 
    "depends_on": "", 
    "fieldname": "item_attribute_values", 
    "fieldtype": "Table", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
    "in_filter": 0, 
+   "in_global_search": 0, 
    "in_list_view": 0, 
+   "in_standard_filter": 0, 
    "label": "Item Attribute Values", 
    "length": 0, 
    "no_copy": 0, 
@@ -214,24 +296,29 @@
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
    "read_only": 0, 
+   "remember_last_selected_value": 0, 
    "report_hide": 0, 
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }
  ], 
+ "has_web_view": 0, 
  "hide_heading": 0, 
  "hide_toolbar": 0, 
  "icon": "fa fa-edit", 
+ "idx": 0, 
+ "image_view": 0, 
  "in_create": 0, 
-
  "is_submittable": 0, 
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2015-11-16 06:29:48.198647", 
+ "modified": "2019-01-01 13:17:46.524806", 
  "modified_by": "Administrator", 
  "module": "Stock", 
  "name": "Item Attribute", 
@@ -240,7 +327,6 @@
  "permissions": [
   {
    "amend": 0, 
-   "apply_user_permissions": 0, 
    "cancel": 0, 
    "create": 1, 
    "delete": 1, 
@@ -259,8 +345,13 @@
    "write": 1
   }
  ], 
+ "quick_entry": 0, 
  "read_only": 0, 
  "read_only_onload": 0, 
+ "show_name_in_global_search": 0, 
  "sort_field": "modified", 
- "sort_order": "DESC"
+ "sort_order": "DESC", 
+ "track_changes": 1, 
+ "track_seen": 0, 
+ "track_views": 0
 }
\ No newline at end of file
diff --git a/erpnext/stock/doctype/item_variant_attribute/item_variant_attribute.json b/erpnext/stock/doctype/item_variant_attribute/item_variant_attribute.json
index 1e55580..6d02ea9 100644
--- a/erpnext/stock/doctype/item_variant_attribute/item_variant_attribute.json
+++ b/erpnext/stock/doctype/item_variant_attribute/item_variant_attribute.json
@@ -1,5 +1,6 @@
 {
  "allow_copy": 0, 
+ "allow_events_in_timeline": 0, 
  "allow_guest_to_view": 0, 
  "allow_import": 0, 
  "allow_rename": 0, 
@@ -14,6 +15,40 @@
  "fields": [
   {
    "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "variant_of", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Variant Of", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Item", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -41,10 +76,12 @@
    "reqd": 1, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
    "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -70,10 +107,12 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
    "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -102,10 +141,12 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
    "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -133,10 +174,12 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
    "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -163,10 +206,12 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
    "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -194,10 +239,12 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
    "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -225,10 +272,12 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
    "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -254,10 +303,12 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }, 
   {
    "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -285,6 +336,7 @@
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
+   "translatable": 0, 
    "unique": 0
   }
  ], 
@@ -299,7 +351,7 @@
  "issingle": 0, 
  "istable": 1, 
  "max_attachments": 0, 
- "modified": "2017-12-11 11:26:25.126350", 
+ "modified": "2019-01-03 15:36:59.129006", 
  "modified_by": "Administrator", 
  "module": "Stock", 
  "name": "Item Variant Attribute", 
@@ -313,5 +365,6 @@
  "sort_field": "modified", 
  "sort_order": "DESC", 
  "track_changes": 0, 
- "track_seen": 0
+ "track_seen": 0, 
+ "track_views": 0
 }
\ No newline at end of file
diff --git a/erpnext/templates/generators/item.html b/erpnext/templates/generators/item.html
deleted file mode 100644
index b258bde..0000000
--- a/erpnext/templates/generators/item.html
+++ /dev/null
@@ -1,143 +0,0 @@
-{% extends "templates/web.html" %}
-
-{% block title %} {{ title }} {% endblock %}
-
-{% block breadcrumbs %}
-	{% include "templates/includes/breadcrumbs.html" %}
-{% endblock %}
-
-{% block page_content %}
-{% from "erpnext/templates/includes/macros.html" import product_image %}
-<div class="item-content">
-	<div class="product-page-content" itemscope itemtype="http://schema.org/Product">
-		<div class="row">
-			<div class="row">
-				{% if slideshow %}
-				{% set slideshow_items = frappe.get_list(doctype="Website Slideshow Item",  fields=["image"], filters={ "parent": doc.slideshow }) %}
-				<div class="col-md-1">
-				{%- for slideshow_item in slideshow_items -%}
-					{% set image_src = slideshow_item['image'] %}
-					{% if image_src %}
-					<div class="item-alternative-image border">
-						<img src="{{ image_src }}" height="50" weight="50" />
-					</div>
-					{% endif %}
-				{% endfor %}
-				</div>
-				<div class="col-md-5">
-					<div class="item-image">
-						{% set first_image = slideshow_items[0]['image'] %}
-						{{ product_image(first_image, "product-full-image") }}
-					</div>
-				</div>
-				{% else %}
-				<div class="col-md-6">
-					{{ product_image(website_image, "product-full-image") }}
-				</div>
-				{% endif %}
-				<div class="col-sm-6">
-					<h2 itemprop="name">{{ item_name }}</h2>
-					<p class="text-muted">
-						{{ _("Item Code") }}: <span itemprop="productID">{{ variant and variant.name or name }}</span>
-					</p>
-					<br>
-					<div class="item-attribute-selectors">
-						{% if has_variants and attributes %}
-
-						{% for d in attributes %}
-						{% if attribute_values[d.attribute] -%}
-						<div class="item-view-attribute {% if (attribute_values[d.attribute] | len)==1 -%} hidden {%- endif %}"
-								style="margin-bottom: 10px;">
-							<h6 class="text-muted">{{ _(d.attribute) }}</h6>
-							<select class="form-control"
-								style="max-width: 140px"
-								data-attribute="{{ d.attribute }}">
-							{% for value in attribute_values[d.attribute] %}
-							<option value="{{ value }}"
-							{% if selected_attributes and selected_attributes[d.attribute]==value -%}
-								selected
-							{%- elif disabled_attributes and value in disabled_attributes.get(d.attribute, []) -%}
-								disabled
-							{%- endif %}>
-								{{ _(value) }}
-							</option>
-							{% endfor %}
-							</select>
-						</div>
-						{%- endif %}
-						{% endfor %}
-
-						{% endif %}
-					</div>
-					<br>
-					<div>
-						<div itemprop="offers" itemscope itemtype="http://schema.org/Offer">
-							<h4 class="item-price hide" itemprop="price"></h4>
-							<div class="item-stock hide" itemprop="availability"></div>
-						</div>
-						<div class="item-cart hide">
-							<div id="item-spinner">
-								<span style="display: inline-block">
-									<div class="input-group number-spinner">
-										<span class="input-group-btn">
-											<button class="btn btn-default cart-btn" data-dir="dwn">
-												–</button>
-										</span>
-										<input class="form-control text-right cart-qty" value="1">
-										<span class="input-group-btn">
-											<button class="btn btn-default cart-btn" data-dir="up" style="margin-left:-2px;">
-											+</button>
-										</span>
-									</div>
-								</span>
-							</div>
-							<div id="item-add-to-cart">
-								<button class="btn btn-primary btn-sm">
-									{{ _("Add to Cart") }}</button>
-							</div>
-							<div id="item-update-cart" style="display: none;">
-								<a href="/cart" class='btn btn-sm btn-default'>
-									<i class='octicon octicon-check'></i>
-									{{ _("View in Cart") }}</a>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			<div class="row item-website-description margin-top">
-				<div class="col-md-12">
-					<div class="h6 text-uppercase">{{ _("Description") }}</div>
-					<div itemprop="description" class="item-desc">
-					{{ web_long_description or description or _("No description given") }}
-					</div>
-				</div>
-			</div>
-			{% if website_specifications -%}
-			<div class="row item-website-specification margin-top">
-				<div class="col-md-12">
-					<div class="h6 text-uppercase">{{ _("Specifications") }}</div>
-
-					<table class="table">
-					{% for d in website_specifications -%}
-						<tr>
-							<td class="text-muted" style="width: 30%;">{{ d.label }}</td>
-							<td>{{ d.description }}</td>
-						</tr>
-					{%- endfor %}
-					</table>
-				</div>
-			</div>
-			{%- endif %}
-		</div>
-	</div>
-</div>
-<script>
-	{% include "templates/includes/product_page.js" %}
-
-	{% if variant_info %}
-	window.variant_info = {{ variant_info }};
-	{% else %}
-	window.variant_info = null;
-	{% endif %}
-</script>
-{% endblock %}
diff --git a/erpnext/templates/generators/item/item.html b/erpnext/templates/generators/item/item.html
new file mode 100644
index 0000000..d3691a6
--- /dev/null
+++ b/erpnext/templates/generators/item/item.html
@@ -0,0 +1,32 @@
+{% extends "templates/web.html" %}
+
+{% block title %} {{ title }} {% endblock %}
+
+{% block breadcrumbs %}
+	{% include "templates/includes/breadcrumbs.html" %}
+{% endblock %}
+
+{% block page_content %}
+{% from "erpnext/templates/includes/macros.html" import product_image %}
+<div class="item-content">
+	<div class="product-page-content" itemscope itemtype="http://schema.org/Product">
+		<div class="row mb-5">
+			{% include "templates/generators/item/item_image.html" %}
+			{% include "templates/generators/item/item_details.html" %}
+		</div>
+
+		{% include "templates/generators/item/item_specifications.html" %}
+
+		{{ doc.website_content or '' }}
+	</div>
+</div>
+{% endblock %}
+
+{% block base_scripts %}
+<!-- js should be loaded in body! -->
+<script type="text/javascript" src="/assets/frappe/js/lib/jquery/jquery.min.js"></script>
+<script type="text/javascript" src="/assets/js/frappe-web.min.js"></script>
+<script type="text/javascript" src="/assets/js/control.min.js"></script>
+<script type="text/javascript" src="/assets/js/dialog.min.js"></script>
+<script type="text/javascript" src="/assets/js/bootstrap-4-web.min.js"></script>
+{% endblock %}
\ No newline at end of file
diff --git a/erpnext/templates/generators/item/item_add_to_cart.html b/erpnext/templates/generators/item/item_add_to_cart.html
new file mode 100644
index 0000000..f4a31a7
--- /dev/null
+++ b/erpnext/templates/generators/item/item_add_to_cart.html
@@ -0,0 +1,67 @@
+{% if shopping_cart and shopping_cart.cart_settings.enabled %}
+
+{% set cart_settings = shopping_cart.cart_settings %}
+{% set product_info = shopping_cart.product_info %}
+
+<div class="item-cart row mt-2" data-variant-item-code="{{ item_code }}">
+	<div class="col-md-12">
+		{% if cart_settings.show_price and product_info.price %}
+		<h4>
+			{{ product_info.price.formatted_price_sales_uom }}
+			<small class="text-muted">({{ product_info.price.formatted_price }} / {{ product_info.uom }})</small>
+		</h4>
+		{% endif %}
+		{% if cart_settings.show_stock_availability %}
+		<div>
+			{% if product_info.in_stock == 0 %}
+			<span class="text-danger">
+				{{ _('Not in stock') }}
+			</span>
+			{% elif product_info.in_stock == 1 %}
+			<span class="text-success">
+				{{ _('In stock') }}
+				{% if product_info.show_stock_qty and product_info.stock_qty %}
+					({{ product_info.stock_qty[0][0] }})
+				{% endif %}
+			</span>
+			{% endif %}
+		</div>
+		{% endif %}
+		<div class="mt-3">
+			<a href="/cart"
+				class="btn btn-light btn-view-in-cart {% if not product_info.qty %}hidden{% endif %}"
+				role="button"
+			>
+				{{ _("View in Cart") }}
+			</a>
+			<button
+				data-item-code="{{item_code}}"
+				class="btn btn-outline-primary btn-add-to-cart {% if product_info.qty %}hidden{% endif %}"
+			>
+				{{ _("Add to Cart") }}
+			</button>
+		</div>
+	</div>
+</div>
+
+<script>
+	frappe.ready(() => {
+		$('.page_content').on('click', '.btn-add-to-cart', (e) => {
+			const $btn = $(e.currentTarget);
+			$btn.prop('disabled', true);
+			const item_code = $btn.data('item-code');
+			erpnext.shopping_cart.update_cart({
+				item_code,
+				qty: 1,
+				callback(r) {
+					$btn.prop('disabled', false);
+					if (r.message) {
+						$('.btn-add-to-cart, .btn-view-in-cart').toggleClass('hidden');
+					}
+				}
+			});
+		});
+	});
+</script>
+
+{% endif %}
\ No newline at end of file
diff --git a/erpnext/templates/generators/item/item_configure.html b/erpnext/templates/generators/item/item_configure.html
new file mode 100644
index 0000000..04f89ec
--- /dev/null
+++ b/erpnext/templates/generators/item/item_configure.html
@@ -0,0 +1,23 @@
+{% if shopping_cart and shopping_cart.cart_settings.enabled %}
+{% set cart_settings = shopping_cart.cart_settings %}
+
+<div class="mt-3">
+	{% if cart_settings.show_configure_button | int %}
+	<button class="btn btn-primary btn-configure"
+		data-item-code="{{ doc.name }}"
+		data-item-name="{{ doc.item_name }}"
+	>
+		{{ _('Configure') }}
+	</button>
+	{% endif %}
+	{% if cart_settings.show_contact_us_button | int %}
+	<button class="btn btn-link btn-inquiry" data-item-code="{{ doc.name }}">
+		{{ _('Contact Us') }}
+	</button>
+	{% endif %}
+</div>
+<script>
+{% include "templates/generators/item/item_configure.js" %}
+{% include "templates/generators/item/item_inquiry.js" %}
+</script>
+{% endif %}
diff --git a/erpnext/templates/generators/item/item_configure.js b/erpnext/templates/generators/item/item_configure.js
new file mode 100644
index 0000000..5fd9011
--- /dev/null
+++ b/erpnext/templates/generators/item/item_configure.js
@@ -0,0 +1,318 @@
+class ItemConfigure {
+	constructor(item_code, item_name) {
+		this.item_code = item_code;
+		this.item_name = item_name;
+
+		this.get_attributes_and_values()
+			.then(attribute_data => {
+				this.attribute_data = attribute_data;
+				this.show_configure_dialog();
+			});
+	}
+
+	show_configure_dialog() {
+		const fields = this.attribute_data.map(a => {
+			return {
+				fieldtype: 'Select',
+				label: a.attribute,
+				fieldname: a.attribute,
+				options: a.values.map(v => {
+					return {
+						label: v,
+						value: v
+					};
+				}),
+				change: (e) => {
+					this.on_attribute_selection(e);
+				}
+			};
+		});
+
+		this.dialog = new frappe.ui.Dialog({
+			title: __('Configure {0}', [this.item_name]),
+			fields,
+			on_hide: () => {
+				set_continue_configuration();
+			}
+		});
+
+		this.attribute_data.forEach(a => {
+			const field = this.dialog.get_field(a.attribute);
+			const $a = $(`<a href>${__("Clear")}</a>`);
+			$a.on('click', (e) => {
+				e.preventDefault();
+				this.dialog.set_value(a.attribute, '');
+			});
+			field.$wrapper.find('.help-box').append($a);
+		});
+
+		this.append_status_area();
+		this.dialog.show();
+
+		this.dialog.set_values(JSON.parse(localStorage.getItem(this.get_cache_key())));
+
+		$('.btn-configure').prop('disabled', false);
+	}
+
+	on_attribute_selection(e) {
+		if (e) {
+			const changed_fieldname = $(e.target).data('fieldname');
+			this.show_range_input_if_applicable(changed_fieldname);
+		} else {
+			this.show_range_input_for_all_fields();
+		}
+
+		const values = this.dialog.get_values();
+		if (Object.keys(values).length === 0) {
+			this.clear_status();
+			localStorage.removeItem(this.get_cache_key());
+			return;
+		}
+
+		// save state
+		localStorage.setItem(this.get_cache_key(), JSON.stringify(values));
+
+		// show
+		this.set_loading_status();
+
+		this.get_next_attribute_and_values(values)
+			.then(data => {
+				const {
+					valid_options_for_attributes,
+				} = data;
+
+				this.set_item_found_status(data);
+
+				for (let attribute in valid_options_for_attributes) {
+					const valid_options = valid_options_for_attributes[attribute];
+					const options = this.dialog.get_field(attribute).df.options;
+					const new_options = options.map(o => {
+						o.disabled = !valid_options.includes(o.value);
+						return o;
+					});
+
+					this.dialog.set_df_property(attribute, 'options', new_options);
+					this.dialog.get_field(attribute).set_options();
+				}
+			});
+	}
+
+	show_range_input_for_all_fields() {
+		this.dialog.fields.forEach(f => {
+			this.show_range_input_if_applicable(f.fieldname);
+		});
+	}
+
+	show_range_input_if_applicable(fieldname) {
+		const changed_field = this.dialog.get_field(fieldname);
+		const changed_value = changed_field.get_value();
+		if (changed_value && changed_value.includes(' to ')) {
+			// possible range input
+			let numbers = changed_value.split(' to ');
+			numbers = numbers.map(number => parseFloat(number));
+
+			if (!numbers.some(n => isNaN(n))) {
+				numbers.sort((a, b) => a - b);
+				if (changed_field.$input_wrapper.find('.range-selector').length) {
+					return;
+				}
+				const parent = $('<div class="range-selector">')
+					.insertBefore(changed_field.$input_wrapper.find('.help-box'));
+				const control = frappe.ui.form.make_control({
+					df: {
+						fieldtype: 'Int',
+						label: __('Enter value betweeen {0} and {1}', [numbers[0], numbers[1]]),
+						change: () => {
+							const value = control.get_value();
+							if (value < numbers[0] || value > numbers[1]) {
+								control.$wrapper.addClass('was-validated');
+								control.set_description(
+									__('Value must be between {0} and {1}', [numbers[0], numbers[1]]));
+								control.$input[0].setCustomValidity('error');
+							} else {
+								control.$wrapper.removeClass('was-validated');
+								control.set_description('');
+								control.$input[0].setCustomValidity('');
+								this.update_range_values(fieldname, value);
+							}
+						}
+					},
+					render_input: true,
+					parent
+				});
+				control.$wrapper.addClass('mt-3');
+			}
+		}
+	}
+
+	update_range_values(attribute, range_value) {
+		this.range_values = this.range_values || {};
+		this.range_values[attribute] = range_value;
+	}
+
+	show_remaining_optional_attributes() {
+		// show all attributes if remaining
+		// unselected attributes are all optional
+		const unselected_attributes = this.dialog.fields.filter(df => {
+			const value_selected = this.dialog.get_value(df.fieldname);
+			return !value_selected;
+		});
+		const is_optional_attribute = df => {
+			const optional_attributes = this.attribute_data
+				.filter(a => a.optional).map(a => a.attribute);
+			return optional_attributes.includes(df.fieldname);
+		};
+		if (unselected_attributes.every(is_optional_attribute)) {
+			unselected_attributes.forEach(df => {
+				this.dialog.fields_dict[df.fieldname].$wrapper.show();
+			});
+		}
+	}
+
+	set_loading_status() {
+		this.dialog.$status_area.html(`
+			<div class="alert alert-warning d-flex justify-content-between align-items-center" role="alert">
+				${__('Loading...')}
+			</div>
+		`);
+	}
+
+	set_item_found_status(data) {
+		const html = this.get_html_for_item_found(data);
+		this.dialog.$status_area.html(html);
+	}
+
+	clear_status() {
+		this.dialog.$status_area.empty();
+	}
+
+	get_html_for_item_found({ filtered_items_count, filtered_items, exact_match, product_info }) {
+		const exact_match_message = __('1 exact match.');
+		const one_item = exact_match.length === 1 ?
+			exact_match[0] :
+			filtered_items_count === 1 ?
+				filtered_items[0] : '';
+
+		const item_add_to_cart = one_item ? `
+			<div class="alert alert-success d-flex justify-content-between align-items-center" role="alert">
+				<div>
+					<div>${one_item} ${product_info && product_info.price ? '(' + product_info.price.formatted_price_sales_uom + ')' : ''}</div>
+				</div>
+				<a href data-action="btn_add_to_cart" data-item-code="${one_item}">
+					${__('Add to cart')}
+				</a>
+			</div>
+		`: '';
+
+		const items_found = filtered_items_count === 1 ?
+			__('{0} item found.', [filtered_items_count]) :
+			__('{0} items found.', [filtered_items_count]);
+
+		const item_found_status = `
+			<div class="alert alert-warning d-flex justify-content-between align-items-center" role="alert">
+				<span>
+					${exact_match.length === 1 ? '' : items_found}
+					${exact_match.length === 1 ? `<span>${exact_match_message}</span>` : ''}
+				</span>
+				<a href data-action="btn_clear_values">
+					${__('Clear values')}
+				</a>
+			</div>
+		`;
+
+		return `
+			${item_add_to_cart}
+			${item_found_status}
+		`;
+	}
+
+	btn_add_to_cart(e) {
+		if (frappe.session.user !== 'Guest') {
+			localStorage.removeItem(this.get_cache_key());
+		}
+		const item_code = $(e.currentTarget).data('item-code');
+		const additional_notes = Object.keys(this.range_values || {}).map(attribute => {
+			return `${attribute}: ${this.range_values[attribute]}`;
+		}).join('\n');
+		erpnext.shopping_cart.update_cart({
+			item_code,
+			additional_notes,
+			qty: 1
+		});
+		this.dialog.hide();
+	}
+
+	btn_clear_values() {
+		this.dialog.fields_list.forEach(f => {
+			f.df.options = f.df.options.map(option => {
+				option.disabled = false;
+				return option;
+			});
+		});
+		this.dialog.clear();
+		this.on_attribute_selection();
+	}
+
+	append_status_area() {
+		this.dialog.$status_area = $('<div class="status-area">');
+		this.dialog.$wrapper.find('.modal-body').prepend(this.dialog.$status_area);
+		this.dialog.$wrapper.on('click', '[data-action]', (e) => {
+			e.preventDefault();
+			const $target = $(e.currentTarget);
+			const action = $target.data('action');
+			const method = this[action];
+			method.call(this, e);
+		});
+		this.dialog.$body.css({ maxHeight: '75vh', overflow: 'auto', overflowX: 'hidden' });
+	}
+
+	get_next_attribute_and_values(selected_attributes) {
+		return this.call('erpnext.portal.product_configurator.utils.get_next_attribute_and_values', {
+			item_code: this.item_code,
+			selected_attributes
+		});
+	}
+
+	get_attributes_and_values() {
+		return this.call('erpnext.portal.product_configurator.utils.get_attributes_and_values', {
+			item_code: this.item_code
+		});
+	}
+
+	get_cache_key() {
+		return `configure:${this.item_code}`;
+	}
+
+	call(method, args) {
+		// promisified frappe.call
+		return new Promise((resolve, reject) => {
+			frappe.call(method, args)
+				.then(r => resolve(r.message))
+				.fail(reject);
+		});
+	}
+}
+
+function set_continue_configuration() {
+	const $btn_configure = $('.btn-configure');
+	const { itemCode } = $btn_configure.data();
+
+	if (localStorage.getItem(`configure:${itemCode}`)) {
+		$btn_configure.text(__('Continue Configuration'));
+	} else {
+		$btn_configure.text(__('Configure'));
+	}
+}
+
+frappe.ready(() => {
+	const $btn_configure = $('.btn-configure');
+	if (!$btn_configure.length) return;
+	const { itemCode, itemName } = $btn_configure.data();
+
+	set_continue_configuration();
+
+	$btn_configure.on('click', () => {
+		$btn_configure.prop('disabled', true);
+		new ItemConfigure(itemCode, itemName);
+	});
+});
diff --git a/erpnext/templates/generators/item/item_details.html b/erpnext/templates/generators/item/item_details.html
new file mode 100644
index 0000000..4f8f8c2
--- /dev/null
+++ b/erpnext/templates/generators/item/item_details.html
@@ -0,0 +1,22 @@
+<div class="col-md-8">
+<!-- title -->
+<h1 itemprop="name">
+	{{ item_name }}
+</h1>
+<p class="text-muted">
+	<span>{{ _("Item Code") }}:</span>
+	<span itemprop="productID">{{ doc.name }}</span>
+</p>
+<!-- description -->
+<div itemprop="description">
+	{{ doc.web_long_description or doc.description or _("No description given") | safe }}
+</div>
+
+{% if has_variants %}
+	<!-- configure template -->
+	{% include "templates/generators/item/item_configure.html" %}
+{% else %}
+	<!-- add variant to cart -->
+	{% include "templates/generators/item/item_add_to_cart.html" %}
+{% endif %}
+</div>
diff --git a/erpnext/templates/generators/item/item_image.html b/erpnext/templates/generators/item/item_image.html
new file mode 100644
index 0000000..0dd4c35
--- /dev/null
+++ b/erpnext/templates/generators/item/item_image.html
@@ -0,0 +1,107 @@
+<div class="col-md-4 h-100">
+{% if slides %}
+{{ product_image(slides[0].image, 'product-image') }}
+<div class="item-slideshow">
+	{% for item in slides %}
+	<img class="item-slideshow-image mt-2 {% if loop.first %}active{% endif %}"
+			src="{{ item.image }}" alt="{{ item.heading }}">
+	{% endfor %}
+</div>
+<!-- Simple image slideshow -->
+<script>
+	frappe.ready(() => {
+		$('.page_content').on('click', '.item-slideshow-image', (e) => {
+			const $img = $(e.currentTarget);
+			const link = $img.prop('src');
+			const $product_image = $('.product-image');
+			$product_image.find('a').prop('href', link);
+			$product_image.find('img').prop('src', link);
+
+			$('.item-slideshow-image').removeClass('active');
+			$img.addClass('active');
+		});
+	})
+</script>
+{% else %}
+{{ product_image(website_image or image or 'no-image.jpg') }}
+{% endif %}
+
+<!-- Simple image preview -->
+
+<div class="image-zoom-view" style="display: none;">
+	<button type="button" class="close" aria-label="Close">
+		<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
+		 stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-x">
+			<line x1="18" y1="6" x2="6" y2="18"></line>
+			<line x1="6" y1="6" x2="18" y2="18"></line>
+		</svg>
+	</button>
+</div>
+</div>
+<style>
+	.website-image {
+		cursor: pointer;
+	}
+
+	.image-zoom-view {
+		position: fixed;
+		top: 0;
+		left: 0;
+		right: 0;
+		bottom: 0;
+		height: 100vh;
+		width: 100vw;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		background: rgba(0, 0, 0, 0.8);
+		z-index: 1080;
+	}
+
+	.image-zoom-view img {
+		max-height: 100%;
+		max-width: 100%;
+	}
+
+	.image-zoom-view button {
+		position: absolute;
+		right: 3rem;
+		top: 2rem;
+	}
+
+	.image-zoom-view svg {
+		color: var(--white);
+	}
+</style>
+<script>
+	frappe.ready(() => {
+		const $zoom_wrapper = $('.image-zoom-view');
+
+		$('.website-image').on('click', (e) => {
+			e.preventDefault();
+			const $img = $(e.target);
+			const src = $img.prop('src');
+			if (!src) return;
+			show_preview(src);
+		});
+
+		$zoom_wrapper.on('click', 'button', hide_preview);
+
+		$(document).on('keydown', (e) => {
+			if (e.key === 'Escape') {
+				hide_preview();
+			}
+		});
+
+		function show_preview(src) {
+			$zoom_wrapper.show();
+			const $img = $(`<img src="${src}">`)
+			$zoom_wrapper.append($img);
+		}
+
+		function hide_preview() {
+			$zoom_wrapper.find('img').remove();
+			$zoom_wrapper.hide();
+		}
+	})
+</script>
diff --git a/erpnext/templates/generators/item/item_inquiry.js b/erpnext/templates/generators/item/item_inquiry.js
new file mode 100644
index 0000000..52ddae2
--- /dev/null
+++ b/erpnext/templates/generators/item/item_inquiry.js
@@ -0,0 +1,70 @@
+frappe.ready(() => {
+	const d = new frappe.ui.Dialog({
+		title: __('Contact Us'),
+		fields: [
+			{
+				fieldtype: 'Data',
+				label: __('Full Name'),
+				fieldname: 'lead_name',
+				reqd: 1
+			},
+			{
+				fieldtype: 'Data',
+				label: __('Organization Name'),
+				fieldname: 'company_name',
+			},
+			{
+				fieldtype: 'Data',
+				label: __('Email'),
+				fieldname: 'email_id',
+				options: 'Email',
+				reqd: 1
+			},
+			{
+				fieldtype: 'Data',
+				label: __('Subject'),
+				fieldname: 'subject',
+				reqd: 1
+			},
+			{
+				fieldtype: 'Text',
+				label: __('Message'),
+				fieldname: 'message',
+				reqd: 1
+			}
+		],
+		primary_action: send_inquiry,
+		primary_action_label: __('Send')
+	});
+
+	function send_inquiry() {
+		const values = d.get_values();
+		const doc = Object.assign({}, values);
+		delete doc.subject;
+		delete doc.message;
+
+		d.hide();
+
+		frappe.call('erpnext.shopping_cart.cart.create_lead_for_item_inquiry', {
+			lead: doc,
+			subject: values.subject,
+			message: values.message
+		}).then(r => {
+			if (r.message) {
+				d.clear();
+			}
+		});
+	}
+
+	$('.btn-inquiry').click((e) => {
+		const $btn = $(e.target);
+		const item_code = $btn.data('item-code');
+		d.set_value('subject', 'Inquiry about ' + item_code);
+		if (!['Administrator', 'Guest'].includes(frappe.session.user)) {
+			d.set_value('email_id', frappe.session.user);
+			d.set_value('lead_name', frappe.get_cookie('full_name'));
+		}
+
+		d.show();
+	});
+});
\ No newline at end of file
diff --git a/erpnext/templates/generators/item/item_specifications.html b/erpnext/templates/generators/item/item_specifications.html
new file mode 100644
index 0000000..a12a074
--- /dev/null
+++ b/erpnext/templates/generators/item/item_specifications.html
@@ -0,0 +1,16 @@
+{% if doc.website_specifications -%}
+<div class="row item-website-specification mt-5">
+	<div class="col-md-12">
+		<h6 class="text-uppercase text-muted">{{ _("Specifications") }}</h6>
+
+		<table class="table table-bordered">
+		{% for d in doc.website_specifications -%}
+			<tr>
+				<td class="text-muted" style="width: 30%;">{{ d.label }}</td>
+				<td>{{ d.description }}</td>
+			</tr>
+		{%- endfor %}
+		</table>
+	</div>
+</div>
+{%- endif %}
\ No newline at end of file
diff --git a/erpnext/templates/generators/item_group.html b/erpnext/templates/generators/item_group.html
index cf8aa15..3f98453 100644
--- a/erpnext/templates/generators/item_group.html
+++ b/erpnext/templates/generators/item_group.html
@@ -9,29 +9,32 @@
 		{% include "templates/includes/slideshow.html" %}
 		{% endif %}
 		{% if description %}<!-- description -->
-		<div itemprop="description">{{ description or ""}}</div>
+		<div class="mb-3" itemprop="description">{{ description or ""}}</div>
 		{% endif %}
 	</div>
-	<div>
-		{% if items %}
-		<div id="search-list" {% if not products_as_list -%} class="row" {%- endif %}>
-			{% for i in range(0, page_length) %}
-				{% if items[i] %}
-					{{ items[i] }}
+	<div class="row">
+		<div class="col-md-8">
+			{% if items %}
+			<div id="search-list">
+				{% for i in range(0, page_length) %}
+					{% if items[i] %}
+						{%- set item = items[i] %}
+						{% include "erpnext/www/all-products/item_row.html" %}
+					{% endif %}
+				{% endfor %}
+			</div>
+			<div class="item-group-nav-buttons">
+				{% if frappe.form_dict.start|int > 0 %}
+				<a class="btn btn-outline-secondary" href="/{{ pathname }}?start={{ frappe.form_dict.start|int - page_length }}">{{ _("Prev") }}</a>
 				{% endif %}
-			{% endfor %}
-		</div>
-		<div class="text-center item-group-nav-buttons">
-			{% if frappe.form_dict.start|int > 0 %}
-			<a class="btn btn-default" href="/{{ pathname }}?start={{ frappe.form_dict.start|int - page_length }}">{{ _("Prev") }}</a>
-			{% endif %}
-			{% if items|length > page_length %}
-			<a class="btn btn-default" href="/{{ pathname }}?start={{ frappe.form_dict.start|int + page_length }}">{{ _("Next") }}</a>
-			{% endif %}
-		</div>
-		{% else %}
+				{% if items|length > page_length %}
+				<a class="btn btn-outline-secondary" href="/{{ pathname }}?start={{ frappe.form_dict.start|int + page_length }}">{{ _("Next") }}</a>
+				{% endif %}
+			</div>
+			{% else %}
 			<div class="text-muted">{{ _("No items listed") }}.</div>
-		{% endif %}
+			{% endif %}
+		</div>
 	</div>
 </div>
 {% endblock %}
\ No newline at end of file
diff --git a/erpnext/templates/includes/address_row.html b/erpnext/templates/includes/address_row.html
index bfc035a..dadd2df 100644
--- a/erpnext/templates/includes/address_row.html
+++ b/erpnext/templates/includes/address_row.html
@@ -1,12 +1,12 @@
-<div class="web-list-item">
-    <a href="/addresses?name={{ doc.name | urlencode }}" class="no-decoration">
+<div class="web-list-item mb-3">
+    <a href="/addresses?name={{ doc.name | urlencode }}" class="no-underline text-reset">
 	    <div class="row">
-	        <div class="col-xs-3">
+	        <div class="col-3">
 	                 <span class="indicator {{ "red" if doc.address_type=="Office" else "green" if doc.address_type=="Billing" else "blue" if doc.address_type=="Shipping" else "darkgrey" }}">{{ doc.address_title }}</span>
 			</div>
-			<div class="col-xs-2"> {{ _(doc.address_type) }} </div>
-			<div class="col-xs-2"> {{ doc.city }} </div>
-			<div class="col-xs-5 text-right small text-muted">
+			<div class="col-2"> {{ _(doc.address_type) }} </div>
+			<div class="col-2"> {{ doc.city }} </div>
+			<div class="col-5 text-right small text-muted">
 	            {{ frappe.get_doc(doc).get_display() }}
 	        </div>
 	    </div>
diff --git a/erpnext/templates/includes/cart.js b/erpnext/templates/includes/cart.js
index 51be954..983898b 100644
--- a/erpnext/templates/includes/cart.js
+++ b/erpnext/templates/includes/cart.js
@@ -16,41 +16,33 @@
 	bind_events: function() {
 		shopping_cart.bind_address_select();
 		shopping_cart.bind_place_order();
+		shopping_cart.bind_request_quotation();
 		shopping_cart.bind_change_qty();
+		shopping_cart.bind_change_notes();
 		shopping_cart.bind_dropdown_cart_buttons();
 	},
 
 	bind_address_select: function() {
-		$(".cart-addresses").find('input[data-address-name]').on("click", function() {
-			if($(this).prop("checked")) {
-				var me = this;
+		$(".cart-addresses").on('click', '.address-card', function(e) {
+			const $card = $(e.currentTarget);
+			const address_fieldname = $card.closest('[data-fieldname]').attr('data-fieldname');
+			const address_name = $card.closest('[data-address-name]').attr('data-address-name');
 
-				// uncheck other shipping or billing addresses:
-				if ( $(this).is('input[data-fieldname=customer_address]') ) {
-					$('input[data-fieldname=customer_address]').not(this).prop('checked', false);
-				} else {
-					$('input[data-fieldname=shipping_address_name]').not(this).prop('checked', false);
-				}
-
-				return frappe.call({
-					type: "POST",
-					method: "erpnext.shopping_cart.cart.update_cart_address",
-					freeze: true,
-					args: {
-						address_fieldname: $(this).attr("data-fieldname"),
-						address_name: $(this).attr("data-address-name")
-					},
-					callback: function(r) {
-						if(!r.exc) {
-							$(".cart-tax-items").html(r.message.taxes);
-						}
+			return frappe.call({
+				type: "POST",
+				method: "erpnext.shopping_cart.cart.update_cart_address",
+				freeze: true,
+				args: {
+					address_fieldname,
+					address_name
+				},
+				callback: function(r) {
+					if(!r.exc) {
+						$(".cart-tax-items").html(r.message.taxes);
 					}
-				});
-			} else {
-				return false;
-			}
+				}
+			});
 		});
-
 	},
 
 	bind_place_order: function() {
@@ -59,12 +51,18 @@
 		});
 	},
 
+	bind_request_quotation: function() {
+		$('.btn-request-for-quotation').on('click', function() {
+			shopping_cart.request_quotation(this);
+		});
+	},
+
 	bind_change_qty: function() {
 		// bind update button
 		$(".cart-items").on("change", ".cart-qty", function() {
 			var item_code = $(this).attr("data-item-code");
 			var newVal = $(this).val();
-			shopping_cart.shopping_cart_update(item_code, newVal);
+			shopping_cart.shopping_cart_update({item_code, qty: newVal});
 		});
 
 		$(".cart-items").on('click', '.number-spinner button', function () {
@@ -82,7 +80,21 @@
 			}
 			input.val(newVal);
 			var item_code = input.attr("data-item-code");
-			shopping_cart.shopping_cart_update(item_code, newVal);
+			shopping_cart.shopping_cart_update({item_code, qty: newVal});
+		});
+	},
+
+	bind_change_notes: function() {
+		$('.cart-items').on('change', 'textarea', function() {
+			const $textarea = $(this);
+			const item_code = $textarea.attr('data-item-code');
+			const qty = $textarea.closest('tr').find('.cart-qty').val();
+			const notes = $textarea.val();
+			shopping_cart.shopping_cart_update({
+				item_code,
+				qty,
+				additional_notes: notes
+			});
 		});
 	},
 
@@ -150,7 +162,32 @@
 						.html(msg || frappe._("Something went wrong!"))
 						.toggle(true);
 				} else {
-					window.location.href = "/orders/" + encodeURIComponent(r.message);
+					window.open('/orders/' + encodeURIComponent(r.message), '_blank');
+					window.location.reload();
+				}
+			}
+		});
+	},
+
+	request_quotation: function(btn) {
+		return frappe.call({
+			type: "POST",
+			method: "erpnext.shopping_cart.cart.request_for_quotation",
+			btn: btn,
+			callback: function(r) {
+				if(r.exc) {
+					var msg = "";
+					if(r._server_messages) {
+						msg = JSON.parse(r._server_messages || []).join("<br>");
+					}
+
+					$("#cart-error")
+						.empty()
+						.html(msg || frappe._("Something went wrong!"))
+						.toggle(true);
+				} else {
+					window.open('/printview?doctype=Quotation&name=' + r.message, '_blank');
+					window.location.reload();
 				}
 			}
 		});
diff --git a/erpnext/templates/includes/cart/address_card.html b/erpnext/templates/includes/cart/address_card.html
new file mode 100644
index 0000000..c91723e
--- /dev/null
+++ b/erpnext/templates/includes/cart/address_card.html
@@ -0,0 +1,12 @@
+<div class="card address-card h-100">
+	<div class="check" style="position: absolute; right: 15px; top: 15px;">
+		<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check"><polyline points="20 6 9 17 4 12"></polyline></svg>
+	</div>
+	<div class="card-body">
+		<h5 class="card-title">{{ address.name }}</h5>
+		<p class="card-text text-muted">
+			{{ address.display }}
+		</p>
+		<a href="/addresses?name={{address.name}}" class="card-link">{{ _('Edit') }}</a>
+	</div>
+</div>
diff --git a/erpnext/templates/includes/cart/cart_address.html b/erpnext/templates/includes/cart/cart_address.html
index 7bd9256..2c90f8c 100644
--- a/erpnext/templates/includes/cart/cart_address.html
+++ b/erpnext/templates/includes/cart/cart_address.html
@@ -1,26 +1,141 @@
 {% from "erpnext/templates/includes/cart/cart_macros.html" import show_address %}
-<div class="row">
-	{% if addresses|length == 1%}
-		{% set select_address = True %}
-	{% endif %}
-	<div class="col-sm-6">
-		<div class="h6 text-uppercase">{{ _("Shipping Address") }}</div>
-		<div id="cart-shipping-address" class="panel-group"
-			data-fieldname="shipping_address_name">
-            {% for address in shipping_addresses %}
-                {{ show_address(address, doc, "shipping_address_name", select_address) }}
-            {% endfor %}
-        </div>
-		<a class="btn btn-default btn-sm" href="/addresses">
-			{{ _("Manage Addresses") }}</a>
-	</div>
-	<div class="col-sm-6">
-        <div class="h6 text-uppercase">{{ _("Billing Address") }}</div>
-		<div id="cart-billing-address" class="panel-group"
-			data-fieldname="customer_address">
-            {% for address in billing_addresses %}
-                {{ show_address(address, doc, "customer_address", select_address) }}
-            {% endfor %}
-        </div>
+
+{% if addresses | length == 1%}
+	{% set select_address = True %}
+{% endif %}
+
+<div class="mb-3" data-section="shipping-address">
+	<h6 class="text-uppercase">{{ _("Shipping Address") }}</h6>
+	<div class="row no-gutters" data-fieldname="shipping_address_name">
+		{% for address in shipping_addresses %}
+			<div class="mr-3 mb-3 w-25" data-address-name="{{address.name}}" {% if doc.shipping_address_name == address.name %} data-active {% endif %}>
+				{% include "templates/includes/cart/address_card.html" %}
+			</div>
+		{% endfor %}
 	</div>
 </div>
+<div class="mb-3" data-section="billing-address">
+	<h6 class="text-uppercase">{{ _("Billing Address") }}</h6>
+	<div class="row no-gutters" data-fieldname="customer_address">
+		{% for address in billing_addresses %}
+			<div class="mr-3 mb-3 w-25" data-address-name="{{address.name}}" {% if doc.customer_address == address.name %} data-active {% endif %}>
+				{% include "templates/includes/cart/address_card.html" %}
+			</div>
+		{% endfor %}
+	</div>
+</div>
+<div class="custom-control custom-checkbox">
+	<input type="checkbox" class="custom-control-input" id="input_same_billing" checked>
+	<label class="custom-control-label" for="input_same_billing">{{ _('Billing Address is same as Shipping Address') }}</label>
+</div>
+<button class="btn btn-outline-primary btn-sm mt-3 btn-new-address">{{ _("Add a new address") }}</button>
+
+<script>
+frappe.ready(() => {
+	$(document).on('click', '.address-card', (e) => {
+		const $target = $(e.currentTarget);
+		const $section = $target.closest('[data-section]');
+		$section.find('.address-card').removeClass('active');
+		$target.addClass('active');
+	});
+
+	$('#input_same_billing').change((e) => {
+		const $check = $(e.target);
+		toggle_billing_address_section(!$check.is(':checked'));
+	});
+
+	$('.btn-new-address').click(() => {
+		const d = new frappe.ui.Dialog({
+			title: __('New Address'),
+			fields: [
+				{
+					label: __('Address Title'),
+					fieldname: 'address_title',
+					fieldtype: 'Data',
+					reqd: 1
+				},
+				{
+					label: __('Address Type'),
+					fieldname: 'address_type',
+					fieldtype: 'Select',
+					options: [
+						'Billing',
+						'Shipping'
+					],
+					reqd: 1
+				},
+				{
+					label: __('Address Line 1'),
+					fieldname: 'address_line1',
+					fieldtype: 'Data',
+					reqd: 1
+				},
+				{
+					label: __('Address Line 2'),
+					fieldname: 'address_line2',
+					fieldtype: 'Data'
+				},
+				{
+					label: __('City/Town'),
+					fieldname: 'city',
+					fieldtype: 'Data',
+					reqd: 1
+				},
+				{
+					label: __('State'),
+					fieldname: 'state',
+					fieldtype: 'Data'
+				},
+				{
+					label: __('Pin Code'),
+					fieldname: 'pincode',
+					fieldtype: 'Data'
+				},
+				{
+					label: __('Country'),
+					fieldname: 'country',
+					fieldtype: 'Data',
+					reqd: 1
+				},
+			],
+			primary_action_label: __('Save'),
+			primary_action: (values) => {
+				frappe.call('erpnext.shopping_cart.cart.add_new_address', { doc: values })
+					.then(r => {
+						d.hide();
+						window.location.reload();
+					});
+			}
+		})
+
+		d.show();
+	});
+
+	function setup_state() {
+		const shipping_address = $('[data-section="shipping-address"]')
+			.find('[data-address-name][data-active]').attr('data-address-name');
+
+		const billing_address = $('[data-section="billing-address"]')
+			.find('[data-address-name][data-active]').attr('data-address-name');
+
+		$('#input_same_billing').prop('checked', shipping_address === billing_address).trigger('change');
+
+		if (!shipping_address && !billing_address) {
+			$('#input_same_billing').prop('checked', true).trigger('change');
+		}
+
+		if (shipping_address) {
+			$(`[data-section="shipping-address"] [data-address-name="${shipping_address}"] .address-card`).addClass('active');
+		}
+		if (billing_address) {
+			$(`[data-section="billing-address"] [data-address-name="${billing_address}"] .address-card`).addClass('active');
+		}
+	}
+
+	setup_state();
+
+	function toggle_billing_address_section(flag) {
+		$('[data-section="billing-address"]').toggle(flag);
+	}
+});
+</script>
diff --git a/erpnext/templates/includes/cart/cart_items.html b/erpnext/templates/includes/cart/cart_items.html
index 65b81d9..ca5744b 100644
--- a/erpnext/templates/includes/cart/cart_items.html
+++ b/erpnext/templates/includes/cart/cart_items.html
@@ -1,31 +1,42 @@
-{% from "erpnext/templates/includes/order/order_macros.html" import item_name_and_description %}
-{% from "erpnext/templates/includes/order/order_macros.html" import item_name_and_description_cart %}
-
 {% for d in doc.items %}
-<div class="row checkout">
-    <div class="col-sm-8 col-xs-6 col-name-description">
-        {{ item_name_and_description(d) }}
-    </div>
-    <div class="col-sm-2 col-xs-3 text-right col-qty">
-        <span style="display: inline-block">
-			<div class="input-group number-spinner">
-                <span class="input-group-btn">
-                    <button class="btn btn-default cart-btn" data-dir="dwn">
-                        –</button>
-                </span>
-            <input class="form-control text-right cart-qty"
-            value = "{{ d.get_formatted('qty') }}"
-            data-item-code="{{ d.item_code }}">
-                <span class="input-group-btn">
-                    <button class="btn btn-default cart-btn" data-dir="up" style="margin-left:-2px;">
-                        +</button>
-                </span>
-			</div>
+<tr data-name="{{ d.name }}">
+	<td>
+		<div class="font-weight-bold">
+			{{ d.item_name }}
+		</div>
+		<div>
+			{{ d.item_code }}
+		</div>
+		{%- set variant_of = frappe.db.get_value('Item', d.item_code, 'variant_of') %}
+		{% if variant_of %}
+		<span class="text-muted">
+			{{ _('Variant of') }} <a href="{{frappe.db.get_value('Item', variant_of, 'route')}}">{{ variant_of }}</a>
 		</span>
-	</div>
-    <div class="col-sm-2 col-xs-3 text-right col-amount">
-        {{ d.get_formatted("amount") }}
-        <p class="text-muted small item-rate">{{ _("Rate") }}&nbsp;{{ d.get_formatted("rate") }}</p>
-    </div>
-</div>
-{% endfor %}
\ No newline at end of file
+		{% endif %}
+		<div class="mt-2">
+			<textarea data-item-code="{{d.item_code}}" class="form-control" rows="2" placeholder="{{ _('Add notes') }}">{{d.additional_notes or ''}}</textarea>
+		</div>
+	</td>
+	<td class="text-right">
+		<div class="input-group number-spinner">
+			<span class="input-group-prepend d-none d-sm-inline-block">
+				<button class="btn btn-outline-secondary cart-btn" data-dir="dwn">–</button>
+			</span>
+			<input class="form-control text-right cart-qty border-secondary" value="{{ d.get_formatted('qty') }}" data-item-code="{{ d.item_code }}">
+			<span class="input-group-append d-none d-sm-inline-block">
+				<button class="btn btn-outline-secondary cart-btn" data-dir="up">+</button>
+			</span>
+		</div>
+	</td>
+	{% if cart_settings.enable_checkout %}
+	<td class="text-right">
+		<div>
+			{{ d.get_formatted('amount') }}
+		</div>
+		<span class="text-muted">
+			{{ _('Rate:') }} {{ d.get_formatted('rate') }}
+		</span>
+	</td>
+	{% endif %}
+</tr>
+{% endfor %}
diff --git a/erpnext/templates/includes/footer/footer_extension.html b/erpnext/templates/includes/footer/footer_extension.html
index 23a6a34..8cf3081 100644
--- a/erpnext/templates/includes/footer/footer_extension.html
+++ b/erpnext/templates/includes/footer/footer_extension.html
@@ -1,11 +1,14 @@
 {% if not hide_footer_signup %}
-<div class='input-group input-group-sm pull-right footer-subscribe'>
-	<input class="form-control" type="text" id="footer-subscribe-email"
-		placeholder="{{ _('Your email address') }}...">
-	<span class='input-group-btn'>
-		<button class="btn btn-default" type="button"
-			id="footer-subscribe-button">{{ _("Get Updates") }}</button>
-	</span>
+<div class="input-group">
+	<input type="text" class="form-control border-secondary"
+		id="footer-subscribe-email"
+		placeholder="{{ _('Your email address...') }}"
+		aria-label="{{ _('Your email address...') }}"
+		aria-describedby="footer-subscribe-button">
+	<div class="input-group-append">
+		<button class="btn btn-outline-secondary"
+			type="button" id="footer-subscribe-button">{{ _("Get Updates") }}</button>
+	</div>
 </div>
 
 <script>
diff --git a/erpnext/templates/includes/footer/footer_powered.html b/erpnext/templates/includes/footer/footer_powered.html
index e9d5f56..faf5e92 100644
--- a/erpnext/templates/includes/footer/footer_powered.html
+++ b/erpnext/templates/includes/footer/footer_powered.html
@@ -1,2 +1 @@
-<a href="https://erpnext.com?source=website_footer" target="_blank" class="text-muted">
-		Powered by ERPNext</a>
+<a href="https://erpnext.com?source=website_footer" target="_blank" class="text-muted">Powered by ERPNext</a>
diff --git a/erpnext/templates/includes/macros.html b/erpnext/templates/includes/macros.html
index 863d48e..2d27915 100644
--- a/erpnext/templates/includes/macros.html
+++ b/erpnext/templates/includes/macros.html
@@ -1,7 +1,4 @@
 {% macro product_image_square(website_image, css_class="") %}
-{% if website_image -%}
-	<meta itemprop="image" content="{{ frappe.utils.quoted(website_image) | abs_url }}"></meta>
-{%- endif %}
 <div class="product-image product-image-square
 	{% if not website_image -%} missing-image {%- endif %} {{ css_class }}"
 	{% if website_image -%}
@@ -11,12 +8,8 @@
 {% endmacro %}
 
 {% macro product_image(website_image, css_class="") %}
-    <div class="product-image {% if not website_image -%} missing-image {%- endif %} {{ css_class }}">
-    	{% if website_image -%}
-			<a href="{{ frappe.utils.quoted(website_image) }}">
-				<img itemprop="image" src="{{ frappe.utils.quoted(website_image) | abs_url }}" class="img-responsive">
-			</a>
-    	{%- endif %}
+    <div class="border text-center rounded h-100 {{ css_class }}" style="overflow: hidden;">
+		<img itemprop="image" class="website-image h-100 w-100" src="{{ frappe.utils.quoted(website_image or 'no-image.jpg') | abs_url }}">
     </div>
 {% endmacro %}
 
@@ -33,3 +26,35 @@
     	{%- endif %}
     </div>
 {% endmacro %}
+
+{% macro render_homepage_section(section) %}
+
+{% if section.section_based_on == 'Custom HTML' and section.section_html %}
+	{{ section.section_html }}
+{% elif section.section_based_on == 'Cards' %}
+<section class="container my-5">
+	<h3>{{ section.name }}</h3>
+
+	<div class="row">
+		{% for card in section.section_cards %}
+		<div class="col-md-{{ section.column_value }} mb-4">
+			<div class="card h-100 justify-content-between">
+				{% if card.image %}
+				<div class="website-image-lazy" data-class="card-img-top h-100" data-src="{{ card.image }}" data-alt="{{ card.title }}"></div>
+				{% endif %}
+				<div class="card-body">
+					<h5 class="card-title">{{ card.title }}</h5>
+					<p class="card-subtitle mb-2 text-muted">{{ card.subtitle or '' }}</p>
+					<p class="card-text">{{ card.content | truncate(140, True) }}</p>
+				</div>
+				<div class="card-body flex-grow-0">
+					<a href="{{ card.route }}" class="card-link">{{ _('More details') }}</a>
+				</div>
+			</div>
+		</div>
+		{% endfor %}
+	</div>
+</section>
+{% endif %}
+
+{% endmacro %}
\ No newline at end of file
diff --git a/erpnext/templates/includes/navbar/navbar_items.html b/erpnext/templates/includes/navbar/navbar_items.html
index faf8adf..4daf0e7 100644
--- a/erpnext/templates/includes/navbar/navbar_items.html
+++ b/erpnext/templates/includes/navbar/navbar_items.html
@@ -1,12 +1,10 @@
 {% extends 'frappe/templates/includes/navbar/navbar_items.html' %}
 
 {% block navbar_right_extension %}
-	<li class="shopping-cart hidden">
-		<div class="cart-icon">
-			<a class="dropdown-toggle" href="#" data-toggle="dropdown" id="navLogin">
-				{{ _("Cart") }} <span class="badge-wrapper" id="cart-count"></span>
-			</a>
-			<div id="cart-overlay" class="dropdown-menu shopping-cart-menu"></div>
-		</div>
+	<li class="shopping-cart cart-icon hidden">
+		<a href="/cart" class="nav-link">
+			{{ _("Cart") }}
+			<span class="badge badge-primary" id="cart-count"></span>
+		</a>
 	 </li>
 {% endblock %}
\ No newline at end of file
diff --git a/erpnext/templates/includes/order/order_macros.html b/erpnext/templates/includes/order/order_macros.html
index c2dff8c..da4fb8c 100644
--- a/erpnext/templates/includes/order/order_macros.html
+++ b/erpnext/templates/includes/order/order_macros.html
@@ -9,7 +9,9 @@
         </div>
         <div class="col-xs-8 col-sm-10">
             {{ d.item_code }}
-            <div class="text-muted small item-description">{{ d.description }}</div>
+            <div class="text-muted small item-description">
+				{{ html2text(d.description) | truncate(140) }}
+			</div>
         </div>
     </div>
 {% endmacro %}
@@ -25,14 +27,14 @@
            {{ d.item_name|truncate(25) }}
 			<div class="input-group number-spinner">
                 <span class="input-group-btn">
-                    <button class="btn btn-default cart-btn" data-dir="dwn">
+                    <button class="btn btn-light cart-btn" data-dir="dwn">
                         –</button>
                 </span>
 	            <input class="form-control text-right cart-qty"
 		            value = "{{ d.get_formatted('qty') }}"
 		            data-item-code="{{ d.item_code }}">
                 <span class="input-group-btn">
-                    <button class="btn btn-default cart-btn" data-dir="up">
+                    <button class="btn btn-light cart-btn" data-dir="up">
                         +</button>
                 </span>
 			</div>
diff --git a/erpnext/templates/includes/order/order_taxes.html b/erpnext/templates/includes/order/order_taxes.html
index 462d77d..1d26700 100644
--- a/erpnext/templates/includes/order/order_taxes.html
+++ b/erpnext/templates/includes/order/order_taxes.html
@@ -1,24 +1,32 @@
 {% if doc.taxes %}
-<div class="row tax-net-total-row">
-    <div class="col-xs-6 text-right">{{ _("Net Total") }}</div>
-    <div class="col-xs-6 text-right">
-        {{ doc.get_formatted("net_total") }}</div>
-</div>
+<tr>
+	<td class="text-right" colspan="2">
+		{{ _("Net Total") }}
+	</td>
+	<td class="text-right">
+		{{ doc.get_formatted("net_total") }}
+	</td>
+</tr>
 {% endif %}
+
 {% for d in doc.taxes %}
 {% if d.base_tax_amount > 0 %}
-<div class="row tax-row">
-    <div class="col-xs-6 text-right">{{ d.description }}</div>
-    <div class="col-xs-6 text-right">
-        {{ d.get_formatted("base_tax_amount") }}</div>
-</div>
+<tr>
+	<td class="text-right" colspan="2">
+		{{ d.description }}
+	</td>
+	<td class="text-right">
+		{{ d.get_formatted("base_tax_amount") }}
+	</td>
+</tr>
 {% endif %}
 {% endfor %}
-<div class="row tax-grand-total-row">
-    <div class="col-xs-6 text-right text-uppercase h6 text-muted">{{ _("Grand Total") }}</div>
-    <div class="col-xs-6 text-right">
-        <span class="tax-grand-total bold">
-            {{ doc.get_formatted("grand_total") }}
-        </span>
-    </div>
-</div>
+
+<tr>
+	<th class="text-right" colspan="2">
+		{{ _("Grand Total") }}
+	</th>
+	<th class="text-right">
+		{{ doc.get_formatted("grand_total") }}
+	</th>
+</tr>
diff --git a/erpnext/templates/includes/product_page.js b/erpnext/templates/includes/product_page.js
deleted file mode 100644
index ef69e20..0000000
--- a/erpnext/templates/includes/product_page.js
+++ /dev/null
@@ -1,215 +0,0 @@
-// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-// License: GNU General Public License v3. See license.txt
-
-frappe.ready(function() {
-	window.item_code = $('[itemscope] [itemprop="productID"]').text().trim();
-	var qty = 0;
-
-	frappe.call({
-		type: "POST",
-		method: "erpnext.shopping_cart.product_info.get_product_info_for_website",
-		args: {
-			item_code: get_item_code()
-		},
-		callback: function(r) {
-			if(r.message) {
-				if(r.message.cart_settings.enabled) {
-					$(".item-cart, .item-price, .item-stock").toggleClass("hide", (!!!r.message.product_info.price || !!!r.message.product_info.in_stock));
-				}
-				if(r.message.cart_settings.show_price) {
-					$(".item-price").toggleClass("hide", false);
-				}
-				if(r.message.cart_settings.show_stock_availability) {
-					$(".item-stock").toggleClass("hide", false);
-				}
-				if(r.message.product_info.price) {
-					$(".item-price")
-						.html(r.message.product_info.price.formatted_price_sales_uom + "<div style='font-size: small'>\
-							(" + r.message.product_info.price.formatted_price + " / " + r.message.product_info.uom + ")</div>");
-
-					if(r.message.product_info.in_stock==0) {
-						$(".item-stock").html("<div style='color: red'> <i class='fa fa-close'></i> {{ _("Not in stock") }}</div>");
-					}
-					else if(r.message.product_info.in_stock==1) {
-						var qty_display = "{{ _("In stock") }}";
-						if (r.message.product_info.show_stock_qty) {
-							qty_display += " ("+r.message.product_info.stock_qty+")";
-						}
-						$(".item-stock").html("<div style='color: green'>\
-							<i class='fa fa-check'></i> "+qty_display+"</div>");
-					}
-
-					if(r.message.product_info.qty) {
-						qty = r.message.product_info.qty;
-						toggle_update_cart(r.message.product_info.qty);
-					} else {
-						toggle_update_cart(0);
-					}
-				}
-			}
-		}
-	})
-
-	$("#item-add-to-cart button").on("click", function() {
-		frappe.provide('erpnext.shopping_cart');
-
-		erpnext.shopping_cart.update_cart({
-			item_code: get_item_code(),
-			qty: $("#item-spinner .cart-qty").val(),
-			callback: function(r) {
-				if(!r.exc) {
-					toggle_update_cart(1);
-					qty = 1;
-				}
-			},
-			btn: this,
-		});
-	});
-
-	$("#item-spinner").on('click', '.number-spinner button', function () {
-		var btn = $(this),
-			input = btn.closest('.number-spinner').find('input'),
-			oldValue = input.val().trim(),
-			newVal = 0;
-
-		if (btn.attr('data-dir') == 'up') {
-			newVal = parseInt(oldValue) + 1;
-		} else if (btn.attr('data-dir') == 'dwn')  {
-			if (parseInt(oldValue) > 1) {
-				newVal = parseInt(oldValue) - 1;
-			}
-			else {
-				newVal = parseInt(oldValue);
-			}
-		}
-		input.val(newVal);
-	});
-
-	$("[itemscope] .item-view-attribute .form-control").on("change", function() {
-		try {
-			var item_code = encodeURIComponent(get_item_code());
-
-		} catch(e) {
-			// unable to find variant
-			// then chose the closest available one
-
-			var attribute = $(this).attr("data-attribute");
-			var attribute_value = $(this).val();
-			var item_code = find_closest_match(attribute, attribute_value);
-
-			if (!item_code) {
-				frappe.msgprint(__("Cannot find a matching Item. Please select some other value for {0}.", [attribute]))
-				throw e;
-			}
-		}
-
-		if (window.location.search == ("?variant=" + item_code) || window.location.search.includes(item_code)) {
-			return;
-		}
-
-		window.location.href = window.location.pathname + "?variant=" + item_code;
-	});
-
-	// change the item image src when alternate images are hovered
-	$(document.body).on('mouseover', '.item-alternative-image', (e) => {
-		const $alternative_image = $(e.currentTarget);
-		const src = $alternative_image.find('img').prop('src');
-		$('.item-image img').prop('src', src);
-	});
-});
-
-var toggle_update_cart = function(qty) {
-	$("#item-add-to-cart").toggle(qty ? false : true);
-	$("#item-update-cart")
-		.toggle(qty ? true : false)
-		.find("input").val(qty);
-	$("#item-spinner").toggle(qty ? false : true);
-}
-
-function get_item_code() {
-	var variant_info = window.variant_info;
-	if(variant_info) {
-		var attributes = get_selected_attributes();
-		var no_of_attributes = Object.keys(attributes).length;
-
-		for(var i in variant_info) {
-			var variant = variant_info[i];
-
-			if (variant.attributes.length < no_of_attributes) {
-				// the case when variant has less attributes than template
-				continue;
-			}
-
-			var match = true;
-			for(var j in variant.attributes) {
-				if(attributes[variant.attributes[j].attribute]
-					!= variant.attributes[j].attribute_value
-				) {
-					match = false;
-					break;
-				}
-			}
-			if(match) {
-				return variant.name;
-			}
-		}
-		throw "Unable to match variant";
-	} else {
-		return window.item_code;
-	}
-}
-
-function find_closest_match(selected_attribute, selected_attribute_value) {
-	// find the closest match keeping the selected attribute in focus and get the item code
-
-	var attributes = get_selected_attributes();
-
-	var previous_match_score = 0;
-	var previous_no_of_attributes = 0;
-	var matched;
-
-	var variant_info = window.variant_info;
-	for(var i in variant_info) {
-		var variant = variant_info[i];
-		var match_score = 0;
-		var has_selected_attribute = false;
-
-		for(var j in variant.attributes) {
-			if(attributes[variant.attributes[j].attribute]===variant.attributes[j].attribute_value) {
-				match_score = match_score + 1;
-
-				if (variant.attributes[j].attribute==selected_attribute && variant.attributes[j].attribute_value==selected_attribute_value) {
-					has_selected_attribute = true;
-				}
-			}
-		}
-
-		if (has_selected_attribute
-			&& ((match_score > previous_match_score) || (match_score==previous_match_score && previous_no_of_attributes < variant.attributes.length))) {
-			previous_match_score = match_score;
-			matched = variant;
-			previous_no_of_attributes = variant.attributes.length;
-
-
-		}
-	}
-
-	if (matched) {
-		for (var j in matched.attributes) {
-			var attr = matched.attributes[j];
-			$('[itemscope]')
-				.find(repl('.item-view-attribute .form-control[data-attribute="%(attribute)s"]', attr))
-				.val(attr.attribute_value);
-		}
-
-		return matched.name;
-	}
-}
-
-function get_selected_attributes() {
-	var attributes = {};
-	$('[itemscope]').find(".item-view-attribute .form-control").each(function() {
-		attributes[$(this).attr('data-attribute')] = $(this).val();
-	});
-	return attributes;
-}
diff --git a/erpnext/templates/pages/cart.html b/erpnext/templates/pages/cart.html
index fb0c05f..b301fc0 100644
--- a/erpnext/templates/pages/cart.html
+++ b/erpnext/templates/pages/cart.html
@@ -2,18 +2,25 @@
 
 {% block title %} {{ _("Shopping Cart") }} {% endblock %}
 
-{% block header %}<h2>{{ _("My Cart") }}</h2>{% endblock %}
+{% block header %}<h1>{{ _("Shopping Cart") }}</h1>{% endblock %}
 
+<!--
 {% block script %}
 <script>{% include "templates/includes/cart.js" %}</script>
 {% endblock %}
+-->
 
 
 {% block header_actions %}
-{% if doc.items %}
-<button class="btn btn-primary btn-place-order btn-sm"
-    type="button">
-    {{ _("Place Order") }}</button>
+{% if doc.items and cart_settings.enable_checkout %}
+<button class="btn btn-primary btn-place-order" type="button">
+	{{ _("Place Order") }}
+</button>
+{% endif %}
+{% if doc.items and not cart_settings.enable_checkout %}
+<button class="btn btn-primary btn-request-for-quotation" type="button">
+	{{ _("Request for Quotation") }}
+</button>
 {% endif %}
 {% endblock %}
 
@@ -22,58 +29,89 @@
 {% from "templates/includes/macros.html" import item_name_and_description %}
 
 <div class="cart-container">
-	<div id="cart-container">
-			<div id="cart-error" class="alert alert-danger"
-		style="display: none;"></div>
-		<div id="cart-items">
-			<div class="row cart-item-header text-muted">
-				<div class="col-sm-8 col-xs-6 h6 text-uppercase">
-				{{ _("Item") }}
-				</div>
-				<div class="col-sm-2 col-xs-3 text-center h6 text-uppercase">
-				{{ _("Qty") }}
-				</div>
-				<div class="col-sm-2 col-xs-3 text-right h6 text-uppercase">
-				{{ _("Subtotal") }}
-				</div>
-			</div>
-			{% if doc.items %}
-				<div class="cart-items">
-					{% include "templates/includes/cart/cart_items.html" %}
-				</div>
-			{% else %}
-				<p class="empty-cart">{{ _("Cart is Empty") }}</p>
-			{% endif %}
-		</div>
-		{% if doc.items %}
-		<!-- taxes -->
-		<div class="row cart-taxes">
-			<div class="col-sm-6"><!-- empty --></div>
-			<div class="col-sm-6 text-right cart-tax-items">
+	<div id="cart-error" class="alert alert-danger" style="display: none;"></div>
+
+	{% if doc.items %}
+	<table class="table table-bordered mt-3">
+		<thead>
+			<tr>
+				<th width="60%">{{ _('Item') }}</th>
+				<th width="20%" class="text-right">{{ _('Quantity') }}</th>
+				{% if cart_settings.enable_checkout %}
+				<th width="20%" class="text-right">{{ _('Subtotal') }}</th>
+				{% endif %}
+			</tr>
+		</thead>
+		<tbody class="cart-items">
+			{% include "templates/includes/cart/cart_items.html" %}
+		</tbody>
+		{% if cart_settings.enable_checkout %}
+		<tfoot class="cart-tax-items">
 			{% include "templates/includes/order/order_taxes.html" %}
-			</div>
-		</div>
-
-		{% if doc.tc_name %}
-			<div class="cart-terms" style="display: none;" title={{doc.tc_name}}>
-				{{doc.tc_name}}
-				{{doc.terms}}
-			</div>
-			<div class="cart-link">
-				<a href="#" onclick="show_terms();return false;">*{{ __("Terms and Conditions") }}</a>
-			</div>
+		</tfoot>
 		{% endif %}
+	</table>
+	{% else %}
+	<p class="text-muted">{{ _('Your cart is Empty') }}</p>
+	{% endif %}
 
-		<div class="cart-addresses">
-		{% include "templates/includes/cart/cart_address.html" %}
+	{% if doc.items %}
+	{% if doc.tc_name %}
+		<div class="terms-and-conditions-link">
+			<a href class="link-terms-and-conditions" data-terms-name="{{ doc.tc_name }}">
+				{{ _("Terms and Conditions") }}
+			</a>
+			<script>
+				frappe.ready(() => {
+					$('.link-terms-and-conditions').click((e) => {
+						e.preventDefault();
+						const $link = $(e.target);
+						const terms_name = $link.attr('data-terms-name');
+						show_terms_and_conditions(terms_name);
+					})
+				});
+				function show_terms_and_conditions(terms_name) {
+					frappe.call('erpnext.shopping_cart.cart.get_terms_and_conditions', { terms_name })
+					.then(r => {
+						frappe.msgprint({
+							title: terms_name,
+							message: r.message
+						});
+					});
+				}
+			</script>
 		</div>
+	{% endif %}
 
-		<p class="cart-footer text-right">
-		<button class="btn btn-primary btn-place-order btn-sm" type="button">
-		{{ _("Place Order") }}</button></p>
+	{% if cart_settings.enable_checkout %}
+	<div class="cart-addresses mt-5">
+	{% include "templates/includes/cart/cart_address.html" %}
+	</div>
+	{% endif %}
+	{% endif %}
+</div>
+
+<div class="row mt-5">
+	<div class="col-12">
+		{% if cart_settings.enable_checkout %}
+		<a href="/orders">
+			{{ _('See past orders') }}
+		</a>
+		{% else %}
+		<a href="/quotations">
+			{{ _('See past quotations') }}
+		</a>
 		{% endif %}
 	</div>
 </div>
 
+{% endblock %}
 
+{% block base_scripts %}
+<!-- js should be loaded in body! -->
+<script type="text/javascript" src="/assets/frappe/js/lib/jquery/jquery.min.js"></script>
+<script type="text/javascript" src="/assets/js/frappe-web.min.js"></script>
+<script type="text/javascript" src="/assets/js/control.min.js"></script>
+<script type="text/javascript" src="/assets/js/dialog.min.js"></script>
+<script type="text/javascript" src="/assets/js/bootstrap-4-web.min.js"></script>
 {% endblock %}
diff --git a/erpnext/templates/pages/help.html b/erpnext/templates/pages/help.html
index 8c26852..1cfe358 100644
--- a/erpnext/templates/pages/help.html
+++ b/erpnext/templates/pages/help.html
@@ -11,7 +11,7 @@
 		value='{{ frappe.form_dict.q or ''}}'
 		{% if not frappe.form_dict.q%}placeholder="{{ _("What do you need help with?") }}"{% endif %}>
 	<input type='submit'
-		class='btn btn-sm btn-default btn-search' value="{{ _("Search") }}">
+		class='btn btn-sm btn-light btn-search' value="{{ _("Search") }}">
 	</form>
 </div>
 
diff --git a/erpnext/templates/pages/home.css b/erpnext/templates/pages/home.css
new file mode 100644
index 0000000..cf54766
--- /dev/null
+++ b/erpnext/templates/pages/home.css
@@ -0,0 +1,9 @@
+/* csslint ignore:start */
+{% if homepage.hero_image %}
+.hero-image {
+	background-image: url("{{ homepage.hero_image }}");
+	background-size: cover;
+	padding: 10rem 0;
+}
+{% endif %}
+/* csslint ignore:end */
\ No newline at end of file
diff --git a/erpnext/templates/pages/home.html b/erpnext/templates/pages/home.html
index f36b4e0..b67a465 100644
--- a/erpnext/templates/pages/home.html
+++ b/erpnext/templates/pages/home.html
@@ -1,75 +1,75 @@
 {% extends "templates/web.html" %}
-{% from "erpnext/templates/includes/macros.html" import product_image_square %}
 
-{% block page_content %}
+{% from "erpnext/templates/includes/macros.html" import render_homepage_section %}
 
-<div class="row">
-	<div class="col-sm-12">
-		<div class="hero">
-			<h1 class="text-center">{{ homepage.tag_line or '' }}</h1>
-			<p class="text-center">{{ homepage.description or '' }}</p>
+{% block content %}
+<main>
+	{% if homepage.hero_section_based_on == 'Default' %}
+	<section class="hero-section border-bottom {%if homepage.hero_image%}hero-image{%endif%}">
+		<div class="container py-5">
+			<h1 class="d-none d-sm-block display-4">{{ homepage.tag_line }}</h1>
+			<h1 class="d-block d-sm-none">{{ homepage.tag_line }}</h1>
+			<h2 class="d-none d-sm-block">{{ homepage.description }}</h2>
+			<h3 class="d-block d-sm-none">{{ homepage.description }}</h3>
 		</div>
-		{% if homepage.products %}
-		<div class='featured-products-section' itemscope itemtype="http://schema.org/Product">
-			<h5 class='featured-product-heading'>{{ _("Featured Products") }}</h5>
-			<div class="featured-products">
-				<div id="search-list" class="row" style="margin-top:40px;">
-					{% for item in homepage.products %}
-					<a class="product-link" href="{{ item.route|abs_url }}">
-						<div class="col-sm-4 col-xs-4 product-image-wrapper">
-							<div class="product-image-img">
-								<!-- thumbnail not updated, and used as background image in item card -->
-								{{ product_image_square(item.image) }}
-							<div class="product-text" itemprop="name">{{ item.item_name }}</div>
-							</div>
-						</div>
-					</a>
-					{% endfor %}
+
+		<div class="container">
+			<a href="{{ explore_link }}" class="mb-5 btn btn-primary">{{ _('Explore') }}</a>
+		</div>
+	</section>
+	{% elif homepage.hero_section_based_on == 'Slideshow' and slideshow %}
+	<section class="hero-section">
+		{% include "templates/includes/slideshow.html" %}
+	</section>
+	{% elif homepage.hero_section_based_on == 'Homepage Section' %}
+		{{ render_homepage_section(homepage.hero_section_doc) }}
+	{% endif %}
+
+	{% if homepage.products %}
+	<section class="container section-products my-5">
+		<h3>{{ _('Products') }}</h3>
+
+		<div class="row">
+			{% for item in homepage.products %}
+			<div class="col-md-4 mb-4">
+				<div class="card h-100 justify-content-between">
+					<div class="website-image-lazy" data-class="card-img-top h-100" data-src="{{ item.image }}" data-alt="{{ item.item_name }}"></div>
+					<div class="card-body flex-grow-0">
+						<h5 class="card-title">{{ item.item_name }}</h5>
+						<a href="{{ item.route }}" class="card-link">{{ _('More details') }}</a>
+					</div>
 				</div>
 			</div>
-			<div class="text-center padding">
-				<a href="{{ homepage.products_url or "/products" }}" class="btn btn-primary all-products">
-					{{ _("View All Products") }}</a></div>
+			{% endfor %}
 		</div>
-		{% endif %}
-	</div>
-</div>
-{% endblock %}
+	</section>
+	{% endif %}
 
-{% block style %}
-<style>
-	.hero {
-		padding-top: 50px;
-		padding-bottom: 100px;
-	}
+	{% if blogs %}
+	<section class="container my-5">
+		<h3>{{ _('Publications') }}</h3>
 
-	.hero h1 {
-		font-size: 40px;
-		font-weight: 200;
-	}
+		<div class="row">
+			{% for blog in blogs %}
+			<div class="col-md-4 mb-4">
+				<div class="card h-100">
+					<div class="card-body">
+						<h5 class="card-title">{{ blog.title }}</h5>
+						<p class="card-subtitle mb-2 text-muted">{{ _('By {0}').format(blog.blogger) }}</p>
+						<p class="card-text">{{ blog.blog_intro }}</p>
+					</div>
+					<div class="card-body flex-grow-0">
+						<a href="{{ blog.route }}" class="card-link">{{ _('Read blog') }}</a>
+					</div>
+				</div>
+			</div>
+			{% endfor %}
+		</div>
+	</section>
+	{% endif %}
 
-	.home-login {
-		margin-top: 30px;
-	}
-	.btn-login {
-		width: 80px;
-	}
-
-	.featured-product-heading, .all-products {
-		 text-transform: uppercase;
-		 letter-spacing: 0.5px;
-		 font-size: 12px;
-		 font-weight: 500;
-	}
-
-	.all-products {
-		 font-weight: 300;
-		 padding-left: 25px;
-		 padding-right: 25px;
-		 padding-top: 10px;
-		 padding-bottom: 10px;
-	}
-
-
-</style>
-{% endblock %}
+	{% for section in homepage_sections %}
+		{{ render_homepage_section(section) }}
+	{% endfor %}
+</main>
+{% endblock %}
\ No newline at end of file
diff --git a/erpnext/templates/pages/home.py b/erpnext/templates/pages/home.py
index 82d525a..4b688b1 100644
--- a/erpnext/templates/pages/home.py
+++ b/erpnext/templates/pages/home.py
@@ -15,15 +15,38 @@
 		if route:
 			item.route = '/' + route
 
-	context.title = homepage.title or homepage.company
-
-	# show atleast 3 products
-	if len(homepage.products) < 3:
-		for i in range(3 - len(homepage.products)):
-			homepage.append('products', {
-				'item_code': 'product-{0}'.format(i),
-				'item_name': frappe._('Product {0}').format(i),
-				'route': '#'
-			})
-
+	homepage.title = homepage.title or homepage.company
+	context.title = homepage.title
 	context.homepage = homepage
+
+	if homepage.hero_section_based_on == 'Homepage Section' and homepage.hero_section:
+		homepage.hero_section_doc = frappe.get_doc('Homepage Section', homepage.hero_section)
+
+	if homepage.slideshow:
+		doc = frappe.get_doc('Website Slideshow', homepage.slideshow)
+		context.slideshow = homepage.slideshow
+		context.slideshow_header = doc.header
+		context.slides = doc.slideshow_items
+
+	context.blogs = frappe.get_all('Blog Post',
+		fields=['title', 'blogger', 'blog_intro', 'route'],
+		filters={
+			'published': 1
+		},
+		order_by='modified desc',
+		limit=3
+	)
+
+	# filter out homepage section which is used as hero section
+	homepage_hero_section = homepage.hero_section_based_on == 'Homepage Section' and homepage.hero_section
+	homepage_sections = frappe.get_all('Homepage Section',
+		filters=[['name', '!=', homepage_hero_section]] if homepage_hero_section else None,
+		order_by='section_order asc'
+	)
+	context.homepage_sections = [frappe.get_doc('Homepage Section', name) for name in homepage_sections]
+
+	context.metatags = context.metatags or frappe._dict({})
+	context.metatags.image = homepage.hero_image or None
+	context.metatags.description = homepage.description or None
+
+	context.explore_link = '/all-products'
diff --git a/erpnext/templates/pages/material_request_info.html b/erpnext/templates/pages/material_request_info.html
index ff3bd65..9d18989 100644
--- a/erpnext/templates/pages/material_request_info.html
+++ b/erpnext/templates/pages/material_request_info.html
@@ -12,7 +12,7 @@
 {% endblock %}
 
 {% block header_actions %}
-<a class='btn btn-xs btn-default' href='/printview?doctype={{ doc.doctype}}&name={{ doc.name }}&format={{ print_format }}' target="_blank" rel="noopener noreferrer">{{ _("Print") }}</a>
+<a class='btn btn-xs btn-light' href='/printview?doctype={{ doc.doctype}}&name={{ doc.name }}&format={{ print_format }}' target="_blank" rel="noopener noreferrer">{{ _("Print") }}</a>
 {% endblock %}
 
 {% block page_content %}
@@ -70,5 +70,5 @@
 		{% endif %}
 		{% endfor %}
 	</div>
-</div>	
+</div>
 {% endblock %}
\ No newline at end of file
diff --git a/erpnext/templates/pages/non_profit/leave-chapter.html b/erpnext/templates/pages/non_profit/leave-chapter.html
index 009c7af..bc4242f 100644
--- a/erpnext/templates/pages/non_profit/leave-chapter.html
+++ b/erpnext/templates/pages/non_profit/leave-chapter.html
@@ -9,7 +9,7 @@
 					<label for="leave">Why do you want to leave this chapter</label>
 					<input type="text" name="leave" class="form-control" id="leave">
 				</div>
-				<button type="button" class="btn btn-default btn-leave" data-title= "{{ chapter.name }}" id="btn-leave">Submit
+				<button type="button" class="btn btn-light btn-leave" data-title= "{{ chapter.name }}" id="btn-leave">Submit
 				</button>
 			</form>
 		</div>
diff --git a/erpnext/templates/pages/order.html b/erpnext/templates/pages/order.html
index 64fd32a..67a8fed 100644
--- a/erpnext/templates/pages/order.html
+++ b/erpnext/templates/pages/order.html
@@ -8,23 +8,22 @@
 {% block title %}{{ doc.name }}{% endblock %}
 
 {% block header %}
-	<h1>{{ doc.name }}</h1>
+	<h1 class="m-0">{{ doc.name }}</h1>
 {% endblock %}
 
 {% block header_actions %}
-<a class='btn btn-xs btn-default' href='/printview?doctype={{ doc.doctype}}&name={{ doc.name }}&format={{ print_format }}' target="_blank" rel="noopener noreferrer">{{ _("Print") }}</a>
+<a href='/printview?doctype={{ doc.doctype}}&name={{ doc.name }}&format={{ print_format }}' target="_blank" rel="noopener noreferrer">{{ _("Print") }}</a>
 {% endblock %}
 
 {% block page_content %}
 
 <div class="row transaction-subheading">
-	<div class="col-xs-6">
-
+	<div class="col-6">
 		<span class="indicator {{ doc.indicator_color or ("blue" if doc.docstatus==1 else "darkgrey") }}">
 			{{ _(doc.get('indicator_title')) or _(doc.status) or _("Submitted") }}
 		</span>
 	</div>
-	<div class="col-xs-6 text-muted text-right small">
+	<div class="col-6 text-muted text-right small">
 		{{ frappe.utils.formatdate(doc.transaction_date, 'medium') }}
 		{% if doc.valid_till %}
 		<p>
@@ -34,16 +33,14 @@
 	</div>
 </div>
 
-<p class='small' style='padding-top: 15px;'>
-{% if doc.doctype == 'Supplier Quotation' %}
-	<b>{{ doc.supplier_name}}</b>
-{% else %}
-	<b>{{ doc.customer_name}}</b>
-{% endif %}
-{% if doc.contact_display %}
-	<br>
-	{{ doc.contact_display }}
-{% endif %}
+<p class="small my-3">
+	{%- set party_name = doc.supplier_name if doc.doctype == 'Supplier Quotation' else doc.customer_name %}
+	<b>{{ party_name }}</b>
+
+	{% if doc.contact_display and doc.contact_display != party_name %}
+		<br>
+		{{ doc.contact_display }}
+	{% endif %}
 </p>
 
 {% if doc._header %}
@@ -55,7 +52,7 @@
 	<!-- items -->
 	<div class="order-item-table">
 		<div class="row order-items order-item-header text-muted">
-			<div class="col-sm-6 col-xs-6 h6 text-uppercase">
+			<div class="col-sm-6 col-6 h6 text-uppercase">
 				{{ _("Item") }}
 			</div>
 			<div class="col-sm-3 col-xs-3 text-right h6 text-uppercase">
@@ -67,7 +64,7 @@
 		</div>
 		{% for d in doc.items %}
 		<div class="row order-items">
-			<div class="col-sm-6 col-xs-6">
+			<div class="col-sm-6 col-6">
 				{{ item_name_and_description(d) }}
 			</div>
 			<div class="col-sm-3 col-xs-3 text-right">
@@ -85,11 +82,10 @@
 	</div>
 
 	<!-- taxes -->
-	<div class="order-taxes row">
-		<div class="col-sm-6"><!-- empty --></div>
-		<div class="col-sm-6 text-right">
+	<div class="order-taxes d-flex justify-content-end">
+		<table>
 			{% include "erpnext/templates/includes/order/order_taxes.html" %}
-		</div>
+		</table>
 	</div>
 </div>
 
@@ -115,7 +111,7 @@
 							<div class="control-input">
 								<input class="form-control" type="number" min="0" max="{{ available_loyalty_points }}" id="loyalty-point-to-redeem">
 							</div>
-							<p class="help-box small text-muted hidden-xs"> Available Points: {{ available_loyalty_points }} </p>
+							<p class="help-box small text-muted d-none d-sm-block"> Available Points: {{ available_loyalty_points }} </p>
 						</div>
 					</div>
 					{% endif %}
diff --git a/erpnext/templates/pages/product_search.html b/erpnext/templates/pages/product_search.html
index f9efd48..6a5425b 100644
--- a/erpnext/templates/pages/product_search.html
+++ b/erpnext/templates/pages/product_search.html
@@ -25,7 +25,7 @@
 	<div style="text-align: center;">
 		<div class="more-btn"
 			style="display: none; text-align: center;">
-            <button class="btn btn-default">{{ _("More...") }}</button>
+            <button class="btn btn-light">{{ _("More...") }}</button>
 		</div>
 	</div>
 </div>
diff --git a/erpnext/templates/pages/projects.html b/erpnext/templates/pages/projects.html
index baa2ae6..7e294e0 100644
--- a/erpnext/templates/pages/projects.html
+++ b/erpnext/templates/pages/projects.html
@@ -20,11 +20,11 @@
 	aria-valuemin="0" aria-valuemax="100" style="width:{{ doc.percent_complete|round|int }}%;">
 	</div>
 </div>
-{% endif %}		
+{% endif %}
 
 <div class="clearfix">
   <h4 style="float: left;">{{ _("Tasks") }}</h4>
-  <a class="btn btn-secondary btn-default btn-sm" style="float: right; position: relative; top: 10px;" href='/tasks?new=1&project={{ doc.project_name }}'>{{ _("New task") }}</a>
+  <a class="btn btn-secondary btn-light btn-sm" style="float: right; position: relative; top: 10px;" href='/tasks?new=1&project={{ doc.project_name }}'>{{ _("New task") }}</a>
 </div>
 
 <p>
diff --git a/erpnext/templates/pages/task_info.html b/erpnext/templates/pages/task_info.html
index 6cfac28..6cd6a7e 100644
--- a/erpnext/templates/pages/task_info.html
+++ b/erpnext/templates/pages/task_info.html
@@ -20,7 +20,7 @@
 		<div class="page-header-actions-block" data-html-block="header-actions">
 			<button type="submit" class="btn btn-primary btn-sm btn-form-submit">
 	    		{{ __("Update") }}</button>
-	    		<a href="tasks" class="btn btn-default btn-sm">
+	    		<a href="tasks" class="btn btn-light btn-sm">
 	    		{{ __("Cancel") }}</a>
 		</div>
     </div>
@@ -91,7 +91,7 @@
 		{% endfor %}
 	</div>
 	<div class="comment-form-wrapper">
-		<a class="add-comment btn btn-default btn-sm">{{ __("Add Comment") }}</a>
+		<a class="add-comment btn btn-light btn-sm">{{ __("Add Comment") }}</a>
 		<div style="display: none;" id="comment-form">
 			<p>{{ __("Add Comment") }}</p>
 			<form>
diff --git a/erpnext/www/all-products/__init__.py b/erpnext/www/all-products/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/www/all-products/__init__.py
diff --git a/erpnext/www/all-products/index.html b/erpnext/www/all-products/index.html
new file mode 100644
index 0000000..ade72a2
--- /dev/null
+++ b/erpnext/www/all-products/index.html
@@ -0,0 +1,163 @@
+{% extends "templates/web.html" %}
+
+{% block title %}{{ _('Products') }}{% endblock %}
+{% block header %}
+<h1>{{ _('Products') }}</h1>
+{% endblock header %}
+
+{% block page_content %}
+<div class="row">
+	<div class="col-8">
+		<div class="input-group input-group-sm mb-3">
+			<input type="search" class="form-control" placeholder="{{_('Search')}}"
+				aria-label="{{_('Product Search')}}" aria-describedby="product-search"
+				value="{{ frappe.form_dict.search or '' }}"
+			>
+		</div>
+	</div>
+
+	<div class="col-4 pl-0">
+		<button class="btn btn-light btn-sm btn-block d-md-none"
+			type="button"
+			data-toggle="collapse"
+			data-target="#product-filters"
+			aria-expanded="false"
+			aria-controls="product-filters"
+			style="white-space: nowrap;"
+		>
+			{{ _('Toggle Filters') }}
+		</button>
+	</div>
+</div>
+
+<div class="row">
+	<div class="col-12 order-2 col-md-8 order-md-1 products-list">
+		{% if items %}
+			{% for item in items %}
+				{% include "erpnext/www/all-products/item_row.html" %}
+			{% endfor %}
+		{% else %}
+			{% include "erpnext/www/all-products/not_found.html" %}
+		{% endif %}
+	</div>
+	<div class="col-12 order-1 col-md-4 order-md-2">
+
+		{% if frappe.form_dict.start or frappe.form_dict.field_filters or frappe.form_dict.search %}
+		<a class="mb-3 d-inline-block" href="/all-products">{{ _('Clear filters') }}</a>
+		{% endif  %}
+
+		<div class="collapse d-md-block" id="product-filters">
+			{% for field_filter in field_filters %}
+				{%- set item_field =  field_filter[0] %}
+				{%- set values =  field_filter[1] %}
+				<div class="mb-4">
+					<h6>{{ item_field.label }}</h6>
+
+					{% if values | len > 20 %}
+					<!-- show inline filter if values more than 20 -->
+					<input type="text" class="form-control form-control-sm mb-2 product-filter-filter"/>
+					{% endif %}
+
+					{% if values %}
+					<div class="filter-options">
+						{% for value in values %}
+						<div class="custom-control custom-checkbox" data-value="{{ value }}">
+							<input type="checkbox"
+								class="product-filter field-filter custom-control-input"
+								id="{{value}}"
+								data-filter-name="{{ item_field.fieldname }}"
+								data-filter-value="{{ value }}"
+							>
+							<label class="custom-control-label" for="{{value}}">
+								{{ value }}
+							</label>
+						</div>
+						{% endfor %}
+					</div>
+					{% else %}
+					<i class="text-muted">{{ _('No values') }}</i>
+					{% endif %}
+				</div>
+			{% endfor %}
+
+			{% for attribute in attribute_filters %}
+				<div class="mb-4">
+					<h6>{{ attribute.name }}</h6>
+
+					{% if values | len > 20 %}
+					<!-- show inline filter if values more than 20 -->
+					<input type="text" class="form-control form-control-sm mb-2 product-filter-filter"/>
+					{% endif %}
+
+					{% if attribute.item_attribute_values %}
+					<div class="filter-options">
+						{% for attr_value in attribute.item_attribute_values %}
+						<div class="custom-control custom-checkbox" data-value="{{ value }}">
+							<input type="checkbox"
+								class="product-filter attribute-filter custom-control-input"
+								id="{{attr_value.name}}"
+								data-attribute-name="{{ attribute.name }}"
+								data-attribute-value="{{ attr_value.attribute_value }}"
+								{% if attr_value.checked %} checked {% endif %}
+							>
+							<label class="custom-control-label" for="{{attr_value.name}}">
+								{{ attr_value.attribute_value }}
+							</label>
+						</div>
+						{% endfor %}
+					</div>
+					{% else %}
+					<i class="text-muted">{{ _('No values') }}</i>
+					{% endif %}
+				</div>
+			{% endfor %}
+		</div>
+
+		<script>
+			frappe.ready(() => {
+				$('.product-filter-filter').on('keydown', frappe.utils.debounce((e) => {
+					const $input = $(e.target);
+					const keyword = ($input.val() || '').toLowerCase();
+					const $filter_options = $input.next('.filter-options');
+
+					$filter_options.find('.custom-control').show();
+					$filter_options.find('.custom-control').each((i, el) => {
+						const $el = $(el);
+						const value = $el.data('value').toLowerCase();
+						if (!value.includes(keyword)) {
+							$el.hide();
+						}
+					});
+				}, 300));
+			})
+		</script>
+	</div>
+</div>
+<div class="row">
+	<div class="col-12">
+		{% if frappe.form_dict.start|int > 0 %}
+		<button class="btn btn-outline-secondary btn-prev" data-start="{{ frappe.form_dict.start|int - page_length }}">{{ _("Prev") }}</button>
+		{% endif %}
+		{% if items|length >= page_length %}
+		<button class="btn btn-outline-secondary btn-next" data-start="{{ frappe.form_dict.start|int + page_length }}">{{ _("Next") }}</button>
+		{% endif %}
+	</div>
+</div>
+
+<script>
+	frappe.ready(() => {
+		$('.btn-prev, .btn-next').click((e) => {
+			const $btn = $(e.target);
+			$btn.prop('disabled', true);
+			const start = $btn.data('start');
+			let query_params = frappe.utils.get_query_params();
+			query_params.start = start;
+			let path = window.location.pathname + '?' + frappe.utils.get_url_from_dict(query_params);
+			window.location.href = path;
+		});
+	});
+</script>
+
+{% endblock %}
+
+
diff --git a/erpnext/www/all-products/index.js b/erpnext/www/all-products/index.js
new file mode 100644
index 0000000..cb9e7e6
--- /dev/null
+++ b/erpnext/www/all-products/index.js
@@ -0,0 +1,161 @@
+$(() => {
+	class ProductListing {
+		constructor() {
+			this.bind_filters();
+			this.bind_search();
+			this.restore_filters_state();
+		}
+
+		bind_filters() {
+			this.field_filters = {};
+			this.attribute_filters = {};
+
+			$('.product-filter').on('change', frappe.utils.debounce((e) => {
+				const $checkbox = $(e.target);
+				const is_checked = $checkbox.is(':checked');
+
+				if ($checkbox.is('.attribute-filter')) {
+					const {
+						attributeName: attribute_name,
+						attributeValue: attribute_value
+					} = $checkbox.data();
+
+					if (is_checked) {
+						this.attribute_filters[attribute_name] = this.attribute_filters[attribute_name] || [];
+						this.attribute_filters[attribute_name].push(attribute_value);
+					} else {
+						this.attribute_filters[attribute_name] = this.attribute_filters[attribute_name] || [];
+						this.attribute_filters[attribute_name] = this.attribute_filters[attribute_name].filter(v => v !== attribute_value);
+					}
+
+					if (this.attribute_filters[attribute_name].length === 0) {
+						delete this.attribute_filters[attribute_name];
+					}
+				} else if ($checkbox.is('.field-filter')) {
+					const {
+						filterName: filter_name,
+						filterValue: filter_value
+					} = $checkbox.data();
+
+					if (is_checked) {
+						this.field_filters[filter_name] = this.field_filters[filter_name] || [];
+						this.field_filters[filter_name].push(filter_value);
+					} else {
+						this.field_filters[filter_name] = this.field_filters[filter_name] || [];
+						this.field_filters[filter_name] = this.field_filters[filter_name].filter(v => v !== filter_value);
+					}
+
+					if (this.field_filters[filter_name].length === 0) {
+						delete this.field_filters[filter_name];
+					}
+				}
+
+				const query_string = get_query_string({
+					field_filters: JSON.stringify(if_key_exists(this.field_filters)),
+					attribute_filters: JSON.stringify(if_key_exists(this.attribute_filters)),
+				});
+				window.history.pushState('filters', '', '/all-products?' + query_string);
+
+				$('.page_content input').prop('disabled', true);
+				this.get_items_with_filters()
+					.then(html => {
+						$('.products-list').html(html);
+					})
+					.then(data => {
+						$('.page_content input').prop('disabled', false);
+						return data;
+					})
+					.catch(() => {
+						$('.page_content input').prop('disabled', false);
+					});
+			}, 1000));
+		}
+
+		make_filters() {
+
+		}
+
+		bind_search() {
+			$('input[type=search]').on('keydown', (e) => {
+				if (e.keyCode === 13) {
+					// Enter
+					const value = e.target.value;
+					if (value) {
+						window.location.search = 'search=' + e.target.value;
+					} else {
+						window.location.search = '';
+					}
+				}
+			});
+		}
+
+		restore_filters_state() {
+			const filters = frappe.utils.get_query_params();
+			let {field_filters, attribute_filters} = filters;
+
+			if (field_filters) {
+				field_filters = JSON.parse(field_filters);
+				for (let fieldname in field_filters) {
+					const values = field_filters[fieldname];
+					const selector = values.map(value => {
+						return `input[data-filter-name="${fieldname}"][data-filter-value="${value}"]`;
+					}).join(',');
+					$(selector).prop('checked', true);
+				}
+				this.field_filters = field_filters;
+			}
+			if (attribute_filters) {
+				attribute_filters = JSON.parse(attribute_filters);
+				for (let attribute in attribute_filters) {
+					const values = attribute_filters[attribute];
+					const selector = values.map(value => {
+						return `input[data-attribute-name="${attribute}"][data-attribute-value="${value}"]`;
+					}).join(',');
+					$(selector).prop('checked', true);
+				}
+				this.attribute_filters = attribute_filters;
+			}
+		}
+
+		get_items_with_filters() {
+			const { attribute_filters, field_filters } = this;
+			const args = {
+				field_filters: if_key_exists(field_filters),
+				attribute_filters: if_key_exists(attribute_filters)
+			};
+
+			return new Promise((resolve, reject) => {
+				frappe.call('erpnext.portal.product_configurator.utils.get_products_html_for_website', args)
+					.then(r => {
+						if (r.exc) reject(r.exc);
+						else resolve(r.message);
+					})
+					.fail(reject);
+			});
+		}
+	}
+
+	new ProductListing();
+
+	function get_query_string(object) {
+		const url = new URLSearchParams();
+		for (let key in object) {
+			const value = object[key];
+			if (value) {
+				url.append(key, value);
+			}
+		}
+		return url.toString();
+	}
+
+	function if_key_exists(obj) {
+		let exists = false;
+		for (let key in obj) {
+			if (obj.hasOwnProperty(key) && obj[key]) {
+				exists = true;
+				break;
+			}
+		}
+		return exists ? obj : undefined;
+	}
+});
diff --git a/erpnext/www/all-products/index.py b/erpnext/www/all-products/index.py
new file mode 100644
index 0000000..8e2d268
--- /dev/null
+++ b/erpnext/www/all-products/index.py
@@ -0,0 +1,26 @@
+import frappe
+from erpnext.portal.product_configurator.utils import (get_products_for_website, get_product_settings,
+	get_field_filter_data, get_attribute_filter_data)
+
+def get_context(context):
+
+	if frappe.form_dict:
+		search = frappe.form_dict.search
+		field_filters = frappe.parse_json(frappe.form_dict.field_filters)
+		attribute_filters = frappe.parse_json(frappe.form_dict.attribute_filters)
+	else:
+		search = field_filters = attribute_filters = None
+
+	context.items = get_products_for_website(field_filters, attribute_filters, search)
+
+	product_settings = get_product_settings()
+	context.field_filters = get_field_filter_data() \
+		if product_settings.enable_field_filters else []
+
+	context.attribute_filters = get_attribute_filter_data() \
+		if product_settings.enable_attribute_filters else []
+
+	context.product_settings = product_settings
+	context.page_length = product_settings.products_per_page
+
+	context.no_cache = 1
diff --git a/erpnext/www/all-products/item_row.html b/erpnext/www/all-products/item_row.html
new file mode 100644
index 0000000..9fa7fa3
--- /dev/null
+++ b/erpnext/www/all-products/item_row.html
@@ -0,0 +1,24 @@
+<div class="card mb-3">
+	<div class="row no-gutters">
+		<div class="col-md-3">
+			<div class="card-body">
+				<a class="no-underline" href="{{ item.route }}">
+					<img class="website-image" src="{{ item.website_image or item.image or 'no-image.jpg' }}" alt="{{ item.item_name }}">
+				</a>
+			</div>
+		</div>
+		<div class="col-md-9">
+			<div class="card-body">
+				<h5 class="card-title">
+					<a class="text-dark" href="{{ item.route }}">
+						{{ item.item_name or item.name }}
+					</a>
+				</h5>
+				<p class="card-text">
+					{{ item.website_description or item.description or '<i class="text-muted">No description</i>' }}
+				</p>
+				<a href="{{ item.route }}" class="btn btn-sm btn-light">{{ _('More details') }}</a>
+			</div>
+		</div>
+	</div>
+</div>
diff --git a/erpnext/www/all-products/not_found.html b/erpnext/www/all-products/not_found.html
new file mode 100644
index 0000000..e1986b4
--- /dev/null
+++ b/erpnext/www/all-products/not_found.html
@@ -0,0 +1 @@
+<div class="d-flex justify-content-center p-3 text-muted">{{ _('No products found') }}</div>
\ No newline at end of file