Débuter avec le CMS Wagtail

18 janvier 2021 Etienne Tutoriels 1367 vues
Débuter avec le CMS Wagtail

Photo de Lukas provenant de Pexels

Wagtail est un CMS basé sur le framework Django, lequel est écrit en Python. Dans cet article je vais vous présenter comment mettre en place Wagtail et créer la page d'accueil de notre site.

La première chose à faire est de mettre en place l'environnement de développement sur notre poste de travail. Pour ce faire nous allons utiliser un environnement virtuel proposé par Python, pour éviter de mélanger les librairies que nous allons utiliser avec vos autres projets.

Dans une deuxième phase nous allons installer et configurer Wagtail pour qu'il soit prêt à recevoir notre site.

Installation de l'environnement de développement

Je développe toujours depuis un environnement Linux (Ubuntu et Debian), les commandes qui suivent sont donc plus orientées pour ces OS, mais ils ne devraient pas beaucoup différer pour Windows ou MacOS.

Commençons par créer un dossier au nom de notre projet dans lequel nous installons l'environnement virtuel :

Bash
mkdir -p ~/projets/mon_site
cd ~/projets/mon_site
python3 -m venv env

Une fois l'environnement créé (un nouveau dossier nommé env est apparu), nous devons l'activer avec la commande suivante :

Bash
source env/bin/activate

Sous Windows il faut utiliser la commande suivante :

Bash
.\env\Scripts\activate

Installation de Wagtail

Nous installons Wagtail, et tous les packages qui lui sont nécessaires, avec la commande suivante (vérifiez toujours avant que vous êtes bien dans votre environnement virtuel, sinon les packages seront mélangés avec ceux de votre OS) :

Bash
pip install wagtail

Une fois installé, Wagtail dispose d'une commande similaire à celle de Django django-admin startproject pour générer un nouveau site/projet :

Bash
mkdir app
wagtail start mon_site app

Nous avons ainsi installé tous les répertoires et fichiers nécessaires à Wagtail dans un sous-répertoire nommé app afin de séparer les données du site avec les autres outils dont nous aurons besoin plus tard (par exemple pour "Dockeriser" notre site et pour le déploiement en production).

On se déplace ensuite dans notre répertoire nouvellement créé et nous procédons aux étapes de mise en place nécessaires à tout projet Django.

Pour commencer, on met à jour les dépendances du projet :

Bash
cd app
pip install -r requirements.txt

On applique ensuite les migrations à la base de données et on crée un super-utilisateur :

Bash
python manage.py migrate
python manage.py createsuperuser

Finalement nous lançons le serveur local comme pour chaque projet Django :

Bash
python manage.py runserver

Notre application est dès lors disponible à l'url http://localhost:8000/ et se présente comme suit :

Wagtail-homepage.png
Page d'accueil par défaut de Wagtail

Comme vous pouvez le voir, la page d'accueil du site est une page provisoire qui nous indique que notre installation fonctionne bien. Nous allons voir dans la suite de cet article comment procéder pour créer une page d'accueil sur mesure.

L'admin de Wagtail est disponible à l'url http://localhost:8000/admin/ et nous pouvons nous y connecter avec le super-utilisateur créé précédemment.

Connexion-admin-Wagtail.png
Connexion à l'admin de Wagtail
Interface-admin-Wagtail.png
Interface de l'admin de Wagtail

S'agissant d'un CMS basé sur Django, l'admin de Django reste disponible à l'url http://localhost:8000/django-admin/.

Création de la page d'accueil du site

Lorsque nous avons installé Wagtail, celui-ci nous a automatiquement créé une app nommée home. C'est dans cette app que nous allons gérer notre page d'accueil ainsi que les pages simples de notre site (par exemple, page "À propos", "Contact", etc.).

Nous allons commencer par créer le modèle de notre page d'accueil. Pour ce faire, nous ouvrons le fichier app/home/models.py et nous y ajoutons le code suivant :

Python mon_site/app/home/models.py
from django.db import models

from wagtail.core.models import Page
from wagtail.core.fields import StreamField
from wagtail.core import blocks
from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel
from wagtail.images.blocks import ImageChooserBlock


