Created
February 26, 2026 05:31
-
-
Save vapvarun/16993b156ae5aaec120b0a25e735763c to your computer and use it in GitHub Desktop.
Performance Optimization for High-Traffic BuddyPress Communities (bpcustomdev.com)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // BAD: N+1 pattern — fires a query per member | |
| $members = bp_core_get_users( array( 'per_page' => 20 ) ); | |
| foreach ( $members['users'] as $member ) { | |
| // Each call fires a SELECT against bp_xprofile_data | |
| $location = xprofile_get_field_data( 'Location', $member->ID ); | |
| $job_title = xprofile_get_field_data( 'Job Title', $member->ID ); | |
| $company = xprofile_get_field_data( 'Company', $member->ID ); | |
| echo "<div class='member-card'>"; | |
| echo "<h3>" . bp_core_get_user_displayname( $member->ID ) . "</h3>"; | |
| echo "<p>{$job_title} at {$company} — {$location}</p>"; | |
| echo "</div>"; | |
| } | |
| // Total: 1 + (20 × 3) = 61 queries just for the directory listing |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // GOOD: Bulk prefetch — 2 queries total regardless of member count | |
| $members = bp_core_get_users( array( 'per_page' => 20 ) ); | |
| $user_ids = wp_list_pluck( $members['users'], 'ID' ); | |
| // Prefetch all xprofile data for these users in one query | |
| BP_XProfile_ProfileData::get_all_for_user_ids( $user_ids ); | |
| // Now these calls hit the object cache, not the database | |
| foreach ( $members['users'] as $member ) { | |
| $location = xprofile_get_field_data( 'Location', $member->ID ); | |
| $job_title = xprofile_get_field_data( 'Job Title', $member->ID ); | |
| $company = xprofile_get_field_data( 'Company', $member->ID ); | |
| // ... render member card | |
| } | |
| // Total: 2 queries — one for members, one for all their profile data |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Bulk-fetch xprofile data for multiple users. | |
| * | |
| * @param array $user_ids Array of user IDs. | |
| * @param array $field_ids Array of xprofile field IDs to fetch. | |
| * @return array Keyed by user_id => field_id => value. | |
| */ | |
| function bpcd_bulk_get_xprofile_data( $user_ids, $field_ids ) { | |
| global $wpdb; | |
| $bp = buddypress(); | |
| $user_ids_sql = implode( ',', array_map( 'absint', $user_ids ) ); | |
| $field_ids_sql = implode( ',', array_map( 'absint', $field_ids ) ); | |
| $results = $wpdb->get_results( | |
| "SELECT user_id, field_id, value | |
| FROM {$bp->profile->table_name_data} | |
| WHERE user_id IN ({$user_ids_sql}) | |
| AND field_id IN ({$field_ids_sql})", | |
| OBJECT | |
| ); | |
| $data = array(); | |
| foreach ( $results as $row ) { | |
| $data[ $row->user_id ][ $row->field_id ] = $row->value; | |
| } | |
| return $data; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| SELECT a.id, a.user_id, a.component, a.type, a.action, | |
| a.content, a.primary_link, a.item_id, a.secondary_item_id, | |
| a.date_recorded, a.hide_sitewide, a.is_spam | |
| FROM wp_bp_activity a | |
| WHERE a.hide_sitewide = 0 | |
| AND a.is_spam = 0 | |
| AND a.type != 'activity_comment' | |
| ORDER BY a.date_recorded DESC | |
| LIMIT 0, 20; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- Composite index for the primary activity stream query pattern | |
| ALTER TABLE wp_bp_activity | |
| ADD INDEX idx_activity_stream ( | |
| hide_sitewide, | |
| is_spam, | |
| type, | |
| date_recorded DESC | |
| ); | |
| -- Index for user-specific activity feeds | |
| ALTER TABLE wp_bp_activity | |
| ADD INDEX idx_user_activity ( | |
| user_id, | |
| hide_sitewide, | |
| is_spam, | |
| date_recorded DESC | |
| ); | |
| -- Index for component-specific queries (group feeds, etc.) | |
| ALTER TABLE wp_bp_activity | |
| ADD INDEX idx_component_activity ( | |
| component, | |
| item_id, | |
| hide_sitewide, | |
| is_spam, | |
| date_recorded DESC | |
| ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- Index for looking up a user's profile data (member profiles) | |
| ALTER TABLE wp_bp_xprofile_data | |
| ADD INDEX idx_user_field_value (user_id, field_id, value(191)); | |
| -- Index for searching members by field value (member directory filters) | |
| ALTER TABLE wp_bp_xprofile_data | |
| ADD INDEX idx_field_value_user (field_id, value(191), user_id); | |
| -- Index for the last_updated column (recently updated profiles) | |
| ALTER TABLE wp_bp_xprofile_data | |
| ADD INDEX idx_last_updated (last_updated); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Ubuntu/Debian | |
| sudo apt install redis-server php-redis | |
| # Verify Redis is running | |
| redis-cli ping | |
| # Expected: PONG | |
| # Check memory usage | |
| redis-cli info memory | grep used_memory_human | |
| # Allocate at least 256MB for a 50K+ member community |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* Redis Object Cache Configuration */ | |
| define( 'WP_REDIS_HOST', '127.0.0.1' ); | |
| define( 'WP_REDIS_PORT', 6379 ); | |
| define( 'WP_REDIS_DATABASE', 0 ); // Use database 0 for this site | |
| define( 'WP_REDIS_TIMEOUT', 1 ); // 1 second connection timeout | |
| define( 'WP_REDIS_READ_TIMEOUT', 1 ); // 1 second read timeout | |
| define( 'WP_REDIS_MAXTTL', 86400 ); // Max 24-hour TTL for all keys | |
| // CRITICAL: Set a unique prefix if you host multiple WP sites on the same Redis | |
| define( 'WP_REDIS_PREFIX', 'bpsite1:' ); | |
| // Enable igbinary serialization for ~30% less memory usage | |
| define( 'WP_REDIS_SERIALIZER', 'igbinary' ); | |
| // Disable banners in admin | |
| define( 'WP_REDIS_DISABLE_BANNERS', true ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Check Redis key count after loading a BuddyPress page | |
| redis-cli dbsize | |
| # Should show hundreds of keys after a single page load | |
| # Monitor cache hits in real-time | |
| redis-cli monitor | grep -i "bp_" | |
| # You should see keys like bp_activity, bp_xprofile, bp_groups |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Warm the object cache for commonly accessed BuddyPress data. | |
| * Run this on a cron schedule (every 5-15 minutes). | |
| */ | |
| function bpcd_warm_cache() { | |
| // Pre-cache the 100 most recently active members | |
| $active_users = BP_Core_User::get_users( | |
| 'active', | |
| 100, | |
| 1, | |
| 0, | |
| false, | |
| false, | |
| true // populate_extras | |
| ); | |
| // Pre-cache popular groups | |
| $groups = groups_get_groups( array( | |
| 'per_page' => 50, | |
| 'orderby' => 'popular', | |
| 'show_hidden' => false, | |
| ) ); | |
| // Pre-cache active activity items | |
| bp_activity_get( array( | |
| 'per_page' => 50, | |
| 'fields' => 'all', | |
| ) ); | |
| } | |
| add_action( 'bpcd_cache_warm_event', 'bpcd_warm_cache' ); | |
| // Schedule the cache warming event | |
| if ( ! wp_next_scheduled( 'bpcd_cache_warm_event' ) ) { | |
| wp_schedule_event( time(), 'every_ten_minutes', 'bpcd_cache_warm_event' ); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Fragment cache helper for BuddyPress template parts. | |
| */ | |
| class BPCD_Fragment_Cache { | |
| /** | |
| * Get or generate a cached fragment. | |
| * | |
| * @param string $key Cache key. | |
| * @param callable $callback Function that generates the HTML. | |
| * @param int $ttl Time to live in seconds. | |
| * @param string $group Cache group. | |
| * @return string The HTML fragment. | |
| */ | |
| public static function get( $key, $callback, $ttl = 300, $group = 'bpcd_fragments' ) { | |
| $html = wp_cache_get( $key, $group ); | |
| if ( false === $html ) { | |
| ob_start(); | |
| call_user_func( $callback ); | |
| $html = ob_get_clean(); | |
| wp_cache_set( $key, $html, $group, $ttl ); | |
| } | |
| return $html; | |
| } | |
| /** | |
| * Invalidate a fragment. | |
| */ | |
| public static function invalidate( $key, $group = 'bpcd_fragments' ) { | |
| wp_cache_delete( $key, $group ); | |
| } | |
| } | |
| // Usage: Cache the member directory header stats for 5 minutes | |
| echo BPCD_Fragment_Cache::get( | |
| 'member_directory_stats', | |
| function() { | |
| $total = bp_get_total_member_count(); | |
| $online = bp_get_online_member_count(); | |
| echo "<div class='member-stats'>"; | |
| echo "<span>{$total} members</span> | <span>{$online} online</span>"; | |
| echo "</div>"; | |
| }, | |
| 300 // 5-minute TTL | |
| ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Cache the activity stream output per user per page. | |
| */ | |
| function bpcd_cached_activity_stream() { | |
| $user_id = bp_loggedin_user_id(); | |
| $page = bp_current_action() ? bp_current_action() : 1; | |
| $scope = isset( $_COOKIE['bp-activity-scope'] ) | |
| ? sanitize_key( $_COOKIE['bp-activity-scope'] ) | |
| : 'all'; | |
| $cache_key = "activity_stream_{$scope}_{$page}_{$user_id}"; | |
| echo BPCD_Fragment_Cache::get( | |
| $cache_key, | |
| function() { | |
| if ( bp_has_activities( bp_ajax_querystring( 'activity' ) ) ) { | |
| while ( bp_activities() ) { | |
| bp_the_activity(); | |
| bp_get_template_part( 'activity/entry' ); | |
| } | |
| } | |
| }, | |
| 120 // 2-minute TTL — balance freshness vs performance | |
| ); | |
| } | |
| // Invalidate when new activity is posted | |
| add_action( 'bp_activity_add', function( $args ) { | |
| // Flush all activity fragments — simple but effective | |
| if ( function_exists( 'wp_cache_flush_group' ) ) { | |
| wp_cache_flush_group( 'bpcd_fragments' ); | |
| } | |
| } ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Replace the activity stream with a skeleton loader on initial load. | |
| * The actual content loads via AJAX after DOMContentLoaded. | |
| */ | |
| function bpcd_lazy_activity_stream() { | |
| // Only lazy-load the main activity page, not AJAX requests | |
| if ( wp_doing_ajax() || ! bp_is_activity_component() ) { | |
| return; | |
| } | |
| // Enqueue the lazy loader script | |
| wp_enqueue_script( | |
| 'bpcd-lazy-activity', | |
| get_stylesheet_directory_uri() . '/js/lazy-activity.js', | |
| array( 'jquery' ), | |
| '1.0.0', | |
| true | |
| ); | |
| wp_localize_script( 'bpcd-lazy-activity', 'bpcdLazy', array( | |
| 'ajaxurl' => admin_url( 'admin-ajax.php' ), | |
| 'nonce' => wp_create_nonce( 'bpcd_lazy_activity' ), | |
| ) ); | |
| } | |
| add_action( 'bp_enqueue_scripts', 'bpcd_lazy_activity_stream' ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // lazy-activity.js — Load activity stream after page shell renders | |
| (function($) { | |
| 'use strict'; | |
| $(document).ready(function() { | |
| var $container = $('#activity-stream'); | |
| if (!$container.length) return; | |
| // Show skeleton placeholders | |
| var skeleton = ''; | |
| for (var i = 0; i < 5; i++) { | |
| skeleton += '<div class="activity-skeleton">' + | |
| '<div class="skeleton-avatar"></div>' + | |
| '<div class="skeleton-content">' + | |
| '<div class="skeleton-line w-60"></div>' + | |
| '<div class="skeleton-line w-80"></div>' + | |
| '<div class="skeleton-line w-40"></div>' + | |
| '</div></div>'; | |
| } | |
| $container.html(skeleton); | |
| // Fetch actual activity via AJAX | |
| $.ajax({ | |
| url: bpcdLazy.ajaxurl, | |
| type: 'POST', | |
| data: { | |
| action: 'bpcd_load_activity', | |
| nonce: bpcdLazy.nonce, | |
| scope: 'all', | |
| page: 1 | |
| }, | |
| success: function(response) { | |
| if (response.success) { | |
| $container.html(response.data.html); | |
| } | |
| } | |
| }); | |
| }); | |
| })(jQuery); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Modern infinite scroll using Intersection Observer | |
| (function() { | |
| 'use strict'; | |
| var page = 1; | |
| var loading = false; | |
| var sentinel = document.getElementById('activity-sentinel'); | |
| if (!sentinel) return; | |
| var observer = new IntersectionObserver(function(entries) { | |
| if (entries[0].isIntersecting && !loading) { | |
| loading = true; | |
| page++; | |
| fetch(bpcdLazy.ajaxurl, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, | |
| body: 'action=bpcd_load_activity&nonce=' + bpcdLazy.nonce + '&page=' + page | |
| }) | |
| .then(function(res) { return res.json(); }) | |
| .then(function(data) { | |
| if (data.success && data.data.html) { | |
| var stream = document.getElementById('activity-stream'); | |
| stream.insertAdjacentHTML('beforeend', data.data.html); | |
| loading = false; | |
| } else { | |
| // No more items — disconnect observer | |
| observer.disconnect(); | |
| } | |
| }); | |
| } | |
| }, { rootMargin: '200px' }); // Start loading 200px before sentinel is visible | |
| observer.observe(sentinel); | |
| })(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Maintain a fast lookup table for member last-active times. | |
| * This avoids querying bp_activity for sorting member directories. | |
| */ | |
| function bpcd_update_last_active_index( $user_id ) { | |
| global $wpdb; | |
| $wpdb->replace( | |
| $wpdb->prefix . 'bp_member_last_active', | |
| array( | |
| 'user_id' => $user_id, | |
| 'last_active' => current_time( 'mysql', true ), | |
| ), | |
| array( '%d', '%s' ) | |
| ); | |
| } | |
| add_action( 'bp_activity_add', function( $args ) { | |
| if ( ! empty( $args['user_id'] ) ) { | |
| bpcd_update_last_active_index( $args['user_id'] ); | |
| } | |
| }); | |
| add_action( 'wp_login', function( $user_login, $user ) { | |
| bpcd_update_last_active_index( $user->ID ); | |
| }, 10, 2 ); | |
| /** | |
| * Create the fast lookup table. | |
| */ | |
| function bpcd_create_last_active_table() { | |
| global $wpdb; | |
| $table = $wpdb->prefix . 'bp_member_last_active'; | |
| $charset_collate = $wpdb->get_charset_collate(); | |
| $sql = "CREATE TABLE IF NOT EXISTS {$table} ( | |
| user_id BIGINT UNSIGNED NOT NULL, | |
| last_active DATETIME NOT NULL, | |
| PRIMARY KEY (user_id), | |
| INDEX idx_last_active (last_active DESC) | |
| ) {$charset_collate};"; | |
| require_once ABSPATH . 'wp-admin/includes/upgrade.php'; | |
| dbDelta( $sql ); | |
| } | |
| register_activation_hook( __FILE__, 'bpcd_create_last_active_table' ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Pre-filter member directory queries to reduce JOIN overhead. | |
| * Hooks into bp_pre_user_query to add efficient conditions. | |
| */ | |
| function bpcd_optimize_member_query( $query ) { | |
| // Only optimize when xprofile search is active | |
| if ( empty( $query->query_vars['xprofile_query'] ) ) { | |
| return; | |
| } | |
| global $wpdb; | |
| $bp = buddypress(); | |
| // Get the field ID and value from the search | |
| $xprofile_query = $query->query_vars['xprofile_query']; | |
| foreach ( $xprofile_query as $clause ) { | |
| $field_id = absint( $clause['field'] ); | |
| $value = sanitize_text_field( $clause['value'] ); | |
| // Use a subquery with our optimized index | |
| $user_ids = $wpdb->get_col( $wpdb->prepare( | |
| "SELECT user_id FROM {$bp->profile->table_name_data} | |
| WHERE field_id = %d AND value LIKE %s | |
| LIMIT 1000", | |
| $field_id, | |
| '%' . $wpdb->esc_like( $value ) . '%' | |
| ) ); | |
| if ( ! empty( $user_ids ) ) { | |
| $query->query_vars['include'] = $user_ids; | |
| } else { | |
| // No matches — short-circuit the query | |
| $query->query_vars['include'] = array( 0 ); | |
| } | |
| } | |
| } | |
| add_action( 'bp_pre_user_query', 'bpcd_optimize_member_query' ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Rewrite BuddyPress avatar URLs to use CDN. | |
| */ | |
| function bpcd_cdn_avatar_url( $avatar_url ) { | |
| $site_url = site_url(); | |
| $cdn_url = 'https://cdn.yourdomain.com'; | |
| return str_replace( $site_url, $cdn_url, $avatar_url ); | |
| } | |
| add_filter( 'bp_core_fetch_avatar_url', 'bpcd_cdn_avatar_url' ); | |
| add_filter( 'bp_core_fetch_avatar', 'bpcd_cdn_avatar_url' ); | |
| /** | |
| * Rewrite cover image URLs for CDN. | |
| */ | |
| function bpcd_cdn_cover_image_url( $cover_url ) { | |
| $upload_dir = wp_upload_dir(); | |
| $cdn_url = 'https://cdn.yourdomain.com/wp-content/uploads'; | |
| return str_replace( $upload_dir['baseurl'], $cdn_url, $cover_url ); | |
| } | |
| add_filter( 'bp_attachments_pre_get_attachment', 'bpcd_cdn_cover_image_url' ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # .htaccess — Cache BuddyPress static assets aggressively | |
| <IfModule mod_expires.c> | |
| # Avatars and cover images — 30 days | |
| <FilesMatch "\.(jpg|jpeg|png|gif|webp)$"> | |
| ExpiresDefault "access plus 30 days" | |
| Header set Cache-Control "public, max-age=2592000, immutable" | |
| </FilesMatch> | |
| # CSS and JS — 7 days (with versioned query strings for cache busting) | |
| <FilesMatch "\.(css|js)$"> | |
| ExpiresDefault "access plus 7 days" | |
| Header set Cache-Control "public, max-age=604800" | |
| </FilesMatch> | |
| </IfModule> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* Query Monitor — enable full profiling */ | |
| define( 'QM_ENABLE_CAPS_PANEL', true ); // Show capability checks | |
| define( 'SAVEQUERIES', true ); // Store query caller info | |
| /* Enable slow query highlighting (queries taking > 0.05s) */ | |
| define( 'QM_DB_EXPENSIVE', 0.05 ); | |
| /* Show queries from all plugins, not just the current request */ | |
| define( 'QM_DARK_MODE', true ); // Easier on the eyes during long sessions |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Log BuddyPress slow queries to a dedicated log file. | |
| * Enable in production for ongoing performance monitoring. | |
| */ | |
| function bpcd_log_slow_queries() { | |
| if ( ! defined( 'SAVEQUERIES' ) || ! SAVEQUERIES ) { | |
| return; | |
| } | |
| global $wpdb; | |
| $slow_threshold = 0.05; // 50ms | |
| foreach ( $wpdb->queries as $query ) { | |
| list( $sql, $time, $caller ) = $query; | |
| if ( $time > $slow_threshold && strpos( $caller, 'bp_' ) !== false ) { | |
| $log_entry = sprintf( | |
| "[%s] %.4fs | %s | %s\n", | |
| current_time( 'mysql' ), | |
| $time, | |
| trim( preg_replace( '/\s+/', ' ', $sql ) ), | |
| $caller | |
| ); | |
| error_log( $log_entry, 3, WP_CONTENT_DIR . '/bp-slow-queries.log' ); | |
| } | |
| } | |
| } | |
| add_action( 'shutdown', 'bpcd_log_slow_queries' ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* ============================================ | |
| Performance Configuration for BuddyPress | |
| ============================================ */ | |
| /* Memory — BuddyPress is memory-hungry, especially with large member lists */ | |
| define( 'WP_MEMORY_LIMIT', '256M' ); | |
| define( 'WP_MAX_MEMORY_LIMIT', '512M' ); // Admin memory limit | |
| /* Cron — Disable wp-cron on page loads, use system cron instead */ | |
| define( 'DISABLE_WP_CRON', true ); | |
| // Add to crontab: */2 * * * * wget -q -O - https://yourdomain.com/wp-cron.php | |
| /* Post revisions — Reduce DB bloat */ | |
| define( 'WP_POST_REVISIONS', 5 ); | |
| /* Autosave interval — Reduce ajax requests */ | |
| define( 'AUTOSAVE_INTERVAL', 120 ); // 2 minutes instead of 60s | |
| /* Trash — Auto-delete trashed items after 14 days */ | |
| define( 'EMPTY_TRASH_DAYS', 14 ); | |
| /* Concatenate admin scripts — Fewer HTTP requests in admin */ | |
| define( 'CONCATENATE_SCRIPTS', true ); | |
| /* Disable file editing — Security + slight performance gain */ | |
| define( 'DISALLOW_FILE_EDIT', true ); | |
| /* Table repair optimization */ | |
| define( 'WP_ALLOW_REPAIR', false ); // Disable in production |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # System cron for WordPress — runs every 2 minutes | |
| # Edit with: crontab -e | |
| */2 * * * * /usr/bin/php /var/www/yourdomain.com/wp-cron.php > /dev/null 2>&1 | |
| # Or using WP-CLI for more reliable execution: | |
| */2 * * * * cd /var/www/yourdomain.com && /usr/local/bin/wp cron event run --due-now > /dev/null 2>&1 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Configure HyperDB for read/write splitting. | |
| * Place this in db-config.php (not wp-config.php). | |
| */ | |
| $wpdb->add_database( array( | |
| 'host' => 'primary-db.yourserver.com', | |
| 'user' => 'wp_user', | |
| 'password' => 'secure_password', | |
| 'name' => 'wp_buddypress', | |
| 'write' => 1, // Primary handles all writes | |
| 'read' => 1, // Primary also handles some reads | |
| 'dataset' => 'global', | |
| 'timeout' => 0.5, | |
| ) ); | |
| $wpdb->add_database( array( | |
| 'host' => 'replica-db.yourserver.com', | |
| 'user' => 'wp_reader', | |
| 'password' => 'secure_password', | |
| 'name' => 'wp_buddypress', | |
| 'write' => 0, // Replica never writes | |
| 'read' => 2, // Higher priority for reads | |
| 'dataset' => 'global', | |
| 'timeout' => 0.5, | |
| ) ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- Partition bp_activity by month for fast range scans | |
| ALTER TABLE wp_bp_activity | |
| PARTITION BY RANGE (YEAR(date_recorded) * 100 + MONTH(date_recorded)) ( | |
| PARTITION p202501 VALUES LESS THAN (202502), | |
| PARTITION p202502 VALUES LESS THAN (202503), | |
| PARTITION p202503 VALUES LESS THAN (202504), | |
| PARTITION p202504 VALUES LESS THAN (202505), | |
| PARTITION p202505 VALUES LESS THAN (202506), | |
| PARTITION p202506 VALUES LESS THAN (202507), | |
| PARTITION p_future VALUES LESS THAN MAXVALUE | |
| ); | |
| -- Activity stream queries now only scan recent partitions | |
| -- A query for "last 20 activities" hits 1-2 partitions instead of the entire table |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Nginx FastCGI Cache configuration for BuddyPress | |
| fastcgi_cache_path /var/cache/nginx/bp levels=1:2 | |
| keys_zone=bp_cache:100m | |
| inactive=60m | |
| max_size=2g; | |
| server { | |
| # ... your server block ... | |
| # Cache key — includes scheme, host, and request URI | |
| set $skip_cache 0; | |
| # Skip cache for logged-in users (BuddyPress personalizes content) | |
| if ($http_cookie ~* "wordpress_logged_in_") { | |
| set $skip_cache 1; | |
| } | |
| # Skip cache for BuddyPress AJAX requests | |
| if ($request_uri ~* "/wp-admin/admin-ajax.php") { | |
| set $skip_cache 1; | |
| } | |
| # Skip cache for BuddyPress activity post submissions | |
| if ($request_method = POST) { | |
| set $skip_cache 1; | |
| } | |
| location ~ \.php$ { | |
| fastcgi_cache bp_cache; | |
| fastcgi_cache_valid 200 10m; | |
| fastcgi_cache_bypass $skip_cache; | |
| fastcgi_no_cache $skip_cache; | |
| fastcgi_cache_key "$scheme$request_method$host$request_uri"; | |
| add_header X-Cache-Status $upstream_cache_status; | |
| # ... fastcgi_pass and other params ... | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Disable BuddyPress components you are not using. | |
| * Each disabled component eliminates its database queries entirely. | |
| * Add to your theme's functions.php or a custom plugin. | |
| */ | |
| function bpcd_disable_unused_components( $components ) { | |
| // Remove components you do not need | |
| $disable = array( | |
| 'blogs', // Blog tracking (rarely needed on single-site) | |
| 'settings', // If you use a custom settings page | |
| ); | |
| foreach ( $disable as $component ) { | |
| unset( $components[ $component ] ); | |
| } | |
| return $components; | |
| } | |
| add_filter( 'bp_active_components', 'bpcd_disable_unused_components' ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Limit activity queries to the last 90 days by default. | |
| * Prevents full-table scans on large activity tables. | |
| */ | |
| function bpcd_limit_activity_date_range( $args ) { | |
| if ( empty( $args['date_query'] ) ) { | |
| $args['date_query'] = array( | |
| array( | |
| 'after' => '90 days ago', | |
| 'inclusive' => true, | |
| ), | |
| ); | |
| } | |
| return $args; | |
| } | |
| add_filter( 'bp_after_has_activities_parse_args', 'bpcd_limit_activity_date_range' ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Add native lazy loading to BuddyPress avatars. | |
| * Reduces initial page weight significantly for member directories. | |
| */ | |
| function bpcd_lazy_load_avatars( $avatar_html ) { | |
| // Add loading="lazy" to avatar img tags | |
| if ( strpos( $avatar_html, 'loading=' ) === false ) { | |
| $avatar_html = str_replace( '<img ', '<img loading="lazy" decoding="async" ', $avatar_html ); | |
| } | |
| return $avatar_html; | |
| } | |
| add_filter( 'bp_core_fetch_avatar', 'bpcd_lazy_load_avatars' ); | |
| /** | |
| * Serve WebP avatars when the browser supports them. | |
| */ | |
| function bpcd_webp_avatars( $avatar_url ) { | |
| $webp_path = preg_replace( '/\.(jpg|jpeg|png)$/i', '.webp', $avatar_url ); | |
| // Check if the WebP version exists | |
| $upload_dir = wp_upload_dir(); | |
| $local_path = str_replace( $upload_dir['baseurl'], $upload_dir['basedir'], $webp_path ); | |
| if ( file_exists( $local_path ) ) { | |
| return $webp_path; | |
| } | |
| return $avatar_url; | |
| } | |
| add_filter( 'bp_core_fetch_avatar_url', 'bpcd_webp_avatars' ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Defer non-critical BuddyPress JavaScript. | |
| * Improves First Contentful Paint by ~200-400ms. | |
| */ | |
| function bpcd_defer_bp_scripts( $tag, $handle ) { | |
| $defer_handles = array( | |
| 'bp-confirm', | |
| 'bp-widget-members', | |
| 'bp-jquery-query', | |
| 'bp-mentions', | |
| ); | |
| if ( in_array( $handle, $defer_handles, true ) ) { | |
| return str_replace( ' src', ' defer src', $tag ); | |
| } | |
| return $tag; | |
| } | |
| add_filter( 'script_loader_tag', 'bpcd_defer_bp_scripts', 10, 2 ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment