diff --git a/.gitattributes b/.gitattributes index 43a1ca8b4a..3fc0d24409 100644 --- a/.gitattributes +++ b/.gitattributes @@ -23,6 +23,8 @@ /package-lock.json export-ignore /package.json export-ignore /phpcs.xml export-ignore +/phpstan.neon.dist export-ignore +/phpstan-baseline.neon export-ignore /phpunit.xml.dist export-ignore /tsconfig.json export-ignore /webpack.config.js export-ignore diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml new file mode 100644 index 0000000000..15943c1a77 --- /dev/null +++ b/.github/workflows/phpstan.yml @@ -0,0 +1,44 @@ +name: PHPStan +on: + push: + branches: + - trunk + paths: + - '**/*.php' + - 'composer.json' + - 'composer.lock' + - 'phpstan.neon.dist' + - 'phpstan-baseline.neon' + - 'tests/phpstan/**' + - '.github/workflows/phpstan.yml' + - '!build/**/*.asset.php' + pull_request: + paths: + - '**/*.php' + - 'composer.json' + - 'composer.lock' + - 'phpstan.neon.dist' + - 'phpstan-baseline.neon' + - 'tests/phpstan/**' + - '.github/workflows/phpstan.yml' + - '!build/**/*.asset.php' +permissions: + contents: read +jobs: + phpstan: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v7 + - name: Setup PHP + uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # 2.37.2 + with: + php-version: '8.3' + coverage: none + tools: composer + - name: Install Composer dependencies for PHP + uses: ramsey/composer-install@26d8a556604053a9612623447203a691f406fbe6 # v4 + - name: Analyse + run: composer analyze -- --no-progress --error-format=github + - name: Test PHPStan extension + run: composer analyze:test diff --git a/activitypub.php b/activitypub.php index 3f8e0fb21f..7c0ddd8281 100644 --- a/activitypub.php +++ b/activitypub.php @@ -47,6 +47,8 @@ /** * Initialize REST routes. + * + * @return void */ function rest_init() { Rest\Server::init(); @@ -86,6 +88,8 @@ function rest_init() { /** * Initialize plugin. + * + * @return void */ function plugin_init() { \add_action( 'init', array( __NAMESPACE__ . '\Activitypub', 'init' ) ); @@ -131,11 +135,13 @@ function plugin_init() { /** * Initialize plugin admin. + * + * @return void */ function plugin_admin_init() { // Screen Options and Menus are set before `admin_init`. \add_action( 'init', array( __NAMESPACE__ . '\WP_Admin\Heartbeat', 'init' ), 9 ); // Before script loader. - \add_filter( 'init', array( __NAMESPACE__ . '\WP_Admin\Screen_Options', 'init' ) ); + \add_action( 'init', array( __NAMESPACE__ . '\WP_Admin\Screen_Options', 'init' ) ); \add_action( 'init', array( __NAMESPACE__ . '\WP_Admin\Menu', 'init' ) ); \add_action( 'admin_init', array( __NAMESPACE__ . '\WP_Admin\Admin', 'init' ) ); @@ -160,6 +166,8 @@ function plugin_admin_init() { * Redirect to the welcome page after plugin activation. * * @param string $plugin The plugin basename. + * + * @return void */ function activation_redirect( $plugin ) { if ( ACTIVITYPUB_PLUGIN_BASENAME === $plugin ) { diff --git a/composer.json b/composer.json index 8aa07b2048..ee8d136431 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,15 @@ "dealerdirect/phpcodesniffer-composer-installer": "^1.0.0", "sirbrillig/phpcs-variable-analysis": "^3.0", "phpcsstandards/phpcsextra": "^1.1.0", - "dms/phpunit-arraysubset-asserts": "^0.5.0" + "dms/phpunit-arraysubset-asserts": "^0.5.0", + "phpstan/phpstan": "^2.1", + "szepeviktor/phpstan-wordpress": "^2.0" + }, + "autoload-dev": { + "classmap": [ + "tests/phpstan/class-magic-accessors-extension.php", + "tests/phpstan/class-magic-accessor.php" + ] }, "config": { "allow-plugins": true @@ -48,6 +56,15 @@ "test:wp-env": [ "wp-env run tests-cli --env-cwd=\"wp-content/plugins/activitypub\" vendor/bin/phpunit" ], + "analyze": [ + "phpstan analyse --memory-limit=-1" + ], + "analyze:baseline": [ + "phpstan analyse --memory-limit=-1 --generate-baseline phpstan-baseline.neon" + ], + "analyze:test": [ + "phpunit --configuration tests/phpstan/phpunit.xml.dist" + ], "lint": [ "vendor/bin/phpcs" ], diff --git a/docs/code-linting.md b/docs/code-linting.md index 7e17661f8d..d1e7941860 100644 --- a/docs/code-linting.md +++ b/docs/code-linting.md @@ -2,6 +2,7 @@ ## Table of Contents - [PHP Code Standards](#php-code-standards) +- [Static Analysis](#static-analysis) - [JavaScript Standards](#javascript-standards) - [CSS Standards](#css-standards) - [Pre-commit Automation](#pre-commit-automation) @@ -54,6 +55,30 @@ See [PHP Coding Standards](php-coding-standards.md). **Important:** All DocBlock descriptions must end with proper punctuation (periods). +## Static Analysis + +PHPStan checks the PHP code for type errors and for missing type declarations: + +```bash +composer analyze +``` + +The configuration lives in `phpstan.neon.dist`. It runs at level 6 and checks parameter and return types; the value types of arrays (`array`) are not required. `phpstan-baseline.neon` suppresses existing findings by message, file and occurrence count, not by changed lines. New findings and obsolete baseline entries fail the check. After fixing existing findings, remove their baseline entries or regenerate the baseline: + +```bash +composer analyze:baseline +``` + +Review the baseline diff: it should remove resolved findings, not suppress new errors. Fix new errors before regenerating it. + +Run the custom magic-accessor extension's regression tests without WordPress or Docker: + +```bash +composer analyze:test +``` + +Integrations reference classes of other plugins that are not installed here; those "class not found" findings are ignored for the `integration/` directory. WP-CLI is covered by the small stubs in `tests/phpstan/stubs/`. + ## JavaScript Standards ### Quick Commands diff --git a/includes/activity/class-activity.php b/includes/activity/class-activity.php index 577cbe9f6a..88198d9b55 100644 --- a/includes/activity/class-activity.php +++ b/includes/activity/class-activity.php @@ -186,6 +186,8 @@ class Activity extends Base_Object { * @see https://www.w3.org/TR/activitypub/#object-without-create * * @param array|string|Base_Object|Activity|Actor|null $data Activity object. + * + * @return void */ public function set_object( $data ) { $object = $data; @@ -205,6 +207,8 @@ public function set_object( $data ) { /** * Fills the Activity with the specified activity object. + * + * @return void */ public function pre_fill_activity_from_object() { $object = $this->get_object(); diff --git a/includes/activity/class-base-object.php b/includes/activity/class-base-object.php index c0850e555e..bf7c9ee653 100644 --- a/includes/activity/class-base-object.php +++ b/includes/activity/class-base-object.php @@ -670,7 +670,7 @@ public function get( $key ) { * Generic setter. * * @param string $key The key to set. - * @param string $value The value to set. + * @param mixed $value The value to set. * * @return mixed The value. */ diff --git a/includes/activity/class-generic-object.php b/includes/activity/class-generic-object.php index 96e20ebc6e..bb6372b47f 100644 --- a/includes/activity/class-generic-object.php +++ b/includes/activity/class-generic-object.php @@ -106,7 +106,7 @@ public function get( $key ) { * Generic setter. * * @param string $key The key to set. - * @param string $value The value to set. + * @param mixed $value The value to set. * * @return mixed The value. */ @@ -200,6 +200,8 @@ public static function init_from_array( $data ) { * Convert JSON input to an array and pre-fill the object. * * @param array $data The array. + * + * @return void */ public function from_array( $data ) { foreach ( $data as $key => $value ) { @@ -218,6 +220,8 @@ public function from_array( $data ) { * Convert JSON input to an array and pre-fill the object. * * @param string $json The JSON string. + * + * @return void */ public function from_json( $json ) { $array = \json_decode( $json, true ); diff --git a/includes/activity/extended-object/class-place.php b/includes/activity/extended-object/class-place.php index 3b72706eb8..87cbbd0a89 100644 --- a/includes/activity/extended-object/class-place.php +++ b/includes/activity/extended-object/class-place.php @@ -104,6 +104,8 @@ class Place extends Base_Object { * Set the address of the place. * * @param array|string $address The address of the place. + * + * @return void */ public function set_address( $address ) { if ( \is_string( $address ) || \is_array( $address ) ) { diff --git a/includes/cache/class-avatar.php b/includes/cache/class-avatar.php index 1dbce36858..5da8eb2bc6 100644 --- a/includes/cache/class-avatar.php +++ b/includes/cache/class-avatar.php @@ -71,6 +71,8 @@ public static function get_max_dimension() { /** * Initialize the cache handler. + * + * @return void */ public static function init() { if ( ! self::is_enabled() ) { @@ -93,6 +95,8 @@ public static function init() { * Invalidates cached files so the avatar is re-downloaded on next access. * * @param int $post_id The actor post ID. + * + * @return void */ public static function clear_cached_avatar( $post_id ) { // Invalidate cached files so next access re-downloads. @@ -129,6 +133,8 @@ public static function maybe_cache( $url, $context, $entity_id = null, $options * Maybe clean up cached avatar when actor is deleted. * * @param int $post_id The post ID being deleted. + * + * @return void */ public static function maybe_cleanup( $post_id ) { if ( Remote_Actors::POST_TYPE !== \get_post_type( $post_id ) ) { diff --git a/includes/cache/class-emoji.php b/includes/cache/class-emoji.php index bf76c331cc..4dc9e4cc5a 100644 --- a/includes/cache/class-emoji.php +++ b/includes/cache/class-emoji.php @@ -80,6 +80,8 @@ public static function get_max_dimension() { /** * Initialize the cache handler. + * + * @return void */ public static function init() { if ( ! self::is_enabled() ) { diff --git a/includes/cache/class-file.php b/includes/cache/class-file.php index ca0fbb866b..71e8f7758a 100644 --- a/includes/cache/class-file.php +++ b/includes/cache/class-file.php @@ -81,6 +81,8 @@ abstract public static function get_max_dimension(); * Initialize the cache handler. * * Subclasses should override this to register filters and actions. + * + * @return void */ public static function init() { // Subclasses implement specific initialization. diff --git a/includes/cache/class-media.php b/includes/cache/class-media.php index e314f98cde..e2bc0df811 100644 --- a/includes/cache/class-media.php +++ b/includes/cache/class-media.php @@ -129,6 +129,8 @@ public static function get_storage_paths_for_context( $entity_id, $context = sel /** * Initialize the cache handler. + * + * @return void */ public static function init() { // Only register local caching filter when caching is enabled. @@ -167,6 +169,8 @@ public static function maybe_cache( $url, $context, $entity_id = null, $options * Maybe clean up cached media when post is deleted. * * @param int $post_id The post ID being deleted. + * + * @return void */ public static function maybe_cleanup( $post_id ) { if ( Remote_Posts::POST_TYPE !== \get_post_type( $post_id ) ) { diff --git a/includes/cache/class-stats-image.php b/includes/cache/class-stats-image.php index 631aa3b1b8..5d6228cce1 100644 --- a/includes/cache/class-stats-image.php +++ b/includes/cache/class-stats-image.php @@ -406,6 +406,8 @@ private static function render( $summary, $actor_webfinger, $site_name, $year ) * @param int|float $size Font size in points (TTF) or 1-5 (built-in). * @param int $color The text color. * @param string|false $font Path to TTF file, or false for built-in. + * + * @return void */ private static function draw_text( $image, $text, $x, $y, $size, $color, $font = false ) { if ( $font && \function_exists( 'imagefttext' ) ) { diff --git a/includes/class-activitypub.php b/includes/class-activitypub.php index 2252ee8cbc..067e3ecc91 100644 --- a/includes/class-activitypub.php +++ b/includes/class-activitypub.php @@ -20,6 +20,8 @@ class Activitypub { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_action( 'init', array( self::class, 'theme_compat' ), 11 ); @@ -38,6 +40,8 @@ public static function init() { * Activation Hook. * * @param bool $network_wide Whether to activate the plugin for all sites in the network or just the current site. + * + * @return void */ public static function activate( $network_wide ) { self::flush_rewrite_rules(); @@ -60,6 +64,8 @@ public static function activate( $network_wide ) { * Deactivation Hook. * * @param bool $network_wide Whether to deactivate the plugin for all sites in the network or just the current site. + * + * @return void */ public static function deactivate( $network_wide ) { self::flush_rewrite_rules(); @@ -80,6 +86,8 @@ public static function deactivate( $network_wide ) { /** * Uninstall Hook. + * + * @return void */ public static function uninstall() { Scheduler::deregister_schedules(); @@ -97,7 +105,9 @@ public static function uninstall() { /** * Store permalink in meta, to send delete Activity. * - * @param string $post_id The Post ID. + * @param int $post_id The Post ID. + * + * @return void */ public static function trash_post( $post_id ) { \add_post_meta( @@ -111,7 +121,9 @@ public static function trash_post( $post_id ) { /** * Delete permalink from meta. * - * @param string $post_id The Post ID. + * @param int $post_id The Post ID. + * + * @return void */ public static function untrash_post( $post_id ) { \delete_post_meta( $post_id, '_activitypub_canonical_url' ); @@ -119,6 +131,8 @@ public static function untrash_post( $post_id ) { /** * Flush rewrite rules. + * + * @return void */ public static function flush_rewrite_rules() { Router::add_rewrite_rules(); @@ -129,6 +143,8 @@ public static function flush_rewrite_rules() { * Add rewrite rules. * * @deprecated 7.5.0 Use {@see Router::add_rewrite_rules()}. + * + * @return void */ public static function add_rewrite_rules() { \_deprecated_function( __FUNCTION__, '7.5.0', '\Activitypub\Router::add_rewrite_rules()' ); @@ -138,6 +154,8 @@ public static function add_rewrite_rules() { /** * Theme compatibility stuff. + * + * @return void */ public static function theme_compat() { // We assume that you want to use Post-Formats when enabling the setting. @@ -162,6 +180,8 @@ public static function theme_compat() { * Add the 'activitypub' capability to users who can publish posts. * * @param int $user_id User ID. + * + * @return void */ public static function user_register( $user_id ) { if ( \user_can( $user_id, 'publish_posts' ) ) { @@ -172,6 +192,8 @@ public static function user_register( $user_id ) { /** * Register user meta. + * + * @return void */ public static function register_user_meta() { $blog_prefix = $GLOBALS['wpdb']->get_blog_prefix(); diff --git a/includes/class-application.php b/includes/class-application.php index 240d3a9cd1..9e7952822e 100644 --- a/includes/class-application.php +++ b/includes/class-application.php @@ -39,6 +39,8 @@ class Application { * Initialize the class, registering WordPress hooks. * * @since 9.1.0 + * + * @return void */ public static function init() { /* diff --git a/includes/class-attachments.php b/includes/class-attachments.php index 9923aa3ab2..a0d619e1b2 100644 --- a/includes/class-attachments.php +++ b/includes/class-attachments.php @@ -469,6 +469,8 @@ private static function optimize_image( $file_path, $max_dimension ) { * * @param int $post_id The post ID. * @param int[] $attachment_ids Array of attachment IDs. + * + * @return void */ private static function append_media_to_post_content( $post_id, $attachment_ids ) { $post = \get_post( $post_id ); @@ -622,6 +624,8 @@ private static function get_object_content( $object_id, $object_type ) { * @param int $object_id The object ID (post or comment). * @param string $object_type The object type ('post' or 'comment'). * @param string $content The new content. + * + * @return void */ private static function update_object_content( $object_id, $object_type, $content ) { if ( 'comment' === $object_type ) { @@ -650,6 +654,8 @@ private static function update_object_content( $object_id, $object_type, $conten * @param int $object_id The object ID (post or comment). * @param array $files Array of file data arrays with 'url', 'mime_type', and 'alt' keys. * @param string $object_type The object type ('post' or 'comment'). + * + * @return void */ public static function append_files_to_content( $object_id, $files, $object_type = 'post' ) { $content = self::get_object_content( $object_id, $object_type ); diff --git a/includes/class-autoloader.php b/includes/class-autoloader.php index 232a83232a..7bbdc0df56 100644 --- a/includes/class-autoloader.php +++ b/includes/class-autoloader.php @@ -60,6 +60,8 @@ public function __construct( $prefix, $path ) { * * @param string $prefix Namespace prefix all classes have in common. * @param string $path Path to the files to be loaded. + * + * @return void */ public static function register_path( $prefix, $path ) { $loader = new self( $prefix, $path ); @@ -70,6 +72,8 @@ public static function register_path( $prefix, $path ) { * Loads a class if its namespace starts with `$this->prefix`. * * @param string $class_name The class to be loaded. + * + * @return void */ public function load( $class_name ) { if ( \strpos( $class_name, $this->prefix . self::NS_SEPARATOR ) !== 0 ) { diff --git a/includes/class-avatars.php b/includes/class-avatars.php index b755bf9417..3febe964f9 100644 --- a/includes/class-avatars.php +++ b/includes/class-avatars.php @@ -15,6 +15,8 @@ class Avatars { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'pre_get_avatar_data', array( self::class, 'pre_get_avatar_data' ), 11, 2 ); diff --git a/includes/class-blocklist-subscriptions.php b/includes/class-blocklist-subscriptions.php index 0b93da0256..88449c9132 100644 --- a/includes/class-blocklist-subscriptions.php +++ b/includes/class-blocklist-subscriptions.php @@ -141,6 +141,8 @@ public static function sync( $url ) { * Sync all subscriptions. * * Called by cron job. + * + * @return void */ public static function sync_all() { \array_map( array( __CLASS__, 'sync' ), \array_keys( self::get_all() ) ); diff --git a/includes/class-blocks.php b/includes/class-blocks.php index 2409d4dde7..bb2e448da7 100644 --- a/includes/class-blocks.php +++ b/includes/class-blocks.php @@ -66,6 +66,8 @@ class Blocks { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { // This is already being called on the init hook, so just add it. @@ -90,6 +92,8 @@ public static function init() { /** * Enqueue the block editor assets. + * + * @return void */ public static function enqueue_editor_assets() { $data = array( @@ -129,6 +133,8 @@ public static function enqueue_editor_assets() { /** * Enqueue the reply handle script if the in_reply_to GET param is set. + * + * @return void */ public static function handle_in_reply_to_get_param() { self::enqueue_intent_script( 'in_reply_to', 'reply-intent' ); @@ -144,6 +150,8 @@ public static function handle_in_reply_to_get_param() { * * @param string $param The URL parameter carrying the address. * @param string $script The build folder and script handle suffix. + * + * @return void */ private static function enqueue_intent_script( $param, $script ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only, the script only prefills a block. @@ -160,6 +168,8 @@ private static function enqueue_intent_script( $param, $script ) { * Enqueue the quote intent script if the quotation_of GET param is set. * * @since unreleased + * + * @return void */ public static function handle_quotation_of_get_param() { self::enqueue_intent_script( 'quotation_of', 'quote-intent' ); @@ -167,6 +177,8 @@ public static function handle_quotation_of_get_param() { /** * Register the blocks. + * + * @return void */ public static function register_blocks() { \register_block_type_from_metadata( ACTIVITYPUB_PLUGIN_DIR . '/build/extra-fields' ); @@ -245,6 +257,8 @@ public static function register_blocks() { /** * Register block patterns for ActivityPub. + * + * @return void */ public static function register_patterns() { // Register the ActivityPub pattern category. @@ -276,6 +290,8 @@ public static function register_patterns() { /** * Register FSE templates for block themes. + * + * @return void */ public static function register_templates() { // Only register templates for block themes on WP 6.7+. @@ -320,6 +336,8 @@ public static function register_templates() { /** * Register REST fields needed for blocks. + * + * @return void */ public static function register_rest_fields() { // Register the post_count field for Follow Me block. @@ -887,6 +905,8 @@ public static function render_quote_block( $attrs, $content = '', $block = null * (e.g. 'context.modal.title'). When set, uses data-wp-text * on the title element and enables dynamic compact toggling. * } + * + * @return void */ public static function render_modal( $args = array() ) { $defaults = array( @@ -950,6 +970,8 @@ class="activitypub-modal__close wp-element-button" * interactions to users unfamiliar with the Fediverse. * * @since 8.0.0 + * + * @return void */ public static function render_modal_help() { ?> @@ -969,6 +991,8 @@ public static function render_modal_help() { * Renders an actor list component that can be used by different blocks. * * @param array $args Arguments for the actor list. + * + * @return void */ public static function render_actor_list( $args = array() ) { $defaults = array( @@ -1090,9 +1114,9 @@ static function ( $paragraph ) { /** * Add Interactivity directions to the specified element. * - * @param string $content The block content. - * @param string[] $selector The selector for the element to add directions to. - * @param string[] $attributes The attributes to add to the element. + * @param string $content The block content. + * @param array{tag_name?: string, class_name?: string} $selector The tag processor query for the element to add directions to. + * @param string[] $attributes The attributes to add to the element. * * @return string The updated content. */ @@ -1117,6 +1141,8 @@ public static function add_directions( $content, $selector, $attributes ) { * Add post transformation callbacks. * * @param object $post The post object. + * + * @return void */ public static function add_post_transformation_callbacks( $post ) { \add_filter( 'render_block_core/embed', array( self::class, 'revert_embed_links' ), 10, 2 ); @@ -1458,6 +1484,8 @@ private static function to_block( $tag, $html ) { * @since 8.1.0 * * @param WP_Query $query The WP_Query instance. + * + * @return void */ public static function filter_query_loop_vars( $query ) { // Never touch admin or feed queries. diff --git a/includes/class-cache.php b/includes/class-cache.php index 6de72a4322..e588649523 100644 --- a/includes/class-cache.php +++ b/includes/class-cache.php @@ -26,6 +26,8 @@ class Cache { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { if ( ! self::is_enabled() ) { @@ -73,6 +75,8 @@ public static function is_enabled() { /** * Register all cache handlers. + * + * @return void */ public static function register_caches() { Avatar::init(); diff --git a/includes/class-cli.php b/includes/class-cli.php index 6affa94521..c3270a8535 100644 --- a/includes/class-cli.php +++ b/includes/class-cli.php @@ -47,6 +47,8 @@ class Cli { * - wp activitypub stats * - wp activitypub fetch * - wp activitypub blurhash backfill [--dry-run] [--limit=] [--force] + * + * @return void */ public static function register() { // Register parent command with version subcommand. diff --git a/includes/class-comment.php b/includes/class-comment.php index 4716d2fc16..c3942632bf 100644 --- a/includes/class-comment.php +++ b/includes/class-comment.php @@ -19,6 +19,8 @@ class Comment { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { self::register_comment_types(); @@ -283,7 +285,7 @@ public static function should_be_federated( $comment ) { } $comment = \get_comment( $comment ); - $user_id = $comment->user_id; + $user_id = (int) $comment->user_id; // Comments without user can't be federated. if ( ! $user_id ) { @@ -363,7 +365,7 @@ public static function object_id_to_comment( $id, $args = array() ) { * * @param string $url The URL to check. * - * @return string|null Comment ID or null if not found. + * @return int|null Comment ID or null if not found. */ public static function url_to_commentid( $url ) { if ( ! $url || ! \filter_var( $url, \FILTER_VALIDATE_URL ) ) { @@ -381,7 +383,7 @@ public static function url_to_commentid( $url ) { $comment = \get_comment( $params['c'] ); if ( $comment ) { - return $comment->comment_ID; + return (int) $comment->comment_ID; } } } @@ -406,7 +408,7 @@ public static function url_to_commentid( $url ) { $comments = $query->query( $args ); if ( $comments && \is_array( $comments ) ) { - return $comments[0]->comment_ID; + return (int) $comments[0]->comment_ID; } return null; @@ -534,7 +536,7 @@ public static function generate_id( $comment ) { $comment = \get_comment( $comment ); // Show external comment ID if it exists. - $public_comment_link = self::get_source_id( $comment->comment_ID ); + $public_comment_link = self::get_source_id( (int) $comment->comment_ID ); if ( $public_comment_link ) { return $public_comment_link; @@ -697,6 +699,8 @@ public static function get_comment_type_attr( $type, $attr ) { /** * Register the comment types used by the ActivityPub plugin. + * + * @return void */ public static function register_comment_types() { register_comment_type( @@ -779,6 +783,8 @@ public static function get_avatar_comment_types( $types ) { * @see https://github.com/janboddez/indieblocks/blob/a2d59de358031056a649ee47a1332ce9e39d4ce2/includes/functions.php#L423-L432 * * @param \WP_Comment_Query $query Comment count. + * + * @return void */ public static function comment_query( $query ) { if ( ! $query instanceof \WP_Comment_Query ) { @@ -981,6 +987,8 @@ public static function pre_comment_approved( $approved, $comment_data ) { * * @param mixed $old_value The old option value. * @param mixed $value The new option value. + * + * @return void */ public static function maybe_update_comment_counts( $old_value, $value ) { if ( '1' === $old_value && '1' !== $value ) { diff --git a/includes/class-dispatcher.php b/includes/class-dispatcher.php index 33ea3c4d47..a5f76a8190 100644 --- a/includes/class-dispatcher.php +++ b/includes/class-dispatcher.php @@ -30,6 +30,8 @@ class Dispatcher { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_action( 'activitypub_process_outbox', array( self::class, 'process_outbox' ) ); @@ -112,6 +114,8 @@ public static function get_retry_error_codes() { * Process the outbox. * * @param int $id The outbox ID. + * + * @return void */ public static function process_outbox( $id ) { $outbox_item = \get_post( $id ); @@ -141,7 +145,7 @@ public static function process_outbox( $id ) { } // Send to mentioned and replied-to users. Everyone other than followers. - self::send_to_additional_inboxes( $activity, $outbox_item->post_author, $outbox_item ); + self::send_to_additional_inboxes( $activity, (int) $outbox_item->post_author, $outbox_item ); if ( self::should_send_to_followers( $activity, $actor, $outbox_item ) ) { \do_action( @@ -188,7 +192,7 @@ public static function send_to_followers( $outbox_item_id, $batch_size = ACTIVIT } $json = $activity->to_json(); - $inboxes = Followers::get_inboxes_for_activity( $json, $outbox_item->post_author, $batch_size, $offset ); + $inboxes = Followers::get_inboxes_for_activity( $json, (int) $outbox_item->post_author, $batch_size, $offset ); $retries = self::send_to_inboxes( $inboxes, $outbox_item_id ); // Retry failed inboxes. @@ -238,6 +242,8 @@ public static function send_to_followers( $outbox_item_id, $batch_size = ACTIVIT * @param string $transient_key The key to retrieve retry inboxes. * @param int $outbox_item_id The Outbox item ID. * @param int $attempt The attempt number. + * + * @return void */ public static function retry_send_to_followers( $transient_key, $outbox_item_id, $attempt = 1 ) { $inboxes = \get_transient( $transient_key ); @@ -294,7 +300,7 @@ private static function send_to_inboxes( $inboxes, $outbox_item_id ) { if ( is_same_domain( $inbox ) ) { $result = self::send_to_local_inbox( $inbox, $json ); } else { - $result = safe_remote_post( $inbox, $json, $outbox_item->post_author ); + $result = safe_remote_post( $inbox, $json, (int) $outbox_item->post_author ); } if ( \is_wp_error( $result ) && \in_array( $result->get_error_code(), self::get_retry_error_codes(), true ) ) { @@ -357,6 +363,8 @@ private static function send_to_local_inbox( $inbox_url, $json ) { * @param array $retries The inboxes to retry. * @param int $outbox_item_id The Outbox item ID. * @param int $attempt Optional. The attempt number. Default 1. + * + * @return void */ private static function schedule_retry( $retries, $outbox_item_id, $attempt = 1 ) { $transient_key = 'activitypub_retry_' . \wp_generate_password( 12, false ); @@ -377,6 +385,8 @@ private static function schedule_retry( $retries, $outbox_item_id, $attempt = 1 * @param Activity $activity The ActivityPub Activity. * @param int $actor_id The actor ID. * @param \WP_Post $outbox_item The WordPress object. + * + * @return void */ private static function send_to_additional_inboxes( $activity, $actor_id, $outbox_item = null ) { /** @@ -502,7 +512,7 @@ protected static function should_send_to_followers( $activity, $actor, $outbox_i ); if ( $send ) { - $followers = Followers::get_inboxes_for_activity( $activity->to_json(), $outbox_item->post_author ); + $followers = Followers::get_inboxes_for_activity( $activity->to_json(), (int) $outbox_item->post_author ); // Only send if there are followers to send to. $send = ! \is_countable( $followers ) || 0 < \count( $followers ); @@ -551,6 +561,8 @@ public static function add_inboxes_of_relays( $inboxes, $actor_id, $activity ) { * * @param int $outbox_id The Outbox item ID. * @param Activity $activity The Activity that was just added to the Outbox. + * + * @return void */ public static function fire_outbox_handlers( $outbox_id, $activity ) { $outbox_item = \get_post( $outbox_id ); @@ -581,6 +593,8 @@ public static function fire_outbox_handlers( $outbox_id, $activity ) { * * @param int $outbox_id The Outbox item ID. * @param Activity $activity The Activity that was just added to the Outbox. + * + * @return void */ public static function send_immediate_accept( $outbox_id, $activity ) { $outbox_item = \get_post( $outbox_id ); @@ -590,6 +604,6 @@ public static function send_immediate_accept( $outbox_id, $activity ) { } // Send to mentioned and replied-to users. Everyone other than followers. - self::send_to_additional_inboxes( $activity, $outbox_item->post_author, $outbox_item ); + self::send_to_additional_inboxes( $activity, (int) $outbox_item->post_author, $outbox_item ); } } diff --git a/includes/class-embed.php b/includes/class-embed.php index a832638682..7f009a7781 100644 --- a/includes/class-embed.php +++ b/includes/class-embed.php @@ -14,6 +14,8 @@ class Embed { /** * Initialize the embed handler. + * + * @return void */ public static function init() { \add_filter( 'pre_oembed_result', array( self::class, 'maybe_use_activitypub_embed' ), 10, 3 ); diff --git a/includes/class-event-stream.php b/includes/class-event-stream.php index c01898264d..a85aaae1fd 100644 --- a/includes/class-event-stream.php +++ b/includes/class-event-stream.php @@ -26,6 +26,8 @@ class Event_Stream { * Initialize the event stream signals. * * Registered on `init`, so the setting is read once the site context is settled. + * + * @return void */ public static function init() { if ( ! \get_option( 'activitypub_api', false ) ) { @@ -42,6 +44,8 @@ public static function init() { * @param int $outbox_activity_id The outbox post ID. * @param \Activitypub\Activity\Activity $activity The activity object. * @param int $user_id The user ID. + * + * @return void */ public static function signal_outbox( $outbox_activity_id, $activity, $user_id ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable $signal_key = \sprintf( 'activitypub_sse_signal_%s_outbox', $user_id ); @@ -53,6 +57,8 @@ public static function signal_outbox( $outbox_activity_id, $activity, $user_id ) * * @param array $data The activity data array. * @param array $user_ids The user IDs that received the activity. + * + * @return void */ public static function signal_inbox( $data, $user_ids ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable if ( ! \is_array( $user_ids ) ) { diff --git a/includes/class-handler.php b/includes/class-handler.php index f5d81b59d6..a8a1a2886f 100644 --- a/includes/class-handler.php +++ b/includes/class-handler.php @@ -13,6 +13,8 @@ class Handler { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { self::register_handlers(); @@ -21,6 +23,8 @@ public static function init() { /** * Register handlers. + * + * @return void */ public static function register_handlers() { Handler\Accept::init(); @@ -47,6 +51,8 @@ public static function register_handlers() { /** * Register outbox handlers. + * + * @return void */ public static function register_outbox_handlers() { Handler\Outbox\Add::init(); diff --git a/includes/class-hashtag.php b/includes/class-hashtag.php index 908a3da960..9115dc8c58 100644 --- a/includes/class-hashtag.php +++ b/includes/class-hashtag.php @@ -15,6 +15,8 @@ class Hashtag { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { if ( '1' === \get_option( 'activitypub_use_hashtags', '0' ) ) { @@ -48,6 +50,8 @@ public static function filter_activity_object( $activity ) { * * @param int $post_id Post ID. * @param \WP_Post $post Post object. + * + * @return void */ public static function insert_post( $post_id, $post ) { // Check if the post supports ActivityPub. diff --git a/includes/class-http.php b/includes/class-http.php index 82da2c9df2..26b45cc1a6 100644 --- a/includes/class-http.php +++ b/includes/class-http.php @@ -289,7 +289,7 @@ public static function generate_cache_key( $url ) { * caller having to re-check the origin itself. * * @param array|string $url_or_object The Object or the Object URL. - * @param bool $cached Optional. Whether the result should be cached. Default true. + * @param bool|int $cached Optional. Whether the result should be cached, or the cache duration in seconds. Default true. * * @return array|\WP_Error The Object data as array or WP_Error on failure. */ @@ -372,10 +372,10 @@ public static function get_remote_object( $url_or_object, $cached = true ) { /** * Fetch and JSON-decode a single remote document. * - * @param string $url The URL to fetch. Must already be resolved (not a WebFinger acct). - * @param bool $cached Whether the result may be served from and written to cache. - * @param string $final_url Filled by reference with the URL the document was served from, - * after following any redirects. + * @param string $url The URL to fetch. Must already be resolved (not a WebFinger acct). + * @param bool|int $cached Whether the result may be served from and written to cache, or the cache duration in seconds. + * @param string $final_url Filled by reference with the URL the document was served from, + * after following any redirects. * * @return array|\WP_Error The decoded document, or WP_Error on failure. */ diff --git a/includes/class-icons.php b/includes/class-icons.php index 11716ccf97..0127d99185 100644 --- a/includes/class-icons.php +++ b/includes/class-icons.php @@ -18,6 +18,8 @@ class Icons { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { // The Icons API was introduced in WordPress 7.1. @@ -32,6 +34,8 @@ public static function init() { * Register the icon collection and icons. * * @since 9.3.0 + * + * @return void */ public static function register_icons() { \wp_register_icon_collection( diff --git a/includes/class-link.php b/includes/class-link.php index e2d02a7001..1bf7da83f2 100644 --- a/includes/class-link.php +++ b/includes/class-link.php @@ -14,6 +14,8 @@ class Link { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'activitypub_extra_field_content', array( self::class, 'the_content' ) ); diff --git a/includes/class-mailer.php b/includes/class-mailer.php index a2d7816ee5..c428c27469 100644 --- a/includes/class-mailer.php +++ b/includes/class-mailer.php @@ -16,6 +16,8 @@ class Mailer { /** * Initialize the Mailer. + * + * @return void */ public static function init() { \add_filter( 'comment_notification_subject', array( self::class, 'comment_notification_subject' ), 10, 2 ); @@ -127,7 +129,7 @@ public static function comment_notification_text( $message, $comment_id ) { // For quotes, link to the quoting post itself so the author can review and respond. if ( 'quote' === $comment->comment_type ) { - $quote_url = Comment::get_source_url( $comment->comment_ID ); + $quote_url = Comment::get_source_url( (int) $comment->comment_ID ); if ( $quote_url ) { /* translators: Quoting post URL. */ @@ -138,7 +140,7 @@ public static function comment_notification_text( $message, $comment_id ) { $notify_message .= "\r\n"; /* translators: Comment type label */ $notify_message .= \sprintf( \esc_html__( 'You can see all %s on this post here:', 'activitypub' ), \esc_html( $comment_type['label'] ) ) . "\r\n"; - $notify_message .= \get_permalink( $comment->comment_post_ID ) . '#' . \esc_attr( $comment_type['type'] ) . "\r\n\r\n"; + $notify_message .= \get_permalink( (int) $comment->comment_post_ID ) . '#' . \esc_attr( $comment_type['type'] ) . "\r\n\r\n"; return $notify_message; } @@ -149,6 +151,8 @@ public static function comment_notification_text( $message, $comment_id ) { * @param array $activity The activity object. * @param int|int[] $user_ids The id(s) of the local blog-user(s). * @param bool $success True on success, false otherwise. + * + * @return void */ public static function new_follower( $activity, $user_ids, $success ) { // Only send notification if the follow was successful. @@ -245,6 +249,8 @@ public static function new_follower( $activity, $user_ids, $success ) { * * @param array $activity The activity object. * @param int|int[] $user_ids The id(s) of the local blog-user(s). + * + * @return void */ public static function direct_message( $activity, $user_ids ) { // Early return if activity is public or has no recipients. @@ -342,6 +348,8 @@ public static function direct_message( $activity, $user_ids ) { * * @param array $activity The activity object. * @param int|int[] $user_ids The id(s) of the local blog-user(s). + * + * @return void */ public static function mention( $activity, $user_ids ) { // Early return if activity has no mentions. @@ -589,6 +597,6 @@ public static function maybe_prevent_reaction_notification( $maybe_notify, $comm return $maybe_notify; } - return (bool) \get_user_option( 'activitypub_mailer_new_reaction', $post->post_author ); + return (bool) \get_user_option( 'activitypub_mailer_new_reaction', (int) $post->post_author ); } } diff --git a/includes/class-mention.php b/includes/class-mention.php index 35004c1870..70c6e23955 100644 --- a/includes/class-mention.php +++ b/includes/class-mention.php @@ -18,6 +18,8 @@ class Mention { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'the_content', array( self::class, 'the_content' ), 99 ); @@ -181,7 +183,7 @@ public static function extract_mention_links( $content ) { $links = array(); $processor = new \WP_HTML_Tag_Processor( $content ); - while ( $processor->next_tag( 'A' ) ) { + while ( $processor->next_tag( array( 'tag_name' => 'A' ) ) ) { $rel = (string) $processor->get_attribute( 'rel' ); if ( ! $processor->has_class( 'mention' ) && ! \in_array( 'mention', \preg_split( '/\s+/', $rel ), true ) ) { continue; diff --git a/includes/class-migration.php b/includes/class-migration.php index 4c33c9f31e..e249ea6160 100644 --- a/includes/class-migration.php +++ b/includes/class-migration.php @@ -28,6 +28,8 @@ class Migration { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { self::maybe_migrate(); @@ -72,6 +74,8 @@ public static function lock() { /** * Unlocks the database migration process. + * + * @return void */ public static function unlock() { \delete_option( 'activitypub_migration_lock' ); @@ -114,6 +118,8 @@ public static function is_latest_version() { /** * Updates the database structure if necessary. + * + * @return void */ public static function maybe_migrate() { if ( self::is_latest_version() ) { @@ -272,6 +278,8 @@ public static function maybe_migrate() { /** * Updates the custom template to use shortcodes instead of the deprecated templates. + * + * @return void */ private static function migrate_from_0_16() { // Get the custom template. @@ -309,6 +317,8 @@ private static function migrate_from_0_16() { /** * Updates the DB-schema of the followers-list. + * + * @return void */ public static function migrate_from_0_17() { // Migrate followers. @@ -325,6 +335,8 @@ public static function migrate_from_0_17() { /** * Clear the cache after updating to 1.3.0. + * + * @return void */ private static function migrate_from_1_2_0() { $user_ids = \get_users( @@ -341,6 +353,8 @@ private static function migrate_from_1_2_0() { /** * Unschedule Hooks after updating to 2.0.0. + * + * @return void */ private static function migrate_from_2_0_0() { \wp_clear_scheduled_hook( 'activitypub_send_post_activity' ); @@ -360,6 +374,8 @@ private static function migrate_from_2_0_0() { /** * Add the ActivityPub capability to all users that can publish posts * Delete old meta to store followers. + * + * @return void */ private static function migrate_from_2_2_0() { // Add the ActivityPub capability to all users that can publish posts. @@ -368,6 +384,8 @@ private static function migrate_from_2_2_0() { /** * Rename DB fields. + * + * @return void */ private static function migrate_from_2_6_0() { \wp_cache_flush(); @@ -381,6 +399,8 @@ private static function migrate_from_2_6_0() { /** * * Update actor-mode settings. * * Get the ID of the latest blog post and save it to the options table. + * + * @return void */ private static function migrate_to_4_0_0() { $latest_post_id = 0; @@ -429,6 +449,8 @@ private static function migrate_to_4_0_0() { * Update to 4.1.0 * * * Migrate the `activitypub_post_content_type` to only use `activitypub_custom_post_content`. + * + * @return void */ public static function migrate_to_4_1_0() { $content_type = \get_option( 'activitypub_post_content_type' ); @@ -471,6 +493,8 @@ public static function migrate_to_4_1_0() { /** * Updates post meta keys to be prefixed with an underscore. + * + * @return void */ public static function migrate_to_4_7_1() { global $wpdb; @@ -491,6 +515,8 @@ public static function migrate_to_4_7_1() { /** * Clears the post cache for Followers, we should have done this in 4.7.1 when we renamed those keys. + * + * @return void */ public static function migrate_to_4_7_2() { global $wpdb; @@ -569,11 +595,11 @@ public static function create_post_outbox_items( $batch_size = 50, $offset = 0 ) foreach ( $posts as $post ) { $visibility = \get_post_meta( $post->ID, 'activitypub_content_visibility', true ); - self::add_to_outbox( $post, 'Create', $post->post_author, $visibility ); + self::add_to_outbox( $post, 'Create', (int) $post->post_author, $visibility ); // Add Update activity when the post has been modified. if ( $post->post_modified !== $post->post_date ) { - self::add_to_outbox( $post, 'Update', $post->post_author, $visibility ); + self::add_to_outbox( $post, 'Update', (int) $post->post_author, $visibility ); } } @@ -611,7 +637,7 @@ public static function create_comment_outbox_items( $batch_size = 50, $offset = ); foreach ( $comments as $comment ) { - self::add_to_outbox( $comment, 'Create', $comment->user_id ); + self::add_to_outbox( $comment, 'Create', (int) $comment->user_id ); } if ( \count( $comments ) === $batch_size ) { @@ -724,6 +750,8 @@ public static function update_comment_author_emails( $batch_size = 50, $offset = * Set the defaults needed for the plugin to work. * * Add the ActivityPub capability to all users that can publish posts. + * + * @return void */ public static function add_default_settings() { self::add_activitypub_capability(); @@ -736,6 +764,8 @@ public static function add_default_settings() { * @param string $activity_type The type of activity. * @param int $user_id The user ID. * @param string $visibility Optional. The visibility of the content. Default 'public'. + * + * @return void */ private static function add_to_outbox( $comment, $activity_type, $user_id, $visibility = ACTIVITYPUB_CONTENT_VISIBILITY_PUBLIC ) { $transformer = Factory::get_transformer( $comment ); @@ -765,6 +795,8 @@ private static function add_to_outbox( $comment, $activity_type, $user_id, $visi /** * Add the ActivityPub capability to all users that can publish posts. + * + * @return void */ private static function add_activitypub_capability() { // Get all WP_User objects that can publish posts. @@ -785,6 +817,8 @@ private static function add_activitypub_capability() { * * @param string $old_key The old comment meta key. * @param string $new_key The new comment meta key. + * + * @return void */ private static function update_usermeta_key( $old_key, $new_key ) { global $wpdb; @@ -803,6 +837,8 @@ private static function update_usermeta_key( $old_key, $new_key ) { * * @param string $old_key The old post meta key. * @param string $new_key The new post meta key. + * + * @return void */ private static function update_postmeta_key( $old_key, $new_key ) { global $wpdb; @@ -821,6 +857,8 @@ private static function update_postmeta_key( $old_key, $new_key ) { * * @param string $old_key The old option key. * @param string $new_key The new option key. + * + * @return void */ private static function update_options_key( $old_key, $new_key ) { global $wpdb; @@ -836,6 +874,8 @@ private static function update_options_key( $old_key, $new_key ) { /** * Migrate the actor mode settings. + * + * @return void */ public static function migrate_actor_mode() { $blog_profile = \get_option( 'activitypub_enable_blog_user', '0' ); @@ -868,6 +908,8 @@ public static function migrate_actor_mode() { * for non-existent users. The result is a number of user extra fields with no author. * * @ticket https://github.com/Automattic/wordpress-activitypub/pull/1554 + * + * @return void */ public static function delete_mastodon_api_orphaned_extra_fields() { global $wpdb; @@ -884,6 +926,8 @@ public static function delete_mastodon_api_orphaned_extra_fields() { /** * Update notification options. + * + * @return void */ public static function update_notification_options() { $new_dm = \get_option( 'activitypub_mailer_new_dm', '1' ); @@ -915,6 +959,8 @@ public static function update_notification_options() { /** * Migrate followers to the new CPT. + * + * @return void */ public static function migrate_followers_to_ap_actor_cpt() { global $wpdb; @@ -997,6 +1043,8 @@ public static function update_actor_json_storage( $batch_size = 100 ) { /** * Removes pending follow requests for the application user. + * + * @return void */ public static function remove_pending_application_user_follow_requests() { global $wpdb; @@ -1015,6 +1063,8 @@ public static function remove_pending_application_user_follow_requests() { * Sync Jetpack meta for all followings. * * Replays the added_post_meta sync action for Jetpack with the Following::FOLLOWING_META_KEY meta key. + * + * @return void */ public static function sync_jetpack_following_meta() { if ( ! \class_exists( 'Jetpack' ) || ! \Jetpack::is_connection_ready() ) { @@ -1051,6 +1101,8 @@ public static function sync_jetpack_following_meta() { * * Deletes all existing inbox items to prepare for the new shared inbox structure * where activities are stored once with multiple recipients as metadata. + * + * @return void */ private static function clean_up_inbox() { global $wpdb; @@ -1316,6 +1368,8 @@ public static function migrate_actor_emoji( $batch_size = 50, $offset = 0 ) { * activitypub_application_user_private_key) are migrated lazily on first read. * * @since 9.1.0 + * + * @return void */ public static function migrate_application_keypair_option() { self::update_options_key( 'activitypub_keypair_for_-1', Application::KEYPAIR_OPTION_KEY ); @@ -1343,6 +1397,8 @@ public static function migrate_application_keypair_option() { * harmless, the second pass finds nothing. * * @since unreleased + * + * @return void */ public static function remove_duplicate_cache_files() { $upload_dir = \wp_upload_dir(); @@ -1360,6 +1416,8 @@ public static function remove_duplicate_cache_files() { * undeliverable and are removed. * * @since 9.1.0 + * + * @return void */ public static function delete_application_outbox_items() { $items = \get_posts( diff --git a/includes/class-moderation.php b/includes/class-moderation.php index aa92279ba9..14811dd56d 100644 --- a/includes/class-moderation.php +++ b/includes/class-moderation.php @@ -203,9 +203,9 @@ public static function add_user_block( $user_id, $type, $value ) { /** * Remove a block for a user. * - * @param int $user_id The user ID. - * @param string $type The block type (actor, domain, keyword). - * @param string $value The value to unblock. + * @param int $user_id The user ID. + * @param string $type The block type (actor, domain, keyword). + * @param string|int $value The value to unblock. * @return bool True on success, false on failure. */ public static function remove_user_block( $user_id, $type, $value ) { @@ -294,6 +294,8 @@ public static function add_site_block( $type, $value ) { * * @param string $type The block type (domain or keyword only). * @param array $values Array of values to block. + * + * @return void */ public static function add_site_blocks( $type, $values ) { if ( ! \in_array( $type, array( self::TYPE_DOMAIN, self::TYPE_KEYWORD ), true ) ) { diff --git a/includes/class-move.php b/includes/class-move.php index a6a9606c2c..7a0058f469 100644 --- a/includes/class-move.php +++ b/includes/class-move.php @@ -25,6 +25,8 @@ class Move { /** * Initialize the Move class. + * + * @return void */ public static function init() { /** @@ -218,6 +220,8 @@ public static function internally( $from, $to ) { * * @param int $user_id The user ID. * @param string $from The current account URL. + * + * @return void */ private static function update_user_also_known_as( $user_id, $from ) { $also_known_as = \get_user_option( 'activitypub_also_known_as', $user_id ) ?: array(); @@ -235,6 +239,8 @@ private static function update_user_also_known_as( $user_id, $from ) { * Update the alsoKnownAs property of the blog. * * @param string $from The current account URL. + * + * @return void */ private static function update_blog_also_known_as( $from ) { $also_known_as = \get_option( 'activitypub_blog_user_also_known_as', array() ); @@ -319,6 +325,8 @@ public static function change_domain( $from, $to ) { * If it does, it retrieves the cached data for the user and populates the instance. * * @param Blog|User $instance The Blog or User instance to populate. + * + * @return void */ public static function maybe_initiate_old_user( $instance ) { if ( ! Query::get_instance()->is_old_host_request() ) { @@ -340,6 +348,8 @@ public static function maybe_initiate_old_user( $instance ) { * Pre-send to inboxes. * * @param string $json The ActivityPub Activity JSON. + * + * @return void */ public static function pre_send_to_inboxes( $json ) { $json = \json_decode( $json, true ); diff --git a/includes/class-notification.php b/includes/class-notification.php index 9b22d4bc41..cf2ea3e27e 100644 --- a/includes/class-notification.php +++ b/includes/class-notification.php @@ -60,6 +60,8 @@ public function __construct( $type, $actor, $activity, $target ) { /** * Send the notification. + * + * @return void */ public function send() { $type = \strtolower( $this->type ); diff --git a/includes/class-options.php b/includes/class-options.php index 1a95e7baab..c0a187a684 100644 --- a/includes/class-options.php +++ b/includes/class-options.php @@ -16,6 +16,8 @@ class Options { /** * Initialize the options. + * + * @return void */ public static function init() { \add_action( 'admin_init', array( self::class, 'register_settings' ) ); @@ -48,6 +50,8 @@ public static function init() { /** * Register ActivityPub settings. + * + * @return void */ public static function register_settings() { /* @@ -570,6 +574,8 @@ public static function register_settings() { /** * Delete all options. + * + * @return void */ public static function delete() { global $wpdb; @@ -1039,6 +1045,8 @@ public static function sanitize_purge_days( $value ) { * * @param mixed $old_value The old option value. * @param mixed $new_value The new option value. + * + * @return void */ public static function relay_mode_changed( $old_value, $new_value ) { if ( $new_value && ! $old_value ) { diff --git a/includes/class-post-types.php b/includes/class-post-types.php index 1712765302..66a59b9e6d 100644 --- a/includes/class-post-types.php +++ b/includes/class-post-types.php @@ -28,6 +28,8 @@ class Post_Types { /** * Initialize the class, registering all custom post types and post meta. + * + * @return void */ public static function init() { \add_action( 'init', array( self::class, 'register_remote_actors_post_type' ), 11 ); @@ -62,6 +64,8 @@ public static function init() { /** * Register the Remote Actors post type and its meta. + * + * @return void */ public static function register_remote_actors_post_type() { \register_post_type( @@ -120,6 +124,8 @@ public static function register_remote_actors_post_type() { /** * Register the Inbox post type and its meta. + * + * @return void */ public static function register_inbox_post_type() { \register_post_type( @@ -229,6 +235,8 @@ public static function register_inbox_post_type() { /** * Register the Outbox post type and its meta. + * + * @return void */ public static function register_outbox_post_type() { \register_post_type( @@ -355,6 +363,8 @@ public static function register_outbox_post_type() { /** * Register the Post post type. + * + * @return void */ public static function register_post_post_type() { \register_post_type( @@ -428,6 +438,8 @@ public static function register_post_post_type() { /** * Register the Extra Fields post types. + * + * @return void */ public static function register_extra_fields_post_types() { $extra_field_args = array( @@ -477,6 +489,8 @@ public static function register_extra_fields_post_types() { * * Registers post type for OAuth clients. * Note: Tokens are stored in user meta and authorization codes in transients. + * + * @return void */ public static function register_oauth_post_types() { // OAuth Clients post type. @@ -580,6 +594,8 @@ public static function register_oauth_post_types() { * The post type is fully internal — never queried publicly, never shown in UI. * * @since 8.3.0 + * + * @return void */ public static function register_tombstone_post_type() { \register_post_type( @@ -609,6 +625,8 @@ public static function register_tombstone_post_type() { /** * Register post meta for ActivityPub supported post types. + * + * @return void */ public static function register_activitypub_post_meta() { $ap_post_types = \get_post_types_by_support( 'activitypub' ); @@ -720,6 +738,8 @@ public static function register_activitypub_post_meta() { /** * Register REST field for ap_actor posts. + * + * @return void */ public static function register_ap_actor_rest_field() { \register_rest_field( @@ -830,6 +850,8 @@ public static function filter_ap_actor_query_by_follower( $args, $request ) { /** * Register a REST field for the ap_post post type to embed remote actor data. + * + * @return void */ public static function register_ap_post_actor_rest_field() { \register_rest_field( @@ -870,6 +892,8 @@ public static function register_ap_post_actor_rest_field() { /** * Register custom REST API parameters for ap_post endpoint. + * + * @return void */ public static function register_ap_post_rest_params() { \add_filter( @@ -1091,6 +1115,8 @@ private static function filter_terms_by_user( $args, $request, $taxonomy ) { * @param int $object_id ID of the object metadata is for. * @param string $meta_key Metadata key. * @param mixed $meta_value Metadata value. Must be serializable if non-scalar. + * + * @return null|bool Whether to allow updating metadata for the given type. */ public static function prevent_empty_post_meta( $check, $object_id, $meta_key, $meta_value ) { $post_metas = array( diff --git a/includes/class-query.php b/includes/class-query.php index 09998e7e42..6b54e97538 100644 --- a/includes/class-query.php +++ b/includes/class-query.php @@ -410,6 +410,8 @@ public function is_old_host_request() { * Fake an old host request. * * @param bool $state Optional. The state to set. Default true. + * + * @return void */ public function set_old_host_request( $state = true ) { $this->is_old_host_request = $state; @@ -442,7 +444,7 @@ private function maybe_get_stamp() { return false; } - $user_uri = get_user_id( $post->post_author ); + $user_uri = get_user_id( (int) $post->post_author ); if ( ! $user_uri ) { return false; diff --git a/includes/class-relay.php b/includes/class-relay.php index 1ccdf58d4a..67aa84ff5a 100644 --- a/includes/class-relay.php +++ b/includes/class-relay.php @@ -23,6 +23,8 @@ class Relay { * Initialize the class, registering WordPress hooks. * * Registered on `init`, so the setting is read once the site context is settled. + * + * @return void */ public static function init() { if ( ! \get_option( 'activitypub_relay_mode', false ) ) { @@ -42,6 +44,8 @@ public static function init() { * @param array $activity The activity data. * @param array $user_ids The user IDs that are recipients. * @param bool $success Whether the activity was handled successfully. + * + * @return void */ public static function handle_activity( $activity, $user_ids, $success ) { // Only relay if: successfully handled, Blog actor is recipient, activity is public, and in single-user mode. @@ -69,6 +73,8 @@ public static function handle_activity( $activity, $user_ids, $success ) { * Unhook settings fields when relay mode is enabled. * * Removes all settings sections except moderation when relay mode is active. + * + * @return void */ public static function unhook_settings_fields() { global $wp_settings_sections; diff --git a/includes/class-router.php b/includes/class-router.php index 2b211a8050..9d2464833e 100644 --- a/includes/class-router.php +++ b/includes/class-router.php @@ -16,6 +16,8 @@ class Router { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_action( 'init', array( self::class, 'add_rewrite_rules' ), 11 ); @@ -32,6 +34,8 @@ public static function init() { /** * Add rewrite rules. + * + * @return void */ public static function add_rewrite_rules() { /* @@ -242,6 +246,8 @@ public static function render_activitypub_template( $template ) { /** * Add the 'self' link to the header. + * + * @return void */ public static function add_headers() { $id = Query::get_instance()->get_activitypub_object_id(); @@ -450,6 +456,8 @@ public static function add_query_vars( $vars ) { * since we only need to return the blog actor, not posts. * * @param \WP_Query $wp_query The WP_Query instance. + * + * @return void */ public static function fix_is_home_check( $wp_query ) { if ( diff --git a/includes/class-sanitize.php b/includes/class-sanitize.php index acf79b9cb6..82c020637c 100644 --- a/includes/class-sanitize.php +++ b/includes/class-sanitize.php @@ -179,7 +179,14 @@ public static function blog_identifier( $value ) { $parts = \array_map( 'sanitize_title', $parts ); // A segment can sanitize away to nothing, and a leading, trailing or doubled dot is not a usable handle. - $sanitized = \implode( '.', \array_filter( $parts, 'strlen' ) ); + $parts = \array_filter( + $parts, + static function ( $part ) { + return '' !== $part; + } + ); + + $sanitized = \implode( '.', $parts ); if ( empty( $sanitized ) ) { return Blog::get_default_username(); diff --git a/includes/class-scheduler.php b/includes/class-scheduler.php index 38285ad8c8..a088c438fd 100644 --- a/includes/class-scheduler.php +++ b/includes/class-scheduler.php @@ -74,6 +74,8 @@ public static function get_retry_delay( $hook = null ) { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { self::register_schedulers(); @@ -105,6 +107,8 @@ public static function init() { /** * Register handlers. + * + * @return void */ public static function register_schedulers() { Post::init(); @@ -148,6 +152,8 @@ public static function add_cron_schedules( $schedules ) { * * @param string $hook The cron event hook name. * @param callable $callback The callback to execute. + * + * @return void */ public static function register_async_batch_callback( $hook, $callback ) { if ( \did_action( 'init' ) && ! \doing_action( 'init' ) ) { @@ -167,6 +173,8 @@ public static function register_async_batch_callback( $hook, $callback ) { /** * Schedule all ActivityPub schedules. + * + * @return void */ public static function register_schedules() { foreach ( self::SCHEDULES as $hook => $recurrence ) { @@ -240,6 +248,8 @@ private static function get_next_december_first() { * Unschedule events for an outbox item. * * @param int $outbox_item_id The outbox item ID. + * + * @return void */ public static function unschedule_events_for_item( $outbox_item_id ) { \delete_post_meta( $outbox_item_id, '_activitypub_outbox_offset' ); @@ -265,6 +275,8 @@ public static function unschedule_events_for_item( $outbox_item_id ) { /** * Update remote Actors. + * + * @return void */ public static function update_remote_actors() { $number = 5; @@ -336,6 +348,8 @@ public static function update_remote_actors() { /** * Cleanup remote Actors. + * + * @return void */ public static function cleanup_remote_actors() { $number = 5; @@ -381,6 +395,8 @@ public static function cleanup_remote_actors() { * * @param int $id The ID of the outbox item. * @param int $offset The offset to add to the scheduled time. Default 3 seconds. + * + * @return void */ public static function schedule_outbox_activity_for_federation( $id, $offset = 3 ) { $hook = 'activitypub_process_outbox'; @@ -397,6 +413,8 @@ public static function schedule_outbox_activity_for_federation( $id, $offset = 3 /** * Reprocess the outbox. + * + * @return void */ public static function reprocess_outbox() { $ids = \get_posts( @@ -427,6 +445,8 @@ public static function reprocess_outbox() { /** * Purge outbox items based on a schedule. + * + * @return void */ public static function purge_outbox() { Outbox::purge( \get_option( 'activitypub_outbox_purge_days', ACTIVITYPUB_OUTBOX_PURGE_DAYS ) ); @@ -434,6 +454,8 @@ public static function purge_outbox() { /** * Purge inbox items based on a schedule. + * + * @return void */ public static function purge_inbox() { Inbox::purge( \get_option( 'activitypub_inbox_purge_days', ACTIVITYPUB_INBOX_PURGE_DAYS ) ); @@ -441,6 +463,8 @@ public static function purge_inbox() { /** * Purge remote posts based on a schedule. + * + * @return void */ public static function purge_ap_posts() { Remote_Posts::purge( \get_option( 'activitypub_ap_post_purge_days', ACTIVITYPUB_AP_POST_PURGE_DAYS ) ); @@ -453,6 +477,8 @@ public static function purge_ap_posts() { * drain across multiple daily runs. * * @since 8.3.0 + * + * @return void */ public static function purge_tombstones() { Tombstone::purge(); @@ -464,6 +490,8 @@ public static function purge_tombstones() { * Retrieves all collected user IDs for an activity and processes them together. * * @param string $activity_id The activity ID. + * + * @return void */ public static function process_inbox_activity( $activity_id ) { // Deduplicate if multiple inbox items were created due to race condition. @@ -510,6 +538,8 @@ public static function process_inbox_activity( $activity_id ) { * * @param int $old_value The old value. * @param int $value The new value. + * + * @return void */ public static function update_outbox_purge_schedule( $old_value, $value ) { if ( 0 === (int) $value ) { @@ -524,6 +554,8 @@ public static function update_outbox_purge_schedule( $old_value, $value ) { * * @param int $old_value The old value. * @param int $value The new value. + * + * @return void */ public static function update_inbox_purge_schedule( $old_value, $value ) { if ( 0 === (int) $value ) { @@ -538,6 +570,8 @@ public static function update_inbox_purge_schedule( $old_value, $value ) { * * @param int $old_value The old value. * @param int $value The new value. + * + * @return void */ public static function update_ap_post_purge_schedule( $old_value, $value ) { if ( 0 === (int) $value ) { @@ -554,6 +588,8 @@ public static function update_ap_post_purge_schedule( $old_value, $value ) { * Beyond that it's a helper to run a callback asynchronously with locking to prevent simultaneous processing. * * @params mixed ...$args Optional. Parameters that get passed to the callback. + * + * @return void */ public static function async_batch() { $args = \func_get_args(); // phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue @@ -602,6 +638,8 @@ private static function has_scheduled_outbox_delivery_batch( $outbox_item_id, $o * Unschedule all pending delivery batches for an outbox item. * * @param int $outbox_item_id The outbox item ID. + * + * @return void */ private static function unschedule_outbox_delivery_batches( $outbox_item_id ) { foreach ( self::get_scheduled_outbox_delivery_batches( $outbox_item_id ) as $event ) { @@ -672,6 +710,8 @@ public static function lock( $key ) { * Unlocks processing for the async batch callback. * * @param string $key Serialized callback name. + * + * @return void */ public static function unlock( $key ) { \delete_option( 'activitypub_async_batch_' . $key ); @@ -707,6 +747,8 @@ public static function is_locked( $key ) { * @param Activity $activity The activity object. * @param int $actor_id The actor ID. * @param int $content_visibility The content visibility. + * + * @return void */ public static function schedule_announce_activity( $outbox_activity_id, $activity, $actor_id, $content_visibility ) { // Only if we're in both Blog and User modes. diff --git a/includes/class-search.php b/includes/class-search.php index 313f4ce074..3846562ae2 100644 --- a/includes/class-search.php +++ b/includes/class-search.php @@ -19,6 +19,8 @@ class Search { /** * Initialize the search enhancement. + * + * @return void */ public static function init() { \add_filter( 'pre_get_posts', array( self::class, 'enhance_public_search' ) ); @@ -73,6 +75,8 @@ public static function enhance_public_search( $query ) { /** * Handle admin comment search to check for URLs and ActivityPub objects. * Runs on admin_init to avoid infinite loops. + * + * @return void */ public static function enhance_admin_comment_search() { // Check user capabilities. diff --git a/includes/class-shortcodes.php b/includes/class-shortcodes.php index edda9281a1..96ca400d03 100644 --- a/includes/class-shortcodes.php +++ b/includes/class-shortcodes.php @@ -13,6 +13,8 @@ class Shortcodes { /** * Register the shortcodes. + * + * @return void */ public static function register() { foreach ( \get_class_methods( self::class ) as $shortcode ) { @@ -24,6 +26,8 @@ public static function register() { /** * Unregister the shortcodes. + * + * @return void */ public static function unregister() { foreach ( \get_class_methods( self::class ) as $shortcode ) { @@ -331,7 +335,7 @@ public static function author() { return ''; } - $author_id = \get_post_field( 'post_author', $item->ID ); + $author_id = (int) \get_post_field( 'post_author', $item->ID ); $name = \get_the_author_meta( 'display_name', $author_id ); if ( ! $name ) { @@ -353,7 +357,7 @@ public static function authorurl() { return ''; } - $author_id = \get_post_field( 'post_author', $item->ID ); + $author_id = (int) \get_post_field( 'post_author', $item->ID ); $url = \get_the_author_meta( 'user_url', $author_id ); if ( ! $url ) { diff --git a/includes/class-signature.php b/includes/class-signature.php index 92ad7cb041..0d9b58e377 100644 --- a/includes/class-signature.php +++ b/includes/class-signature.php @@ -20,6 +20,8 @@ class Signature { /** * Initialize the class. + * + * @return void */ public static function init() { \add_filter( 'http_request_args', array( self::class, 'sign_request' ), 0, 2 ); // Ahead of all other filters, so signature is set. @@ -319,6 +321,8 @@ private static function could_support_rfc9421( $url ) { * Set RFC-9421 signature unsupported for a given host. * * @param string $url The URL to set. + * + * @return void */ private static function rfc9421_add_unsupported_host( $url ) { $list = \get_option( 'activitypub_rfc9421_unsupported', array() ); diff --git a/includes/class-tombstone.php b/includes/class-tombstone.php index e287790356..f31223582e 100644 --- a/includes/class-tombstone.php +++ b/includes/class-tombstone.php @@ -258,6 +258,8 @@ private static function find_post_ids_by_url( $normalized ) { * normalized URL. * * @param string ...$urls The URLs to add to the tombstone registry. + * + * @return void */ public static function bury( ...$urls ) { foreach ( $urls as $url ) { @@ -313,6 +315,8 @@ public static function bury( ...$urls ) { * This marks the URLs as no longer tombstoned for future local checks. * * @param string ...$urls The URLs to remove from the tombstone registry. + * + * @return void */ public static function remove( ...$urls ) { $normalized_urls = array(); diff --git a/includes/cli/class-actor-command.php b/includes/cli/class-actor-command.php index 1c8cdae04f..86a7ffd2fe 100644 --- a/includes/cli/class-actor-command.php +++ b/includes/cli/class-actor-command.php @@ -37,6 +37,8 @@ class Actor_Command extends \WP_CLI_Command { * * @param array $args The positional arguments. * @param array $assoc_args The associative arguments (unused). + * + * @return void */ public function delete( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable // Only the blog actor (0) and real users (positive IDs) can be deleted; negative IDs (e.g. the former -1 application ID) are never valid actors. @@ -70,6 +72,8 @@ public function delete( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis. * * @param array $args The positional arguments. * @param array $assoc_args The associative arguments (unused). + * + * @return void */ public function update( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable Actor::schedule_profile_update( $args[0] ); diff --git a/includes/cli/class-blurhash-command.php b/includes/cli/class-blurhash-command.php index 09ff4bf041..cd1706c18a 100644 --- a/includes/cli/class-blurhash-command.php +++ b/includes/cli/class-blurhash-command.php @@ -88,6 +88,8 @@ class Blurhash_Command extends \WP_CLI_Command { * @param array $assoc_args Associative CLI flags. * * @when after_wp_load + * + * @return void */ public function backfill( $args, $assoc_args ) { unset( $args ); diff --git a/includes/cli/class-cache-command.php b/includes/cli/class-cache-command.php index b81f99ecb8..8f054bfc95 100644 --- a/includes/cli/class-cache-command.php +++ b/includes/cli/class-cache-command.php @@ -57,6 +57,8 @@ class Cache_Command extends \WP_CLI_Command { * * @param array $args The positional arguments. * @param array $assoc_args The associative arguments. + * + * @return void */ public function clear( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable $type = $assoc_args['type'] ?? 'all'; @@ -113,6 +115,8 @@ public function clear( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis.C * * @param array $args The positional arguments. * @param array $assoc_args The associative arguments. + * + * @return void */ public function status( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable $upload_dir = \wp_upload_dir(); @@ -209,6 +213,8 @@ public function status( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis. * * @param array $args The positional arguments. * @param array $assoc_args The associative arguments. + * + * @return void */ public function cleanup( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable $type = $assoc_args['type'] ?? 'all'; diff --git a/includes/cli/class-command.php b/includes/cli/class-command.php index d27bf46969..2c11f2c9b3 100644 --- a/includes/cli/class-command.php +++ b/includes/cli/class-command.php @@ -26,6 +26,8 @@ class Command extends \WP_CLI_Command { * * @param array $args The positional arguments (unused). * @param array $assoc_args The associative arguments (unused). + * + * @return void */ public function version( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable \WP_CLI::line( 'ActivityPub ' . ACTIVITYPUB_PLUGIN_VERSION ); diff --git a/includes/cli/class-comment-command.php b/includes/cli/class-comment-command.php index 8f8a7f0ad0..9fb42a3585 100644 --- a/includes/cli/class-comment-command.php +++ b/includes/cli/class-comment-command.php @@ -40,6 +40,8 @@ class Comment_Command extends \WP_CLI_Command { * * @param array $args The positional arguments. * @param array $assoc_args The associative arguments. + * + * @return void */ public function delete( $args, $assoc_args ) { $comment = \get_comment( $args[0] ); @@ -53,7 +55,7 @@ public function delete( $args, $assoc_args ) { } \WP_CLI::confirm( 'Do you really want to delete the Comment with the ID: ' . $args[0], $assoc_args ); - add_to_outbox( $comment, 'Delete', $comment->user_id ); + add_to_outbox( $comment, 'Delete', (int) $comment->user_id ); \WP_CLI::success( '"Delete" activity is queued.' ); } @@ -77,6 +79,8 @@ public function delete( $args, $assoc_args ) { * * @param array $args The positional arguments. * @param array $assoc_args The associative arguments (unused). + * + * @return void */ public function update( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable $comment = \get_comment( $args[0] ); @@ -89,7 +93,7 @@ public function update( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis. \WP_CLI::error( 'This comment was received via ActivityPub and cannot be deleted or updated.' ); } - $result = add_to_outbox( $comment, 'Update', $comment->user_id ); + $result = add_to_outbox( $comment, 'Update', (int) $comment->user_id ); if ( \is_wp_error( $result ) ) { \WP_CLI::error( $result->get_error_message() ); diff --git a/includes/cli/class-fetch-command.php b/includes/cli/class-fetch-command.php index 8125c4bb29..63da049a88 100644 --- a/includes/cli/class-fetch-command.php +++ b/includes/cli/class-fetch-command.php @@ -75,6 +75,8 @@ class Fetch_Command extends \WP_CLI_Command { * * @param array $args The positional arguments. * @param array $assoc_args The associative arguments. + * + * @return void */ public function __invoke( $args, $assoc_args ) { $url = $args[0]; diff --git a/includes/cli/class-follow-command.php b/includes/cli/class-follow-command.php index fdf95f72b3..89f87f3a12 100644 --- a/includes/cli/class-follow-command.php +++ b/includes/cli/class-follow-command.php @@ -37,6 +37,8 @@ class Follow_Command extends \WP_CLI_Command { * * @param array $args The positional arguments. * @param array $assoc_args The associative arguments (unused). + * + * @return void */ public function __invoke( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable $user_id = \get_current_user_id(); diff --git a/includes/cli/class-move-command.php b/includes/cli/class-move-command.php index 40e8259f90..0cc4de1e85 100644 --- a/includes/cli/class-move-command.php +++ b/includes/cli/class-move-command.php @@ -38,6 +38,8 @@ class Move_Command extends \WP_CLI_Command { * * @param array $args The positional arguments. * @param array $assoc_args The associative arguments (unused). + * + * @return void */ public function __invoke( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable $from = $args[0]; diff --git a/includes/cli/class-outbox-command.php b/includes/cli/class-outbox-command.php index c9be9fd5c2..9d09054b82 100644 --- a/includes/cli/class-outbox-command.php +++ b/includes/cli/class-outbox-command.php @@ -39,6 +39,8 @@ class Outbox_Command extends \WP_CLI_Command { * * @param array $args The positional arguments. * @param array $assoc_args The associative arguments (unused). + * + * @return void */ public function undo( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable $outbox_item_id = $args[0]; @@ -81,6 +83,8 @@ public function undo( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis.Co * * @param array $args The positional arguments. * @param array $assoc_args The associative arguments (unused). + * + * @return void */ public function reschedule( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable $outbox_item_id = $args[0]; diff --git a/includes/cli/class-post-command.php b/includes/cli/class-post-command.php index 7909e3f5d8..b4116143f1 100644 --- a/includes/cli/class-post-command.php +++ b/includes/cli/class-post-command.php @@ -39,6 +39,8 @@ class Post_Command extends \WP_CLI_Command { * * @param array $args The positional arguments. * @param array $assoc_args The associative arguments. + * + * @return void */ public function delete( $args, $assoc_args ) { $post = \get_post( $args[0] ); @@ -48,7 +50,7 @@ public function delete( $args, $assoc_args ) { } \WP_CLI::confirm( 'Do you really want to delete the (Custom) Post with the ID: ' . $args[0], $assoc_args ); - add_to_outbox( $post, 'Delete', $post->post_author ); + add_to_outbox( $post, 'Delete', (int) $post->post_author ); \WP_CLI::success( '"Delete" activity is queued.' ); } @@ -72,6 +74,8 @@ public function delete( $args, $assoc_args ) { * * @param array $args The positional arguments. * @param array $assoc_args The associative arguments (unused). + * + * @return void */ public function update( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable $post = \get_post( $args[0] ); @@ -80,7 +84,7 @@ public function update( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis. \WP_CLI::error( 'Post not found.' ); } - $result = add_to_outbox( $post, 'Update', $post->post_author ); + $result = add_to_outbox( $post, 'Update', (int) $post->post_author ); if ( \is_wp_error( $result ) ) { \WP_CLI::error( $result->get_error_message() ); diff --git a/includes/cli/class-self-destruct-command.php b/includes/cli/class-self-destruct-command.php index be17c7b6cd..7149c6b420 100644 --- a/includes/cli/class-self-destruct-command.php +++ b/includes/cli/class-self-destruct-command.php @@ -65,6 +65,8 @@ class Self_Destruct_Command extends \WP_CLI_Command { * * @param array $args The positional arguments (unused). * @param array $assoc_args The associative arguments (--status, --yes). + * + * @return void */ public function __invoke( $args, $assoc_args = array() ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable // Check if --status flag is provided. @@ -93,6 +95,8 @@ public function __invoke( $args, $assoc_args = array() ) { // phpcs:ignore Varia * 5. Provides progress feedback and completion instructions * * @param array $assoc_args The associative arguments from WP-CLI. + * + * @return void */ private function execute_self_destruct( $assoc_args ) { $this->display_self_destruct_warning(); @@ -117,6 +121,8 @@ private function execute_self_destruct( $assoc_args ) { /** * Display the self-destruct warning message. + * + * @return void */ private function display_self_destruct_warning() { \WP_CLI::line( \WP_CLI::colorize( '%R⚠️ DESTRUCTIVE OPERATION ⚠️%n' ) ); @@ -213,6 +219,8 @@ private function create_delete_activity_for_user( $user_id, $processed, $user_co * Display the completion message after processing. * * @param int $processed Number of users successfully processed. + * + * @return void */ private function display_completion_message( $processed ) { if ( 0 === $processed ) { @@ -242,6 +250,8 @@ private function display_completion_message( $processed ) { * - NOT STARTED: Process hasn't been initiated * - IN PROGRESS: Delete activities are still being processed * - COMPLETED: All Delete activities have been sent + * + * @return void */ private function show_self_destruct_status() { // Only proceed if self-destruct is active. diff --git a/includes/cli/class-stats-command.php b/includes/cli/class-stats-command.php index 45e8a201ad..47300f5859 100644 --- a/includes/cli/class-stats-command.php +++ b/includes/cli/class-stats-command.php @@ -57,6 +57,8 @@ class Stats_Command extends \WP_CLI_Command { * * @param array $args The positional arguments (unused). * @param array $assoc_args The associative arguments. + * + * @return void */ public function collect( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable $user_id = isset( $assoc_args['user_id'] ) ? (int) $assoc_args['user_id'] : null; @@ -136,6 +138,8 @@ public function collect( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis * * @param array $args The positional arguments (unused). * @param array $assoc_args The associative arguments. + * + * @return void */ public function compile( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable $user_id = isset( $assoc_args['user_id'] ) ? (int) $assoc_args['user_id'] : null; @@ -186,6 +190,8 @@ public function compile( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis * * @param array $args The positional arguments (unused). * @param array $assoc_args The associative arguments. + * + * @return void */ public function send( $args, $assoc_args ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable $user_id = isset( $assoc_args['user_id'] ) ? (int) $assoc_args['user_id'] : null; diff --git a/includes/collection/class-actors.php b/includes/collection/class-actors.php index 8de28e0256..5ac3eafc63 100644 --- a/includes/collection/class-actors.php +++ b/includes/collection/class-actors.php @@ -47,7 +47,7 @@ class Actors { * * @param int $user_id The user ID. * - * @return Actor|User|Blog|Application|\WP_Error Actor object or WP_Error if not found or not permitted. + * @return User|Blog|\WP_Error Actor object or WP_Error if not found or not permitted. */ public static function get_by_id( $user_id ) { if ( \is_numeric( $user_id ) ) { diff --git a/includes/collection/class-extra-fields.php b/includes/collection/class-extra-fields.php index 42632831d2..76b8e818ec 100644 --- a/includes/collection/class-extra-fields.php +++ b/includes/collection/class-extra-fields.php @@ -126,7 +126,7 @@ public static function fields_to_attachments( $fields ) { \class_exists( '\WP_HTML_Tag_Processor' ) ) { $tags = new \WP_HTML_Tag_Processor( $link_content ); - $tags->next_tag( 'A' ); + $tags->next_tag( array( 'tag_name' => 'A' ) ); if ( 'A' === $tags->get_tag() ) { $attachment = array( diff --git a/includes/collection/class-followers.php b/includes/collection/class-followers.php index 93c331af3a..bd28b7a538 100644 --- a/includes/collection/class-followers.php +++ b/includes/collection/class-followers.php @@ -422,6 +422,8 @@ public static function follows( $post_id, $user_id ) { * @param string $value The blocked actor URI. * @param string $type The block type (actor, domain, keyword). * @param int $user_id The user ID. + * + * @return void */ public static function remove_blocked_actors( $value, $type, $user_id ) { if ( 'actor' !== $type ) { diff --git a/includes/collection/class-following.php b/includes/collection/class-following.php index dc0cd927d8..e306d5bd37 100644 --- a/includes/collection/class-following.php +++ b/includes/collection/class-following.php @@ -536,6 +536,8 @@ public static function get_follower_ids( $actor_url ) { * @param string $value The blocked actor URI or domain/keyword. * @param string $type The block type (actor, domain, keyword). * @param int $user_id The user ID. + * + * @return void */ public static function remove_blocked_actors( $value, $type, $user_id ) { if ( 'actor' !== $type ) { diff --git a/includes/collection/class-inbox.php b/includes/collection/class-inbox.php index 33df87db4a..d6a3f2e96c 100644 --- a/includes/collection/class-inbox.php +++ b/includes/collection/class-inbox.php @@ -397,6 +397,8 @@ public static function remove_recipient( $post_id, $user_id ) { * * @param int $post_id The inbox post ID. * @param int[] $user_ids The user ID or array of user IDs to add. + * + * @return void */ public static function add_recipients( $post_id, $user_ids ) { foreach ( $user_ids as $user_id ) { diff --git a/includes/collection/class-interactions.php b/includes/collection/class-interactions.php index 8a2455cdf7..47a77c3383 100644 --- a/includes/collection/class-interactions.php +++ b/includes/collection/class-interactions.php @@ -232,8 +232,8 @@ public static function add_reaction( $activity ) { * * @since unreleased * - * @param string $url The target URL. - * @param int $parent_comment_id Optional. The resolved parent comment ID. + * @param string $url The target URL. + * @param int|null $parent_comment_id Optional. The resolved parent comment ID. * * @return int The post ID, or 0 when the target is unknown. */ diff --git a/includes/collection/class-outbox.php b/includes/collection/class-outbox.php index 0237506a8c..233f53e72f 100644 --- a/includes/collection/class-outbox.php +++ b/includes/collection/class-outbox.php @@ -301,7 +301,7 @@ public static function undo( $outbox_item ) { $activity->set_published( null ); $activity->set_updated( null ); - return add_to_outbox( $activity, $type, $outbox_item->post_author, $visibility ); + return add_to_outbox( $activity, $type, (int) $outbox_item->post_author, $visibility ); } /** diff --git a/includes/collection/class-remote-actors.php b/includes/collection/class-remote-actors.php index b9c973a9f0..72e5dcd185 100644 --- a/includes/collection/class-remote-actors.php +++ b/includes/collection/class-remote-actors.php @@ -237,6 +237,8 @@ private static function get_follower_ids( $post_id ) { * @since unreleased * * @param int[] $user_ids The local users whose follower inbox lists include the actor. + * + * @return void */ private static function clear_inbox_caches( $user_ids ) { $keys = array( self::CACHE_KEY_INBOXES ); diff --git a/includes/collection/class-remote-posts.php b/includes/collection/class-remote-posts.php index 41e9d8a0ec..275fd539c9 100644 --- a/includes/collection/class-remote-posts.php +++ b/includes/collection/class-remote-posts.php @@ -365,6 +365,8 @@ private static function activity_to_post( $activity ) { * * @param int $post_id The post ID. * @param array $activity_object The activity object data. + * + * @return void */ private static function add_taxonomies( $post_id, $activity_object ) { // Save Object Type as Taxonomy item. @@ -550,6 +552,8 @@ public static function add_recipient( $post_id, $user_id ) { * * @param int $post_id The post ID. * @param int[] $user_ids The user ID or array of user IDs to add. + * + * @return void */ public static function add_recipients( $post_id, $user_ids ) { foreach ( $user_ids as $user_id ) { diff --git a/includes/collection/class-replies.php b/includes/collection/class-replies.php index fe5e6631b8..9392dc276b 100644 --- a/includes/collection/class-replies.php +++ b/includes/collection/class-replies.php @@ -25,6 +25,8 @@ class Replies { * Build base arguments for fetching the comments of either a WordPress post or comment. * * @param \WP_Post|\WP_Comment|\WP_Error $wp_object The post or comment to fetch replies for on success. + * + * @return array|\WP_Error The query arguments, or WP_Error when the object is neither a post nor a comment. */ private static function build_args( $wp_object ) { $args = array( @@ -169,7 +171,7 @@ public static function get_context_collection( $post_id ) { $post_uri = ( new Post_Transformer( $post ) )->to_id(); \array_unshift( $ids, $post_uri ); - $author = Actors::get_by_id( $post->post_author ); + $author = Actors::get_by_id( (int) $post->post_author ); if ( \is_wp_error( $author ) ) { if ( is_user_type_disabled( 'blog' ) ) { return false; @@ -206,7 +208,7 @@ private static function get_reply_ids( $comments, $include_blog_comments = false continue; } - $public_comment_id = Comment::get_source_id( $comment->comment_ID ); + $public_comment_id = Comment::get_source_id( (int) $comment->comment_ID ); if ( $public_comment_id ) { $comment_ids[] = $public_comment_id; continue; diff --git a/includes/functions-comment.php b/includes/functions-comment.php index 8cbad474d0..a69ade7464 100644 --- a/includes/functions-comment.php +++ b/includes/functions-comment.php @@ -40,7 +40,7 @@ function object_id_to_comment( $id, $args = array() ) { * * @param string $url The URL to check. * - * @return string|null Comment ID or null if not found + * @return int|null Comment ID or null if not found */ function url_to_commentid( $url ) { return Comment::url_to_commentid( $url ); diff --git a/includes/functions-federation.php b/includes/functions-federation.php index 3a27cd68ac..0e8ba76d6f 100644 --- a/includes/functions-federation.php +++ b/includes/functions-federation.php @@ -21,6 +21,8 @@ * * @param \WP_Comment|\WP_Post $wp_object The WordPress object. * @param string $state The state of the object. + * + * @return void */ function set_wp_object_state( $wp_object, $state ) { if ( $wp_object instanceof \WP_Post ) { @@ -155,6 +157,12 @@ function add_to_outbox( $data, $activity_type = null, $user_id = 0, $content_vis $activity = $transformer->to_activity( $activity_type ); $activity->set_actor( Actors::get_by_id( $user_id )->get_id() ); } else { + /** + * Without an Activity type, `$data` is already an Activity, and its transformer + * hands it back as one. + * + * @var Activity $activity + */ $activity = $transformer->to_object(); } diff --git a/includes/functions-media.php b/includes/functions-media.php index 4f8cb85154..8918e65d45 100644 --- a/includes/functions-media.php +++ b/includes/functions-media.php @@ -112,7 +112,7 @@ function process_remote_images( $content, $attachments = array() ) { $processor = new \WP_HTML_Tag_Processor( $content ); // Mark remote images for wrapping using a data attribute. - while ( $processor->next_tag( 'IMG' ) ) { + while ( $processor->next_tag( array( 'tag_name' => 'IMG' ) ) ) { $src = $processor->get_attribute( 'src' ); if ( $src && is_remote_url( $src ) && ! isset( $seen_urls[ $src ] ) ) { diff --git a/includes/functions-post.php b/includes/functions-post.php index c04e8c5fc6..9a4e6ea0f7 100644 --- a/includes/functions-post.php +++ b/includes/functions-post.php @@ -437,7 +437,7 @@ function get_post_id( $id ) { /** * Get the visibility of a post. * - * @param int $post_id The post ID. + * @param int|\WP_Post $post_id The post ID or object. * * @return string|false The visibility of the post or false if not found. */ diff --git a/includes/functions-request.php b/includes/functions-request.php index a697a34d31..ba82738b23 100644 --- a/includes/functions-request.php +++ b/includes/functions-request.php @@ -170,7 +170,9 @@ function accept_prefers_activitypub( $accept ) { * Cache-Control would not reach a page cache or CDN. WordPress core sends its own CORS `Vary: Origin` * the same raw way for the same reason. The raw header is skipped once the headers are already sent. * - * @param \WP_REST_Response $response The response to mark. + * @param \WP_HTTP_Response $response The response to mark. + * + * @return void */ function maybe_set_no_store( $response ) { $response->header( 'Cache-Control', 'private, no-store, max-age=0' ); diff --git a/includes/functions.php b/includes/functions.php index 5a5ac64c02..dd3aa11fd6 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -14,7 +14,7 @@ * * Returns the canonical ActivityPub URI for a WP_Post or WP_Comment. * - * @param \WP_Post|\WP_Comment $wp_object The WordPress post or comment. + * @param mixed $wp_object The WordPress post or comment; anything else yields null. * * @return string|null The ActivityPub ID (a URL), or null if unsupported type. */ diff --git a/includes/handler/class-accept.php b/includes/handler/class-accept.php index e49f339aa8..5ed93fb8e7 100644 --- a/includes/handler/class-accept.php +++ b/includes/handler/class-accept.php @@ -24,6 +24,8 @@ class Accept { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_action( 'activitypub_inbox_accept', array( self::class, 'handle_accept' ), 10, 2 ); @@ -35,6 +37,8 @@ public static function init() { * * @param array $accept The activity-object. * @param int|int[] $user_ids The id of the local blog-user. + * + * @return void */ public static function handle_accept( $accept, $user_ids ) { // Validate that there is a preceding Activity of ours. @@ -61,6 +65,8 @@ public static function handle_accept( $accept, $user_ids ) { * * @param array $accept The activity-object. * @param int[]|int $user_ids The local user IDs. + * + * @return void */ private static function accept_follow( $accept, $user_ids ) { /* @@ -102,6 +108,8 @@ private static function accept_follow( $accept, $user_ids ) { * @param array $accept The activity-object. * @param \WP_Post $outbox_post Our QuoteRequest outbox item. * @param int[]|int $user_ids The local user IDs. + * + * @return void */ private static function accept_quote_request( $accept, $outbox_post, $user_ids ) { $request = Outbox::get_activity( $outbox_post ); @@ -172,7 +180,7 @@ private static function accept_quote_request( $accept, $outbox_post, $user_ids ) \update_post_meta( $post->ID, '_activitypub_quote_authorization', $stamp_uri ); \delete_post_meta( $post->ID, '_activitypub_quote_rejected' ); - add_to_outbox( $post, 'Update', $post->post_author ); + add_to_outbox( $post, 'Update', (int) $post->post_author ); /** This action is documented in includes/handler/class-accept.php */ \do_action( 'activitypub_handled_accept', $accept, (array) $user_ids, true, $post ); diff --git a/includes/handler/class-announce.php b/includes/handler/class-announce.php index 78d9daee2c..9a5daf5a26 100644 --- a/includes/handler/class-announce.php +++ b/includes/handler/class-announce.php @@ -23,6 +23,8 @@ class Announce { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_action( 'activitypub_inbox_announce', array( self::class, 'handle_announce' ), 10, 3 ); @@ -34,6 +36,8 @@ public static function init() { * @param array $announcement The activity-object. * @param int|int[] $user_ids The id(s) of the local blog-user(s). * @param \Activitypub\Activity\Activity $activity The activity object. + * + * @return void */ public static function handle_announce( $announcement, $user_ids, $activity = null ) { // Check if Activity is public or not. @@ -138,6 +142,8 @@ public static function handle_announce( $announcement, $user_ids, $activity = nu * * @param array $activity The activity-object. * @param int|int[] $user_ids The id of the local blog-user. + * + * @return void */ public static function maybe_save_announce( $activity, $user_ids ) { $url = object_to_uri( $activity ); diff --git a/includes/handler/class-collection-sync.php b/includes/handler/class-collection-sync.php index 6782331cbe..51d522e1d1 100644 --- a/includes/handler/class-collection-sync.php +++ b/includes/handler/class-collection-sync.php @@ -23,6 +23,8 @@ class Collection_Sync { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_action( 'activitypub_inbox_create', array( self::class, 'handle_collection_synchronization' ), 10, 2 ); @@ -41,6 +43,8 @@ public static function init() { * * @param array $data The activity data. * @param int|int[] $user_ids The user ID(s). + * + * @return void */ public static function handle_collection_synchronization( $data, $user_ids ) { if ( empty( $_SERVER['HTTP_COLLECTION_SYNCHRONIZATION'] ) ) { diff --git a/includes/handler/class-create.php b/includes/handler/class-create.php index 7b6ce3ee1e..7d8aeef785 100644 --- a/includes/handler/class-create.php +++ b/includes/handler/class-create.php @@ -23,6 +23,8 @@ class Create { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_action( 'activitypub_handled_inbox_create', array( self::class, 'handle_create' ), 10, 3 ); @@ -36,6 +38,8 @@ public static function init() { * @param array $activity The activity-object. * @param int|int[] $user_ids The id(s) of the local blog-user(s). * @param \Activitypub\Activity\Activity $activity_object Optional. The activity object. Default null. + * + * @return void */ public static function handle_create( $activity, $user_ids, $activity_object = null ) { // Check for private and/or direct messages. @@ -162,6 +166,8 @@ public static function validate_object( $valid, $param, $request ) { * * @param int $outbox_id The ID of the outbox activity. * @param \Activitypub\Activity\Activity $activity The Activity object. + * + * @return void */ public static function maybe_unbury( $outbox_id, $activity ) { if ( ! \in_array( $activity->get_type(), array( 'Create', 'Update' ), true ) ) { diff --git a/includes/handler/class-delete.php b/includes/handler/class-delete.php index 53c5f77788..66dd4a1ef3 100644 --- a/includes/handler/class-delete.php +++ b/includes/handler/class-delete.php @@ -25,6 +25,8 @@ class Delete { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_action( 'activitypub_inbox_delete', array( self::class, 'handle_delete' ), 10, 4 ); @@ -45,6 +47,8 @@ public static function init() { * @param int|int[] $user_ids The local user ID(s). * @param \Activitypub\Activity\Activity|null $activity_object Optional. The activity object. Default null. * @param string|null $context Optional. The inbox context. Default null. + * + * @return void */ public static function handle_delete( $activity, $user_ids, $activity_object = null, $context = null ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable // The shared inbox invokes this once per resolved recipient and once on the shared hook; @@ -172,7 +176,7 @@ private static function revoke_quote_authorization( $activity, $user_ids ) { \delete_post_meta( $post->ID, '_activitypub_quote_authorization' ); - add_to_outbox( $post, 'Update', $post->post_author ); + add_to_outbox( $post, 'Update', (int) $post->post_author ); /** This action is documented in includes/handler/class-delete.php */ \do_action( 'activitypub_handled_delete', $activity, (array) $user_ids, true, $post ); @@ -185,6 +189,8 @@ private static function revoke_quote_authorization( $activity, $user_ids ) { * * @param array $activity The Activity object. * @param int|int[] $user_ids The user ID(s). + * + * @return void */ public static function delete_object( $activity, $user_ids ) { $result = self::maybe_delete_interaction( $activity ); @@ -211,6 +217,8 @@ public static function delete_object( $activity, $user_ids ) { * * @param array $activity The Activity object. * @param int|int[] $user_ids The user ID(s). + * + * @return bool True on success, false otherwise. */ public static function delete_remote_actor( $activity, $user_ids ) { $result = self::maybe_delete_follower( $activity ); @@ -253,6 +261,8 @@ public static function maybe_delete_follower( $activity ) { * Schedule Deletion of Interactions of a Remote Actor. * * @param int $id The remote actor ID. + * + * @return void */ public static function maybe_delete_interactions( $id ) { \wp_schedule_single_event( @@ -266,6 +276,8 @@ public static function maybe_delete_interactions( $id ) { * Schedule Deletion of Reader Items of a Remote Actor. * * @param int $id The remote actor ID. + * + * @return void */ public static function maybe_delete_posts( $id ) { \wp_schedule_single_event( @@ -444,6 +456,8 @@ public static function outbox_activity( $activity ) { * * @param int $outbox_id The ID of the outbox activity. * @param \Activitypub\Activity\Activity $activity The Activity object. + * + * @return void */ public static function maybe_bury( $outbox_id, $activity ) { if ( 'Delete' !== $activity->get_type() ) { diff --git a/includes/handler/class-feature-request.php b/includes/handler/class-feature-request.php index 19033066a0..85613209f8 100644 --- a/includes/handler/class-feature-request.php +++ b/includes/handler/class-feature-request.php @@ -38,6 +38,8 @@ class Feature_Request { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_action( 'activitypub_inbox_feature_request', array( self::class, 'handle_feature_request' ), 10, 2 ); @@ -51,6 +53,8 @@ public static function init() { * * @param array $activity The activity object. * @param int|int[] $user_ids The user ID(s) targeted by the inbox dispatch. + * + * @return void */ public static function handle_feature_request( $activity, $user_ids ) { $state = true; @@ -106,6 +110,8 @@ public static function handle_feature_request( $activity, $user_ids ) { * @param array $activity The activity array. * @param int|int[]|null $user_ids The user ID(s). * @param string $type The activity type. + * + * @return void */ public static function handle_blocked_request( $activity, $user_ids, $type ) { if ( ! \in_array( \strtolower( $type ), array( 'featurerequest', 'feature_request' ), true ) ) { @@ -124,6 +130,8 @@ public static function handle_blocked_request( $activity, $user_ids, $type ) { * * @param array $activity_object The activity object. * @param int $user_id The local user ID being featured (0 for the blog actor). + * + * @return void */ public static function queue_accept( $activity_object, $user_id ) { if ( ! user_can_activitypub( $user_id ) ) { @@ -286,6 +294,8 @@ public static function get_stamp( $user_id, $stamp_id ) { * * @param array $activity_object The activity object. * @param int $user_id The user ID. + * + * @return void */ public static function queue_reject( $activity_object, $user_id ) { if ( ! user_can_activitypub( $user_id ) ) { diff --git a/includes/handler/class-follow.php b/includes/handler/class-follow.php index 5e9f229619..228377fd50 100644 --- a/includes/handler/class-follow.php +++ b/includes/handler/class-follow.php @@ -23,6 +23,8 @@ class Follow { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_action( 'activitypub_inbox_follow', array( self::class, 'handle_follow' ), 10, 2 ); @@ -37,6 +39,8 @@ public static function init() { * * @param array $activity The activity object. * @param int|int[] $user_ids The user ID(s). + * + * @return void */ public static function handle_follow( $activity, $user_ids ) { // Extract the user ID (follow requests are always for a single user). @@ -91,6 +95,8 @@ public static function handle_follow( $activity, $user_ids ) { * @param int|int[] $user_ids The local user IDs. * @param bool $success True on success, false otherwise. * @param \WP_Post|\WP_Error $remote_actor The remote actor/follower, or WP_Error if failed. + * + * @return void */ public static function queue_accept( $activity_object, $user_ids, $success, $remote_actor ) { if ( \is_wp_error( $remote_actor ) ) { @@ -135,6 +141,8 @@ public static function queue_accept( $activity_object, $user_ids, $success, $rem * * @param array $activity The Follow activity data. * @param int[] $user_ids The local recipient IDs the inbox resolved. + * + * @return void */ public static function reject_application_follow( $activity, $user_ids ) { // A resolved recipient means the Follow targets a real actor, not the Application. diff --git a/includes/handler/class-like.php b/includes/handler/class-like.php index 4e02a6f4fe..5d86006a2b 100644 --- a/includes/handler/class-like.php +++ b/includes/handler/class-like.php @@ -18,6 +18,8 @@ class Like { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_action( 'activitypub_inbox_like', array( self::class, 'handle_like' ), 10, 2 ); @@ -29,6 +31,8 @@ public static function init() { * * @param array $like The Activity array. * @param int|int[] $user_ids The user ID(s). + * + * @return void */ public static function handle_like( $like, $user_ids ) { if ( ! Comment::is_comment_type_enabled( 'like' ) ) { diff --git a/includes/handler/class-move.php b/includes/handler/class-move.php index b2e311d233..dc60487818 100644 --- a/includes/handler/class-move.php +++ b/includes/handler/class-move.php @@ -23,6 +23,8 @@ class Move { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_action( 'activitypub_inbox_move', array( self::class, 'handle_move' ), 10, 2 ); @@ -33,6 +35,8 @@ public static function init() { * * @param array $activity The JSON "Move" Activity. * @param int|int[] $user_ids The user ID(s). + * + * @return void */ public static function handle_move( $activity, $user_ids ) { $target_uri = self::extract_target( $activity ); @@ -63,7 +67,7 @@ public static function handle_move( $activity, $user_ids ) { $wpdb->update( $wpdb->posts, array( 'guid' => \sanitize_url( $target_uri ) ), - array( 'ID' => \sanitize_key( $origin_object->ID ) ) + array( 'ID' => (int) $origin_object->ID ) ); // Clear the cache. diff --git a/includes/handler/class-quote-request.php b/includes/handler/class-quote-request.php index c717478fa2..1a7bd5ad0a 100644 --- a/includes/handler/class-quote-request.php +++ b/includes/handler/class-quote-request.php @@ -26,6 +26,8 @@ class Quote_Request { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_action( 'activitypub_inbox_quote_request', array( self::class, 'handle_quote_request' ), 10, 2 ); @@ -40,6 +42,8 @@ public static function init() { * * @param array $activity The activity object. * @param int|int[] $user_ids The user ID(s). + * + * @return void */ public static function handle_quote_request( $activity, $user_ids ) { $state = true; @@ -98,6 +102,8 @@ public static function handle_quote_request( $activity, $user_ids ) { * @param array $activity The activity array. * @param int|int[]|null $user_ids The user ID(s). * @param string $type The type of the activity. + * + * @return void */ public static function handle_blocked_request( $activity, $user_ids, $type ) { if ( ! \in_array( \strtolower( $type ), array( 'quoterequest', 'quote_request' ), true ) ) { @@ -118,6 +124,8 @@ public static function handle_blocked_request( $activity, $user_ids, $type ) { * * @param int $comment_id The comment ID being deleted. * @param \WP_Comment|null $comment The comment object, or null if not available. + * + * @return void */ public static function handle_quote_delete( $comment_id, $comment ) { // Try to get comment if not provided. @@ -131,7 +139,7 @@ public static function handle_quote_delete( $comment_id, $comment ) { } // Get the post being quoted. - $post_id = $comment->comment_post_ID; + $post_id = (int) $comment->comment_post_ID; if ( ! $post_id ) { return; } @@ -182,7 +190,7 @@ public static function handle_quote_delete( $comment_id, $comment ) { \delete_post_meta( $post_id, '_activitypub_quoted_by', $instrument_url ); // Send Reject activity to revoke the quote permission. - self::queue_reject( $activity_object, $post->post_author ); + self::queue_reject( $activity_object, (int) $post->post_author ); /** * Fires after a quote comment has been deleted and Reject activity sent. @@ -203,6 +211,8 @@ public static function handle_quote_delete( $comment_id, $comment ) { * @param array $activity_object The activity object. * @param int $user_id The user ID. * @param int $post_id The post ID. + * + * @return void */ public static function queue_accept( $activity_object, $user_id, $post_id ) { // Fall back to the blog actor if the user has ActivityPub disabled. @@ -272,6 +282,8 @@ public static function queue_accept( $activity_object, $user_id, $post_id ) { * * @param array $activity_object The activity object. * @param int $user_id The user ID. + * + * @return void */ public static function queue_reject( $activity_object, $user_id ) { // Fall back to the blog actor if the user has ActivityPub disabled. diff --git a/includes/handler/class-reject.php b/includes/handler/class-reject.php index d50ad9957f..839ef1e4f5 100644 --- a/includes/handler/class-reject.php +++ b/includes/handler/class-reject.php @@ -22,6 +22,8 @@ class Reject { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_action( 'activitypub_inbox_reject', array( self::class, 'handle_reject' ), 10, 2 ); @@ -33,6 +35,8 @@ public static function init() { * * @param array $reject The activity-object. * @param int|int[] $user_ids The user ID(s). + * + * @return void */ public static function handle_reject( $reject, $user_ids ) { // Validate that there is a preceding Activity. @@ -59,6 +63,8 @@ public static function handle_reject( $reject, $user_ids ) { * * @param array $reject The activity-object. * @param int|int[] $user_ids The user ID(s). + * + * @return void */ private static function reject_follow( $reject, $user_ids ) { /* @@ -101,6 +107,8 @@ private static function reject_follow( $reject, $user_ids ) { * @param array $reject The activity-object. * @param \WP_Post $outbox_post Our QuoteRequest outbox item. * @param int[]|int $user_ids The local user IDs. + * + * @return void */ private static function reject_quote_request( $reject, $outbox_post, $user_ids ) { $request = Outbox::get_activity( $outbox_post ); @@ -131,7 +139,7 @@ private static function reject_quote_request( $reject, $outbox_post, $user_ids ) \update_post_meta( $post->ID, '_activitypub_quote_rejected', '1' ); \delete_post_meta( $post->ID, '_activitypub_quote_authorization' ); - add_to_outbox( $post, 'Update', $post->post_author ); + add_to_outbox( $post, 'Update', (int) $post->post_author ); /** This action is documented in includes/handler/class-reject.php */ \do_action( 'activitypub_handled_reject', $reject, (array) $user_ids, true, $post ); diff --git a/includes/handler/class-undo.php b/includes/handler/class-undo.php index ff462127b8..b3ad94245c 100644 --- a/includes/handler/class-undo.php +++ b/includes/handler/class-undo.php @@ -17,6 +17,8 @@ class Undo { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_action( 'activitypub_inbox_undo', array( self::class, 'handle_undo' ), 10, 2 ); @@ -28,6 +30,8 @@ public static function init() { * * @param array $activity The JSON "Undo" Activity. * @param int|int[]|null $user_ids The user ID(s). + * + * @return void */ public static function handle_undo( $activity, $user_ids ) { $success = false; diff --git a/includes/handler/class-update.php b/includes/handler/class-update.php index b8e1ec7b09..f518736417 100644 --- a/includes/handler/class-update.php +++ b/includes/handler/class-update.php @@ -21,6 +21,8 @@ class Update { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_action( 'activitypub_handled_inbox_update', array( self::class, 'handle_update' ), 10, 3 ); @@ -32,6 +34,8 @@ public static function init() { * @param array $activity The Activity object. * @param int[] $user_ids Local recipient user IDs (followers and addressed local actors); may be empty. * @param \Activitypub\Activity\Activity $activity_object The activity object. Default null. + * + * @return void */ public static function handle_update( $activity, $user_ids, $activity_object ) { $object_type = $activity['object']['type'] ?? ''; @@ -81,6 +85,8 @@ public static function handle_update( $activity, $user_ids, $activity_object ) { * @param array $activity The Activity object. * @param int[]|null $user_ids Local recipient user IDs (followers and addressed local actors); may be empty. * @param \Activitypub\Activity\Activity $activity_object The activity object. Default null. + * + * @return void */ public static function update_object( $activity, $user_ids, $activity_object ) { $result = new \WP_Error( 'activitypub_update_failed', 'Update failed' ); @@ -109,7 +115,8 @@ public static function update_object( $activity, $user_ids, $activity_object ) { // There is no object to update, try to trigger create instead. if ( ! $updated ) { - return Create::handle_create( $activity, $user_ids, $activity_object ); + Create::handle_create( $activity, $user_ids, $activity_object ); + return; } $success = ( $result && ! \is_wp_error( $result ) ); @@ -130,6 +137,8 @@ public static function update_object( $activity, $user_ids, $activity_object ) { * * @param array $activity The Activity object. * @param int[]|null $user_ids Local recipient user IDs (followers and addressed local actors); may be empty. + * + * @return void */ public static function update_actor( $activity, $user_ids ) { /* diff --git a/includes/handler/outbox/class-add.php b/includes/handler/outbox/class-add.php index 71fec16ae1..f83cc0d4e3 100644 --- a/includes/handler/outbox/class-add.php +++ b/includes/handler/outbox/class-add.php @@ -20,6 +20,8 @@ class Add { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'activitypub_outbox_add', array( self::class, 'handle_add' ), 10, 2 ); diff --git a/includes/handler/outbox/class-announce.php b/includes/handler/outbox/class-announce.php index 4e9ef5f68c..867bbf090d 100644 --- a/includes/handler/outbox/class-announce.php +++ b/includes/handler/outbox/class-announce.php @@ -15,6 +15,8 @@ class Announce { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'activitypub_outbox_announce', array( self::class, 'handle_announce' ), 10, 2 ); @@ -27,6 +29,8 @@ public static function init() { * * @param array $data The activity data array. * @param int $user_id The user ID. + * + * @return array The activity data array. */ public static function handle_announce( $data, $user_id = null ) { $object_url = object_to_uri( $data['object'] ?? '' ); diff --git a/includes/handler/outbox/class-arrive.php b/includes/handler/outbox/class-arrive.php index 7865e16d9a..4220e56172 100644 --- a/includes/handler/outbox/class-arrive.php +++ b/includes/handler/outbox/class-arrive.php @@ -22,6 +22,8 @@ class Arrive { * Initialize the class, registering WordPress hooks. * * @since 8.1.0 + * + * @return void */ public static function init() { \add_filter( 'activitypub_outbox_arrive', array( self::class, 'handle_arrive' ), 10, 3 ); @@ -143,6 +145,8 @@ private static function create_checkin_post( $data, $user_id, $visibility ) { * * @param int $post_id The post ID. * @param array|null $location The ActivityPub location data. + * + * @return void */ private static function save_location( $post_id, $location ) { if ( ! \is_array( $location ) ) { diff --git a/includes/handler/outbox/class-block.php b/includes/handler/outbox/class-block.php index e8bb83b377..f46d10a839 100644 --- a/includes/handler/outbox/class-block.php +++ b/includes/handler/outbox/class-block.php @@ -18,6 +18,8 @@ class Block { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'activitypub_outbox_block', array( self::class, 'handle_block' ), 10, 2 ); diff --git a/includes/handler/outbox/class-create.php b/includes/handler/outbox/class-create.php index c65ac1c756..5d3b197cbb 100644 --- a/includes/handler/outbox/class-create.php +++ b/includes/handler/outbox/class-create.php @@ -23,6 +23,8 @@ class Create { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'activitypub_outbox_create', array( self::class, 'handle_create' ), 10, 3 ); diff --git a/includes/handler/outbox/class-delete.php b/includes/handler/outbox/class-delete.php index ceb411e00f..9c57528ec3 100644 --- a/includes/handler/outbox/class-delete.php +++ b/includes/handler/outbox/class-delete.php @@ -18,6 +18,8 @@ class Delete { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'activitypub_outbox_delete', array( self::class, 'handle_delete' ), 10, 2 ); diff --git a/includes/handler/outbox/class-follow.php b/includes/handler/outbox/class-follow.php index 86bab9825c..109a168fcb 100644 --- a/includes/handler/outbox/class-follow.php +++ b/includes/handler/outbox/class-follow.php @@ -16,6 +16,8 @@ class Follow { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'activitypub_outbox_follow', array( self::class, 'handle_follow' ), 10, 2 ); diff --git a/includes/handler/outbox/class-like.php b/includes/handler/outbox/class-like.php index 5a87ac091e..113bcff977 100644 --- a/includes/handler/outbox/class-like.php +++ b/includes/handler/outbox/class-like.php @@ -15,6 +15,8 @@ class Like { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'activitypub_outbox_like', array( self::class, 'handle_like' ), 10, 2 ); @@ -27,6 +29,8 @@ public static function init() { * * @param array $data The activity data array. * @param int $user_id The user ID. + * + * @return array The activity data array. */ public static function handle_like( $data, $user_id = null ) { $object_url = object_to_uri( $data['object'] ?? '' ); diff --git a/includes/handler/outbox/class-remove.php b/includes/handler/outbox/class-remove.php index 48f698ac77..8f16e04b49 100644 --- a/includes/handler/outbox/class-remove.php +++ b/includes/handler/outbox/class-remove.php @@ -20,6 +20,8 @@ class Remove { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'activitypub_outbox_remove', array( self::class, 'handle_remove' ), 10, 2 ); diff --git a/includes/handler/outbox/class-undo.php b/includes/handler/outbox/class-undo.php index ea5ca945a5..858ca542c5 100644 --- a/includes/handler/outbox/class-undo.php +++ b/includes/handler/outbox/class-undo.php @@ -20,6 +20,8 @@ class Undo { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'activitypub_outbox_undo', array( self::class, 'handle_undo' ), 10, 2 ); diff --git a/includes/handler/outbox/class-update.php b/includes/handler/outbox/class-update.php index 3c4c002d57..a8c882e8c7 100644 --- a/includes/handler/outbox/class-update.php +++ b/includes/handler/outbox/class-update.php @@ -18,6 +18,8 @@ class Update { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'activitypub_outbox_update', array( self::class, 'handle_update' ), 10, 3 ); diff --git a/includes/oauth/class-server.php b/includes/oauth/class-server.php index aca0ad9930..c1cfbc9437 100644 --- a/includes/oauth/class-server.php +++ b/includes/oauth/class-server.php @@ -26,6 +26,8 @@ class Server { * Initialize the OAuth server. * * Registered on `init`, so the setting is read once the site context is settled. + * + * @return void */ public static function init() { if ( ! \get_option( 'activitypub_api', false ) ) { @@ -321,6 +323,8 @@ public static function check_oauth_permission( $request, $scope = null ) { /** * Run cleanup tasks for OAuth data. + * + * @return void */ public static function cleanup() { // Clean up expired tokens. @@ -361,6 +365,8 @@ public static function get_metadata() { * Handle OAuth authorization consent page via wp-login.php. * * This is triggered by wp-login.php?action=activitypub_authorize + * + * @return void */ public static function login_form_authorize() { // Require user to be logged in. @@ -395,6 +401,8 @@ public static function login_form_authorize() { /** * Render the OAuth authorization consent form. + * + * @return void */ private static function render_authorize_form() { // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Initial form display, nonce checked on POST. @@ -463,6 +471,8 @@ private static function render_authorize_form() { /** * Process the OAuth authorization consent form submission. + * + * @return void */ private static function process_authorize_form() { // Verify nonce. It is bound to the client, so a consent form for one app can't approve another. @@ -566,6 +576,8 @@ private static function process_authorize_form() { * * @param string $redirect_uri The client's redirect URI. * @param array $params Query parameters to append. + * + * @return void */ private static function redirect_to_client( $redirect_uri, $params ) { $url = Sanitize::redirect_uri( \add_query_arg( $params, $redirect_uri ) ); diff --git a/includes/oauth/class-token.php b/includes/oauth/class-token.php index 36ab782f54..6f172ceb3a 100644 --- a/includes/oauth/class-token.php +++ b/includes/oauth/class-token.php @@ -494,6 +494,8 @@ private static function caller_owns_token( $token_user_id, $token_client_id, $ca * * @param int $user_id The user ID. * @param string $client_id The OAuth client ID. + * + * @return void */ private static function maybe_untrack_user( $user_id, $client_id ) { if ( empty( $client_id ) ) { @@ -736,6 +738,8 @@ public static function hash_token( $token ) { * * @param int $user_id The user ID. * @param string $client_id The OAuth client ID. + * + * @return void */ private static function track_user( $user_id, $client_id ) { $client = Client::get( $client_id ); @@ -758,6 +762,8 @@ private static function track_user( $user_id, $client_id ) { * @since 8.1.0 * * @param int $user_id The user ID. + * + * @return void */ private static function enforce_token_limit( $user_id ) { $all_meta = \get_user_meta( $user_id ); @@ -810,6 +816,8 @@ function ( $a, $b ) { * * @param int $user_id The user ID. * @param string $client_id The OAuth client ID. + * + * @return void */ private static function untrack_user( $user_id, $client_id ) { $client = Client::get( $client_id ); @@ -825,6 +833,8 @@ private static function untrack_user( $user_id, $client_id ) { * Untrack all users from a specific client. * * @param string $client_id The OAuth client ID. + * + * @return void */ private static function untrack_all_users( $client_id ) { $client = Client::get( $client_id ); diff --git a/includes/rest/admin/class-actions-controller.php b/includes/rest/admin/class-actions-controller.php index ba9ec1a3aa..6aa5ae5d79 100644 --- a/includes/rest/admin/class-actions-controller.php +++ b/includes/rest/admin/class-actions-controller.php @@ -37,6 +37,8 @@ class Actions_Controller extends \WP_REST_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { // Delete follower relationship. diff --git a/includes/rest/admin/class-statistics-controller.php b/includes/rest/admin/class-statistics-controller.php index 4208ccfb7b..d02328f56c 100644 --- a/includes/rest/admin/class-statistics-controller.php +++ b/includes/rest/admin/class-statistics-controller.php @@ -36,6 +36,8 @@ class Statistics_Controller extends \WP_REST_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { \register_rest_route( diff --git a/includes/rest/class-actor-autocomplete-controller.php b/includes/rest/class-actor-autocomplete-controller.php index a3e19e4472..a14694f9dd 100644 --- a/includes/rest/class-actor-autocomplete-controller.php +++ b/includes/rest/class-actor-autocomplete-controller.php @@ -49,6 +49,8 @@ class Actor_Autocomplete_Controller extends \WP_REST_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { \register_rest_route( diff --git a/includes/rest/class-actors-controller.php b/includes/rest/class-actors-controller.php index 1e3255a000..fa94cb6ee4 100644 --- a/includes/rest/class-actors-controller.php +++ b/includes/rest/class-actors-controller.php @@ -38,6 +38,8 @@ class Actors_Controller extends \WP_REST_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { \register_rest_route( diff --git a/includes/rest/class-actors-inbox-controller.php b/includes/rest/class-actors-inbox-controller.php index 4d99dde2f7..59b1dde252 100644 --- a/includes/rest/class-actors-inbox-controller.php +++ b/includes/rest/class-actors-inbox-controller.php @@ -32,6 +32,8 @@ class Actors_Inbox_Controller extends Actors_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { \register_rest_route( diff --git a/includes/rest/class-application-controller.php b/includes/rest/class-application-controller.php index ed052f8c08..500e0c4f15 100644 --- a/includes/rest/class-application-controller.php +++ b/includes/rest/class-application-controller.php @@ -40,6 +40,8 @@ class Application_Controller extends \WP_REST_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { \register_rest_route( diff --git a/includes/rest/class-collections-controller.php b/includes/rest/class-collections-controller.php index 07ab8614fa..9f0bf8a853 100644 --- a/includes/rest/class-collections-controller.php +++ b/includes/rest/class-collections-controller.php @@ -29,6 +29,8 @@ class Collections_Controller extends Actors_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { \register_rest_route( diff --git a/includes/rest/class-comments-controller.php b/includes/rest/class-comments-controller.php index 319eb1217f..4407764cab 100644 --- a/includes/rest/class-comments-controller.php +++ b/includes/rest/class-comments-controller.php @@ -36,6 +36,8 @@ class Comments_Controller extends \WP_REST_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { \register_rest_route( diff --git a/includes/rest/class-followers-controller.php b/includes/rest/class-followers-controller.php index 5ee379550b..7b0b7c695d 100644 --- a/includes/rest/class-followers-controller.php +++ b/includes/rest/class-followers-controller.php @@ -30,6 +30,8 @@ class Followers_Controller extends Actors_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { \register_rest_route( diff --git a/includes/rest/class-following-controller.php b/includes/rest/class-following-controller.php index c83dbf0117..1c6237f32a 100644 --- a/includes/rest/class-following-controller.php +++ b/includes/rest/class-following-controller.php @@ -26,6 +26,8 @@ class Following_Controller extends Actors_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { \register_rest_route( diff --git a/includes/rest/class-inbox-controller.php b/includes/rest/class-inbox-controller.php index 4bda1e45db..26ae6966fc 100644 --- a/includes/rest/class-inbox-controller.php +++ b/includes/rest/class-inbox-controller.php @@ -50,6 +50,8 @@ class Inbox_Controller extends \WP_REST_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { \register_rest_route( diff --git a/includes/rest/class-interaction-controller.php b/includes/rest/class-interaction-controller.php index 51163ea095..a83058e0e7 100644 --- a/includes/rest/class-interaction-controller.php +++ b/includes/rest/class-interaction-controller.php @@ -49,6 +49,8 @@ class Interaction_Controller extends \WP_REST_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { \register_rest_route( diff --git a/includes/rest/class-liked-controller.php b/includes/rest/class-liked-controller.php index 03e5d76b33..63ed05de8c 100644 --- a/includes/rest/class-liked-controller.php +++ b/includes/rest/class-liked-controller.php @@ -29,6 +29,8 @@ class Liked_Controller extends Actors_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { \register_rest_route( diff --git a/includes/rest/class-moderators-controller.php b/includes/rest/class-moderators-controller.php index dc9e624bc0..c3f13bd421 100644 --- a/includes/rest/class-moderators-controller.php +++ b/includes/rest/class-moderators-controller.php @@ -33,6 +33,8 @@ class Moderators_Controller extends \WP_REST_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { \register_rest_route( diff --git a/includes/rest/class-nodeinfo-controller.php b/includes/rest/class-nodeinfo-controller.php index 470d9fdc2f..5b3010c159 100644 --- a/includes/rest/class-nodeinfo-controller.php +++ b/includes/rest/class-nodeinfo-controller.php @@ -34,6 +34,8 @@ class Nodeinfo_Controller extends \WP_REST_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { \register_rest_route( diff --git a/includes/rest/class-outbox-controller.php b/includes/rest/class-outbox-controller.php index a1badb08a6..1b63d570ef 100644 --- a/includes/rest/class-outbox-controller.php +++ b/includes/rest/class-outbox-controller.php @@ -55,6 +55,8 @@ class Outbox_Controller extends \WP_REST_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { \register_rest_route( @@ -546,9 +548,9 @@ public function create_item( $request ) { * - array: Modified activity data (fallback to default handling) * - Other: No handler processed the activity (fallback to default) * - * @param array $data The activity data. - * @param int $user_id The user ID. - * @param string $visibility Content visibility. + * @param array|\WP_Post|\WP_Comment|int|\WP_Error|false $data The activity data, or the result of an earlier handler. + * @param int $user_id The user ID. + * @param string $visibility Content visibility. */ $result = \apply_filters( 'activitypub_outbox_' . $type, $data, $user_id, $visibility ); diff --git a/includes/rest/class-post-controller.php b/includes/rest/class-post-controller.php index e309038b4e..0518b535d3 100644 --- a/includes/rest/class-post-controller.php +++ b/includes/rest/class-post-controller.php @@ -40,6 +40,8 @@ class Post_Controller extends \WP_REST_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { \register_rest_route( diff --git a/includes/rest/class-proxy-controller.php b/includes/rest/class-proxy-controller.php index 9fadb7f4c9..5429973faa 100644 --- a/includes/rest/class-proxy-controller.php +++ b/includes/rest/class-proxy-controller.php @@ -43,6 +43,8 @@ class Proxy_Controller extends \WP_REST_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { \register_rest_route( diff --git a/includes/rest/class-replies-controller.php b/includes/rest/class-replies-controller.php index b8a21949c6..5b86a6a211 100644 --- a/includes/rest/class-replies-controller.php +++ b/includes/rest/class-replies-controller.php @@ -35,6 +35,8 @@ class Replies_Controller extends \WP_REST_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { \register_rest_route( diff --git a/includes/rest/class-seek-controller.php b/includes/rest/class-seek-controller.php index a88b322b0d..2291eb12fa 100644 --- a/includes/rest/class-seek-controller.php +++ b/includes/rest/class-seek-controller.php @@ -53,6 +53,8 @@ class Seek_Controller extends \WP_REST_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { \register_rest_route( diff --git a/includes/rest/class-server.php b/includes/rest/class-server.php index 4ce9d540a0..4fef5af01c 100644 --- a/includes/rest/class-server.php +++ b/includes/rest/class-server.php @@ -22,6 +22,8 @@ class Server { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'rest_pre_dispatch', array( self::class, 'normalize_route' ), 1, 3 ); @@ -420,6 +422,8 @@ public static function allow_cors_headers( $allow_headers, $request ) { * (e.g. SSE streams that call exit() instead of returning a WP_REST_Response). * * @since 8.1.0 + * + * @return void */ public static function send_cors_headers() { \header( 'Access-Control-Allow-Origin: *' ); diff --git a/includes/rest/class-stats-image-controller.php b/includes/rest/class-stats-image-controller.php index 0cbcc540ae..827aee8a66 100644 --- a/includes/rest/class-stats-image-controller.php +++ b/includes/rest/class-stats-image-controller.php @@ -83,6 +83,8 @@ public function validate_user_id( $value ) { /** * Register routes. + * + * @return void */ public function register_routes() { $route_pattern = '/(?P[\d]+)/(?P[\d]{4})'; diff --git a/includes/rest/class-webfinger-controller.php b/includes/rest/class-webfinger-controller.php index 356f087e67..08c0316c29 100644 --- a/includes/rest/class-webfinger-controller.php +++ b/includes/rest/class-webfinger-controller.php @@ -31,6 +31,8 @@ class Webfinger_Controller extends \WP_REST_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { \register_rest_route( diff --git a/includes/rest/oauth/class-authorization-controller.php b/includes/rest/oauth/class-authorization-controller.php index 8e4c4c6297..646dd63197 100644 --- a/includes/rest/oauth/class-authorization-controller.php +++ b/includes/rest/oauth/class-authorization-controller.php @@ -39,6 +39,8 @@ class Authorization_Controller extends \WP_REST_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { // Authorization endpoint - GET displays consent form, POST handles approval. diff --git a/includes/rest/oauth/class-clients-controller.php b/includes/rest/oauth/class-clients-controller.php index 9f717c0e42..6328fabad7 100644 --- a/includes/rest/oauth/class-clients-controller.php +++ b/includes/rest/oauth/class-clients-controller.php @@ -41,6 +41,8 @@ class Clients_Controller extends \WP_REST_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { // Dynamic client registration (RFC 7591). diff --git a/includes/rest/oauth/class-token-controller.php b/includes/rest/oauth/class-token-controller.php index c3f929a7a8..411c592c2d 100644 --- a/includes/rest/oauth/class-token-controller.php +++ b/includes/rest/oauth/class-token-controller.php @@ -44,6 +44,8 @@ class Token_Controller extends \WP_REST_Controller { /** * Register routes. + * + * @return void */ public function register_routes() { // Token endpoint. diff --git a/includes/rest/trait-collection.php b/includes/rest/trait-collection.php index 980ad35ed3..2165c3d620 100644 --- a/includes/rest/trait-collection.php +++ b/includes/rest/trait-collection.php @@ -166,6 +166,20 @@ public function get_seek_item_arg() { ); } + /** + * Resolve the zero-based position of an item under the collection's own query and visibility rules. + * + * Collections with a seekable order override this; the default has nothing to seek. + * + * @param string $item The ActivityPub ID of the item. + * @param \WP_REST_Request $request Full details about the request. + * + * @return int|false|\WP_Error Zero-based index of the item, false or WP_Error when not found. + */ + public function get_item_index( $item, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable, Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed + return false; + } + /** * Handle a seek request by redirecting to the collection page that contains the sought item. * diff --git a/includes/rest/trait-event-stream.php b/includes/rest/trait-event-stream.php index 78428f136c..ad7e691f6c 100644 --- a/includes/rest/trait-event-stream.php +++ b/includes/rest/trait-event-stream.php @@ -97,6 +97,8 @@ public function get_stream_permissions_check( $request ) { * @since 8.1.0 * * @see https://swicg.github.io/activitypub-api/sse + * + * @return void */ private function authenticate_from_query_param() { // phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Opaque auth token, must not be altered. @@ -133,6 +135,8 @@ private function authenticate_from_query_param() { * * @param int $user_id The actor ID. * @param string $collection The collection type ('outbox' or 'inbox'). + * + * @return void */ protected function stream_collection( $user_id, $collection ) { // Allow PHP to detect client disconnects instead of auto-terminating. @@ -202,6 +206,8 @@ protected function stream_collection( $user_id, $collection ) { * does not support streaming responses. * * @param string $stream_url The remote eventStream URL. + * + * @return void */ protected function relay_remote_stream( $stream_url ) { \ignore_user_abort( true ); @@ -364,6 +370,8 @@ protected function relay_remote_stream( $stream_url ) { /** * Send SSE-specific HTTP headers. + * + * @return void */ protected function send_sse_headers() { while ( \ob_get_level() > 0 ) { @@ -385,6 +393,8 @@ protected function send_sse_headers() { * * @param \WP_Post $item The collection post item. * @param string $collection The collection type ('outbox' or 'inbox'). + * + * @return void */ protected function send_sse_event( $item, $collection ) { $event_type = $this->get_event_type( $item, $collection ); @@ -405,6 +415,8 @@ protected function send_sse_event( $item, $collection ) { * Send an SSE comment line. * * @param string $comment The comment text. + * + * @return void */ protected function send_sse_comment( $comment ) { // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- SSE protocol requires raw output. @@ -413,6 +425,8 @@ protected function send_sse_comment( $comment ) { /** * Flush all output buffers. + * + * @return void */ protected function flush_output() { if ( \ob_get_level() > 0 ) { diff --git a/includes/scheduler/class-actor.php b/includes/scheduler/class-actor.php index 1befdeee8c..da56727c0e 100644 --- a/includes/scheduler/class-actor.php +++ b/includes/scheduler/class-actor.php @@ -21,6 +21,8 @@ class Actor { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { // Profile updates for blog options. @@ -73,6 +75,8 @@ public static function init() { * @param int $meta_id Meta ID being updated. * @param int $user_id User ID being updated. * @param string $meta_key Meta key being updated. + * + * @return void */ public static function user_meta_update( $meta_id, $user_id, $meta_key ) { // Don't bother if the user can't publish. @@ -101,6 +105,8 @@ public static function user_meta_update( $meta_id, $user_id, $meta_key ) { * Send a profile update when a user is updated. * * @param int $user_id User ID being updated. + * + * @return void */ public static function user_update( $user_id ) { // Don't bother if the user can't publish. @@ -129,11 +135,13 @@ public static function blog_user_update( $value = null ) { * @param string $new_status New post status. * @param string $old_status Old post status. * @param \WP_Post $post Post object. + * + * @return void */ public static function schedule_post_activity( $new_status, $old_status, $post ) { if ( $post instanceof \WP_Post ) { if ( Extra_Fields::USER_POST_TYPE === $post->post_type ) { - self::schedule_profile_update( $post->post_author ); + self::schedule_profile_update( (int) $post->post_author ); } elseif ( Extra_Fields::BLOG_POST_TYPE === $post->post_type ) { self::schedule_profile_update( Actors::BLOG_USER_ID ); } @@ -148,6 +156,8 @@ public static function schedule_post_activity( $new_status, $old_status, $post ) * followers of the blog actor and of every author receive the change. * * @since 9.0.1 + * + * @return void */ public static function schedule_all_profile_updates() { foreach ( Actors::get_all_ids() as $user_id ) { @@ -159,6 +169,8 @@ public static function schedule_all_profile_updates() { * Send a profile update to all followers. Gets hooked into all relevant options/meta etc. * * @param int $user_id The user ID to update (Could be 0 for Blog-User). + * + * @return void */ public static function schedule_profile_update( $user_id ) { if ( \defined( 'WP_IMPORTING' ) && WP_IMPORTING ) { @@ -180,6 +192,8 @@ public static function schedule_profile_update( $user_id ) { * Send a profile update when a post's sticky status changes. * * @param int $post_id The post ID. + * + * @return void */ public static function sticky_post_update( $post_id ) { $post = \get_post( $post_id ); @@ -188,13 +202,15 @@ public static function sticky_post_update( $post_id ) { return; } - self::schedule_profile_update( $post->post_author ); + self::schedule_profile_update( (int) $post->post_author ); } /** * Schedule a Delete activity when a user is deleted. * * @param int $user_id The user ID being deleted. + * + * @return void */ public static function schedule_user_delete( $user_id ) { // Get the actor before deletion to ensure we have the data. diff --git a/includes/scheduler/class-collection-sync.php b/includes/scheduler/class-collection-sync.php index 5d613aa63a..cd753c38fa 100644 --- a/includes/scheduler/class-collection-sync.php +++ b/includes/scheduler/class-collection-sync.php @@ -21,6 +21,8 @@ class Collection_Sync { /** * Initialize the scheduler. + * + * @return void */ public static function init() { \add_action( 'activitypub_collection_sync', array( self::class, 'schedule_reconciliation' ), 10, 4 ); @@ -34,6 +36,8 @@ public static function init() { * @param int $user_id The local user ID. * @param string $actor_url The remote actor URL. * @param array $params The Collection-Synchronization header parameters. + * + * @return void */ public static function schedule_reconciliation( $type, $user_id, $actor_url, $params ) { // Schedule async processing to avoid blocking the inbox. @@ -50,6 +54,8 @@ public static function schedule_reconciliation( $type, $user_id, $actor_url, $pa * @param int $user_id The local user ID. * @param string $actor_url The remote actor URL. * @param array $params The Collection-Synchronization header parameters. + * + * @return void */ public static function reconcile_followers( $user_id, $actor_url, $params ) { if ( empty( $params['url'] ) ) { diff --git a/includes/scheduler/class-comment.php b/includes/scheduler/class-comment.php index d01281cca5..69a6cab845 100644 --- a/includes/scheduler/class-comment.php +++ b/includes/scheduler/class-comment.php @@ -18,6 +18,8 @@ class Comment { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { if ( ACTIVITYPUB_DISABLE_OUTGOING_INTERACTIONS ) { @@ -38,6 +40,8 @@ public static function init() { * @param string $new_status New comment status. * @param string $old_status Old comment status. * @param \WP_Comment $comment Comment object. + * + * @return void */ public static function schedule_comment_activity( $new_status, $old_status, $comment ) { if ( \defined( 'WP_IMPORTING' ) && WP_IMPORTING ) { @@ -90,7 +94,7 @@ public static function schedule_comment_activity( $new_status, $old_status, $com $type = 'Create'; } elseif ( 'approved' === $new_status ) { $type = 'Update'; - \update_comment_meta( $comment->comment_ID, 'activitypub_comment_modified', \time(), true ); + \update_comment_meta( (int) $comment->comment_ID, 'activitypub_comment_modified', \time(), true ); } elseif ( 'trash' === $new_status || ( 'delete' === $new_status && '' === $old_status ) || // Went through schedule_comment_delete_activity(). @@ -108,7 +112,7 @@ public static function schedule_comment_activity( $new_status, $old_status, $com return; } - add_to_outbox( $comment, $type, $comment->user_id ); + add_to_outbox( $comment, $type, (int) $comment->user_id ); } /** @@ -116,6 +120,8 @@ public static function schedule_comment_activity( $new_status, $old_status, $com * * @param int $comment_id Comment ID. * @param \WP_Comment $comment Comment object. + * + * @return void */ public static function schedule_comment_activity_on_insert( $comment_id, $comment ) { if ( 1 === (int) $comment->comment_approved ) { @@ -128,6 +134,8 @@ public static function schedule_comment_activity_on_insert( $comment_id, $commen * * @param int $comment_id Comment ID. * @param \WP_Comment $comment Comment object. + * + * @return void */ public static function schedule_comment_delete_activity( $comment_id, $comment ) { // Only send Delete activities for comments that were previously federated. diff --git a/includes/scheduler/class-post.php b/includes/scheduler/class-post.php index d46f412d03..e4da538ac3 100644 --- a/includes/scheduler/class-post.php +++ b/includes/scheduler/class-post.php @@ -22,6 +22,8 @@ class Post { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { // Post transitions. @@ -53,6 +55,8 @@ public static function init() { * @param \WP_Post $post Post object. * @param bool $update Whether this is an existing post being updated. * @param \WP_Post $post_before Post object before the update. + * + * @return void */ public static function triage( $post_id, $post, $update, $post_before ) { if ( \defined( 'WP_IMPORTING' ) && WP_IMPORTING ) { @@ -155,13 +159,15 @@ public static function triage( $post_id, $post, $update, $post_before ) { $type = 'Delete'; } - add_to_outbox( $post, $type, $post->post_author ); + add_to_outbox( $post, $type, (int) $post->post_author ); } /** * Schedules Activities for attachment transitions. * * @param int $post_id Attachment ID. + * + * @return void */ public static function transition_attachment_status( $post_id ) { if ( \defined( 'WP_IMPORTING' ) && WP_IMPORTING ) { @@ -196,13 +202,15 @@ public static function transition_attachment_status( $post_id ) { return; } - add_to_outbox( $post, $type, $post->post_author ); + add_to_outbox( $post, $type, (int) $post->post_author ); } /** * Schedule an Add activity when a post is added to the featured collection. * * @param int $post_id The post ID. + * + * @return void */ public static function schedule_featured_add( $post_id ) { self::schedule_featured_update( $post_id, 'Add' ); @@ -212,6 +220,8 @@ public static function schedule_featured_add( $post_id ) { * Schedule a Remove activity when a post is removed from the featured collection. * * @param int $post_id The post ID. + * + * @return void */ public static function schedule_featured_remove( $post_id ) { self::schedule_featured_update( $post_id, 'Remove' ); @@ -227,6 +237,8 @@ public static function schedule_featured_remove( $post_id ) { * * @param int $post_id The post ID. * @param string $activity_type The activity type ('Add' or 'Remove'). + * + * @return void */ private static function schedule_featured_update( $post_id, $activity_type ) { if ( \defined( 'WP_IMPORTING' ) && WP_IMPORTING ) { @@ -243,7 +255,7 @@ private static function schedule_featured_update( $post_id, $activity_type ) { return; } - $actor = Actors::get_by_id( $post->post_author ); + $actor = Actors::get_by_id( (int) $post->post_author ); if ( ! $actor || \is_wp_error( $actor ) ) { return; @@ -255,6 +267,6 @@ private static function schedule_featured_update( $post_id, $activity_type ) { $activity->set_object( get_post_id( $post->ID ) ); $activity->set_target( $actor->get_featured() ); - add_to_outbox( $activity, null, $post->post_author ); + add_to_outbox( $activity, null, (int) $post->post_author ); } } diff --git a/includes/scheduler/class-quote-request.php b/includes/scheduler/class-quote-request.php index bc4c97c40c..b10fd153ad 100644 --- a/includes/scheduler/class-quote-request.php +++ b/includes/scheduler/class-quote-request.php @@ -26,6 +26,8 @@ class Quote_Request { * Initialize the class, registering WordPress hooks. * * @since unreleased + * + * @return void */ public static function init() { \add_action( 'post_activitypub_add_to_outbox', array( self::class, 'maybe_send_request' ), 10, 3 ); @@ -39,6 +41,8 @@ public static function init() { * @param int $outbox_id The outbox item ID. * @param Activity $activity The activity object. * @param int $user_id The local user ID. + * + * @return void */ public static function maybe_send_request( $outbox_id, $activity, $user_id ) { if ( ! \in_array( $activity->get_type(), array( 'Create', 'Update' ), true ) ) { diff --git a/includes/scheduler/class-statistics.php b/includes/scheduler/class-statistics.php index 9c3d159e51..078f6dbff6 100644 --- a/includes/scheduler/class-statistics.php +++ b/includes/scheduler/class-statistics.php @@ -20,6 +20,8 @@ class Statistics { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_action( 'activitypub_collect_monthly_stats', array( self::class, 'collect_all_monthly_stats' ) ); @@ -30,6 +32,8 @@ public static function init() { * Collect monthly statistics for all active users. * * This runs on the 1st of each month and collects stats for the previous month. + * + * @return void */ public static function collect_all_monthly_stats() { $user_ids = Statistics_Collector::get_active_user_ids(); @@ -69,6 +73,8 @@ public static function collect_all_monthly_stats() { * @todo Create a shareable landing page instead of just sending an email. * The email should link to a public page where stats can be viewed * and shared. Consider adding a summary image generator. + * + * @return void */ public static function compile_and_send_annual_stats() { $user_ids = Statistics_Collector::get_active_user_ids(); @@ -99,6 +105,8 @@ public static function compile_and_send_annual_stats() { * @param int $year The year. * @param array $summary The annual summary data. * @param bool $force Whether to bypass user preference checks. + * + * @return void */ public static function send_annual_email( $user_id, $year, $summary, $force = false ) { if ( ! $force && ! self::should_send_report( $user_id, $summary, 'activitypub_mailer_annual_report', '1' ) ) { @@ -198,6 +206,8 @@ public static function send_annual_email( $user_id, $year, $summary, $force = fa * @param int $year The year. * @param int $month The month (1-12). * @param bool $force Whether to bypass user preference checks. + * + * @return void */ public static function send_monthly_email( $user_id, $year, $month, $force = false ) { $option_name = Statistics_Collector::get_monthly_option_name( $user_id, $year, $month ); diff --git a/includes/transformer/class-base.php b/includes/transformer/class-base.php index 434f3ed5cb..14e8f7ba1b 100644 --- a/includes/transformer/class-base.php +++ b/includes/transformer/class-base.php @@ -161,6 +161,8 @@ public function get_content_visibility() { * Set the content visibility. * * @param string $content_visibility The content visibility. + * + * @return static */ public function set_content_visibility( $content_visibility ) { $this->content_visibility = $content_visibility; @@ -451,7 +453,7 @@ protected function parse_html_images( $media, $max_images, $content ) { // This linter warning is a false positive - we have to re-count each time here as we modify $images. // phpcs:ignore Squiz.PHP.DisallowSizeFunctionsInLoops.Found - while ( $tags->next_tag( 'img' ) && ( \count( $images ) <= $max_images ) ) { + while ( $tags->next_tag( array( 'tag_name' => 'img' ) ) && ( \count( $images ) <= $max_images ) ) { /** * Filter the image source URL. * diff --git a/includes/transformer/class-comment.php b/includes/transformer/class-comment.php index 434b5519be..553b66067b 100644 --- a/includes/transformer/class-comment.php +++ b/includes/transformer/class-comment.php @@ -180,12 +180,12 @@ protected function get_in_reply_to() { } if ( $parent_comment ) { - $in_reply_to = Comment_Utils::get_source_id( $parent_comment->comment_ID ); + $in_reply_to = Comment_Utils::get_source_id( (int) $parent_comment->comment_ID ); if ( ! $in_reply_to && ! empty( $parent_comment->user_id ) ) { $in_reply_to = Comment_Utils::generate_id( $parent_comment ); } } else { - $in_reply_to = \get_permalink( $comment->comment_post_ID ); + $in_reply_to = \get_permalink( (int) $comment->comment_post_ID ); } return $in_reply_to; @@ -223,7 +223,7 @@ protected function get_actor_object() { return $blog_user; } - $user = Actors::get_by_id( $this->item->user_id ); + $user = Actors::get_by_id( (int) $this->item->user_id ); if ( $user && ! \is_wp_error( $user ) ) { $this->actor_object = $user; diff --git a/includes/transformer/class-post.php b/includes/transformer/class-post.php index 7928adb245..07f3382b3a 100644 --- a/includes/transformer/class-post.php +++ b/includes/transformer/class-post.php @@ -34,6 +34,8 @@ * Currently supported are: * * - Activitypub\Activity\Base_Object + * + * @property \WP_Post $item The post being transformed. */ class Post extends Base { /** @@ -53,7 +55,7 @@ class Post extends Base { /** * The summary. * - * @var string|null|false False indicates not yet computed. + * @var string|false False indicates not yet computed. */ private $summary = false; @@ -208,7 +210,7 @@ public function get_actor_object() { return $blog_user; } - $user = Actors::get_by_id( $this->item->post_author ); + $user = Actors::get_by_id( (int) $this->item->post_author ); if ( $user && ! \is_wp_error( $user ) ) { $this->actor_object = $user; diff --git a/includes/wp-admin/class-admin.php b/includes/wp-admin/class-admin.php index b07c34c593..b5503350a2 100644 --- a/includes/wp-admin/class-admin.php +++ b/includes/wp-admin/class-admin.php @@ -34,6 +34,8 @@ class Admin { /** * Initialize the class, registering WordPress hooks, + * + * @return void */ public static function init() { \add_action( 'load-comment.php', array( self::class, 'edit_comment' ) ); @@ -92,6 +94,8 @@ public static function init() { /** * Display admin menu notices about configuration problems or conflicts. + * + * @return void */ public static function admin_notices() { $current_screen = \get_current_screen(); @@ -130,6 +134,8 @@ public static function admin_notices() { /** * Load user settings page. + * + * @return void */ public static function followers_list_page() { // User has to be able to publish posts. @@ -140,6 +146,8 @@ public static function followers_list_page() { /** * Load user following list page. + * + * @return void */ public static function following_list_page() { // User has to be able to publish posts. @@ -150,6 +158,8 @@ public static function following_list_page() { /** * Load blocked actors page. + * + * @return void */ public static function blocked_actors_list_page() { // User has to be able to publish posts. @@ -160,6 +170,8 @@ public static function blocked_actors_list_page() { /** * Creates the followers and following list tables in ActivityPub settings. + * + * @return void */ public static function add_settings_list_tables() { $tab = \sanitize_text_field( \wp_unslash( $_GET['tab'] ?? 'welcome' ) ); // phpcs:ignore WordPress.Security.NonceVerification @@ -179,6 +191,8 @@ public static function add_settings_list_tables() { /** * Creates the followers list table. + * + * @return void */ public static function add_followers_list_table() { $GLOBALS['followers_list_table'] = new Table\Followers(); @@ -186,6 +200,8 @@ public static function add_followers_list_table() { /** * Creates the following list table. + * + * @return void */ public static function add_following_list_table() { $GLOBALS['following_list_table'] = new Table\Following(); @@ -193,6 +209,8 @@ public static function add_following_list_table() { /** * Creates the blocked actors list table. + * + * @return void */ public static function add_blocked_actors_list_table() { $GLOBALS['blocked_actors_list_table'] = new Table\Blocked_Actors(); @@ -200,6 +218,8 @@ public static function add_blocked_actors_list_table() { /** * Render user settings. + * + * @return void */ public static function add_profile() { \wp_enqueue_media(); @@ -215,6 +235,8 @@ public static function add_profile() { * Handles the saving of the ActivityPub settings. * * @param int $user_id The user ID. + * + * @return void */ public static function save_user_settings( $user_id ) { if ( ! isset( $_REQUEST['_apnonce'] ) ) { @@ -272,6 +294,8 @@ public static function save_user_settings( $user_id ) { * Enqueue the admin scripts and styles. * * @param string $hook_suffix The current page. + * + * @return void */ public static function enqueue_scripts( $hook_suffix ) { \wp_register_script( @@ -378,6 +402,8 @@ public static function enqueue_scripts( $hook_suffix ) { /** * Enqueue moderation admin scripts. + * + * @return void */ public static function enqueue_moderation_scripts() { \wp_enqueue_script( @@ -408,6 +434,8 @@ public static function enqueue_moderation_scripts() { * Enqueue connected apps admin scripts on the profile page. * * @since 8.1.0 + * + * @return void */ public static function enqueue_connected_apps_scripts() { \wp_enqueue_script( @@ -448,6 +476,8 @@ public static function enqueue_connected_apps_scripts() { * Hook into the edit_comment functionality. * * Disables the edit_comment capability for federated comments. + * + * @return void */ public static function edit_comment() { // phpcs:ignore WordPress.Security.NonceVerification @@ -479,6 +509,8 @@ public static function edit_comment() { * Hook into the edit_post functionality. * * Disables the edit_post capability for federated posts. + * + * @return void */ public static function edit_post() { // Disable the edit_post capability for federated posts. @@ -508,6 +540,8 @@ static function ( $all_caps, $caps, $arg ) { /** * Add ActivityPub specific actions/filters to the post list view. + * + * @return void */ public static function list_posts() { // Remove all views for the extra fields. @@ -597,6 +631,8 @@ public static function manage_post_columns( $columns, $post_type ) { * * @param array $column The column to implement. * @param int $comment_id The comment id. + * + * @return void */ public static function manage_comments_custom_column( $column, $comment_id ) { if ( 'comment_type' === $column && ! \defined( 'WEBMENTION_PLUGIN_DIR' ) ) { @@ -789,6 +825,8 @@ public static function handle_bulk_request( $send_back, $action, $users ) { /** * Handle the bulk capability removal page request directly. + * + * @return void */ public static function handle_bulk_actor_delete_page() { @@ -827,6 +865,8 @@ public static function handle_bulk_actor_delete_page() { /** * Handle the bulk capability removal confirmation form submission. + * + * @return void */ public static function handle_bulk_actor_delete_confirmation() { // Verify nonce. @@ -992,6 +1032,8 @@ public static function row_actions( $actions, $post ) { * Add plugin settings link. * * @param array $actions The current actions. + * + * @return array The action links. */ public static function add_plugin_settings_link( $actions ) { $actions[] = \sprintf( @@ -1008,6 +1050,8 @@ public static function add_plugin_settings_link( $actions ) { * * @param array $data The plugin data. * @param object $update The plugin update data. + * + * @return void */ public static function plugin_update_message( $data, $update ) { if ( ! isset( $update->upgrade_notice ) ) { @@ -1019,6 +1063,8 @@ public static function plugin_update_message( $data, $update ) { /** * Adds meta box on wp-admin/tools.php. + * + * @return void */ public static function tool_box() { \load_template( ACTIVITYPUB_PLUGIN_DIR . 'templates/toolbox.php' ); @@ -1029,6 +1075,8 @@ public static function tool_box() { * * This function is used to open the help tab, * it is triggered by the hash in the URL. + * + * @return void */ public static function open_help_tab() { // get all tabs registered for the ActivityPub settings page. @@ -1062,6 +1110,8 @@ function activitypub_open_help_tab(event) { /** * AJAX handler for moderation settings (add/remove blocks). + * + * @return void */ public static function ajax_moderation_settings() { $context = \sanitize_text_field( \wp_unslash( $_POST['context'] ?? '' ) ); @@ -1123,6 +1173,8 @@ public static function ajax_moderation_settings() { /** * AJAX handler for blocklist subscriptions (add/remove). + * + * @return void */ public static function ajax_blocklist_subscription() { $operation = \sanitize_text_field( \wp_unslash( $_POST['operation'] ?? '' ) ); @@ -1172,6 +1224,8 @@ public static function ajax_blocklist_subscription() { * AJAX handler for registering a new OAuth client from the user profile. * * @since 8.1.0 + * + * @return void */ public static function ajax_register_oauth_client() { // Verify nonce. @@ -1222,6 +1276,8 @@ public static function ajax_register_oauth_client() { * AJAX handler for deleting a registered OAuth client. * * @since 8.1.0 + * + * @return void */ public static function ajax_delete_oauth_client() { // Verify nonce. @@ -1252,6 +1308,8 @@ public static function ajax_delete_oauth_client() { * AJAX handler for deleting all manually registered OAuth clients. * * @since 8.1.0 + * + * @return void */ public static function ajax_delete_all_oauth_clients() { // Verify nonce. @@ -1278,6 +1336,8 @@ public static function ajax_delete_all_oauth_clients() { * Follows the WordPress core Application Passwords pattern. * * @since 8.1.0 + * + * @return void */ public static function ajax_revoke_oauth_token() { // Verify nonce. @@ -1319,6 +1379,8 @@ public static function ajax_revoke_oauth_token() { * AJAX handler for revoking all OAuth tokens for the current user. * * @since 8.1.0 + * + * @return void */ public static function ajax_revoke_all_oauth_tokens() { // Verify nonce. diff --git a/includes/wp-admin/class-advanced-settings-fields.php b/includes/wp-admin/class-advanced-settings-fields.php index bbfdbdcb04..135ab6765e 100644 --- a/includes/wp-admin/class-advanced-settings-fields.php +++ b/includes/wp-admin/class-advanced-settings-fields.php @@ -16,6 +16,8 @@ class Advanced_Settings_Fields { /** * Initialize. + * + * @return void */ public static function init() { \add_action( 'load-settings_page_activitypub', array( self::class, 'register_advanced_fields' ) ); @@ -23,6 +25,8 @@ public static function init() { /** * Register settings. + * + * @return void */ public static function register_advanced_fields() { \add_settings_section( @@ -136,6 +140,8 @@ public static function register_advanced_fields() { /** * Render Advanced Settings Section. + * + * @return void */ public static function render_advanced_settings_section() { ?> @@ -155,6 +161,8 @@ public static function render_advanced_settings_section() { /** * Render vary header field. + * + * @return void */ public static function render_vary_header_field() { $value = \get_option( 'activitypub_vary_header', '1' ); @@ -173,6 +181,8 @@ public static function render_vary_header_field() { /** * Render content negotiation field. + * + * @return void */ public static function render_content_negotiation_field() { $value = \get_option( 'activitypub_content_negotiation', '1' ); @@ -191,6 +201,8 @@ public static function render_content_negotiation_field() { /** * Render use Authorized Fetch field. + * + * @return void */ public static function render_authorized_fetch_field() { $value = \get_option( 'activitypub_authorized_fetch', '0' ); @@ -212,6 +224,8 @@ public static function render_authorized_fetch_field() { /** * Render RFC-9421 signature field. + * + * @return void */ public static function render_rfc9421_signature_field() { $value = \get_option( 'activitypub_rfc9421_signature', '1' ); @@ -230,6 +244,8 @@ public static function render_rfc9421_signature_field() { /** * Render show following UI field. + * + * @return void */ public static function render_following_ui_field() { $value = \get_option( 'activitypub_following_ui', '0' ); @@ -251,6 +267,8 @@ public static function render_following_ui_field() { /** * Render reader field. + * + * @return void */ public static function render_reader_field() { $value = \get_option( 'activitypub_reader_ui', '0' ); @@ -272,6 +290,8 @@ public static function render_reader_field() { /** * Render ActivityPub API field. + * + * @return void */ public static function render_api_field() { $value = \get_option( 'activitypub_api', '0' ); @@ -298,6 +318,8 @@ public static function render_api_field() { /** * Render object type field. + * + * @return void */ public static function render_object_type_field() { $value = \get_option( 'activitypub_object_type', ACTIVITYPUB_DEFAULT_OBJECT_TYPE ); @@ -318,6 +340,8 @@ public static function render_object_type_field() { * Render distribution mode field. * * @since 9.0.0 + * + * @return void */ public static function render_distribution_mode_field() { $mode = \get_option( 'activitypub_distribution_mode', 'default' ); diff --git a/includes/wp-admin/class-app.php b/includes/wp-admin/class-app.php index b9178d524f..7ce63bf452 100644 --- a/includes/wp-admin/class-app.php +++ b/includes/wp-admin/class-app.php @@ -38,6 +38,8 @@ public static function is_supported() { * Initialize the App page. * * Must run early (on admin_init) before the admin bar is initialized. + * + * @return void */ public static function init() { // phpcs:ignore WordPress.Security.NonceVerification.Recommended @@ -48,6 +50,8 @@ public static function init() { /** * Remove admin notices from the App page. + * + * @return void */ public static function remove_admin_notices() { \remove_all_actions( 'admin_notices' ); @@ -64,6 +68,8 @@ static function ( $classes ) { /** * Enqueue scripts and styles for the App page. + * + * @return void */ public static function enqueue_scripts() { \wp_dequeue_style( 'colors' ); @@ -180,6 +186,8 @@ static function ( $handle ) { * Add boot configuration for the app loader module. * * @param array $routes Route definitions. + * + * @return void */ private static function add_loader_data( $routes ) { $mount_id = self::MOUNT_ID; @@ -197,6 +205,8 @@ static function ( $data ) use ( $mount_id, $routes ) { /** * Preload REST data used by the first app render. + * + * @return void */ private static function preload_rest_data() { // Define paths to preload - must match exact fields from entities.js. @@ -244,6 +254,8 @@ private static function get_routes() { * Register app script modules. * * @param array $routes Route definitions. + * + * @return void */ private static function register_app_modules( $routes ) { $module_assets = self::get_app_module_assets(); @@ -303,6 +315,8 @@ private static function get_app_module_assets() { * @param string $module_id Script module ID. * @param string $script Script path relative to the plugin root. * @param string $asset_file Asset metadata path relative to the plugin root. + * + * @return void */ private static function register_script_module( $module_id, $script, $asset_file ) { $asset = self::get_asset( $asset_file ); @@ -360,6 +374,8 @@ private static function get_boot_dependencies( $routes ) { /** * Enqueue styles emitted by the module build. + * + * @return void */ private static function enqueue_app_styles() { $style_path = 'build/app/routes/feed/style-content.css'; @@ -438,6 +454,8 @@ private static function get_asset( $asset_file ) { /** * Render the App admin page. + * + * @return void */ public static function render_page() { if ( ! self::is_supported() ) { diff --git a/includes/wp-admin/class-blog-settings-fields.php b/includes/wp-admin/class-blog-settings-fields.php index 5e84333428..5aa0eddffd 100644 --- a/includes/wp-admin/class-blog-settings-fields.php +++ b/includes/wp-admin/class-blog-settings-fields.php @@ -17,6 +17,8 @@ class Blog_Settings_Fields { /** * Initialize the settings fields. + * + * @return void */ public static function init() { \add_action( 'load-settings_page_activitypub', array( self::class, 'register_settings' ) ); @@ -24,6 +26,8 @@ public static function init() { /** * Register all settings fields. + * + * @return void */ public static function register_settings() { // If we're in blog mode, and we're on the blog profile tab, mark the profile setup step as done. @@ -119,6 +123,8 @@ public static function register_settings() { /** * Name field callback. + * + * @return void */ public static function name_callback() { ?> @@ -133,6 +139,8 @@ public static function name_callback() { /** * Avatar field callback. + * + * @return void */ public static function avatar_callback() { $blog = new Blog(); @@ -197,6 +205,8 @@ class=""> /** * Header image field callback. + * + * @return void */ public static function header_image_callback() { $classes_for_button = 'button upload-button button-add-media button-add-header-image activitypub-media-picker-button'; @@ -247,6 +257,8 @@ class="" /** * Profile ID field callback. + * + * @return void */ public static function profile_id_callback() { ?> @@ -267,6 +279,8 @@ public static function profile_id_callback() { /** * Description field callback. + * + * @return void */ public static function description_callback() { ?> @@ -287,6 +301,8 @@ class="blog-user-description large-text" /** * Notifications field callback. + * + * @return void */ public static function notifications_callback() { ?> @@ -327,6 +343,8 @@ public static function notifications_callback() { /** * Extra fields callback. + * + * @return void */ public static function extra_fields_callback() { ?> @@ -375,6 +393,8 @@ public static function extra_fields_callback() { /** * Also Known As field callback. + * + * @return void */ public static function also_known_as_callback() { $also_known_as = \get_option( 'activitypub_blog_user_also_known_as' ); @@ -398,6 +418,8 @@ class="large-text" /** * Hide Social Graph field callback. + * + * @return void */ public static function hide_followers_callback() { ?> diff --git a/includes/wp-admin/class-dashboard.php b/includes/wp-admin/class-dashboard.php index 70efb92b76..60ca61042f 100644 --- a/includes/wp-admin/class-dashboard.php +++ b/includes/wp-admin/class-dashboard.php @@ -22,6 +22,8 @@ class Dashboard { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_action( 'wp_dashboard_setup', array( self::class, 'add_dashboard_widgets' ) ); @@ -30,6 +32,8 @@ public static function init() { /** * Add Dashboard widgets. + * + * @return void */ public static function add_dashboard_widgets() { // Plugin news widget. @@ -75,6 +79,8 @@ public static function add_dashboard_widgets() { * Enqueue scripts for the dashboard widgets. * * @param string $hook The current admin page. + * + * @return void */ public static function enqueue_scripts( $hook ) { if ( 'index.php' !== $hook ) { @@ -148,6 +154,8 @@ private static function user_can_see_stats() { /** * Render the ActivityPub.blog news feed widget. + * + * @return void */ public static function render_news_widget() { echo '
'; @@ -165,6 +173,8 @@ public static function render_news_widget() { /** * Render the ActivityPub Author profile widget. + * + * @return void */ public static function render_author_profile_widget() { $user = Actors::get_by_id( \get_current_user_id() ); @@ -185,6 +195,8 @@ public static function render_author_profile_widget() { /** * Render the ActivityPub Blog profile widget. + * + * @return void */ public static function render_blog_profile_widget() { $user = new Blog(); @@ -207,6 +219,8 @@ public static function render_blog_profile_widget() { /** * Render the stats widget container. + * + * @return void */ public static function render_stats_widget() { echo '
'; diff --git a/includes/wp-admin/class-health-check.php b/includes/wp-admin/class-health-check.php index 64c967a802..62c4991a92 100644 --- a/includes/wp-admin/class-health-check.php +++ b/includes/wp-admin/class-health-check.php @@ -26,6 +26,8 @@ class Health_Check { /** * Initialize health checks. + * + * @return void */ public static function init() { \add_filter( 'site_status_tests', array( self::class, 'add_tests' ) ); @@ -40,6 +42,8 @@ public static function init() { * * This is called when the ActivityPub settings page is loaded to * automatically restore any missing scheduled events. + * + * @return void */ public static function ensure_schedules_registered() { $missing_schedules = self::get_missing_schedules(); diff --git a/includes/wp-admin/class-heartbeat.php b/includes/wp-admin/class-heartbeat.php index af9185bb5c..48f8b1efdf 100644 --- a/includes/wp-admin/class-heartbeat.php +++ b/includes/wp-admin/class-heartbeat.php @@ -17,6 +17,8 @@ class Heartbeat { /** * Initialize the Heartbeat API integration. + * + * @return void */ public static function init() { \add_action( 'admin_print_scripts-settings_page_activitypub', array( self::class, 'enqueue_scripts' ) ); @@ -27,6 +29,8 @@ public static function init() { /** * Enqueue scripts and localize data for the Following list table. + * + * @return void */ public static function enqueue_scripts() { $tab = \sanitize_text_field( \wp_unslash( $_GET['tab'] ?? 'welcome' ) ); // phpcs:ignore WordPress.Security.NonceVerification diff --git a/includes/wp-admin/class-menu.php b/includes/wp-admin/class-menu.php index 0ad2eb2f9f..619c049ea7 100644 --- a/includes/wp-admin/class-menu.php +++ b/includes/wp-admin/class-menu.php @@ -16,6 +16,8 @@ class Menu { /** * Initialize the Menu class. + * + * @return void */ public static function init() { \add_action( 'admin_menu', array( self::class, 'admin_menu' ) ); @@ -24,6 +26,8 @@ public static function init() { /** * Add admin menu entry. + * + * @return void */ public static function admin_menu() { $settings_page = \add_options_page( @@ -106,6 +110,8 @@ public static function admin_menu() { * Add Social Web item to the admin bar. * * @param \WP_Admin_Bar $wp_admin_bar The WP_Admin_Bar instance. + * + * @return void */ public static function admin_bar_menu( $wp_admin_bar ) { // Only show if reader UI is enabled and the WordPress app boot stack is available. diff --git a/includes/wp-admin/class-screen-options.php b/includes/wp-admin/class-screen-options.php index 8d5b56c5d1..9d1b42f80a 100644 --- a/includes/wp-admin/class-screen-options.php +++ b/includes/wp-admin/class-screen-options.php @@ -13,6 +13,8 @@ class Screen_Options { /** * Initialize the class. + * + * @return void */ public static function init() { \add_filter( 'set-screen-option', array( self::class, 'set_per_page_option' ), 10, 3 ); @@ -24,6 +26,8 @@ public static function init() { * Add settings list screen options. * * @see Menu::admin_menu() + * + * @return void */ public static function add_settings_list_options() { $tab = \sanitize_text_field( \wp_unslash( $_GET['tab'] ?? 'welcome' ) ); // phpcs:ignore WordPress.Security.NonceVerification @@ -45,6 +49,8 @@ public static function add_settings_list_options() { * Add follower list screen options. * * @see Menu::admin_menu() + * + * @return void */ public static function add_followers_list_options() { \add_screen_option( @@ -61,6 +67,8 @@ public static function add_followers_list_options() { * Add screen options for following list. * * @see Menu::admin_menu() + * + * @return void */ public static function add_following_list_options() { \add_screen_option( @@ -77,6 +85,8 @@ public static function add_following_list_options() { * Add screen options for blocked actors list. * * @see Menu::admin_menu() + * + * @return void */ public static function add_blocked_actors_list_options() { \add_screen_option( diff --git a/includes/wp-admin/class-settings-fields.php b/includes/wp-admin/class-settings-fields.php index 5b58523dea..5d6dff20a4 100644 --- a/includes/wp-admin/class-settings-fields.php +++ b/includes/wp-admin/class-settings-fields.php @@ -19,6 +19,8 @@ class Settings_Fields { /** * Initialize the settings fields. + * + * @return void */ public static function init() { \add_action( 'load-settings_page_activitypub', array( self::class, 'register_settings_fields' ) ); @@ -26,6 +28,8 @@ public static function init() { /** * Register settings fields. + * + * @return void */ public static function register_settings_fields() { // Add settings sections. @@ -195,6 +199,8 @@ public static function register_settings_fields() { /** * Render actor mode field. + * + * @return void */ public static function render_actor_mode_field() { $disabled = ( \defined( 'ACTIVITYPUB_SINGLE_USER_MODE' ) && ACTIVITYPUB_SINGLE_USER_MODE ) || @@ -259,6 +265,8 @@ public static function render_actor_mode_field() { /** * Render custom post content field. + * + * @return void */ public static function render_custom_post_content_field() { $switch_url = \wp_nonce_url( @@ -306,6 +314,8 @@ public static function render_custom_post_content_field() { /** * Render max image attachments field. + * + * @return void */ public static function render_max_image_attachments_field() { $value = \get_option( 'activitypub_max_image_attachments', ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS ); @@ -333,6 +343,8 @@ public static function render_max_image_attachments_field() { /** * Render support post types field. + * + * @return void */ public static function render_support_post_types_field() { $post_types = \get_post_types( array( 'public' => true ), 'objects' ); @@ -357,6 +369,8 @@ public static function render_support_post_types_field() { /** * Render allow interactions field. + * + * @return void */ public static function render_allow_interactions_field() { if ( \defined( 'ACTIVITYPUB_DISABLE_INCOMING_INTERACTIONS' ) && ACTIVITYPUB_DISABLE_INCOMING_INTERACTIONS ) { @@ -394,6 +408,8 @@ public static function render_allow_interactions_field() { /** * Render default quote policy field. + * + * @return void */ public static function render_default_quote_policy_field() { $value = \get_option( 'activitypub_default_quote_policy', ACTIVITYPUB_INTERACTION_POLICY_ANYONE ); @@ -411,6 +427,8 @@ public static function render_default_quote_policy_field() { /** * Render default feature policy field. + * + * @return void */ public static function render_default_feature_policy_field() { $value = \get_option( 'activitypub_default_feature_policy', ACTIVITYPUB_INTERACTION_POLICY_ME ); @@ -428,6 +446,8 @@ public static function render_default_feature_policy_field() { /** * Render use hashtags field. + * + * @return void */ public static function render_use_hashtags_field() { $value = \get_option( 'activitypub_use_hashtags', '0' ); @@ -443,6 +463,8 @@ public static function render_use_hashtags_field() { /** * Render use OpenGraph field. + * + * @return void */ public static function render_use_opengraph_field() { $value = \get_option( 'activitypub_use_opengraph', '1' ); @@ -458,6 +480,8 @@ public static function render_use_opengraph_field() { /** * Render attribution domains field. + * + * @return void */ public static function render_attribution_domains_field() { $value = \get_option( 'activitypub_attribution_domains', home_host() ); @@ -475,6 +499,8 @@ class="large-text" /** * Render relays field. + * + * @return void */ public static function render_relays_field() { $value = \get_option( 'activitypub_relays', array() ); @@ -506,6 +532,8 @@ class="large-text" /** * Render moderation section description. + * + * @return void */ public static function render_moderation_section_description() { echo '

