Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
a7ec9c9
Build/Test Tools: Infer apply_filters() return types from hook docblo…
westonruter May 29, 2026
260254d
Bundled Themes: Add hook documentation references.
westonruter May 29, 2026
bd260a0
Docs: Document hook invocations in XML-RPC and the Abilities API.
westonruter May 29, 2026
8bc73ae
Build/Test Tools: Enforce hook documentation and resolve "documented …
westonruter May 29, 2026
a0ec688
Improve array documentation for wp_get_image_editor_output_format() a…
westonruter May 29, 2026
b77d903
Bundled Themes: Pass the post to the the_permalink filter.
westonruter May 30, 2026
dcfd548
Bundled Themes: Fix hook parameter documentation.
westonruter May 30, 2026
72e9acf
REST API: Pass the $is_update argument to the wp_creating_autosave ac…
westonruter May 30, 2026
b23f1d2
HTTP API: Pass the request URL to the https_local_ssl_verify filter.
westonruter May 30, 2026
753e502
Menus: Pass $menu_data to the wp_update_nav_menu action from auto-add…
westonruter May 30, 2026
d359a7f
Plugins: Pass $network_wide to the activate_{$plugin} action in error…
westonruter May 30, 2026
ea34b55
Build/Test Tools: Resolve file-scope @global docblocks in PHPStan.
westonruter May 30, 2026
413ba4c
Plugins: Pass $paged to the install_plugins_upload action.
westonruter May 30, 2026
c75eff1
Taxonomy: Pass $args to edit/edited term actions and the term_id_filter.
westonruter May 30, 2026
92a2767
Build/Test Tools: Add a PHPStan rule enforcing hook argument counts.
westonruter May 30, 2026
daaf47d
Networks and Sites: Pass the site ID to handle_network_bulk_actions o…
westonruter May 30, 2026
8765464
Comments, REST API: Stop passing an undocumented argument to the_cont…
westonruter May 30, 2026
faa7cf0
Add missing EOL at EOF
westonruter May 31, 2026
286ebd5
Build/Test Tools: Scope hook docblocks to the node that introduces them.
westonruter May 31, 2026
7799649
Apply fixes to minor issues identified by PhpStorm inspections
westonruter May 31, 2026
b0f6210
fixup! Plugins: Pass $network_wide to the activate_{$plugin} action i…
westonruter May 31, 2026
21c1f27
Merge trunk into add/phpstan-apply-filters-return-type-extension
westonruter Jul 26, 2026
6f3531f
Build/Test Tools: Restore GlobalDocBlockVisitor docblocks to match tr…
westonruter Jul 26, 2026
1a37705
Merge branch 'trunk' into add/phpstan-apply-filters-return-type-exten…
westonruter Jul 29, 2026
6d47f4c
Make it clear the rule is for actions as well as filters
westonruter Jul 29, 2026
3ef9a0f
Merge branch 'trunk' into add/phpstan-apply-filters-return-type-exten…
westonruter Jul 29, 2026
15b4c45
Resolve hook doc references against the WordPress root
westonruter Jul 29, 2026
6c67b2b
Merge branch 'trunk' of https://github.com/WordPress/wordpress-develo…
westonruter Jul 29, 2026
6cdc47a
Merge branch 'trunk' into add/phpstan-apply-filters-return-type-exten…
westonruter Jul 29, 2026
a0b8ae9
Merge branch 'trunk' into add/phpstan-apply-filters-return-type-exten…
westonruter Jul 29, 2026
f2ba41e
Merge branch 'trunk' into add/phpstan-apply-filters-return-type-exten…
westonruter Jul 29, 2026
a9378dc
Build/Test Tools: Require a specific anchor to resolve a hook doc ref…
westonruter Jul 29, 2026
8198b3e
Build/Test Tools: Invalidate cached results when inherited hook docs …
westonruter Jul 30, 2026
6ff4d1c
Build/Test Tools: Record hook docblocks only where they are read.
westonruter Jul 30, 2026
9b0a628
Build/Test Tools: Require a filter's docblock to document the filtere…
westonruter Jul 30, 2026
5bdff02
Build/Test Tools: Count every documented hook parameter, including re…
westonruter Jul 30, 2026
d391884
Build/Test Tools: Resolve a hook's documentation in one place.
westonruter Jul 30, 2026
aa69363
Build/Test Tools: Drop an unread field and narrow the hook doc shapes.
westonruter Jul 30, 2026
e062b18
Remove unnecessary noinspection tag
westonruter Jul 30, 2026
0801179
Build/Test Tools: Stop resolving a hook doc reference outside the ana…
westonruter Jul 30, 2026
a909048
Build/Test Tools: Confine a resolved hook doc reference to the analyz…
westonruter Jul 30, 2026
2dbf724
Build/Test Tools: Give each key of a documented array shape its own l…
westonruter Jul 30, 2026
e84c793
Build/Test Tools: Drop two unset() calls that did nothing.
westonruter Jul 30, 2026
39db8b3
Build/Test Tools: Take the filtered value's type without looping to d…
westonruter Jul 30, 2026
3dee659
Build/Test Tools: Align the two rules' `@param` tags.
westonruter Jul 30, 2026
a1147d4
Build/Test Tools: Describe each hook documentation service it registers.
westonruter Jul 30, 2026
f2501c0
Build/Test Tools: Name the license and pin the commit the hook toolin…
westonruter Jul 30, 2026
13da481
Build/Test Tools: Document the WordPress-specific PHPStan extensions.
westonruter Jul 30, 2026
92c6553
Build/Test Tools: Reference the filter function docs with `@link`, no…
westonruter Jul 30, 2026
43272fe
Build/Test Tools: Survive a referenced file that cannot be parsed.
westonruter Jul 30, 2026
0679b04
Build/Test Tools: Note that actions are documented elsewhere too.
westonruter Jul 30, 2026
269bae9
Merge branch 'trunk' into add/phpstan-apply-filters-return-type-exten…
westonruter Jul 30, 2026
748aed7
Build/Test Tools: Report a filter documented without parameters once.
westonruter Jul 30, 2026
0ad0b6f
Build/Test Tools: Name the hook in every documentation error.
westonruter Jul 30, 2026
bb83383
Build/Test Tools: Name a dynamic hook in an argument count error too.
westonruter Jul 30, 2026
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
95 changes: 95 additions & 0 deletions tests/phpstan/ApplyFiltersDynamicFunctionReturnTypeExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php
/**
* PHPStan dynamic return type extension that types the return value of
* `apply_filters()` (and its variants) from the `@param` type documented in the
* docblock immediately preceding the call.
*
* For example, given:
*
* /**
* * @param array $data Response data.
* * ...
* *\/
* return apply_filters( 'response_data', $data );
*
* PHPStan will infer the call returns `array` rather than `mixed`.
*
* This assumes filters honor the documented type. A misbehaving filter could
* return something else, but that is treated as the unusual case.
*
* @link https://github.com/szepeviktor/phpstan-wordpress/blob/20f0406fcb96f8e1b8369d8c0df6f5c525a761aa/src/ApplyFiltersDynamicFunctionReturnTypeExtension.php Adapted from szepeviktor/phpstan-wordpress, MIT license.
*
* @package WordPress
*/

