diff --git a/README.md b/README.md index b1168a8..4c41fcd 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ **Contributors:** [automattic](https://profiles.wordpress.org/automattic/), [pfefferle](https://profiles.wordpress.org/pfefferle/), [mediaformat](https://profiles.wordpress.org/mediaformat/), [mattwiebe](https://profiles.wordpress.org/mattwiebe/), [akirk](https://profiles.wordpress.org/akirk/), [jeherve](https://profiles.wordpress.org/jeherve/), [nuriapena](https://profiles.wordpress.org/nuriapena/), [cavalierlife](https://profiles.wordpress.org/cavalierlife/) **Tags:** OStatus, fediverse, activitypub, activitystream **Requires at least:** 4.7 -**Tested up to:** 6.3 -**Stable tag:** 1.0.10 +**Tested up to:** 6.4 +**Stable tag:** 1.1.0 **Requires PHP:** 5.6 **License:** MIT **License URI:** http://opensource.org/licenses/MIT @@ -110,6 +110,10 @@ Project maintained on GitHub at [automattic/wordpress-activitypub](https://githu * Improved: audio and video attachments are now supported! * Improved: better error messages if remote profile is not accessible * Improved: PHP 8.1 compatibility +* Fixed: don't try to parse mentions or hashtags for very large (>1MB) posts to prevent timeouts +* Fixed: better handling of ISO-639-1 locale codes +* Improved: more reliable [ap_author], props @uk3 +* Improved: NodeInfo statistics ### 1.0.10 ### diff --git a/activitypub.php b/activitypub.php index 97f6067..380b438 100644 --- a/activitypub.php +++ b/activitypub.php @@ -3,7 +3,7 @@ * Plugin Name: ActivityPub * Plugin URI: https://github.com/pfefferle/wordpress-activitypub/ * Description: The ActivityPub protocol is a decentralized social networking protocol based upon the ActivityStreams 2.0 data format. - * Version: 1.0.10 + * Version: 1.1.0 * Author: Matthias Pfefferle & Automattic * Author URI: https://automattic.com/ * License: MIT diff --git a/includes/class-shortcodes.php b/includes/class-shortcodes.php index 708aa61..491a6ad 100644 --- a/includes/class-shortcodes.php +++ b/includes/class-shortcodes.php @@ -390,7 +390,8 @@ class Shortcodes { return ''; } - $name = \get_the_author_meta( 'display_name', $item->post_author ); + $author_id = \get_post_field( 'post_author', $item->ID ); + $name = \get_the_author_meta( 'display_name', $author_id ); if ( ! $name ) { return ''; @@ -415,7 +416,8 @@ class Shortcodes { return ''; } - $url = \get_the_author_meta( 'user_url', $item->post_author ); + $author_id = \get_post_field( 'post_author', $item->ID ); + $url = \get_the_author_meta( 'user_url', $author_id ); if ( ! $url ) { return ''; 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/includes/transformer/class-post.php b/includes/transformer/class-post.php index c10f0cf..2117ce7 100644 --- a/includes/transformer/class-post.php +++ b/includes/transformer/class-post.php @@ -82,7 +82,7 @@ class Post { $object->set_content( $this->get_content() ); $object->set_content_map( array( - \strstr( \get_locale(), '_', true ) => $this->get_content(), + $this->get_locale() => $this->get_content(), ) ); $path = sprintf( 'users/%d/followers', intval( $wp_post->post_author ) ); @@ -580,4 +580,25 @@ class Post { protected function get_mentions() { return apply_filters( 'activitypub_extract_mentions', array(), $this->wp_post->post_content, $this->wp_post ); } + + /** + * Returns the locale of the post. + * + * @return string The locale of the post. + */ + public function get_locale() { + $post_id = $this->wp_post->ID; + $lang = \strtolower( \strtok( \get_locale(), '_-' ) ); + + /** + * Filter the locale of the post. + * + * @param string $lang The locale of the post. + * @param int $post_id The post ID. + * @param WP_Post $post The post object. + * + * @return string The filtered locale of the post. + */ + return apply_filters( 'activitypub_post_locale', $lang, $post_id, $this->wp_post ); + } } 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; } } diff --git a/readme.txt b/readme.txt index 5a70498..eed006a 100644 --- a/readme.txt +++ b/readme.txt @@ -2,8 +2,8 @@ Contributors: automattic, pfefferle, mediaformat, mattwiebe, akirk, jeherve, nuriapena, cavalierlife Tags: OStatus, fediverse, activitypub, activitystream Requires at least: 4.7 -Tested up to: 6.3 -Stable tag: 1.0.10 +Tested up to: 6.4 +Stable tag: 1.1.0 Requires PHP: 5.6 License: MIT License URI: http://opensource.org/licenses/MIT @@ -111,6 +111,9 @@ Project maintained on GitHub at [automattic/wordpress-activitypub](https://githu * Improved: better error messages if remote profile is not accessible * Improved: PHP 8.1 compatibility * Fixed: don't try to parse mentions or hashtags for very large (>1MB) posts to prevent timeouts +* Fixed: better handling of ISO-639-1 locale codes +* Improved: more reliable [ap_author], props @uk3 +* Improved: NodeInfo statistics = 1.0.10 =