From c99f6c68d52e31357e3bbd563df293f5b74ed9d9 Mon Sep 17 00:00:00 2001
From: Jens Schwidder
Date: Mon, 20 Apr 2026 20:25:51 +0200
Subject: [PATCH 01/10] #1444 Option to remove RSS links (#1466)
* #1444 Control rendering of RSS links
* #1444 RSS links release notes
---
RELEASE_NOTES.md | 9 ++
application/configs/application.ini | 1 +
library/Application/View/Helper/RssLink.php | 85 +++++++++++++
.../Application/View/Helper/RssMetaLink.php | 58 +++++++++
modules/home/views/scripts/index/index.phtml | 8 +-
.../views/scripts/browse/doctypes.phtml | 4 +-
.../views/scripts/browse/index.phtml | 4 +-
.../views/scripts/browse/series.phtml | 4 +-
.../views/scripts/browse/years.phtml | 5 +-
.../scripts/index/browsecollection.phtml | 5 +-
.../views/scripts/index/nohits.phtml | 8 +-
.../views/scripts/index/results.phtml | 8 +-
.../scripts/index/simpleSearchForm.phtml | 4 +-
.../Application/View/Helper/RssLinkTest.php | 118 ++++++++++++++++++
.../View/Helper/RssMetaLinkTest.php | 95 ++++++++++++++
15 files changed, 375 insertions(+), 41 deletions(-)
create mode 100644 library/Application/View/Helper/RssLink.php
create mode 100644 library/Application/View/Helper/RssMetaLink.php
create mode 100644 tests/library/Application/View/Helper/RssLinkTest.php
create mode 100644 tests/library/Application/View/Helper/RssMetaLinkTest.php
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 6f66e43a7..3e07921c8 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,14 @@
# OPUS 4 Release Notes
+## Release 4.10 - 2026-05-12
+
+### RSS-Links
+
+RSS-Links können nun ausgeblendet werden. Sie werden automatisch ausgeblendet,
+wenn ein User keinen Zugriff auf das RSS-Modul hat.
+
+ rss.showLinks = 0
+
## Release 4.9 - 2026-04-14
### Unterstützte PHP-Versionen
diff --git a/application/configs/application.ini b/application/configs/application.ini
index 9e941e643..a775403a8 100644
--- a/application/configs/application.ini
+++ b/application/configs/application.ini
@@ -250,6 +250,7 @@ search.index.enrichment.blacklist = 'opus_doi_json'
; RSS Feed
rss.maxDocs = 100
+rss.showLinks = 1
;DOCTYPE VALIDATION SCHEMA FILE
; TODO determine path dynamically (does this belong into the framework)
diff --git a/library/Application/View/Helper/RssLink.php b/library/Application/View/Helper/RssLink.php
new file mode 100644
index 000000000..9b1e3d0c8
--- /dev/null
+++ b/library/Application/View/Helper/RssLink.php
@@ -0,0 +1,85 @@
+isShowRssLinks() || ! $this->isRssAllowed()) {
+ return '';
+ }
+
+ $view = $this->view;
+
+ if (is_string($options)) {
+ $rssUrl = $options;
+ } else {
+ $basicOptions = [
+ 'module' => 'rss',
+ 'controller' => 'index',
+ 'action' => 'index',
+ ];
+
+ if (is_array($options)) {
+ $rssUrl = $view->url(array_merge($basicOptions, $options), null, true);
+ } else {
+ $rssUrl = $view->url($basicOptions, null, true);
+ }
+ }
+
+ $imagePath = $view->layoutPath() . '/img/feed_small.png';
+ $alt = $view->translate('rss_icon');
+ $title = $view->translate('rss_title');
+
+ $output = "";
+
+ return $output;
+ }
+
+ protected function isShowRssLinks(): bool
+ {
+ $config = $this->getConfig();
+ return isset($config->rss->showLinks) && filter_var($config->rss->showLinks, FILTER_VALIDATE_BOOLEAN);
+ }
+
+ protected function isRssAllowed(): bool
+ {
+ $realm = Realm::getInstance();
+ return $realm->checkModule('rss');
+ }
+}
diff --git a/library/Application/View/Helper/RssMetaLink.php b/library/Application/View/Helper/RssMetaLink.php
new file mode 100644
index 000000000..9b9ad5710
--- /dev/null
+++ b/library/Application/View/Helper/RssMetaLink.php
@@ -0,0 +1,58 @@
+isShowRssLinks() || ! $this->isRssAllowed()) {
+ return '';
+ }
+
+ $view = $this->view;
+
+ if ($rssUrl === null) {
+ $rssUrl = $view->baseUrl() . '/rss/index/index';
+ }
+
+ $view->headLink([
+ 'rel' => 'alternate',
+ 'type' => 'application/rss+xml',
+ 'href' => $view->serverUrl() . $rssUrl,
+ ]);
+
+ return '';
+ }
+}
diff --git a/modules/home/views/scripts/index/index.phtml b/modules/home/views/scripts/index/index.phtml
index b19e045e4..5811d0105 100644
--- a/modules/home/views/scripts/index/index.phtml
+++ b/modules/home/views/scripts/index/index.phtml
@@ -31,13 +31,7 @@
?>
-headLink([
- 'rel' => 'alternate',
- 'type' => 'application/rss+xml',
- 'href' => $this->serverUrl() . $this->baseUrl() . '/rss/index/index',
- ]);
- ?>
+rssMetaLink() ?>
title = 'home_index_index_pagetitle' ?>
diff --git a/modules/solrsearch/views/scripts/browse/doctypes.phtml b/modules/solrsearch/views/scripts/browse/doctypes.phtml
index 814c9fef7..cb93e7f0f 100644
--- a/modules/solrsearch/views/scripts/browse/doctypes.phtml
+++ b/modules/solrsearch/views/scripts/browse/doctypes.phtml
@@ -41,9 +41,7 @@
= htmlspecialchars($this->translate($facetitem->getText())) ?>
(= $facetitem->getCount() ?>)
-
+ = $this->rssLink(['searchtype' => 'simple', 'query' => '*:*', 'doctypefq' => $facetitem->getText()]) ?>
diff --git a/modules/solrsearch/views/scripts/browse/index.phtml b/modules/solrsearch/views/scripts/browse/index.phtml
index eb469f268..d995cf034 100644
--- a/modules/solrsearch/views/scripts/browse/index.phtml
+++ b/modules/solrsearch/views/scripts/browse/index.phtml
@@ -44,9 +44,7 @@
showLatestDocuments) : ?>
= htmlspecialchars($this->translate('latest_documents_title')) ?>
-
+ = $this->rssLink() ?>
showDocumentTypes) : ?>
diff --git a/modules/solrsearch/views/scripts/browse/series.phtml b/modules/solrsearch/views/scripts/browse/series.phtml
index eef51c2bc..5fe693067 100644
--- a/modules/solrsearch/views/scripts/browse/series.phtml
+++ b/modules/solrsearch/views/scripts/browse/series.phtml
@@ -38,9 +38,7 @@
series as $seriesitem) : ?>
= htmlspecialchars($seriesitem['title']) ?>
-
+ = $this->rssLink(['searchtype' => 'series', 'id' => $seriesitem['id']]) ?>
diff --git a/modules/solrsearch/views/scripts/browse/years.phtml b/modules/solrsearch/views/scripts/browse/years.phtml
index 1baa05f8a..41c59af95 100644
--- a/modules/solrsearch/views/scripts/browse/years.phtml
+++ b/modules/solrsearch/views/scripts/browse/years.phtml
@@ -41,10 +41,7 @@
= htmlspecialchars($this->translate($facetitem->getText())) ?>
(= $facetitem->getCount() ?>)
-
+ = $this->rssLink(['searchtype' => 'simple', 'query' => '*:*', 'yearfq' => $facetitem->getText()]) ?>
diff --git a/modules/solrsearch/views/scripts/index/browsecollection.phtml b/modules/solrsearch/views/scripts/index/browsecollection.phtml
index eaf5e031b..5e28286f6 100644
--- a/modules/solrsearch/views/scripts/index/browsecollection.phtml
+++ b/modules/solrsearch/views/scripts/index/browsecollection.phtml
@@ -84,10 +84,7 @@ use Opus\Common\Config;
= htmlspecialchars($child->getDisplayNameForBrowsingContext($this->collectionRole)) ?>
(= $documentCount ?>)
-
+ = $this->rssLink(['searchtype' => 'collection', 'id' => $child->getId()]) ?>
diff --git a/modules/solrsearch/views/scripts/index/nohits.phtml b/modules/solrsearch/views/scripts/index/nohits.phtml
index 1e65c61bb..fb0834ffd 100644
--- a/modules/solrsearch/views/scripts/index/nohits.phtml
+++ b/modules/solrsearch/views/scripts/index/nohits.phtml
@@ -31,13 +31,7 @@
?>
-headLink([
- 'rel' => 'alternate',
- 'type' => 'application/rss+xml',
- 'href' => $this->serverUrl() . $this->url($this->rssUrl),
- ]);
- ?>
+rssMetaLink($this->url($this->rssUrl)) ?>
searchType === 'simple') {
diff --git a/modules/solrsearch/views/scripts/index/results.phtml b/modules/solrsearch/views/scripts/index/results.phtml
index 7b7a55243..863087a6a 100644
--- a/modules/solrsearch/views/scripts/index/results.phtml
+++ b/modules/solrsearch/views/scripts/index/results.phtml
@@ -37,13 +37,7 @@ if ($this->jQueryEnabled()) {
}
?>
-headLink([
- 'rel' => 'alternate',
- 'type' => 'application/rss+xml',
- 'href' => $this->serverUrl() . $this->url($this->rssUrl),
- ]);
- ?>
+rssMetaLink($this->url($this->rssUrl)) ?>
specialTitle)) : ?>
= htmlspecialchars($this->specialTitle) ?>
diff --git a/modules/solrsearch/views/scripts/index/simpleSearchForm.phtml b/modules/solrsearch/views/scripts/index/simpleSearchForm.phtml
index aae0f5a09..636a3b449 100644
--- a/modules/solrsearch/views/scripts/index/simpleSearchForm.phtml
+++ b/modules/solrsearch/views/scripts/index/simpleSearchForm.phtml
@@ -60,9 +60,7 @@ if ($this->jQueryEnabled()) {
?>
= $searchAllDocsText; ?>
= $this->translate('solrsearch_title_latest'); ?>
-
+ = $this->rssLink() ?>
diff --git a/tests/library/Application/View/Helper/RssLinkTest.php b/tests/library/Application/View/Helper/RssLinkTest.php
new file mode 100644
index 000000000..c0636141c
--- /dev/null
+++ b/tests/library/Application/View/Helper/RssLinkTest.php
@@ -0,0 +1,118 @@
+helper = new Application_View_Helper_RssLink();
+ $this->helper->setView($this->getView());
+ }
+
+ public function testRssLinkDefault()
+ {
+ $output = $this->helper->rssLink();
+
+ $expected = <<