Try: Fediverse Wrapped statistics feature#2633
Conversation
Implements monthly/annual statistics collection and display: - Core Statistics class for collecting engagement metrics - Scheduler for monthly stats collection and annual compilation - Dashboard widget showing stats with charts - Annual email template for year-end summaries - Shareable wrapped card for public sharing Known issues: - URL rewrite rules for wrapped card need debugging (year parameter not captured) - Stats display shows 0 values on HTTP requests despite correct query var registration Related to #2597
Eliminated the Fediverse Wrapped shareable card functionality by deleting the template, removing related rewrite rules, query vars, and rendering logic from Statistics, and cleaning up associated JavaScript and dashboard UI elements.
- Replace jQuery-based widget with React components - Add REST API endpoint for statistics data - Add TypeScript types for stats data structures - Add chart legend showing engagement types - Support stored monthly stats for demo/historical data - Add CLI command for populating demo data (local dev only)
- Make StatHighlights display engagement types dynamically from API - Add period label "This month vs. last year" to clarify comparison - Draw individual lines for each engagement type in the chart - Use WordPress default color palette CSS variables with fallbacks - Remove hardcoded comment types - all types now dynamic - Move demo data generation from Statistics class to local CLI
obenland
left a comment
There was a problem hiding this comment.
Keeping it to structure, I'd see if there are stats we can bump as they occur instead of aggregating monthly. I reckon that'll probably be more accurate, especially for things we can't or are hard to query after the fact.
One of the reasons Jetpack is so powerful is because it can store large amounts of data, process them remotely, and aggregate them. It might be worth considering making this a jetpack integration instead of hoping an option is enough?
The dashboard widget is neat, is there something we can do to make that a bit more interactive?
|
@obenland thanks for your feedback! 🫶 |
I somehow agree, that we might be able to have a collab, but you checked the number of folks that have both installed an that is quite low. So I would love to have at least a basic stats feature in the plugin, to maybe motivate users to interact a bit more!? |
- Move cron schedule methods (add_cron_schedules, register_schedules, deregister_schedules) from Scheduler\Statistics to main Scheduler - Move helper methods (get_next_first_of_month, get_next_january_first) to main Scheduler - Update dashboard stats widget to get actors on JS side like the reader - Use @wordpress/core-data to check actor mode and capabilities - Remove PHP-passed actors from Statistics_Dashboard
Resolved conflicts: - includes/class-migration.php: Added both emoji migration and stats backfill callbacks - includes/class-scheduler.php: Combined SCHEDULES constant loop with stats scheduling Additional changes based on PR feedback: - Changed annual stats notification from January 1st to December 1st (per @obenland) - Fixed CSS linting issues in dashboard-stats stylesheet
- Changed compile_and_send_annual_stats to get current year instead of previous year (since it now runs December 1st, not January 1st) - Updated docblock to reflect the December timing - Added TODO for shareable landing page feature (per @obenland feedback)
- Use WordPress admin color palette (#2c3338, #646970, #f6f7f7, etc.) - Add dashicons for stat types (followers, posts, likes, reposts, comments) - Match padding and spacing from #dashboard_right_now widget - Use border-top separators instead of background color blocks - Style top supporter section like WordPress admin notices - Style top posts section like activity widget list items - Add responsive breakpoint for mobile
- Make chart container full width with background extending to edges - Better align icons with text using flex-start and margin adjustments - Simplify stat-content to inline display for natural text flow
Change all section headlines from h4 to h3 for proper heading hierarchy. Move the "Engagement Over Time" title outside the grey background area by applying the background only to the chart container.
Change "This month vs. last year" from p to h3 for consistent heading hierarchy across all widget sections.
Match WordPress admin dashboard CSS patterns: - Centralize h3 styles (14px, font-weight 400) - Use WordPress admin color palette (#50575e, #82878c) - Match padding patterns from #dashboard_right_now - Simplify section styling for cleaner appearance
- Use float layout for stat items (matches #dashboard_right_now li) - Icon styling exactly matches WordPress: font, padding, display, vertical-align - Activity block pattern for sections with negative margins - Exact padding values from WordPress dashboard CSS - h3 margins match #dashboard-widgets h3 pattern
- Current month stats are now always queried live to include recent engagement (likes, reposts, comments) - Backfill migration now skips the current month since it's in progress - Previous months use stored stats for performance - Add delete_monthly_stats() and recollect_monthly_stats() methods - Add force option to trigger_monthly_collection() scheduler method This fixes an issue where new reposts wouldn't show in stats because the current month data was being served from cached options.
Expose the scheduler's trigger_monthly_collection() and trigger_annual_compilation() methods via the local development CLI: - stats collect: Trigger monthly stats collection - stats compile: Trigger annual stats compilation Options include --year, --month, --force, and --no-email for flexibility.
- Remove get_yearly_monthly_breakdown() (replaced by get_rolling_monthly_breakdown) - Remove deprecated get_year_comparison() (use get_period_comparison instead)
- Remove trigger_monthly_collection() from scheduler - Remove trigger_annual_compilation() from scheduler - Remove delete_monthly_stats() and recollect_monthly_stats() from Statistics - Implement collect and compile logic directly in local CLI class
The queries were defaulting to only 'post' type, missing engagement on pages and custom post types enabled for ActivityPub. Now uses activitypub_support_post_types option in all queries: - count_engagement_in_range() - get_top_posts() - get_top_multiplicator() - get_earliest_data_year()
There was a problem hiding this comment.
Pull request overview
This PR implements a "Fediverse Wrapped" statistics feature for the ActivityPub plugin, providing users with engagement analytics similar to Spotify Wrapped. The feature includes a React-based dashboard widget displaying follower growth, post metrics, and engagement statistics with month-over-month comparisons and trend visualization.
Changes:
- Adds comprehensive statistics collection and storage system with monthly/annual aggregation
- Implements REST API endpoint for fetching statistics data with permission checks
- Creates interactive React dashboard widget with stat highlights, line charts, top posts, and top supporter sections
- Adds WP-CLI commands for demo data population and statistics management
- Includes scheduled jobs for automatic monthly statistics collection and annual compilation
- Provides email notification system for annual "wrapped" summary
Reviewed changes
Copilot reviewed 24 out of 24 changed files in this pull request and generated 21 comments.
Show a summary per file
| File | Description |
|---|---|
| includes/class-statistics.php | Core statistics collection class with methods for aggregating engagement metrics, follower counts, and top content |
| includes/rest/class-statistics-controller.php | REST API controller providing authenticated endpoint for retrieving statistics data |
| includes/wp-admin/class-statistics-dashboard.php | Dashboard widget registration and asset enqueuing for the statistics display |
| includes/scheduler/class-statistics.php | Scheduled task handlers for monthly/annual statistics collection and email notifications |
| includes/class-scheduler.php | Cron schedule registration for monthly and annual statistics compilation |
| includes/class-migration.php | Migration hook to backfill historical statistics data on plugin update |
| includes/collection/class-followers.php | Added count_in_range method to support follower growth tracking |
| local/class-cli.php | WP-CLI commands for statistics management including populate, clear, collect, and compile actions |
| activitypub.php | Plugin initialization updates to register new statistics classes and REST controller |
| src/dashboard-stats/ | Complete React/TypeScript implementation of the dashboard widget UI with components for highlights, charts, top posts, and supporters |
| templates/emails/annual-wrapped.php | HTML email template for annual statistics summary notifications |
| build/dashboard-stats/ | Compiled JavaScript and CSS assets for the dashboard widget |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Fix annual email guard to check all registered comment types dynamically instead of hardcoded plural keys (likes_count vs like_count) - Fix follower growth calculation to use followers_count (gained) instead of non-existent followers_gained/followers_lost keys - Add comment date filter to get_top_posts() to only count engagement within the specified date range - Use get_comment_types_for_stats() in count_engagement_in_range() and get_period_comparison() to include federated comments in totals - Fix dashboard widget to fall back to user stats when blog stats are forbidden (non-admin users) - Fix December scheduling to correctly check if past Dec 1st 3:00 AM
- Add generic Mailer::send() method for email dispatching - Change "Followers" to "New Followers" in dashboard highlights (clarity) - Add SVG accessibility (role="img", aria-labelledby, title element) - Add aria-label for external links (opens in new tab indicator) - Use deterministic color assignment via djb2 hash for chart lines - Delay statistics backfill by 1 hour to avoid immediate load after upgrade
Move subject generation to caller instead of determining it internally based on template name. This simplifies the Mailer class and gives callers more control over email subjects.
Register collect and compile as proper subcommands following the existing CLI structure pattern.
Move the stats endpoint under the admin subfolder and update the rest_base to admin/stats to match the admin controller pattern.
- Register Scheduler\Statistics::init() so cron callbacks work - Add import section comments to all dashboard-stats TSX files - Fix auto-generated @param root0 JSDoc with proper annotations - Add ReactNode return type to all component functions - Fix missing backslash on current_user_can in dashboard template
…I send command - Make Mailer::send() accept an optional $alt_body parameter; auto-generate plain text from HTML via wp_strip_all_tags() when not provided - Remove tightly-coupled get_plain_text_body() from Mailer; move plain text generation into the Statistics scheduler caller - Add activitypub_mailer_annual_report user/blog preference with checkbox in both user profile and blog settings notification fieldsets - Fix esc_html() misuse on %d format specifier in annual-wrapped template - Add `wp activitypub stats send` CLI subcommand for testing the annual report email without waiting for cron - Make Statistics::send_annual_email() public for CLI access
- Cast user_id to int in Statistics_Controller to fix strict comparison with BLOG_USER_ID that broke blog actor stats - Replace unbounded get_posts(-1) with SQL subqueries to prevent OOM on large sites; extract get_post_ids_subquery() helper - Add 15-minute transient caching to stats REST endpoint - Fix email template using esc_html__() with HTML arguments (wp_kses) - Fix timezone mismatch in date construction (gmmktime instead of strtotime/gmdate mix) - Reschedule monthly cron to exact first-of-month to prevent 30-day drift - Sanitize template path in Mailer::send() to prevent path traversal - Guard against duplicate 'comment' key in get_comment_types_for_stats()
Fixes #2597
Proposed changes:
Removed from original scope:
Other information:
Testing instructions:
Setup demo data (optional):
Dashboard Widget:
/wp-admin/)Clear demo data:
Changelog entry
Changelog Entry Details
Significance
Type
Message
Add Fediverse statistics dashboard widget with engagement metrics and charts.