Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
44 changes: 44 additions & 0 deletions .github/workflows/phpstan.yml
Original file line number Diff line number Diff line change
@@ -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
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
- name: Test PHPStan extension
run: composer analyze:test
10 changes: 9 additions & 1 deletion activitypub.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@

/**
* Initialize REST routes.
*
* @return void
*/
function rest_init() {
Rest\Server::init();
Expand Down Expand Up @@ -86,6 +88,8 @@ function rest_init() {

/**
* Initialize plugin.
*
* @return void
*/
function plugin_init() {
\add_action( 'init', array( __NAMESPACE__ . '\Activitypub', 'init' ) );
Expand Down Expand Up @@ -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' ) );
Expand All @@ -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 ) {
Expand Down
19 changes: 18 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Comment thread
pfefferle marked this conversation as resolved.
},
"autoload-dev": {
"classmap": [
"tests/phpstan/class-magic-accessors-extension.php",
"tests/phpstan/class-magic-accessor.php"
]
},
"config": {
"allow-plugins": true
Expand Down Expand Up @@ -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"
],
Expand Down
25 changes: 25 additions & 0 deletions docs/code-linting.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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<string, mixed>`) 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
Expand Down
4 changes: 4 additions & 0 deletions includes/activity/class-activity.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion includes/activity/class-base-object.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
6 changes: 5 additions & 1 deletion includes/activity/class-generic-object.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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 ) {
Expand All @@ -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 );
Expand Down
2 changes: 2 additions & 0 deletions includes/activity/extended-object/class-place.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) ) {
Expand Down
6 changes: 6 additions & 0 deletions includes/cache/class-avatar.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ public static function get_max_dimension() {

/**
* Initialize the cache handler.
*
* @return void
*/
public static function init() {
if ( ! self::is_enabled() ) {
Expand All @@ -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.
Expand Down Expand Up @@ -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 ) ) {
Expand Down
2 changes: 2 additions & 0 deletions includes/cache/class-emoji.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ public static function get_max_dimension() {

/**
* Initialize the cache handler.
*
* @return void
*/
public static function init() {
if ( ! self::is_enabled() ) {
Expand Down
2 changes: 2 additions & 0 deletions includes/cache/class-file.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 4 additions & 0 deletions includes/cache/class-media.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 ) ) {
Expand Down
2 changes: 2 additions & 0 deletions includes/cache/class-stats-image.php
Original file line number Diff line number Diff line change
Expand Up @@ -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' ) ) {
Expand Down
Loading
Loading