Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
29e0353
Docs: Add PHPStan integer ranges and literal types.
swissspidy Oct 1, 2026
16929d7
Merge remote-tracking branch 'upstream/trunk' into fix/phpstan-int-ra…
claude Oct 5, 2026
e729b55
Docs: Address review feedback on integer range and literal types.
claude Oct 5, 2026
4ba7d3e
Merge branch 'trunk' into fix/phpstan-int-ranges-literals
swissspidy Oct 7, 2026
9d8d956
Merge branch 'trunk' into fix/phpstan-int-ranges-literals
westonruter Oct 7, 2026
419da78
Type `$wp_actions` and `$wp_filters` globals as positive-int counts
westonruter Oct 7, 2026
1862d06
Narrow `wp_insert_link()` return to `non-negative-int`
westonruter Oct 7, 2026
1cc1ec5
Narrow `wp_insert_category()` and term `term_id` returns to `non-nega…
westonruter Oct 7, 2026
945a1bb
Update baseline for narrowed `$term_id` passed to `sanitize_title()`
westonruter Oct 7, 2026
b40136e
Narrow `WP_User::$ID` to `non-negative-int`
westonruter Oct 7, 2026
04a3691
Update baselines for narrowed `WP_User::$ID`
westonruter Oct 7, 2026
2c3333a
Clamp IDs with `max( 0, (int) … )` instead of `absint()`
westonruter Oct 7, 2026
5437060
Type the static suffix cache in `wp_scripts_get_suffix()`
westonruter Oct 7, 2026
88a9359
Narrow referer check returns to the nonce tick literals
westonruter Oct 7, 2026
af89d43
Narrow network ID returns to `non-negative-int`
westonruter Oct 7, 2026
40b88ca
Reject a negative link ID in `wp_insert_link()` instead of clamping it
westonruter Oct 8, 2026
51beb14
Remove the literal `$context` type from `sanitize_title_with_dashes()`
westonruter Oct 8, 2026
2352b60
Keep `WP_User::$ID` and `$data->ID` in agreement for invalid IDs
westonruter Oct 8, 2026
63ec1b7
Remove dead `WP_Error` check from `get_bookmark_field()`
westonruter Oct 8, 2026
ee5dad5
Space it out
westonruter Oct 9, 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
14 changes: 12 additions & 2 deletions src/wp-admin/includes/bookmark.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
* @since 2.0.0
*
* @return int The link ID on success. The value 0 on failure.
*
* @phpstan-return non-negative-int
*/
function add_link() {
return edit_link();
Expand All @@ -24,6 +26,8 @@ function add_link() {
*
* @param int $link_id Optional. ID of the link to edit. Default 0.
* @return int The link ID on success. The value 0 on failure.
*
* @phpstan-return non-negative-int
*/
function edit_link( $link_id = 0 ) {
if ( ! current_user_can( 'manage_links' ) ) {
Expand Down Expand Up @@ -174,7 +178,7 @@ function get_link_to_edit( $link ) {
* @param bool $wp_error Optional. Whether to return a WP_Error object on failure. Default false.
* @return int|WP_Error The link ID on success. The value 0 or WP_Error on failure.
*
* @phpstan-return ( $wp_error is false ? int : int|WP_Error )
* @phpstan-return ( $wp_error is false ? non-negative-int : non-negative-int|WP_Error )
*/
function wp_insert_link( $linkdata, $wp_error = false ) {
global $wpdb;
Expand All @@ -189,10 +193,14 @@ function wp_insert_link( $linkdata, $wp_error = false ) {
$parsed_args = wp_parse_args( $linkdata, $defaults );
$parsed_args = wp_unslash( sanitize_bookmark( $parsed_args, 'db' ) );

$link_id = $parsed_args['link_id'];
$link_id = (int) $parsed_args['link_id'];
$link_name = $parsed_args['link_name'];
$link_url = $parsed_args['link_url'];

if ( $link_id < 0 ) {
return 0;
}

$update = false;
if ( ! empty( $link_id ) ) {
$update = true;
Expand Down Expand Up @@ -301,6 +309,8 @@ function wp_set_link_cats( $link_id = 0, $link_categories = array() ) {
*
* @param array $linkdata Link data to update. See wp_insert_link() for accepted arguments.
* @return int The updated link ID on success. The value 0 on failure.
*
* @phpstan-return non-negative-int
*/
function wp_update_link( $linkdata ) {
$link_id = (int) $linkdata['link_id'];
Expand Down
2 changes: 2 additions & 0 deletions src/wp-admin/includes/class-custom-image-header.php
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,8 @@ public function process_default_headers() {
*
* @param string $type The header type. One of 'default' (for the Uploaded Images control)
* or 'uploaded' (for the Uploaded Images control).
*
* @phpstan-param 'default'|'uploaded' $type
*/
public function show_header_selector( $type = 'default' ) {
if ( 'default' === $type ) {
Expand Down
4 changes: 2 additions & 2 deletions src/wp-admin/includes/class-wp-importer.php
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,8 @@ public function min_whitespace( $text ) {
*
* @since 3.0.0
*
* @global wpdb $wpdb WordPress database abstraction object.
* @global int[] $wp_actions Stores the number of times each action was triggered.
* @global wpdb $wpdb WordPress database abstraction object.
* @global array<string, positive-int> $wp_actions Stores the number of times each action was triggered.
*/
public function stop_the_insanity() {
global $wpdb, $wp_actions;
Expand Down
4 changes: 3 additions & 1 deletion src/wp-admin/includes/taxonomy.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ function wp_create_categories( $categories, $post_id = 0 ) {
* depending on param `$wp_error`.
*
* @phpstan-return (
* $wp_error is false ? int : int|WP_Error
* $wp_error is false ? non-negative-int : non-negative-int|WP_Error
* )
*/
function wp_insert_category( $catarr, $wp_error = false ) {
Expand Down Expand Up @@ -188,6 +188,8 @@ function wp_insert_category( $catarr, $wp_error = false ) {
*
* @param array $catarr The 'cat_ID' value is required. All other keys are optional.
* @return int|false The ID number of the new or updated Category on success. Zero or FALSE on failure.
*
* @phpstan-return non-negative-int|false
*/
function wp_update_category( $catarr ) {
$cat_id = (int) $catarr['cat_ID'];
Expand Down
2 changes: 2 additions & 0 deletions src/wp-admin/includes/template.php
Original file line number Diff line number Diff line change
Expand Up @@ -1302,6 +1302,8 @@ function _get_plugin_from_callback( $callback ) {
* Often this is the object that's the focus of the current screen,
* for example a `WP_Post` or `WP_Comment` object.
* @return int Number of meta_boxes.
*
* @phpstan-return non-negative-int
*/
function do_meta_boxes( $screen, $context, $data_object ) {
global $wp_meta_boxes;
Expand Down
12 changes: 7 additions & 5 deletions src/wp-includes/bookmark.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,15 @@ function get_bookmark( $bookmark, $output = OBJECT, $filter = 'raw' ) {
* @param string $field The name of the data field to return.
* @param int $bookmark The bookmark ID to get field.
* @param string $context Optional. The context of how the field will be used. Default 'display'.
* @return string|WP_Error
* @return mixed The sanitized field value, or an empty string if the bookmark or field does not exist.
*
* @phpstan-param 'link_id'|'link_url'|'link_name'|'link_image'|'link_target'|'link_description'|'link_visible'|'link_owner'|'link_rating'|'link_updated'|'link_rel'|'link_notes'|'link_rss'|'link_category' $field
* @phpstan-return ( $field is 'link_category' ? array<int, non-negative-int>|'' : ( $field is 'link_id'|'link_rating' ? int|'' : mixed ) )
*/
function get_bookmark_field( $field, $bookmark, $context = 'display' ) {
$bookmark = (int) $bookmark;
$bookmark = get_bookmark( $bookmark );

if ( is_wp_error( $bookmark ) ) {
return $bookmark;
}

if ( ! is_object( $bookmark ) ) {
return '';
}
Expand Down Expand Up @@ -403,6 +402,9 @@ function sanitize_bookmark( $bookmark, $context = 'display' ) {
* @param string $context How to filter the field value. Accepts 'raw', 'edit', 'db',
* 'display', 'attribute', or 'js'. Default 'display'.
* @return mixed The filtered value.
*
* @phpstan-param 'link_id'|'link_url'|'link_name'|'link_image'|'link_target'|'link_description'|'link_visible'|'link_owner'|'link_rating'|'link_updated'|'link_rel'|'link_notes'|'link_rss'|'link_category' $field
* @phpstan-return ($field is 'link_category' ? array<int, non-negative-int> : ($field is 'link_id'|'link_rating' ? int : mixed))
*/
function sanitize_bookmark_field( $field, $value, $bookmark_id, $context ) {
$int_fields = array( 'link_id', 'link_rating' );
Expand Down
4 changes: 3 additions & 1 deletion src/wp-includes/class-wp-locale.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ class WP_Locale {
* Default is 'words'.
*
* @since 6.2.0
* @var string
* @var string|null
*
* @phpstan-var 'characters_excluding_spaces'|'characters_including_spaces'|'words'|null
*/
public $word_count_type;

Expand Down
9 changes: 6 additions & 3 deletions src/wp-includes/class-wp-user.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class WP_User {
*
* @since 2.1.0
* @var int
* @phpstan-var non-negative-int
*/
public $ID = 0;

Expand Down Expand Up @@ -181,11 +182,13 @@ public function __construct( $id = 0, $name = '', $site_id = 0 ) {
* @param int $site_id Optional. The site ID to initialize for.
*/
public function init( $data, $site_id = 0 ) {
if ( ! isset( $data->ID ) ) {
$id = isset( $data->ID ) ? (int) $data->ID : 0;
if ( ! isset( $data->ID ) || $id < 0 ) {
$id = 0;
$data->ID = 0;
}
$this->data = $data;
$this->ID = (int) $data->ID;
$this->ID = $id;

$this->for_site( $site_id );
}
Expand Down Expand Up @@ -364,7 +367,7 @@ public function __set( $key, $value ) {
'<code>WP_User->ID</code>'
)
);
$this->ID = (int) $value;
$this->ID = max( 0, (int) $value );
return;
}

Expand Down
3 changes: 3 additions & 0 deletions src/wp-includes/class-wpdb.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ class wpdb {
* @since 0.71
*
* @var int
* @phpstan-var non-negative-int
*/
public $insert_id = 0;

Expand Down Expand Up @@ -3098,6 +3099,8 @@ public function get_var( $query = null, $x = 0, $y = 0 ) {
* )
* : null
* )
*
* @phpstan-param non-negative-int $y
*/
public function get_row( $query = null, $output = OBJECT, $y = 0 ) {
$this->func_call = "\$db->get_row(\"$query\",$output,$y)";
Expand Down
2 changes: 2 additions & 0 deletions src/wp-includes/comment.php
Original file line number Diff line number Diff line change
Expand Up @@ -1899,6 +1899,8 @@ function wp_unspam_comment( $comment_id ) {
*
* @param int|WP_Comment $comment_id Comment ID or WP_Comment object
* @return string|false Status might be 'trash', 'approved', 'unapproved', 'spam'. False on failure.
*
* @phpstan-return 'approved'|'spam'|'trash'|'unapproved'|false
*/
function wp_get_comment_status( $comment_id ) {
$comment = get_comment( $comment_id );
Expand Down
3 changes: 3 additions & 0 deletions src/wp-includes/formatting.php
Original file line number Diff line number Diff line change
Expand Up @@ -2834,6 +2834,7 @@ function format_to_edit( $content, $rich_text = false ) {
* @param int $threshold Digit places number needs to be to not have zeros added.
* @return string Adds leading zeros to number if needed.
*
* @phpstan-param non-negative-int $threshold
* @phpstan-return (
* $threshold is 0
* ? lowercase-string&non-empty-string&numeric-string
Expand Down Expand Up @@ -3005,6 +3006,8 @@ function urldecode_deep( $value ) {
* @param string $email_address Email address.
* @param int $hex_encoding Optional. Set to 1 to enable hex encoding.
* @return string Converted email address.
*
* @phpstan-param 0|1 $hex_encoding
*/
function antispambot( $email_address, $hex_encoding = 0 ) {
$obfuscated = '';
Expand Down
15 changes: 14 additions & 1 deletion src/wp-includes/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -1036,6 +1036,8 @@ function wp_get_http_headers( $url, $deprecated = false ) {
* @global string $previousday The day of the previous post in the loop.
*
* @return int 1 when new day, 0 if not a new day.
*
* @phpstan-return 0|1
*/
function is_new_day() {
global $currentday, $previousday;
Expand Down Expand Up @@ -4485,6 +4487,7 @@ function _wp_die_process_input( $message, $title = '', $args = array() ) {
* greater than 0. Default 512.
* @return string|false The JSON encoded string, or false if it cannot be encoded.
*
* @phpstan-param positive-int $depth
* @phpstan-return non-empty-string|false
*/
function wp_json_encode( $value, $flags = 0, $depth = 512 ) {
Expand Down Expand Up @@ -6256,6 +6259,8 @@ function _doing_it_wrong( $function_name, $message, $version ) {
* before passing to this function to avoid being stripped {@see wp_kses()}.
* @param int $error_level Optional. The designated error type for this error.
* Only works with E_USER family of constants. Default E_USER_NOTICE.
*
* @phpstan-param \E_USER_ERROR|\E_USER_WARNING|\E_USER_NOTICE|\E_USER_DEPRECATED $error_level
*/
function wp_trigger_error( $function_name, $message, $error_level = E_USER_NOTICE ) {
/**
Expand Down Expand Up @@ -6692,6 +6697,8 @@ function is_main_network( $network_id = null ) {
* @since 4.3.0
*
* @return int The ID of the main network.
*
* @phpstan-return non-negative-int
*/
function get_main_network_id() {
if ( ! is_multisite() ) {
Expand Down Expand Up @@ -6722,7 +6729,7 @@ function get_main_network_id() {
*
* @param int $main_network_id The ID of the main network.
*/
return (int) apply_filters( 'get_main_network_id', $main_network_id );
return max( 0, (int) apply_filters( 'get_main_network_id', $main_network_id ) );
}

/**
Expand Down Expand Up @@ -7203,6 +7210,8 @@ function __return_false() { // phpcs:ignore WordPress.NamingConventions.ValidFun
* @since 3.0.0
*
* @return int 0.
*
* @phpstan-return 0
*/
function __return_zero() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
return 0;
Expand All @@ -7216,6 +7225,8 @@ function __return_zero() { // phpcs:ignore WordPress.NamingConventions.ValidFunc
* @since 3.0.0
*
* @return array Empty array.
*
* @phpstan-return array{}
*/
function __return_empty_array() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
return array();
Expand Down Expand Up @@ -7244,6 +7255,8 @@ function __return_null() { // phpcs:ignore WordPress.NamingConventions.ValidFunc
* @see __return_null()
*
* @return string Empty string.
*
* @phpstan-return ''
*/
function __return_empty_string() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
return '';
Expand Down
6 changes: 6 additions & 0 deletions src/wp-includes/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
* @since 4.4.0
*
* @return string The HTTP protocol. Default: HTTP/1.0.
*
* @phpstan-return 'HTTP/1.0'|'HTTP/1.1'|'HTTP/2'|'HTTP/2.0'|'HTTP/3'
*/
function wp_get_server_protocol() {
$protocol = $_SERVER['SERVER_PROTOCOL'] ?? '';
Expand Down Expand Up @@ -1509,6 +1511,8 @@ function absint( $maybeint ): int {
* @global int $blog_id
*
* @return int Site ID.
*
* @phpstan-return non-negative-int
*/
function get_current_blog_id() {
global $blog_id;
Expand All @@ -1522,6 +1526,8 @@ function get_current_blog_id() {
* @since 4.6.0
*
* @return int The ID of the current network.
*
* @phpstan-return non-negative-int
*/
function get_current_network_id() {
if ( ! is_multisite() ) {
Expand Down
6 changes: 4 additions & 2 deletions src/wp-includes/pluggable.php
Original file line number Diff line number Diff line change
Expand Up @@ -1375,7 +1375,7 @@ function auth_redirect() {
* 2 if the nonce is valid and generated between 12-24 hours ago.
* False if the nonce is invalid. Only possible when `$action` is -1,
* as the function otherwise exits rather than returning false.
* @phpstan-return ( $action is -1 ? int|false : int )
* @phpstan-return ( $action is -1 ? 1|2|false : 1|2 )
*/
function check_admin_referer( $action = -1, $query_arg = '_wpnonce' ) {
if ( -1 === $action ) {
Expand Down Expand Up @@ -1422,7 +1422,7 @@ function check_admin_referer( $action = -1, $query_arg = '_wpnonce' ) {
* 2 if the nonce is valid and generated between 12-24 hours ago.
* False if the nonce is invalid. Only possible when `$stop` is false,
* as the function otherwise exits rather than returning false.
* @phpstan-return ( $stop is true ? int : int|false )
* @phpstan-return ( $stop is true ? 1|2 : 1|2|false )

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If $stop is true, then it returns 1|2|never. But I think we settled that we wouldn't include never or void in a union.

*/
function check_ajax_referer( $action = -1, $query_arg = false, $stop = true ) {
if ( -1 === $action ) {
Expand Down Expand Up @@ -2477,6 +2477,8 @@ function wp_nonce_tick( $action = -1 ) {
* @return int|false 1 if the nonce is valid and generated between 0-12 hours ago,
* 2 if the nonce is valid and generated between 12-24 hours ago.
* False if the nonce is invalid.
*
* @phpstan-return 1|2|false
*/
function wp_verify_nonce( $nonce, $action = -1 ) {
$nonce = (string) $nonce;
Expand Down
Loading
Loading