diff --git a/app/models/communication/website/page.rb b/app/models/communication/website/page.rb
index 1a3317f754900d41953edc7c38ebcd6b7bd61d52..da268152d78e2cfc5c7c1402bcb2bb7111947ef4 100644
--- a/app/models/communication/website/page.rb
+++ b/app/models/communication/website/page.rb
@@ -48,18 +48,19 @@ class Communication::Website::Page < ApplicationRecord
 
   include Accessible
   include Sanitizable
-  include WithUniversity
   include WithBlobs
   include WithBlocks
+  include WithDuplication
   include WithFeaturedImage
   include WithGit
   include WithMenuItemTarget
   include WithPosition
   include WithTree
   include WithPath
-  include WithType
   include WithPermalink
+  include WithType
   include WithTranslations
+  include WithUniversity
 
   has_summernote :text # TODO: Remove text attribute
 
@@ -110,19 +111,6 @@ class Communication::Website::Page < ApplicationRecord
     active_storage_blobs
   end
 
-  def duplicate
-    page = self.dup
-    page.published = false
-    page.save
-    blocks.ordered.each do |block|
-      b = block.duplicate
-      b.about = page
-      b.position = block.position
-      b.save
-    end
-    page
-  end
-
   def to_s
     "#{title}"
   end
diff --git a/app/models/communication/website/post.rb b/app/models/communication/website/post.rb
index 723c144fa40671161ba96c4590a9db8bb0be64bf..5264c87a58e5cc09dc1be2f23935b5bc17d7235e 100644
--- a/app/models/communication/website/post.rb
+++ b/app/models/communication/website/post.rb
@@ -39,15 +39,16 @@
 #
 class Communication::Website::Post < ApplicationRecord
   include Sanitizable
-  include WithUniversity
-  include WithGit
-  include WithFeaturedImage
   include WithBlobs
   include WithBlocks
+  include WithDuplication
+  include WithFeaturedImage
+  include WithGit
   include WithMenuItemTarget
   include WithPermalink
   include WithSlug # We override slug_unavailable? method
   include WithTranslations
+  include WithUniversity
 
   has_summernote :text # TODO: Remove text attribute
 
@@ -145,20 +146,6 @@ class Communication::Website::Post < ApplicationRecord
     "#{Static.remove_trailing_slash website.url}#{Static.clean_path current_permalink_in_website(website).path}"
   end
 
-  def duplicate
-    post = self.dup
-    post.published = false
-    post.published_at = nil
-    post.save
-    blocks.ordered.each do |block|
-      b = block.duplicate
-      b.about = post
-      b.position = block.position
-      b.save
-    end
-    post
-  end
-
   def translated_author
     @translated_author ||= author.find_or_translate!(language)
   end
diff --git a/app/models/concerns/with_duplication.rb b/app/models/concerns/with_duplication.rb
new file mode 100644
index 0000000000000000000000000000000000000000..3285ff9a664e02dcabd2f992dd2b0561b16f85cf
--- /dev/null
+++ b/app/models/concerns/with_duplication.rb
@@ -0,0 +1,39 @@
+module WithDuplication
+  extend ActiveSupport::Concern
+
+  def duplicate
+    instance = duplicate_instance
+    duplicate_blocks_to(instance)
+    duplicate_featured_image_to(instance)
+    instance
+  end
+
+  protected
+
+  def duplicate_instance
+    instance = self.dup
+    instance.published = false if respond_to?(:published)
+    instance.published_at = nil if respond_to?(:published_at)
+    instance.save
+    instance
+  end
+
+  def duplicate_blocks_to(instance)
+    return unless respond_to?(:blocks)
+    blocks.ordered.each do |block|
+      b = block.duplicate
+      b.about = instance
+      b.position = block.position
+      b.save
+    end
+  end
+
+  def duplicate_featured_image_to(instance)
+    return unless respond_to?(:featured_image) && featured_image.attached?
+    instance.featured_image.attach(
+      io: URI.open(featured_image.url),
+      filename: featured_image.filename.to_s,
+      content_type: featured_image.content_type
+    )
+  end
+end
\ No newline at end of file