class HomePage(Page):
    body = StreamField([
        ('paragraph', blocks.RichTextBlock(
            label='Paragraphe', features=['h1', 'h2', 'h3', 'bold', 'italic', 'link', 'hr']
        )),
        ('image', ImageChooserBlock()),
    ], verbose_name='Contenu', null=True)

    content_panels = Page.content_panels + [
        StreamFieldPanel('body', classname="full"),
    ]

    class Meta:
        verbose_name = "page d'accueil"

Nous aurions pu n'utiliser qu'un RichTextField (un éditeur de texte simple) au lieu du StreamField, mais comme nous le verrons par la suite, un StreamField permet de créer des pages bien plus complexes et en utilisant des templates sur mesure pour chaque partie du code, ce que ne permet pas un RichTextField.

Pour que notre code soit utilisable, nous devons créer une migration de la base de donnée, puis appliquer cette migration. Depuis notre dossier app/ :

Bash
python manage.py makemigrations home
python manage.py migrate

Pour pouvoir afficher notre page d'accueil sur le site il nous faut un template. Pour chaque classe héritant de la classe Page, le chemin du template pour cette class ese trouve dans app/mon_app/templates/mon_app/maclasse_page.html, maclasse_page.html découlant du nom de notre classe class MaclassePage(Page). Dès lors, pour notre modèle/classe HomePage de l'app home, le template se trouve dans app/home/templates/home/home_page.html. Ce fichier a été automatiquement créé par Wagtail lors de son installation, mais pour les prochaines classes héritant de Page nous devrons créer nous-même les templates.

Ouvrons le fichier app/home/templates/home/home_page.html et remplaçons son contenu par le code suivant :

Python mon_site/app/home/templates/home/home_page.html
{% extends "base.html" %}
{% load static wagtailcore_tags wagtailimages_tags %}

{% block body_class %}template-homepage{% endblock %}

{% block content %}
    {% for block in page.body %}
    <div class="row">
        <div class="col">
            {% include_block block %}
        </div>
    </div>
    {% endfor %}
{% endblock content %}

