diff --git a/.distignore b/.distignore
index 47ccea3c3..4f2b58537 100755
--- a/.distignore
+++ b/.distignore
@@ -27,6 +27,9 @@ package-lock.json
phpcs.xml
phpcs.xml.dist
phpcs.ruleset.xml
+phpstan.neon
+phpstan.neon.dist
+phpstan.stubs
phpunit.xml
phpunit.xml.dist
playwright.config.js
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
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..55cb65467 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."
@@ -28,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": {
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/gatherpress.php b/gatherpress.php
index 5cceb802e..b5c9df735 100644
--- a/gatherpress.php
+++ b/gatherpress.php
@@ -22,6 +22,7 @@
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
// Constants.
+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-assets.php b/includes/core/classes/class-assets.php
index 347c595fb..057414a4b 100644
--- a/includes/core/classes/class-assets.php
+++ b/includes/core/classes/class-assets.php
@@ -105,7 +105,7 @@ protected function setup_hooks(): void {
*/
public function add_global_object(): void {
?>
-
+
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';
+ $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 ) {
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-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-event.php b/includes/core/classes/class-event.php
index 66e491363..df24be8d5 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'] = (string) get_permalink( $venue->ID );
}
return $venue_information;
@@ -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();
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 );
}
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 );
}
diff --git a/includes/core/classes/class-rsvp-query.php b/includes/core/classes/class-rsvp-query.php
index 974bf3c2a..505641be0 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;
@@ -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 );
}
@@ -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;
@@ -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;
}
@@ -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'];
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'];
}
}
diff --git a/includes/core/classes/class-rsvp.php b/includes/core/classes/class-rsvp.php
index 4da755339..80de2772e 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;
@@ -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;
}
@@ -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_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 );
+ $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, 15 * MINUTE_IN_SECONDS );
+ wp_cache_set( $cache_key, $retval, GATHERPRESS_CACHE_GROUP, 15 * MINUTE_IN_SECONDS );
return $retval;
}
@@ -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/includes/core/classes/class-settings.php b/includes/core/classes/class-settings.php
index d42643bc1..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,9 +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;
-
- default:
- break;
}
Utility::render_template(
sprintf( '%s/includes/templates/admin/settings/partials/urlrewrite-preview.php', GATHERPRESS_CORE_PATH ),
diff --git a/includes/core/classes/class-setup.php b/includes/core/classes/class-setup.php
index 9752ea043..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,
@@ -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();
}
@@ -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/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,
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.
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 () {
diff --git a/includes/templates/admin/settings/fields/select.php b/includes/templates/admin/settings/fields/select.php
index a847bdb65..9bee92139 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;
}
?>
@@ -27,7 +28,7 @@
$gatherpress_label ) :
?>
-
prefix, Event::POST_TYPE );
+ $table = sprintf( Event::TABLE_FORMAT, $wpdb->prefix );
$retval = $instance->adjust_event_sql( array(), 'all', 'DESC' );
$this->assertStringContainsString( 'DESC', $retval['orderby'] );
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 f94bc115a..a77078d02 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_GROUP );
+
$responses = $rsvp->responses();
$this->assertEmpty(
@@ -344,13 +347,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.'
);
}
}
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.'
+ );
+ }
}