diff --git a/blog/blocks.py b/blog/blocks.py index dded4d3..dc42348 100644 --- a/blog/blocks.py +++ b/blog/blocks.py @@ -1,4 +1,4 @@ -from wagtail.blocks import RichTextBlock +from wagtail.blocks import RichTextBlock, BlockQuoteBlock from wagtail.embeds.blocks import EmbedBlock from base.blocks import StreamBlock, HeadingBlock, ImageBlock @@ -6,6 +6,7 @@ from wagtailcodeblock.blocks import CodeBlock class BlogPostBlock(StreamBlock): heading_block = HeadingBlock() + blockquote = BlockQuoteBlock() paragraph = RichTextBlock(blank=True) code = CodeBlock(label='Code snippet') image_block = ImageBlock() diff --git a/blog/migrations/0014_alter_blogpage_body.py b/blog/migrations/0014_alter_blogpage_body.py new file mode 100644 index 0000000..1218862 --- /dev/null +++ b/blog/migrations/0014_alter_blogpage_body.py @@ -0,0 +1,22 @@ +# Generated by Django 5.0.2 on 2024-04-05 16:56 + +import wagtail.blocks +import wagtail.embeds.blocks +import wagtail.fields +import wagtail.images.blocks +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('blog', '0013_alter_blogpage_body'), + ] + + operations = [ + migrations.AlterField( + model_name='blogpage', + name='body', + field=wagtail.fields.StreamField([('heading_block', wagtail.blocks.StructBlock([('heading_text', wagtail.blocks.CharBlock(form_classname='title', required=True)), ('size', wagtail.blocks.ChoiceBlock(blank=True, choices=[('', 'Select a heading size'), ('h2', 'H2'), ('h3', 'H3'), ('h4', 'H4')], required=False))])), ('blockquote', wagtail.blocks.BlockQuoteBlock()), ('paragraph', wagtail.blocks.RichTextBlock(blank=True)), ('code', wagtail.blocks.StructBlock([('language', wagtail.blocks.ChoiceBlock(choices=[('bash', 'Bash/Shell'), ('css', 'CSS'), ('dart', 'Dart'), ('docker', 'Docker'), ('elixir', 'Elixir'), ('go', 'Go'), ('html', 'HTML'), ('javascript', 'Javascript'), ('json', 'JSON'), ('kotlin', 'Kotlin'), ('python', 'Python'), ('rust', 'Rust'), ('swift', 'Swift'), ('toml', 'TOML'), ('yaml', 'YAML')], help_text='Coding language', identifier='language', label='Language')), ('code', wagtail.blocks.TextBlock(identifier='code', label='Code'))], label='Code snippet')), ('image_block', wagtail.blocks.StructBlock([('image', wagtail.images.blocks.ImageChooserBlock(required=True)), ('caption', wagtail.blocks.CharBlock(required=False)), ('attribution', wagtail.blocks.CharBlock(required=False))])), ('embed_block', wagtail.embeds.blocks.EmbedBlock(help_text='Insert a URL to embed. For example, https://www.youtube.com/watch?v=SGJFWirQ3ks', icon='media'))], blank=True, help_text='Write anything'), + ), + ] diff --git a/blog/models.py b/blog/models.py index d98a731..2f0c893 100644 --- a/blog/models.py +++ b/blog/models.py @@ -14,6 +14,7 @@ from wagtail.snippets.models import register_snippet from blog.blocks import BlogPostBlock from wagtailseo.models import SeoMixin, SeoType + class BlogIndexPage(SeoMixin, Page): intro = RichTextField(blank=True) @@ -29,6 +30,7 @@ class BlogIndexPage(SeoMixin, Page): ] promote_panels = SeoMixin.seo_panels + class BlogTagIndexPage(Page): def get_context(self, request): @@ -40,6 +42,7 @@ class BlogTagIndexPage(Page): context['blogpages'] = blogpages return context + class BlogPageTag(TaggedItemBase): content_object = ParentalKey( 'BlogPage', @@ -47,6 +50,7 @@ class BlogPageTag(TaggedItemBase): on_delete=models.CASCADE ) + class BlogPage(SeoMixin, Page): date = models.DateField("Post date") intro = models.TextField() @@ -104,6 +108,7 @@ class BlogPageGalleryImage(Orderable): FieldPanel('caption'), ] + @register_snippet class Author(models.Model): name = models.CharField(max_length=255) @@ -121,4 +126,4 @@ class Author(models.Model): return self.name class Meta: - verbose_name_plural = 'Authors' \ No newline at end of file + verbose_name_plural = 'Authors' diff --git a/home/blocks.py b/home/blocks.py new file mode 100644 index 0000000..1cd28c3 --- /dev/null +++ b/home/blocks.py @@ -0,0 +1,16 @@ +from wagtail.blocks import RichTextBlock, BlockQuoteBlock +from wagtail.embeds.blocks import EmbedBlock + +from base.blocks import StreamBlock, HeadingBlock, ImageBlock +from wagtailcodeblock.blocks import CodeBlock + +class HomeContentBlock(StreamBlock): + heading_block = HeadingBlock() + paragraph = RichTextBlock(blank=True) + code = CodeBlock(label='Code snippet') + blockquote = BlockQuoteBlock() + image_block = ImageBlock() + embed_block = EmbedBlock( + help_text="Insert a URL to embed. For example, https://www.youtube.com/watch?v=SGJFWirQ3ks", + icon="media", + ) \ No newline at end of file diff --git a/home/migrations/0006_alter_homepage_body.py b/home/migrations/0006_alter_homepage_body.py new file mode 100644 index 0000000..7a0ecf6 --- /dev/null +++ b/home/migrations/0006_alter_homepage_body.py @@ -0,0 +1,136 @@ +# Generated by Django 5.0.2 on 2024-04-05 16:56 + +import json +import wagtail.blocks +import wagtail.embeds.blocks +import wagtail.fields +import wagtail.images.blocks + +from django.core.serializers.json import DjangoJSONEncoder +from django.db import migrations + + +def convert_to_streamfield(apps, schema_editor): + HomePage = apps.get_model("home", "HomePage") + for page in HomePage.objects.all(): + page.body = json.dumps( + [{"type": "paragraph", "value": page.body}], + cls=DjangoJSONEncoder + ) + page.save() + + +def convert_to_richtext(apps, schema_editor): + HomePage = apps.get_model("home", "HomePage") + for page in HomePage.objects.all(): + if page.body: + stream = json.loads(page.body) + page.body = "".join([ + child["value"] for child in stream + if child["type"] == "paragraph" + ]) + page.save() + + +class Migration(migrations.Migration): + dependencies = [ + ('home', '0005_homepage_canonical_url_homepage_og_image_and_more'), + ] + + operations = [ + migrations.RunPython( + convert_to_streamfield, + convert_to_richtext, + ), + + migrations.AlterField( + model_name='homepage', + name='body', + field=wagtail.fields.StreamField([('heading_block', wagtail.blocks.StructBlock( + [('heading_text', wagtail.blocks.CharBlock(form_classname='title', required=True)), ('size', + wagtail.blocks.ChoiceBlock( + blank=True, + choices=[('', + 'Select a heading size'), + ('h2', + 'H2'), + ('h3', + 'H3'), + ('h4', + 'H4')], + required=False))])), + ('paragraph', wagtail.blocks.RichTextBlock(blank=True)), ('code', + wagtail.blocks.StructBlock( + [( + 'language', + wagtail.blocks.ChoiceBlock( + choices=[ + ( + 'bash', + 'Bash/Shell'), + ( + 'css', + 'CSS'), + ( + 'dart', + 'Dart'), + ( + 'docker', + 'Docker'), + ( + 'elixir', + 'Elixir'), + ( + 'go', + 'Go'), + ( + 'html', + 'HTML'), + ( + 'javascript', + 'Javascript'), + ( + 'json', + 'JSON'), + ( + 'kotlin', + 'Kotlin'), + ( + 'python', + 'Python'), + ( + 'rust', + 'Rust'), + ( + 'swift', + 'Swift'), + ( + 'toml', + 'TOML'), + ( + 'yaml', + 'YAML')], + help_text='Coding language', + identifier='language', + label='Language')), + ('code', + wagtail.blocks.TextBlock( + identifier='code', + label='Code'))], + label='Code snippet')), + ('blockquote', wagtail.blocks.BlockQuoteBlock()), ('image_block', + wagtail.blocks.StructBlock( + [('image', + wagtail.images.blocks.ImageChooserBlock( + required=True)), + ('caption', + wagtail.blocks.CharBlock( + required=False)), + ('attribution', + wagtail.blocks.CharBlock( + required=False))])), + ('embed_block', wagtail.embeds.blocks.EmbedBlock( + help_text='Insert a URL to embed. For example, https://www.youtube.com/watch?v=SGJFWirQ3ks', + icon='media'))], blank=True, help_text='Write anything'), + ), + ] diff --git a/home/models.py b/home/models.py index 66e2d6c..cab0e1d 100644 --- a/home/models.py +++ b/home/models.py @@ -1,9 +1,10 @@ from django.db import models from wagtail.models import Page -from wagtail.fields import RichTextField +from wagtail.fields import RichTextField, StreamField from wagtail.admin.panels import FieldPanel, MultiFieldPanel from wagtailseo.models import SeoMixin +from .blocks import HomeContentBlock class HomePage(SeoMixin, Page): @@ -34,7 +35,12 @@ class HomePage(SeoMixin, Page): verbose_name="Hero CTA link", help_text="Choose a page to link to for the Call to Action", ) - body = RichTextField(blank=True) + body = StreamField( + HomeContentBlock(), + blank=True, + use_json_field=True, + help_text="Write anything", + ) content_panels = Page.content_panels + [ MultiFieldPanel( diff --git a/home/templates/home/home_page.html b/home/templates/home/home_page.html index 0fdafa9..9e7141f 100644 --- a/home/templates/home/home_page.html +++ b/home/templates/home/home_page.html @@ -19,7 +19,7 @@
- {{ page.body|richtext }} + {{ page.body }}