diff --git a/app/controllers/course/wiki.php b/app/controllers/course/wiki.php
index d817ce01a942983483fe3ebc121169f86032bd27..2420f1d7ecd2984cd290881545090db3f79da230 100644
--- a/app/controllers/course/wiki.php
+++ b/app/controllers/course/wiki.php
@@ -18,6 +18,9 @@ class Course_WikiController extends AuthenticatedController
         parent::before_filter($action, $args);
         object_set_visit_module('wiki');
         $this->range = Context::get();
+        $this->plugin = PluginManager::getInstance()->getPlugin('CoreWiki');
+
+        PageLayout::setTitle(Navigation::getItem('/course/wiki')->getTitle());
     }
 
     public function page_action($page_id = null)
@@ -26,7 +29,6 @@ class Course_WikiController extends AuthenticatedController
             $page_id = $this->range->getConfiguration()->WIKI_STARTPAGE_ID;
         }
         Navigation::activateItem('/course/wiki/start');
-        PageLayout::setTitle(Navigation::getItem('/course/wiki')->getTitle());
 
         $this->page = new WikiPage($page_id);
 
@@ -547,60 +549,51 @@ class Course_WikiController extends AuthenticatedController
         Navigation::activateItem('/course/wiki/listnew');
 
         $this->limit = Config::get()->ENTRIES_PER_PAGE;
+        $this->last_visit = object_get_visit($this->range->id, $this->plugin->getPluginId());
         $statement = DBManager::get()->prepare("
-            SELECT COUNT(*) FROM (
-                SELECT `wiki_pages`.`page_id` AS `id`,
-                       0 AS `is_version`,
-                       `wiki_pages`.`chdate` AS `timestamp`
-                FROM `wiki_pages`
-                WHERE `wiki_pages`.`range_id` = :range_id
-
-                UNION
-
-                SELECT `wiki_versions`.`version_id` AS `id`,
-                       1 AS `is_version`,
-                       `wiki_versions`.`mkdate` AS `timestamp`
-                FROM `wiki_versions`
-                JOIN `wiki_pages` USING (`page_id`)
-                WHERE `wiki_pages`.`range_id` = :range_id
-            ) AS `all_entries`
-        ");
-        $statement->execute([
-            'range_id' => $this->range->id
-        ]);
-        $this->num_entries = $statement->fetch(PDO::FETCH_COLUMN);
-        $this->page = Request::int('page', 0);
-
-        $statement = DBManager::get()->prepare("
-            SELECT `wiki_pages`.`page_id` AS `id`,
-                   0 AS `is_version`,
-                   `wiki_pages`.`chdate` AS `timestamp`
+            SELECT COUNT(*)
             FROM `wiki_pages`
             WHERE `wiki_pages`.`range_id` = :range_id
-
-            UNION
-
-            SELECT `wiki_versions`.`version_id` AS `id`,
-                   1 AS `is_version`,
-                   `wiki_versions`.`mkdate` AS `timestamp`
-            FROM `wiki_versions`
-            JOIN `wiki_pages` USING (`page_id`)
-            WHERE `wiki_pages`.`range_id` = :range_id
-            ORDER BY `timestamp` DESC
-            LIMIT :offset, :limit
+                AND `wiki_pages`.`chdate` > :threshold
+                AND `wiki_pages`.`user_id` != :me
         ");
         $statement->execute([
             'range_id' => $this->range->id,
-            'offset' => Request::int('page', 0) * $this->limit,
-            'limit' => $this->limit
+            'threshold' => $this->last_visit,
+            'me' => User::findCurrent()->id
         ]);
-        $this->versions = [];
-        foreach ($statement->fetchAll(PDO::FETCH_ASSOC) as $row) {
-            if ($row['is_version']) {
-                $this->versions[] = WikiVersion::find($row['id']);
-            } else {
-                $this->versions[] = WikiPage::find($row['id']);
-            }
+        $this->num_entries = $statement->fetch(PDO::FETCH_COLUMN);
+        $this->pagenumber = Request::int('page', 0);
+        $this->sort = Request::option('sort', 'chdate');
+        if (!in_array($this->sort, ['name', 'chdate'])) {
+            $this->sort = 'chdate';
+        }
+        $this->sort_asc = Request::bool('sort_asc', $this->sort === 'name');
+
+
+        if ($this->num_entries > 0) {
+            $statement = DBManager::get()->prepare("
+                SELECT `wiki_pages`.*
+                FROM `wiki_pages`
+                WHERE `wiki_pages`.`range_id` = :range_id
+                    AND `wiki_pages`.`chdate` > :threshold
+                    AND `wiki_pages`.`user_id` != :me
+                ORDER BY `wiki_pages`.`{$this->sort}` " . ($this->sort_asc ? 'ASC' : 'DESC') . "
+                LIMIT :offset, :limit
+            ");
+            $statement->execute([
+                'range_id' => $this->range->id,
+                'threshold' => $this->last_visit,
+                'offset' => $this->pagenumber * $this->limit,
+                'limit' => $this->limit,
+                'me' => User::findCurrent()->id
+            ]);
+            $this->pages = array_map(
+                fn($p) => WikiPage::buildExisting($p),
+                $statement->fetchAll(PDO::FETCH_ASSOC)
+            );
+        } else {
+            $this->pages = [];
         }
     }
 
@@ -1113,4 +1106,24 @@ class Course_WikiController extends AuthenticatedController
             }
         }
     }
