=== VaultFeed ===
Contributors: theteamccgnomes
Tags: social media, instagram, facebook, social feed, privacy
Requires at least: 6.4
Tested up to: 7.1
Stable tag: 0.9.1
Requires PHP: 8.1
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Self-sovereign social feeds: your tokens stay encrypted on your own server, never uploaded to a third party.

== Description ==

**VaultFeed** displays social media feeds on your WordPress site while keeping your OAuth tokens encrypted on your own server — never uploaded to a third-party SaaS platform.

Connect accounts from these feed sources: **Facebook**, **Instagram**, **Twitter / X**, **YouTube**, **TikTok**, **Threads**, **LinkedIn**, **Bluesky**, **Pinterest**, **Mastodon**, **Reddit**, **Snapchat**, **Twitch**, **Vimeo**, **Google Business Profile**, **Yelp**, and more. Every token is AES-256-GCM encrypted and stored only in your own database.

= Features =

VaultFeed is fully functional with no artificial limits on feed count, post count, or layout — everything below is included with the plugin as distributed on WordPress.org:

* Connect accounts from these feed sources: Facebook Pages, Instagram Business / Creator, Twitter / X, YouTube, TikTok, Threads, LinkedIn, Bluesky, Pinterest, Mastodon (public accounts, no credentials needed), Reddit, Snapchat (Snap Kit Display API), Twitch (clips and VODs via Helix API), Vimeo (user/channel/group feeds), Google Business Profile, Yelp, and more
* Display photo, video, reel, and **review** feeds in **Grid, List, Masonry, Carousel, Slider, Waterfall, Ticker, Timeline,** or **Wall** layout
* Star-rating widget with WCAG-compliant aria-label for review feeds
* Configurable columns (1–6), aspect ratio, hover effects, and post count
* Lightbox for photos and videos with keyboard navigation
* **Load More** button and infinite scroll
* Feed header with optional follow button
* Shortcode `[vaultfeed id="N"]` and Gutenberg block
* Automatic content caching with configurable TTL, fully adjustable
* Caption display, source icon, date, and like / comment counts
* Optional "Powered by VaultFeed" attribution link — off by default, opt-in only
* Fully translatable — `.pot` file included
* WCAG 2.1 AA compliant — focus traps, live regions, 4.5:1 contrast
* Zero telemetry — nothing phones home

= Pro add-on =

