diff --git a/app/assets/images/communication/blocks/templates/key_figures.jpg b/app/assets/images/communication/blocks/templates/key_figures.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..de66f462ccf6e2ca5a376e7c32a6da9919036d5b
Binary files /dev/null and b/app/assets/images/communication/blocks/templates/key_figures.jpg differ
diff --git a/app/controllers/admin/communication/websites_controller.rb b/app/controllers/admin/communication/websites_controller.rb
index aa95abda1dddd39d7d1e3a7dada51ba12bc2c6f5..a4bdc69707a4f41ab87e12fe47f0c20d10ae64fc 100644
--- a/app/controllers/admin/communication/websites_controller.rb
+++ b/app/controllers/admin/communication/websites_controller.rb
@@ -13,6 +13,8 @@ class Admin::Communication::WebsitesController < Admin::Communication::Applicati
   end
 
   def show
+    @pages = @website.pages.published.recent
+    @posts = @website.posts.published.recent
     breadcrumb
   end
 
diff --git a/app/models/communication/block.rb b/app/models/communication/block.rb
index 733a971a2bcca774877080b7b140ffcebccc930c..7e9d8a1e18f40b7d9bc213b048ec078033a8641c 100644
--- a/app/models/communication/block.rb
+++ b/app/models/communication/block.rb
@@ -46,6 +46,7 @@ class Communication::Block < ApplicationRecord
     partners: 200,
     posts: 500,
     pages: 600,
+    key_figures: 56,
   }
 
   before_save :update_template_images
diff --git a/app/models/communication/block/template/key_figure.rb b/app/models/communication/block/template/key_figure.rb
new file mode 100644
index 0000000000000000000000000000000000000000..0c4abee7d7d9722a106e21a5728ced277a7e47b7
--- /dev/null
+++ b/app/models/communication/block/template/key_figure.rb
@@ -0,0 +1,15 @@
+class Communication::Block::Template::KeyFigure < Communication::Block::Template
+  def build_git_dependencies
+  end
+
+  def figures
+    @figures ||= elements.map { |element| figure(element) }
+                              .compact
+  end
+
+  protected
+
+  def figure(element)
+    element.to_dot
+  end
+end
diff --git a/app/models/communication/website/git_file.rb b/app/models/communication/website/git_file.rb
index 2514920234e1d429ce0fd2c0da8ed9cf9717f883..764e32104737702b133a92a8a278c76d7c61d29d 100644
--- a/app/models/communication/website/git_file.rb
+++ b/app/models/communication/website/git_file.rb
@@ -62,14 +62,7 @@ class Communication::Website::GitFile < ApplicationRecord
   end
 
   def to_s
-    @to_s ||= ApplicationController.render(
-      template: template_static,
-      layout: false,
-      assigns: {
-        about: about,
-        website: website
-      }
-    )
+    @to_s ||= Static.render(template_static, about, website)
   end
 
   protected
diff --git a/app/models/communication/website/menu/item/with_targets.rb b/app/models/communication/website/menu/item/with_targets.rb
index f93175d2f0a2c701b4f5eb9aa98939d0612e1447..0dab54e1304fd086d1cce889201d5c36e1ed0171 100644
--- a/app/models/communication/website/menu/item/with_targets.rb
+++ b/app/models/communication/website/menu/item/with_targets.rb
@@ -12,66 +12,70 @@ module Communication::Website::Menu::Item::WithTargets
   end
 
   def target_for_page
-    about.path if about&.published
+    Static.clean_path about.path if about&.published
   end
 
   def target_for_programs
-    "#{website.special_page(:education_programs).path}"
+    Static.clean_path website.special_page(:education_programs).path
   end
 
   def target_for_program
-    "#{website.special_page(:education_programs).path}#{about.path}".gsub("//", '/')
+    Static.clean_path "#{website.special_page(:education_programs).path}#{about.path}"
   end
 
   def target_for_news
-    "#{website.special_page(:communication_posts).path}"
+    Static.clean_path website.special_page(:communication_posts).path
   end
 
   def target_for_news_article
-    "#{website.special_page(:communication_posts).path}#{about.path}".gsub("//", '/') if about&.published && about&.published_at
+    return unless about&.published?
+    Static.clean_path "#{website.special_page(:communication_posts).path}#{about.path}"
   end
 
   def target_for_news_category
-    "#{website.special_page(:communication_posts).path}#{about.path}".gsub("//", '/') if about
+    return unless about
+    Static.clean_path "#{website.special_page(:communication_posts).path}#{about.path}"
   end
 
   def target_for_organizations
-    "#{website.special_page(:organizations).path}"
+    Static.clean_path website.special_page(:organizations).path
   end
 
   def target_for_staff