+
+    /**
+     * @see https://stackoverflow.com/a/7475502/982902
+     */
+    public function findLongestCommonSubstring(string $str0, string $str1, bool $from_end = false): int
+    {
+        if ($from_end) {
+            $str0 = implode('', array_reverse(mb_str_split($str0, 1)));
+            $str1 = implode('', array_reverse(mb_str_split($str1, 1)));
+        }
+        $length = mb_strlen(
+            mb_strcut(
+                $str0,
+                0,
+                strspn($str0 ^ $str1, "\0")
+            )
+        );
+
+        return $from_end ? mb_strlen($str0) - $length : $length;
+    }
 }
diff --git a/app/views/course/wiki/newpages.php b/app/views/course/wiki/newpages.php
index 0220ac4dcde6843ba632eb86e56750c847dbf14f..d9e0dceea899ae4e9580d7d592548dbf20da382c 100644
--- a/app/views/course/wiki/newpages.php
+++ b/app/views/course/wiki/newpages.php
@@ -1,25 +1,113 @@
-<table class="default sortable-table" data-sortlist="[[3, 1]]">
+<?php
+/**
+ * @var Course_WikiController $controller
+ * @var string $sort
+ * @var bool $sort_asc
+ * @var WikiPage[]|null $pages
+ * @var int $last_visit
+ *
+ * @var int $num_entries
+ * @var int $limit
+ * @var int $pagenumber
+ */
+?>
+<table class="default">
     <caption>
         <?= _('Letzte Änderungen') ?>
     </caption>
+    <colgroup>
+        <col style="min-width: 120px;">
+        <col>
+        <col style="min-width: 150px;">
+        <col>
+    </colgroup>
     <thead>
-        <tr>
-            <th data-sort="text"><?= _('Seitenname') ?></th>
-            <th data-sort="false"><?= _('Text') ?></th>
-            <th data-sort="text"><?= _('Autor/-in') ?></th>
-            <th data-sort="text"><?= _('Datum') ?></th>
+        <tr class="sortable">
+            <th <? if ($sort === 'name') echo 'class="' . ($sort_asc ? 'sortasc' : 'sortdesc') . '"'; ?>>
+                <a href="<?= $controller->newpages(['sort' => 'name', 'sort_asc' => $sort !== 'name' || !$sort_asc ? 1 : 0]) ?>">
+                    <?= _('Seitenname') ?>
+                </a>
+            </th>
+            <th><?= _('Text') ?></th>
+            <th><?= _('Autor/-in') ?></th>
+            <th <? if ($sort === 'chdate') echo 'class="' . ($sort_asc ? 'sortasc' : 'sortdesc') . '"'; ?>>
+                <a href="<?= $controller->newpages(['sort' => 'chdate', 'sort_asc' => $sort === 'chdate' && !$sort_asc ? 1 : 0]) ?>">
+                    <?= _('Datum') ?>
+                </a>
+            </th>
         </tr>
     </thead>
     <tbody>
