diff --git a/wagtail/wagtailcore/blocks.py b/wagtail/wagtailcore/blocks.py index 8d45a9df2..c08c424bb 100644 --- a/wagtail/wagtailcore/blocks.py +++ b/wagtail/wagtailcore/blocks.py @@ -225,6 +225,12 @@ class Block(six.with_metaclass(BaseBlock, object)): """ return force_text(value) + def get_searchable_content(self, value): + """ + Returns a list of strings containing text content within this block to be used in a search engine. + """ + return [] + def __eq__(self, other): """ The deep_deconstruct method in django.db.migrations.autodetector.MigrationAutodetector does not @@ -347,6 +353,10 @@ class FieldBlock(Block): def clean(self, value): return self.field.clean(value) + def get_searchable_content(self, value): + return [value] + + class CharBlock(FieldBlock): def __init__(self, required=True, help_text=None, max_length=None, min_length=None, **kwargs): # TODO: decide what to do about 'label' and 'initial' parameters to the form field @@ -542,6 +552,14 @@ class BaseStructBlock(Block): for name, val in value.items() ]) + def get_searchable_content(self, value): + content = [] + + for name, block in self.child_blocks.items(): + content.extend(block.get_searchable_content(value.get(name, block.meta.default))) + + return content + def deconstruct(self): """ Always deconstruct StructBlock instances as if they were plain StructBlocks with all of the @@ -747,6 +765,14 @@ class ListBlock(Block): ) return format_html("", children) + def get_searchable_content(self, value): + content = [] + + for child_value in value: + content.extend(self.child_block.get_searchable_content(child_value)) + + return content + # =========== # StreamBlock @@ -925,6 +951,14 @@ class BaseStreamBlock(Block): [(child, child.block_type) for child in value] ) + def get_searchable_content(self, value): + content = [] + + for child in value: + content.extend(child.block.get_searchable_content(child.value)) + + return content + def deconstruct(self): """ Always deconstruct StreamBlock instances as if they were plain StreamBlocks with all of the diff --git a/wagtail/wagtailcore/tests/test_blocks.py b/wagtail/wagtailcore/tests/test_blocks.py index 6d9fd0115..06186633d 100644 --- a/wagtail/wagtailcore/tests/test_blocks.py +++ b/wagtail/wagtailcore/tests/test_blocks.py @@ -35,6 +35,12 @@ class TestFieldBlock(unittest.TestCase): self.assertIn('This field is required.', html) + def test_charfield_searchable_content(self): + block = blocks.CharBlock() + content = block.get_searchable_content("Hello world!") + + self.assertEqual(content, ["Hello world!"]) + def test_choicefield_render(self): class ChoiceBlock(blocks.FieldBlock): field = forms.ChoiceField(choices=( @@ -62,6 +68,19 @@ class TestFieldBlock(unittest.TestCase): self.assertIn('', html) self.assertIn('', html) + @unittest.expectedFailure # Returning "choice-1" instead of "Choice 1" + def test_choicefield_searchable_content(self): + class ChoiceBlock(blocks.FieldBlock): + field = forms.ChoiceField(choices=( + ('choice-1', "Choice 1"), + ('choice-2', "Choice 2"), + )) + + block = ChoiceBlock() + content = block.get_searchable_content("choice-1") + + self.assertEqual(content, ["Choice 1"]) + class TestMeta(unittest.TestCase): def test_set_template_with_meta(self): @@ -262,6 +281,19 @@ class TestStructBlock(unittest.TestCase): block = LinkBlock() self.assertIn('', block.all_html_declarations()) + def test_searchable_content(self): + class LinkBlock(blocks.StructBlock): + title = blocks.CharBlock() + link = blocks.URLBlock() + + block = LinkBlock() + content = block.get_searchable_content({ + 'title': "Wagtail site", + 'link': 'http://www.wagtail.io', + }) + + self.assertEqual(content, ["Wagtail site", "http://www.wagtail.io"]) + class TestListBlock(unittest.TestCase): def test_initialise_with_class(self): @@ -398,6 +430,25 @@ class TestListBlock(unittest.TestCase): block = blocks.ListBlock(CharBlockWithDeclarations()) self.assertIn('', block.all_html_declarations()) + def test_searchable_content(self): + class LinkBlock(blocks.StructBlock): + title = blocks.CharBlock() + link = blocks.URLBlock() + + block = blocks.ListBlock(LinkBlock()) + content = block.get_searchable_content([ + { + 'title': "Wagtail", + 'link': 'http://www.wagtail.io', + }, + { + 'title': "Django", + 'link': 'http://www.djangoproject.com', + }, + ]) + + self.assertEqual(content, ["Wagtail", "http://www.wagtail.io", "Django", "http://www.djangoproject.com"]) + class TestStreamBlock(unittest.TestCase): def test_initialisation(self): @@ -646,3 +697,32 @@ class TestStreamBlock(unittest.TestCase): block_value = block.value_from_datadict(post_data, {}, 'article') self.assertEqual(block_value[2].value, "heading 2") + + def test_searchable_content(self): + class ArticleBlock(blocks.StreamBlock): + heading = blocks.CharBlock() + paragraph = blocks.CharBlock() + + block = ArticleBlock() + value = block.to_python([ + { + 'type': 'heading', + 'value': "My title", + }, + { + 'type': 'paragraph', + 'value': 'My first paragraph', + }, + { + 'type': 'paragraph', + 'value': 'My second paragraph', + }, + ]) + + content = block.get_searchable_content(value) + + self.assertEqual(content, [ + "My title", + "My first paragraph", + "My second paragraph", + ])