diff --git a/app/assets/javascripts/admin/commons/batch-selectable.js b/app/assets/javascripts/admin/commons/batch-selectable.js
new file mode 100644
index 0000000000000000000000000000000000000000..09f9f4f6c896865bf5639443f4c6acc33a2d39a3
--- /dev/null
+++ b/app/assets/javascripts/admin/commons/batch-selectable.js
@@ -0,0 +1,35 @@
+/* global */
+window.osuny.BatchSelectable = function BatchSelectable (element) {
+    'use strict';
+    this.element = element;
+    this.selectAllInput = this.element.querySelector('[data-batch-selectable-role="select-all"]');
+    this.selectSingleInputs = this.element.querySelectorAll('[data-batch-selectable-role="select-single"]');
+    this.initEvents();
+};
+
+window.osuny.BatchSelectable.prototype.initEvents = function () {
+    'use strict';
+    if (this.selectAllInput === null) {
+        return;
+    }
+    this.selectAllInput.addEventListener('change', function () {
+        this.toggleSingleInputs(this.selectAllInput.checked);
+    }.bind(this));
+};
+
+window.osuny.BatchSelectable.prototype.toggleSingleInputs = function (checked) {
+    'use strict';
+    var i;
+    for (i = 0; i < this.selectSingleInputs.length; i += 1) {
+        this.selectSingleInputs[i].checked = checked;
+    }
+};
+
+window.addEventListener('DOMContentLoaded', function () {
+    'use strict';
+    var elements = document.querySelectorAll('[data-batch-selectable]'),
+        i;
+    for (i = 0; i < elements.length; i += 1) {
+        new window.osuny.BatchSelectable(elements[i]);
+    }
+});
diff --git a/app/controllers/admin/communication/website/posts_controller.rb b/app/controllers/admin/communication/website/posts_controller.rb
index 2c515e621523a213fa4cf4cece6a196481fed6ec..ef64565104f4a3bcaac82da9439e1401a002ea04 100644
--- a/app/controllers/admin/communication/website/posts_controller.rb
+++ b/app/controllers/admin/communication/website/posts_controller.rb
@@ -6,6 +6,19 @@ class Admin::Communication::Website::PostsController < Admin::Communication::Web
     breadcrumb
   end
 
+  def publish
+    ids = params[:ids] || []
+    target_posts = @website.posts.where(id: ids)
+    if params[:published] == "true"
+      target_posts.update(published: true)
+    elsif params[:published] == "false"
+      target_posts.update(published: false)
+    end
+    @website.sync_objects_with_git(target_posts) if target_posts.any?
+    redirect_back fallback_location: admin_communication_website_posts_path,
+                  notice: t('communication.website.posts.successful_batch_update')
+  end
+
   def show
     breadcrumb
   end
diff --git a/app/models/communication/website/with_git_repository.rb b/app/models/communication/website/with_git_repository.rb
index 436b1f64ef663f438eff86b1efabc1e93b935e83..1339143e00a5abb1cb3b51e66101999934732bd1 100644
--- a/app/models/communication/website/with_git_repository.rb
+++ b/app/models/communication/website/with_git_repository.rb
@@ -10,4 +10,18 @@ module Communication::Website::WithGitRepository
   def git_repository
     @git_repository ||= Git::Repository.new self
   end
+
+  def sync_objects_with_git(objects)
+    touch
+    return unless git_repository.valid?
+    objects.each do |object|
+      next unless object.has_website_for_self?(self)
+      dependencies = object.git_dependencies(self).to_a.flatten.uniq.compact
+      dependencies.each do |dependency|
+        Communication::Website::GitFile.sync self, dependency
+      end
+    end
+    git_repository.sync!
+  end
+  handle_asynchronously :sync_objects_with_git, queue: 'default'
 end
diff --git a/app/models/concerns/with_git.rb b/app/models/concerns/with_git.rb
index 174e5b227789f34b95b0bd1d5f1baf3ec1646eca..0b6845c2e1381f48f5c50a4c527cc665a2e28ce0 100644
--- a/app/models/concerns/with_git.rb
+++ b/app/models/concerns/with_git.rb
@@ -64,6 +64,18 @@ module WithGit
     end
   end
 
+  def has_website_for_self?(website)
+    websites_for_self.include?(website)
+  end
+
+  def git_dependencies(website = nil)
+    [self]
+  end
+
+  def git_destroy_dependencies(website = nil)
+    [self]
+  end
+
   protected
 
   def in_block_dependencies?(website)
@@ -83,12 +95,4 @@ module WithGit
       []
     end
   end
-
-  def git_dependencies(website = nil)
-    [self]
-  end
-
-  def git_destroy_dependencies(website = nil)
-    [self]
-  end
 end
