* Add option to keep or reset article sort order when navigating
Adds a new per-user reading option, "Keep the current sort order when
navigating between categories and feeds" (config key: sticky_sort), under
Settings > Reading > "Left navigation: Categories". It defaults to enabled,
which reproduces the current behaviour exactly.
Background (addresses #8953)
----------------------------
Once a sort/order was active in one view, it was propagated to every sidebar
link and to the "mark all as read" redirect. Opening another category then
ignored that category's own defaultSort/defaultOrder, because FreshRSS_Context
only applies those defaults when sort/order are absent from the request. As a
result the current view's sort (whether chosen manually or resolved from that
view's default) "bled" into the next category/feed.
Behaviour of the new option
---------------------------
- ON (default): unchanged. The current sort/order stays sticky while
navigating, exactly as before.
- OFF: sidebar links and the "mark all as read" redirect no longer carry
sort/order, so each target resolves its own order in FreshRSS_Context:
feed/category defaultSort/defaultOrder, falling back to the global Reading
sort criterion when none is configured.
order/sort propagation across the UI (for reference)
----------------------------------------------------
- Categories & feeds (sidebar): now gated by sticky_sort (app/layout/aside_feed.phtml).
- "Mark all as read" -> next category, both the top navigation button and the
stream-footer button: now gated by sticky_sort
(app/Controllers/entryController.php::readAction, non-AJAX redirect).
- Custom user queries: unaffected. A query's link is a self-contained URL built
from that query's own saved parameters, so switching query A -> B never
carried A's sort; no option is needed there.
- Stream transition links when sorting by category/feed name: intentionally
left unchanged (out of scope; the sort is intrinsic to that grouping).
Compatibility
-------------
- Not a breaking change: the default (true) reproduces the previous behaviour.
- No database migration. The setting is a standard user configuration value
with its default declared in config-user.default.php, so existing users keep
the previous behaviour transparently.
- The read/unread state filter still persists across navigation regardless of
this option.
i18n
----
English strings authored; en-US marked as IGNORE. Translations for the other
25 languages were produced with an automated (AI) translation service and
should be reviewed by native speakers.
* Update app/i18n/en/conf.php
Co-authored-by: Frans de Jonge <fransdejonge@gmail.com>
* Comments preference
* Update app/i18n/en/conf.php
Co-authored-by: Frans de Jonge <fransdejonge@gmail.com>
* i18n updates and comment
* Update translations to match reworded sticky_sort strings
Re-applies the 24 non-English/French translations of the "sticky_sort"
reading option after the English and French wording was updated to
"Keep manual sort order during navigation".
* improve Dutch
* i18n DIRTY
* i18n en: custom sort order
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
Co-authored-by: Frans de Jonge <fransdejonge@gmail.com>
* Worked on Turkish translation
* Add my name to CREDITS.md
* Run make fix-all
* Fix credits
---------
Co-authored-by: Utku Tibet <utkutibet@Utkus-MacBook-Pro.local>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* Add SSRF mitigations using `filter_var` and `CURLOPT_RESOLVE`
The idea is to prevent FreshRSS from sending any HTTP requests to internal services, except for the ones that are explicitly allowed in the config.
Based on 6e82b46a48/lib/filelib.php (L3818) and https://github.com/symfony/symfony/blob/8.1/src/Symfony/Component/HttpClient/NoPrivateNetworkHttpClient.phphttps://github.com/FreshRSS/simplepie/pull/76https://github.com/FreshRSS/simplepie/pull/78
* Add allowlist setting in Web UI
* make readme
* Update app/i18n/fr/admin.php
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* make readme again
* make readme
* Further work
Still WIP and needs testing etc.
* Readd previous if check for domain combination allowlist
* Turn POST to GET after redirect
* Improve
* Update config.default.php
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* make readme
* Skip SSRF check if `CURLOPT_PROXY` is set
* make readme
* Fix `!empty()` mistake
* Respect max redirects feed option when fetching with `httpGet()`
* Respect max redirects during SimplePie fetching + fix bypass
bypass fix: `CURLOPT_FOLLOWLOCATION` was moved below so that emulated redirects are enforced.
* Avoid FreshRSS and Minz code in SimplePie
https://github.com/FreshRSS/FreshRSS/pull/8400#discussion_r2935375980
* Corrected hook code
* phpdoc wrong return type
* Add CIDR support in allowlist
* Implement simple DNS caching
* Suppress `dns_get_record()` warnings
* A bit of proof-reading
* Minor typo
* Fix proxy logic
* Fix HTTP POST redirect logic
* Proofread checkCIDR
Add fixes for several situations
* Remove credentials from URL in logs
* Ensure `CURLOPT_FOLLOWLOCATION` is `false` by setting it at the end
* Fix codesniffer long line
* Fix potential bypass due to wrong return value
If there were no records returned by `dns_get_record()`, no overrides to `CURLOPT_RESOLVE` would get passed,
and a potential bypass could occur, when cURL would try to resolve the domain by itself.
* Put the URL at the end in logs
* Add documentation and environment variable support
* make readme
* Fix wrong behavior in case of IP
* Fix duplicate selector in CSS
* Minor type check change
* i18n fr, en
* Minor type check change
* Fix whitespace i18n fr
* make fix-all
* Fix `$ips_ok` not being returned after domain records were cached
* make readme
* PHPStan fix
* make readme
* Minor syntax in SimplePie
* Only return `null` if no allowed IPs were found
* Add wildcard *, help message
* Consistent docs with help message
* i18n: pl
* SimplePie compatibility PHP 7.2
* make fix-all
* Sync SimplePie
* https://github.com/FreshRSS/simplepie/pull/76
* 💥 Breaking change in the Changelog
* Document `INTERNAL_HOST_ALLOWLIST` in Docker docs
* Remove `Cookie` and `Authorization` headers in `httpGet()` during cross-origin redirect
* Minor whitespace
And same comment convention than below
* Remove authentication headers and change POST to GET on redirect in SimplePie
* Remove .local in Docker example
* Fill in default ports when comparing URL origins
* Remove .local from other places than the Docker example
* Rewrite WebSub subscribe to use `httpGet()`
* make fix-all
* Also unset `CURLOPT_USERPWD` during redirects
* phpcs fix
* Always unset `CURLOPT_FOLLOWLOCATION`
* Bump SimplePie
https://github.com/FreshRSS/simplepie/pull/78
* Update logic for CURLOPT_FOLLOWLOCATION
* Fix PHPStan
* Changelog fix security section
* Update most common RSS Bridge case
https://hub.docker.com/r/rssbridge/rss-bridge
* Replace misleading 127.0.0.1:8080 example for Docker
This does not make sense for a Docker container
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* Add a warning message to the API password section, add a log warning when a client uses GET, use POST in sample curl API usage
References #8834.
* Apply suggestion from @Inverle
Co-authored-by: Inverle <inverle@proton.me>
* Apply suggestion from @Inverle (Polish translation)
Co-authored-by: Inverle <inverle@proton.me>
* French translation
* Dutch translation
* German
* Apply suggestion from @Inverle api via post
Co-authored-by: Inverle <inverle@proton.me>
* Apply suggestion from @Inverle via POST (French)
Co-authored-by: Inverle <inverle@proton.me>
* Add user-agent
* update translation info in README
* avoid phpcs line too long
* also trigger on email as suggested by @Inverle
* i18n: fr typography
* make fix-all
---------
Co-authored-by: Inverle <inverle@proton.me>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
#8839
**Change(s)**
- Fix some typos
- Revise the translations that I hadn't checked before
- Add some new translations
**File(s) changed**
`app/i18n/zh-TW/{admin,conf,gen,sub,user}.php`
`README.md`
`README.fr.md`
* docs: normalize APIs & native apps table glyphs to monochrome
* docs: use en-dash instead of ✗ for "no" in APIs & native apps table
Per maintainer feedback on #8821: ✗ reads as an error/failure mark; an
en-dash is a neutral "not applicable / no" glyph more appropriate for
a feature-matrix table.
* docs: normalize APIs & native apps table glyphs in French README
Mirror the monochrome-glyph substitutions from README.md:
`✔️` -> `✓`, `➖` -> `–`, `❔` -> `?`, `💲` -> `$`.
---------
Co-authored-by: Bjørn A. Andersen <polybjorn@users.noreply.github.com>
Adds two requested clients to the APIs & native apps tables: FeedFlow (mobile, table 1) and FluentFlame Reader (desktop, table 2).
Both rows go at the bottom of their tables to avoid implying a recommendation order, since [an earlier comment](https://github.com/FreshRSS/FreshRSS/pull/8787#issuecomment-4373379000) noted the top reflects recommended apps.
Columns come from each project's README. Cells not documented upstream are left as `❔`, same as Vienna RSS, lire, and Fiery Feeds.
FluentFlame Reader is marked `Work in progress` because its [README](https://github.com/FluentFlame/fluentflame-reader#download) states "Currently we do not have any stable version!". Same handling as the Netnewswire row.
FeedFlow's sync-spam issue was fixed upstream in [feed-flow#425](https://github.com/prof18/feed-flow/issues/425), closed 2025-02-06 with commit [`a6b6e4c`](a6b6e4ce76). 15 months and 14 releases since, no re-report.
Potentially closes#7301, #8608
Co-authored-by: Bjørn A. Andersen <polybjorn@users.noreply.github.com>
* Update the zh-tw translation for conf.php
* Fix translation errors in previous PRs
Also add more new translations.
* make fix-all
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* Update the zh-tw translation for admin.php
* Update the zh-tw translation for index.php
* Update the zh-tw translation for user.php
* Correct the typos in install.php
* make fix-all
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* Reorder add feed and add category
Implements some suggestions made in https://github.com/FreshRSS/FreshRSS/issues/2014
Changes proposed in this pull request:
- Move "Add feed" as the first section of the Subscriptions add page.
- Add checkbox "Keep adding feeds" to stay on the "add" page.
How to test the feature manually:
1. Navigate to the page "Add a feed or category"
2. See new order.
3. Type URL of a new feed, select a category, and check "Keep adding feeds "
4. See FreshRSS confirm the feed was added while staying in the same page.
* Add checkbox to stay in the add feed page
* Update i18n
* PHP CS
* Manually set i18n progress
* Change i18n
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
Closes https://github.com/FreshRSS/FreshRSS/issues/8508
Changes proposed in this pull request:
- Use an integer for `Feed::error` everywhere (follow up to #8646)
- Extract `Entry::machineReadableDate()` into function for use in HTML templates
- Add `timeago()` function that converts a unix timestamp into a "4 weeks ago" string
- Show the last successful feed update, and the last erroneous update
How to test the feature manually:
1. Update a feed
2. Modify the feed URL in the database and set it to a non-existing URL
3. Update the feed again
4. Open the "Manage feed" and see the expanded error message:
> Blast! This feed has encountered a problem. If this situation persists, please verify that it is still reachable.
> Last successful update 3 hours ago, last erroneous update 1 hour ago.
You can hover the relative dates to see the timestamp.
* Make Feed::error an int everywhere
Related: https://github.com/FreshRSS/FreshRSS/pull/8646
* Extract timestamptomachinedate()
.. for later usage in the feed error time display.
* Show time since when a feed has problems
We add our own "timeago" function that converts a unix timestamp
into a "4 weeks ago" string.
Resolves: https://github.com/FreshRSS/FreshRSS/issues/8508
* Add new translation keys
* i18n fr, en-US
* Minor XHTML preference
* Slightly shorter rewrite, also hopefully easier to read
* Rewrite to allow (simple) plural
I also moved some functions around for hopefully a more generic and better structure.
I made some changes for the sake of speed (e.g. second-based logic instead of datetime intervals).
Note: I used automatic translation as I was worried it would be too complicated to explain to translators... I proofread the few languages I have some familiarity with.
* Add reference to CLDR
* Slightly more compact syntax
* Always show last update, fix case of unknown error date
* Remove forgotten span
* No need for multi-lines anymore
* Fix error date thresshold
* plurals forms
* Extract gettext formula conversion script to cli
* Simplify a bit
* Escort excess parentheses to the door
* Simplify
* Avoid being too clever in localization
* Fix German
* Fix plural TODO parsing
* Ignore en-US translation
* make fix-all
* git update-index --chmod=+x cli/compile.plurals.php
* Heredoc indent PHP 7.3+
* compileAll: Continue on error
* PHP strict comparisons
* Light logical simplification
* Cache plural_message_families
* Avoid case of empty value
* A bit of documentation
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
Co-authored-by: Frans de Jonge <frans@clevercast.com>
Co-authored-by: Frans de Jonge <fransdejonge@gmail.com>
* Add form to create user queries
Closes https://github.com/FreshRSS/FreshRSS/issues/6361
Changes proposed in this pull request:
- Add a form to create new user queries on the User Queries page
- Fix the controller to properly handle request data
How to test the feature manually:
1. Open FreshRSS
2. Open Settings
3. Click User queries
4. Create new user query
* Add tranlation key for title in create new user query
* Fix 'for' conflict with aside in labels
* Fix input widths
* i18n: fr
* make fix-all
* Fix conditions in configureController
* Remove token condition
* Fix ctype_digits condition
* Fix errors
* Fix phpStan error
* Fix syntax and state for checkboxes
* Add new way to create user queries in docs
* Compress image more
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* German Translation updates
* Fix German translations in admin.php
* Fix capitalization in encoding support warning
* Update German translations in admin.php
* Fix capitalization in encoding support warning
* Update German Translation of conf.php
* Update German translations for feedback messages
* Update German translations in index.php
* Update German translations in install.php
* Update German translations in sub.php
* Fix German translations for email validation messages
* make fix-all
* Update ZIP extension message in German translation
* make fix-all
* Update app/i18n/de/conf.php
Co-authored-by: maTh <1645099+math-GH@users.noreply.github.com>
* Update app/i18n/de/admin.php
Co-authored-by: maTh <1645099+math-GH@users.noreply.github.com>
* Update app/i18n/de/conf.php
Co-authored-by: maTh <1645099+math-GH@users.noreply.github.com>
* Global replace of Twitter → X (Twitter)
* Also ignore Twitter in German
* Update sensitive parameter description in German
* Ungelesene Artikel
* fix typo
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
Co-authored-by: maTh <1645099+math-GH@users.noreply.github.com>
Co-authored-by: Frans de Jonge <fransdejonge@gmail.com>
* Update database title translation to Italian
* Update app/i18n/it/install.php
* make fix-all
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* Translate database connection messages to Italian
Added missing Italian translations to FreshRSS/app/i18n/it/install.php
* make fix-all
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* Add option to hide sidebar by default (#8515)
Closes https://github.com/FreshRSS/FreshRSS/issues/8515
Changes proposed in this pull request:
- Add `sidebar_hidden_by_default` user preference (default: `false`)
- Add a checkbox in the Display settings page to toggle this preference
- Hide the sidebar on page load in `normal` and `reader` views when the preference is enabled and no session state exists
- Add English translation key; mark all other languages as `TODO` for translators
How to test the feature manually:
1. Go to Settings → Display, tick "Hide sidebar by default", save
2. Go back to the main view (normal or reader): the sidebar should be hidden on load
3. Toggle the sidebar manually — it should open/stay open for the rest of the session
4. Open a new tab: the sidebar should be hidden again
5. Go to Settings → Display, untick the option, save: the sidebar should now be visible on load as usual
6. Check that the sidebar is always visible on Settings pages regardless of the preference
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: PR comment
* Update app/i18n/pl/conf.php
* i18n: fr
* make fix-all
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Inverle <inverle@proton.me>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* Re-add database status in installation check
It got disabled in 2014 to get a beta out.
Time to re-enable it.
Tested on SQLite.
"checkTable" now only verifies that at least the expected columns
exist, but does not fail on additional columns provided by
e.g. extensions.
Related: https://github.com/FreshRSS/FreshRSS/issues/678
* make fix-all
* i18n
* Simpler and more correct content_bin
* Fix PostgreSQL
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* docs: Fix broken or dead links
Used the following commands to find broken links:
1. `lychee -E --dump https://freshrss.github.io/FreshRSS/en/ --include freshrss.github.io --output links.txt`
2. `lychee -v --suggest --archive wayback --timeout 5 -u "Mozilla/5.0 (X11; Linux x86_64; rv:148.0) Gecko/20100101 Firefox/148.0" --files-from links.txt --output output.txt`
3. `cat output.txt`
Then did the same for https://freshrss.github.io/FreshRSS/fr/
We could look into using lychee in CI:
https://github.com/lycheeverse/lychee?tab=readme-ov-file#github-action-usage
* Replace PostgreSQL 16 link with current version
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* Remove paragraph about bug message format
* Update README with official app website links
* Replace broken French images with English versions
* Fix broken Fever API docs link in French docs
* Replace GNU Social link with new one in `shares.php`
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* Translate notification enable message to German
* Translate English phrases to German in admin.php
* Translate UI strings to German
Translated various UI strings from English to German.
* Update German translations in index.php
* make fix-all
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
* added local feed sorting
Addresses https://github.com/FreshRSS/FreshRSS/issues/4761
- Added number of sorted feeds and associative array for feed sorting option in Context.
- Number of sorted feeds and local sorting option by its index saved into Minz Request Parameters.
- Number of sorted feeds and local sorting options deleted when choosing another Option Of Global Sorting.
- Added option of allowing sorting by feed in configuration.
- Added variable for allowing local sorting in userConf.
- Added function to get feeds by current get in context.
- Added menu button for all individual feed sorting.
- New database options for individual feed sorting in EntryDAO.
- Considered choosing new entries based on chosen load limit.
- Local sorting parameter saved into continuation value in Index Controller.
How to test the feature manually:
1. At the bottom of Reading Configuration menu turn on individual sorting option menu
2. Choose Sorting by feed option
3. Choose feed at next sorting menu and choose sorting option for that feed
* added feed sorting option
* added sort feeds display
* added template for sort feed name
* added title to feed sorting button
* added comments
* added local sorting option
* Added Docs
* css reset
* added getter and seter for local sort
* added getter and seter for local sort
* allowed sorting per feed
* allowed sorting per feed
* added sorting option for category
* deleted changes from NetryDAO
* add setting up sorting for category
* docs reset
* i18 reset
* updated i18 for category
* added i18 for categories
* added i18 for category
* added setting sorting for feeds and category
* removing userConf.allow-local-sort
* removing userConf.allow-local-sort
* removing white space
* added credits
* removed feeds_by_get
* removed whitespace
* changed escaping for values
* added escaping to user set values
* added in_array
* added secondary sort and order
* added secondary sort and order
* fixed readme
* removed whitespace change
* reseted i18n
* added translations
* added feed setting translations
* fixed i18n
* fixed i18n
* changes in sort order per feed
* changes in sort order per feed
* added secondary sort order
* primary sort
* changed to preferred sort order
* i18n
* Revert wrong whitespace changes
* Re-order new options
* added blank option
* fixed escaping
* fixed default sort in feed
* fixed default sort recovery
* siplyfied option
* added rand option
* Revert unrelated change
* Minor plaintext
* Whitespace and formatting fixes
* Avoid unneeded SQL requests and processing
* Improve syntax
* Improve logic
* Reuse existing translations as much as possible
* i18n
* Remove some options that make little sense
* Separators
* Fix old transation key
* Add help messages
* Progress on secondary sort
* raw name
* Pass parameters. Add TODO
* Progress
* Minor ordering
* Fix parenthesis
---------
Co-authored-by: root <root@LAPTOP-C8TCHHPN.localdomain>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
Closes https://github.com/FreshRSS/FreshRSS/issues/7330
- Default behavior is same
- Added FreshRSS_Context::userConf()->html5_disable_notif so that, it determines weather user wants notification. (will not show any even it has permission) (i want default false so disable, so old configs get proper default values)
- Added button such that checking it makes it request permission too
<img width="707" height="119" alt="image" src="https://github.com/user-attachments/assets/a0fdbc4d-9f15-4644-8753-f0e6c979677f" />
- test notification actually happening (how can i trigger it, do i have to wait it), this code fixes permissions.