diff --git a/app/models/communication/website/github_file.rb b/app/models/communication/website/github_file.rb
index 95a09b42e14e91ee20a680fc95cc638d2c0b3abc..a915bd9c2d109edcfeb1f541087686cb94c72aef 100644
--- a/app/models/communication/website/github_file.rb
+++ b/app/models/communication/website/github_file.rb
@@ -46,6 +46,12 @@ class Communication::Website::GithubFile < ApplicationRecord
     add_media_to_batch(github)
   end
 
+  def manifest_data
+    @manifest_data ||= about.github_manifest.detect { |item|
+      item[:identifier] == manifest_identifier
+    }
+  end
+
   protected
 
   def add_media_to_batch(github)
@@ -112,12 +118,6 @@ class Communication::Website::GithubFile < ApplicationRecord
     "[Medium] Remove ##{blob.id}"
   end
 
-  def manifest_data
-    @manifest_data ||= about.github_manifest.detect { |item|
-      item[:identifier] == manifest_identifier
-    }
-  end
-
   def valid_for_publication?
     if about.respond_to?(:published)
       about.published?
diff --git a/app/models/communication/website/page.rb b/app/models/communication/website/page.rb
index 08e47284b6df7f7eac59d849abd128a2a9270885..4259488271bad604a922afbe6dad363a07d84bde 100644
--- a/app/models/communication/website/page.rb
+++ b/app/models/communication/website/page.rb
@@ -92,6 +92,13 @@ class Communication::Website::Page < ApplicationRecord
     best_image
   end
 
+  def update_children_paths
+    children.each do |child|
+      child.update_column :path, child.generated_path
+      child.update_children_paths
+    end
+  end
+
   protected
 
   def slug_unavailable?(slug)
@@ -100,8 +107,4 @@ class Communication::Website::Page < ApplicationRecord
               .where.not(id: self.id)
               .exists?
   end
-
-  def update_children_paths
-    children.each(&:save)
-  end
 end
diff --git a/app/models/communication/website/with_batch_publication.rb b/app/models/communication/website/with_batch_publication.rb
index 6f815fe2b9836cc443baafeba3791f82dc1310a3..29149aff77e3c80c08b6ff82efe490cd499577c3 100644
--- a/app/models/communication/website/with_batch_publication.rb
+++ b/app/models/communication/website/with_batch_publication.rb
@@ -56,7 +56,11 @@ module Communication::Website::WithBatchPublication
 
     def commit_files_in_batch(files, commit_message)
       files.find_each { |file| file.add_to_batch(github) }
-      github.commit_batch commit_message
+      if github.commit_batch(commit_message)
+        files.find_each { |file|
+          file.update_column :github_path, file.manifest_data[:generated_path].call(file)
+        }
+      end
     end
   end
 
diff --git a/app/models/concerns/with_github_files.rb b/app/models/concerns/with_github_files.rb
index 3e73a032a0eec2240d7922699623c444f8230fc4..79caadb30eb94a7f27daeb1b55e61d938057238d 100644
--- a/app/models/concerns/with_github_files.rb
+++ b/app/models/concerns/with_github_files.rb
@@ -50,10 +50,36 @@ module WithGithubFiles
   end
 
   def publish_github_files
+    if respond_to?(:descendents)
+      publish_github_files_with_descendents
+    else
+      list_of_websites.each do |website|
+        github_manifest.each do |manifest_item|
+          github_file = github_files.where(website: website, manifest_identifier: manifest_item[:identifier]).first_or_create
+          github_file.publish
+        end
+      end
+    end
+  end
+
+  def publish_github_files_with_descendents
     list_of_websites.each do |website|
+      website_github = Github.with_website website
+      target_github_files = []
       github_manifest.each do |manifest_item|
         github_file = github_files.where(website: website, manifest_identifier: manifest_item[:identifier]).first_or_create
-        github_file.publish
+        target_github_files << github_file
+        github_file.add_to_batch(website_github)
+        descendents.each do |descendent|
+          descendent_github_file = descendent.github_files.where(website: website, manifest_identifier: manifest_item[:identifier]).first_or_create
+          target_github_files << descendent_github_file
+          descendent_github_file.add_to_batch(website_github)
+        end
+      end
+      if website_github.commit_batch("[#{self.class.name.demodulize}] Save #{to_s} & descendents")
+        target_github_files.each { |file|
+          file.update_column :github_path, file.manifest_data[:generated_path].call(file)
+        }
       end
     end
   end
diff --git a/app/models/concerns/with_slug.rb b/app/models/concerns/with_slug.rb
index f0e773ec712b956dfa26ecf780d05ac731d10339..ac3272e2a3f686f3004d9e3c4e3178c6ae57950b 100644
--- a/app/models/concerns/with_slug.rb
+++ b/app/models/concerns/with_slug.rb
@@ -18,6 +18,10 @@ module WithSlug
       end
     end
 
+    def generated_path
+      "#{parent&.path}/#{slug}".gsub(/\/+/, '/')
+    end
+
     protected
 
     def slug_unavailable?(slug)
@@ -29,7 +33,7 @@ module WithSlug
 
     def make_path
       return unless respond_to?(:path) && respond_to?(:parent)
-      self.path = "#{parent&.path}/#{slug}".gsub(/\/+/, '/')
+      self.path = generated_path
     end
   end
 end
diff --git a/app/models/concerns/with_tree.rb b/app/models/concerns/with_tree.rb
index 7869bb8f0ec083d40fe67f5b618a78f65601227d..0987f1ac8a49ca489ce7afb22c48f0ec54d5e661 100644
--- a/app/models/concerns/with_tree.rb
+++ b/app/models/concerns/with_tree.rb
@@ -18,6 +18,11 @@ module WithTree
                   : []
     end
 
+    def descendents
+      has_children? ? children.map { |child| [child, child.descendents].flatten }.flatten
+                    : []
+    end
+
     def self_and_children(level)
       elements = []
       label = "&nbsp;&nbsp;&nbsp;" * level + self.to_s