A separately sold Pro add-on is planned and will be available from [the VaultFeed website](https://ccgnomes.com/vaultfeed/). It will not be distributed via WordPress.org, and none of its code is included in this plugin. It will add functionality that depends on infrastructure this plugin does not include or run:

* ReelVault source — a video feed served from your own self-hosted Holochain node (requires running that node yourself; VaultFeed does not bundle or install it)
* DHT token storage as an alternative to the local database storage described below
* Priority support

None of this is locked or hidden in the WordPress.org version; it is simply not part of this plugin.

= How token storage works =

When you connect an account, VaultFeed encrypts the OAuth token with AES-256-GCM and stores it in your own WordPress database. The encryption key is derived from your WordPress secret keys and a random per-installation salt that is generated at first activation and stored in your WordPress database (the `vaultfeed_token_salt` option). VaultFeed never writes to `wp-config.php` or to any WordPress core, plugin, or theme file. No token ever leaves your server.

= External services =

VaultFeed relies on third-party services to do its job: it fetches feed content from the social platforms you explicitly connect, and it can optionally send data to a small number of integrations (email marketing, analytics, notifications, store lookups, AI caption rewriting) that stay completely inactive until you enter your own credentials or URL for them. Every service the plugin can contact is listed below with what is sent, when, and its terms and privacy policy. No data is ever sent to VaultFeed or its authors; the plugin operates no background service and has no telemetry.

1. **Facebook Graph API** (`graph.facebook.com`) — when you initiate an OAuth connection from the Accounts page, and when fetching feed content. Governed by [Meta's Terms of Service](https://www.facebook.com/terms.php) and [Privacy Policy](https://www.facebook.com/policy.php). Only called when you have a connected Facebook account.

2. **Instagram Graph API** (`graph.instagram.com`, `graph.facebook.com`) — when you initiate an Instagram OAuth connection from the Accounts page, and when fetching Instagram feed, tagged-post, or story content. Governed by [Meta's Terms of Service](https://www.facebook.com/terms.php) and [Instagram's Privacy Policy](https://privacycenter.instagram.com/policy). Only called when you have a connected Instagram account.

3. **Twitter / X API v2** (`api.twitter.com`) — when you initiate a Twitter OAuth 2.0 PKCE connection, and when fetching tweet content. Governed by [X's Terms of Service](https://x.com/en/tos) and [Privacy Policy](https://x.com/en/privacy). Only called when you have a connected Twitter account.

4. **Google / YouTube Data API v3** (`accounts.google.com`, `oauth2.googleapis.com`, `www.googleapis.com`) — when you initiate a Google OAuth 2.0 connection (your browser is sent to Google's consent screen), and when fetching YouTube channel or playlist content. Governed by [Google's Terms of Service](https://policies.google.com/terms) and [Privacy Policy](https://policies.google.com/privacy). Only called when you have a connected YouTube account.

5. **TikTok for Developers API v2** (`www.tiktok.com`, `open.tiktokapis.com`) — when you initiate a TikTok OAuth 2.0 connection, and when fetching video content. Governed by [TikTok's Terms of Service](https://www.tiktok.com/legal/page/row/terms-of-service/en) and [Privacy Policy](https://www.tiktok.com/legal/page/row/privacy-policy/en). Only called when you have a connected TikTok account.

6. **Threads API** (`graph.threads.net`) — when you initiate a Threads OAuth 2.0 connection, and when fetching posts. Governed by [Meta's Terms of Service](https://www.facebook.com/terms.php) and [Privacy Policy](https://www.facebook.com/policy.php). Only called when you have a connected Threads account.

7. **Google Business Profile APIs** (`mybusiness.googleapis.com`, `mybusinessaccountmanagement.googleapis.com`, `mybusinessbusinessinformation.googleapis.com`) — when listing your business accounts/locations and when fetching Google business reviews. Uses the same Google OAuth credentials as YouTube (item 4 above); both APIs must be enabled in your Google Cloud project. Governed by [Google's Terms of Service](https://policies.google.com/terms) and [Privacy Policy](https://policies.google.com/privacy). Only called when you have a connected Google Business Profile account.

8. **Yelp Fusion API** (`api.yelp.com`) — when you verify a Yelp API key connection, and when fetching business reviews. Governed by [Yelp's Terms of Service](https://www.yelp.com/static?p=tos) and [Privacy Policy](https://www.yelp.com/static?p=privacy). Only called when you have a connected Yelp account.

9. **LinkedIn REST API** (`api.linkedin.com`) — when you initiate a LinkedIn OAuth 2.0 connection, and when fetching posts. Governed by [LinkedIn's User Agreement](https://www.linkedin.com/legal/user-agreement) and [Privacy Policy](https://www.linkedin.com/legal/privacy-policy). Only called when you have a connected LinkedIn account.

10. **Bluesky AT Protocol API** (`bsky.social`, `public.api.bsky.app`) — when you connect a Bluesky account via App Password, and when fetching posts. Governed by [Bluesky's Terms of Service](https://bsky.social/about/support/tos) and [Privacy Policy](https://bsky.social/about/support/privacy-policy). Only called when you have a connected Bluesky account.

11. **Pinterest API** (`api.pinterest.com`) — when you initiate a Pinterest OAuth 2.0 connection, and when fetching boards and pins. Governed by [Pinterest's Terms of Service](https://policy.pinterest.com/en/terms-of-service) and [Privacy Policy](https://policy.pinterest.com/en/privacy-policy). Only called when you have a connected Pinterest account.

12. **Mastodon API** (`{your-instance}/api/v1/`) — when you look up a Mastodon account by handle, and when fetching public statuses. The specific domain depends on the Mastodon instance you connect, and each instance publishes its own terms and privacy policy — for example, mastodon.social's [Terms of Service](https://mastodon.social/terms-of-service) and [Privacy Policy](https://mastodon.social/privacy-policy). Only called when you have a connected Mastodon account.

13. **Reddit OAuth2 / REST API** (`oauth.reddit.com`, `www.reddit.com`) — when you initiate a Reddit OAuth 2.0 client-credentials connection, and when fetching subreddit posts. Governed by [Reddit's User Agreement](https://www.redditinc.com/policies/user-agreement) and [Privacy Policy](https://www.reddit.com/policies/privacy-policy). Only called when you have a connected Reddit account.

14. **Snapchat Login Kit / Snap Kit Display API** (`accounts.snapchat.com`, `kit.snapchat.com`) — when you initiate a Snapchat OAuth 2.0 connection and exchange or refresh its token, and when fetching your profile and public stories. Governed by [Snapchat's Terms of Service](https://www.snap.com/en-US/terms) and [Privacy Policy](https://www.snap.com/en-US/privacy/privacy-policy). Only called when you have a connected Snapchat account.

15. **Twitch Helix API** (`id.twitch.tv`, `api.twitch.tv`) — when you connect a Twitch app (an app access token is requested from `id.twitch.tv`), and when fetching clips and VODs. Governed by [Twitch's Terms of Service](https://www.twitch.tv/p/legal/terms-of-service/) and [Privacy Policy](https://www.twitch.tv/p/legal/privacy-policy/). Only called when you have a connected Twitch account.

16. **Vimeo API** (`api.vimeo.com`) — when you connect a Vimeo account via Personal Access Token, and when fetching user, channel, or group video feeds. Governed by [Vimeo's Terms of Service](https://vimeo.com/terms) and [Privacy Policy](https://vimeo.com/privacy). Only called when you have a connected Vimeo account.

17. **AI caption rewriting — via the WordPress AI Client** — optional, and never automatic: it runs only when you click "Enhance Caption" on the Moderation screen, and sends only that one caption's text plus a short rewrite instruction (the chosen tone). No OAuth tokens, visitor data, or other site data is ever included. VaultFeed hands the request to WordPress's built-in AI Client (WordPress 7.0 and later), so the text goes to whichever AI provider **you** have connected under WordPress's own AI settings; VaultFeed stores no credentials for it and contacts no AI provider on its own, and that provider's terms and privacy policy apply. If you have not connected an AI provider in WordPress, the feature is simply unavailable and nothing is sent anywhere.

18. **Mailchimp Marketing API** (`<dc>.api.mailchimp.com`) — used only by the optional email-capture feature. Only active if you enable email capture on a feed **and** enter your own Mailchimp API key and Audience (list) ID in VaultFeed → Settings. When a visitor submits the email-capture form, their email address is sent to Mailchimp to be added as a subscriber to your audience. Nothing is sent if a Mailchimp key is not configured. Governed by [Mailchimp's Terms of Use](https://mailchimp.com/legal/terms/) and [Privacy Policy](https://www.intuit.com/privacy/statement/).

19. **ConvertKit / Kit API** (`api.convertkit.com`) — used only by the optional email-capture feature. Only active if you enable email capture on a feed **and** enter your own ConvertKit (Kit) API key and Form ID in VaultFeed → Settings. When a visitor submits the email-capture form, their email address is sent to ConvertKit to subscribe them to your form. Nothing is sent if a ConvertKit key is not configured. Governed by [Kit's Terms of Service](https://kit.com/terms) and [Privacy Policy](https://kit.com/privacy).

20. **Google Analytics 4 Measurement Protocol** (`www.google-analytics.com`) — used only for optional click analytics. Only active if you enter your own GA4 Measurement ID and API Secret in VaultFeed → Settings. When a visitor clicks a post, a `vaultfeed_click` event (feed ID, post ID, and post type — no personal data) is sent to your Google Analytics property. Nothing is sent if GA4 credentials are not configured. Governed by [Google's Terms of Service](https://policies.google.com/terms) and [Privacy Policy](https://policies.google.com/privacy).

21. **Slack incoming webhooks** (`hooks.slack.com`) — used only for optional new-post notifications. Only active if you paste your own Slack incoming-webhook URL in VaultFeed → Settings **and** enable new-post alerts on a feed. When new posts arrive in that feed, a short text message (the number of new posts and the feed's name — no post content and no visitor data) is sent to your Slack webhook. Nothing is sent if no Slack URL is configured. Governed by [Slack's Terms of Service](https://slack.com/terms-of-service/user) and [Privacy Policy](https://slack.com/trust/privacy/privacy-policy).

22. **Zapier webhooks** (`hooks.zapier.com`) — used only for optional automation. Only active if you paste your own Zapier "Catch Hook" URL in VaultFeed → Settings. When a feed refresh finds new posts, the feed ID and, for each new post, its platform ID, caption text, first media URL, permalink, and timestamp are sent to your Zapier webhook. This is public social content you chose to display — no visitor data is included. Nothing is sent if no Zapier URL is configured. Governed by [Zapier's Terms of Service](https://zapier.com/legal/terms-of-service) and [Privacy Policy](https://zapier.com/privacy).

23. **Shopify Storefront API** (`{your-store}.myshopify.com`) — used only by the optional "Shop" badge. Only active if you enter your own Shopify store URL and Storefront API access token in VaultFeed → Settings and enable the shop badge on a feed. When a post's hashtag has no product link you mapped manually, that hashtag is sent to your own store's Storefront API as a product-handle lookup, together with your Storefront token, to find the product's URL (results are cached for one hour). No visitor data is sent. Nothing is sent if Shopify is not configured. Governed by [Shopify's Terms of Service](https://www.shopify.com/legal/terms) and [Privacy Policy](https://www.shopify.com/legal/privacy).

24. **Your own outbound webhook URLs** — optional. Only active if you add one or more webhook endpoints in VaultFeed → Webhooks. When an event you selected fires (feed refreshed, feed error, post approved/rejected), a JSON payload is POSTed to the URL(s) **you** entered: the event name, the feed ID, and for refresh events each post's platform ID, type, source, caption text (first 280 characters), permalink, and publish date. Requests are signed with HMAC-SHA256 using your webhook secret. The destination is whatever server you specify, so its terms and privacy policy are those of the service you choose; no data goes anywhere unless you add a URL.

25. **Social platform media CDNs** (for example `scontent.cdninstagram.com`, `pbs.twimg.com`, `i.ytimg.com` — the exact hosts depend on the platforms you connect) — the images, thumbnails and videos inside your feeds are served from the platform's own CDN, so a visitor's browser requests them directly from that platform while viewing the feed, exactly as an ordinary embedded post would. The URLs come from the platform API response; VaultFeed does not rehost them. The platform's terms and privacy policy are the ones listed for that platform above. If you would rather your visitors never contact those CDNs, switch on the built-in image proxy — `wp option update vaultfeed_image_proxy_enabled 1` — and your own server fetches and caches the images instead.

26. **YouTube embedded player** (`www.youtube-nocookie.com`) — only when a visitor clicks a YouTube video; nothing loads before the click. The visitor's browser then loads YouTube's player directly, so YouTube receives the visitor's IP address, browser details, your page address and the video ID, and may set cookies. [YouTube Terms](https://www.youtube.com/t/terms), [Google Privacy Policy](https://policies.google.com/privacy).

27. **Vimeo embedded player** (`player.vimeo.com`) — only when a visitor clicks a Vimeo video; nothing loads before the click. The visitor's browser then loads Vimeo's player directly, so Vimeo receives the visitor's IP address, browser details, your page address and the video ID, and may set cookies. [Vimeo Terms](https://vimeo.com/terms), [Vimeo Privacy Policy](https://vimeo.com/privacy).

28. **TikTok embedded player** (`www.tiktok.com`) — only when a visitor clicks a TikTok video; nothing loads before the click. The visitor's browser then loads TikTok's player directly, so TikTok receives the visitor's IP address, browser details, your page address and the video ID, and may set cookies. [TikTok Terms](https://www.tiktok.com/legal/page/row/terms-of-service/en), [TikTok Privacy Policy](https://www.tiktok.com/legal/page/row/privacy-policy/en).

29. **Twitch embedded player** (`player.twitch.tv` for videos, `clips.twitch.tv` for clips) — only when a visitor clicks a Twitch video or clip; nothing loads before the click. The visitor's browser then loads Twitch's player directly, so Twitch receives the visitor's IP address, browser details, your page address (your site's host name is passed as the `parent` setting Twitch requires) and the video or clip ID, and may set cookies. [Twitch Terms](https://www.twitch.tv/p/legal/terms-of-service/), [Twitch Privacy Policy](https://www.twitch.tv/p/legal/privacy-policy/).

30. **WordPress.org update API** — standard WordPress plugin update check behaviour. No VaultFeed-specific data is transmitted beyond the plugin slug and current version.

= Third-party libraries =

VaultFeed's own scripts, styles and fonts are all bundled with the plugin — none are loaded from an external server or CDN. (The post images and videos *inside* your feeds are a separate matter: those are served from the social platforms' CDNs, as described in item 25 of "External services" above.)

* **SortableJS 1.15.7** (MIT licence) — drag-to-reorder on the admin Moderation screen. Bundled at `assets/js/vendor/sortable.min.js` with the unminified source alongside at `assets/js/vendor/sortable.js` and the upstream licence at `assets/js/vendor/sortable-LICENSE.txt`. Source: [github.com/SortableJS/Sortable](https://github.com/SortableJS/Sortable).
* All other minified files in `assets/js/*.min.js` and `assets/css/*.min.css` are built from the human-readable `.js` / `.css` files of the same name that ship next to them.

== Installation ==

1. Upload the `vaultfeed` folder to `/wp-content/plugins/`
2. Activate the plugin via **Plugins → Installed Plugins**
3. Go to **VaultFeed → Settings** and enter your app credentials for the platforms you want to use
4. Go to **VaultFeed → Accounts** and connect your accounts
5. Go to **VaultFeed → Feeds** and click **+ New Feed** to create your first feed
6. Copy the shortcode (e.g. `[vaultfeed id="1"]`) and paste it into any post, page, or widget

= Requirements =

* WordPress 6.4 or later
* PHP 8.1 or later
* Developer credentials for each platform you wish to connect:
  * **Facebook / Instagram** — a Meta Developer App with `pages_read_engagement` and `instagram_basic` permissions
  * **Twitter / X** — a Twitter Developer App with OAuth 2.0 enabled and scopes `tweet.read users.read offline.access`
  * **YouTube** — Google Cloud OAuth 2.0 credentials with the YouTube Data API v3 enabled
  * **TikTok** — a TikTok Developer App with `user.info.basic` and `video.list` scopes
  * **Threads** — a Meta Developer App with `threads_basic` permissions (separate from your Facebook / Instagram app)
  * **Google Business Profile reviews** — same Google Cloud project as YouTube, with the Business Profile APIs additionally enabled
  * **Yelp** — a Yelp Fusion API key from the [Yelp developer portal](https://docs.developer.yelp.com/)
  * **LinkedIn** — a LinkedIn Developer App with `openid profile email r_member_social w_member_social` scopes enabled
  * **Bluesky** — no developer account needed; create an App Password at bsky.app → Settings → App Passwords
  * **Pinterest** — a Pinterest Developer App with `boards:read`, `pins:read`, and `user_accounts:read` scopes
  * **Mastodon** — no credentials required; public accounts are accessible via the Mastodon public API

== Frequently Asked Questions ==

= Do I need developer accounts for the platforms I want to connect? =

Most platforms require their own developer app credentials, entered in **VaultFeed → Settings**. The setup takes 10–15 minutes per platform. Two exceptions: **Bluesky** uses an App Password (no developer account needed), and **Mastodon** uses public accounts with no credentials at all. The credentials each platform needs are listed under **Installation → Requirements** above, and each platform's section in **VaultFeed → Settings** links to the matching developer portal. For the exact OAuth callback URL and required scopes for each platform, plus troubleshooting, see the [VaultFeed setup guide](https://ccgnomes.com/vaultfeed/support/).

= Where can I get help? =

Setup, troubleshooting, and a support ticket form are on the [VaultFeed Setup & Support page](https://ccgnomes.com/vaultfeed/support/). You can also use the plugin's support forum here on WordPress.org.

= Where are my OAuth tokens stored? =

Tokens are stored in the `vaultfeed_tokens` table in your WordPress database, encrypted with AES-256-GCM. The encryption key is derived locally from your `AUTH_KEY` and a random salt stored in your WordPress database (VaultFeed does not write to `wp-config.php`). No token is ever transmitted to VaultFeed or any third party.

= Is there a limit on feeds, posts, or layouts in the free version? =

No. There is no cap on the number of feeds you can create, no cap on posts per feed, and all nine layouts (Grid, List, Masonry, Carousel, Slider, Waterfall, Ticker, Timeline, Wall) are available. The optional "Powered by VaultFeed" attribution link is off by default and only appears if you turn it on yourself in a feed's Display Settings.

= Does this work with WordPress multisite? =

Yes. Each sub-site manages its feeds and account connections independently.

= Is this GDPR-compliant? =

VaultFeed sends nothing to its authors and makes no unsolicited third-party network calls. By default it stores no visitor personal data: click and impression analytics are aggregate counters, and the visitor IP address is used only transiently (hashed, in short-lived rate-limit/de-duplication keys) and is never stored in readable form. If you turn on the optional **email capture** form, the addresses visitors submit are sent to the Mailchimp or ConvertKit account you configured — or, if neither is configured, kept in your own WordPress database — so you are the data controller for them and should disclose that in your Privacy Policy. Your wider GDPR obligations depend on the content of your social media feeds and your agreements with the respective platforms. See the "External services" section for exactly what each optional integration sends.

= Can I display the same feed on multiple pages? =

Yes — use the same shortcode `[vaultfeed id="N"]` anywhere on your site. The cached content is shared so it counts as one API call.

= Does the plugin support Instagram Stories? =

Yes (free tier). Stories are a feed type you can choose in the feed creation wizard, step 3.

= Is my data sent to VaultFeed servers? =

No. VaultFeed operates no background service and receives no data from your site. Out of the box, the plugin makes outbound HTTP calls only to the social platforms you explicitly connect (to fetch feed content) and to the WordPress.org API (to check for plugin updates). The optional integrations listed under "External services" (Mailchimp, ConvertKit, Google Analytics 4, Slack, Zapier, Shopify, and your own webhooks) contact those services only after you enter your own credentials or URL for them — and even then, the data goes to **your** account with that service, never to VaultFeed. Your OAuth tokens never leave your server.

= Does this work with caching plugins? =

Yes. VaultFeed maintains its own server-side cache in the `vaultfeed_feed_cache` database table, independent of any full-page cache. Feeds load correctly behind WP Super Cache, W3 Total Cache, WP Rocket, LiteSpeed Cache, and similar plugins. If you use a page cache with a very long TTL, enable **auto-refresh** in your feed's Display Settings so content stays current without a full page reload.

= What PHP version is required? =

PHP 8.1 or higher is required. PHP 8.2 and 8.3 are fully supported. WordPress 6.4 or higher is required.

= What happens if my token expires? =

VaultFeed checks token expiry and marks the account as "expiring" in the Accounts page. You can reconnect by clicking **Reconnect** on the account card. Feeds for that account are paused until the token is refreshed.

== Screenshots ==

1. The Feeds list page — all your feeds at a glance with shortcode copy.
2. Feed creation wizard — choose source, account, type, and display settings.
3. Live preview panel — see changes in real time as you configure.
4. Grid layout with hover overlay effect on the front end.
5. List layout with caption, date, and meta displayed.
6. Accounts page — connected accounts with token status badges.

== Changelog ==

= 0.9.1 =
Fixes found on a live YouTube feed. Adds a small data migration (YouTube reconnect date only).

* Fix: YouTube, Vimeo, TikTok and Twitch videos play in the lightbox and the post window using each platform's official embedded player; Bluesky videos play where the browser supports them natively.
* Fix: closing the lightbox or post window stops the video.
* Fix: a freshly connected YouTube account no longer shows "Expiring soon"; every account whose access token expires is renewed before a feed is fetched.
* Fix: a failed refresh no longer replaces good cached posts with an empty list; the feed list and Analytics show why a sync failed.
* Fix: the hashtag shortcode keeps showing the last cached posts when its cache has just expired.
* Fix: a refresh that returned posts was recorded as failed whenever the Zapier listener ran.

= 0.9.0 =
Fixes found by independent audits. No database changes.

* Security (WP.org review): the feed-import upload reader no longer carries any `phpcs:ignore` for a sanitisation rule and no longer alters PHP's temporary file path.
* Fix: the wizard's live preview, editing of aggregated feeds, and the legacy widget and block editor now keep feeds that are paused, scheduled or in error instead of dropping them.
* Security: the block editor lists non-active feeds only to users who can edit others' posts; an aggregated feed's RSS ETag and Last-Modified respect each reader's visibility.
* Fix: stored schedules without a time zone are shown as the UTC instant the server enforces.

= 0.8.9 =
Supersedes the unreleased 0.8.6, 0.8.7 and 0.8.8 builds. Many security and correctness fixes: feed visibility is enforced on every REST, RSS, shortcode and embed surface, and editing a feed in the wizard no longer resets fields the form did not change.

= 0.8.5 and earlier =
Plugin Check and WP.org review fixes, and security hardening of the public endpoints.

Full history: see changelog.txt in the plugin folder.

== Upgrade Notice ==

= 0.9.1 =
YouTube, Vimeo, TikTok and Twitch videos now play in the lightbox; fixes the YouTube reconnect warning and the last sync time.

= 0.9.0 =
Bug-fix release: live preview, aggregate members, stored filters, widget feeds, aggregate RSS caching, block-editor feed names and a cleaner upload reader. No database changes.

= 0.8.9 =
Security and bug-fix release: closes cached-render and RSS/REST cache leaks of restricted feeds and picker exposure, and the wizard no longer resets filter or display settings when you edit a feed. No database changes.

= 0.8.5 =
Bug-fix release: aggregated feeds save again, exported feeds import again (old export files included), and the wizard no longer logs PHP deprecation notices. No database changes.

= 0.8.4 =
Security hardening of admin input handling and feed import, per WordPress.org review. Injected cards are limited to a fixed HTML tag whitelist; cards using table, video, iframe, form or section tags will have those stripped when rendered. No database changes.

= 0.8.3 =
WP.org compliance release. Removed a third-party review-site integration per WordPress.org guidelines; feed source count is now 20. No database changes.

= 0.8.2 =
Security release. Fixes two cross-site scripting holes (review schema output, social-proof popup), an RSS injection, and an email-capture endpoint that ignored its on/off setting. Restricted feeds are now hidden from embed, RSS, JSON Feed and oEmbed too. No database changes.

= 0.8.1 =
Security and compliance release. Database tables are renamed automatically (vf_* to vaultfeed_*) with no data loss. If your site is behind Cloudflare or a reverse proxy, set VaultFeed → Settings → Reverse Proxy / CDN after updating.

= 0.44.0 =
Adds Snapchat, Twitch, and Vimeo source adapters. No database schema changes. Safe to update in place.

= 0.43.0 =
Adds API key management and Embed SDK. No database schema changes. Safe to update in place.

= 0.42.0 =
Adds CTA card injection and notification log. No database schema changes. Safe to update in place.

= 0.41.0 =
Adds Reddit, Instagram Tagged, and Twitter Mentions adapters. No database schema changes. Safe to update in place.

= 0.40.0 =
Adds Pinterest, WordPress CPT, Mastodon, Bluesky, LinkedIn, and Google Reviews adapters alongside the Moderation page. No database schema changes. Safe to update in place.

= 0.39.0 =
Adds Threads, TikTok, YouTube, and Twitter / X adapters, plus WP-CLI commands and RSS output. No database schema changes. Safe to update in place.

= 0.33.0 =
No database changes. Safe to update in place.

= 0.31.0 =
No database changes. Safe to update in place.

= 0.28.0 =
Adds an orphan-cache sweep that runs automatically during the next hourly cron. No manual action required. No database schema changes.

= 0.2.1 =
WP.org compliance fixes. Token salt storage changes from wp-config.php to wp_options — existing tokens remain readable. Safe to update in place.

= 0.2.0 =
Adds Twitter/X, YouTube, and TikTok source adapters. No database changes — safe to update in place.

= 0.1.0 =
Initial release — no upgrade path required.