-    "#{website.special_page(:persons).path}"
+    Static.clean_path website.special_page(:persons).path
   end
 
   def target_for_administrators
-    "#{website.special_page(:administrators).path}"
+    Static.clean_path website.special_page(:administrators).path
   end
 
   def target_for_authors
-    "#{website.special_page(:authors).path}"
+    Static.clean_path website.special_page(:authors).path
   end
 
   def target_for_researchers
-    "#{website.special_page(:researchers).path}"
+    Static.clean_path website.special_page(:researchers).path
   end
 
   def target_for_teachers
-    "#{website.special_page(:teachers).path}"
+    Static.clean_path website.special_page(:teachers).path
   end
 
   def target_for_research_volumes
-    "#{website.special_page(:research_volumes).path}"
+    Static.clean_path website.special_page(:research_volumes).path
   end
 
   def target_for_research_volume
-    "#{website.special_page(:research_volumes).path}#{about.path}".gsub("//", '/') if about&.published && about&.published_at
+    return unless about&.published && about&.published_at
+    Static.clean_path "#{website.special_page(:research_volumes).path}#{about.path}"
   end
 
   def target_for_research_articles
-    "#{website.special_page(:research_articles).path}"
+    Static.clean_path website.special_page(:research_articles).path
   end
 
   def target_for_research_article
-    "#{website.special_page(:research_articles).path}#{about.path}".gsub("//", '/') if about&.published && about&.published_at
+    return unless about&.published && about&.published_at
+    Static.clean_path "#{website.special_page(:research_articles).path}#{about.path}"
   end
 end
diff --git a/app/models/communication/website/post.rb b/app/models/communication/website/post.rb
index 7702f2fa24a04964af2406699a579c9c496b7f7b..c498286f6d5e7aea0c3f83c10b90468a6109328a 100644
--- a/app/models/communication/website/post.rb
+++ b/app/models/communication/website/post.rb
@@ -66,7 +66,18 @@ class Communication::Website::Post < ApplicationRecord
   before_validation :set_published_at, if: :published_changed?
   after_save_commit :update_authors_statuses!, if: :saved_change_to_author_id?
 
