From 4f1b8e9efb84bf72d15bc827e26213997c86ec1f Mon Sep 17 00:00:00 2001 From: Marian <42134098+IanDelMar@users.noreply.github.com> Date: Wed, 20 Aug 2025 20:30:50 +0200 Subject: [PATCH] Add, fix, update bookmark related functions --- functionMap.php | 8 +++- tests/CallToParameterTest.php | 19 +++++++++ tests/TypeInferenceTest.php | 4 +- tests/data/bookmark-admin.php | 56 +++++++++++++++++++++++++ tests/data/bookmark-params.php | 69 +++++++++++++++++++++++++++++++ tests/data/bookmark.php | 37 +++++++++++++++++ tests/data/get_bookmark.php | 15 ------- tests/data/wp_error_parameter.php | 9 ---- tests/data/wp_update_link.php | 12 ------ wordpress-stubs.php | 11 ++++- 10 files changed, 200 insertions(+), 40 deletions(-) create mode 100644 tests/data/bookmark-admin.php create mode 100644 tests/data/bookmark-params.php create mode 100644 tests/data/bookmark.php delete mode 100644 tests/data/get_bookmark.php delete mode 100644 tests/data/wp_update_link.php diff --git a/functionMap.php b/functionMap.php index 870eb7b..91ddc9e 100644 --- a/functionMap.php +++ b/functionMap.php @@ -40,6 +40,7 @@ 'absint' => ['($maybeint is T&int<0, max> ? T : ($maybeint is int ? int<1, max> : ($maybeint is empty ? 0 : ($maybeint is numeric-string ? int<0, max> : ($maybeint is string ? 0 : ($maybeint is true|non-empty-array ? 1 : ($maybeint is bool ? 0|1 : int<0, max>)))))))', '@phpstan-template T' => 'of int', 'maybeint' => 'T|scalar|array|resource|null'], 'add_comments_page' => [null, 'callback' => "''|callable"], 'add_dashboard_page' => [null, 'callback' => "''|callable"], + 'add_link' => ['int<0, max>'], 'add_links_page' => [null, 'callback' => "''|callable"], 'add_management_page' => [null, 'callback' => "''|callable"], 'add_media_page' => [null, 'callback' => "''|callable"], @@ -59,12 +60,14 @@ 'comment_class' => ['($display is true ? void : string)'], 'current_time' => ["(\$type is 'timestamp'|'U' ? int : string)"], 'did_action' => ['int<0, max>'], + 'edit_link' => ['int<0, max>'], 'edit_term_link' => ['($display is true ? void : string|void)'], 'get_approved_comments' => ["(\$args is array{count: true}&array ? int : (\$args is array{fields: 'ids'}&array ? array : array))"], 'get_attachment_taxonomies' => ["(\$output is 'names' ? array : array)"], 'get_available_post_statuses' => ['list'], 'get_block_wrapper_attributes' => ['($extra_attributes is empty ? string : non-falsy-string)', 'extra_attributes' => 'array'], 'get_bookmark' => ["null|(\$output is 'ARRAY_A' ? array : (\$output is 'ARRAY_N' ? array : \stdClass))", 'output' => "'OBJECT'|'ARRAY_A'|'ARRAY_N'"], + 'get_bookmark_field' => ['array>|int|string|\WP_Error', 'field' => "'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'"], 'get_calendar' => ['($args is array{display: false}&array ? string : void)'], 'get_categories' => ["(\$args is array{fields: 'count'}&array ? list : (\$args is array{fields: 'names'|'slugs'}&array ? list : (\$args is array{fields: 'id=>name'|'id=>slug'}&array ? array : (\$args is array{fields: 'id=>parent'}&array ? array : (\$args is array{fields: 'ids'|'tt_ids'}&array ? list : array)))))"], 'get_category' => ["(\$category is object ? array|\WP_Term : array|\WP_Term|\WP_Error|null) & (\$output is 'ARRAY_A' ? array|\WP_Error|null : (\$output is 'ARRAY_N' ? array|\WP_Error|null : \WP_Term|\WP_Error|null))", 'output' => "'OBJECT'|'ARRAY_A'|'ARRAY_N'"], @@ -74,6 +77,7 @@ 'get_compat_media_markup' => ['array{item: string, meta: string}'], 'get_current_blog_id' => ['int<0, max>'], 'get_current_user_id' => ['int<0, max>'], + 'get_default_link_to_edit' => ["object{link_url: string, link_name: string, link_visible: 'Y'}&\stdClass", '@phpstan-impure' => ''], 'get_html_split_regex' => ['non-falsy-string'], 'get_object_taxonomies' => ["(\$output is 'names' ? array : array)"], 'get_page_by_path' => ["(\$output is 'ARRAY_A' ? array|null : (\$output is 'ARRAY_N' ? array|null : \WP_Post|null))"], @@ -119,6 +123,7 @@ 'rest_authorization_required_code' => ['401|403'], 'rest_sanitize_boolean' => ["(T is bool ? T : (T is ''|'false'|'FALSE'|'0'|0 ? false : true))", '@phpstan-template T' => 'of bool|string|int', 'value' => 'T'], 'rest_ensure_response' => ['($response is \WP_Error ? \WP_Error : \WP_REST_Response)'], + 'sanitize_bookmark_field' => ['array|int|string', 'field' => "'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'"], 'sanitize_category' => ['T', '@phpstan-template' => 'T of array|object', 'category' => 'T'], 'sanitize_post' => ['T', '@phpstan-template' => 'T of array|object', 'post' => 'T'], 'sanitize_sql_orderby' => ['(T is non-falsy-string ? T|false : false)', '@phpstan-template T' => 'of string', 'orderby' => 'T'], @@ -159,6 +164,7 @@ 'wp_get_archives' => ['($args is array{echo: false|0}&array ? string|void : void)'], 'wp_get_comment_status' => ["'approved'|'spam'|'trash'|'unapproved'|false"], 'wp_get_inline_script_tag' => ['non-falsy-string', 'attributes' => 'array'], + 'wp_get_link_cats' => ['($link_id is empty ? array{} : array>)'], 'wp_get_object_terms' => ["(\$object_ids is empty ? array{} : (\$taxonomies is empty ? array{} : ((\$args is array{fields: 'names'|'slugs'}&array ? list : (\$args is array{fields: 'id=>name'|'id=>slug'}&array ? array : (\$args is array{fields: 'id=>parent'}&array ? array : (\$args is array{fields: 'ids'|'tt_ids'}&array ? list : (\$args is array{fields: 'count'}&array ? numeric-string : array)))))|\WP_Error)))"], 'wp_get_post_categories' => ["(\$post_id is 0 ? array{} : ((\$args is array{fields: 'names'|'slugs'}&array ? list : (\$args is array{fields: 'id=>name'|'id=>slug'}&array ? array : (\$args is array{fields: 'id=>parent'}&array ? array : (\$args is array{fields: 'all'|'all_with_object_id'}&array ? array : (\$args is array{fields: 'count'}&array ? numeric-string : list)))))|\WP_Error))"], 'wp_get_post_tags' => ["(\$post_id is 0 ? array{} : ((\$args is array{fields: 'names'|'slugs'}&array ? list : (\$args is array{fields: 'id=>name'|'id=>slug'}&array ? array : (\$args is array{fields: 'id=>parent'}&array ? array : (\$args is array{fields: 'ids'|'tt_ids'}&array ? list : (\$args is array{fields: 'count'}&array ? numeric-string : array)))))|\WP_Error))"], @@ -216,7 +222,7 @@ 'wp_unschedule_hook' => ['($wp_error is false ? int<0, max>|false : int<0, max>|\WP_Error)'], 'wp_unslash' => ['T', '@phpstan-template' => 'T', 'value' => 'T'], 'wp_update_comment' => ['($wp_error is false ? 0|1|false : 0|1|\WP_Error)'], - 'wp_update_link' => ['int<0, max>|\WP_Error'], + 'wp_update_link' => ['int<0, max>'], 'wp_update_post' => ['($wp_error is false ? int<0, max> : int<1, max>|\WP_Error)'], 'wp_verify_nonce' => ['1|2|false', 'action' => '-1|string'], 'wp_widget_rss_form' => ['void', 'args' => $wpWidgetRssFormArgsType, 'inputs' => $wpWidgetRssFormInputsType], diff --git a/tests/CallToParameterTest.php b/tests/CallToParameterTest.php index 439d6e0..1645e8d 100644 --- a/tests/CallToParameterTest.php +++ b/tests/CallToParameterTest.php @@ -50,6 +50,25 @@ public function testAddMenuPage(): void ); } + public function testBookmarks(): void + { + $field = "'link_category'|'link_description'|'link_id'|'link_image'|'link_name'|'link_notes'|'link_owner'|'link_rating'|'link_rel'|'link_rss'|'link_target'|'link_updated'|'link_url'|'link_visible'"; + + $this->analyse( + __DIR__ . '/data/bookmark-params.php', + [ + ["Parameter #1 \$field of function get_bookmark_field expects $field, 'foo' given.", 16], + ["Parameter #1 \$field of function get_bookmark_field expects $field, 'foo' given.", 17], + ["Parameter #1 \$field of function get_bookmark_field expects $field, int given.", 18], + ["Parameter #1 \$field of function sanitize_bookmark_field expects $field, 'foo' given.", 21], + ["Parameter #1 \$field of function sanitize_bookmark_field expects $field, int given.", 22], + // Maybes + ["Parameter #1 \$field of function get_bookmark_field expects $field, string given.", 30], + ["Parameter #1 \$field of function sanitize_bookmark_field expects $field, string given.", 32], + ] + ); + } + public function testWpdbGetRow(): void { $this->analyse( diff --git a/tests/TypeInferenceTest.php b/tests/TypeInferenceTest.php index d7b8339..2fc1b01 100644 --- a/tests/TypeInferenceTest.php +++ b/tests/TypeInferenceTest.php @@ -15,6 +15,8 @@ public function dataFileAsserts(): iterable yield from $this->gatherAssertTypes(__DIR__ . '/data/_get_list_table.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/absint.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/block_version.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/data/bookmark-admin.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/data/bookmark.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/bool_from_yn.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/current_time.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/echo_parameter.php'); @@ -23,7 +25,6 @@ public function dataFileAsserts(): iterable yield from $this->gatherAssertTypes(__DIR__ . '/data/get_attachment_taxonomies.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/get_available_post_statuses.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/get_block_wrapper_attributes.php'); - yield from $this->gatherAssertTypes(__DIR__ . '/data/get_bookmark.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/get_categories.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/get_category.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/get_category_by_path.php'); @@ -112,7 +113,6 @@ public function dataFileAsserts(): iterable yield from $this->gatherAssertTypes(__DIR__ . '/data/wp_theme.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/wp_translations.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/wp_unique_id.php'); - yield from $this->gatherAssertTypes(__DIR__ . '/data/wp_update_link.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/wp_widget_factory.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/wp_widget_rss.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/wp_widgets_access_body_class.php'); diff --git a/tests/data/bookmark-admin.php b/tests/data/bookmark-admin.php new file mode 100644 index 0000000..e94285f --- /dev/null +++ b/tests/data/bookmark-admin.php @@ -0,0 +1,56 @@ +', add_link()); + +/* + * edit_link() + * calls wp_update_link() if ! empty($link_id), wp_insert_link() with default $wp_error (false) otherwise + */ +assertType('int<0, max>', edit_link()); +assertType('int<0, max>', edit_link(0)); +assertType('int<0, max>', edit_link(123)); +assertType('int<0, max>', edit_link(Faker::int())); + +/* + * wp_insert_link() + */ +assertType('int<0, max>', wp_insert_link([])); +assertType('int<0, max>', wp_insert_link([], false)); +assertType('int<0, max>|WP_Error', wp_insert_link([], true)); +assertType('int<0, max>|WP_Error', wp_insert_link([], Faker::bool())); + +/* + * wp_update_link() + * calls wp_insert_link() with default $wp_error (false) + */ +assertType('int<0, max>', wp_update_link([])); +assertType('int<0, max>', wp_update_link(['link_id' => 123])); +assertType('int<0, max>', wp_update_link(Faker::array())); + +/* + * get_default_link_to_edit() + */ +assertType("object{link_url: string, link_name: string, link_visible: 'Y'}&stdClass", get_default_link_to_edit()); + +/* + * wp_get_link_cats() + */ +assertType('array{}', wp_get_link_cats()); +assertType('array{}', wp_get_link_cats(0)); +assertType('array>', wp_get_link_cats(123)); +assertType('array>', wp_get_link_cats(Faker::int())); diff --git a/tests/data/bookmark-params.php b/tests/data/bookmark-params.php new file mode 100644 index 0000000..9c9936a --- /dev/null +++ b/tests/data/bookmark-params.php @@ -0,0 +1,69 @@ +|null', get_bookmark($stdClassOrInt, 'ARRAY_A')); +assertType('array|null', get_bookmark($stdClassOrInt, 'ARRAY_N')); + +/* + * get_bookmark_field() + */ + +assertType('array>|int|string|WP_Error', get_bookmark_field('link_id', Faker::int())); +assertType('array>|int|string|WP_Error', get_bookmark_field('foo', Faker::int())); +assertType('array>|int|string|WP_Error', get_bookmark_field(Faker::string(), Faker::int())); + +/* + * sanitize_bookmark_field() + */ + +assertType('array|int|string', sanitize_bookmark_field('link_id', Faker::mixed(), Faker::int(), 'raw')); +assertType('array|int|string', sanitize_bookmark_field('foo', Faker::mixed(), Faker::int(), 'raw')); +assertType('array|int|string', sanitize_bookmark_field(Faker::string(), Faker::mixed(), Faker::int(), 'raw')); diff --git a/tests/data/get_bookmark.php b/tests/data/get_bookmark.php deleted file mode 100644 index 739abad..0000000 --- a/tests/data/get_bookmark.php +++ /dev/null @@ -1,15 +0,0 @@ -|null', get_bookmark($stdClassOrInt, 'ARRAY_A')); -assertType('array|null', get_bookmark($stdClassOrInt, 'ARRAY_N')); diff --git a/tests/data/wp_error_parameter.php b/tests/data/wp_error_parameter.php index 8383e24..f221575 100644 --- a/tests/data/wp_error_parameter.php +++ b/tests/data/wp_error_parameter.php @@ -7,7 +7,6 @@ use function wp_clear_scheduled_hook; use function wp_insert_attachment; use function wp_insert_category; -use function wp_insert_link; use function wp_insert_post; use function wp_reschedule_event; use function wp_schedule_event; @@ -19,14 +18,6 @@ use function wp_update_post; use function PHPStan\Testing\assertType; -/* - * wp_insert_link() - */ -assertType('int<0, max>', wp_insert_link([])); -assertType('int<0, max>', wp_insert_link([], false)); -assertType('int<0, max>|WP_Error', wp_insert_link([], true)); -assertType('int<0, max>|WP_Error', wp_insert_link([], Faker::bool())); - /* * wp_insert_category() */ diff --git a/tests/data/wp_update_link.php b/tests/data/wp_update_link.php deleted file mode 100644 index 88a195e..0000000 --- a/tests/data/wp_update_link.php +++ /dev/null @@ -1,12 +0,0 @@ -|WP_Error', wp_update_link([])); -assertType('int<0, max>|WP_Error', wp_update_link(['linkd_id' => 123])); -assertType('int<0, max>|WP_Error', wp_update_link(Faker::array())); diff --git a/wordpress-stubs.php b/wordpress-stubs.php index b5b4a47..3551270 100644 --- a/wordpress-stubs.php +++ b/wordpress-stubs.php @@ -82401,6 +82401,7 @@ function wp_ajax_send_password_reset() * @since 2.0.0 * * @return int|WP_Error Value 0 or WP_Error on failure. The link ID on success. + * @phpstan-return int<0, max> */ function add_link() { @@ -82412,6 +82413,7 @@ function add_link() * * @param int $link_id Optional. ID of the link to edit. Default 0. * @return int|WP_Error Value 0 or WP_Error on failure. The link ID on success. + * @phpstan-return int<0, max> */ function edit_link($link_id = 0) { @@ -82422,6 +82424,8 @@ function edit_link($link_id = 0) * @since 2.0.0 * * @return stdClass Default link object. + * @phpstan-impure + * @phpstan-return object{link_url: string, link_name: string, link_visible: 'Y'}&\stdClass */ function get_default_link_to_edit() { @@ -82446,6 +82450,7 @@ function wp_delete_link($link_id) * * @param int $link_id Link ID to look up. * @return int[] The IDs of the requested link's categories. + * @phpstan-return ($link_id is empty ? array{} : array>) */ function wp_get_link_cats($link_id = 0) { @@ -82544,7 +82549,7 @@ function wp_set_link_cats($link_id = 0, $link_categories = array()) * link_rss?: string, * link_category?: int, * } $linkdata See wp_insert_link() - * @phpstan-return int<0, max>|\WP_Error + * @phpstan-return int<0, max> */ function wp_update_link($linkdata) { @@ -99171,6 +99176,8 @@ function get_bookmark($bookmark, $output = \OBJECT, $filter = 'raw') * @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 + * @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 array>|int|string|\WP_Error */ function get_bookmark_field($field, $bookmark, $context = 'display') { @@ -99265,6 +99272,8 @@ function sanitize_bookmark($bookmark, $context = 'display') * 'display', 'attribute', or 'js'. Default 'display'. * @return mixed The filtered value. * @phpstan-param 'raw'|'edit'|'db'|'display'|'attribute'|'js' $context + * @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 array|int|string */ function sanitize_bookmark_field($field, $value, $bookmark_id, $context) {