From f3f79a7c82ed3ec3231a5ba36238095508733fc0 Mon Sep 17 00:00:00 2001 From: Filip Ilic Date: Fri, 30 Jan 2026 15:56:46 +0100 Subject: [PATCH 1/3] WIP --- classes/class-badges.php | 45 +++++++++++++++++++++++++++---- views/popovers/badge-streak.php | 1 + views/popovers/monthly-badges.php | 1 + 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/classes/class-badges.php b/classes/class-badges.php index 904c94f0b..2c751ba63 100644 --- a/classes/class-badges.php +++ b/classes/class-badges.php @@ -83,7 +83,19 @@ public function __construct() { * @return \Progress_Planner\Badges\Badge[] */ public function get_badges( $context ) { - return isset( $this->$context ) ? $this->$context : []; + // phpcs:ignore Generic.Commenting.DocComment.MissingShort -- Inline @var for PHPStan. + /** @var \Progress_Planner\Badges\Badge[] $badges */ + $badges = isset( $this->$context ) ? $this->$context : []; + + /** + * Filter the badges for a context. + * + * @param \Progress_Planner\Badges\Badge[] $badges The badges. + * @param string $context The badges context. + * + * @return \Progress_Planner\Badges\Badge[] + */ + return \apply_filters( 'progress_planner_badges', $badges, $context ); } /** @@ -101,7 +113,18 @@ public function get_badge( $badge_id ) { } } } - return null; + + /** + * Filter for retrieving a single badge by ID. + * + * Allows external plugins to provide custom badges. + * + * @param \Progress_Planner\Badges\Badge|null $badge The badge object or null. + * @param string $badge_id The badge ID. + * + * @return \Progress_Planner\Badges\Badge|null + */ + return \apply_filters( 'progress_planner_get_badge', null, $badge_id ); } /** @@ -183,6 +206,8 @@ public function get_latest_completed_badge() { // Get the settings for badges (stores completion dates). $settings = \progress_planner()->get_settings()->get( 'badges', [] ); + // phpcs:ignore Generic.Commenting.DocComment.MissingShort -- Inline @var for PHPStan. + /** @var string|null $latest_date */ $latest_date = null; // Loop through all badge contexts to find the most recently completed badge. @@ -204,20 +229,30 @@ public function get_latest_completed_badge() { if ( null === $latest_date ) { $this->latest_completed_badge = $badge; if ( isset( $settings[ $badge->get_id() ]['date'] ) ) { - $latest_date = $settings[ $badge->get_id() ]['date']; + $latest_date = (string) $settings[ $badge->get_id() ]['date']; } continue; } // Compare completion dates as Unix timestamps to find the most recent. // Using >= ensures that if multiple badges complete simultaneously, the last one processed wins. - if ( \DateTime::createFromFormat( 'Y-m-d H:i:s', $settings[ $badge->get_id() ]['date'] )->format( 'U' ) >= \DateTime::createFromFormat( 'Y-m-d H:i:s', $latest_date )->format( 'U' ) ) { - $latest_date = $settings[ $badge->get_id() ]['date']; + if ( \DateTime::createFromFormat( 'Y-m-d H:i:s', (string) $settings[ $badge->get_id() ]['date'] )->format( 'U' ) >= \DateTime::createFromFormat( 'Y-m-d H:i:s', $latest_date )->format( 'U' ) ) { + $latest_date = (string) $settings[ $badge->get_id() ]['date']; $this->latest_completed_badge = $badge; } } } + /** + * Filter the latest completed badge. + * + * @param \Progress_Planner\Badges\Badge|null $badge The latest completed badge. + * @param string|null $latest_date The latest completion date. + * + * @return \Progress_Planner\Badges\Badge|null + */ + $this->latest_completed_badge = \apply_filters( 'progress_planner_latest_completed_badge', $this->latest_completed_badge, $latest_date ); + return $this->latest_completed_badge; } } diff --git a/views/popovers/badge-streak.php b/views/popovers/badge-streak.php index 90e1d9853..dbeabeca0 100644 --- a/views/popovers/badge-streak.php +++ b/views/popovers/badge-streak.php @@ -33,6 +33,7 @@ the_view( 'popovers/parts/badge-streak-progressbar.php', [ 'prpl_context' => 'content' ] ); ?> + + From da6457a6abf6b226bf46438b8fbebd272763c428 Mon Sep 17 00:00:00 2001 From: Filip Ilic Date: Thu, 5 Feb 2026 12:57:13 +0100 Subject: [PATCH 2/3] filter out the activity category --- classes/class-suggested-tasks.php | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/classes/class-suggested-tasks.php b/classes/class-suggested-tasks.php index e25fc6036..d88ff5dc7 100644 --- a/classes/class-suggested-tasks.php +++ b/classes/class-suggested-tasks.php @@ -100,12 +100,25 @@ public function init(): void { * @return void */ public function insert_activity( string $task_id ): void { + /** + * Filter the activity category for a completed task. + * + * Allows customizing the category used when recording task completion activities. + * For example, onboarding tasks may use 'onboarding_task' instead of 'suggested_task' + * to exclude them from monthly badge calculations. + * + * @param string $category The activity category (default: 'suggested_task'). + * @param string $task_id The task ID being completed. + */ + $category = \apply_filters( 'progress_planner_task_activity_category', 'suggested_task', $task_id ); + // Insert an activity. - $activity = new Suggested_Task_Activity(); - $activity->type = 'completed'; - $activity->data_id = (string) $task_id; - $activity->date = new \DateTime(); - $activity->user_id = \get_current_user_id(); + $activity = new Suggested_Task_Activity(); + $activity->category = $category; + $activity->type = 'completed'; + $activity->data_id = (string) $task_id; + $activity->date = new \DateTime(); + $activity->user_id = \get_current_user_id(); $activity->save(); // Allow other classes to react to the completion of a suggested task. From af4cf920f15588123c1b491e12787997e3ac93b0 Mon Sep 17 00:00:00 2001 From: Filip Ilic Date: Thu, 5 Feb 2026 15:11:59 +0100 Subject: [PATCH 3/3] tweak when onboarding tasks should show, pp-hosts compat --- classes/class-plugin-upgrade-tasks.php | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/classes/class-plugin-upgrade-tasks.php b/classes/class-plugin-upgrade-tasks.php index a111e7906..f1762c9d6 100644 --- a/classes/class-plugin-upgrade-tasks.php +++ b/classes/class-plugin-upgrade-tasks.php @@ -104,14 +104,26 @@ protected function add_initial_onboarding_tasks() { public function maybe_add_onboarding_tasks() { $onboard_task_provider_ids = \apply_filters( 'prpl_onboarding_task_providers', [] ); - // Privacy policy is not accepted, so it's a fresh install. - $fresh_install = ! \progress_planner()->is_privacy_policy_accepted(); - - // Check if task providers option exists, it will not on fresh installs and v1.0.4 and older. - $old_task_providers = \get_option( 'progress_planner_previous_version_task_providers', [] ); + // Check if task providers option exists. If not, it's either a fresh install or upgrading from v1.0.4 or older. + $old_task_providers = \get_option( 'progress_planner_previous_version_task_providers', [] ); + $task_providers_option_set = false !== \get_option( 'progress_planner_previous_version_task_providers', false ); + + // Fresh install detection: + // - Option doesn't exist AND privacy policy not yet accepted (standalone fresh install) + // - Option doesn't exist AND running as branded/hosted version (pp-hosts fresh install, privacy auto-accepted) + // In these cases, save current providers as baseline without showing upgrade popover. + if ( ! $task_providers_option_set ) { + $is_branded_version = \defined( 'PROGRESS_PLANNER_BRANDING_ID' ); + $is_privacy_policy_pending = ! \progress_planner()->is_privacy_policy_accepted(); + + if ( $is_branded_version || $is_privacy_policy_pending ) { + // Fresh install - save current providers as baseline and skip upgrade popover. + \update_option( 'progress_planner_previous_version_task_providers', \array_unique( $onboard_task_provider_ids ), SORT_REGULAR ); + return; + } - // We're upgrading from v1.0.4 or older, set the old task providers to what we had before the upgrade. - if ( ! $fresh_install && empty( $old_task_providers ) ) { + // Upgrading from v1.0.4 or older (standalone, privacy accepted but no task providers option). + // Set baseline to what existed before the upgrade. $old_task_providers = [ 'core-blogdescription', 'wp-debug-display',