From 26d0d357c22734b931331fffb14f610f384ffaca Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Tue, 7 Nov 2023 10:27:20 +0100 Subject: [PATCH] Add monthly active users (#530) * Add monthly active users for better stats on FediDB * use more optimized query thanks @mattwiebe * use transients, improve logic --------- Co-authored-by: Matt Wiebe --- includes/functions.php | 73 ++++++++++++++++++++++++++++++++ includes/rest/class-nodeinfo.php | 34 ++++----------- integration/class-nodeinfo.php | 15 +++++++ 3 files changed, 96 insertions(+), 26 deletions(-) diff --git a/includes/functions.php b/includes/functions.php index b2972c0..ecb8765 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -5,6 +5,7 @@ use WP_Error; use Activitypub\Http; use Activitypub\Activity\Activity; use Activitypub\Collection\Followers; +use Activitypub\Collection\Users; /** * Returns the ActivityPub default JSON-context @@ -474,3 +475,75 @@ function is_json( $data ) { function is_blog_public() { return (bool) apply_filters( 'activitypub_is_blog_public', \get_option( 'blog_public', 1 ) ); } + +/** + * Get active users based on a given duration + * + * @param int $duration The duration to check in month(s) + * + * @return int The number of active users + */ +function get_active_users( $duration = 1 ) { + + $duration = intval( $duration ); + $transient_key = sprintf( 'monthly_active_users_%d', $duration ); + $count = get_transient( $transient_key ); + + if ( false === $count ) { + global $wpdb; + $query = "SELECT COUNT( DISTINCT post_author ) FROM {$wpdb->posts} WHERE post_type = 'post' AND post_status = 'publish' AND post_date <= DATE_SUB( NOW(), INTERVAL %d MONTH )"; + $query = $wpdb->prepare( $query, $duration ); + $count = $wpdb->get_var( $query ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery + + set_transient( $transient_key, $count, DAY_IN_SECONDS ); + } + + // if 0 authors where active + if ( 0 === $count ) { + return 0; + } + + // if single user mode + if ( is_single_user() ) { + return 1; + } + + // if blog user is disabled + if ( is_user_disabled( Users::BLOG_USER_ID ) ) { + return $count; + } + + // also count blog user + return $count + 1; +} + +/** + * Get the total number of users + * + * @return int The total number of users + */ +function get_total_users() { + // if single user mode + if ( is_single_user() ) { + return 1; + } + + $users = \get_users( + array( + 'capability__in' => array( 'publish_posts' ), + ) + ); + + if ( is_array( $users ) ) { + $users = count( $users ); + } else { + $users = 1; + } + + // if blog user is disabled + if ( is_user_disabled( Users::BLOG_USER_ID ) ) { + return $users; + } + + return $users + 1; +} diff --git a/includes/rest/class-nodeinfo.php b/includes/rest/class-nodeinfo.php index 4829e75..62151ff 100644 --- a/includes/rest/class-nodeinfo.php +++ b/includes/rest/class-nodeinfo.php @@ -3,6 +3,8 @@ namespace Activitypub\Rest; use WP_REST_Response; +use function Activitypub\get_total_users; +use function Activitypub\get_active_users; use function Activitypub\get_rest_url_by_path; /** @@ -82,24 +84,14 @@ class Nodeinfo { 'version' => \get_bloginfo( 'version' ), ); - $users = \get_users( - array( - 'capability__in' => array( 'publish_posts' ), - ) - ); - - if ( is_countable( $users ) ) { - $users = count( $users ); - } else { - $users = 1; - } - $posts = \wp_count_posts(); $comments = \wp_count_comments(); $nodeinfo['usage'] = array( 'users' => array( - 'total' => $users, + 'total' => get_total_users(), + 'activeMonth' => get_active_users( '1 month ago' ), + 'activeHalfyear' => get_active_users( '6 month ago' ), ), 'localPosts' => (int) $posts->publish, 'localComments' => (int) $comments->approved, @@ -139,24 +131,14 @@ class Nodeinfo { 'version' => \get_bloginfo( 'version' ), ); - $users = \get_users( - array( - 'capability__in' => array( 'publish_posts' ), - ) - ); - - if ( is_countable( $users ) ) { - $users = count( $users ); - } else { - $users = 1; - } - $posts = \wp_count_posts(); $comments = \wp_count_comments(); $nodeinfo['usage'] = array( 'users' => array( - 'total' => (int) $users, + 'total' => get_total_users(), + 'activeMonth' => get_active_users( 1 ), + 'activeHalfyear' => get_active_users( 6 ), ), 'localPosts' => (int) $posts->publish, 'localComments' => (int) $comments->approved, diff --git a/integration/class-nodeinfo.php b/integration/class-nodeinfo.php index f1e2506..dea6c67 100644 --- a/integration/class-nodeinfo.php +++ b/integration/class-nodeinfo.php @@ -1,6 +1,9 @@ get_total_users(), + 'activeMonth' => get_active_users( '1 month ago' ), + 'activeHalfyear' => get_active_users( '6 month ago' ), + ); + return $nodeinfo; } @@ -44,6 +53,12 @@ class Nodeinfo { public static function add_nodeinfo2_discovery( $nodeinfo ) { $nodeinfo['protocols'][] = 'activitypub'; + $nodeinfo['usage']['users'] = array( + 'total' => get_total_users(), + 'activeMonth' => get_active_users( '1 month ago' ), + 'activeHalfyear' => get_active_users( '6 month ago' ), + ); + return $nodeinfo; } }