A WordPress plugin that re-serves external RSS/Atom feeds with unwanted items removed by keyword — while keeping each feed's original identity (title, link, favicon) in your reader.
Source: https://github.com/ironprogrammer/filtered-feeds Built for the very common case of a publisher flooding its feed with coupon/deal posts. Point the plugin at the feed, list the words you don't want, and subscribe to the cleaned URL instead.
You subscribe your reader to the plugin's URL instead of the origin feed:
https://your-site.example/filtered-feed/{slug}/
On request, the plugin fetches the upstream feed, removes items whose title, categories, or description match any of your keywords, and streams the result back. The channel envelope (title, link, image) is passed through untouched, so NetNewsWire — or any reader — shows the origin's name and favicon exactly as if you had subscribed directly.
Individual feed items are never stored as WordPress posts.
One keyword per line in Settings → Filtered Feeds:
- Case-insensitive substring match.
*is a wildcard, matching any run of characters (e.g.save *%).- Lines beginning with
#are comments. - Matches the item title, its categories (including
media:keywordsanddc:subject), and its description/summary excerpt.
A Preview filtering button dry-runs a URL + keyword list against the live feed and shows exactly which items would be dropped, so you can tune the list before saving.
Broad words like
dealcan catch legitimate headlines. Prefer specific terms (deals,promo code,black friday) and use the preview to check.
- Upstream feeds are fetched at most once per 15 minutes via a WordPress transient, so many reader polls cost one origin request. Transients expire on their own — nothing accumulates in the database.
- A separate 24-hour "last known good" copy backstops upstream errors, so a brief outage at the origin doesn't break your reader (the admin flags when a feed is served from this fallback).
- Upstream fetches use conditional GET (
If-None-Match/If-Modified-Since). - The filtered response carries an
ETagandCache-Control, and answers a reader'sIf-None-Matchwith304 Not Modified.
Per feed, the admin shows how many items were dropped and kept on the last fetch, a cumulative all-time dropped count, and the titles of the most recently dropped items — so you can confirm it's doing what you expect.
The filtered-feed URL segment can be changed in the admin (e.g. to feeds),
in which case feeds are served at https://your-site.example/feeds/{slug}/.
Rewrite rules are flushed automatically when the path changes.
- WordPress 6.9+
- PHP 7.4+
- Download
filtered-feeds.zipfrom the latest release and install it via Plugins → Add New → Upload Plugin (the zip already contains the compiled admin app). - Activate Filtered Feeds in Plugins.
- Go to Settings → Filtered Feeds, add a feed, and subscribe your reader to the generated URL.
The admin UI is a React (DataViews) app built with @wordpress/scripts. The
compiled build/ directory is not committed — build it before running the
plugin from a source checkout:
npm install
npm run build # production build
npm run start # watch modeRelease zips are produced automatically: pushing a v* tag runs
.github/workflows/release.yml, which builds
the app, packages the plugin with wp-scripts plugin-zip, and attaches the zip
to a GitHub Release.
includes/class-store.php— feed configs and the path setting, exposed via the core/wp/v2/settingsREST endpoint; server-managed diagnostic stats.includes/class-filter.php— keyword → pattern compilation and DOM-level item removal (operates on raw XML to preserve the channel envelope).includes/class-server.php— the public/{base}/{slug}/endpoint: fetch, cache, conditional GET, filter, and serve.includes/class-rest-controller.php—filtered-feeds/v1routes for stats and the live preview.includes/class-admin.php— settings page and asset loading.src/— React (DataViews) admin app built with@wordpress/scripts.
GPL-2.0-or-later.