Dans l'interface d'admin de notre site (http://localhost:8000/admin), nous cliquons sur Pages puis sur le crayon à droite de Home.

Modifier page accueil Wagtail
Pour modifier la page d'accueil de notre site

Nous pouvons dès lors saisir le titre de notre page (qui sera affiché dans la barre de titre du navigateur) et le contenu de notre page. Le fait d'avoir utilisé un StreamField pour le contenu de notre page plutôt qu'un simple RichTextField nous permet de choisir si nous voulons saisir du texte ou une image, puis, en cliquant sur le + qui s'affiche en dessous, nous pouvons compléter notre page avec à nouveau le choix entre du texte ou une image.

Compléter homepage Wagtail
Page d'accueil vide prête à être complétée
Compléter homepage Wagtail
On ajoute un texte puis une image

Une fois votre page d'accueil complétée, n'oubliez pas de cliquer sur le bouton Save Draft pour sauvegarder vos données. En cliquant ensuite sur le bouton Preview nous pouvons avoir un aperçu de ce que donnera notre page une fois publiée. Si la page vous semble correcte, vous pouvez cliquer sur la petite flèche à droite du bouton Save Draft puis, dans le menu déroulant qui s'affiche, cliquer sur Publish. La page d'accueil de notre site a ainsi été modifiée et nous pouvons la voir en allant sur notre site http://localhost:8000.

Changer la langue de l'interface d'admin

Vous aurez constaté que l'interface d'admin de Wagtail est en anglais. Pourtant une traduction française est disponible. Si vous désirez garder l'anglais par défaut pour le site mais utiliser le français pour l'interface d'admin, vous pouvez cliquer sur la flèche à droite de votre nom d'utilisateur, dans le menu en bas à gauche de l'interface d'admin et cliquer sur Account Settings. Ensuite cliquez sur Language Preferences, sélectionnez French dans le menu déroulant et cliquez sur Update. L'interface d'admin est dorénavant en francais, victoire !

Néanmoins elle n'est en français que pour vous. Si un autre utilisateur se connecte à l'interface d'admin elle sera à nouveau en anglais. Si la majorité de vos utilisateurs est francophone, il est préférable d'effectuer la modification globalement. Pour ce faire nous modifions le fichier app/mon_site/settings/base.py et nous remplaçons la ligne LANGUAGE_CODE = 'en-us' par LANGUAGE_CODE = 'fr-ch' (pour le français de Suisse, sinon fr-fr pour la France, fr-ca pour le Canada, etc.).

Python mon_site/app/mon_site/settings/base.py
#LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'fr-ch'

Ce code change la lange par défaut de votre site, c'est à dire aussi de la partie visible par vos visiteurs. Il faut en tenir compte si votre site est multilingue.

On peut aussi en profiter pour adapter le fuseau horaire avec le code suivant :

Python mon_site/app/mon_site/settings/base.py
#TIME_ZONE = 'UTC'
TIME_ZONE = 'Europe/Zurich'

On sauvegarde le fichier et on rafraîchit l'interface d'admin de notre site. Il est dorénavant en français par défaut pour tous les utilisateurs. Ceux-ci peuvent néanmoins choisir une autre langue en utilisant le cheminement indiqué précédemment.

Si après avoir modifié la langue par défaut de votre site Wagtail vous avez une erreur de type ValidationError avec l'indication {'locale': ["L'instance locale avec l'id 1 n'existe pas"]}, vous devez rajouter l'app wagtail.locales dans le fichier app/mon_site/settings/base.py, puis dans l'admin de Wagtail, dans Paramètres -> Régions, sélectionner la langue désirée.

Python mon_site/app/mon_site/settings/base.py
...
    'wagtail.core',
    'wagtail.locales',
...

Intégrer Bootstrap pour améliorer la ligne graphique

Vous l'aurez sans doute remarqué, le graphisme par défaut de notre site est... inexistant ! En effet, Wagtail fournit une interface d'admin très léchée, mais nous laisse le champs vierge pour la partie visiteur.

Pour y remédier, je vous propose d'ajouter Bootstrap pour obtenir rapidement une ligne graphique plus élégante.

Ouvrons le fichier app/mon_site/templates/base.html et ajoutons le code fourni par Bootstrap pour le CSS dans la partie indiquée dans le commentaire {# Global stylesheets #} comme suit :

Django mon_site/app/mon_site/templates/base.html
{# Global stylesheets #}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="{% static 'css/mon_site.css' %}">

Dans le même fichier, dans la section {# Global javascript #} nous ajoutons le code suivant :

Django mon_site/app/mon_site/templates/base.html
{# Global javascript #}
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx" crossorigin="anonymous"></script>
<script type="text/javascript" src="{% static 'js/mon_site.js' %}"></script>

Puis, toujours dans le même fichier, nous entourons le code {% block content %}{% endblock %} d'un <div class="container">...</div> afin de centrer notre contenu dans la page.

Django mon_site/app/mon_site/templates/base.html
<div class="container">
    {% block content %}{% endblock %}
</div>

Finalement, nous ajoutons un entête à notre site avec le code suivant, toujours dans le même fichier, juste après le code <body class="body {% block body_class %}{% endblock %}">{% wagtailuserbar %} :

Django mon_site/app/mon_site/templates/base.html
<nav class="navbar navbar-expand-lg navbar-light bg-light mb-3">
    <div class="container">
        <a class="navbar-brand" href="{% url 'wagtail_serve' '' %}">{% with self.get_site.site_name as site_name %}{% if site_name %}{{ site_name }}{% else %}Mon Site{% endif %}{% endwith %}</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
    </div>
</nav>

Notre fichier doit dorénavant ressembler à cela :

Django mon_site/app/mon_site/templates/base.html
{% load static wagtailuserbar %}

<!DOCTYPE html>
<html class="no-js" lang="en">
    <head>
        <meta charset="utf-8" />
        <title>
            {% block title %}
                {% if self.seo_title %}{{ self.seo_title }}{% else %}{{ self.title }}{% endif %}
            {% endblock %}
            {% block title_suffix %}
                {% with self.get_site.site_name as site_name %}
                    {% if site_name %}- {{ site_name }}{% endif %}
                {% endwith %}
            {% endblock %}
        </title>
        <meta name="description" content="" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />

        {# Global stylesheets #}
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
        <link rel="stylesheet" type="text/css" href="{% static 'css/mon_site.css' %}">

        {% block extra_css %}
            {# Override this in templates to add extra stylesheets #}
        {% endblock %}
    </head>

    <body class="{% block body_class %}{% endblock %}">
        {% wagtailuserbar %}

        <nav class="navbar navbar-expand-lg navbar-light bg-light mb-3">
            <div class="container">
                <a class="navbar-brand" href="{% url 'wagtail_serve' '' %}">{% with self.get_site.site_name as site_name %}{% if site_name %}{{ site_name }}{% else %}Mon Site{% endif %}{% endwith %}</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
            </div>
        </nav>

        <div class="container">
            {% block content %}{% endblock %}
        </div>

        {# Global javascript #}
        <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx" crossorigin="anonymous"></script>
        <script type="text/javascript" src="{% static 'js/mon_site.js' %}"></script>

        {% block extra_js %}
            {# Override this in templates to add extra javascript #}
        {% endblock %}
    </body>
</html>

Avez-vous remarqué le code {% with self.get_site.site_name as site_name %}{% if site_name %}{{ site_name }}{% else %}Mon Site{% endif %}{% endwith %} dans l'entête que nous venons d'ajouter ? Wagtail fourni automatiquement le nom de notre site une fois que nous l'avons indiqué dans l'interface d'admin. Pour ce faire nous devons aller dans Paramètres -> Sites et indiquer le nom de notre site dans le champ... Nom du site.

Wagtail : indiquer le nom du site
Changer le nom de notre site

Ajouter l'affichage en colonnes dans notre StreamField

Nous commençons à pouvoir créer une page d'accueil pas trop mal, mais ce serait nettement mieux si nous pouvions décider de placer certains contenus dans des colonnes.

Nous allons créer de nouveaux blocks que nous intégrerons à notre StreamField et qui nous permettrons de définir du contenu sur 2 ou 3 colonnes. Pour cela nous créons un fichier blocks.py dans notre app home et nous y ajoutons le code suivant :

Python mon_site/app/home/blocks.py
from wagtail.core import blocks
from wagtail.images.blocks import ImageChooserBlock


class ColumnBlock(blocks.StreamBlock):
    paragraph = blocks.RichTextBlock(label='Paragraphe')
    image = ImageChooserBlock()

    class Meta:
        template = 'blocks/column.html'


class TwoColumnBlock(blocks.StructBlock):
    position = blocks.ChoiceBlock(choices=[
        ('left', '70%-30%'),
        ('middle', '50%-50%'),
        ('right', '30%-70%')
    ], label="Disposition des colonnes")
    left_column = ColumnBlock(icon='arrow-left', label='Colonne de gauche')
    right_column = ColumnBlock(icon='arrow-right', label='Colonne de droite')

    class Meta:
        template = 'blocks/two_column_block.html'
        icon = 'placeholder'
        label = 'Deux Colonnes'


class ThreeColumnBlock(blocks.StructBlock):
    left_column = ColumnBlock(icon='arrow-left', label='Colonne de gauche')
    middle_column = ColumnBlock(label='Colonne centrale')
    right_column = ColumnBlock(icon='arrow-right', label='Colonne de droite')

    class Meta:
        template = 'blocks/three_column_block.html'
        icon = 'placeholder'
        label = 'Trois Colonnes'

Puis dans le fichier models.py, toujours dans notre app home, nous intégrons ces nouveaux blocks à notre StreamField. Nous commençons par importer ces classes nouvellement créées :

Python mon_site/app/home/models.py
from .blocks import TwoColumnBlock, ThreeColumnBlock

Puis nous mettons à jour la classe HomePage comme suit :

Python mon_site/app/home/models.py
class HomePage(Page):
    body = StreamField([
        ('paragraph', blocks.RichTextBlock(
            label='Paragraphe', features=['h1', 'h2', 'h3', 'bold', 'italic', 'link', 'hr']
        )),
        ('image', ImageChooserBlock()),
        ('two_columns', TwoColumnBlock()),
        ('three_columns', ThreeColumnBlock()),
    ], verbose_name='Contenu', null=True)

...

Une fois le modèle adapté, nous devons créer une nouvelle migrations de la base de données et l'appliquer avec les commandes suivantes :

Bash
python3 manage.py makemigrations home
python3 manage.py migrate

Finalement nous devons créer les templates qui nous permettrons d'appliquer la mise en page désirée.

Nous créons tout d'abord le template qui permet de créer une colonne, nous créons le fichier app/home/templates/blocks/column.html et y ajoutons le code suivant :

Django mon_site/app/home/templates/blocks/column.html
{% load wagtailcore_tags wagtailimages_tags %}

{% if blocks %}

    {% for block in blocks %}
        {% if block.block_type == 'image' %}
            <section class="block-{{ block.block_type }} text-center">
                {% image block.value width-420 class="img-responsive" %}
            </section>
        {% else %}
           <section class="block-{{ block.block_type }}">
               {{ block }}
           </section>
        {% endif %}
    {% endfor %}

{% endif %}

Puis nous créons le fichier app/home/templates/blocks/two_column_block.html avec ce code :

Django mon_site/app/home/templates/blocks/two_column_block.html
{% load wagtailcore_tags %}
<div class="row my-3">

    {% if self.position == 'left' %}
        <div class="col-md-7">
            {% for block in self.left_column %}
                {% include_block block %}
            {% endfor %}
        </div>
        <div class="col-md-5">
            {% for block in self.right_column %}
                {% include_block block %}
            {% endfor %}
        </div>
    {% elif self.position == 'middle' %}
        <div class="col-md-6">
            {% for block in self.left_column %}
                {% include_block block %}
            {% endfor %}
        </div>
        <div class="col-md-6">
            {% for block in self.right_column %}
                {% include_block block %}
            {% endfor %}
        </div>
    {% else %}
        <div class="col-md-5">
            {% for block in self.left_column %}
                {% include_block block %}
            {% endfor %}
        </div>
        <div class="col-md-7">
            {% for block in self.right_column %}
                {% include_block block %}
            {% endfor %}
        </div>
    {% endif %}

</div>

Finalement, nous créons le fichier app/home/templates/blocks/three_column_block.html comme suit :

Django mon_site/app/home/templates/blocks/three_column_block.html
{% load wagtailcore_tags %}
<div class="row my-3">

    <div class="col-md-4">
        {% for block in self.left_column %}
            {% include_block block %}
        {% endfor %}
    </div>
    <div class="col-md-4">
        {% for block in self.middle_column %}
            {% include_block block %}
        {% endfor %}
    </div>
    <div class="col-md-4">
        {% for block in self.right_column %}
            {% include_block block %}
        {% endfor %}
    </div>

</div>

Nous pouvons dorénavant créer une page d'accueil bien plus complexe.

Wagtail affichage en colonnes
Page d'accueil avec l'affichage en colonnes

Dans mon prochain article je vous montre comment ajouter des pages classiques à notre site et y intégrer un menu. Ensuite nous ajouterons un blog à notre site.

D'ici là, n'hésitez pas à laisser vos commentaires ci-dessous, je me ferai un plaisir de les lire et d'y répondre.

Si vous n'êtes pas sûr de votre code, vous pouvez retrouver tout le code présenté ci-dessus sur le repo Github dédié https://github.com/egrisel/site-wagtail/tree/01-installation.

Cet article est publié sous licence Creative Commons CC BY-SA : Attribution - Partage dans les Mêmes Conditions
CC BY-SA - Attribution - Partage dans les Mêmes Conditions

Commentaires

Aucun commentaire n'a été posté pour le moment.

Postez votre commentaire

Requis pour la vérification des commentaires

Catégories

Tutoriels (2)