feat: Shop by Category

- Added Shop by Category Page
- Tabbed sections for item fields in Shop by Category Page
- Added Shop by Category Section in E commerce Settings
- Nested Navigation & Breadcrumbs in Item group pages
- Added scrollable & clickable Sub categories in Item Group page
- Made breadcrumbs slightly dynamic in Item Page
- Added image to Brand doctype
diff --git a/erpnext/e_commerce/doctype/e_commerce_settings/e_commerce_settings.json b/erpnext/e_commerce/doctype/e_commerce_settings/e_commerce_settings.json
index b1b1cae..75f9c31 100644
--- a/erpnext/e_commerce/doctype/e_commerce_settings/e_commerce_settings.json
+++ b/erpnext/e_commerce/doctype/e_commerce_settings/e_commerce_settings.json
@@ -38,7 +38,9 @@
   "enable_field_filters",
   "filter_fields",
   "enable_attribute_filters",
-  "filter_attributes"
+  "filter_attributes",
+  "shop_by_category_section",
+  "slideshow"
  ],
  "fields": [
   {
@@ -64,7 +66,7 @@
    "collapsible": 1,
    "fieldname": "filter_categories_section",
    "fieldtype": "Section Break",
-   "label": "Filters"
+   "label": "Filters and Categories"
   },
   {
    "default": "0",
@@ -78,9 +80,10 @@
   },
   {
    "default": "0",
+   "description": "The field filters will also work as categories in the <b>Shop by Category</b> page.",
    "fieldname": "enable_field_filters",
    "fieldtype": "Check",
-   "label": "Enable Field Filters"
+   "label": "Enable Field Filters (Categories)"
   },
   {
    "default": "0",
@@ -258,12 +261,25 @@
    "label": "Payment Gateway Account",
    "mandatory_depends_on": "enable_checkout",
    "options": "Payment Gateway Account"
+  },
+  {
+   "collapsible": 1,
+   "depends_on": "enable_field_filters",
+   "fieldname": "shop_by_category_section",
+   "fieldtype": "Section Break",
+   "label": "Shop by Category"
+  },
+  {
+   "fieldname": "slideshow",
+   "fieldtype": "Link",
+   "label": "Slideshow",
+   "options": "Website Slideshow"
   }
  ],
  "index_web_pages_for_search": 1,
  "issingle": 1,
  "links": [],
- "modified": "2021-02-11 18:22:14.556880",
+ "modified": "2021-03-01 20:24:56.548673",
  "modified_by": "Administrator",
  "module": "E-commerce",
  "name": "E Commerce Settings",
diff --git a/erpnext/e_commerce/doctype/website_item/website_item.py b/erpnext/e_commerce/doctype/website_item/website_item.py
index e3197b9..856b9b7 100644
--- a/erpnext/e_commerce/doctype/website_item/website_item.py
+++ b/erpnext/e_commerce/doctype/website_item/website_item.py
@@ -165,7 +165,7 @@
 		context.show_search = True
 		context.search_link = '/search'
 
-		context.parents = get_parent_item_groups(self.item_group)
+		context.parents = get_parent_item_groups(self.item_group, from_item=True)
 		context.body_class = "product-page"
 		self.attributes = frappe.get_all("Item Variant Attribute",
 					  fields=["attribute", "attribute_value"],
diff --git a/erpnext/e_commerce/product_configurator/utils.py b/erpnext/e_commerce/product_configurator/utils.py
index 6c652cf..7ccb053 100644
--- a/erpnext/e_commerce/product_configurator/utils.py
+++ b/erpnext/e_commerce/product_configurator/utils.py
@@ -2,7 +2,6 @@
 from frappe.utils import cint
 
 from erpnext.e_commerce.product_configurator.item_variants_cache import ItemVariantsCacheManager
-from erpnext.e_commerce.shopping_cart.product_info import get_product_info_for_website
 
 def get_item_codes_by_attributes(attribute_filters, template_item_code=None):
 	items = []
diff --git a/erpnext/public/scss/shopping_cart.scss b/erpnext/public/scss/shopping_cart.scss
index fef1e76..da22aa6 100644
--- a/erpnext/public/scss/shopping_cart.scss
+++ b/erpnext/public/scss/shopping_cart.scss
@@ -323,6 +323,32 @@
 	}
 }
 
