From 697978c8f3aa2ad192a518dc4e9d394eaf4dcb27 Mon Sep 17 00:00:00 2001 From: "stravo1@mac" Date: Fri, 13 Feb 2026 21:37:57 +0530 Subject: [PATCH 1/3] fix(website_404): cache website 404 results wrt to users fixes #37007 --- frappe/website/page_renderers/not_found_page.py | 2 +- frappe/website/path_resolver.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/website/page_renderers/not_found_page.py b/frappe/website/page_renderers/not_found_page.py index 704dca77d1..1898d7dece 100644 --- a/frappe/website/page_renderers/not_found_page.py +++ b/frappe/website/page_renderers/not_found_page.py @@ -21,7 +21,7 @@ class NotFoundPage(TemplatePage): def render(self): if self.can_cache_404(): - frappe.cache.hset("website_404", self.request_url, True) + frappe.cache.hset("website_404", f"{frappe.session.user}|{self.request_url}", True) return super().render() def can_cache_404(self): diff --git a/frappe/website/path_resolver.py b/frappe/website/path_resolver.py index 0a2e302118..929438e055 100644 --- a/frappe/website/path_resolver.py +++ b/frappe/website/path_resolver.py @@ -35,7 +35,7 @@ class PathResolver: return "desk", TemplatePage("desk", self.http_status_code) # check if the request url is in 404 list - if request.url and can_cache() and frappe.cache.hget("website_404", request.url): + if request.url and can_cache() and frappe.cache.hget("website_404", f"{frappe.session.user}|{request.url}"): return self.path, NotFoundPage(self.path) try: From a534936726adaaaa5d6b44dfacd036659b2c67df Mon Sep 17 00:00:00 2001 From: "stravo1@mac" Date: Mon, 16 Feb 2026 22:15:01 +0530 Subject: [PATCH 2/3] Revert "fix(website_404): cache website 404 results wrt to users" This reverts commit 697978c8f3aa2ad192a518dc4e9d394eaf4dcb27. --- frappe/website/page_renderers/not_found_page.py | 2 +- frappe/website/path_resolver.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/website/page_renderers/not_found_page.py b/frappe/website/page_renderers/not_found_page.py index 1898d7dece..704dca77d1 100644 --- a/frappe/website/page_renderers/not_found_page.py +++ b/frappe/website/page_renderers/not_found_page.py @@ -21,7 +21,7 @@ class NotFoundPage(TemplatePage): def render(self): if self.can_cache_404(): - frappe.cache.hset("website_404", f"{frappe.session.user}|{self.request_url}", True) + frappe.cache.hset("website_404", self.request_url, True) return super().render() def can_cache_404(self): diff --git a/frappe/website/path_resolver.py b/frappe/website/path_resolver.py index 929438e055..0a2e302118 100644 --- a/frappe/website/path_resolver.py +++ b/frappe/website/path_resolver.py @@ -35,7 +35,7 @@ class PathResolver: return "desk", TemplatePage("desk", self.http_status_code) # check if the request url is in 404 list - if request.url and can_cache() and frappe.cache.hget("website_404", f"{frappe.session.user}|{request.url}"): + if request.url and can_cache() and frappe.cache.hget("website_404", request.url): return self.path, NotFoundPage(self.path) try: From 9dcaab96eef44c54aa3e7d53ae9afc30f21357cb Mon Sep 17 00:00:00 2001 From: "stravo1@mac" Date: Mon, 16 Feb 2026 23:41:32 +0530 Subject: [PATCH 3/3] fix(website_404): skip caching 404 for pages with permission checks --- .../website/page_renderers/not_found_page.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/frappe/website/page_renderers/not_found_page.py b/frappe/website/page_renderers/not_found_page.py index 704dca77d1..9b980f5d51 100644 --- a/frappe/website/page_renderers/not_found_page.py +++ b/frappe/website/page_renderers/not_found_page.py @@ -2,6 +2,7 @@ import os from urllib.parse import urlparse import frappe +from frappe.website.page_renderers.document_page import _find_matching_document_webview from frappe.website.page_renderers.template_page import TemplatePage from frappe.website.utils import can_cache @@ -26,10 +27,26 @@ class NotFoundPage(TemplatePage): def can_cache_404(self): # do not cache 404 for custom homepages - return can_cache() and self.request_url and not self.is_custom_home_page() + # also skip caching docs with website permission checks (access is dynamic) + return ( + can_cache() + and self.request_url + and not self.is_custom_home_page() + and not self.has_website_permission_check() + ) def is_custom_home_page(self): url_parts = urlparse(self.request_url) request_url = os.path.splitext(url_parts.path)[0] request_path = os.path.splitext(self.request_path)[0] return request_url in HOMEPAGE_PATHS and request_path not in HOMEPAGE_PATHS + + def has_website_permission_check(self): + request_path = os.path.splitext(self.request_path)[0] + if not (document := _find_matching_document_webview(request_path)): + return False + doctype, docname = document + doc = frappe.get_cached_doc(doctype, docname) + return hasattr(doc, "has_website_permission") or bool( + frappe.get_hooks("has_website_permission", {}).get(doctype) + )