' . \esc_html__( 'Configure site-wide moderation settings. These blocks will affect all users and ActivityPub content on your site.', 'activitypub' ) . '

'; @@ -513,6 +541,8 @@ public static function render_moderation_section_description() { /** * Render site blocked domains field. + * + * @return void */ public static function render_site_blocked_domains_field() { $blocked_domains = Moderation::get_site_blocks()['domains']; @@ -567,6 +597,8 @@ public static function render_site_blocked_domains_field() { /** * Render site blocked keywords field. + * + * @return void */ public static function render_site_blocked_keywords_field() { $blocked_keywords = Moderation::get_site_blocks()['keywords']; @@ -621,6 +653,8 @@ public static function render_site_blocked_keywords_field() { /** * Render blocklist subscriptions field. + * + * @return void */ public static function render_blocklist_subscriptions_field() { $subscriptions = Blocklist_Subscriptions::get_all(); diff --git a/includes/wp-admin/class-settings.php b/includes/wp-admin/class-settings.php index 5642cae1c4..110d2bfa83 100644 --- a/includes/wp-admin/class-settings.php +++ b/includes/wp-admin/class-settings.php @@ -17,6 +17,8 @@ class Settings { /** * Initialize the class, registering WordPress hooks, + * + * @return void */ public static function init() { \add_action( 'admin_menu', array( self::class, 'add_settings_page' ) ); @@ -30,6 +32,8 @@ public static function init() { * Set the page title to the tab that is being viewed. * * Runs on `load-settings_page_activitypub`, before core prints the `` tag. + * + * @return void */ public static function set_page_title() { $active_tab = \wp_filter_object_list( self::get_settings_tabs(), array( 'active' => true ) ); @@ -129,6 +133,8 @@ public static function get_settings_tabs() { /** * Load settings page. + * + * @return void */ public static function settings_page() { $settings_tabs = self::get_settings_tabs(); @@ -167,6 +173,8 @@ public static function settings_page() { /** * Adds the ActivityPub settings to the Help tab. + * + * @return void */ public static function add_settings_help_tab() { // Getting Started / Introduction to the Fediverse. @@ -276,6 +284,8 @@ public static function add_settings_help_tab() { /** * Adds the ActivityPub help tab to the users page. + * + * @return void */ public static function add_following_help_tab() { \get_current_screen()->add_help_tab( @@ -297,6 +307,8 @@ public static function add_following_help_tab() { /** * Adds the ActivityPub help tab to the users page. + * + * @return void */ public static function add_users_help_tab() { \get_current_screen()->add_help_tab( @@ -312,6 +324,8 @@ public static function add_users_help_tab() { /** * Handle 'welcome' query arg. + * + * @return void */ public static function handle_welcome_query_arg() { // phpcs:ignore WordPress.Security.NonceVerification.Recommended @@ -328,6 +342,8 @@ public static function handle_welcome_query_arg() { * Handle switching from legacy template mode to automatic object type. * * @since 8.0.0 + * + * @return void */ public static function handle_switch_object_type() { // phpcs:ignore WordPress.Security.NonceVerification.Recommended @@ -349,6 +365,8 @@ public static function handle_switch_object_type() { /** * Returns an array of recommended plugins for ActivityPub. + * + * @return array The recommended plugins. */ public static function get_recommended_plugins() { $plugins = array(); @@ -430,6 +448,8 @@ public static function get_recommended_plugins() { /** * Render recommended plugins as a beautiful, rich showcase for the help tab. + * + * @return string|false The rendered list, or false when output buffering is off. */ public static function render_recommended_plugins_list() { $plugins = self::get_recommended_plugins(); diff --git a/includes/wp-admin/class-user-settings-fields.php b/includes/wp-admin/class-user-settings-fields.php index 66bce24f04..dc7668dcf8 100644 --- a/includes/wp-admin/class-user-settings-fields.php +++ b/includes/wp-admin/class-user-settings-fields.php @@ -20,6 +20,8 @@ class User_Settings_Fields { /** * Initialize the settings fields. + * + * @return void */ public static function init() { \add_action( 'load-profile.php', array( self::class, 'register_settings' ) ); @@ -27,6 +29,8 @@ public static function init() { /** * Register all settings fields. + * + * @return void */ public static function register_settings() { // Mark checklist item as done. @@ -133,6 +137,8 @@ public static function register_settings() { /** * Section description callback. + * + * @return void */ public static function section_description() { echo '<p>' . \esc_html__( 'Define what others can see on your public Fediverse profile and next to your posts. With a profile picture and a fully completed profile, you are more likely to gain interactions and followers.', 'activitypub' ) . '</p>'; @@ -141,6 +147,8 @@ public static function section_description() { /** * Profile URL field callback. + * + * @return void */ public static function profile_url_callback() { $user = Actors::get_by_id( \get_current_user_id() ); @@ -169,6 +177,8 @@ public static function profile_url_callback() { /** * Description field callback. + * + * @return void */ public static function description_callback() { $description = \get_user_option( 'activitypub_description', \get_current_user_id() ); @@ -181,6 +191,8 @@ public static function description_callback() { /** * Header image field callback. + * + * @return void */ public static function header_image_callback() { $header_image = \get_user_option( 'activitypub_header_image', \get_current_user_id() ); @@ -237,6 +249,8 @@ class="<?php echo \esc_attr( $classes_for_button ); ?>" /** * Notifications field callback. + * + * @return void */ public static function notifications_callback() { ?> @@ -283,6 +297,8 @@ public static function notifications_callback() { /** * Extra fields callback. + * + * @return void */ public static function extra_fields_callback() { $extra_fields = Extra_Fields::get_actor_fields( \get_current_user_id() ); @@ -320,6 +336,8 @@ public static function extra_fields_callback() { /** * Also Known As field callback. + * + * @return void */ public static function also_known_as_callback() { $also_known_as = \get_user_option( 'activitypub_also_known_as', \get_current_user_id() ); @@ -341,6 +359,8 @@ class="large-text" /** * Moderation section description callback. + * + * @return void */ public static function moderation_section_description() { echo '<p>' . \esc_html__( 'Configure personal blocks to filter ActivityPub content you don\'t want to see.', 'activitypub' ) . '</p>'; @@ -348,6 +368,8 @@ public static function moderation_section_description() { /** * Blocked domains field callback. + * + * @return void */ public static function blocked_domains_callback() { $user_id = \get_current_user_id(); @@ -383,6 +405,8 @@ public static function blocked_domains_callback() { /** * Blocked keywords field callback. + * + * @return void */ public static function blocked_keywords_callback() { $user_id = \get_current_user_id(); @@ -423,6 +447,8 @@ public static function blocked_keywords_callback() { * not through the Settings API. * * @since 8.1.0 + * + * @return void */ public static function connected_apps_section() { $tokens = Token::get_all_for_user( \get_current_user_id() ); @@ -568,6 +594,8 @@ public static function connected_apps_section() { /** * Hide Social Graph field callback. + * + * @return void */ public static function hide_followers_callback() { $hide_followers = \get_user_option( 'activitypub_hide_social_graph', \get_current_user_id() ); diff --git a/includes/wp-admin/class-welcome-fields.php b/includes/wp-admin/class-welcome-fields.php index 104593a841..ebc002d9a3 100644 --- a/includes/wp-admin/class-welcome-fields.php +++ b/includes/wp-admin/class-welcome-fields.php @@ -15,6 +15,8 @@ class Welcome_Fields { /** * Initialize the welcome fields. + * + * @return void */ public static function init() { \add_action( 'load-settings_page_activitypub', array( self::class, 'register_welcome_fields' ) ); @@ -33,6 +35,8 @@ public static function init() { /** * Register welcome fields. + * + * @return void */ public static function register_welcome_fields() { \add_settings_section( @@ -74,6 +78,8 @@ public static function register_welcome_fields() { /** * Render welcome header section. + * + * @return void */ public static function render_welcome_header_section() { $completed_steps = self::get_completed_steps_count(); @@ -84,7 +90,7 @@ public static function render_welcome_header_section() { <div class="activitypub-welcome-header"> <div class="activitypub-progress-circle"> <div class="activitypub-progress-circle-content"> - <span><?php echo \esc_html( $completed_steps ); ?>/<?php echo \esc_html( $total_steps ); ?></span> + <span><?php echo (int) $completed_steps; ?>/<?php echo (int) $total_steps; ?></span> </div> <svg class="activitypub-progress-ring" width="120" height="120"> <circle class="activitypub-progress-ring-bg" cx="60" cy="60" r="54" /> @@ -101,6 +107,8 @@ public static function render_welcome_header_section() { /** * Get the count of completed steps. + * + * @return int Number of completed steps. */ private static function get_completed_steps_count() { $count = 1; // Plugin is already installed. @@ -132,6 +140,8 @@ private static function get_completed_steps_count() { /** * Get the total number of steps. + * + * @return int Number of steps. */ private static function get_total_steps_count() { global $wp_filter; @@ -151,6 +161,8 @@ private static function get_total_steps_count() { /** * Get the next incomplete step. + * + * @return string The step key, or an empty string when all steps are done. */ private static function get_next_incomplete_step() { if ( self::has_step( 'site_health' ) && '0' !== \get_option( 'activitypub_checklist_health_check_issues', (string) Health_Check::count_results( 'critical' ) ) ) { @@ -188,6 +200,8 @@ private static function has_step( $step ) { /** * Render onboarding steps section. + * + * @return void */ public static function render_onboarding_steps_section() { ?> @@ -201,6 +215,8 @@ public static function render_onboarding_steps_section() { /** * Render plugin installed step. + * + * @return void */ public static function render_step_plugin_installed() { ?> @@ -219,6 +235,8 @@ public static function render_step_plugin_installed() { /** * Render site health step. + * + * @return void */ public static function render_step_site_health() { $health_issues = Health_Check::count_results(); @@ -263,6 +281,8 @@ public static function render_step_site_health() { /** * Render the Fediverse-Intro step. + * + * @return void */ public static function render_step_fediverse_intro() { $checked = '1' === \get_option( 'activitypub_checklist_fediverse_intro_visited', false ); @@ -295,6 +315,8 @@ public static function render_step_fediverse_intro() { /** * Render the Profile Mode step. + * + * @return void */ public static function render_step_profile_mode() { $checked = '1' === \get_option( 'activitypub_checklist_settings_visited', false ); @@ -327,6 +349,8 @@ public static function render_step_profile_mode() { /** * Render the Profile Setup step. + * + * @return void */ public static function render_step_profile_setup() { $user_can_activitypub = user_can_activitypub( \get_current_user_id() ); @@ -370,6 +394,8 @@ public static function render_step_profile_setup() { /** * Render the Features step. + * + * @return void */ public static function render_step_features() { $checked = '1' === \get_option( 'activitypub_checklist_blocks_visited', false ); @@ -402,6 +428,8 @@ public static function render_step_features() { /** * Render welcome footer section. + * + * @return void */ public static function render_welcome_footer_section() { ?> @@ -416,6 +444,8 @@ public static function render_welcome_footer_section() { /** * Resolve the welcome checklist. + * + * @return void */ public static function resolve_checklist() { if ( self::get_total_steps_count() === self::get_completed_steps_count() ) { diff --git a/includes/wp-admin/import/class-blocklist.php b/includes/wp-admin/import/class-blocklist.php index 8b15404780..4b29730271 100644 --- a/includes/wp-admin/import/class-blocklist.php +++ b/includes/wp-admin/import/class-blocklist.php @@ -19,6 +19,8 @@ class Blocklist { /** * Dispatch the importer based on current step. + * + * @return void */ public static function dispatch() { // phpcs:ignore WordPress.Security.NonceVerification.Recommended @@ -47,6 +49,8 @@ public static function dispatch() { /** * Display the importer header. + * + * @return void */ private static function header() { echo '<div class="wrap">'; @@ -55,6 +59,8 @@ private static function header() { /** * Display the importer footer. + * + * @return void */ private static function footer() { echo '</div>'; @@ -62,6 +68,8 @@ private static function footer() { /** * Display the greeting/intro screen. + * + * @return void */ private static function greet() { echo '<div class="narrow">'; @@ -123,6 +131,8 @@ private static function greet() { /** * Handle file upload and import. + * + * @return void */ private static function handle_upload() { $error_message = \__( 'Sorry, there has been an error.', 'activitypub' ); @@ -178,6 +188,8 @@ private static function handle_upload() { /** * Handle URL import. + * + * @return void */ private static function handle_url_import() { $error_message = \__( 'Sorry, there has been an error.', 'activitypub' ); @@ -215,6 +227,8 @@ private static function handle_url_import() { * Execute the import for file uploads. * * @param array $domains Array of domains to import. + * + * @return void */ private static function import( $domains ) { \set_time_limit( 0 ); @@ -274,6 +288,8 @@ private static function import( $domains ) { * * @param int $imported Number of domains imported. * @param bool $subscribed Whether the URL was subscribed to. + * + * @return void */ private static function show_url_import_results( $imported, $subscribed ) { echo '<h3>' . \esc_html__( 'Import Complete', 'activitypub' ) . '</h3>'; diff --git a/includes/wp-admin/import/class-mastodon.php b/includes/wp-admin/import/class-mastodon.php index bd7af36601..f4ff8b6d38 100644 --- a/includes/wp-admin/import/class-mastodon.php +++ b/includes/wp-admin/import/class-mastodon.php @@ -54,6 +54,8 @@ class Mastodon { /** * Dispatch + * + * @return void */ public static function dispatch() { // phpcs:ignore WordPress.Security.NonceVerification.Recommended @@ -152,6 +154,8 @@ public static function handle_upload() { /** * Import options. + * + * @return void */ public static function import_options() { $author = 0; @@ -208,6 +212,8 @@ public static function import_options() { /** * Import. + * + * @return void */ public static function import() { $error_message = \__( 'Sorry, there has been an error.', 'activitypub' ); @@ -252,7 +258,7 @@ public static function import() { \wp_defer_comment_counting( false ); $wp_filesystem->delete( $import_folder, true ); - \wp_import_cleanup( self::$import_id ); + \wp_import_cleanup( (string) self::$import_id ); if ( \is_wp_error( $result ) ) { echo '<p><strong>' . \esc_html( $error_message ) . '</strong><br />'; @@ -629,6 +635,8 @@ private static function import_as_comment( $post, $source_to_post_id, &$source_t /** * Header. + * + * @return void */ public static function header() { echo '<div class="wrap">'; @@ -637,6 +645,8 @@ public static function header() { /** * Footer. + * + * @return void */ public static function footer() { echo '</div>'; @@ -644,6 +654,8 @@ public static function footer() { /** * Intro. + * + * @return void */ public static function greet() { echo '<div class="narrow">'; @@ -693,6 +705,8 @@ private static function prepend_archive_path( $attachment ) { * * Some Mastodon exports wrap all files in a root folder. This method * detects this pattern and updates the archive path to point inside it. + * + * @return void */ private static function maybe_unwrap_archive() { global $wp_filesystem; diff --git a/includes/wp-admin/import/class-starter-kit.php b/includes/wp-admin/import/class-starter-kit.php index 908a7525b5..f51e2f2d2b 100644 --- a/includes/wp-admin/import/class-starter-kit.php +++ b/includes/wp-admin/import/class-starter-kit.php @@ -68,6 +68,8 @@ class Starter_Kit { /** * Dispatch + * + * @return void */ public static function dispatch() { // phpcs:ignore WordPress.Security.NonceVerification.Recommended @@ -122,6 +124,8 @@ static function ( $actor ) { /** * Handle upload. + * + * @return bool Whether the upload was imported. */ public static function handle_upload() { $error_message = \__( 'Sorry, there has been an error.', 'activitypub' ); @@ -180,6 +184,8 @@ public static function handle_upload() { /** * Handle URL import. + * + * @return bool Whether the import was started. */ public static function handle_url_import() { $error_message = \__( 'Sorry, there has been an error.', 'activitypub' ); @@ -285,6 +291,8 @@ public static function handle_url_import() { /** * Import options. + * + * @return void */ public static function import_options() { self::setup_blog_user_filter(); @@ -301,6 +309,8 @@ public static function import_options() { /** * Setup blog user filter for dropdown. + * + * @return void */ private static function setup_blog_user_filter() { if ( is_user_type_disabled( 'blog' ) ) { @@ -322,6 +332,8 @@ private static function setup_blog_user_filter() { /** * Cleanup blog user filter. + * + * @return void */ private static function cleanup_blog_user_filter() { if ( self::$blog_user_filter_callback && self::$blog_user_filter_added ) { @@ -336,6 +348,8 @@ private static function cleanup_blog_user_filter() { * Render error message. * * @param \WP_Error $error The error to render. + * + * @return void */ private static function render_error( $error ) { \printf( @@ -349,6 +363,8 @@ private static function render_error( $error ) { * Render the import form. * * @param array $actors The actors to render. + * + * @return void */ private static function render_import_form( $actors ) { ?> @@ -369,6 +385,8 @@ private static function render_import_form( $actors ) { /** * Render starter kit information. + * + * @return void */ private static function render_starter_kit_info() { $name = empty( self::$starter_kit['name'] ) @@ -405,6 +423,8 @@ private static function render_starter_kit_info() { /** * Render author selection. + * + * @return void */ private static function render_author_selection() { ?> @@ -430,6 +450,8 @@ private static function render_author_selection() { * Render actor selection. * * @param array $actors The actors to render. + * + * @return void */ private static function render_actor_selection( $actors ) { ?> @@ -475,6 +497,8 @@ private static function is_valid_actor( $actor_uri ) { /** * Import. + * + * @return void */ public static function import() { $error_message = \__( 'Sorry, there has been an error.', 'activitypub' ); @@ -490,7 +514,7 @@ public static function import() { \wp_suspend_cache_invalidation( false ); - \wp_import_cleanup( self::$import_id ); + \wp_import_cleanup( (string) self::$import_id ); if ( \is_wp_error( $result ) ) { \printf( '<p><strong>%s</strong><br />%s</p>', \esc_html( $error_message ), \esc_html( $result->get_error_message() ) ); @@ -549,6 +573,8 @@ public static function follow() { /** * Intro. + * + * @return void */ public static function greet() { echo '<div class="narrow">'; @@ -589,6 +615,8 @@ public static function greet() { /** * Header. + * + * @return void */ public static function header() { echo '<div class="wrap">'; @@ -597,6 +625,8 @@ public static function header() { /** * Footer. + * + * @return void */ public static function footer() { echo '</div>'; @@ -604,6 +634,8 @@ public static function footer() { /** * Get actor list. + * + * @return array|\WP_Error The actors, or WP_Error when the file cannot be used. */ private static function get_actor_list() { $file = \get_attached_file( self::$import_id ); diff --git a/includes/wp-admin/import/load.php b/includes/wp-admin/import/load.php index ad4508e67c..35b21968ca 100644 --- a/includes/wp-admin/import/load.php +++ b/includes/wp-admin/import/load.php @@ -9,6 +9,8 @@ /** * Load importers. + * + * @return void */ function load() { require_once ABSPATH . 'wp-admin/includes/import.php'; diff --git a/includes/wp-admin/table/class-blocked-actors.php b/includes/wp-admin/table/class-blocked-actors.php index 2b950931cc..8be6c46a8c 100644 --- a/includes/wp-admin/table/class-blocked-actors.php +++ b/includes/wp-admin/table/class-blocked-actors.php @@ -58,6 +58,8 @@ public function __construct() { /** * Process action. + * + * @return void */ public function process_action() { if ( ! \current_user_can( 'edit_user', $this->user_id ) ) { @@ -154,6 +156,8 @@ public function process_action() { /** * Process admin notices based on query parameters. + * + * @return void */ public function process_admin_notices() { \settings_errors( 'activitypub' ); @@ -161,6 +165,8 @@ public function process_admin_notices() { /** * Prepare items. + * + * @return void */ public function prepare_items() { $page_num = $this->get_pagenum(); @@ -188,8 +194,8 @@ public function prepare_items() { $this->items = array(); $this->set_pagination_args( array( - 'total_items' => $counter, - 'total_pages' => \ceil( $counter / $per_page ), + 'total_items' => (int) $counter, + 'total_pages' => (int) \ceil( $counter / $per_page ), 'per_page' => $per_page, ) ); @@ -284,6 +290,8 @@ public function column_modified( $item ) { /** * Message to be displayed when there are no blocked actors. + * + * @return void */ public function no_items() { \esc_html_e( 'No blocked actors found.', 'activitypub' ); @@ -322,6 +330,8 @@ public function no_items() { * Single row. * * @param array $item Item. + * + * @return void */ public function single_row( $item ) { \printf( diff --git a/includes/wp-admin/table/class-followers.php b/includes/wp-admin/table/class-followers.php index 6629c0090a..7339afe07f 100644 --- a/includes/wp-admin/table/class-followers.php +++ b/includes/wp-admin/table/class-followers.php @@ -68,6 +68,8 @@ public function __construct() { /** * Process action. + * + * @return void */ public function process_action() { if ( ! \current_user_can( 'edit_user', $this->user_id ) ) { @@ -207,6 +209,8 @@ public function process_action() { /** * Process admin notices based on query parameters. + * + * @return void */ public function process_admin_notices() { \settings_errors( 'activitypub' ); @@ -214,6 +218,8 @@ public function process_admin_notices() { /** * Prepare items. + * + * @return void */ public function prepare_items() { $page_num = $this->get_pagenum(); @@ -240,8 +246,8 @@ public function prepare_items() { $this->items = array(); $this->set_pagination_args( array( - 'total_items' => $counter, - 'total_pages' => \ceil( $counter / $per_page ), + 'total_items' => (int) $counter, + 'total_pages' => (int) \ceil( $counter / $per_page ), 'per_page' => $per_page, ) ); @@ -370,6 +376,8 @@ public function column_modified( $item ) { /** * Message to be displayed when there are no followers. + * + * @return void */ public function no_items() { // phpcs:ignore WordPress.Security.NonceVerification.Recommended diff --git a/includes/wp-admin/table/class-following.php b/includes/wp-admin/table/class-following.php index 4db2e2f2ec..d816e15697 100644 --- a/includes/wp-admin/table/class-following.php +++ b/includes/wp-admin/table/class-following.php @@ -59,6 +59,8 @@ public function __construct() { /** * Process action. + * + * @return void */ public function process_action() { if ( ! \current_user_can( 'edit_user', $this->user_id ) ) { @@ -179,6 +181,8 @@ public function process_action() { /** * Process admin notices based on query parameters. + * + * @return void */ public function process_admin_notices() { \settings_errors( 'activitypub' ); @@ -186,6 +190,8 @@ public function process_admin_notices() { /** * Prepare items. + * + * @return void */ public function prepare_items() { $status = Following_Collection::ALL; @@ -224,8 +230,8 @@ public function prepare_items() { $this->items = array(); $this->set_pagination_args( array( - 'total_items' => $counter, - 'total_pages' => \ceil( $counter / $per_page ), + 'total_items' => (int) $counter, + 'total_pages' => (int) \ceil( $counter / $per_page ), 'per_page' => $per_page, ) ); @@ -400,6 +406,8 @@ public function column_modified( $item ) { /** * Message to be displayed when there are no followings. + * + * @return void */ public function no_items() { \esc_html_e( 'No profiles found.', 'activitypub' ); @@ -438,6 +446,8 @@ public function no_items() { * Single row. * * @param array $item Item. + * + * @return void */ public function single_row( $item ) { \printf( diff --git a/integration/class-akismet.php b/integration/class-akismet.php index 511cef3966..79dfeedaf3 100644 --- a/integration/class-akismet.php +++ b/integration/class-akismet.php @@ -17,6 +17,8 @@ class Akismet { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'comment_row_actions', array( self::class, 'comment_row_actions' ), 10, 2 ); diff --git a/integration/class-buddypress.php b/integration/class-buddypress.php index 4a0af9b851..5afb59fe2e 100644 --- a/integration/class-buddypress.php +++ b/integration/class-buddypress.php @@ -15,6 +15,8 @@ class Buddypress { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'activitypub_json_author_array', array( self::class, 'add_user_metadata' ), 11, 2 ); diff --git a/integration/class-classic-editor.php b/integration/class-classic-editor.php index 137370b267..0f412de8aa 100644 --- a/integration/class-classic-editor.php +++ b/integration/class-classic-editor.php @@ -16,6 +16,8 @@ class Classic_Editor { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'activitypub_attachments_media_markup', array( self::class, 'filter_attachments_media_markup' ), 10, 2 ); @@ -106,6 +108,8 @@ static function ( $id ) { * * @param string $post_type The post type. * @param \WP_Post|null $post The post being edited. + * + * @return void */ public static function add_meta_box( $post_type, $post = null ) { // Only add for post types that support ActivityPub. @@ -138,6 +142,8 @@ public static function add_meta_box( $post_type, $post = null ) { * Render the ActivityPub meta box. * * @param \WP_Post $post The post object. + * + * @return void */ public static function render_meta_box( $post ) { // Add nonce for security. @@ -260,6 +266,8 @@ private static function get_default_visibility( $post ) { * Save ActivityPub meta data. * * @param int $post_id The post ID. + * + * @return void */ public static function save_meta_data( $post_id ) { // Check if this is an autosave. diff --git a/integration/class-enable-mastodon-apps.php b/integration/class-enable-mastodon-apps.php index 428ea83a60..37a35d8f55 100644 --- a/integration/class-enable-mastodon-apps.php +++ b/integration/class-enable-mastodon-apps.php @@ -40,6 +40,8 @@ class Enable_Mastodon_Apps { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'mastodon_api_valid_user', array( self::class, 'is_ap_actor' ), 10, 2 ); @@ -175,6 +177,8 @@ private static function get_extra_fields( $user_id ) { * * @param int $user_id The user id to act on. * @param array $fields The fields to set. It is assumed to be the entire set of desired fields. + * + * @return void */ private static function set_extra_fields( $user_id, $fields ) { // The Mastodon API submits a simple hash for every field. @@ -315,8 +319,8 @@ public static function api_account_external( $user_data, $user_id ) { /** * Resolve internal accounts for Mastodon API * - * @param Account $user_data The user data. - * @param string $user_id The user id. + * @param Account|null $user_data The user data. + * @param string $user_id The user id. * * @return Account The filtered Account. */ @@ -1104,7 +1108,7 @@ public static function api_notifications_get( $notifications, $request, $limit = continue; } - $status = self::api_post_status( $comment->comment_post_ID ); + $status = self::api_post_status( (int) $comment->comment_post_ID ); if ( ! $status ) { continue; } diff --git a/integration/class-jetpack.php b/integration/class-jetpack.php index 7a24d97c66..fb046614c1 100644 --- a/integration/class-jetpack.php +++ b/integration/class-jetpack.php @@ -27,6 +27,8 @@ class Jetpack { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { if ( ! \defined( 'IS_WPCOM' ) ) { @@ -165,6 +167,8 @@ public static function pre_option_activitypub_following_ui() { /** * Adapt the parameters for a post share request to be compatible with the Federated Reply block. + * + * @return void */ public static function adapt_post_share() { if ( ! isset( $_GET['is_post_share'], $_GET['url'] ) || ! $_GET['is_post_share'] ) { // phpcs:ignore WordPress.Security diff --git a/integration/class-litespeed-cache.php b/integration/class-litespeed-cache.php index ab000facb3..f88f40d5f8 100644 --- a/integration/class-litespeed-cache.php +++ b/integration/class-litespeed-cache.php @@ -50,6 +50,8 @@ class Litespeed_Cache { /** * Initialize the integration. + * + * @return void */ public static function init() { // Add rules if LiteSpeed Cache is active and rules aren't set. @@ -75,6 +77,8 @@ public static function init() { * Clean up htaccess rules when LiteSpeed Cache plugin is deleted. * * @param string $plugin_file Path to the plugin file relative to the plugins directory. + * + * @return void */ public static function on_plugin_deleted( $plugin_file ) { if ( self::$plugin_slug === $plugin_file && \get_option( self::$option_name ) ) { @@ -84,6 +88,8 @@ public static function on_plugin_deleted( $plugin_file ) { /** * Add the LiteSpeed Cache htaccess rules. + * + * @return void */ public static function add_htaccess_rules() { $added_rules = self::append_with_markers( self::$marker, self::$rules ); @@ -98,6 +104,8 @@ public static function add_htaccess_rules() { /** * Remove the LiteSpeed Cache htaccess rules. + * + * @return void */ public static function remove_htaccess_rules() { self::append_with_markers( self::$marker, '' ); diff --git a/integration/class-multisite-language-switcher.php b/integration/class-multisite-language-switcher.php index c598cb2f5a..55ddc1c41f 100644 --- a/integration/class-multisite-language-switcher.php +++ b/integration/class-multisite-language-switcher.php @@ -17,6 +17,8 @@ class Multisite_Language_Switcher { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_action( 'save_post', array( self::class, 'ignore_outbox_post' ), 9, 2 ); @@ -28,6 +30,8 @@ public static function init() { * * @param int $post_id The post id. * @param \WP_Post $post The post object. + * + * @return void */ public static function ignore_outbox_post( $post_id, $post ) { if ( Outbox::POST_TYPE === $post->post_type ) { @@ -40,6 +44,8 @@ public static function ignore_outbox_post( $post_id, $post ) { * * @param int $post_id The post id. * @param \WP_Post $post The post object. + * + * @return void */ public static function unignore_outbox_post( $post_id, $post ) { if ( Outbox::POST_TYPE === $post->post_type ) { diff --git a/integration/class-nodeinfo.php b/integration/class-nodeinfo.php index f64096167f..6c5a5ad618 100644 --- a/integration/class-nodeinfo.php +++ b/integration/class-nodeinfo.php @@ -21,6 +21,8 @@ class Nodeinfo { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'nodeinfo_data', array( self::class, 'add_nodeinfo_data' ), 10, 2 ); diff --git a/integration/class-opengraph.php b/integration/class-opengraph.php index 83500a8b35..716bcff1ee 100644 --- a/integration/class-opengraph.php +++ b/integration/class-opengraph.php @@ -25,6 +25,8 @@ class Opengraph { * Initialize the class, registering WordPress hooks. * * Registered on `init`, so the setting is read once the site context is settled. + * + * @return void */ public static function init() { if ( '1' !== \get_option( 'activitypub_use_opengraph', '1' ) ) { @@ -98,6 +100,8 @@ public static function add_metadata( $metadata ) { /** * Output Open Graph <meta> tags in the page header. + * + * @return void */ public static function add_meta_tags() { $metadata = \apply_filters( 'opengraph_metadata', array() ); diff --git a/integration/class-polylang.php b/integration/class-polylang.php index de9571cde7..eeda73b67c 100644 --- a/integration/class-polylang.php +++ b/integration/class-polylang.php @@ -15,6 +15,8 @@ class Polylang { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'activitypub_locale', array( self::class, 'get_post_locale' ), 10, 2 ); diff --git a/integration/class-surge.php b/integration/class-surge.php index 6d012967dc..a9b4e95112 100644 --- a/integration/class-surge.php +++ b/integration/class-surge.php @@ -27,6 +27,8 @@ class Surge { /** * Initialize the Surge integration. + * + * @return void */ public static function init() { \add_action( 'activate_surge/surge.php', array( self::class, 'add_cache_config' ) ); @@ -37,6 +39,8 @@ public static function init() { /** * Add the Surge cache config. + * + * @return void */ public static function add_cache_config() { // Check if surge is installed and active. @@ -82,6 +86,8 @@ public static function add_cache_config() { /** * Remove the Surge cache config. + * + * @return void */ public static function remove_cache_config() { if ( ! \defined( 'WP_CACHE_CONFIG' ) ) { diff --git a/integration/class-webfinger.php b/integration/class-webfinger.php index e55fe6a226..c122677bfa 100644 --- a/integration/class-webfinger.php +++ b/integration/class-webfinger.php @@ -19,6 +19,8 @@ class Webfinger { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'webfinger_user_data', array( self::class, 'add_user_discovery' ), 1, 3 ); diff --git a/integration/class-wpml.php b/integration/class-wpml.php index c2fee3b9d4..5d61e7535f 100644 --- a/integration/class-wpml.php +++ b/integration/class-wpml.php @@ -15,6 +15,8 @@ class WPML { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'activitypub_locale', array( self::class, 'get_wpml_post_locale' ), 10, 2 ); diff --git a/integration/class-yoast-seo.php b/integration/class-yoast-seo.php index d4f0d18461..768777a7c0 100644 --- a/integration/class-yoast-seo.php +++ b/integration/class-yoast-seo.php @@ -14,6 +14,8 @@ class Yoast_Seo { /** * Initialize the class, registering WordPress hooks. + * + * @return void */ public static function init() { \add_filter( 'site_status_tests', array( self::class, 'add_site_health_tests' ), 11 ); // After Health_Check::add_tests(). diff --git a/integration/load.php b/integration/load.php index 18c6499f6e..7dc8a8ba7a 100644 --- a/integration/load.php +++ b/integration/load.php @@ -15,6 +15,8 @@ /** * Initialize the ActivityPub integrations. + * + * @return void */ function plugin_init() { /** diff --git a/integration/stream/class-stream.php b/integration/stream/class-stream.php index 56730b30ce..5094931c6c 100644 --- a/integration/stream/class-stream.php +++ b/integration/stream/class-stream.php @@ -17,6 +17,8 @@ class Stream { /** * Initialize the Stream integration. + * + * @return void */ public static function init() { \add_filter( 'wp_stream_connectors', array( self::class, 'register_connector' ) ); diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 0000000000..ff6f4681ad --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,601 @@ +parameters: + ignoreErrors: + - + message: '#^Unable to resolve the template type TUrl in call to function wp_http_validate_url$#' + identifier: argument.templateType + count: 1 + path: includes/activity/class-generic-object.php + + - + message: '#^Unsafe usage of new static\(\)\.$#' + identifier: new.static + count: 1 + path: includes/activity/class-generic-object.php + + - + message: '#^Negated boolean expression is always false\.$#' + identifier: booleanNot.alwaysFalse + count: 1 + path: includes/cache/class-file.php + + - + message: '#^Negated boolean expression is always true\.$#' + identifier: booleanNot.alwaysTrue + count: 1 + path: includes/cache/class-file.php + + - + message: '#^Result of \|\| is always true\.$#' + identifier: booleanOr.alwaysTrue + count: 1 + path: includes/cache/class-file.php + + - + message: '#^Unable to resolve the template type TUrl in call to function wp_http_validate_url$#' + identifier: argument.templateType + count: 1 + path: includes/class-attachments.php + + - + message: '#^Property WP_Comment\:\:\$comment_type \(string\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: includes/class-avatars.php + + - + message: '#^Call to method get\(\) on an unknown class Activitypub\\WP_Query\.$#' + identifier: class.notFound + count: 1 + path: includes/class-blocks.php + + - + message: '#^Call to method is_feed\(\) on an unknown class Activitypub\\WP_Query\.$#' + identifier: class.notFound + count: 1 + path: includes/class-blocks.php + + - + message: '#^Call to method is_main_query\(\) on an unknown class Activitypub\\WP_Query\.$#' + identifier: class.notFound + count: 1 + path: includes/class-blocks.php + + - + message: '#^Call to method is_singular\(\) on an unknown class Activitypub\\WP_Query\.$#' + identifier: class.notFound + count: 1 + path: includes/class-blocks.php + + - + message: '#^Method Activitypub\\Blocks\:\:get_user_id\(\) should return int\|null but returns string\.$#' + identifier: return.type + count: 2 + path: includes/class-blocks.php + + - + message: '#^Method Activitypub\\Blocks\:\:render_reply_block\(\) should return string but returns null\.$#' + identifier: return.type + count: 1 + path: includes/class-blocks.php + + - + message: '#^Parameter \$query of method Activitypub\\Blocks\:\:filter_query_loop_vars\(\) has invalid type Activitypub\\WP_Query\.$#' + identifier: class.notFound + count: 1 + path: includes/class-blocks.php + + - + message: '#^Comparison operation "\<" between int\<1, max\> and 1 is always false\.$#' + identifier: smaller.alwaysFalse + count: 2 + path: includes/class-blurhash.php + + - + message: '#^Offset 0 on array\{0\: int\<0, max\>, 1\: int\<0, max\>, 2\: int, 3\: string, mime\: string, channels\?\: int, bits\?\: int\} in isset\(\) always exists and is not nullable\.$#' + identifier: isset.offset + count: 1 + path: includes/class-blurhash.php + + - + message: '#^Offset 1 on array\{0\: int\<0, max\>, 1\: int\<0, max\>, 2\: int, 3\: string, mime\: string, channels\?\: int, bits\?\: int\} in isset\(\) always exists and is not nullable\.$#' + identifier: isset.offset + count: 1 + path: includes/class-blurhash.php + + - + message: '#^Result of \|\| is always false\.$#' + identifier: booleanOr.alwaysFalse + count: 1 + path: includes/class-blurhash.php + + - + message: '#^Static method Activitypub\\Comment\:\:post_has_remote_comments\(\) is unused\.$#' + identifier: method.unused + count: 1 + path: includes/class-comment.php + + - + message: '#^@param int \$actor_id does not accept actual type of parameter\: ''''\|numeric\-string\.$#' + identifier: parameter.phpDocType + count: 4 + path: includes/class-dispatcher.php + + - + message: '#^@param int \$user_id does not accept actual type of parameter\: ''''\|numeric\-string\.$#' + identifier: parameter.phpDocType + count: 1 + path: includes/class-dispatcher.php + + - + message: '#^Expected 1 @param tags, found 4\.$#' + identifier: paramTag.count + count: 1 + path: includes/class-migration.php + + - + message: '#^Strict comparison using \!\=\= between ''1'' and mixed~''1'' will always evaluate to true\.$#' + identifier: notIdentical.alwaysTrue + count: 1 + path: includes/class-migration.php + + - + message: '#^If condition is always false\.$#' + identifier: if.alwaysFalse + count: 1 + path: includes/class-options.php + + - + message: '#^Strict comparison using \=\=\= between false and false will always evaluate to true\.$#' + identifier: identical.alwaysTrue + count: 1 + path: includes/class-options.php + + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: includes/class-options.php + + - + message: '#^Parameter \#2 \$args of function register_post_type expects array\{label\?\: string, labels\?\: array\<string\>, description\?\: string, public\?\: bool, hierarchical\?\: bool, exclude_from_search\?\: bool, publicly_queryable\?\: bool, show_ui\?\: bool, \.\.\.\}, array\{labels\: array\{name\: string, singular_name\: string\}, capabilities\: array\{create_posts\: false\}, map_meta_cap\: true, public\: false, show_in_rest\: false, rewrite\: false, query_var\: false, supports\: array\{''title'', ''editor'', ''author'', ''custom\-fields''\}, \.\.\.\} given\.$#' + identifier: argument.type + count: 2 + path: includes/class-post-types.php + + - + message: '#^Parameter \#2 \$args of function register_post_type expects array\{label\?\: string, labels\?\: array\<string\>, description\?\: string, public\?\: bool, hierarchical\?\: bool, exclude_from_search\?\: bool, publicly_queryable\?\: bool, show_ui\?\: bool, \.\.\.\}, array\{labels\: array\{name\: string, singular_name\: string\}, map_meta_cap\: true, public\: false, capabilities\: array\{create_posts\: false\}, show_in_rest\: true, rest_controller_class\: ''Activitypub\\\\Rest\\\\Remote_Posts_Controller'', rewrite\: false, query_var\: false, \.\.\.\} given\.$#' + identifier: argument.type + count: 1 + path: includes/class-post-types.php + + - + message: '#^Parameter \#2 \$args of function register_post_type expects array\{label\?\: string, labels\?\: array\<string\>, description\?\: string, public\?\: bool, hierarchical\?\: bool, exclude_from_search\?\: bool, publicly_queryable\?\: bool, show_ui\?\: bool, \.\.\.\}, array\{labels\: array\{name\: string, singular_name\: string\}, public\: false, capabilities\: array\{create_posts\: false\}, show_in_rest\: true, rest_controller_class\: ''Activitypub\\\\Rest\\\\Remote_Actors_Controller'', hierarchical\: false, rewrite\: false, query_var\: false, \.\.\.\} given\.$#' + identifier: argument.type + count: 1 + path: includes/class-post-types.php + + - + message: '#^Cannot access property \$meta_id on object\|true\.$#' + identifier: property.nonObject + count: 1 + path: includes/class-query.php + + - + message: '#^Cannot access property \$meta_key on object\|true\.$#' + identifier: property.nonObject + count: 1 + path: includes/class-query.php + + - + message: '#^Cannot access property \$meta_value on object\|true\.$#' + identifier: property.nonObject + count: 1 + path: includes/class-query.php + + - + message: '#^Cannot access property \$post_id on object\|true\.$#' + identifier: property.nonObject + count: 1 + path: includes/class-query.php + + - + message: '#^Property Activitypub\\Query\:\:\$is_activitypub_request \(bool\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: includes/class-query.php + + - + message: '#^Property Activitypub\\Query\:\:\$is_old_host_request \(bool\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: includes/class-query.php + + - + message: '#^Static property Activitypub\\Query\:\:\$instance \(Activitypub\\Query\) does not accept null\.$#' + identifier: assign.propertyType + count: 1 + path: includes/class-query.php + + - + message: '#^Static property Activitypub\\Query\:\:\$instance \(Activitypub\\Query\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: includes/class-query.php + + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: includes/class-query.php + + - + message: '#^If condition is always false\.$#' + identifier: if.alwaysFalse + count: 1 + path: includes/class-router.php + + - + message: '#^Method Activitypub\\Router\:\:redirect_canonical\(\) should return string but returns null\.$#' + identifier: return.type + count: 2 + path: includes/class-router.php + + - + message: '#^Method Activitypub\\Sanitize\:\:constant_value\(\) should return string but returns mixed\.$#' + identifier: return.type + count: 1 + path: includes/class-sanitize.php + + - + message: '#^Call to function is_wp_error\(\) with non\-empty\-array\<mixed, mixed\> will always evaluate to false\.$#' + identifier: function.impossibleType + count: 2 + path: includes/class-scheduler.php + + - + message: '#^Unable to resolve the template type TUrl in call to function wp_http_validate_url$#' + identifier: argument.templateType + count: 1 + path: includes/class-search.php + + - + message: '#^Call to function is_wp_error\(\) with non\-empty\-array\<mixed, mixed\> will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: includes/collection/class-followers.php + + - + message: '#^Argument of an invalid type stdClass supplied for foreach, only iterables are supported\.$#' + identifier: foreach.nonIterable + count: 1 + path: includes/collection/class-inbox.php + + - + message: '#^Expression on left side of \?\? is not nullable\.$#' + identifier: nullCoalesce.expr + count: 1 + path: includes/collection/class-inbox.php + + - + message: '#^If condition is always false\.$#' + identifier: if.alwaysFalse + count: 1 + path: includes/collection/class-inbox.php + + - + message: '#^Callback expects 0 parameters, \$accepted_args is set to 4\.$#' + identifier: arguments.count + count: 1 + path: includes/collection/class-interactions.php + + - + message: '#^Argument of an invalid type stdClass supplied for foreach, only iterables are supported\.$#' + identifier: foreach.nonIterable + count: 1 + path: includes/collection/class-outbox.php + + - + message: '#^Parameter \#1 \$post_id of function Activitypub\\get_content_visibility expects int\|WP_Post, array given\.$#' + identifier: argument.type + count: 2 + path: includes/collection/class-posts.php + + - + message: '#^Method Activitypub\\Collection\\Remote_Actors\:\:persist\(\) never returns WP_Error so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: includes/collection/class-remote-actors.php + + - + message: '#^Argument of an invalid type stdClass supplied for foreach, only iterables are supported\.$#' + identifier: foreach.nonIterable + count: 1 + path: includes/collection/class-remote-posts.php + + - + message: '#^Variable \$post_ids in empty\(\) always exists and is not falsy\.$#' + identifier: empty.variable + count: 1 + path: includes/collection/class-remote-posts.php + + - + message: '#^Function Activitypub\\add_to_outbox\(\) should return bool\|int but returns WP_Error\.$#' + identifier: return.type + count: 1 + path: includes/functions-federation.php + + - + message: '#^Result of && is always false\.$#' + identifier: booleanAnd.alwaysFalse + count: 1 + path: includes/functions.php + + - + message: '#^Strict comparison using \=\=\= between 0 and \(float\|false\) will always evaluate to false\.$#' + identifier: identical.alwaysFalse + count: 2 + path: includes/functions.php + + - + message: '#^Expected 1 @param tags, found 3\.$#' + identifier: paramTag.count + count: 1 + path: includes/handler/class-collection-sync.php + + - + message: '#^Action callback returns bool but should not return anything\.$#' + identifier: return.void + count: 2 + path: includes/handler/class-delete.php + + - + message: '#^@param string\|WP_Comment \$result does not accept actual type of parameter\: bool\|WP_Error\.$#' + identifier: parameter.phpDocType + count: 1 + path: includes/handler/class-undo.php + + - + message: '#^Action callback returns bool but should not return anything\.$#' + identifier: return.void + count: 1 + path: includes/handler/class-undo.php + + - + message: '#^Method Activitypub\\Handler\\Outbox\\Follow\:\:handle_follow\(\) should return int\|WP_Error but returns array\.$#' + identifier: return.type + count: 1 + path: includes/handler/outbox/class-follow.php + + - + message: '#^Method Activitypub\\Handler\\Outbox\\Undo\:\:handle_undo\(\) should return int\|WP_Error but returns array\.$#' + identifier: return.type + count: 3 + path: includes/handler/outbox/class-undo.php + + - + message: '#^@param tag must not be named \$this\. Choose a descriptive alias, for example \$instance\.$#' + identifier: phpDoc.parseError + count: 1 + path: includes/model/class-blog.php + + - + message: '#^Method Activitypub\\Model\\Blog\:\:get_tag\(\) should return array\<string\> but returns list\<array\<string, string\>\>\.$#' + identifier: return.type + count: 1 + path: includes/model/class-blog.php + + - + message: '#^PHPDoc type array of property Activitypub\\Model\\Blog\:\:\$generator is not covariant with PHPDoc type string\|null of overridden property Activitypub\\Activity\\Base_Object\:\:\$generator\.$#' + identifier: property.phpDocType + count: 1 + path: includes/model/class-blog.php + + - + message: '#^@param tag must not be named \$this\. Choose a descriptive alias, for example \$instance\.$#' + identifier: phpDoc.parseError + count: 1 + path: includes/model/class-user.php + + - + message: '#^PHPDoc type array of property Activitypub\\Model\\User\:\:\$generator is not covariant with PHPDoc type string\|null of overridden property Activitypub\\Activity\\Base_Object\:\:\$generator\.$#' + identifier: property.phpDocType + count: 1 + path: includes/model/class-user.php + + - + message: '#^Unsafe usage of new static\(\)\.$#' + identifier: new.static + count: 1 + path: includes/model/class-user.php + + - + message: '#^Property Activitypub\\OAuth\\Token\:\:\$token_key is never read, only written\.$#' + identifier: property.onlyWritten + count: 1 + path: includes/oauth/class-token.php + + - + message: '#^Call to function is_wp_error\(\) with array\{id\: mixed, type\: ''OrderedCollection'', totalItems\: int\<0, max\>, orderedItems\: mixed, ''@context''\: mixed\} will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: includes/rest/class-moderators-controller.php + + - + message: '#^Offset ''@context'' on array\{id\: mixed, type\: ''OrderedCollection'', totalItems\: int\<0, max\>, orderedItems\: mixed\} in empty\(\) does not exist\.$#' + identifier: empty.offset + count: 1 + path: includes/rest/class-moderators-controller.php + + - + message: '#^Method Activitypub\\Rest\\Outbox_Controller\:\:prepare_item_for_response\(\) should return array but returns WP_Error\.$#' + identifier: return.type + count: 1 + path: includes/rest/class-outbox-controller.php + + - + message: '#^Return type \(array\) of method Activitypub\\Rest\\Outbox_Controller\:\:prepare_item_for_response\(\) should be compatible with return type \(WP_Error\|WP_REST_Response\) of method WP_REST_Controller\:\:prepare_item_for_response\(\)$#' + identifier: method.childReturnType + count: 1 + path: includes/rest/class-outbox-controller.php + + - + message: '#^Left side of && is always false\.$#' + identifier: booleanAnd.leftAlwaysFalse + count: 1 + path: includes/rest/class-server.php + + - + message: '#^Method Activitypub\\Rest\\OAuth\\Token_Controller\:\:handle_authorization_code_grant\(\) never returns WP_Error so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: includes/rest/oauth/class-token-controller.php + + - + message: '#^Method Activitypub\\Rest\\OAuth\\Token_Controller\:\:handle_refresh_token_grant\(\) never returns WP_Error so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: includes/rest/oauth/class-token-controller.php + + - + message: '#^Action callback returns mixed but should not return anything\.$#' + identifier: return.void + count: 15 + path: includes/scheduler/class-actor.php + + - + message: '#^Callback expects 1 parameter, \$accepted_args is set to 3\.$#' + identifier: arguments.count + count: 1 + path: includes/scheduler/class-actor.php + + - + message: '#^If condition is always false\.$#' + identifier: if.alwaysFalse + count: 1 + path: includes/scheduler/class-comment.php + + - + message: '#^Method Activitypub\\Signature\\Http_Signature_Draft\:\:get_signed_data\(\) should return string but returns false\.$#' + identifier: return.type + count: 8 + path: includes/signature/class-http-signature-draft.php + + - + message: '#^Method Activitypub\\Transformer\\Activity_Object\:\:get_content_map\(\) should return array but returns null\.$#' + identifier: return.type + count: 1 + path: includes/transformer/class-activity-object.php + + - + message: '#^Method Activitypub\\Transformer\\Activity_Object\:\:get_name_map\(\) should return array but returns null\.$#' + identifier: return.type + count: 1 + path: includes/transformer/class-activity-object.php + + - + message: '#^Method Activitypub\\Transformer\\Activity_Object\:\:get_summary_map\(\) should return array but returns null\.$#' + identifier: return.type + count: 1 + path: includes/transformer/class-activity-object.php + + - + message: '#^Class WP_Term referenced with incorrect case\: WP_term\.$#' + identifier: class.nameCase + count: 1 + path: includes/transformer/class-base.php + + - + message: '#^Method Activitypub\\Transformer\\Base\:\:get_attributed_to\(\) should return string but returns null\.$#' + identifier: return.type + count: 1 + path: includes/transformer/class-base.php + + - + message: '#^Method Activitypub\\Transformer\\Base\:\:to_object\(\) should return Activitypub\\Activity\\Base_Object but returns WP_Error\.$#' + identifier: return.type + count: 1 + path: includes/transformer/class-base.php + + - + message: '#^Unsafe usage of new static\(\)\.$#' + identifier: new.static + count: 1 + path: includes/transformer/class-base.php + + - + message: '#^Method Activitypub\\Transformer\\Comment\:\:get_context\(\) should return string but returns null\.$#' + identifier: return.type + count: 1 + path: includes/transformer/class-comment.php + + - + message: '#^Access to an undefined property Activitypub\\Activity\\Base_Object\:\:\$@context\.$#' + identifier: property.notFound + count: 1 + path: includes/transformer/class-term.php + + - + message: '#^Right side of && is always false\.$#' + identifier: booleanAnd.rightAlwaysFalse + count: 1 + path: includes/wp-admin/class-settings-fields.php + + - + message: '#^Static property Activitypub\\WP_Admin\\Import\\Starter_Kit\:\:\$blog_user_filter_callback \(callable\(\)\: mixed\) does not accept null\.$#' + identifier: assign.propertyType + count: 1 + path: includes/wp-admin/import/class-starter-kit.php + + - + message: '#^Static property Activitypub\\WP_Admin\\Import\\Starter_Kit\:\:\$file is unused\.$#' + identifier: property.unused + count: 1 + path: includes/wp-admin/import/class-starter-kit.php + + - + message: '#^Static property Activitypub\\WP_Admin\\Import\\Starter_Kit\:\:\$starter_kit \(object\) does not accept mixed\.$#' + identifier: assign.propertyType + count: 1 + path: includes/wp-admin/import/class-starter-kit.php + + - + message: '#^Parameter \#1 \$user_id of static method Activitypub\\Collection\\Followers\:\:count\(\) expects int, string given\.$#' + identifier: argument.type + count: 1 + path: integration/class-enable-mastodon-apps.php + + - + message: '#^Parameter \#1 \$user_id of static method Activitypub\\Integration\\Enable_Mastodon_Apps\:\:maybe_map_user_to_blog\(\) expects int, string given\.$#' + identifier: argument.type + count: 2 + path: integration/class-enable-mastodon-apps.php + + - + message: '#^Unable to resolve the template type T in call to function wp_unslash$#' + identifier: argument.templateType + count: 1 + path: integration/class-enable-mastodon-apps.php + + - + message: '#^Call to function method_exists\(\) with ''Automattic\\\\Jetpack\\\\Podcast\\\\Feed\\\\Customize_Feed'' and ''resolve_category_id'' will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: integration/class-jetpack.php + + - + message: '#^Call to function method_exists\(\) with ''Automattic\\\\Jetpack\\\\Podcast\\\\Feed\\\\Episode_Block_Tags'' and ''get_block_attrs'' will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: integration/class-jetpack.php + + - + message: '#^Call to function method_exists\(\) with ''Automattic\\\\Jetpack\\\\Podcast\\\\Settings'' and ''raw_show_image_url'' will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: integration/class-jetpack.php + + - + message: '#^Action callback returns null but should not return anything\.$#' + identifier: return.void + count: 1 + path: integration/class-multisite-language-switcher.php diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000000..d1ef4a51a4 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,43 @@ +includes: + - vendor/szepeviktor/phpstan-wordpress/extension.neon + - phpstan-baseline.neon + +parameters: + level: 6 + phpVersion: 70400 + paths: + - includes + - integration + - activitypub.php + excludePaths: + # Extends a class from the Stream plugin, which PHPStan cannot analyse without it. + - integration/stream/class-connector.php + bootstrapFiles: + - tests/phpstan/bootstrap.php + scanFiles: + - tests/phpstan/stubs/wp-cli.php + - tests/phpstan/stubs/wp-cli-utils.php + stubFiles: + # Core documents the escaping functions as taking a string, but they convert any scalar. + - tests/phpstan/stubs/escaping.stub + treatPhpDocTypesAsCertain: false + # Keep the baseline in sync when findings are fixed, rather than hiding regressions. + reportUnmatchedIgnoredErrors: true + ignoreErrors: + # `array<string, mixed>` generics in every array docblock; WordPress code + # does not carry them, and on PHP 7.4 they could only live in docblocks. + - identifier: missingType.iterableValue + # Integrations talk to other plugins that are not installed here. + - + identifiers: + - class.notFound + - function.notFound + paths: + - integration/* + +services: + # `Generic_Object::__call()` answers get_*/set_*/add_* from the object's attributes. + - + class: Activitypub\PHPStan\Magic_Accessors_Extension + tags: + - phpstan.broker.methodsClassReflectionExtension diff --git a/tests/README.md b/tests/README.md index 79060bf181..3dde6e25cb 100644 --- a/tests/README.md +++ b/tests/README.md @@ -11,6 +11,10 @@ This file provides detailed testing patterns and examples. For basic test comman ## Test Organization +### PHPStan Extension Tests + +Tests for the development-only PHPStan extension live in `tests/phpstan/tests/`, with a `class-test-` file matching the extension's source file. Helpers and fixtures live in `tests/phpstan/data/`. These tests use PHPStan's testing base class rather than WordPress's, and run independently of WordPress and Docker with `composer analyze:test`. + ### PHP Test Structure ``` diff --git a/tests/phpstan/bootstrap-tests.php b/tests/phpstan/bootstrap-tests.php new file mode 100644 index 0000000000..f6ce2ed130 --- /dev/null +++ b/tests/phpstan/bootstrap-tests.php @@ -0,0 +1,14 @@ +<?php +/** + * Bootstrap the standalone PHPStan extension tests. + * + * @package Activitypub + */ + +use Activitypub\Autoloader; + +require_once __DIR__ . '/../../vendor/autoload.php'; +require_once __DIR__ . '/../../includes/class-autoloader.php'; + +Autoloader::register_path( 'Activitypub', __DIR__ . '/../../includes/' ); +Autoloader::register_path( 'Activitypub\Tests\PHPStan', __DIR__ . '/data/' ); diff --git a/tests/phpstan/bootstrap.php b/tests/phpstan/bootstrap.php new file mode 100644 index 0000000000..b5929277b7 --- /dev/null +++ b/tests/phpstan/bootstrap.php @@ -0,0 +1,11 @@ +<?php +/** + * Constants the plugin defines at runtime, for static analysis. + * + * @package Activitypub + */ + +\define( 'ACTIVITYPUB_PLUGIN_DIR', \dirname( __DIR__, 2 ) . '/' ); +\define( 'ACTIVITYPUB_PLUGIN_URL', 'https://example.com/wp-content/plugins/activitypub/' ); +\define( 'ACTIVITYPUB_PLUGIN_BASENAME', 'activitypub/activitypub.php' ); +\define( 'WPINC', 'wp-includes' ); diff --git a/tests/phpstan/class-magic-accessor.php b/tests/phpstan/class-magic-accessor.php new file mode 100644 index 0000000000..81925ba637 --- /dev/null +++ b/tests/phpstan/class-magic-accessor.php @@ -0,0 +1,125 @@ +<?php +/** + * One dynamic accessor of the activity objects, as PHPStan sees it. + * + * @package Activitypub + */ + +namespace Activitypub\PHPStan; + +use PHPStan\Reflection\ClassMemberReflection; +use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\FunctionVariant; +use PHPStan\Reflection\MethodReflection; +use PHPStan\Reflection\Native\NativeParameterReflection; +use PHPStan\TrinaryLogic; +use PHPStan\Type\Generic\TemplateTypeMap; +use PHPStan\Type\Type; + +/** + * One accessor as PHPStan sees it. + */ +class Magic_Accessor implements MethodReflection { + /** + * The class the accessor belongs to. + * + * @var ClassReflection + */ + private $class_reflection; + + /** + * The method name. + * + * @var string + */ + private $name; + + /** + * The parameters. + * + * @var NativeParameterReflection[] + */ + private $parameters; + + /** + * The return type. + * + * @var Type + */ + private $return_type; + + /** + * Constructor. + * + * @param ClassReflection $class_reflection The class. + * @param string $name The method name. + * @param NativeParameterReflection[] $parameters The parameters. + * @param Type $return_type The return type. + */ + public function __construct( ClassReflection $class_reflection, string $name, array $parameters, Type $return_type ) { + $this->class_reflection = $class_reflection; + $this->name = $name; + $this->parameters = $parameters; + $this->return_type = $return_type; + } + + // phpcs:disable WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid, Squiz.Commenting.FunctionComment.Missing + + public function getDeclaringClass(): ClassReflection { + return $this->class_reflection; + } + + public function isStatic(): bool { + return false; + } + + public function isPrivate(): bool { + return false; + } + + public function isPublic(): bool { + return true; + } + + public function getDocComment(): ?string { + return null; + } + + public function getName(): string { + return $this->name; + } + + public function getPrototype(): ClassMemberReflection { + return $this; + } + + public function getVariants(): array { + return array( new FunctionVariant( TemplateTypeMap::createEmpty(), null, $this->parameters, false, $this->return_type ) ); + } + + public function isDeprecated(): TrinaryLogic { + return TrinaryLogic::createNo(); + } + + public function getDeprecatedDescription(): ?string { + return null; + } + + public function isFinal(): TrinaryLogic { + return TrinaryLogic::createNo(); + } + + public function isInternal(): TrinaryLogic { + return TrinaryLogic::createNo(); + } + + public function getThrowType(): ?Type { + return null; + } + + public function hasSideEffects(): TrinaryLogic { + return TrinaryLogic::createMaybe(); + } + + // phpcs:enable +} diff --git a/tests/phpstan/class-magic-accessors-extension.php b/tests/phpstan/class-magic-accessors-extension.php new file mode 100644 index 0000000000..e4089947cb --- /dev/null +++ b/tests/phpstan/class-magic-accessors-extension.php @@ -0,0 +1,85 @@ +<?php +/** + * PHPStan extension for the dynamic accessors of the activity objects. + * + * @package Activitypub + */ + +namespace Activitypub\PHPStan; + +use Activitypub\Activity\Base_Object; +use Activitypub\Activity\Generic_Object; +use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\MethodReflection; +use PHPStan\Reflection\MethodsClassReflectionExtension; +use PHPStan\Reflection\Native\NativeParameterReflection; +use PHPStan\Reflection\PassedByReference; +use PHPStan\Type\ArrayType; +use PHPStan\Type\MixedType; +use PHPStan\Type\ObjectType; +use PHPStan\Type\StaticType; +use PHPStan\Type\TypeCombinator; + +/** + * Teaches PHPStan the `get_*()`, `set_*()` and `add_*()` methods dispatched by + * Generic_Object and its descendants. The attribute is the method name after + * the prefix, lower-cased. + * + * A getter has the declared type of the attribute, or `null` when the object + * does not carry it; an attribute the class does not declare may still be set + * dynamically, so it is `mixed`. Setters return the object; adders return an + * array or null. Base objects can reject undeclared properties with WP_Error. + */ +class Magic_Accessors_Extension implements MethodsClassReflectionExtension { + /** + * Whether the class answers the method through `__call()`. + * + * @param ClassReflection $class_reflection The class. + * @param string $method_name The method name. + * + * @return bool + */ + public function hasMethod( ClassReflection $class_reflection, string $method_name ): bool { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid + if ( Generic_Object::class !== $class_reflection->getName() && ! $class_reflection->isSubclassOf( Generic_Object::class ) ) { + return false; + } + + if ( Generic_Object::class !== $class_reflection->getNativeMethod( '__call' )->getDeclaringClass()->getName() ) { + return false; + } + + return 1 === \preg_match( '/^(get|set|add)_.+$/i', $method_name ); + } + + /** + * Build the signature `__call()` implements. + * + * @param ClassReflection $class_reflection The class. + * @param string $method_name The method name. + * + * @return MethodReflection + */ + public function getMethod( ClassReflection $class_reflection, string $method_name ): MethodReflection { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid + $method_name = \strtolower( $method_name ); + $attribute = \substr( $method_name, 4 ); + + if ( 0 === \strpos( $method_name, 'get' ) ) { + $type = $class_reflection->hasNativeProperty( $attribute ) + ? TypeCombinator::addNull( $class_reflection->getNativeProperty( $attribute )->getReadableType() ) + : new MixedType(); + + return new Magic_Accessor( $class_reflection, $method_name, array(), $type ); + } + + $value = new NativeParameterReflection( 'value', false, new MixedType(), PassedByReference::createNo(), false, null ); + $type = 0 === \strpos( $method_name, 'add' ) + ? TypeCombinator::addNull( new ArrayType( new MixedType(), new MixedType() ) ) + : new StaticType( $class_reflection ); + + if ( ! $class_reflection->hasNativeProperty( $attribute ) && ( Base_Object::class === $class_reflection->getName() || $class_reflection->isSubclassOf( Base_Object::class ) ) ) { + $type = TypeCombinator::union( $type, new ObjectType( 'WP_Error' ) ); + } + + return new Magic_Accessor( $class_reflection, $method_name, array( $value ), $type ); + } +} diff --git a/tests/phpstan/data/class-overridden-magic-object.php b/tests/phpstan/data/class-overridden-magic-object.php new file mode 100644 index 0000000000..df51c27128 --- /dev/null +++ b/tests/phpstan/data/class-overridden-magic-object.php @@ -0,0 +1,26 @@ +<?php +/** + * An activity object with its own magic dispatcher. + * + * @package Activitypub + */ + +namespace Activitypub\Tests\PHPStan; + +use Activitypub\Activity\Generic_Object; + +/** + * An activity object that overrides the generic accessor dispatcher. + */ +class Overridden_Magic_Object extends Generic_Object { + /** + * Dispatch a method. + * + * @param string $method The method. + * @param array $params The parameters. + * @return mixed + */ + public function __call( $method, $params ) { + return $params[ $method ] ?? null; + } +} diff --git a/tests/phpstan/data/class-unrelated-magic-object.php b/tests/phpstan/data/class-unrelated-magic-object.php new file mode 100644 index 0000000000..e7108039a0 --- /dev/null +++ b/tests/phpstan/data/class-unrelated-magic-object.php @@ -0,0 +1,24 @@ +<?php +/** + * Magic dispatchers that do not implement Generic_Object's accessors. + * + * @package Activitypub + */ + +namespace Activitypub\Tests\PHPStan; + +/** + * An unrelated class with a magic dispatcher. + */ +class Unrelated_Magic_Object { + /** + * Dispatch a method. + * + * @param string $method The method. + * @param array $params The parameters. + * @return mixed + */ + public function __call( $method, $params ) { + return $params[ $method ] ?? null; + } +} diff --git a/tests/phpstan/phpunit.xml.dist b/tests/phpstan/phpunit.xml.dist new file mode 100644 index 0000000000..69790faadc --- /dev/null +++ b/tests/phpstan/phpunit.xml.dist @@ -0,0 +1,8 @@ +<?xml version="1.0"?> +<phpunit bootstrap="bootstrap-tests.php" colors="true"> + <testsuites> + <testsuite name="PHPStan extensions"> + <directory suffix=".php">tests</directory> + </testsuite> + </testsuites> +</phpunit> diff --git a/tests/phpstan/stubs/escaping.stub b/tests/phpstan/stubs/escaping.stub new file mode 100644 index 0000000000..9c37315eae --- /dev/null +++ b/tests/phpstan/stubs/escaping.stub @@ -0,0 +1,18 @@ +<?php +/** + * Core documents the escaping functions as taking a string, but they convert any scalar. + * + * @package Activitypub + */ + +/** + * @param string|int|float $text + * @return string + */ +function esc_attr( $text ) {} + +/** + * @param string|int|float $text + * @return string + */ +function esc_html( $text ) {} diff --git a/tests/phpstan/stubs/wp-cli-utils.php b/tests/phpstan/stubs/wp-cli-utils.php new file mode 100644 index 0000000000..c03475f5fc --- /dev/null +++ b/tests/phpstan/stubs/wp-cli-utils.php @@ -0,0 +1,26 @@ +<?php +/** + * Minimal WP-CLI utility stubs for static analysis: only what the plugin calls. + * + * @package Activitypub + */ + +// phpcs:ignoreFile + +namespace WP_CLI\Utils; + +/** + * @param array<string, mixed> $assoc_args + * @param string $flag + * @param mixed $default_value + * @return mixed + */ +function get_flag_value( $assoc_args, $flag, $default_value = null ) {} + +/** + * @param string $format + * @param array<int, mixed> $items + * @param array<int, string>|string $fields + * @return void + */ +function format_items( $format, $items, $fields ) {} diff --git a/tests/phpstan/stubs/wp-cli.php b/tests/phpstan/stubs/wp-cli.php new file mode 100644 index 0000000000..d99da9d263 --- /dev/null +++ b/tests/phpstan/stubs/wp-cli.php @@ -0,0 +1,54 @@ +<?php +/** + * Minimal WP-CLI stubs for static analysis: only what the plugin calls. + * + * @package Activitypub + */ + +// phpcs:ignoreFile + +class WP_CLI { + /** + * @param mixed ...$args + * @return mixed + */ + public static function add_command( ...$args ) {} + /** + * @param mixed ...$args + * @return mixed + */ + public static function colorize( ...$args ) {} + /** + * @param mixed ...$args + * @return mixed + */ + public static function confirm( ...$args ) {} + /** + * @param mixed ...$args + * @return mixed + */ + public static function error( ...$args ) {} + /** + * @param mixed ...$args + * @return mixed + */ + public static function line( ...$args ) {} + /** + * @param mixed ...$args + * @return mixed + */ + public static function log( ...$args ) {} + /** + * @param mixed ...$args + * @return mixed + */ + public static function success( ...$args ) {} + /** + * @param mixed ...$args + * @return mixed + */ + public static function warning( ...$args ) {} +} + +class WP_CLI_Command {} + diff --git a/tests/phpstan/tests.neon b/tests/phpstan/tests.neon new file mode 100644 index 0000000000..a9d8e60640 --- /dev/null +++ b/tests/phpstan/tests.neon @@ -0,0 +1,2 @@ +parameters: + phpVersion: 70400 diff --git a/tests/phpstan/tests/class-test-magic-accessors-extension.php b/tests/phpstan/tests/class-test-magic-accessors-extension.php new file mode 100644 index 0000000000..bcb518eae7 --- /dev/null +++ b/tests/phpstan/tests/class-test-magic-accessors-extension.php @@ -0,0 +1,93 @@ +<?php +/** + * Magic accessor reflection tests. + * + * @package Activitypub + * @group activitypub + */ + +namespace Activitypub\Tests; + +use Activitypub\Activity\Base_Object; +use Activitypub\Activity\Generic_Object; +use Activitypub\PHPStan\Magic_Accessors_Extension; +use Activitypub\Tests\PHPStan\Overridden_Magic_Object; +use Activitypub\Tests\PHPStan\Unrelated_Magic_Object; +use PHPStan\Testing\PHPStanTestCase; +use PHPStan\Type\ArrayType; +use PHPStan\Type\MixedType; +use PHPStan\Type\ObjectType; +use PHPStan\Type\StaticType; +use PHPStan\Type\StringType; +use PHPStan\Type\TypeCombinator; + +/** + * Test the signatures exposed to PHPStan. + */ +class Test_Magic_Accessors_Extension extends PHPStanTestCase { + /** + * Load only the classes needed by the reflection tests. + * + * @return string[] + */ + public static function getAdditionalConfigFiles(): array { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid + return array( \dirname( __DIR__ ) . '/tests.neon' ); + } + + /** + * Only inherited activity-object magic methods are handled. + */ + public function test_supported_classes(): void { + $provider = self::createReflectionProvider(); + $extension = new Magic_Accessors_Extension(); + $generic = $provider->getClass( Generic_Object::class ); + + $this->assertTrue( $extension->hasMethod( $generic, 'get_id' ) ); + $this->assertTrue( $extension->hasMethod( $generic, 'SET_id' ) ); + $this->assertTrue( $extension->hasMethod( $provider->getClass( Base_Object::class ), 'add_cc' ) ); + $this->assertFalse( $extension->hasMethod( $generic, 'delete_id' ) ); + $this->assertFalse( $extension->hasMethod( $provider->getClass( Unrelated_Magic_Object::class ), 'get_id' ) ); + $this->assertFalse( $extension->hasMethod( $provider->getClass( Overridden_Magic_Object::class ), 'get_id' ) ); + } + + /** + * Getters preserve the declared property type and its nullable state. + */ + public function test_getter_types(): void { + $class = self::createReflectionProvider()->getClass( Generic_Object::class ); + $extension = new Magic_Accessors_Extension(); + $type = $extension->getMethod( $class, 'GET_id' )->getVariants()[0]->getReturnType(); + + $this->assertTrue( $type->equals( TypeCombinator::addNull( new StringType() ) ) ); + $this->assertInstanceOf( MixedType::class, $extension->getMethod( $class, 'get_custom' )->getVariants()[0]->getReturnType() ); + } + + /** + * Setters are fluent, unless a base object rejects an unknown property. + */ + public function test_setter_types(): void { + $provider = self::createReflectionProvider(); + $extension = new Magic_Accessors_Extension(); + $generic = $provider->getClass( Generic_Object::class ); + $base = $provider->getClass( Base_Object::class ); + + $this->assertTrue( $extension->getMethod( $generic, 'set_custom' )->getVariants()[0]->getReturnType()->equals( new StaticType( $generic ) ) ); + $this->assertTrue( $extension->getMethod( $base, 'set_id' )->getVariants()[0]->getReturnType()->equals( new StaticType( $base ) ) ); + $this->assertTrue( $extension->getMethod( $base, 'set_custom' )->getVariants()[0]->getReturnType()->equals( TypeCombinator::union( new StaticType( $base ), new ObjectType( 'WP_Error' ) ) ) ); + } + + /** + * Adders return the accumulated array, not a fluent object. + */ + public function test_adder_types(): void { + $provider = self::createReflectionProvider(); + $extension = new Magic_Accessors_Extension(); + $generic = $provider->getClass( Generic_Object::class ); + $base = $provider->getClass( Base_Object::class ); + $expected = TypeCombinator::addNull( new ArrayType( new MixedType(), new MixedType() ) ); + + $this->assertTrue( $extension->getMethod( $generic, 'add_custom' )->getVariants()[0]->getReturnType()->equals( $expected ) ); + $this->assertTrue( $extension->getMethod( $base, 'add_cc' )->getVariants()[0]->getReturnType()->equals( $expected ) ); + $this->assertTrue( $extension->getMethod( $base, 'add_custom' )->getVariants()[0]->getReturnType()->equals( TypeCombinator::union( $expected, new ObjectType( 'WP_Error' ) ) ) ); + } +}