diff --git a/index.php b/index.php
index 2c752341c..733074d79 100644
--- a/index.php
+++ b/index.php
@@ -14,6 +14,7 @@ require __DIR__ . '/common.php';
$page_cfg['load_tpl_vars'] = [
'post_icons'
];
+$page_cfg['canonical_link'] = true;
// Show last topic
$show_last_topic = true;
diff --git a/library/includes/functions.php b/library/includes/functions.php
index 67256eb1f..2f0764ed1 100644
--- a/library/includes/functions.php
+++ b/library/includes/functions.php
@@ -2236,3 +2236,43 @@ function infoByIP(string $ipAddress, int $port = 0): array
return $data;
}
+
+/**
+ * Generates canonical url
+ *
+ * @return string
+ */
+function getCanonicalUrl(): string
+{
+ $fullUrl = rtrim(FULL_URL, '/');
+ $script = $_SERVER['SCRIPT_NAME'];
+
+ $allowedParams = [
+ POST_CAT_URL,
+ POST_FORUM_URL,
+ POST_GROUPS_URL,
+ POST_POST_URL,
+ POST_TOPIC_URL,
+ POST_USERS_URL,
+ 'sort',
+ 'start',
+ 'order'
+ ];
+
+ $params = [];
+ foreach ($allowedParams as $key) {
+ if (isset($_GET[$key])) {
+ $params[$key] = $_GET[$key];
+ }
+ }
+
+ if (!empty($params)) {
+ ksort($params);
+ $queryString = http_build_query($params, '', '&', PHP_QUERY_RFC3986);
+ $url = $fullUrl . $script . "?$queryString";
+ } else {
+ $url = $fullUrl . $script;
+ }
+
+ return htmlCHR($url);
+}
diff --git a/library/includes/page_header.php b/library/includes/page_header.php
index f2f22581b..0c715ddaa 100644
--- a/library/includes/page_header.php
+++ b/library/includes/page_header.php
@@ -123,6 +123,9 @@ $template->assign_vars([
'USE_TABLESORTER' => !empty($page_cfg['use_tablesorter']),
'ALLOW_ROBOTS' => !$bb_cfg['board_disable'] && (!isset($page_cfg['allow_robots']) || $page_cfg['allow_robots'] === true),
+ 'META_CANONICAL' => (isset($page_cfg['canonical_link']) && $page_cfg['canonical_link'] === true)
+ ? getCanonicalUrl()
+ : ((isset($page_cfg['canonical_link']) && is_string($page_cfg['canonical_link'])) ? $page_cfg['canonical_link'] : false),
'META_DESCRIPTION' => $page_cfg['meta_description'] ?? '',
'SITENAME' => $bb_cfg['sitename'],
diff --git a/styles/templates/default/page_header.tpl b/styles/templates/default/page_header.tpl
index 0ec5fb8f5..5216225dd 100644
--- a/styles/templates/default/page_header.tpl
+++ b/styles/templates/default/page_header.tpl
@@ -25,6 +25,9 @@
+
+
+
diff --git a/viewforum.php b/viewforum.php
index 7a1cdb4a3..17b962e9e 100644
--- a/viewforum.php
+++ b/viewforum.php
@@ -12,6 +12,7 @@ define('BB_SCRIPT', 'forum');
require __DIR__ . '/common.php';
$page_cfg['include_bbcode_js'] = true;
+$page_cfg['canonical_link'] = true;
$show_last_topic = true;
$last_topic_max_len = 40;
diff --git a/viewtopic.php b/viewtopic.php
index f952e0f15..e71470904 100644
--- a/viewtopic.php
+++ b/viewtopic.php
@@ -22,6 +22,7 @@ $page_cfg['load_tpl_vars'] = [
'post_icons',
'topic_icons'
];
+$page_cfg['canonical_link'] = true;
$newest = $next_topic_id = 0;
$start = isset($_GET['start']) ? abs((int)$_GET['start']) : 0;