Add `privacy` column to `bp_activity` for per-item visibility control
-
BuddyPress activities have a single visibility control:
hide_sitewide(0 or 1). This provides binary visibility — shown everywhere, or hidden from sitewide feeds. There’s no way to express:– **”Only me”** — private activity visible only to the author
– **”Friends only”** — visible only to the author’s friends
– **”Logged-in users”** — hidden from anonymous visitors
– **”Group members only”** — visible only within the group context where it was postedPer-item privacy is a foundational social platform feature. Facebook has had it since 2009. LinkedIn, Twitter/X (with protected tweets), Instagram, and every major social network support some form of per-post audience control. It’s as fundamental to a social platform as
hide_sitewideis — just multi-valued instead of binary.This is not a request for any specific addon’s needs. It’s a request for the same kind of infrastructure that
hide_sitewideprovides — a first-class column that any addon can use to implement privacy-aware features.#### Current State
BuddyPress 14.4.0’s activity query system is well-designed for extensibility:
–
bp_activity_get_where_conditionslets addons inject WHERE clauses
–bp_activity_get_join_sqllets addons add JOINs
– Data hydration usesSELECT *(inpopulate()and the cache-miss path ofget()), so any column added to the table is automatically returned to calling code
–bp_activity_before_save/bp_activity_after_saveprovide save-time hooksAn addon **can** add a
privacycolumn viadbDeltaand filter queries viabp_activity_get_where_conditions. However, thesave()method has a hardcoded column list in its INSERT/UPDATE SQL (inBP_Activity_Activity::save()), meaning an addon must do a separate$wpdb->update()after every save — a double-write on every activity creation. This works but is suboptimal, and the column’s general-purpose nature (used by media addons, document addons, moderation addons, group addons — not just one feature) argues for core inclusion.#### Proposed Change
**Schema:** Add one column + index to
bp_activityinbp_core_install_activity_streams()(inbp-core-admin-schema.php).dbDelta()handles adding the column on upgrade automatically:`sql
— Added after the existingis_spamcolumn in the CREATE TABLE definition:
privacy varchar(75) NOT NULL DEFAULT ‘public’,
— Added to the KEY list:
KEY privacy (privacy)
`**Model class (
BP_Activity_Activity):**1. Add
public $privacy = 'public';property
2. Insave()— addprivacyto the INSERT/UPDATE column list alongside the existing columns (user_id, component, type, action, content, etc.)
3. Inget()— add'privacy'to the$rdefaults (defaultfalse, meaning no filtering). When set, addAND a.privacy IN (...)to the WHERE conditions.**REST API (
BP_REST_Activity_Endpoint):**4. In
prepare_item_for_response()— exposeprivacyin the response object (paralleling howhide_sitewideis currently exposed ashidden)
5. Inprepare_item_for_database()— acceptprivacyas a writable field on create/update**Migration:**
dbDelta()runs on every upgrade viabp_core_install(), so modifying the CREATE TABLE definition is sufficient for the schema change. A DB version bump inbp-core-update.phptracks the upgrade.#### Scope
– ~40 lines of changes across 4 files (
bp-core-admin-schema.php,class-bp-activity-activity.php,class-bp-rest-activity-endpoint.php,bp-core-update.php)
– Default value'public'— 100% backward compatible
– Existing queries that don’t passprivacyreturn all activities as before
–hide_sitewidecontinues to work as-is (orthogonal —hide_sitewidecontrols directory listing,privacycontrols per-item access)#### What Core Provides vs. What Addons Handle
To be explicit about scope: this proposal adds **storage and query filtering only**. Core would:
– Store the
privacyvalue on each activity row
– Allowget()callers to filter by privacy value(s)
– Expose/accept the field through the REST APICore would **not** need to:
– Define a fixed set of allowed values (addons register the values they need — e.g.,
'onlyme','friends','loggedin')
– Enforce access control based on privacy values (addons hook intobp_activity_get_where_conditionsto inject viewer-aware WHERE clauses, exactly as they would today for any custom filtering)
– Provide UI for selecting privacy (addon/theme territory)This mirrors how
hide_sitewideworks today — core stores the flag and filters on it; the decision of *when* to set it is made by callers (groups component, plugins, etc.).#### Prior Art
BuddyBoss Platform (a BuddyPress-derived platform) implemented this exact column. Their
bp_activityschema includesprivacy varchar(75) NOT NULL DEFAULT 'public', and their media, document, video, and moderation subsystems all depend on it for privacy filtering. The column is referenced in their activity save/query paths, REST API, and template layer — making it one of the most cross-cutting additions they made to the activity table. The fact that an independent platform needed this to build standard social features demonstrates both the demand and the general-purpose nature of the column.I’m happy to submit a PR for this change.
- You must be logged in to reply to this topic.