+.sub-category-container {
+	padding-bottom: 1rem;
+	margin-bottom: 1.25rem;
+	border-bottom: 1px solid var(--table-border-color);
+
+	.heading {
+		color: var(--gray-500);
+	}
+}
+
+.scroll-categories {
+	white-space: nowrap;
+	overflow-x: auto;
+
+	.category-pill {
+		margin: 0px 4px;
+		display: inline-block;
+		padding: 6px 12px;
+		background-color: #ecf5fe;
+		width: fit-content;
+		font-size: 14px;
+		border-radius: 18px;
+		color: var(--blue-500);
+	}
+}
+
 .cart-icon {
 	.cart-badge {
 		position: relative;
diff --git a/erpnext/setup/doctype/brand/brand.json b/erpnext/setup/doctype/brand/brand.json
index a8f0674..45b4db8 100644
--- a/erpnext/setup/doctype/brand/brand.json
+++ b/erpnext/setup/doctype/brand/brand.json
@@ -1,270 +1,111 @@
 {
- "allow_copy": 0, 
- "allow_events_in_timeline": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 1, 
- "allow_rename": 1, 
- "autoname": "field:brand", 
- "beta": 0, 
- "creation": "2013-02-22 01:27:54", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "Setup", 
- "editable_grid": 0, 
+ "actions": [],
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "field:brand",
+ "creation": "2013-02-22 01:27:54",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+  "brand",
+  "image",
+  "description",
+  "defaults",
+  "brand_defaults"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 1, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "brand", 
-   "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": "Brand Name", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "brand", 
-   "oldfieldtype": "Data", 
-   "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_in_quick_entry": 1,
+   "fieldname": "brand",
+   "fieldtype": "Data",
+   "label": "Brand Name",
+   "oldfieldname": "brand",
+   "oldfieldtype": "Data",
+   "reqd": 1,
    "unique": 1
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "description", 
-   "fieldtype": "Text", 
-   "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": "Description", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "description", 
-   "oldfieldtype": "Text", 
-   "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, 
+   "fieldname": "description",
+   "fieldtype": "Text",
+   "in_list_view": 1,
+   "label": "Description",
+   "oldfieldname": "description",
+   "oldfieldtype": "Text",
    "width": "300px"
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "defaults", 
-   "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": "Defaults", 
-   "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
-  }, 
+   "fieldname": "defaults",
+   "fieldtype": "Section Break",
+   "label": "Defaults"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "brand_defaults", 
-   "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": "Brand Defaults", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Item Default", 
-   "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
+   "fieldname": "brand_defaults",
+   "fieldtype": "Table",
+   "label": "Brand Defaults",
+   "options": "Item Default"
+  },
+  {
+   "fieldname": "image",
+   "fieldtype": "Attach Image",
+   "hidden": 1,
+   "label": "Image"
   }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "icon": "fa fa-certificate", 
- "idx": 1, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 0, 
- "issingle": 0, 
- "istable": 0, 
- "max_attachments": 0, 
- "modified": "2018-10-23 23:18:06.067612", 
- "modified_by": "Administrator", 
- "module": "Setup", 
- "name": "Brand", 
- "owner": "Administrator", 
+ ],
+ "icon": "fa fa-certificate",
+ "idx": 1,
+ "image_field": "image",
+ "links": [],
+ "modified": "2021-03-01 15:57:30.005783",
+ "modified_by": "Administrator",
+ "module": "Setup",
+ "name": "Brand",
+ "owner": "Administrator",
  "permissions": [
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 1, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Item Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "import": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Item Manager",
+   "share": 1,
    "write": 1
-  }, 
+  },
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 0, 
-   "delete": 0, 
-   "email": 1, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Stock User", 
-   "set_user_permissions": 0, 
-   "share": 0, 
-   "submit": 0, 
-   "write": 0
-  }, 
+   "email": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Stock User"
+  },
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 0, 
-   "delete": 0, 
-   "email": 1, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Sales User", 
-   "set_user_permissions": 0, 
-   "share": 0, 
-   "submit": 0, 
-   "write": 0
-  }, 
+   "email": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Sales User"
+  },
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 0, 
-   "delete": 0, 
-   "email": 1, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Purchase User", 
-   "set_user_permissions": 0, 
-   "share": 0, 
-   "submit": 0, 
-   "write": 0
-  }, 
+   "email": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Purchase User"
+  },
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 0, 
-   "delete": 0, 
-   "email": 1, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Accounts User", 
-   "set_user_permissions": 0, 
-   "share": 0, 
-   "submit": 0, 
-   "write": 0
+   "email": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Accounts User"
   }
- ], 
- "quick_entry": 1, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "show_name_in_global_search": 1, 
- "sort_order": "ASC", 
- "track_changes": 0, 
- "track_seen": 0, 
- "track_views": 0
-}
+ ],
+ "quick_entry": 1,
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "ASC"
+}
\ 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 1e942d7..b375711 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -88,8 +88,8 @@
 		if not field_filters:
 			field_filters = {}
 
-		# Ensure the query remains within current item group & sub group
-		field_filters['item_group'] = [ig[0] for ig in get_child_groups(self.name)]
+		# Ensure the query remains within current item group
+		field_filters['item_group'] = self.name
 
 		engine = ProductQuery()
 		context.items = engine.query(attribute_filters, field_filters, search, start, item_group=self.name)
@@ -104,6 +104,7 @@
 			"title": self.name
 		})
 
+		context.sub_categories = get_child_groups(self.name)
 		if self.slideshow:
 			values = {
 				'show_indicators': 1,
@@ -123,8 +124,9 @@
 
 			context.slideshow = values
 
-		context.breadcrumbs = 0
+		context.no_breadcrumbs = False
 		context.title = self.website_title or self.name
+		context.body_class = "product-page"
 
 		return context
 
@@ -136,10 +138,11 @@
 		validate_item_default_company_links(self.item_group_defaults)
 
 def get_child_groups(item_group_name):
+	"""Returns child item groups *excluding* passed group."""
 	item_group = frappe.get_doc("Item Group", item_group_name)
-	return frappe.db.sql("""select name
-		from `tabItem Group` where lft>=%(lft)s and rgt<=%(rgt)s
-			and show_in_website = 1""", {"lft": item_group.lft, "rgt": item_group.rgt})
+	return frappe.db.sql("""select name, route
+		from `tabItem Group` where lft>%(lft)s and rgt<%(rgt)s
+			and show_in_website = 1""", {"lft": item_group.lft, "rgt": item_group.rgt}, as_dict=1)
 
 def get_child_item_groups(item_group_name):
 	item_group = frappe.get_cached_value("Item Group",
@@ -164,15 +167,25 @@
 	return frappe.get_template(products_template).render(context)
 
 
-def get_parent_item_groups(item_group_name):
+def get_parent_item_groups(item_group_name, from_item=False):
+	base_nav_page = {"name": frappe._("Shop by Category"), "route":"/shop-by-category"}
+
+	if from_item:
+		# base page after 'Home' will vary on Item page
+		last_page = frappe.request.environ["HTTP_REFERER"].split('/')[-1]
+		if last_page and last_page in ("shop-by-category", "all-products"):
+			base_nav_page_title = " ".join(last_page.split("-")).title()
+			base_nav_page = {"name": frappe._(base_nav_page_title), "route":"/"+last_page}
+
 	base_parents = [
 		{"name": frappe._("Home"), "route":"/"},
-		{"name": frappe._("All Products"), "route":"/all-products"},
+		base_nav_page,
 	]
+
 	if not item_group_name:
 		return base_parents
 
-	item_group = frappe.get_doc("Item Group", item_group_name)
+	item_group = frappe.db.get_value("Item Group", item_group_name, ["lft", "rgt"], as_dict=1)
 	parent_groups = frappe.db.sql("""select name, route from `tabItem Group`
 		where lft <= %s and rgt >= %s
 		and show_in_website=1
diff --git a/erpnext/templates/generators/item_group.html b/erpnext/templates/generators/item_group.html
index b5f18ba..233b169 100644
--- a/erpnext/templates/generators/item_group.html
+++ b/erpnext/templates/generators/item_group.html
@@ -8,6 +8,12 @@
 <script type="text/javascript" src="/all-products/index.js"></script>
 {% endblock %}
 
+{% block breadcrumbs %}
+<div class="item-breadcrumbs small text-muted">
+	{% include "templates/includes/breadcrumbs.html" %}
+</div>
+{% endblock %}
+
 {% block page_content %}
 <div class="item-group-content" itemscope itemtype="http://schema.org/Product" data-item-group="{{ name }}">
 	<div class="item-group-slideshow">
@@ -27,6 +33,20 @@
 	</div>
 	<div class="row">
 		<div class="col-12 order-2 col-md-9 order-md-2 item-card-group-section">
+			{% if sub_categories %}
+			<div class="sub-category-container">
+				<div class="heading"> {{ _('Sub Categories') }} </div>
+			</div>
+			<div class="sub-category-container scroll-categories">
+				{% for row in sub_categories%}
+				<a href="{{ row.route or '#' }}" style="text-decoration: none;">
+					<div class="category-pill">
+						{{ row.name }}
+					</div>
+				</a>
+				{% endfor %}
+			</div>
+			{% endif %}
 			<div class="row products-list">
 				{% if items %}
 					{% for item in items %}
diff --git a/erpnext/www/shop-by-category/__init__.py b/erpnext/www/shop-by-category/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/www/shop-by-category/__init__.py
diff --git a/erpnext/www/shop-by-category/category_card_section.html b/erpnext/www/shop-by-category/category_card_section.html
new file mode 100644
index 0000000..532a198
--- /dev/null
+++ b/erpnext/www/shop-by-category/category_card_section.html
@@ -0,0 +1,28 @@
+{%- macro card(title, image, type, url=None, text_primary=False) -%}
+<!-- style defined at shop-by-category index -->
+<div class="card category-card" data-type="{{ type }}" data-name="{{ title }}">
+	{% if image %}
+	<img class="card-img-top" src="{{ image }}" alt="{{ title }}" style="height:80%">
+	{% else %}
+	<div class="placeholder-div">
+		<span class="placeholder">AB</span>
+	</div>
+	{% endif %}
+	<div class="card-body text-center text-muted">
+		{{ title or '' }}
+	</div>
+	<a href="{{ url or '#' }}" class="stretched-link"></a>
+</div>
+{%- endmacro -%}
+
+<div class="col-12 item-card-group-section">
+	<div class="row products-list product-category-section">
+		{%- for row in data -%}
+			{%- set title = row.name -%}
+			{%- set image = row.get("image") -%}
+			{%- if title -%}
+				{{ card(title, image, type, row.get("route")) }}
+			{%- endif -%}
+		{%- endfor -%}
+	</div>
+</div>
\ No newline at end of file
diff --git a/erpnext/www/shop-by-category/index.html b/erpnext/www/shop-by-category/index.html
new file mode 100644
index 0000000..ac0b317
--- /dev/null
+++ b/erpnext/www/shop-by-category/index.html
@@ -0,0 +1,60 @@
+{% extends "templates/web.html" %}
+{% block title %}{{ _('Shop by Category') }}{% endblock %}
+
+{% block head_include %}
+<style>
+	.category-slideshow {
+		margin-bottom: 2rem;
+	}
+	.category-card {
+		height: 300px !important;
+		width: 300px !important;
+		margin: 30px !important;
+	}
+	.placeholder-div {
+		height:80%;
+		width: -webkit-fill-available;
+		padding: 50px;
+		text-align: center;
+		background-color: #F9FAFA;
+		border-top-left-radius: calc(0.75rem - 1px);
+		border-top-right-radius: calc(0.75rem - 1px);
+	}
+	.placeholder {
+		font-size: 72px;
+	}
+</style>
+{% endblock %}
+
+{% block script %}
+<script type="text/javascript" src="/shop-by-category/index.js"></script>
+{% endblock %}
+
+{% block page_content %}
+<div class="shop-by-category-content">
+	<div class="category-slideshow">
+		{% if slideshow %}
+		<!-- slideshow -->
+			{{ web_block(
+				"Hero Slider",
+				values=slideshow,
+				add_container=0,
+				add_top_padding=0,
+				add_bottom_padding=0,
+			) }}
+		{% endif %}
+	</div>
+	<div class="category-tabs">
+		{% if tabs %}
+		<!-- tabs -->
+			{{ web_block(
+				"Section with Tabs",
+				values=tabs,
+				add_container=0,
+				add_top_padding=0,
+				add_bottom_padding=0
+			) }}
+		{% endif %}
+	</div>
+</div>
+{% endblock %}
\ No newline at end of file
diff --git a/erpnext/www/shop-by-category/index.js b/erpnext/www/shop-by-category/index.js
new file mode 100644
index 0000000..1b3116f
--- /dev/null
+++ b/erpnext/www/shop-by-category/index.js
@@ -0,0 +1,12 @@
+$(() => {
+	$('.category-card').on('click', (e) => {
+		let category_type = e.currentTarget.dataset.type;
+		let category_name = e.currentTarget.dataset.name;
+
+		if (category_type != "item_group") {
+			let filters = {};
+			filters[category_type] =  [category_name];
+			window.location.href = "/all-products?field_filters=" + JSON.stringify(filters);
+		}
+	});
+});
\ No newline at end of file
diff --git a/erpnext/www/shop-by-category/index.py b/erpnext/www/shop-by-category/index.py
new file mode 100644
index 0000000..c295335
--- /dev/null
+++ b/erpnext/www/shop-by-category/index.py
@@ -0,0 +1,73 @@
+import frappe
+from frappe import _
+
+sitemap = 1
+
+def get_context(context):
+	settings = frappe.get_doc("E Commerce Settings")
+	context.categories_enabled = settings.enable_field_filters
+
+	if context.categories_enabled:
+		categories = [row.fieldname for row in settings.filter_fields]
+		context.tabs = get_tabs(categories)
+
+	if settings.slideshow:
+		context.slideshow = get_slideshow(settings.slideshow)
+
+	context.no_cache = 1
+
+def get_slideshow(slideshow):
+	values = {
+		'show_indicators': 1,
+		'show_controls': 1,
+		'rounded': 1,
+		'slider_name': "Categories"
+	}
+	slideshow = frappe.get_doc("Website Slideshow", slideshow)
+	slides = slideshow.get({"doctype": "Website Slideshow Item"})
+	for index, slide in enumerate(slides):
+		values[f"slide_{index + 1}_image"] = slide.image
+		values[f"slide_{index + 1}_title"] = slide.heading
+		values[f"slide_{index + 1}_subtitle"] = slide.description
+		values[f"slide_{index + 1}_theme"] = slide.get("theme") or "Light"
+		values[f"slide_{index + 1}_content_align"] = slide.get("content_align") or "Centre"
+		values[f"slide_{index + 1}_primary_action"] = slide.url
+
+	return values
+
+def get_tabs(categories):
+	tab_values = {
+		'title': _("Shop by Category"),
+	}
+
+	categorical_data = get_category_records(categories)
+	for index, tab in enumerate(categorical_data):
+		tab_values[f"tab_{index + 1}_title"] = frappe.unscrub(tab)
+		# pre-render cards for each tab
+		tab_values[f"tab_{index + 1}_content"] = frappe.render_template(
+			"erpnext/www/shop-by-category/category_card_section.html",
+			{"data": categorical_data[tab], "type": tab}
+		)
+	return tab_values
+
+def get_category_records(categories):
+	categorical_data = {}
+	for category in categories:
+		if category == "item_group":
+			categorical_data["item_group"] = frappe.db.sql("""
+				Select name, parent_item_group, is_group, image, route
+				from `tabItem Group`
+				where parent_item_group='All Item Groups'
+				and show_in_website=1""", as_dict=1)
+		else:
+			doctype = frappe.unscrub(category)
+			fields = ["name"]
+			if frappe.get_meta(doctype, cached=True).get_field("image"):
+				fields += ["image"]
+
+			categorical_data[category] = frappe.db.sql("""
+				Select {fields}
+				from `tab{doctype}`""".format(doctype=doctype, fields=",".join(fields)), as_dict=1)
+
+	return categorical_data
+