-        <? foreach (array_reverse($versions) as $version) : ?>
-            <?= $this->render_partial('course/wiki/versioncompare', ['version' => $version]) ?>
-        <? endforeach ?>
+    <? if (count($pages) === 0): ?>
+        <tr>
+            <td colspan="4">
+                <?= _('Keine Seiten wurden seit Ihrem letzten Besuch verändert.') ?>
+            </td>
+        </tr>
+    <? endif ?>
+    <? foreach ($pages as $page) : ?>
+        <tr>
+            <td>
+                <a href="<?= $controller->page($page) ?>">
+                    <?= htmlReady($page->name) ?>
+                </a>
+            </td>
+            <td>
+            <?
+                $authors = [$page->user_id => $page->user];
+                $oldcontent = "";
+                $oldversion = $page;
+                while ($oldversion = $oldversion->predecessor) {
+                    if ($oldversion->mkdate >= $last_visit && $oldversion->user_id !== User::findCurrent()->id) {
+                        $oldcontent = $oldversion->content;
+                        if (!isset($authors[$oldversion->user_id])) {
+                            $authors[$oldversion->user_id] = $oldversion->user;
+                        }
+                    } else {
+                        break;
+                    }
+                }
+                $oldcontent = strip_tags(wikiReady($oldcontent));
+                $content = strip_tags(wikiReady($page->content));
+
+                $commonFromStart = $controller->findLongestCommonSubstring($content, $oldcontent);
+                $commonFromEnd = $controller->findLongestCommonSubstring($content, $oldcontent, true);
+
+                $content = mb_substr($content, $commonFromStart, $commonFromEnd);
+                $oldcontent = mb_substr($oldcontent, $commonFromStart, $commonFromEnd);
+                if ($content) {
+                    echo htmlReady(mila($content, 300), true, true);
+                } elseif ($oldcontent) {
+                    echo _('Gelöscht') . ': ' . htmlReady($oldcontent, true, true);
+                }
+            ?>
+            </td>
+            <td>
+                <ul class="wiki_authors">
+                <? foreach ($authors as $user) : ?>
+                    <li>
+                    <? if ($user): ?>
+                        <a href="<?= URLHelper::getLink('dispatch.php/profile', ['username' => $user->username]) ?>"
+                           style="background-image: url(<?= Avatar::getAvatar($user->id)->getURL(Avatar::SMALL) ?>)"
+                        >
+                            <?= htmlReady($user->getFullName()) ?>
+                        </a>
+                    <? else: ?>
+                        <?= _('unbekannt') ?>
+                    <? endif; ?>
+                    </li>
+                <? endforeach ?>
+                </ul>
+            </td>
+            <td><?= strftime('%x %X', $page->chdate) ?></td>
+        </tr>
+    <? endforeach ?>
     </tbody>
     <? if ($num_entries > $limit) : ?>
         <tfoot>
             <tr>
                 <td colspan="4" class="actions">
-                    <?= Pagination::create($num_entries, $page, $limit)->asLinks() ?>
+                    <?= Pagination::create($num_entries, $pagenumber, $limit)->asLinks() ?>
                 </td>
             </tr>
         </tfoot>
diff --git a/app/views/course/wiki/versioncompare.php b/app/views/course/wiki/versioncompare.php
deleted file mode 100644
index 9c98ce4a27c6ece1bf49c12087c35d1dddb73729..0000000000000000000000000000000000000000
--- a/app/views/course/wiki/versioncompare.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<tr>
-    <td data-sort-value="<?= htmlReady(is_a($version, WikiPage::class) ? $version->name : $version->page->name) ?>">
-        <a href="<?= is_a($version, WikiPage::class) ? $controller->page($version) : $controller->version($version) ?>">
-            <?= htmlReady(is_a($version, WikiPage::class) ? $version->name : $version->page->name) ?>
-        </a>
-    </td>
-    <td>
-        <?
-        $oldversion = $version->predecessor ? $version->predecessor->content : '';
-        $oldcontent = strip_tags(wikiReady($oldversion));
-        $content = strip_tags(wikiReady($version->content));
-        while ($content && $oldcontent && $content[0] == $oldcontent[0]) {
-            $content = substr($content, 1);
-            $oldcontent = substr($oldcontent, 1);
-        }
-        while ($content && $oldcontent && $content[strlen($content) - 1] == $oldcontent[strlen($oldcontent) - 1]) {
-            $content = substr($content, 0, -1);
-            $oldcontent = substr($oldcontent, 0, -1);
-        }
-        if ($content) {
-            echo nl2br(htmlReady(mila($content, 300)));
-        } elseif ($oldcontent) {
-            echo _('Gelöscht') . ': ' . nl2br(htmlReady($oldcontent));
-        } else {
-            echo nl2br(strip_tags(wikiReady(mila($version->content, 300))));
-        }
-
-        ?></td>
-    <? $user = User::find($version->user_id) ?>
-    <td data-sort-value="<?= htmlReady($user ? $user->getFullName() : _('unbekannt')) ?>">
-        <?
-        if ($user) {
-            echo Avatar::getAvatar($user->id)->getImageTag(Avatar::SMALL);
-            echo ' ';
-            echo htmlReady($user->getFullName());
-        } else {
-            echo _('unbekannt');
-        }
-        ?></td>
-    <td data-sort-value="<?= htmlReady(is_a($version, WikiPage::class) ? $version->chdate : $version->mkdate) ?>">
-        <? $chdate = is_a($version, WikiPage::class) ? $version->chdate : $version->mkdate ?>
-        <?= $chdate > 0 ? date('d.m.Y H:i:s', $chdate) : _('unbekannt') ?>
-    </td>
-</tr>
diff --git a/app/views/course/wiki/versiondiff.php b/app/views/course/wiki/versiondiff.php
index 49ac6f4827c412b46234aceb0387a1b94e19fe64..d621446143f42a9a7de686d195e3896a840d2246 100644
--- a/app/views/course/wiki/versiondiff.php
+++ b/app/views/course/wiki/versiondiff.php
@@ -2,16 +2,17 @@
 /**
  * @var WikiPage|WikiVersion $version
  * @var Course_WikiController $controller
+ * @var string $diff
  */
 ?>
 <h3>
     <a href="<?= is_a($version, WikiPage::class) ? $controller->page($version) : $controller->version($version) ?>">
         <? $chdate = is_a($version, WikiPage::class) ? $version->chdate : $version->mkdate ?>
         <?= sprintf(
-            _('Version %1$s, geändert von %2$s am %3$s.'),
-            htmlReady($version->versionnumber),
+            _('Version %1$u, geändert von %2$s am %3$s.'),
+            $version->versionnumber,
             htmlReady($version->user ? $version->user->getFullName() : _('unbekannt')),
-            $chdate > 0 ? date('d.m.Y H:i:s', $chdate) : _('unbekannt')) ?>
+            $chdate ? strftime('%x %X', $chdate) : _('unbekannt')) ?>
     </a>
 </h3>
 <div class="wiki_diffs">