diff --git a/app/views/admin/communication/website/posts/_list.html.erb b/app/views/admin/communication/website/posts/_list.html.erb
index 61f78aa6ced46a4de5dcf6c09a939a47100357da..8ebc3a67791990b8cd12e8238044fc6772047791 100644
--- a/app/views/admin/communication/website/posts/_list.html.erb
+++ b/app/views/admin/communication/website/posts/_list.html.erb
@@ -1,10 +1,16 @@
 <%
   hide_author |= false
   hide_category |= false
+  selectable |= false
 %>
-<table class="<%= table_classes %>">
+<table class="<%= table_classes %>" <%= "data-batch-selectable" if selectable %>>
   <thead>
     <tr>
+      <% if selectable %>
+        <th>
+          <%= check_box_tag nil, nil, false, data: { batch_selectable_role: "select-all" } %>
+        </th>
+      <% end %>
       <th><%= Communication::Website::Post.human_attribute_name('title') %></th>
       <th><%= Communication::Website::Post.human_attribute_name('featured_image') %></th>
       <% unless hide_author %>
@@ -20,6 +26,11 @@
   <tbody>
     <% posts.each do |post| %>
       <tr>
+        <% if selectable %>
+          <td>
+            <%= check_box_tag "ids[]", post.id, false, data: { batch_selectable_role: "select-single" } %>
+          </td>
+        <% end %>
         <td><%= link_to post,
                         admin_communication_website_post_path(website_id: post.website.id, id: post.id),
                         class: "#{'opacity-50' unless post.published?}" %></td>
diff --git a/app/views/admin/communication/website/posts/index.html.erb b/app/views/admin/communication/website/posts/index.html.erb
index 814a431bf51ab1da6c16ae00eb1bec4d3504f962..51b31b48864c64137ad52ee6d21b65743f937b15 100644
--- a/app/views/admin/communication/website/posts/index.html.erb
+++ b/app/views/admin/communication/website/posts/index.html.erb
@@ -2,10 +2,29 @@
 
 <%= render 'admin/communication/websites/sidebar' do %>
   <div class="card">
-    <%= render 'admin/communication/website/posts/list', posts: @posts, hide_author: true %>
-    <% if @posts.total_pages > 1 %>
+    <%= form_tag publish_admin_communication_website_posts_path do %>
+      <input type="hidden" name="ids[]" value="">
+      <%= render 'admin/communication/website/posts/list', posts: @posts, hide_author: true, selectable: true %>
       <div class="card-footer">
-        <%= paginate @posts, theme: 'bootstrap-5' %>
+        <% if @posts.total_pages > 1 %>
+          <div class="float-end">
+            <%= paginate @posts, theme: 'bootstrap-5' %>
+          </div>
+        <% end %>
+        <div class="row align-items-center">
+          <div class="col-auto">
+            Modifier la sélection
+          </div>
+          <div class="col-auto">
+            <select name="published" class="form-select">
+              <option value="false">Non publiée</option>
+              <option value="true">Publiée</option>
+            </select>
+          </div>
+          <div class="col-auto">
+            <input type="submit" value="Enregistrer" class="btn btn-primary">
+          </div>
+        </div>
       </div>
     <% end %>
   </div>
diff --git a/config/locales/communication/fr.yml b/config/locales/communication/fr.yml
index 54f6c1d5d4bf97479dd0f5d04abd0e20456364b2..01b3fc28b1eeb5b01e45f83f141b0bd6d056eb8c 100644
--- a/config/locales/communication/fr.yml
+++ b/config/locales/communication/fr.yml
@@ -302,6 +302,7 @@ fr:
             title: Équipe pédagogique
       posts:
         new_curation: Nouvelle curation
+        successful_batch_update: Les actualités ont bien été mises à jour
       see_all: Voir la liste complète (%{number} éléments)
   enums:
     communication:
diff --git a/config/routes/admin/communication.rb b/config/routes/admin/communication.rb
index 4ebcf1ce0531974450775c95d87cadc58b771641..8e3cfeb11a6f02f1bd38a25c432cc4585f7f19e5 100644
--- a/config/routes/admin/communication.rb
+++ b/config/routes/admin/communication.rb
@@ -25,7 +25,9 @@ namespace :communication do
       end
     end
     resources :authors, controller: 'website/authors', only: [:index, :show]
-    resources :posts, controller: 'website/posts'
+    resources :posts, controller: 'website/posts' do
+      post :publish, on: :collection
+    end
     resources :curations,
               path: 'posts/curations',
               as: :post_curations,
@@ -44,7 +46,7 @@ namespace :communication do
     end
     get   'structure'     => 'website/structure#edit'
     patch 'structure'     => 'website/structure#update'
-    
+
   end
   resources :blocks, controller: 'blocks', except: :index do
     collection do