Compare commits
3 Commits
feature/se
...
feature/#6
Author | SHA1 | Date | |
---|---|---|---|
1d18a82453 | |||
63bbbd70ea | |||
5e343e78a4 |
@ -12,7 +12,7 @@ class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('wagtailcore', '0033_remove_golive_expiry_help_text'),
|
||||
('wagtailcore', '0001_initial'),
|
||||
('wagtail_personalisation', '0011_personalisablepagemetadata'),
|
||||
]
|
||||
|
||||
|
@ -0,0 +1,32 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.1 on 2017-05-31 16:15
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import wagtail.wagtailcore.blocks
|
||||
import wagtail.wagtailcore.fields
|
||||
import wagtail.wagtailimages.blocks
|
||||
import wagtail_personalisation.blocks
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wagtailcore', '0001_initial'),
|
||||
('home', '0003_homepage_text_content'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='PersonalisedFieldsPage',
|
||||
fields=[
|
||||
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')),
|
||||
('body', wagtail.wagtailcore.fields.StreamField((('personalised_block', wagtail.wagtailcore.blocks.StructBlock((('segment', wagtail.wagtailcore.blocks.ChoiceBlock(choices=wagtail_personalisation.blocks.list_segment_choices, help_text='Only show this content block for users in this segment', label='Personalisation segment', required=False)), ('heading', wagtail.wagtailcore.blocks.CharBlock()), ('paragraph', wagtail.wagtailcore.blocks.RichTextBlock())))), ('personalised_block_template', wagtail.wagtailcore.blocks.StructBlock((('segment', wagtail.wagtailcore.blocks.ChoiceBlock(choices=wagtail_personalisation.blocks.list_segment_choices, help_text='Only show this content block for users in this segment', label='Personalisation segment', required=False)), ('heading', wagtail.wagtailcore.blocks.CharBlock()), ('paragraph', wagtail.wagtailcore.blocks.RichTextBlock())), label='Block with template', template='blocks/personalised_block_template.html')), ('personalised_rich_text_block', wagtail.wagtailcore.blocks.StructBlock((('segment', wagtail.wagtailcore.blocks.ChoiceBlock(choices=wagtail_personalisation.blocks.list_segment_choices, help_text='Only show this content block for users in this segment', label='Personalisation segment', required=False)), ('rich_text', wagtail.wagtailcore.blocks.RichTextBlock(label='Rich Text'))))), ('personalised_image', wagtail.wagtailcore.blocks.StructBlock((('segment', wagtail.wagtailcore.blocks.ChoiceBlock(choices=wagtail_personalisation.blocks.list_segment_choices, help_text='Only show this content block for users in this segment', label='Personalisation segment', required=False)), ('image', wagtail.wagtailimages.blocks.ImageChooserBlock(label='Image'))))), ('personalised_char', wagtail.wagtailcore.blocks.StructBlock((('segment', wagtail.wagtailcore.blocks.ChoiceBlock(choices=wagtail_personalisation.blocks.list_segment_choices, help_text='Only show this content block for users in this segment', label='Personalisation segment', required=False)), ('char', wagtail.wagtailcore.blocks.CharBlock(label='Text'))))), ('personalised_text', wagtail.wagtailcore.blocks.StructBlock((('segment', wagtail.wagtailcore.blocks.ChoiceBlock(choices=wagtail_personalisation.blocks.list_segment_choices, help_text='Only show this content block for users in this segment', label='Personalisation segment', required=False)), ('text', wagtail.wagtailcore.blocks.TextBlock(label='Mutli-line Text')))))))),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=('wagtailcore.page',),
|
||||
),
|
||||
]
|
@ -5,8 +5,11 @@ from wagtail.core import blocks
|
||||
from wagtail.core.fields import RichTextField, StreamField
|
||||
from wagtail.core.models import Page
|
||||
|
||||
from wagtail_personalisation.blocks import (
|
||||
PersonalisedCharBlock, PersonalisedImageChooserBlock,
|
||||
PersonalisedRichTextBlock, PersonalisedStructBlock,
|
||||
PersonalisedTextBlock)
|
||||
from wagtail_personalisation.models import PersonalisablePageMixin
|
||||
from wagtail_personalisation.blocks import PersonalisedStructBlock
|
||||
|
||||
|
||||
class HomePage(PersonalisablePageMixin, Page):
|
||||
@ -21,3 +24,24 @@ class HomePage(PersonalisablePageMixin, Page):
|
||||
RichTextFieldPanel('intro'),
|
||||
StreamFieldPanel('body'),
|
||||
]
|
||||
|
||||
|
||||
class PersonalisedFieldsPage(Page):
|
||||
body = StreamField([
|
||||
('personalised_block', PersonalisedStructBlock([
|
||||
('heading', blocks.CharBlock()),
|
||||
('paragraph', blocks.RichTextBlock())
|
||||
], render_fields=['heading', 'paragraph'])),
|
||||
('personalised_block_template', PersonalisedStructBlock([
|
||||
('heading', blocks.CharBlock()),
|
||||
('paragraph', blocks.RichTextBlock())
|
||||
], template='blocks/personalised_block_template.html', label=_('Block with template'))),
|
||||
('personalised_rich_text_block', PersonalisedRichTextBlock()),
|
||||
('personalised_image', PersonalisedImageChooserBlock()),
|
||||
('personalised_char', PersonalisedCharBlock()),
|
||||
('personalised_text', PersonalisedTextBlock()),
|
||||
])
|
||||
|
||||
content_panels = Page.content_panels + [
|
||||
StreamFieldPanel('body')
|
||||
]
|
||||
|
@ -0,0 +1,9 @@
|
||||
{% load wagtailcore_tags %}
|
||||
|
||||
<div class="personalisation-block-template" style="background-color: cornsilk;">
|
||||
<p>This is a block with <strong>template</strong>.</p>
|
||||
<h2>Heading: {{ value.heading }}</h2>
|
||||
<div>
|
||||
{{ value.paragraph|richtext }}
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,15 @@
|
||||
{% extends "base.html" %}
|
||||
{% load wagtailcore_tags %}
|
||||
|
||||
{% block body_class %}template-homepage{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ page.title }}</h1>
|
||||
{% for block in page.body %}
|
||||
<section class="section-{{ block.block_type }}">
|
||||
<p><em>Section for {{ block.block_type }}.</em></p>
|
||||
{% include_block block %}
|
||||
</section>
|
||||
<hr>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
@ -1,25 +1,85 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from wagtail.core import blocks
|
||||
from wagtail.images.blocks import ImageChooserBlock
|
||||
|
||||
from wagtail_personalisation.adapters import get_segment_adapter
|
||||
from wagtail_personalisation.models import Segment
|
||||
|
||||
|
||||
def list_segment_choices():
|
||||
"""Get a list of segment choices visible in the admin site when editing
|
||||
BasePersonalisedStructBlock and its derived classes."""
|
||||
yield (-1, _('Visible to everyone'))
|
||||
|
||||
for pk, name in Segment.objects.values_list('pk', 'name'):
|
||||
yield pk, name
|
||||
|
||||
|
||||
class PersonalisedStructBlock(blocks.StructBlock):
|
||||
"""Struct block that allows personalisation per block."""
|
||||
|
||||
class BasePersonalisedStructBlock(blocks.StructBlock):
|
||||
"""Base class for personalised struct blocks."""
|
||||
segment = blocks.ChoiceBlock(
|
||||
choices=list_segment_choices,
|
||||
required=False, label=_("Personalisation segment"),
|
||||
help_text=_("Only show this content block for users in this segment"))
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Instantiate personalised struct block.
|
||||
|
||||
The arguments are the same as for the blocks.StructBlock constructor and
|
||||
one addtional one.
|
||||
|
||||
Keyword Arguments:
|
||||
render_fields: List with field names to be rendered or None to use
|
||||
the default block rendering. Please set to None if using block
|
||||
with template since then it's the template that takes care
|
||||
of what fields are rendered.
|
||||
"""
|
||||
render_fields = kwargs.pop('render_fields',
|
||||
self._meta_class.render_fields)
|
||||
super(BasePersonalisedStructBlock, self).__init__(*args, **kwargs)
|
||||
|
||||
# Check "render_fields" are either a list or None.
|
||||
if isinstance(render_fields, tuple):
|
||||
render_fields = list(render_fields)
|
||||
|
||||
if render_fields is not None \
|
||||
and not isinstance(render_fields, list):
|
||||
raise ValueError('"render_fields" has to be a list or None.')
|
||||
elif isinstance(render_fields, list) \
|
||||
and not set(render_fields).issubset(self.child_blocks):
|
||||
raise ValueError('"render_fields" has to contain name(s) of the '
|
||||
'specified blocks.')
|
||||
else:
|
||||
setattr(self.meta, 'render_fields', render_fields)
|
||||
|
||||
# Template can be used only when "render_fields" is set to None.
|
||||
if self.meta.render_fields is not None \
|
||||
and getattr(self.meta, 'template', None):
|
||||
raise ValueError('"render_fields" has to be set to None when using '
|
||||
'template.')
|
||||
|
||||
def is_visible(self, value, request):
|
||||
"""Check whether user should see the block based on their segments.
|
||||
|
||||
:param value: The value from the block.
|
||||
:type value: dict
|
||||
:returns: True if user should see the block.
|
||||
:rtype: bool
|
||||
|
||||
"""
|
||||
if int(value['segment']) == -1:
|
||||
return True
|
||||
|
||||
if value['segment']:
|
||||
for segment in get_segment_adapter(request).get_segments():
|
||||
if segment.id == int(value['segment']):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def render(self, value, context=None):
|
||||
"""Only render this content block for users in this segment.
|
||||
|
||||
@ -31,14 +91,80 @@ class PersonalisedStructBlock(blocks.StructBlock):
|
||||
:rtype: blocks.StructBlock or empty str
|
||||
|
||||
"""
|
||||
request = context['request']
|
||||
adapter = get_segment_adapter(request)
|
||||
user_segments = adapter.get_segments()
|
||||
if not self.is_visible(value, context['request']):
|
||||
return ""
|
||||
|
||||
if value['segment']:
|
||||
for segment in user_segments:
|
||||
if segment.id == int(value['segment']):
|
||||
return super(PersonalisedStructBlock, self).render(
|
||||
value, context)
|
||||
if self.meta.render_fields is None:
|
||||
return super(BasePersonalisedStructBlock, self).render(
|
||||
value, context)
|
||||
|
||||
return ""
|
||||
if isinstance(self.meta.render_fields, list):
|
||||
render_value = ''
|
||||
for field_name in self.meta.render_fields:
|
||||
if hasattr(value.bound_blocks[field_name], 'render_as_block'):
|
||||
block_value = value.bound_blocks[field_name].render_as_block(context=context)
|
||||
else:
|
||||
block_value = force_text(value[field_name])
|
||||
|
||||
if block_value != 'None':
|
||||
render_value += block_value
|
||||
|
||||
return render_value
|
||||
|
||||
raise RuntimeError('"render_fields" is neither "None" or "list" '
|
||||
'during rendering.')
|
||||
|
||||
class Meta:
|
||||
"""
|
||||
Setting render field will define which field gets rendered.
|
||||
Please use a name of the field. If none, it will render the whole block.
|
||||
"""
|
||||
render_fields = None
|
||||
|
||||
|
||||
class PersonalisedStructBlock(BasePersonalisedStructBlock):
|
||||
"""Struct block that allows personalisation per block."""
|
||||
|
||||
class Meta:
|
||||
label = _('Personalised Block')
|
||||
render_fields = None
|
||||
|
||||
|
||||
class PersonalisedRichTextBlock(BasePersonalisedStructBlock):
|
||||
"""Rich text block that allows personalisation."""
|
||||
rich_text = blocks.RichTextBlock(label=_('Rich Text'))
|
||||
|
||||
class Meta:
|
||||
icon = blocks.RichTextBlock._meta_class.icon
|
||||
label = _('Personalised Rich Text')
|
||||
render_fields = ['rich_text']
|
||||
|
||||
|
||||
class PersonalisedTextBlock(BasePersonalisedStructBlock):
|
||||
"""Text block that allows personalisation."""
|
||||
text = blocks.TextBlock(label=_('Mutli-line Text'))
|
||||
|
||||
class Meta:
|
||||
icon = blocks.TextBlock._meta_class.icon
|
||||
label = _('Personalised Multi-line Text')
|
||||
render_fields = ['text']
|
||||
|
||||
|
||||
class PersonalisedCharBlock(BasePersonalisedStructBlock):
|
||||
"""Char block that allows personalisation."""
|
||||
char = blocks.CharBlock(label=_('Text'))
|
||||
|
||||
class Meta:
|
||||
icon = blocks.CharBlock._meta_class.icon
|
||||
label = _('Personalised Single-line Text')
|
||||
render_fields = ['char']
|
||||
|
||||
|
||||
class PersonalisedImageChooserBlock(BasePersonalisedStructBlock):
|
||||
"""Image chooser block that allows personalisation."""
|
||||
image = ImageChooserBlock(label=_('Image'))
|
||||
|
||||
class Meta:
|
||||
icon = ImageChooserBlock._meta_class.icon
|
||||
label = _('Personalised Image')
|
||||
render_fields = ['image']
|
||||
|
Reference in New Issue
Block a user