diff --git a/lib/models/WikiPage.class.php b/lib/models/WikiPage.class.php
index a5392b49dc4e6d9e926beca13b261b3b41711a32..3011a26595c2c03e94a394d0e04ef29abed291a3 100644
--- a/lib/models/WikiPage.class.php
+++ b/lib/models/WikiPage.class.php
@@ -22,9 +22,12 @@
  * @property int|null $mkdate database column
  * @property User|null $user belongs_to User
  * @property Course $course belongs_to Course
- * @property-read mixed $parent additional field
- * @property-read mixed $children additional field
- * @property-read mixed $config additional field
+ * @property WikiVersion[]|SimpleORMapCollection $versions
+ * @property WikiOnlineEditingUser[]|SimpleORMapCollection $onlineeditingusers
+ * @property-read WikiPage $parent additional field
+ * @property-read WikiPage[] $children additional field
+ * @property-read WikiVersion|null $predecessor additional field
+ * @property-read int $versionnumber additional field
  */
 class WikiPage extends SimpleORMap implements PrivacyObject
 {
@@ -57,25 +60,25 @@ class WikiPage extends SimpleORMap implements PrivacyObject
         ];
 
         $config['additional_fields']['parent'] = [
-            'get' => function ($page) {
-                return \WikiPage::find($page->parent_id);
+            'get' => function (WikiPage $page): ?WikiPage {
+                return self::find($page->parent_id);
             }
         ];
 
         $config['additional_fields']['children'] = [
-            'get' => function ($page) {
+            'get' => function (WikiPage $page): array {
                 return self::findBySQL('parent_id = ?', [
                     $page->id
                 ]);
             }
         ];
         $config['additional_fields']['predecessor'] = [
-            'get' => function ($page) {
+            'get' => function (WikiPage $page): ?WikiVersion {
                 return $page->versions ? $page->versions[0] : null;
             }
         ];
         $config['additional_fields']['versionnumber'] = [
-            'get' => function ($page) {
+            'get' => function (WikiPage $page): int {
                 return count($page->versions) + 1;
             }
         ];
@@ -92,7 +95,7 @@ class WikiPage extends SimpleORMap implements PrivacyObject
         $this->user_id = User::findCurrent()->id;
         if (
             !$this->isNew()
-            &&  $this->content['content'] !== $this->content_db['content']
+            && $this->content['content'] !== $this->content_db['content']
             && (
                 $this->content_db['user_id'] !== $this->content['user_id']
                 || $this->content_db['chdate'] < time() - 60 * 30
@@ -121,7 +124,7 @@ class WikiPage extends SimpleORMap implements PrivacyObject
 
     /**
      * Returns whether this page is visible to the given user.
-     * @param  mixed  $user User object or id
+     * @param  string|null $user_id User id
      * @return boolean indicating whether the page is visible
      */
     public function isReadable(?string $user_id = null): bool
@@ -166,7 +169,7 @@ class WikiPage extends SimpleORMap implements PrivacyObject
 
     /**
      * Returns whether this page is editable to the given user.
-     * @param  string  $user_id the ID of the user
+     * @param  string|null  $user_id the ID of the user
      * @return boolean indicating whether the page is editable
      */
     public function isEditable(?string $user_id = null): bool
@@ -203,7 +206,7 @@ class WikiPage extends SimpleORMap implements PrivacyObject
      * @param  string $range_id Course id
      * @return WikiPage
      */
-    public static function getStartPage($range_id)
+    public static function getStartPage($range_id): WikiPage
     {
         $page_id = CourseConfig::get($range_id)->WIKI_STARTPAGE_ID;
 
@@ -212,7 +215,6 @@ class WikiPage extends SimpleORMap implements PrivacyObject
         }
 
         $page = new WikiPage();
-        $pagename = _('Startseite');
         $page->content = _('Dieses Wiki ist noch leer.');
         if ($page->isEditable()) {
             $page->content .=  ' ' . _("Bearbeiten Sie es!\nNeue Seiten oder Links werden einfach durch Eingeben von [nop][[Wikinamen]][/nop] in doppelten eckigen Klammern angelegt.");
@@ -244,11 +246,11 @@ class WikiPage extends SimpleORMap implements PrivacyObject
     /**
      * Tests if a given Wikipage name (keyword) is a valid ancestor for this page.
      *
-     * @param   string   ancestor Wikipage name to be tested to be an ancestor
+     * @param   string   $ancestor Wikipage name to be tested to be an ancestor
      * @return  boolean  true if ok, false if not
      *
      */
-    public function isValidAncestor($ancestor)
+    public function isValidAncestor($ancestor): bool
     {
         if ($this->name === 'WikiWikiWeb' || $this->name === $ancestor) {
             return false;
@@ -267,10 +269,10 @@ class WikiPage extends SimpleORMap implements PrivacyObject
     /**
      * Retrieve an array of all descending WikiPages (recursive).
      *
-     * @return   array   Array of all descendant WikiPages
+     * @return WikiPage[] Array of all descendant WikiPages
      *
      */
-    public function getDescendants()
+    public function getDescendants(): array
     {
         $descendants = [];
 
@@ -281,6 +283,9 @@ class WikiPage extends SimpleORMap implements PrivacyObject
         return $descendants;
     }
 
+    /**
+     * @return array
+     */
     public function getOnlineUsers(): array
     {
         $users = [];
diff --git a/resources/assets/stylesheets/scss/variables.scss b/resources/assets/stylesheets/scss/variables.scss
index a915e766f6a0b25edc8fc2e1653f052d132b6c20..a2d90b58ef2e0aa9432c353cba82407fdc2b04c7 100644
--- a/resources/assets/stylesheets/scss/variables.scss
+++ b/resources/assets/stylesheets/scss/variables.scss
@@ -171,6 +171,10 @@ $grid-gap: 0;
     #{"--"}group-color-7: $petrol;
     #{"--"}group-color-8: $brown;
 
+    #{"--"}avatar-small: $avatar-small;
+    #{"--"}avatar-medium: $avatar-medium;
+    #{"--"}avatar-normal: $avatar-normal;
+
     #{"--"}transition-duration: $transition-duration;
     #{"--"}transition-duration-slow: $transition-duration-slow;
 
diff --git a/resources/assets/stylesheets/scss/wiki.scss b/resources/assets/stylesheets/scss/wiki.scss
index 12cf63b3bd579f41189df3897611ad1a1c199ed5..a139eb524c3c89c7a4c312623b3a66eb4191bf3e 100644
--- a/resources/assets/stylesheets/scss/wiki.scss
+++ b/resources/assets/stylesheets/scss/wiki.scss
@@ -185,3 +185,18 @@ article.studip.wiki {
 .wiki_highlight {
     background-color: var(--yellow);
 }
+ ul.wiki_authors {
+     list-style-type: none;
+     padding: 0;
+     li {
+         margin-bottom: 5px;
+     }
+     a {
+         background-position: left top;
+         background-repeat: no-repeat;
+         background-size: var(--avatar-small);
+         display: block;
+         min-height: var(--avatar-small);
+         padding-left: calc(var(--avatar-small) + 1ex);
+     }
+ }