From c2a12ea5732b183873aefecd703193bdab9a88cf Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Tue, 1 Oct 2024 02:18:13 +0200 Subject: [PATCH 01/40] NEW static analyze test PHPStan (for WordPress) --- .distignore | 2 + .gitignore | 1 + composer.json | 3 +- composer.lock | 247 +++++++++++++++++++++++++++++++++++++++++++++- phpstan.neon.dist | 20 ++++ 5 files changed, 271 insertions(+), 2 deletions(-) create mode 100644 phpstan.neon.dist diff --git a/.distignore b/.distignore index 47ccea3c3..9065e1a5b 100755 --- a/.distignore +++ b/.distignore @@ -27,6 +27,8 @@ package-lock.json phpcs.xml phpcs.xml.dist phpcs.ruleset.xml +phpstan.neon +phpstan.neon.dist phpunit.xml phpunit.xml.dist playwright.config.js diff --git a/.gitignore b/.gitignore index 6aa213174..95070a5dc 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ typings # Composer # ########## vendor +phpstan.neon # .wp-env # ########## diff --git a/composer.json b/composer.json index 6ee451593..22198f88d 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,8 @@ "wp-coding-standards/wpcs": "*", "phpcompatibility/phpcompatibility-wp": "*", "phpunit/phpunit": "*", - "yoast/phpunit-polyfills": "*" + "yoast/phpunit-polyfills": "*", + "szepeviktor/phpstan-wordpress": "^1.3" }, "suggest": { "wp-cli/wp-cli-bundle": "Combines the most common WP-CLI commands, including the wp-cli/i18n-command which should be used to create translation-files." diff --git a/composer.lock b/composer.lock index ddb98007a..cc56c924a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4392128689f0f8df116afe7925bd51c3", + "content-hash": "a0329d7079caf0254604e8149663aa90", "packages": [ { "name": "hamcrest/hamcrest-php", @@ -552,6 +552,54 @@ }, "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "php-stubs/wordpress-stubs", + "version": "v6.6.2", + "source": { + "type": "git", + "url": "https://github.com/php-stubs/wordpress-stubs.git", + "reference": "f50fd7ed45894d036e4fef9ab7e5bbbaff6a30cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-stubs/wordpress-stubs/zipball/f50fd7ed45894d036e4fef9ab7e5bbbaff6a30cc", + "reference": "f50fd7ed45894d036e4fef9ab7e5bbbaff6a30cc", + "shasum": "" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "nikic/php-parser": "^4.13", + "php": "^7.4 || ^8.0", + "php-stubs/generator": "^0.8.3", + "phpdocumentor/reflection-docblock": "^5.4.1", + "phpstan/phpstan": "^1.10.49", + "phpunit/phpunit": "^9.5", + "szepeviktor/phpcs-psr-12-neutron-hybrid-ruleset": "^1.0", + "wp-coding-standards/wpcs": "3.1.0 as 2.3.0" + }, + "suggest": { + "paragonie/sodium_compat": "Pure PHP implementation of libsodium", + "symfony/polyfill-php80": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "szepeviktor/phpstan-wordpress": "WordPress extensions for PHPStan" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "WordPress function and class declaration stubs for static analysis.", + "homepage": "https://github.com/php-stubs/wordpress-stubs", + "keywords": [ + "PHPStan", + "static analysis", + "wordpress" + ], + "support": { + "issues": "https://github.com/php-stubs/wordpress-stubs/issues", + "source": "https://github.com/php-stubs/wordpress-stubs/tree/v6.6.2" + }, + "time": "2024-09-30T07:10:48+00:00" + }, { "name": "phpcompatibility/php-compatibility", "version": "9.3.5", @@ -892,6 +940,64 @@ ], "time": "2023-12-08T14:50:00+00:00" }, + { + "name": "phpstan/phpstan", + "version": "1.12.5", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "7e6c6cb7cecb0a6254009a1a8a7d54ec99812b17" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/7e6c6cb7cecb0a6254009a1a8a7d54ec99812b17", + "reference": "7e6c6cb7cecb0a6254009a1a8a7d54ec99812b17", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2024-09-26T12:45:22+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "9.2.30", @@ -2358,6 +2464,145 @@ ], "time": "2024-01-11T20:47:48+00:00" }, + { + "name": "symfony/polyfill-php73", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "szepeviktor/phpstan-wordpress", + "version": "v1.3.5", + "source": { + "type": "git", + "url": "https://github.com/szepeviktor/phpstan-wordpress.git", + "reference": "7f8cfe992faa96b6a33bbd75c7bace98864161e7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/szepeviktor/phpstan-wordpress/zipball/7f8cfe992faa96b6a33bbd75c7bace98864161e7", + "reference": "7f8cfe992faa96b6a33bbd75c7bace98864161e7", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "php-stubs/wordpress-stubs": "^4.7 || ^5.0 || ^6.0", + "phpstan/phpstan": "^1.10.31", + "symfony/polyfill-php73": "^1.12.0" + }, + "require-dev": { + "composer/composer": "^2.1.14", + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.1", + "phpstan/phpstan-strict-rules": "^1.2", + "phpunit/phpunit": "^8.0 || ^9.0", + "szepeviktor/phpcs-psr-12-neutron-hybrid-ruleset": "^1.0", + "wp-coding-standards/wpcs": "3.1.0 as 2.3.0" + }, + "suggest": { + "swissspidy/phpstan-no-private": "Detect usage of internal core functions, classes and methods" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "autoload": { + "psr-4": { + "SzepeViktor\\PHPStan\\WordPress\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "WordPress extensions for PHPStan", + "keywords": [ + "PHPStan", + "code analyse", + "code analysis", + "static analysis", + "wordpress" + ], + "support": { + "issues": "https://github.com/szepeviktor/phpstan-wordpress/issues", + "source": "https://github.com/szepeviktor/phpstan-wordpress/tree/v1.3.5" + }, + "time": "2024-06-28T22:27:19+00:00" + }, { "name": "theseer/tokenizer", "version": "1.2.2", diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 000000000..015a47d55 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,20 @@ +includes: + - vendor/szepeviktor/phpstan-wordpress/extension.neon +parameters: + + # the analysis level, from 0 (loose) to 8 (strict) + # https://phpstan.org/user-guide/rule-levels + level: 5 + + paths: + - includes/ + + excludePaths: + - vendor/ + + ignoreErrors: + - '#^Constant GATHERPRESS_CORE_FILE not found\.$#' + - '#^Constant GATHERPRESS_CORE_PATH not found\.$#' + - '#^Constant GATHERPRESS_CORE_URL not found\.$#' + - '#^Constant GATHERPRESS_REST_NAMESPACE not found\.$#' + - '#^Constant GATHERPRESS_REQUIRES_PHP not found\.$#' From c9517dff03c938dff4c8ce3563ea36f1e8a99cc2 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Tue, 1 Oct 2024 02:19:12 +0200 Subject: [PATCH 02/40] NEW Github actions workflowe to run PHPStan --- .github/workflows/phpstan-tests.yml | 44 +++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/workflows/phpstan-tests.yml diff --git a/.github/workflows/phpstan-tests.yml b/.github/workflows/phpstan-tests.yml new file mode 100644 index 000000000..74584e725 --- /dev/null +++ b/.github/workflows/phpstan-tests.yml @@ -0,0 +1,44 @@ +name: PHPStan Tests +on: + push: + branches: + - main + pull_request: + paths: + - '.github/workflows/phpstan-tests.yml' + - 'includes/**' + # - 'test/unit/php**' + # - '*.php' + - 'phpstan.neon.dist' + - 'composer.*' +jobs: + test-phpstan: + name: PHPStan for WordPress + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + # phpstan requires PHP 7.1+. + php-version: 7.4 + extensions: dom, iconv, json, libxml, zip + coverage: none + tools: cs2pr + + - name: Composer Install + run: composer install --optimize-autoloader --prefer-dist + + - name: Log debug information + run: | + git --version + php --version + composer --version + + - name: Running PHPStan Analyze + if: ${{ success() || failure() }} + run: | + vendor/bin/phpstan --version + vendor/bin/phpstan analyze -vv --memory-limit=2G --error-format=checkstyle | cs2pr From 05d247ced8e502c8eba64caa5a50e56244ea47e1 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Tue, 1 Oct 2024 02:19:58 +0200 Subject: [PATCH 03/40] Minor fix to prevent phpdoc.parseError --- includes/core/classes/traits/class-singleton.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/core/classes/traits/class-singleton.php b/includes/core/classes/traits/class-singleton.php index c207100fc..4c6f08808 100644 --- a/includes/core/classes/traits/class-singleton.php +++ b/includes/core/classes/traits/class-singleton.php @@ -27,9 +27,9 @@ trait Singleton { * The single instance of the class. * * @since 1.0.0 - * @var ?self|null The instance of the class. + * @var self|null The instance of the class or null if not instantiated. */ - private static $instance = null; + private static ?self $instance = null; /** * Get the instance of the Singleton class. From 63b20e638069c70076e814389e69adb1ab064baf Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Tue, 1 Oct 2024 03:31:52 +0200 Subject: [PATCH 04/40] Use additional bleedingEdge config --- phpstan.neon.dist | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 015a47d55..572248d75 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,16 +1,32 @@ includes: - vendor/szepeviktor/phpstan-wordpress/extension.neon + # Bleeding edge offers a preview of the next major version. + # When you enable Bleeding edge in your configuration file, you will get new rules, + # behaviour, and bug fixes that will be enabled for everyone later + # when the next PHPStan’s major version is released. + - phar://phpstan.phar/conf/bleedingEdge.neon + parameters: +# bootstrapFiles: +# - vendor/pmc/unit-test/src/classes/autoloader.php +# - vendor/autoload.php +# - gatherpress.php + + parallel: + maximumNumberOfProcesses: 1 + processTimeout: 300.0 - # the analysis level, from 0 (loose) to 8 (strict) + # the analysis level, from 0 (loose) to 9 (strict) # https://phpstan.org/user-guide/rule-levels level: 5 paths: - includes/ +# - test/ - excludePaths: - - vendor/ +# excludePaths: +# analyse: +# - vendor/ ignoreErrors: - '#^Constant GATHERPRESS_CORE_FILE not found\.$#' From 6dab970947a48b9f7c09c066f06855b98119b0b0 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 03:09:47 +0200 Subject: [PATCH 05/40] Fix: Parameter #1 $version1 of function version_compare expects string, int<50207, max> given. --- includes/core/requirements-check.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/core/requirements-check.php b/includes/core/requirements-check.php index 0f2c2f674..0d1786973 100644 --- a/includes/core/requirements-check.php +++ b/includes/core/requirements-check.php @@ -14,7 +14,7 @@ $gatherpress_activation = true; // Check the PHP version to ensure compatibility with the plugin. -if ( version_compare( PHP_VERSION_ID, GATHERPRESS_REQUIRES_PHP, '<' ) ) { +if ( version_compare( PHP_VERSION, GATHERPRESS_REQUIRES_PHP, '<' ) ) { add_action( 'admin_notices', static function () { From 7bdf65a6d2c6f518c4a0ab27c2235777e752a184 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 03:13:33 +0200 Subject: [PATCH 06/40] Fix: Parameter #1 $term_id of function wp_update_term expects int, string given. --- includes/core/classes/class-venue.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/core/classes/class-venue.php b/includes/core/classes/class-venue.php index 7022e287f..c6c546d17 100644 --- a/includes/core/classes/class-venue.php +++ b/includes/core/classes/class-venue.php @@ -331,7 +331,7 @@ public function maybe_update_term_slug( int $post_id, WP_Post $post_after, WP_Po } else { // Update the existing term with the new name and slug. wp_update_term( - $term['term_id'], + intval( $term['term_id'] ), self::TAXONOMY, array( 'name' => $title, From 90b8a0b75edb1a550b91adff05e8e5379b201fb9 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 03:21:41 +0200 Subject: [PATCH 07/40] Fix: Path in require_once() "./wp-admin/includes/upgrade.php" is not a file or it does not exist. --- phpstan.neon.dist | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 572248d75..152175c51 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -34,3 +34,8 @@ parameters: - '#^Constant GATHERPRESS_CORE_URL not found\.$#' - '#^Constant GATHERPRESS_REST_NAMESPACE not found\.$#' - '#^Constant GATHERPRESS_REQUIRES_PHP not found\.$#' + + # core/classes/class-setup.php + # + # A dev-only error, which can occur if the gatherpress is symlinked into a WP instance or called via wp-env or Playground. + - '#^Path in require_once\(\) "\./wp-admin/includes/upgrade\.php" is not a file or it does not exist\.$#' From ffeecba01f047db7ca95381841aa7212fe6285d8 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 03:25:43 +0200 Subject: [PATCH 08/40] Fix: Call to sprintf contains 1 placeholder, 2 values given. --- includes/core/classes/class-event-setup.php | 2 +- includes/core/classes/class-setup.php | 2 +- test/unit/php/includes/core/classes/class-test-event-query.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/includes/core/classes/class-event-setup.php b/includes/core/classes/class-event-setup.php index 0a94f3448..3b4365203 100644 --- a/includes/core/classes/class-event-setup.php +++ b/includes/core/classes/class-event-setup.php @@ -329,7 +329,7 @@ public function delete_event( int $post_id ): void { return; } - $table = sprintf( Event::TABLE_FORMAT, $wpdb->prefix, Event::POST_TYPE ); + $table = sprintf( Event::TABLE_FORMAT, $wpdb->prefix ); $wpdb->delete( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $table, diff --git a/includes/core/classes/class-setup.php b/includes/core/classes/class-setup.php index 9752ea043..e1d2eb4b3 100644 --- a/includes/core/classes/class-setup.php +++ b/includes/core/classes/class-setup.php @@ -331,7 +331,7 @@ public function on_site_create( WP_Site $new_site ): void { public function on_site_delete( array $tables ): array { global $wpdb; - $tables[] = sprintf( Event::TABLE_FORMAT, $wpdb->prefix, Event::POST_TYPE ); + $tables[] = sprintf( Event::TABLE_FORMAT, $wpdb->prefix ); return $tables; } diff --git a/test/unit/php/includes/core/classes/class-test-event-query.php b/test/unit/php/includes/core/classes/class-test-event-query.php index 56e82e1cc..164ffbdec 100644 --- a/test/unit/php/includes/core/classes/class-test-event-query.php +++ b/test/unit/php/includes/core/classes/class-test-event-query.php @@ -230,7 +230,7 @@ public function test_adjust_event_sql(): void { $instance = Event_Query::get_instance(); - $table = sprintf( Event::TABLE_FORMAT, $wpdb->prefix, Event::POST_TYPE ); + $table = sprintf( Event::TABLE_FORMAT, $wpdb->prefix ); $retval = $instance->adjust_event_sql( array(), 'all', 'DESC' ); $this->assertStringContainsString( 'DESC', $retval['orderby'] ); From dd691e4aa07c3f24603581706356ed76d494f4d3 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 03:28:00 +0200 Subject: [PATCH 09/40] Fix: Parameter #1 $new_blog_id of function switch_to_blog expects int, string given. --- includes/core/classes/class-setup.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/core/classes/class-setup.php b/includes/core/classes/class-setup.php index e1d2eb4b3..74779eb4d 100644 --- a/includes/core/classes/class-setup.php +++ b/includes/core/classes/class-setup.php @@ -310,7 +310,7 @@ public function add_online_event_term(): void { */ public function on_site_create( WP_Site $new_site ): void { if ( is_plugin_active_for_network( 'gatherpress/gatherpress.php' ) ) { - switch_to_blog( $new_site->blog_id ); + switch_to_blog( intval( $new_site->blog_id ) ); $this->create_tables(); restore_current_blog(); } From 3a571561860f519a45fa82c9bb7d5c448a5f07ff Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 03:29:16 +0200 Subject: [PATCH 10/40] Fix: Parameter #1 $term_id of function wp_update_term expects int, string given. --- includes/core/classes/class-setup.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/core/classes/class-setup.php b/includes/core/classes/class-setup.php index 74779eb4d..f1e9763ef 100644 --- a/includes/core/classes/class-setup.php +++ b/includes/core/classes/class-setup.php @@ -285,7 +285,7 @@ public function add_online_event_term(): void { ); } else { wp_update_term( - $term['term_id'], + intval( $term['term_id'] ), Venue::TAXONOMY, array( 'name' => $term_name, From e4ea84565d71eaa7027f34d71f0098e376e4ec86 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 03:45:08 +0200 Subject: [PATCH 11/40] Fix: Variable $suffix might not be defined. --- includes/core/classes/class-settings.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/includes/core/classes/class-settings.php b/includes/core/classes/class-settings.php index d42643bc1..e809c1119 100644 --- a/includes/core/classes/class-settings.php +++ b/includes/core/classes/class-settings.php @@ -725,8 +725,6 @@ public function urlrewrite_preview( string $name, string $value ): void { $suffix = _x( 'sample-topic-term', 'sample topic term slug', 'gatherpress' ); break; - default: - break; } Utility::render_template( sprintf( '%s/includes/templates/admin/settings/partials/urlrewrite-preview.php', GATHERPRESS_CORE_PATH ), From 684d1ec78fbe3cc62ac84da98a69b5aca1076e71 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 03:46:49 +0200 Subject: [PATCH 12/40] Fix & Unit test: Method GatherPress\Core\Settings::sort_sub_pages_by_priority() should return int but returns bool. --- includes/core/classes/class-settings.php | 3 +- .../core/classes/class-test-settings.php | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/includes/core/classes/class-settings.php b/includes/core/classes/class-settings.php index e809c1119..92d04e054 100644 --- a/includes/core/classes/class-settings.php +++ b/includes/core/classes/class-settings.php @@ -614,7 +614,7 @@ public function sort_sub_pages_by_priority( array $first, array $second ): int { $first['priority'] = isset( $first['priority'] ) ? intval( $first['priority'] ) : 10; $second['priority'] = isset( $second['priority'] ) ? intval( $second['priority'] ) : 10; - return ( $first['priority'] > $second['priority'] ); + return $first['priority'] <=> $second['priority']; } /** @@ -724,7 +724,6 @@ public function urlrewrite_preview( string $name, string $value ): void { case 'gatherpress_general[urls][topics]': $suffix = _x( 'sample-topic-term', 'sample topic term slug', 'gatherpress' ); break; - } Utility::render_template( sprintf( '%s/includes/templates/admin/settings/partials/urlrewrite-preview.php', GATHERPRESS_CORE_PATH ), diff --git a/test/unit/php/includes/core/classes/class-test-settings.php b/test/unit/php/includes/core/classes/class-test-settings.php index 6483d8ee8..6d338a606 100644 --- a/test/unit/php/includes/core/classes/class-test-settings.php +++ b/test/unit/php/includes/core/classes/class-test-settings.php @@ -329,4 +329,34 @@ public function test_get_sub_pages(): void { 'Failed to assert that credits is last key.' ); } + + /** + * Coverage for sort_sub_pages_by_priority method. + * + * @covers ::sort_sub_pages_by_priority + * + * @return void + */ + public function test_sort_sub_pages_by_priority(): void { + $instance = Settings::get_instance(); + $sub_pages = $instance->get_sub_pages(); + + $this->assertSame( + -1, + $instance->sort_sub_pages_by_priority( array( 'priority' => 2 ), array( 'priority' => 42 ) ), + 'Failed to assert that it returns a negative number while the first sub-page has a lower priority.' + ); + + $this->assertSame( + 1, + $instance->sort_sub_pages_by_priority( array( 'priority' => 42 ), array( 'priority' => 2 ) ), + 'Failed to assert that it returns a positive number while the second sub-page has a lower priority.' + ); + + $this->assertSame( + 0, + $instance->sort_sub_pages_by_priority( array( 'priority' => 42 ), array( 'priority' => 42 ) ), + 'Failed to assert that it returns 0 while their priorities are equal.' + ); + } } From 968ac3b056382c8436c3f76950ac476638706226 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 03:57:09 +0200 Subject: [PATCH 13/40] Fix: Parameter #3 $group of function wp_cache_set expects string, int given. --- includes/core/classes/class-rsvp.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/core/classes/class-rsvp.php b/includes/core/classes/class-rsvp.php index 4da755339..317da70c2 100644 --- a/includes/core/classes/class-rsvp.php +++ b/includes/core/classes/class-rsvp.php @@ -496,7 +496,7 @@ static function ( $response ) use ( $status ) { $retval[ $status ]['count'] = count( $retval[ $status ]['responses'] ) + $guests; } - wp_cache_set( $cache_key, $retval, 15 * MINUTE_IN_SECONDS ); + wp_cache_set( $cache_key, $retval, '', 15 * MINUTE_IN_SECONDS ); return $retval; } From 3242163db44d281b8ca2ca1806d4af952c7910ae Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 05:17:40 +0200 Subject: [PATCH 14/40] Parameter #2 $callback of function usort expects callable(array, array): int, array{$this(GatherPress\Core\Rsvp), 'sort_by_timestamp'} given. --- includes/core/classes/class-rsvp.php | 8 +++++--- .../includes/core/classes/class-test-rsvp.php | 19 ++++++++++++++----- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/includes/core/classes/class-rsvp.php b/includes/core/classes/class-rsvp.php index 317da70c2..dbcc83366 100644 --- a/includes/core/classes/class-rsvp.php +++ b/includes/core/classes/class-rsvp.php @@ -542,9 +542,11 @@ static function ( $role ) { * * @param array $first First response to compare in the sort. * @param array $second Second response to compare in the sort. - * @return bool True if the first response's timestamp is earlier than the second response's timestamp; otherwise, false. + * @return int Returns a negative number if the first response's timestamp is earlier, + * a positive number if the second response's timestamp is earlier, + * or 0 if both are equal. */ - public function sort_by_timestamp( array $first, array $second ): bool { - return ( strtotime( $first['timestamp'] ) > strtotime( $second['timestamp'] ) ); + public function sort_by_timestamp( array $first, array $second ): int { + return strtotime( $first['timestamp'] ) <=> strtotime( $second['timestamp'] ); } } diff --git a/test/unit/php/includes/core/classes/class-test-rsvp.php b/test/unit/php/includes/core/classes/class-test-rsvp.php index f94bc115a..fc1158917 100644 --- a/test/unit/php/includes/core/classes/class-test-rsvp.php +++ b/test/unit/php/includes/core/classes/class-test-rsvp.php @@ -344,13 +344,22 @@ public function test_sort_by_timestamp(): void { $newer = array( 'timestamp' => '2023-05-11 08:30:00' ); $older = array( 'timestamp' => '2022-05-11 08:30:00' ); - $this->assertTrue( + $this->assertSame( + -1, + $rsvp->sort_by_timestamp( $older, $newer ), + 'Failed to assert that it returns a negative number while the first response\'s timestamp is earlier.' + ); + + $this->assertSame( + 1, $rsvp->sort_by_timestamp( $newer, $older ), - 'Failed to assert correct sorting of timestamp.' + 'Failed to assert that it returns a positive number while the second response\'s timestamp is earlier.' ); - $this->assertFalse( - $rsvp->sort_by_timestamp( $older, $newer ), - 'Failed to assert correct sorting of timestamp.' + + $this->assertSame( + 0, + $rsvp->sort_by_timestamp( $newer, $newer ), + 'Failed to assert that it returns 0 while both response\'s timestamps are equal.' ); } } From 2ed2443f11130a3057e6c1e68d18611424158cf2 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 05:42:29 +0200 Subject: [PATCH 15/40] Revert "Fix: Parameter #3 $group of function wp_cache_set expects string, int given." This reverts commit 968ac3b056382c8436c3f76950ac476638706226. --- includes/core/classes/class-rsvp.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/core/classes/class-rsvp.php b/includes/core/classes/class-rsvp.php index dbcc83366..7d30bbb6c 100644 --- a/includes/core/classes/class-rsvp.php +++ b/includes/core/classes/class-rsvp.php @@ -496,7 +496,7 @@ static function ( $response ) use ( $status ) { $retval[ $status ]['count'] = count( $retval[ $status ]['responses'] ) + $guests; } - wp_cache_set( $cache_key, $retval, '', 15 * MINUTE_IN_SECONDS ); + wp_cache_set( $cache_key, $retval, 15 * MINUTE_IN_SECONDS ); return $retval; } From c86472d9e4ee480ce3c1a9c29cb051649be36129 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 14:49:08 +0200 Subject: [PATCH 16/40] Fix: One or more @ param tags has an invalid name or invalid syntax. --- includes/core/classes/class-import.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/core/classes/class-import.php b/includes/core/classes/class-import.php index afb2d3ef8..dcdb74105 100644 --- a/includes/core/classes/class-import.php +++ b/includes/core/classes/class-import.php @@ -86,7 +86,7 @@ public function prepare( array $post_data_raw ): array { * * @since 1.0.0 * - * @param {array} $post_data_raw Unprocessesd 'gatherpress_event' post being imported. + * @param array $post_data_raw Unprocessesd 'gatherpress_event' post being imported. */ do_action( 'gatherpress_import', $post_data_raw ); } From 0d4b8fdd5a74a615072a343d37ab2a0524802447 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 14:51:25 +0200 Subject: [PATCH 17/40] Fix: Callback expects 1 parameter, $accepted_args is set to 2. --- includes/core/classes/class-export.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/core/classes/class-export.php b/includes/core/classes/class-export.php index aac01eeb8..bc4ebd2a4 100644 --- a/includes/core/classes/class-export.php +++ b/includes/core/classes/class-export.php @@ -73,7 +73,7 @@ protected function setup_hooks(): void { * @return void */ public function export(): void { - add_action( 'the_post', array( $this, 'prepare' ), 10, 2 ); + add_action( 'the_post', array( $this, 'prepare' ) ); add_filter( 'wxr_export_skip_postmeta', array( $this, 'extend' ), 10, 3 ); } From b237d927dc56e637d0c3373008ae8dec81802ffe Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 15:05:08 +0200 Subject: [PATCH 18/40] Fix: Expression on left side of ?? is not nullable. (Because get_permalink returns FALSE, not NULL if it fails) --- includes/core/classes/class-event.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/core/classes/class-event.php b/includes/core/classes/class-event.php index 66e491363..2a26988f8 100644 --- a/includes/core/classes/class-event.php +++ b/includes/core/classes/class-event.php @@ -412,7 +412,7 @@ public function get_venue_information(): array { $venue_information['full_address'] = $venue_meta->fullAddress ?? ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase $venue_information['phone_number'] = $venue_meta->phoneNumber ?? ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase $venue_information['website'] = $venue_meta->website ?? ''; - $venue_information['permalink'] = get_permalink( $venue->ID ) ?? ''; + $venue_information['permalink'] = get_permalink( $venue->ID ) ?: ''; } return $venue_information; From f0e15db18b811eea7ae487050f32a93de0bb6d09 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 15:08:53 +0200 Subject: [PATCH 19/40] Fix: Parameter #1 $string of function str_pad expects string, int given. --- includes/core/classes/class-event.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/core/classes/class-event.php b/includes/core/classes/class-event.php index 2a26988f8..67cdab58d 100644 --- a/includes/core/classes/class-event.php +++ b/includes/core/classes/class-event.php @@ -525,8 +525,8 @@ protected function get_yahoo_calendar_link(): string { $duration = ( ( strtotime( $diff_end ) - strtotime( $diff_start ) ) / 60 / 60 ); $full = intval( $duration ); $fraction = ( $duration - $full ); - $hours = str_pad( intval( $duration ), 2, '0', STR_PAD_LEFT ); - $minutes = str_pad( intval( $fraction * 60 ), 2, '0', STR_PAD_LEFT ); + $hours = str_pad( strval( $duration ), 2, '0', STR_PAD_LEFT ); + $minutes = str_pad( strval( $fraction * 60 ), 2, '0', STR_PAD_LEFT ); $venue = $this->get_venue_information(); $location = $venue['name']; $description = $this->get_calendar_description(); From b754286d32520863694c2fd510d03fbdb4abffbe Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 22:50:40 +0200 Subject: [PATCH 20/40] Fix: Class WP_Comment referenced with incorrect case: WP_comment. --- includes/core/classes/class-rsvp-query.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/core/classes/class-rsvp-query.php b/includes/core/classes/class-rsvp-query.php index 974bf3c2a..905b312ed 100644 --- a/includes/core/classes/class-rsvp-query.php +++ b/includes/core/classes/class-rsvp-query.php @@ -15,7 +15,7 @@ defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use GatherPress\Core\Traits\Singleton; -use WP_comment; +use WP_Comment; use WP_Comment_Query; use WP_Tax_Query; From 4125173ee6e9b17efc9585761432556ad760aa26 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 22:58:46 +0200 Subject: [PATCH 21/40] Fix: Filter callback return statement is missing. Because 'pre_get_comments' is an action, not a filter. --- includes/core/classes/class-rsvp-query.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/includes/core/classes/class-rsvp-query.php b/includes/core/classes/class-rsvp-query.php index 905b312ed..a0af41639 100644 --- a/includes/core/classes/class-rsvp-query.php +++ b/includes/core/classes/class-rsvp-query.php @@ -54,7 +54,7 @@ protected function __construct() { * @return void */ protected function setup_hooks(): void { - add_filter( 'pre_get_comments', array( $this, 'exclude_rsvp_from_comment_query' ) ); + add_action( 'pre_get_comments', array( $this, 'exclude_rsvp_from_comment_query' ) ); add_filter( 'comments_clauses', array( $this, 'taxonomy_query' ), 10, 2 ); } @@ -107,11 +107,11 @@ public function get_rsvps( array $args ): array { // Never allow count-only return, we always want array. $args['count'] = false; - remove_filter( 'pre_get_comments', array( $this, 'exclude_rsvp_from_comment_query' ) ); + remove_action( 'pre_get_comments', array( $this, 'exclude_rsvp_from_comment_query' ) ); $rsvps = get_comments( $args ); - add_filter( 'pre_get_comments', array( $this, 'exclude_rsvp_from_comment_query' ) ); + add_action( 'pre_get_comments', array( $this, 'exclude_rsvp_from_comment_query' ) ); return (array) $rsvps; } From 511330de56a4b05b2d1334817f292ab40b535b70 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 22:59:45 +0200 Subject: [PATCH 22/40] Ignore CS warning: Universal.Operators.DisallowShortTernary.Found --- includes/core/classes/class-event.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/core/classes/class-event.php b/includes/core/classes/class-event.php index 67cdab58d..37fee8c86 100644 --- a/includes/core/classes/class-event.php +++ b/includes/core/classes/class-event.php @@ -412,7 +412,7 @@ public function get_venue_information(): array { $venue_information['full_address'] = $venue_meta->fullAddress ?? ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase $venue_information['phone_number'] = $venue_meta->phoneNumber ?? ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase $venue_information['website'] = $venue_meta->website ?? ''; - $venue_information['permalink'] = get_permalink( $venue->ID ) ?: ''; + $venue_information['permalink'] = get_permalink( $venue->ID ) ?: ''; // phpcs:ignore Universal.Operators.DisallowShortTernary.Found } return $venue_information; From 33fcfeb46992657ce8d88b5d64c3c8a8fd79f116 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 23:05:05 +0200 Subject: [PATCH 23/40] Fix: Instanceof between WP_Comment_Query and WP_Comment_Query will always evaluate to true. --- includes/core/classes/class-rsvp-query.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/includes/core/classes/class-rsvp-query.php b/includes/core/classes/class-rsvp-query.php index a0af41639..0153de33d 100644 --- a/includes/core/classes/class-rsvp-query.php +++ b/includes/core/classes/class-rsvp-query.php @@ -153,13 +153,10 @@ public function get_rsvp( array $args ): ?WP_Comment { * * @since 1.0.0 * - * @param WP_Comment_Query $query The comment query object. + * @param WP_Comment_Query $query Current instance of WP_Comment_Query (passed by reference). * @return void */ - public function exclude_rsvp_from_comment_query( $query ) { - if ( ! $query instanceof WP_Comment_Query ) { - return; - } + public function exclude_rsvp_from_comment_query( WP_Comment_Query $query ) { $current_comment_types = $query->query_vars['type']; From df75ff940ac14448f035e6e224fd1fb53462f6e7 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 23:13:13 +0200 Subject: [PATCH 24/40] Fix: Access to an undefined property WP_Comment_Query::$tax_query. --- includes/core/classes/class-rsvp-query.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/includes/core/classes/class-rsvp-query.php b/includes/core/classes/class-rsvp-query.php index 0153de33d..505641be0 100644 --- a/includes/core/classes/class-rsvp-query.php +++ b/includes/core/classes/class-rsvp-query.php @@ -67,17 +67,17 @@ protected function setup_hooks(): void { * @since 1.0.0 * * @param array $clauses The clauses for the query. - * @param WP_Comment_Query $comment_query The comment query object. + * @param WP_Comment_Query $comment_query Current instance of WP_Comment_Query (passed by reference). * @return array Modified query clauses. */ public function taxonomy_query( array $clauses, WP_Comment_Query $comment_query ): array { global $wpdb; if ( ! empty( $comment_query->query_vars['tax_query'] ) ) { - $comment_query->tax_query = new WP_Tax_Query( $comment_query->query_vars['tax_query'] ); - $pieces = $comment_query->tax_query->get_sql( $wpdb->comments, 'comment_ID' ); - $clauses['join'] .= $pieces['join']; - $clauses['where'] .= $pieces['where']; + $comment_tax_query = new WP_Tax_Query( $comment_query->query_vars['tax_query'] ); + $pieces = $comment_tax_query->get_sql( $wpdb->comments, 'comment_ID' ); + $clauses['join'] .= $pieces['join']; + $clauses['where'] .= $pieces['where']; } return $clauses; From 8b82f0fa00226ee9badb1b296531e7a01a423d12 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Thu, 3 Oct 2024 23:40:15 +0200 Subject: [PATCH 25/40] Fix: Function wxr_cdata not found. (https://github.com/szepeviktor/phpstan-wordpress/issues/241) --- .distignore | 1 + phpstan.neon.dist | 5 +++-- phpstan.stubs | 17 +++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 phpstan.stubs diff --git a/.distignore b/.distignore index 9065e1a5b..4f2b58537 100755 --- a/.distignore +++ b/.distignore @@ -29,6 +29,7 @@ phpcs.xml.dist phpcs.ruleset.xml phpstan.neon phpstan.neon.dist +phpstan.stubs phpunit.xml phpunit.xml.dist playwright.config.js diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 152175c51..6620347d4 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -7,11 +7,12 @@ includes: - phar://phpstan.phar/conf/bleedingEdge.neon parameters: -# bootstrapFiles: + bootstrapFiles: + # Constants, functions, etc. used by GatherPress + - phpstan.stubs # - vendor/pmc/unit-test/src/classes/autoloader.php # - vendor/autoload.php # - gatherpress.php - parallel: maximumNumberOfProcesses: 1 processTimeout: 300.0 diff --git a/phpstan.stubs b/phpstan.stubs new file mode 100644 index 000000000..613c19716 --- /dev/null +++ b/phpstan.stubs @@ -0,0 +1,17 @@ + Date: Fri, 4 Oct 2024 01:30:13 +0200 Subject: [PATCH 26/40] Add shortcut to run phpstan Which is way more performant: vendor/bin/phpstan analyze -vv --memory-limit=2G Elapsed time: 5 seconds Used memory: 663.28 MB Elapsed time: 10 seconds Used memory: 1.08 GB composer test:phpstan (which runs `vendor/bin/phpstan analyze -vv --memory-limit=2G` under the hood) Elapsed time: Used memory: 70.5 MB --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 22198f88d..55cb65467 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,8 @@ "format": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcbf --report=summary,source", "lint": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs --report=summary,source", "lint:errors": "@lint -n", - "test": "@php ./vendor/phpunit/phpunit/phpunit" + "test": "@php ./vendor/phpunit/phpunit/phpunit", + "test:phpstan": "@php ./vendor/bin/phpstan analyze -vv --memory-limit=2G" }, "config": { "allow-plugins": { From ca595d57ed52ce04f8f51040d435e2bc1de284b9 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Fri, 4 Oct 2024 01:37:28 +0200 Subject: [PATCH 27/40] Fix: Variable $option might not be defined. --- includes/templates/admin/settings/fields/select.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/includes/templates/admin/settings/fields/select.php b/includes/templates/admin/settings/fields/select.php index a847bdb65..5b5558308 100644 --- a/includes/templates/admin/settings/fields/select.php +++ b/includes/templates/admin/settings/fields/select.php @@ -10,6 +10,7 @@ * @param string $name The name attribute for the input field. * @param string $label The label text displayed next to the checkbox. * @param string $option The option name in which the field value is stored. + * @param string $options The options for the select field. * @param mixed $value The current value of the checkbox (boolean or equivalent). * @param string $description Optional. The description or tooltip text for the field. */ @@ -17,7 +18,7 @@ // Exit if accessed directly. defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore -if ( ! isset( $name, $label, $options, $options['items'], $value, $description ) ) { +if ( ! isset( $name, $label, $option, $options, $options['items'], $value, $description ) ) { return; } ?> From 6f36dc1a1606d4d8917583d2e5d47932dd680851 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Fri, 4 Oct 2024 01:54:44 +0200 Subject: [PATCH 28/40] Fix: Result of function selected (void) is used. AND (Parameter #1 (void) of echo cannot be converted to string.) which was a false positive. --- includes/templates/admin/settings/fields/select.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/templates/admin/settings/fields/select.php b/includes/templates/admin/settings/fields/select.php index 5b5558308..9bee92139 100644 --- a/includes/templates/admin/settings/fields/select.php +++ b/includes/templates/admin/settings/fields/select.php @@ -28,7 +28,7 @@ $gatherpress_label ) : ?> - Date: Fri, 4 Oct 2024 02:00:29 +0200 Subject: [PATCH 29/40] Fix: Expression on left side of ?? is not nullable. --- includes/core/classes/class-assets.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/core/classes/class-assets.php b/includes/core/classes/class-assets.php index 347c595fb..0182415c3 100644 --- a/includes/core/classes/class-assets.php +++ b/includes/core/classes/class-assets.php @@ -104,8 +104,8 @@ protected function setup_hooks(): void { * @return void */ public function add_global_object(): void { - ?> - + // phpcs:ignore Universal.Operators.DisallowShortTernary.Found ?> + Date: Fri, 4 Oct 2024 02:03:43 +0200 Subject: [PATCH 30/40] Fix: Expression "$blocks" on a separate line does not do anything. --- includes/core/classes/class-assets.php | 1 - 1 file changed, 1 deletion(-) diff --git a/includes/core/classes/class-assets.php b/includes/core/classes/class-assets.php index 0182415c3..766bc6c85 100644 --- a/includes/core/classes/class-assets.php +++ b/includes/core/classes/class-assets.php @@ -385,7 +385,6 @@ protected function unregister_blocks(): array { switch ( get_post_type() ) { case Event::POST_TYPE: - $blocks; break; case Venue::POST_TYPE: $blocks = array( From e58785e5ddabcf6cd446f00e2b498c1c3cbd95d2 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Fri, 4 Oct 2024 02:11:50 +0200 Subject: [PATCH 31/40] Fix: Parameter #1 $comment_id of function get_comment_meta expects int, string given. AND Parameter #1 $object_ids of function wp_get_object_terms expects array|int, string given. --- includes/core/classes/class-rsvp.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/includes/core/classes/class-rsvp.php b/includes/core/classes/class-rsvp.php index 7d30bbb6c..390631624 100644 --- a/includes/core/classes/class-rsvp.php +++ b/includes/core/classes/class-rsvp.php @@ -137,9 +137,9 @@ public function get( int $user_id ): array { if ( ! empty( $rsvp ) ) { $data['id'] = $rsvp->user_id; $data['timestamp'] = $rsvp->comment_date; - $data['anonymous'] = intval( get_comment_meta( $rsvp->comment_ID, 'gatherpress_rsvp_anonymous', true ) ); - $data['guests'] = intval( get_comment_meta( $rsvp->comment_ID, 'gatherpress_rsvp_guests', true ) ); - $terms = wp_get_object_terms( $rsvp->comment_ID, self::TAXONOMY ); + $data['anonymous'] = intval( get_comment_meta( intval( $rsvp->comment_ID ), 'gatherpress_rsvp_anonymous', true ) ); + $data['guests'] = intval( get_comment_meta( intval( $rsvp->comment_ID ), 'gatherpress_rsvp_guests', true ) ); + $terms = wp_get_object_terms( intval( $rsvp->comment_ID ), self::TAXONOMY ); if ( ! empty( $terms ) && is_array( $terms ) ) { $data['status'] = $terms[0]->slug; From 0ad3a3e80cb76893bf8b71e91051508372d3f1bc Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Fri, 4 Oct 2024 02:15:38 +0200 Subject: [PATCH 32/40] Fix: Call to function is_wp_error() with int|string|false will always evaluate to false. --- includes/core/classes/class-rsvp.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/core/classes/class-rsvp.php b/includes/core/classes/class-rsvp.php index 390631624..fc1674269 100644 --- a/includes/core/classes/class-rsvp.php +++ b/includes/core/classes/class-rsvp.php @@ -239,7 +239,7 @@ public function save( int $user_id, string $status, int $anonymous = 0, int $gue wp_update_comment( $args ); } - if ( is_wp_error( $comment_id ) || empty( $comment_id ) ) { + if ( empty( $comment_id ) ) { return $data; } From 9d967fb6cf0473fd1c95d9b887a5cf9e6e0e6b4e Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Fri, 4 Oct 2024 02:22:54 +0200 Subject: [PATCH 33/40] Fix: Offset 'approved' on array{approved: int, awaiting_moderation: int, spam: int, trash: int, post-trashed: int, total_comments: int, all: int} on left side of ?? always exists and is not nullable. --- includes/core/classes/class-rsvp-setup.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/core/classes/class-rsvp-setup.php b/includes/core/classes/class-rsvp-setup.php index 81b774a1d..7720350d8 100644 --- a/includes/core/classes/class-rsvp-setup.php +++ b/includes/core/classes/class-rsvp-setup.php @@ -98,6 +98,6 @@ public function adjust_comments_number( int $comments_number, int $post_id ): in $comment_count = get_comment_count( $post_id ); - return $comment_count['approved'] ?? 0; + return $comment_count['approved']; } } From 64f02715045ed5ad7a2bf822b9e14ffd5c7f4669 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Fri, 4 Oct 2024 02:28:32 +0200 Subject: [PATCH 34/40] Fix: Property WP_Query::$queried_object_id (int) does not accept string. --- includes/core/classes/class-event-query.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/core/classes/class-event-query.php b/includes/core/classes/class-event-query.php index 0a93f6802..f00f38eaa 100644 --- a/includes/core/classes/class-event-query.php +++ b/includes/core/classes/class-event-query.php @@ -196,14 +196,14 @@ public function prepare_event_query_before_execution( WP_Query $query ): void { $query->is_post_type_archive = array( Event::POST_TYPE ); // This will force a page to behave like an archive page. Use -1 as that is not a valid ID. - $query->queried_object_id = '-1'; + $query->queried_object_id = -1; // Option adjustments for page_for_posts and show_on_front to force archive page. add_filter( 'pre_option', static function ( $pre, $option ) { if ( 'page_for_posts' === $option ) { - return '-1'; + return -1; } if ( 'show_on_front' === $option ) { From 2c3585cc6930cb3a523ec18d9fa7c54fb4d714ea Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Fri, 4 Oct 2024 02:31:01 +0200 Subject: [PATCH 35/40] Fix: Property WP_Query::$is_post_type_archive (bool) does not accept array. --- includes/core/classes/class-event-query.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/core/classes/class-event-query.php b/includes/core/classes/class-event-query.php index f00f38eaa..4295136c6 100644 --- a/includes/core/classes/class-event-query.php +++ b/includes/core/classes/class-event-query.php @@ -193,7 +193,7 @@ public function prepare_event_query_before_execution( WP_Query $query ): void { $query->is_page = false; $query->is_singular = false; $query->is_archive = true; - $query->is_post_type_archive = array( Event::POST_TYPE ); + $query->is_post_type_archive = true; // This will force a page to behave like an archive page. Use -1 as that is not a valid ID. $query->queried_object_id = -1; From ea4466ed814cb8b24f1a565e5f0960b3c6910b2e Mon Sep 17 00:00:00 2001 From: Mike Auteri Date: Fri, 4 Oct 2024 08:23:54 -0400 Subject: [PATCH 36/40] Fix wp_cache_set argument. --- includes/core/classes/class-rsvp.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/core/classes/class-rsvp.php b/includes/core/classes/class-rsvp.php index fc1674269..f25dc7d0c 100644 --- a/includes/core/classes/class-rsvp.php +++ b/includes/core/classes/class-rsvp.php @@ -496,7 +496,7 @@ static function ( $response ) use ( $status ) { $retval[ $status ]['count'] = count( $retval[ $status ]['responses'] ) + $guests; } - wp_cache_set( $cache_key, $retval, 15 * MINUTE_IN_SECONDS ); + wp_cache_set( $cache_key, $retval, '', 15 * MINUTE_IN_SECONDS ); return $retval; } From 30599f2e3105018edf4b57212ac50e91b38b196e Mon Sep 17 00:00:00 2001 From: Mike Auteri Date: Fri, 4 Oct 2024 08:56:52 -0400 Subject: [PATCH 37/40] Fix return on method, fix cache bug, update unit tests. --- gatherpress.php | 1 + .../core/classes/class-event-rest-api.php | 35 ++++++++++++++----- includes/core/classes/class-rsvp.php | 6 ++-- .../classes/class-test-event-rest-api.php | 2 +- .../includes/core/classes/class-test-rsvp.php | 3 ++ 5 files changed, 34 insertions(+), 13 deletions(-) diff --git a/gatherpress.php b/gatherpress.php index 5cceb802e..4f039fe97 100644 --- a/gatherpress.php +++ b/gatherpress.php @@ -22,6 +22,7 @@ defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore // Constants. +define( 'GATHERPRESS_CACHE', 'gatherpress_cache' ); define( 'GATHERPRESS_CORE_FILE', __FILE__ ); define( 'GATHERPRESS_CORE_PATH', __DIR__ ); define( 'GATHERPRESS_CORE_URL', plugin_dir_url( __FILE__ ) ); diff --git a/includes/core/classes/class-event-rest-api.php b/includes/core/classes/class-event-rest-api.php index 54c49adb1..bab6a1f2c 100644 --- a/includes/core/classes/class-event-rest-api.php +++ b/includes/core/classes/class-event-rest-api.php @@ -57,7 +57,7 @@ protected function __construct() { */ protected function setup_hooks(): void { add_action( 'rest_api_init', array( $this, 'register_endpoints' ) ); - add_action( 'gatherpress_send_emails', array( $this, 'send_emails' ), 10, 3 ); + add_action( 'gatherpress_send_emails', array( $this, 'handle_email_send_action' ), 10, 3 ); add_filter( sprintf( 'rest_prepare_%s', Event::POST_TYPE ), array( $this, 'prepare_event_data' ) ); } @@ -231,19 +231,35 @@ public function email( WP_REST_Request $request ): WP_REST_Response { } /** - * Send event-related emails to selected members. + * Hooked method to trigger the sending of related emails. * - * This method is responsible for sending event-related emails to specific members. It first checks if the given - * `$post_id` corresponds to an event post type, and if not, it returns early. Then, it retrieves a list of members - * to send the email to and constructs the email subject, body, and headers. Finally, it sends the email to each - * selected member. + * This method hooks into a WordPress action, triggering the `send_emails` method to send emails to selected members. + * It doesn't return any value, as it's intended to be called by an action hook. * * @since 1.0.0 * - * @param int $post_id Event Post ID. + * @param int $post_id Post ID. * @param array $send Members to send the email to. * @param string $message Optional message to include in the email. - * @return bool + * @return void + */ + public function handle_email_send_action( int $post_id, array $send, string $message ): void { + $this->send_emails( $post_id, $send, $message ); + } + + /** + * Send emails to selected members. + * + * This method is responsible for sending emails to specific members. It checks if the given + * `$post_id` corresponds to a specific post type, retrieves the list of members to email, and sends the email with + * the appropriate subject, body, and headers. + * + * @since 1.0.0 + * + * @param int $post_id Post ID. + * @param array $send Members to send the email to. + * @param string $message Optional message to include in the email. + * @return bool True if emails were successfully sent, false otherwise. */ public function send_emails( int $post_id, array $send, string $message ): bool { if ( Event::POST_TYPE !== get_post_type( $post_id ) ) { @@ -252,12 +268,13 @@ public function send_emails( int $post_id, array $send, string $message ): bool // Keep the currently logged-in user. $current_user = wp_get_current_user(); + $members = $this->get_members( $send, $post_id ); - $members = $this->get_members( $send, $post_id ); foreach ( $members as $member ) { if ( '0' === get_user_meta( $member->ID, 'gatherpress_event_updates_opt_in', true ) ) { continue; } + if ( $member->user_email ) { $to = $member->user_email; $switched_locale = switch_to_user_locale( $member->ID ); diff --git a/includes/core/classes/class-rsvp.php b/includes/core/classes/class-rsvp.php index f25dc7d0c..14fea7d12 100644 --- a/includes/core/classes/class-rsvp.php +++ b/includes/core/classes/class-rsvp.php @@ -277,7 +277,7 @@ public function save( int $user_id, string $status, int $anonymous = 0, int $gue 'anonymous' => intval( $anonymous ), ); - wp_cache_delete( sprintf( self::CACHE_KEY, $post_id ) ); + wp_cache_delete( sprintf( self::CACHE_KEY, $post_id ), GATHERPRESS_CACHE ); if ( ! $limit_reached ) { $this->check_waiting_list(); @@ -383,7 +383,7 @@ public function attending_limit_reached( array $current_response, int $guests = public function responses(): array { $post_id = $this->event->ID; $cache_key = sprintf( self::CACHE_KEY, $post_id ); - $retval = wp_cache_get( $cache_key ); + $retval = wp_cache_get( $cache_key, GATHERPRESS_CACHE ); $rsvp_query = Rsvp_Query::get_instance(); // @todo add testing with cache. @@ -496,7 +496,7 @@ static function ( $response ) use ( $status ) { $retval[ $status ]['count'] = count( $retval[ $status ]['responses'] ) + $guests; } - wp_cache_set( $cache_key, $retval, '', 15 * MINUTE_IN_SECONDS ); + wp_cache_set( $cache_key, $retval, GATHERPRESS_CACHE, 15 * MINUTE_IN_SECONDS ); return $retval; } diff --git a/test/unit/php/includes/core/classes/class-test-event-rest-api.php b/test/unit/php/includes/core/classes/class-test-event-rest-api.php index d26f28b3b..4a4cbb315 100644 --- a/test/unit/php/includes/core/classes/class-test-event-rest-api.php +++ b/test/unit/php/includes/core/classes/class-test-event-rest-api.php @@ -42,7 +42,7 @@ public function test_setup_hooks(): void { 'type' => 'action', 'name' => 'gatherpress_send_emails', 'priority' => 10, - 'callback' => array( $instance, 'send_emails' ), + 'callback' => array( $instance, 'handle_email_send_action' ), ), array( 'type' => 'filter', diff --git a/test/unit/php/includes/core/classes/class-test-rsvp.php b/test/unit/php/includes/core/classes/class-test-rsvp.php index fc1158917..b95c8400c 100644 --- a/test/unit/php/includes/core/classes/class-test-rsvp.php +++ b/test/unit/php/includes/core/classes/class-test-rsvp.php @@ -265,6 +265,9 @@ public function test_responses(): void { wp_delete_user( $user_id_2 ); + // User will remain while cached until it expires. + wp_cache_delete( sprintf( Rsvp::CACHE_KEY, $post->ID ), GATHERPRESS_CACHE ); + $responses = $rsvp->responses(); $this->assertEmpty( From b47a6cacc60abfa8a4e1a490acae39109c20aa2a Mon Sep 17 00:00:00 2001 From: Mike Auteri Date: Fri, 4 Oct 2024 09:10:59 -0400 Subject: [PATCH 38/40] Small fixes. --- includes/core/classes/class-assets.php | 4 ++-- includes/core/classes/class-event.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/includes/core/classes/class-assets.php b/includes/core/classes/class-assets.php index 766bc6c85..057414a4b 100644 --- a/includes/core/classes/class-assets.php +++ b/includes/core/classes/class-assets.php @@ -104,8 +104,8 @@ protected function setup_hooks(): void { * @return void */ public function add_global_object(): void { - // phpcs:ignore Universal.Operators.DisallowShortTernary.Found ?> - + ?> + fullAddress ?? ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase $venue_information['phone_number'] = $venue_meta->phoneNumber ?? ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase $venue_information['website'] = $venue_meta->website ?? ''; - $venue_information['permalink'] = get_permalink( $venue->ID ) ?: ''; // phpcs:ignore Universal.Operators.DisallowShortTernary.Found + $venue_information['permalink'] = (string) get_permalink( $venue->ID ); } return $venue_information; From aa69812154ac846f5e35e18afa65de879825d095 Mon Sep 17 00:00:00 2001 From: Mike Auteri Date: Fri, 4 Oct 2024 09:14:28 -0400 Subject: [PATCH 39/40] Name change. --- gatherpress.php | 2 +- includes/core/classes/class-rsvp.php | 6 +++--- test/unit/php/includes/core/classes/class-test-rsvp.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gatherpress.php b/gatherpress.php index 4f039fe97..b5c9df735 100644 --- a/gatherpress.php +++ b/gatherpress.php @@ -22,7 +22,7 @@ defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore // Constants. -define( 'GATHERPRESS_CACHE', 'gatherpress_cache' ); +define( 'GATHERPRESS_CACHE_GROUP', 'gatherpress_cache' ); define( 'GATHERPRESS_CORE_FILE', __FILE__ ); define( 'GATHERPRESS_CORE_PATH', __DIR__ ); define( 'GATHERPRESS_CORE_URL', plugin_dir_url( __FILE__ ) ); diff --git a/includes/core/classes/class-rsvp.php b/includes/core/classes/class-rsvp.php index 14fea7d12..80de2772e 100644 --- a/includes/core/classes/class-rsvp.php +++ b/includes/core/classes/class-rsvp.php @@ -277,7 +277,7 @@ public function save( int $user_id, string $status, int $anonymous = 0, int $gue 'anonymous' => intval( $anonymous ), ); - wp_cache_delete( sprintf( self::CACHE_KEY, $post_id ), GATHERPRESS_CACHE ); + wp_cache_delete( sprintf( self::CACHE_KEY, $post_id ), GATHERPRESS_CACHE_GROUP ); if ( ! $limit_reached ) { $this->check_waiting_list(); @@ -383,7 +383,7 @@ public function attending_limit_reached( array $current_response, int $guests = public function responses(): array { $post_id = $this->event->ID; $cache_key = sprintf( self::CACHE_KEY, $post_id ); - $retval = wp_cache_get( $cache_key, GATHERPRESS_CACHE ); + $retval = wp_cache_get( $cache_key, GATHERPRESS_CACHE_GROUP ); $rsvp_query = Rsvp_Query::get_instance(); // @todo add testing with cache. @@ -496,7 +496,7 @@ static function ( $response ) use ( $status ) { $retval[ $status ]['count'] = count( $retval[ $status ]['responses'] ) + $guests; } - wp_cache_set( $cache_key, $retval, GATHERPRESS_CACHE, 15 * MINUTE_IN_SECONDS ); + wp_cache_set( $cache_key, $retval, GATHERPRESS_CACHE_GROUP, 15 * MINUTE_IN_SECONDS ); return $retval; } diff --git a/test/unit/php/includes/core/classes/class-test-rsvp.php b/test/unit/php/includes/core/classes/class-test-rsvp.php index b95c8400c..a77078d02 100644 --- a/test/unit/php/includes/core/classes/class-test-rsvp.php +++ b/test/unit/php/includes/core/classes/class-test-rsvp.php @@ -266,7 +266,7 @@ public function test_responses(): void { wp_delete_user( $user_id_2 ); // User will remain while cached until it expires. - wp_cache_delete( sprintf( Rsvp::CACHE_KEY, $post->ID ), GATHERPRESS_CACHE ); + wp_cache_delete( sprintf( Rsvp::CACHE_KEY, $post->ID ), GATHERPRESS_CACHE_GROUP ); $responses = $rsvp->responses(); From c615cd534f9ae61901b0699a0398ec829acafceb Mon Sep 17 00:00:00 2001 From: Mike Auteri Date: Fri, 4 Oct 2024 09:17:31 -0400 Subject: [PATCH 40/40] Add ignore. --- phpstan.neon.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 6620347d4..ea3324760 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -30,6 +30,7 @@ parameters: # - vendor/ ignoreErrors: + - '#^Constant GATHERPRESS_CACHE_GROUP not found\.$#' - '#^Constant GATHERPRESS_CORE_FILE not found\.$#' - '#^Constant GATHERPRESS_CORE_PATH not found\.$#' - '#^Constant GATHERPRESS_CORE_URL not found\.$#'