Memory Wiki

Untitled Session

2026-05-28 16:06 UTC · 37 messages · cli

You2026-05-28 16:07 UTC
Find how BuddyPress handles activity posting via AJAX — specifically the wp_ajax handler, the PHP function that processes the post, and how it inserts into the database. I need the full function code and the add_action registration.
Donna2026-05-28 16:07 UTC
Tool2026-05-28 16:07 UTC
{"total_count": 0}
Tool2026-05-28 16:07 UTC
{"total_count": 0}
Donna2026-05-28 16:07 UTC
Tool2026-05-28 16:07 UTC
{"total_count": 20, "matches": [{"path": "/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-core/bp-core-avatars.php", "line": 944, "content": "add_action( 'wp_ajax_bp_avatar_delete', 'bp_avatar_ajax_delete' );"}, {"path": "/var/lib/docker/volumes/staging_wp_data/_data/w...
Tool2026-05-28 16:07 UTC
{"total_count": 1, "matches": [{"path": "/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-activity/bp-activity-admin.php", "line": 137, "content": "add_action( 'wp_ajax_bp-activity-admin-reply', 'bp_activity_admin_reply' );"}]}
Donna2026-05-28 16:07 UTC
Tool2026-05-28 16:07 UTC
{"total_count": 1, "matches": [{"path": "/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-activity/bp-activity-admin.php", "line": 137, "content": "add_action( 'wp_ajax_bp-activity-admin-reply', 'bp_activity_admin_reply' );"}]}
Tool2026-05-28 16:07 UTC
{"total_count": 15, "matches": [{"path": "/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-activity/bp-activity-functions.php", "line": 2153, "content": "function bp_activity_post_update( $args = '' ) {"}, {"path": "/var/lib/docker/volumes/staging_wp_data/_data/wp-conte...
Donna2026-05-28 16:07 UTC
Tool2026-05-28 16:07 UTC
{"total_count": 2, "matches": [{"path": "/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-activity/classes/class-bp-akismet.php", "line": 164, "content": "\t * default AJAX implementation; see bp_dtheme_post_update()."}, {"path": "/var/lib/docker/volumes/staging_wp_data...
Tool2026-05-28 16:07 UTC
{"total_count": 3, "matches": [{"path": "/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-templates/bp-legacy/buddypress-functions.php", "line": 185, "content": "\t\t * The \"wp_ajax_\" action is used for logged in users, and \"wp_ajax_nopriv_\""}, {"path": "/var/lib/do...
Donna2026-05-28 16:07 UTC
Tool2026-05-28 16:07 UTC
{"content": " 160|\t\t\t'post_update' => 'bp_legacy_theme_post_update',\n 161|\t\t\t'bp_spam_activity' => 'bp_legacy_theme_spam_activity',\n 162|\t\t\t'bp_spam_activity_comment' => 'bp_legacy_theme_spam_activity',\n 163|\n 164|\t\t\t// Groups.\n 165|\t\t\t'g...
Tool2026-05-28 16:07 UTC
{"content": " 1|<?php\n 2|/**\n 3| * Activity: Post action\n 4| *\n 5| * @package BuddyPress\n 6| * @subpackage ActivityActions\n 7| * @since 3.0.0\n 8| */\n 9|\n 10|/**\n 11| * Post user/group activity update.\n 12| *\n 13| * @since 1.2.0\n 14| *\n...
Donna2026-05-28 16:07 UTC
Tool2026-05-28 16:07 UTC
{"total_count": 1, "files": ["/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-templates/bp-legacy/buddypress-functions.php"]}
Tool2026-05-28 16:07 UTC
{"total_count": 5, "files": ["/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-templates/bp-nouveau/js/buddypress-activity-post-form.min.js", "/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-templates/bp-nouveau/js/buddypress-activity-post...
Donna2026-05-28 16:07 UTC
Tool2026-05-28 16:07 UTC
{"total_count": 7, "matches": [{"path": "/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-templates/bp-legacy/buddypress-functions.php", "line": 987, "content": " *"}, {"path": "/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-templates/bp-...
Tool2026-05-28 16:07 UTC
{"total_count": 39, "matches": [{"path": "/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-templates/bp-nouveau/includes/activity/ajax.php", "line": 60, "content": "\t\t\t),"}, {"path": "/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-temp...
Donna2026-05-28 16:07 UTC
Let me read both the legacy and nouveau AJAX handlers in full.
Tool2026-05-28 16:07 UTC
{"content": " 985| *\n 986| * @since 1.2.0\n 987| *\n 988| * @return string|null HTML\n 989| */\n 990|function bp_legacy_theme_post_update() {\n 991|\t$bp = buddypress();\n 992|\n 993|\tif ( ! bp_is_post_request() ) {\n 994|\t\treturn;\n 995|\t}\n 996|\n 997|\t// Check the ...
Tool2026-05-28 16:07 UTC
{"content": " 500| * Processes Activity updates received via a POST request.\n 501| *\n 502| * @since 3.0.0\n 503| *\n 504| * @return string JSON reply\n 505| */\n 506|function bp_nouveau_ajax_post_update() {\n 507|\t$bp = buddypress();\n 508|\n 509|\tif ( ! is_user_logged_in() |...
Donna2026-05-28 16:07 UTC
Now let me get the core database insertion function and the Nouveau AJAX registration.
Tool2026-05-28 16:07 UTC
{"content": " 2145| * @type string $content The content of the activity update.\n 2146| * @type int $user_id Optional. Defaults to the logged-in user.\n 2147| * @type string $error_type Optional. Error type to return. Either 'bool' or 'wp_error'. Defaults to\n 2148| * ...
Tool2026-05-28 16:07 UTC
{"content": " 1|<?php\n 2|/**\n 3| * Activity Ajax functions\n 4| *\n 5| * @since 3.0.0\n 6| * @version 12.0.0\n 7| */\n 8|\n 9|// Exit if accessed directly.\n 10|defined( 'ABSPATH' ) || exit;\n 11|\n 12|add_action( 'admin_init', function () {\n 13|\t$...
Donna2026-05-28 16:07 UTC
Let me also find the `bp_activity_add` function that does the actual database insertion.
Tool2026-05-28 16:07 UTC
{"total_count": 7, "matches": [{"path": "/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-activity/bp-activity-functions.php", "line": 2055, "content": " * }"}, {"path": "/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-activity/bp-activity...
Donna2026-05-28 16:07 UTC
Tool2026-05-28 16:07 UTC
{"content": " 2055| * }\n 2056| * @return WP_Error|bool|int The ID of the activity on success. False on error.\n 2057| */\n 2058|function bp_activity_add( $args = '' ) {\n 2059|\n 2060|\t$r = bp_parse_args(\n 2061|\t\t$args,\n 2062|\t\tarray(\n 2063|\t\t\t'id' => false, ...
Donna2026-05-28 16:07 UTC
Tool2026-05-28 16:07 UTC
{"total_count": 7, "matches": [{"path": "/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-activity/classes/class-bp-activity-activity.php", "line": 233, "content": "\t *"}, {"path": "/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-activity...
Donna2026-05-28 16:07 UTC
Tool2026-05-28 16:07 UTC
{"content": " 230|\t * @since 1.0.0\n 231|\t *\n 232|\t * @global wpdb $wpdb WordPress database object.\n 233|\t *\n 234|\t * @return WP_Error|bool True on success.\n 235|\t */\n 236|\tpublic function save() {\n 237|\t\tglobal $wpdb;\n 238|\n 239|\t\t$bp = buddypress();\n 240|\...
Donna2026-05-28 16:07 UTC
Here is a complete summary of how BuddyPress handles activity posting via AJAX. --- ## What I Found BuddyPress has **three** code paths for posting activity updates, with two AJAX-specific ones (legacy and nouveau themes) and one core database function. --- ### 1. Core AJAX Registration — Legacy Theme **File:** `/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-templates/bp-legacy/buddypress-functions.php` (line 160) The legacy theme maps `post_update` to `bp_legacy_theme_post_update`: ```php 'post_update' => 'bp_legacy_theme_post_update', ``` And registers it at line 188–191: ```php foreach ( $actions as $name => $function ) { bp_ajax_register_action( $name ); add_action( 'wp_ajax_' . $name, $function ); add_action( 'wp_ajax_nopriv_' . $name, $function ); } ``` So the action hook is `wp_ajax_post_update`. ### 1a. Full Legacy AJAX Handler — `bp_legacy_theme_post_update()` **File:** `/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-templates/bp-legacy/buddypress-functions.php` (lines 990–1068) ```php function bp_legacy_theme_post_update() { $bp = buddypress(); if ( ! bp_is_post_request() ) { return; } // Check the nonce. check_admin_referer( 'post_update', '_wpnonce_post_update' ); if ( ! is_user_logged_in() ) { exit( '-1' ); } if ( empty( $_POST['content'] ) ) { exit( '-1<div id="message" class="error bp-ajax-message"><p>' . esc_html__( 'Please enter some content to post.', 'buddypress' ) . '</p></div>' ); } $activity_id = 0; $item_id = 0; $object = ''; // Try to get the item id from posted variables. if ( ! empty( $_POST['item_id'] ) ) { $item_id = (int) $_POST['item_id']; } // Try to get the object from posted variables. if ( ! empty( $_POST['object'] ) ) { $object = sanitize_key( $_POST['object'] ); // If the object is not set and we're in a group, set the item id and the object } elseif ( bp_is_group() ) { $item_id = bp_get_current_group_id(); $object = 'groups'; } if ( ! $object && bp_is_active( 'activity' ) ) { $activity_id = bp_activity_post_update( array( 'content' => $_POST['content'], 'error_type' => 'wp_error' ) ); } elseif ( 'groups' === $object ) { if ( $item_id && bp_is_active( 'groups' ) ) $activity_id = groups_post_update( array( 'content' => $_POST['content'], 'group_id' => $item_id, 'error_type' => 'wp_error' ) ); } else { /** This filter is documented in bp-activity/actions/post.php */ $activity_id = apply_filters( 'bp_activity_custom_update', false, $object, $item_id, $_POST['content'] ); } if ( false === $activity_id ) { exit( '-1<div id="message" class="error bp-ajax-message"><p>' . esc_html__( 'There was a problem posting your update. Please try again.', 'buddypress' ) . '</p></div>' ); } elseif ( is_wp_error( $activity_id ) && $activity_id->get_error_code() ) { exit( '-1<div id="message" class="error bp-ajax-message"><p>' . esc_html( $activity_id->get_error_message() ) . '</p></div>' ); } $last_recorded = ! empty( $_POST['since'] ) ? date( 'Y-m-d H:i:s', intval( $_POST['since'] ) ) : 0; if ( $last_recorded ) { $activity_args = array( 'since' => $last_recorded ); $bp->activity->last_recorded = $last_recorded; add_filter( 'bp_get_activity_css_class', 'bp_activity_newest_class', 10, 1 ); } else { $activity_args = array( 'include' => $activity_id ); } if ( bp_has_activities ( $activity_args ) ) { while ( bp_activities() ) { bp_the_activity(); bp_get_template_part( 'activity/entry' ); } } if ( ! empty( $last_recorded ) ) { remove_filter( 'bp_get_activity_css_class', 'bp_activity_newest_class', 10 ); } exit; } ``` --- ### 2. Nouveau Theme AJAX Registration **File:** `/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-templates/bp-nouveau/includes/activity/ajax.php` (lines 12–81) Registered via `admin_init`: ```php add_action( 'admin_init', function () { $ajax_actions = array( // ... other actions ... array( 'post_update' => array( 'function' => 'bp_nouveau_ajax_post_update', 'nopriv' => false, ), ), // ... more actions ... ); foreach ( $ajax_actions as $ajax_action ) { $action = key( $ajax_action ); add_action( 'wp_ajax_' . $action, $ajax_action[ $action ]['function'] ); if ( $ajax_action[ $action ]['nopriv'] ) { add_action( 'wp_ajax_nopriv_' . $action, $ajax_action[ $action ]['function'] ); } } } ); ``` ### 2a. Full Nouveau AJAX Handler — `bp_nouveau_ajax_post_update()` **File:** `/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-templates/bp-nouveau/includes/activity/ajax.php` (lines 506–609) ```php function bp_nouveau_ajax_post_update() { $bp = buddypress(); if ( ! is_user_logged_in() || empty( $_POST['_wpnonce_post_update'] ) || ! wp_verify_nonce( $_POST['_wpnonce_post_update'], 'post_update' ) ) { wp_send_json_error(); } $activity_id = 0; $item_id = 0; $object = ''; $is_private = false; // Try to get the item id from posted variables. if ( ! empty( $_POST['item_id'] ) ) { $item_id = (int) $_POST['item_id']; } // Try to get the object from posted variables. if ( ! empty( $_POST['object'] ) ) { $object = sanitize_key( $_POST['object'] ); // If the object is not set and we're in a group, set the item id and the object } elseif ( bp_is_group() ) { $item_id = bp_get_current_group_id(); $object = 'group'; $status = groups_get_current_group()->status; } if ( 'user' === $object && bp_is_active( 'activity' ) ) { $activity_id = bp_activity_post_update( array( 'content' => $_POST['content'], 'error_type' => 'wp_error', ) ); } elseif ( 'group' === $object ) { if ( $item_id && bp_is_active( 'groups' ) ) { $activity_id = groups_post_update( array( 'content' => $_POST['content'], 'group_id' => $item_id, 'error_type' => 'wp_error', ) ); if ( empty( $status ) ) { if ( ! empty( $bp->groups->current_group->status ) ) { $status = $bp->groups->current_group->status; } else { $group = groups_get_group( array( 'group_id' => $item_id ) ); $status = $group->status; } $is_private = 'public' !== $status; } } } else { /** This filter is documented in bp-activity/actions/post.php */ $activity_id = apply_filters( 'bp_activity_custom_update', false, $object, $item_id, $_POST['content'] ); } if ( is_wp_error( $activity_id ) ) { wp_send_json_error( array( 'message' => $activity_id->get_error_message(), ) ); } elseif ( empty( $activity_id ) ) { wp_send_json_error( array( 'message' => __( 'There was a problem posting your update. Please try again.', 'buddypress' ), ) ); } ob_start(); if ( bp_has_activities( array( 'include' => $activity_id, 'show_hidden' => $is_private ) ) ) { while ( bp_activities() ) { bp_the_activity(); bp_get_template_part( 'activity/entry' ); } } $activity = ob_get_contents(); ob_end_clean(); wp_send_json_success( array( 'id' => $activity_id, 'message' => esc_html__( 'Update posted.', 'buddypress' ) . ' ' . sprintf( '<a href="%s" class="just-posted">%s</a>', esc_url( bp_activity_get_permalink( $activity_id ) ), esc_html__( 'View activity.', 'buddypress' ) ), 'activity' => $activity, 'is_private' => apply_filters( 'bp_nouveau_ajax_post_update_is_private', $is_private ), 'is_directory' => bp_is_activity_directory(), ) ); } ``` --- ### 3. Core Database Insertion — `bp_activity_post_update()` and `bp_activity_add()` **File:** `/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-activity/bp-activity-functions.php` **`bp_activity_post_update()`** (line 2153) is the intermediate function called by both AJAX handlers. It validates content and user, then delegates to `bp_activity_add()`: ```php function bp_activity_post_update( $args = '' ) { $r = bp_parse_args( $args, array( 'content' => false, 'user_id' => bp_loggedin_user_id(), 'error_type' => 'bool', ), 'activity_post_update' ); if ( empty( $r['content'] ) || ! strlen( trim( $r['content'] ) ) ) { if ( 'wp_error' === $r['error_type'] ) { return new WP_Error( 'bp_activity_missing_content', __( 'Please enter some content to post.', 'buddypress' ) ); } return false; } if ( bp_is_user_inactive( $r['user_id'] ) ) { if ( 'wp_error' === $r['error_type'] ) { return new WP_Error( 'bp_activity_inactive_user', __( 'User account has not yet been activated.', 'buddypress' ) ); } return false; } $activity_content = $r['content']; $primary_link = bp_core_get_userlink( $r['user_id'], false, true ); $add_content = apply_filters( 'bp_activity_new_update_content', $activity_content ); $add_primary_link = apply_filters( 'bp_activity_new_update_primary_link', $primary_link ); // Now write the values. $activity_id = bp_activity_add( array( 'user_id' => $r['user_id'], 'content' => $add_content, 'primary_link' => $add_primary_link, 'component' => buddypress()->activity->id, 'type' => 'activity_update', 'error_type' => $r['error_type'] ) ); if ( false === $activity_id || is_wp_error( $activity_id ) ) { return $activity_id; } $activity_content = apply_filters( 'bp_activity_latest_update_content', $r['content'], $activity_content ); bp_update_user_meta( bp_loggedin_user_id(), 'bp_latest_update', array( 'id' => $activity_id, 'content' => $activity_content ) ); do_action( 'bp_activity_posted_update', $r['content'], $r['user_id'], $activity_id ); return $activity_id; } ``` **`bp_activity_add()`** (line 2058) creates a `BP_Activity_Activity` object and calls `save()`, which runs the actual SQL INSERT: ```php function bp_activity_add( $args = '' ) { $r = bp_parse_args( $args, array( 'id' => false, 'action' => '', 'content' => '', 'component' => false, 'type' => false, 'primary_link' => '', 'user_id' => bp_loggedin_user_id(), 'item_id' => false, 'secondary_item_id' => false, 'recorded_time' => bp_core_current_time(), 'hide_sitewide' => false, 'is_spam' => false, 'error_type' => 'bool', ), 'activity_add' ); $activity = new BP_Activity_Activity( $r['id'] ); $activity->user_id = $r['user_id']; $activity->component = $r['component']; $activity->type = $r['type']; $activity->content = $r['content']; $activity->primary_link = $r['primary_link']; $activity->item_id = $r['item_id']; $activity->secondary_item_id = $r['secondary_item_id']; $activity->date_recorded = $r['recorded_time']; $activity->hide_sitewide = $r['hide_sitewide']; $activity->is_spam = $r['is_spam']; $activity->error_type = $r['error_type']; $activity->action = ! empty( $r['action'] ) ? $r['action'] : bp_activity_generate_action_string( $activity ); $save = $activity->save(); if ( 'wp_error' === $r['error_type'] && is_wp_error( $save ) ) { return $save; } elseif ( 'bool' === $r['error_type'] && false === $save ) { return false; } do_action( 'bp_activity_add', $r, $activity->id ); return $activity->id; } ``` ### The Actual SQL INSERT **File:** `/var/lib/docker/volumes/staging_wp_data/_data/wp-content/plugins/buddypress/bp-activity/classes/class-bp-activity-activity.php` (line 313) Inside `BP_Activity_Activity::save()`: ```php $q = $wpdb->prepare( "INSERT INTO {$bp->activity->table_name} ( user_id, component, type, action, content, primary_link, date_recorded, item_id, secondary_item_id, hide_sitewide, is_spam ) VALUES ( %d, %s, %s, %s, %s, %s, %s, %d, %d, %d, %d )", $this->user_id, $this->component, $this->type, $this->action, $this->content, $this->primary_link, $this->date_recorded, $this->item_id, $this->secondary_item_id, $this->hide_sitewide, $this->is_spam ); ``` --- ## Summary of the Full Flow | Step | Legacy Theme | Nouveau Theme | |------|-------------|---------------| | **AJAX action hook** | `wp_ajax_post_update` (line 190) | `wp_ajax_post_update` (line 79) | | **Handler function** | `bp_legacy_theme_post_update()` | `bp_nouveau_ajax_post_update()` | | **Nonce check** | `check_admin_referer( 'post_update', '_wpnonce_post_update' )` | `wp_verify_nonce( $_POST['_wpnonce_post_update'], 'post_update' )` | | **Input sanitization** | `sanitize_key()` on object, `(int)` on item_id; content passed raw through `$_POST['content']` | Same pattern | | **Core insert call** | `bp_activity_post_update()` or `groups_post_update()` | Same, but object value is `'user'`/`'group'` instead of `'groups'` | | **DB insertion** | `bp_activity_add()` → `BP_Activity_Activity->save()` → raw `INSERT INTO {$bp->activity->table_name}` | Same | | **Response** | Renders HTML template `activity/entry` then `exit` | Returns JSON via `wp_send_json_success()` with rendered HTML, activity ID, is_private flag | The legacy handler echoes rendered HTML and calls `exit`, while the nouveau handler uses proper `wp_send_json_success/json_error` with structured JSON responses. Both ultimately call `bp_activity_post_update()` which calls `bp_activity_add()` which instantiates `BP_Activity_Activity`, populates its properties, and calls `save()` which runs the parameterized SQL INSERT.