-  scope :published, -> { where(published: true) }
+  scope :published, -> {
+    where("
+      communication_website_posts.published = true AND
+      DATE(communication_website_posts.published_at) <= now()
+    ")
+  }
+  scope :published_in_the_future, -> {
+    where("
+      communication_website_posts.published = true AND
+      DATE(communication_website_posts.published_at) > now()
+    ")
+  }
   scope :ordered, -> { order(published_at: :desc, created_at: :desc) }
   scope :recent, -> { order(published_at: :desc).limit(5) }
   scope :for_author, -> (author_id) { where(author_id: author_id) }
@@ -84,6 +95,10 @@ class Communication::Website::Post < ApplicationRecord
     ", term: "%#{sanitize_sql_like(term)}%")
   }
 
+  def published?
+    published && published_at.to_date <= Date.today
+  end
+
   # Is it used?
   def path
     # used in menu_item#static_target
diff --git a/app/models/education/program.rb b/app/models/education/program.rb
index a645756376a1e916c14e84cb7d2e89f0af00deae..48d81765c55fa7a6318005ee2a47055701d54f6f 100644
--- a/app/models/education/program.rb
+++ b/app/models/education/program.rb
@@ -59,6 +59,11 @@ class Education::Program < ApplicationRecord
   include WithInheritance
   include WithPosition
   include WithBlocks
+  include WithSchools
+  include WithDiploma
+  include WithAlumni
+  include WithWebsites
+  include WithTeam
 
   rich_text_areas_with_inheritance  :main_information,
                                     :accessibility,
@@ -76,88 +81,16 @@ class Education::Program < ApplicationRecord
                                     :content,
                                     :results
 
-  attr_accessor :skip_websites_categories_callback
-
   belongs_to :parent,
              class_name: 'Education::Program',
              optional: true
+
   has_many   :children,
              class_name: 'Education::Program',
              foreign_key: :parent_id,
              dependent: :destroy
-  belongs_to :diploma,
-             class_name: 'Education::Diploma',
-             optional: true
-  has_many   :university_roles,
-             class_name: 'University::Role',
-             as: :target,
-             dependent: :destroy
-  has_many   :involvements_through_roles,
-             through: :university_roles,
-             source: :involvements
-  has_many   :university_people_through_role_involvements,
-             through: :involvements_through_roles,
-             source: :person
-  has_many   :university_person_involvements,
-             class_name: 'University::Person::Involvement',
-             as: :target,
-             inverse_of: :target,
-             dependent: :destroy
-  has_many   :university_people_through_involvements,
-             through: :university_person_involvements,
-             source: :person
-  has_many   :website_categories,
-             class_name: 'Communication::Website::Category',
-             dependent: :destroy
-  has_and_belongs_to_many :schools,
-                          class_name: 'Education::School',
-                          join_table: 'education_programs_schools',
-                          foreign_key: 'education_program_id',
-                          association_foreign_key: 'education_school_id'
-  has_many   :websites,
-             -> { distinct },
-             through: :schools
-
-  has_many   :education_cohorts,
-             class_name: 'Education::Cohort'
-  alias_attribute :cohorts, :education_cohorts
-
-  has_many   :alumni,
-             through: :education_cohorts,
-             source: :people
-  alias_attribute :university_person_alumni, :alumni
-
-  has_many   :alumni_experiences,
-             -> { distinct },
-             class_name: 'University::Person::Experience',
-             through: :alumni,
-             source: :experiences
-  alias_attribute :university_person_experiences, :alumni_experiences
-
-  has_many   :alumni_organizations,
-             -> { distinct },
-             class_name: 'University::Organization',
-             through: :alumni_experiences,
-             source: :organization
-  alias_attribute :university_person_alumni_organizations, :alumni_organizations
-
-  has_many   :education_academic_years,
-             -> { distinct },
-             class_name: 'Education::AcademicYear',
-             through: :education_cohorts,
-             source: :academic_year
-             alias_attribute :academic_years, :education_academic_years
-
-  # Dénormalisation des alumni pour le faceted search
-  has_and_belongs_to_many :university_people,
-                          class_name: 'University::Person',
-                          foreign_key: 'education_program_id',
-                          association_foreign_key: 'university_person_id'
-
-  accepts_nested_attributes_for :university_person_involvements,
-                                reject_if: :all_blank,
-                                allow_destroy: true
 
+  # Deprecated, now in diploma
   enum level: {
     not_applicable: 0,
     primary: 40,
@@ -174,7 +107,6 @@ class Education::Program < ApplicationRecord
   validates_presence_of :name
 
   after_save :update_children_paths, if: :saved_change_to_path?
-  after_save_commit :set_websites_categories, unless: :skip_websites_categories_callback
 
   scope :published, -> { where(published: true) }
   scope :ordered_by_name, -> { order(:name) }
@@ -231,10 +163,6 @@ class Education::Program < ApplicationRecord
     end
   end
 
-  def set_websites_categories
-    websites.find_each(&:set_programs_categories!)
-  end
-
   #####################
   # Aboutable methods #
   #####################
diff --git a/app/models/education/program/with_alumni.rb b/app/models/education/program/with_alumni.rb
new file mode 100644
index 0000000000000000000000000000000000000000..475572935cce3f68fb1c79b283f528288c7156f8
--- /dev/null
+++ b/app/models/education/program/with_alumni.rb
@@ -0,0 +1,47 @@
+module Education::Program::WithAlumni
+  extend ActiveSupport::Concern
+
+  included do
+    has_many   :cohorts,
+               class_name: 'Education::Cohort'
+               alias_attribute :education_cohorts, :cohorts
+
+    has_many   :alumni,
+               through: :cohorts,
+               source: :people
+               alias_attribute :university_person_alumni, :alumni
+
+    has_many   :alumni_experiences, -> { distinct },
+               through: :alumni,
+               source: :experiences
+               alias_attribute :university_person_experiences, :alumni_experiences
+
+    has_many   :alumni_organizations, -> { distinct },
+               through: :alumni_experiences,
+               source: :organization
+               alias_attribute :university_person_alumni_organizations, :alumni_organizations
+
+    # TODO: Find a fix for wrong table name on WHERE clause
+    #   SELECT "education_academic_years".*
+    #   FROM "education_academic_years"
+    #   INNER JOIN "education_cohorts"
+    #     ON "education_academic_years"."id" = "education_cohorts"."academic_year_id"
+    #   WHERE "cohorts"."program_id" = '<uuid>'
+    #
+    # has_many   :academic_years, -> { distinct },
+    #            class_name: 'Education::AcademicYear',
+    #            through: :cohorts,
+    #            source: :academic_year
+    #            alias_attribute :education_academic_years, :academic_years
+
+    # Dénormalisation des alumni pour le faceted search
+    has_and_belongs_to_many :university_people,
+                            class_name: 'University::Person',
+                            foreign_key: 'education_program_id',
+                            association_foreign_key: 'university_person_id'
+
+    def academic_years
+      Education::AcademicYear.where(id: cohorts.pluck(:academic_year_id))
+    end
+  end
+end
diff --git a/app/models/education/program/with_diploma.rb b/app/models/education/program/with_diploma.rb
new file mode 100644
index 0000000000000000000000000000000000000000..41e3829fc3f170e721959fb1ed8b5b5ea899c6dd
--- /dev/null
+++ b/app/models/education/program/with_diploma.rb
@@ -0,0 +1,9 @@
+module Education::Program::WithDiploma
+  extend ActiveSupport::Concern
+
+  included do
+    belongs_to :diploma,
+      class_name: 'Education::Diploma',
+      optional: true
+  end
+end
diff --git a/app/models/education/program/with_schools.rb b/app/models/education/program/with_schools.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c1f2a9032996fee311448dd98032ed144b23c74f
--- /dev/null
+++ b/app/models/education/program/with_schools.rb
@@ -0,0 +1,11 @@
+module Education::Program::WithSchools
+  extend ActiveSupport::Concern
+
+  included do
+    has_and_belongs_to_many :schools,
+                            class_name: 'Education::School',
+                            join_table: 'education_programs_schools',
+                            foreign_key: 'education_program_id',
+                            association_foreign_key: 'education_school_id'
+  end
+end
diff --git a/app/models/education/program/with_team.rb b/app/models/education/program/with_team.rb
new file mode 100644
index 0000000000000000000000000000000000000000..513fdf9fe38b6e05bc1998e0c5c1843bf50fa64d
--- /dev/null
+++ b/app/models/education/program/with_team.rb
@@ -0,0 +1,32 @@
+module Education::Program::WithTeam
+  extend ActiveSupport::Concern
+
+  included do
+    has_many   :university_roles,
+               class_name: 'University::Role',
+               as: :target,
+               dependent: :destroy
+
+    has_many   :involvements_through_roles,
+               through: :university_roles,
+               source: :involvements
+
+    has_many   :university_people_through_role_involvements,
+               through: :involvements_through_roles,
+               source: :person
+
+    has_many   :university_person_involvements,
+               class_name: 'University::Person::Involvement',
+               as: :target,
+               inverse_of: :target,
+               dependent: :destroy
+
+    accepts_nested_attributes_for :university_person_involvements,
+                                  reject_if: :all_blank,
+                                  allow_destroy: true
+
+    has_many   :university_people_through_involvements,
+               through: :university_person_involvements,
+               source: :person
+  end
+end
diff --git a/app/models/education/program/with_websites.rb b/app/models/education/program/with_websites.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a9b81dbe992889487e4afd02768f994c5a8ccb6f
--- /dev/null
+++ b/app/models/education/program/with_websites.rb
@@ -0,0 +1,21 @@
+module Education::Program::WithWebsites
+  extend ActiveSupport::Concern
+
+  included do
+    attr_accessor :skip_websites_categories_callback
+
+    after_save_commit :set_websites_categories, unless: :skip_websites_categories_callback
+
+    # FIXME incorrect, forgets websites about programs
+    has_many   :websites, -> { distinct },
+               through: :schools
+
+    has_many   :website_categories,
+               class_name: 'Communication::Website::Category',
+               dependent: :destroy
+  end
+
+  def set_websites_categories
+    websites.find_each(&:set_programs_categories!)
+  end
+end
diff --git a/app/models/education/school.rb b/app/models/education/school.rb
index c7399a66dca85204b7c5e11b904e37a070144457..a44a083c57a92dc93765c65fd864de704f11d2bf 100644
--- a/app/models/education/school.rb
+++ b/app/models/education/school.rb
@@ -26,18 +26,9 @@
 class Education::School < ApplicationRecord
   include WithGit
   include Aboutable
-
-  has_and_belongs_to_many :programs,
-                          class_name: 'Education::Program',
-                          join_table: 'education_programs_schools',
-                          foreign_key: 'education_school_id',
-                          association_foreign_key: 'education_program_id'
-  has_and_belongs_to_many :published_programs,
-                          -> { published },
-                          class_name: 'Education::Program',
-                          join_table: 'education_programs_schools',
-                          foreign_key: 'education_school_id',
-                          association_foreign_key: 'education_program_id'
+  include WithPrograms # must come before WithAlumni and WithTeam
+  include WithTeam
+  include WithAlumni
 
   belongs_to  :university
 
@@ -45,59 +36,11 @@ class Education::School < ApplicationRecord
               class_name: 'Communication::Website',
               as: :about,
               dependent: :nullify
-  has_many    :university_roles,
-              class_name: 'University::Role',
-              as: :target,
-              dependent: :destroy
-  has_many    :involvements_through_roles,
-              through: :university_roles,
-              source: :involvements
-  has_many    :university_people_through_role_involvements,
-              through: :involvements_through_roles,
-              source: :person
-  has_many    :university_people_through_program_involvements,
-              through: :programs,
-              source: :university_people_through_involvements
-  has_many    :university_people_through_program_role_involvements,
-              through: :programs,
-              source: :university_people_through_role_involvements
-  has_many    :university_people_through_published_program_involvements,
-              through: :published_programs,
-              source: :university_people_through_involvements
-  has_many    :university_people_through_published_program_role_involvements,
-              through: :published_programs,
-              source: :university_people_through_role_involvements
-
-  has_many    :alumni, -> { distinct },
-              through: :programs
-  alias_attribute :university_person_alumni, :alumni
-
-  has_many    :alumni_experiences, -> { distinct },
-              class_name: 'University::Person::Experience',
-              through: :alumni,
-              source: :experiences
-  alias_attribute :university_person_experiences, :alumni_experiences
-
-  has_many    :alumni_organizations, -> { distinct },
-              class_name: 'University::Organization',
-              through: :alumni_experiences,
-              source: :organization
-  alias_attribute :university_person_alumni_organizations, :alumni_organizations
-
-  has_many    :education_academic_years, -> { distinct },
-              class_name: 'Education::AcademicYear',
-              through: :programs
-  alias_attribute :academic_years, :education_academic_years
 
-  has_many    :education_cohorts, -> { distinct },
-              class_name: 'Education::Cohort',
-              through: :programs
-  alias_attribute :cohorts, :education_cohorts
 
   validates :name, :address, :city, :zipcode, :country, presence: true
 
   scope :ordered, -> { order(:name) }
-  scope :for_program, -> (program_id) { joins(:programs).where(education_programs: { id: program_id }) }
   scope :for_search_term, -> (term) {
     where("
       unaccent(education_schools.address) ILIKE unaccent(:term) OR
@@ -108,65 +51,37 @@ class Education::School < ApplicationRecord
       unaccent(education_schools.zipcode) ILIKE unaccent(:term)
     ", term: "%#{sanitize_sql_like(term)}%")
   }
+  scope :for_program, -> (program_id) {
+    joins(:programs).where(education_programs: { id: program_id })
+  }
 
   def to_s
     "#{name}"
   end
 
-  def researchers
-    people_ids = (
-      university_people_through_published_program_involvements +
-      university_people_through_role_involvements +
-      university_people_through_published_program_role_involvements
-    ).pluck(:id)
-    university.people.where(id: people_ids, is_researcher: true)
-  end
-
-  def teachers
-    people_ids = university_people_through_published_program_involvements.pluck(:id)
-    university.people.where(id: people_ids, is_teacher: true)
-  end
-
-  def administrators
-    people_ids = (
-      university_people_through_role_involvements +
-      university_people_through_published_program_role_involvements
-    ).pluck(:id)
-    university.people.where(id: people_ids, is_administration: true)
-  end
-
   def git_path(website)
     "data/school.yml"
   end
 
   def git_dependencies(website)
     dependencies = [self]
-    dependencies += published_programs + published_programs.map(&:active_storage_blobs).flatten if has_education_programs?
-    dependencies += teachers + teachers.map(&:teacher) + teachers.map(&:active_storage_blobs).flatten if has_teachers?
-    dependencies += researchers + researchers.map(&:researcher) + researchers.map(&:active_storage_blobs).flatten if has_researchers?
-    dependencies += administrators + administrators.map(&:administrator) + administrators.map(&:active_storage_blobs).flatten if has_administrators?
+    dependencies += published_programs
+                    + published_programs.map(&:active_storage_blobs).flatten if has_education_programs?
+    dependencies += teachers
+                    + teachers.map(&:teacher)
+                    + teachers.map(&:active_storage_blobs).flatten if has_teachers?
+    dependencies += researchers
+                    + researchers.map(&:researcher)
+                    + researchers.map(&:active_storage_blobs).flatten if has_researchers?
+    dependencies += administrators
+                    + administrators.map(&:administrator)
+                    + administrators.map(&:active_storage_blobs).flatten if has_administrators?
     dependencies
   end
 
   #####################
   # Aboutable methods #
   #####################
-  def has_administrators?
-    university_people_through_role_involvements.any? ||
-    university_people_through_program_role_involvements.any?
-  end
-
-  def has_researchers?
-    researchers.any?
-  end
-
-  def has_teachers?
-    teachers.any?
-  end
-
-  def has_education_programs?
-    published_programs.any?
-  end
 
   def has_research_articles?
     false
diff --git a/app/models/education/school/with_alumni.rb b/app/models/education/school/with_alumni.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a234267c35ea0eeeca54642dafa75b2bdf73810a
--- /dev/null
+++ b/app/models/education/school/with_alumni.rb
@@ -0,0 +1,32 @@
+module Education::School::WithAlumni
+  extend ActiveSupport::Concern
+
+  included do
+
+      has_many    :alumni, -> { distinct },
+                  through: :programs
+                  alias_attribute :university_person_alumni, :alumni
+
+      has_many    :alumni_experiences, -> { distinct },
+                  class_name: 'University::Person::Experience',
+                  through: :alumni,
+                  source: :experiences
+                  alias_attribute :university_person_experiences, :alumni_experiences
+
+      has_many    :alumni_organizations, -> { distinct },
+                  class_name: 'University::Organization',
+                  through: :alumni_experiences,
+                  source: :organization
+                  alias_attribute :university_person_alumni_organizations, :alumni_organizations
+
+      has_many    :academic_years, -> { distinct },
+                  class_name: 'Education::AcademicYear',
+                  through: :programs
+                  alias_attribute :education_academic_years, :academic_years
+
+      has_many    :cohorts, -> { distinct },
+                  class_name: 'Education::Cohort',
+                  through: :programs
+                  alias_attribute :education_cohorts, :cohorts
+  end
+end
diff --git a/app/models/education/school/with_programs.rb b/app/models/education/school/with_programs.rb
new file mode 100644
index 0000000000000000000000000000000000000000..836aab7fec8dc65ee44c1e3245710766400504e4
--- /dev/null
+++ b/app/models/education/school/with_programs.rb
@@ -0,0 +1,24 @@
+module Education::School::WithPrograms
+  extend ActiveSupport::Concern
+
+  included do
+    has_and_belongs_to_many :programs,
+                            class_name: 'Education::Program',
+                            join_table: 'education_programs_schools',
+                            foreign_key: 'education_school_id',
+                            association_foreign_key: 'education_program_id'
+
+    # Why not programs.published ?
+    has_and_belongs_to_many :published_programs,
+                            -> { published },
+                            class_name: 'Education::Program',
+                            join_table: 'education_programs_schools',
+                            foreign_key: 'education_school_id',
+                            association_foreign_key: 'education_program_id'
+
+  end
+
+  def has_education_programs?
+    published_programs.any?
+  end
+end
diff --git a/app/models/education/school/with_team.rb b/app/models/education/school/with_team.rb
new file mode 100644
index 0000000000000000000000000000000000000000..826b8a6b550762161d5ffb04e532d32cb30140e7
--- /dev/null
+++ b/app/models/education/school/with_team.rb
@@ -0,0 +1,70 @@
+module Education::School::WithTeam
+  extend ActiveSupport::Concern
+
+  included do
+    has_many    :university_roles,
+                class_name: 'University::Role',
+                as: :target,
+                dependent: :destroy
+
+    has_many    :involvements_through_roles,
+                through: :university_roles,
+                source: :involvements
+
+    has_many    :university_people_through_role_involvements,
+                through: :involvements_through_roles,
+                source: :person
+
+    has_many    :university_people_through_program_involvements,
+                through: :programs,
+                source: :university_people_through_involvements
+
+    has_many    :university_people_through_program_role_involvements,
+                through: :programs,
+                source: :university_people_through_role_involvements
+
+    has_many    :university_people_through_published_program_involvements,
+                through: :published_programs,
+                source: :university_people_through_involvements
+
+    has_many    :university_people_through_published_program_role_involvements,
+                through: :published_programs,
+                source: :university_people_through_role_involvements
+  end
+
+  def researchers
+    people_ids = (
+      university_people_through_published_program_involvements +
+      university_people_through_role_involvements +
+      university_people_through_published_program_role_involvements
+    ).pluck(:id)
+    university.people.where(id: people_ids, is_researcher: true)
+  end
+
+  def teachers
+    people_ids = university_people_through_published_program_involvements.pluck(:id)
+    university.people.where(id: people_ids, is_teacher: true)
+  end
+
+  def administrators
+    people_ids = (
+      university_people_through_role_involvements +
+      university_people_through_published_program_role_involvements
+    ).pluck(:id)
+    university.people.where(id: people_ids, is_administration: true)
+  end
+
+
+  def has_administrators?
+    university_people_through_role_involvements.any? ||
+    university_people_through_program_role_involvements.any?
+  end
+
+  def has_researchers?
+    researchers.any?
+  end
+
+  def has_teachers?
+    teachers.any?
+  end
+end
diff --git a/app/models/university/person/experience.rb b/app/models/university/person/experience.rb
index d4b2dbb112f48ca84c38004278f68e798eec4d32..3cee8c3347cd85fbc792cc0aac2bfa61b3ac4523 100644
--- a/app/models/university/person/experience.rb
+++ b/app/models/university/person/experience.rb
@@ -27,7 +27,7 @@
 class University::Person::Experience < ApplicationRecord
   include WithUniversity
   belongs_to :person
-  belongs_to :organization
+  belongs_to :organization, class_name: "University::Organization"
 
   scope :ordered, -> { order(from_year: :desc)}
 end
diff --git a/app/models/university/person/with_education.rb b/app/models/university/person/with_education.rb
index 5348cec25a2d84e8a38287daf05cdad4a5d8a80b..f22aed32deca953f0c34397016482345a9a9f67b 100644
--- a/app/models/university/person/with_education.rb
+++ b/app/models/university/person/with_education.rb
@@ -18,7 +18,7 @@ module University::Person::WithEducation
                             source: :target,
                             source_type: "Education::Program"
 
-    has_many                :experiences
+    has_many                :experiences, class_name: "University::Person::Experience"
 
     has_and_belongs_to_many :cohorts,
                             class_name: '::Education::Cohort',
diff --git a/app/services/static.rb b/app/services/static.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8baf7ba84c9283d83050b6f7f8ef8849a07a3e3a
--- /dev/null
+++ b/app/services/static.rb
@@ -0,0 +1,20 @@
+class Static
+  def self.clean_path(path)
+    path += '/' unless path.end_with? '/'
+    path.gsub("//", '/')
+  end
+
+  def self.render(template_static, about, website)
+    string = ApplicationController.render(
+      template: template_static,
+      layout: false,
+      assigns: {
+        about: about,
+        website: website
+      }
+    )
+    # We don't want &#39; in the frontmatters!
+    string = string.gsub '&#39\;', "'"
+    string
+  end
+end
diff --git a/app/views/admin/communication/blocks/templates/key_figures/_edit.html.erb b/app/views/admin/communication/blocks/templates/key_figures/_edit.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..dcd9e2463af441dfc8d98f912e5c04fdf171d9e4
--- /dev/null
+++ b/app/views/admin/communication/blocks/templates/key_figures/_edit.html.erb
@@ -0,0 +1,50 @@
+<a  class="<%= button_classes('mb-4') %>"
+    v-on:click="data.elements.push({number: 0, unit: '', description: ''})">
+    <%= t '.add_key' %>
+</a>
+
+<draggable :list="data.elements" handle=".dragHandle" class="row">
+  <div v-for="(key, index) in data.elements" class="col-md-4">
+    <div class="card">
+      <div class="card-body">
+        <div class="d-flex">
+          <div>
+            <a class="btn ps-0 pt-0 dragHandle">
+              <i class="fa fa-bars handle"></i>
+            </a>
+          </div>
+          <div class="flex-fill">
+            <label    class="form-label"
+                      :for="'key-' + index + '-number'"><%= t '.number_label' %></label>
+            <input class="form-control mb-3"
+                      v-model="key.number"
+                      placeholder="<%= t '.number_placeholder' %>"
+                      type="number"
+                      :id="'key-' + index + '-number'" />
+
+            <label    class="form-label"
+                      :for="'key-' + index + '-unit'"><%= t '.unit_label' %></label>
+            <input class="form-control mb-3"
+                      v-model="key.unit"
+                      placeholder="<%= t '.unit_placeholder' %>"
+                      :id="'key-' + index + '-unit'">
+
+            <label    class="form-label"
+                      :for="'key-' + index + '-description'"><%= t '.description_label' %></label>
+            <input class="form-control mb-3"
+                      v-model="key.description"
+                      placeholder="<%= t '.description_placeholder' %>"
+                      :id="'key-' + index + '-description'">
+          </div>
+          <div>
+            <a  class="btn btn-sm btn-danger ms-3"
+                v-on:click="data.elements.splice(data.elements.indexOf(key), 1)"
+                title="<%= t '.remove_key' %>">
+                <i class="fas fa-times"></i>
+            </a>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</draggable>
diff --git a/app/views/admin/communication/blocks/templates/key_figures/_preview.html.erb b/app/views/admin/communication/blocks/templates/key_figures/_preview.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/app/views/admin/communication/blocks/templates/key_figures/_static.html.erb b/app/views/admin/communication/blocks/templates/key_figures/_static.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..6870d3caab69caed0baa0ba6802b53b4cd55779c
--- /dev/null
+++ b/app/views/admin/communication/blocks/templates/key_figures/_static.html.erb
@@ -0,0 +1,9 @@
+      figures:
+<% block.template.figures.each do |figure| %>
+        - number: >-
+            <%= prepare_text_for_static figure.number, 6 %>
+          unit: >-
+            <%= prepare_text_for_static figure.unit, 6 %>
+          description: >-
+            <%= prepare_text_for_static figure.description, 6 %>
+<% end %>
diff --git a/app/views/admin/communication/websites/pages/static.html.erb b/app/views/admin/communication/websites/pages/static.html.erb
index e9c8061eef03a0114cbe40a01f86be40269a249a..8812dd9cf9187dad7c1f1988842661a05b0d41ca 100644
--- a/app/views/admin/communication/websites/pages/static.html.erb
+++ b/app/views/admin/communication/websites/pages/static.html.erb
@@ -17,7 +17,7 @@ description: >
 description_short: >
   <%= prepare_text_for_static @about.description_short %>
 header_text: >-
-  <%= @about.header_text %>
+  <%= prepare_html_for_static @about.header_text, @website.university %>
 legacy_text: >
   <%= prepare_html_for_static @about.text, @about.university %>
 <%= render 'admin/communication/blocks/static', about: @about %>
diff --git a/app/views/admin/communication/websites/show/_pages.html.erb b/app/views/admin/communication/websites/show/_pages.html.erb
index cbc93af84fa326ed0d8544f62078a06eb2cb5006..17fbbd2070b3ffa625d6fc21e8ac114d578e3991 100644
--- a/app/views/admin/communication/websites/show/_pages.html.erb
+++ b/app/views/admin/communication/websites/show/_pages.html.erb
@@ -15,5 +15,6 @@
       <% end %>
     </h2>
   </div>
-  <%= render 'admin/communication/websites/pages/list', pages: @website.pages.recent %>
+  <%= render 'admin/communication/websites/pages/list',
+              pages: @pages %>
 </div>
diff --git a/app/views/admin/communication/websites/show/_posts.html.erb b/app/views/admin/communication/websites/show/_posts.html.erb
index d1d97da049fd65efe94398e424f9de5b5c935672..9f91cbbdc8c8cbd4a81185fbbf3d30c20c697b50 100644
--- a/app/views/admin/communication/websites/show/_posts.html.erb
+++ b/app/views/admin/communication/websites/show/_posts.html.erb
@@ -18,5 +18,8 @@
       <% end %>
     </h2>
   </div>
-  <%= render 'admin/communication/websites/posts/list', posts: @website.posts.recent, hide_author: true, hide_category: true %>
+  <%= render 'admin/communication/websites/posts/list',
+              posts: @posts,
+              hide_author: true,
+              hide_category: true %>
 </div>
diff --git a/app/views/admin/education/diplomas/static.html.erb b/app/views/admin/education/diplomas/static.html.erb
index 5f0dadeff9a8fbf326b53c4bd6b6f738bb067ce5..071e23c36b7fd28468ecb770b50ce8487a707fd4 100644
--- a/app/views/admin/education/diplomas/static.html.erb
+++ b/app/views/admin/education/diplomas/static.html.erb
@@ -1,8 +1,8 @@
 ---
 title: >
-  <%= @about.name %>
+  <%= prepare_text_for_static @about.name %>
 short_name: >
-  <%= @about.short_name %>
+  <%= prepare_text_for_static @about.short_name %>
 level: <%= @about.level_i18n %>
 ects: <%= @about.ects %>
 duration: >
diff --git a/config/locales/communication/en.yml b/config/locales/communication/en.yml
index 03e75b9218918a6e371f90e67593e5f78ad7bb54..6fca96732b7f94d15297f83fc4a388d0186208d5 100644
--- a/config/locales/communication/en.yml
+++ b/config/locales/communication/en.yml
@@ -196,6 +196,16 @@ en:
               text_label: Text
               text_placeholder: Enter text
               remove_image: Remove image
+          key_figures:
+            edit:
+              add_key: Add key figure
+              unit_label: Unit
+              unit_placeholder: Enter unit here
+              number_label: Number
+              number_placeholder: Enter key figure's value here
+              description_label: Description
+              description_placeholder: Enter description here
+              remove_key: Remove key figure
           organization_chart:
             edit:
               add_person: Add person
diff --git a/config/locales/communication/fr.yml b/config/locales/communication/fr.yml
index a406c0e00ede63134167eae90abb283944c11348..1b62eae7a6b24508a4308cf7ac59e77797b0b9ac 100644
--- a/config/locales/communication/fr.yml
+++ b/config/locales/communication/fr.yml
@@ -197,6 +197,16 @@ fr:
               text_label: Texte
               text_placeholder: Entrer le texte
               remove_image: Enlever l'image
+          key_figures:
+            edit:
+              add_key: Add key figure
+              unit_label: Unit
+              unit_placeholder: Enter unit here
+              number_label: Number
+              number_placeholder: Enter key figure's value here
+              description_label: Description
+              description_placeholder: Enter description here
+              remove_key: Remove key figure
           organization_chart:
             edit:
               add_person: Ajouter une personne