diff --git a/wagtail/core/templatetags/wagtailcore_tags.py b/wagtail/core/templatetags/wagtailcore_tags.py index 7f13ba27a7..6f2c7ad672 100644 --- a/wagtail/core/templatetags/wagtailcore_tags.py +++ b/wagtail/core/templatetags/wagtailcore_tags.py @@ -34,8 +34,25 @@ def pageurl(context, page): @register.simple_tag(takes_context=True) def slugurl(context, slug): - """Returns the URL for the page that has the given slug.""" - page = Page.objects.filter(slug=slug).first() + """ + Returns the URL for the page that has the given slug. + + First tries to find a page on the current site. If that fails or a request + is not available in the context, then returns the URL for the first page + that matches the slug on any site. + """ + + try: + current_site = context['request'].site + except (KeyError, AttributeError): + # No site object found - allow the fallback below to take place. + page = None + else: + page = Page.objects.in_site(current_site).filter(slug=slug).first() + + # If no page is found, fall back to searching the whole tree. + if page is None: + page = Page.objects.filter(slug=slug).first() if page: # call pageurl() instead of page.relative_url() here so we get the ``accepts_kwarg`` logic diff --git a/wagtail/core/tests/tests.py b/wagtail/core/tests/tests.py index ce8b001c37..e70eacb97c 100644 --- a/wagtail/core/tests/tests.py +++ b/wagtail/core/tests/tests.py @@ -5,7 +5,7 @@ from django.test import TestCase from django.utils.safestring import SafeText from wagtail.core.models import Page, Site -from wagtail.core.templatetags.wagtailcore_tags import richtext +from wagtail.core.templatetags.wagtailcore_tags import richtext, slugurl from wagtail.core.utils import resolve_model_string from wagtail.tests.testapp.models import SimplePage @@ -43,27 +43,47 @@ class TestPageUrlTags(TestCase): with self.assertRaisesRegex(ValueError, "pageurl tag expected a Page object, got None"): tpl.render(template.Context({'page': None})) - def test_slugurl_without_request_in_context(self): - tpl = template.Template('''{% load wagtailcore_tags %}Events''') - - # no 'request' object in context - result = tpl.render(template.Context({})) - self.assertIn('Events', result) - - # 'request' object in context, but no 'site' attribute - result = tpl.render(template.Context({'request': HttpRequest()})) - self.assertIn('Events', result) - def test_bad_slugurl(self): - tpl = template.Template('''{% load wagtailcore_tags %}Events''') - # no 'request' object in context - result = tpl.render(template.Context({})) - self.assertIn('Events', result) + result = slugurl(template.Context({}), 'bad-slug-doesnt-exist') + self.assertEqual(result, None) # 'request' object in context, but no 'site' attribute - result = tpl.render(template.Context({'request': HttpRequest()})) - self.assertIn('Events', result) + result = slugurl(context=template.Context({'request': HttpRequest()}), slug='bad-slug-doesnt-exist') + self.assertEqual(result, None) + + def test_slugurl_tag_returns_url_for_current_site(self): + home_page = Page.objects.get(url_path='/home/') + new_home_page = home_page.copy(update_attrs={'title': "New home page", 'slug': 'new-home'}) + second_site = Site.objects.create(hostname='site2.example.com', root_page=new_home_page) + # Add a page to the new site that has a slug that is the same as one on + # the first site, but is in a different position in the treeself. + new_christmas_page = Page(title='Christmas', slug='christmas') + new_home_page.add_child(instance=new_christmas_page) + request = HttpRequest() + request.site = second_site + url = slugurl(context=template.Context({'request': request}), slug='christmas') + self.assertEqual(url, '/christmas/') + + def test_slugurl_tag_returns_url_for_other_site(self): + home_page = Page.objects.get(url_path='/home/') + new_home_page = home_page.copy(update_attrs={'title': "New home page", 'slug': 'new-home'}) + second_site = Site.objects.create(hostname='site2.example.com', root_page=new_home_page) + request = HttpRequest() + request.site = second_site + # There is no page with this slug on the current site, so this + # should return an absolute URL for the page on the first site. + url = slugurl(slug='christmas', context=template.Context({'request': request})) + self.assertEqual(url, 'http://localhost/events/christmas/') + + def test_slugurl_without_request_in_context(self): + # no 'request' object in context + result = slugurl(template.Context({}), 'events') + self.assertEqual(result, '/events/') + + # 'request' object in context, but no 'site' attribute + result = slugurl(template.Context({'request': HttpRequest()}), 'events') + self.assertEqual(result, '/events/') class TestSiteRootPathsCache(TestCase):