declare(strict_types=1);

namespace WordPress\PHPStan;

use PhpParser\Node\Expr\FuncCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\FunctionReflection;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;

/**
* Resolves the return type of WordPress filter functions from their docblocks.
*/
class ApplyFiltersDynamicFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension {

/**
* Hook docblock resolver.
*
* @var HookDocBlock
*/
protected HookDocBlock $hookDocBlock;

/**
* Constructor.
*
* @param HookDocBlock $hook_doc_block Hook docblock resolver.
*/
public function __construct( HookDocBlock $hook_doc_block ) {
$this->hookDocBlock = $hook_doc_block;
}

/**
* Determines whether this extension applies to the given function.
*
* @param FunctionReflection $functionReflection Function being analyzed.
* @return bool
*/
public function isFunctionSupported( FunctionReflection $functionReflection ): bool {
return in_array( $functionReflection->getName(), HookDocBlock::FILTER_FUNCTIONS, true );
}

/**
* Resolves the return type of the filter call from its preceding docblock.
*
* @link https://developer.wordpress.org/reference/functions/apply_filters/
* @link https://developer.wordpress.org/reference/functions/apply_filters_deprecated/
* @link https://developer.wordpress.org/reference/functions/apply_filters_ref_array/
*
* @param FunctionReflection $functionReflection Function being analyzed.
* @param FuncCall $functionCall The function call node.
* @param Scope $scope Analysis scope.
* @return Type
* @throws ShouldNotHappenException
*/
public function getTypeFromFunctionCall( FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope ): Type {
$default = new MixedType();
$resolved_php_doc = $this->hookDocBlock->getNullableHookDocBlock( $functionCall, $scope );

if ( null === $resolved_php_doc ) {
return $default;
}

// The first `@param` describes the value being filtered.
$params = $resolved_php_doc->getParamTags();
$param = reset( $params );

return false === $param ? $default : $param->getType();
}
}
Loading
Loading