Skip to content

Overview

Social Feeds fetches RSS or Atom documents into a site-scoped local cache and supplies a Social feed Block Library block. The TikTok, YouTube, Bluesky, Instagram, Facebook, LinkedIn, and X labels currently use the same RSS-compatible feed_url path; they are not native API, account, OAuth, or webhook integrations.

Install Block Library first, run the Social Feeds migrations, and keep a working cURL-based HTTP client. Feed fetching requires cURL host pinning so DNS validation cannot be bypassed between validation and connection.

Scheduled syncing is disabled by default. Set CAPELL_SOCIAL_FEEDS_SYNC_SCHEDULE_ENABLED=true and keep Laravel’s scheduler running to execute capell:social-feeds:sync --all hourly with overlap protection. The command processes Connected feeds serially in the scheduler process; it does not dispatch queue jobs. Manual Sync now also fetches in the admin request. There is no automatic retry or failed-job queue for either path.

The connection and item resources use the generated Social Feed permissions and apply assigned-site query scopes. Global administrators bypass the policy checks. The create form accepts a numeric Site ID rather than an assigned-site selector and the database permits a null site, so grant Create:SocialFeedConnection only to trusted roles and verify the ID before saving. A null-site connection can sync but will not render on a site because public lookup requires the current site’s ID.

Open Growth > Social feed connections, create a connection, select a provider label, enter the intended Site ID, set Status to Connected, and provide an absolute HTTP(S) Feed URL. The built-in non-RSS provider labels still require that URL. Their API key and Handle fields are currently ignored; entering them does not enable native provider access. Credentials are encrypted at rest, but users allowed to update a connection should still be treated as credential administrators.

Private, reserved, loopback, and unresolvable targets are blocked by default. The fetch pins the validated IP, uses three-second connect and ten-second response timeouts by default, and does not follow redirects. A legitimate feed that redirects must be configured with its final public URL. Enabling allow_private_feed_urls weakens the server-side request boundary and should only be done for a controlled deployment.

Use Sync now, then inspect Item count, Last synced, Sync status, and Last sync error. A configuration exception such as a missing URL or blocked host marks the connection Error and stores a credential-redacted error. Set it back to Connected after correcting the configuration before syncing again; scheduled --all only selects Connected records.

An HTTP non-success response, redirect, or unparseable/empty feed returns zero posts without throwing. In that case the connection is recorded as Connected/Idle with a new Last synced time and no error, while existing cached items remain. A zero-item result therefore does not prove the upstream feed was healthy. Check the URL directly and compare cached content when freshness matters.

Diagnostics treats a Connected feed as stale when it has never synced or its Last synced time exceeds CAPELL_SOCIAL_FEEDS_STALE_SYNC_MINUTES (180 minutes by default). Run the command directly to reproduce a problem, but remember that it also returns success after individual feed failures because those errors are recorded on each connection.

Open Growth > Cached social feed items to inspect stored text, author, date, permalink, and provider. This resource is read-only; the package has no per-item approve, hide, edit, or delete workflow.

Items are upserted by connection and external ID. A successful feed response does not delete an item merely because it disappeared upstream. Count-based pruning runs only after at least one post is upserted and keeps the newest 200 items per connection by default (CAPELL_SOCIAL_FEEDS_RETENTION_ITEMS). Empty and failed refreshes do not prune. To remove an unsuitable cached post immediately, remove the connection or use a controlled database/integration process; changing the upstream feed alone may leave the old item visible.

Deleting a connection cascades to its cached items and associated OAuth-state rows. The OAuth-state table is schema groundwork only: this package ships no OAuth route or state cleanup schedule. There is no age-based retention for connections, errors, metadata, or OAuth states.

Feed credentials are encrypted, but connection metadata/errors and cached item text, author, URLs, raw provider data, and timestamps are plaintext. Protect database, logs, backups, and admin access. Social Feeds does not contribute a Privacy Center exporter or eraser.

Add Social feed through Block Library and choose a layout, item limit, source connection/provider, caption/author/date/media visibility, and empty-state behaviour. Public lookup is restricted to the current site even if a block contains another site’s connection ID. The configured limit is bounded by package config (48 by default).

Public rendering uses prepared cached fields and includes no third-party embed JavaScript or connection credentials. It escapes feed text and only keeps absolute HTTP(S) public links/media URLs. However, when Show media is enabled, the visitor’s browser loads the cached remote image URL directly, so that host can receive the visitor’s IP address and request metadata. Disable media or add an approved image proxy/local-copy integration when direct third-party requests are not acceptable.

Rendered feed data is cached for 60 seconds by default. Syncing, deleting, or pruning items does not explicitly invalidate those entries, so a public block can show the previous result until that TTL expires. Set CAPELL_SOCIAL_FEEDS_RENDER_CACHE_TTL_SECONDS=0 to disable this cache when immediate changes are more important than repeated-query reduction.


For how to use Social Feeds, see the admin guide. For developers: see the README.