diff --git a/district/models.py b/district/models.py
index ccfd062d491fad0e7a69da49cb24b29fcd84fbfa..242302e3badeb6ab5eb9c936b170cf2b15ca724e 100644
--- a/district/models.py
+++ b/district/models.py
@@ -465,10 +465,14 @@ class DistrictArticlePage(
     def get_context(self, request):
         context = super().get_context(request)
         context["related_articles"] = (
-            self.get_siblings(inclusive=False)
-            .live()  # TODO? filtrovat na stejné tagy? nebo sdílené články?
-            .specific()
-            .order_by("-districtarticlepage__date")[:3]
+            (
+                self.get_siblings(inclusive=False)
+                .live()  # TODO? filtrovat na stejné tagy? nebo sdílené články?
+                .specific()
+                .order_by("-districtarticlepage__date")[:3]
+            )
+            if self.shared_from is None
+            else []
         )
         return context
 
@@ -626,12 +630,7 @@ class DistrictArticlesPage(
         Getuje Tagy pouze pro DistrictArticlePage omezeno IDčky getnutých přes
         root_page. Počítá, kolik článků je s daným tagem.
         """
-        return self.search_tags_by_unioned_id_query(
-            articles,
-            tags_model_query=lambda query: query.annotate(count=models.Count("slug"))
-            .order_by("slug")
-            .values("name", "slug", "count"),
-        )
+        return self.search_tags_with_count(articles)
 
 
 class DistrictContactPage(
diff --git a/shared/models.py b/shared/models.py
index db07abc3057c3f6f1dcec09da7726cad9354e0c1..926dc37b8a881b85936768016c41b4cfb117cf04 100644
--- a/shared/models.py
+++ b/shared/models.py
@@ -114,7 +114,7 @@ class ArticleMixin(models.Model):
         """
         Returns "rel" property for a link to this article
         """
-        return 'rel="noindex"' if self.get_no_index else ""
+        return "rel=noindex" if self.get_no_index else ""
 
     @property
     def get_url(self):
@@ -646,67 +646,81 @@ class ArticlesMixin(models.Model):
         Returns a temporary article class with pk, shared and date as the only properties.
         Useful when optimizing large article queries
         """
-        TmpArticle = namedtuple(
-            "TemporaryArticle", field_names=["page_ptr", "shared_type"]
-        )
+        TmpArticle = namedtuple("TemporaryArticle", field_names=["page_ptr"])
         TmpPrimaryKey = namedtuple("TemporaryPk", field_names=["id"])
         return list(
             map(
                 lambda unioned: TmpArticle(
                     page_ptr=TmpPrimaryKey(id=unioned["union_page_ptr_id"]),
-                    shared_type=unioned["union_shared_type"],
                 ),
-                articles.values("union_page_ptr_id", "union_shared_type", "union_date"),
+                articles.values("union_page_ptr_id", "union_date"),
             )
         )
 
+    def search_tags_with_count(self, articles: list):
+        """
+        Returns a list of tags based on article ids with each count
+        """
+        if isinstance(articles, models.QuerySet):
+            articles = self.materialize_articles_as_id_only(articles)
+
+        article_ids = list(map(lambda article: article.page_ptr.id, articles))
+        tag_list = list(
+            Tag.objects.filter(
+                district_districtarticletag_items__content_object_id__in=article_ids
+            )
+            .union(
+                Tag.objects.filter(
+                    main_mainarticletag_items__content_object_id__in=article_ids
+                ),
+                Tag.objects.filter(
+                    uniweb_uniwebarticletag_items__content_object_id__in=article_ids
+                ),
+                all=True,
+            )
+            .order_by("slug")
+            .values()
+        )
+
+        tag_aggregate = reduce(
+            lambda aggregate, tag: self.merge_dict(
+                aggregate,
+                {tag["slug"]: aggregate[tag["slug"]] + 1}
+                if tag["slug"] in aggregate
+                else {tag["slug"]: 1},
+            ),
+            tag_list,
+            {},
+        )
+        already_present = {}
+        unique_tags = []
+        for tag in tag_list:
+            tag["count"] = tag_aggregate[tag["slug"]]
+            if tag["slug"] not in already_present:
+                unique_tags.append(tag)
+                already_present[tag["slug"]] = True
+
+        return unique_tags
+
     def search_tags_by_unioned_id_query(
         self,
         articles: list,
-        tags_model_query=None,
     ):
         """
         Search tags based on article query or list of articles.
-        Returns a list of Tag objects
+        Returns a list of Tag objects, unique and sorted by slug
         """
         if isinstance(articles, models.QuerySet):
             articles = self.materialize_articles_as_id_only(articles)
 
-        own_page_type = self.determine_page_type()
-        get_ids_by_page_type = lambda page_type: list(
-            map(
-                lambda article: article.page_ptr.id,
-                filter(
-                    lambda article: article.shared_type == page_type
-                    if article.shared_type is not None
-                    else own_page_type.value == page_type,
-                    articles,
-                ),
-            )
-        )
-
+        article_ids = list(map(lambda article: article.page_ptr.id, articles))
         tag_query = Tag.objects.filter(
-            Q(
-                district_districtarticletag_items__content_object_id__in=get_ids_by_page_type(
-                    SharedArticlesPageType.DISTRICT.value
-                )
-            )
-            | Q(
-                main_mainarticletag_items__content_object_id__in=get_ids_by_page_type(
-                    SharedArticlesPageType.MAIN.value
-                )
-            )
-            | Q(
-                uniweb_uniwebarticletag_items__content_object_id__in=get_ids_by_page_type(
-                    SharedArticlesPageType.UNIWEB.value
-                )
-            )
+            Q(district_districtarticletag_items__content_object_id__in=article_ids)
+            | Q(main_mainarticletag_items__content_object_id__in=article_ids)
+            | Q(uniweb_uniwebarticletag_items__content_object_id__in=article_ids)
         )
 
-        if tags_model_query is not None:
-            tag_query = tags_model_query(tag_query)
-
-        return tag_query
+        return tag_query.order_by("slug").distinct("slug")
 
     def search_articles(
         self,
diff --git a/shared/templates/styleguide/2.3.x/article_card.html b/shared/templates/styleguide/2.3.x/article_card.html
index fa7eb5482ce77b92437395b5e87a0bb315a00ff0..aed99e62466db46c0e39f33d249b9d2d0fccb553 100644
--- a/shared/templates/styleguide/2.3.x/article_card.html
+++ b/shared/templates/styleguide/2.3.x/article_card.html
@@ -1,7 +1,7 @@
 {% load wagtailcore_tags wagtailimages_tags %}
 
 <article class="card card--hoveractive article-card " itemtype="http://schema.org/BlogPosting" itemscope="">
-  <link itemprop="mainEntityOfPage" href="{% pageurl article %}">
+  <link itemprop="mainEntityOfPage" href="{{ article.get_url }}">
 
   <div class="article-card-cover">
     <a href="{{ article.get_url }}" {{ article.get_rel }} itemprop="image" itemtype="http://schema.org/ImageObject" itemscope="">
diff --git a/uniweb/models.py b/uniweb/models.py
index b623a6c265d903b94b1c122925b36d66efeff674..07fdf9d5436c88336f741c632e67bee853a69722 100644
--- a/uniweb/models.py
+++ b/uniweb/models.py
@@ -610,10 +610,14 @@ class UniwebArticlePage(
     def get_context(self, request):
         context = super().get_context(request)
         context["related_articles"] = (
-            self.get_siblings(inclusive=False)
-            .live()
-            .specific()
-            .order_by("-uniwebarticlepage__date")[:3]
+            (
+                self.get_siblings(inclusive=False)
+                .live()
+                .specific()
+                .order_by("-uniwebarticlepage__date")[:3]
+            )
+            if self.shared_from is None
+            else []
         )
         return context