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("
{0}
", 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",
+ ])