From 60e8d47d2bec690367c9628a81bd3c03a0e9da76 Mon Sep 17 00:00:00 2001
From: Filip Ilic
Date: Mon, 22 Sep 2025 12:01:59 +0200
Subject: [PATCH 01/50] WIP
---
classes/class-base.php | 4 +
classes/class-suggested-tasks.php | 15 +
.../front-end/class-front-end-onboarding.php | 630 ++++++++++++++++++
3 files changed, 649 insertions(+)
create mode 100644 classes/front-end/class-front-end-onboarding.php
diff --git a/classes/class-base.php b/classes/class-base.php
index f952929cce..a4cb427114 100644
--- a/classes/class-base.php
+++ b/classes/class-base.php
@@ -55,6 +55,7 @@
* @method \Progress_Planner\Admin\Widgets\Challenge get_admin__widgets__challenge()
* @method \Progress_Planner\Admin\Widgets\Activity_Scores get_admin__widgets__activity_scores()
* @method \Progress_Planner\Utils\Date get_utils__date()
+ * @method \Progress_Planner\Front_End\Front_End_Onboarding get_front_end_onboarding()
*/
class Base {
@@ -170,6 +171,9 @@ public function init() {
// Init the enqueue class.
$this->get_admin__enqueue()->init();
+
+ // TODO: Decide when this needs to be initialized.
+ $this->get_front_end__front_end_onboarding();
}
/**
diff --git a/classes/class-suggested-tasks.php b/classes/class-suggested-tasks.php
index 5b1f443621..8f997e7460 100644
--- a/classes/class-suggested-tasks.php
+++ b/classes/class-suggested-tasks.php
@@ -197,6 +197,17 @@ public function maybe_complete_task() {
return;
}
+ $this->complete_task( $task_id );
+ }
+
+ /**
+ * Complete a task.
+ *
+ * @param string $task_id The task ID.
+ *
+ * @return bool
+ */
+ public function complete_task( $task_id ) {
if ( ! $this->was_task_completed( $task_id ) ) {
$task = \progress_planner()->get_suggested_tasks_db()->get_post( $task_id );
@@ -205,8 +216,12 @@ public function maybe_complete_task() {
// Insert an activity.
$this->insert_activity( $task_id );
+
+ return true;
}
}
+
+ return false;
}
/**
diff --git a/classes/front-end/class-front-end-onboarding.php b/classes/front-end/class-front-end-onboarding.php
new file mode 100644
index 0000000000..8814eb580e
--- /dev/null
+++ b/classes/front-end/class-front-end-onboarding.php
@@ -0,0 +1,630 @@
+add_node(
+ [
+ 'id' => 'progress-planner-tour',
+ 'title' => 'Progress Planner Tour',
+ 'href' => '#',
+ 'meta' => [
+ 'onclick' => 'prplStartTour(); return false;',
+ ],
+ ]
+ );
+ }
+
+ /**
+ * Save the tour progress.
+ *
+ * @return void
+ */
+ public function ajax_save_tour_progress() {
+ if ( ! \check_ajax_referer( 'progress_planner', 'nonce', false ) ) {
+ \wp_send_json_error( [ 'message' => \esc_html__( 'Invalid nonce.', 'progress-planner' ) ] );
+ }
+
+ if ( ! isset( $_POST['state'] ) ) {
+ \wp_send_json_error( [ 'message' => \esc_html__( 'State is required.', 'progress-planner' ) ] );
+ }
+ $progress = \sanitize_text_field( \wp_unslash( $_POST['state'] ) );
+
+ \error_log( print_r( $progress, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r, WordPress.PHP.DevelopmentFunctions.error_log_error_log
+
+ // Save as user meta?
+ \update_user_meta( \get_current_user_id(), '_prpl_tour_progress', $progress );
+
+ \wp_send_json_success( [ 'message' => \esc_html__( 'Tour progress saved.', 'progress-planner' ) ] );
+ }
+
+ /**
+ * Complete a task.
+ *
+ * @return void
+ */
+ public function ajax_complete_task() {
+
+ if ( ! \check_ajax_referer( 'progress_planner', 'nonce', false ) ) {
+ \wp_send_json_error( [ 'message' => \esc_html__( 'Invalid nonce.', 'progress-planner' ) ] );
+ }
+
+ if ( ! isset( $_POST['task_id'] ) ) {
+ \wp_send_json_error( [ 'message' => \esc_html__( 'Task ID is required.', 'progress-planner' ) ] );
+ }
+
+ $task_id = \sanitize_text_field( \wp_unslash( $_POST['task_id'] ) );
+
+ // Note: Completing task will set it it to pending, so user will get celebration.
+ // Do we want that?
+ $result = \progress_planner()->get_suggested_tasks()->complete_task( $task_id );
+
+ if ( ! $result ) {
+ \error_log( 'Task not completed: ' . $task_id ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
+ \wp_send_json_error( [ 'message' => \esc_html__( 'Task not completed.', 'progress-planner' ) ] );
+ }
+
+ \error_log( 'Task completed: ' . $task_id ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
+ \wp_send_json_success( [ 'message' => \esc_html__( 'Task completed.', 'progress-planner' ) ] );
+ }
+
+ /**
+ * Add the popover.
+ *
+ * @return void
+ */
+ public function add_popover() {
+ ?>
+
+
+
+ get_suggested_tasks_db()->get_tasks_by(
+ [
+ 'post_status' => 'publish',
+ 'tax_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
+ [
+ 'taxonomy' => 'prpl_recommendations_provider',
+ 'field' => 'slug',
+ 'terms' => 'user',
+ 'operator' => 'NOT IN',
+ ],
+ ],
+ ]
+ );
+ $tasks = [];
+ foreach ( $ravis_recommendations as $recommendation ) {
+
+ $tasks[] = [
+ 'task_id' => $recommendation->task_id,
+ 'title' => $recommendation->post_title,
+ 'url' => $recommendation->url,
+ 'provider_id' => $recommendation->get_provider_id(),
+ 'points' => $recommendation->points,
+ ];
+ }
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Date: Mon, 22 Sep 2025 12:17:02 +0200
Subject: [PATCH 02/50] split stlyes
---
assets/css/front-end-onboarding.css | 83 ++++++++++++
.../front-end/class-front-end-onboarding.php | 121 +++---------------
2 files changed, 98 insertions(+), 106 deletions(-)
create mode 100644 assets/css/front-end-onboarding.css
diff --git a/assets/css/front-end-onboarding.css b/assets/css/front-end-onboarding.css
new file mode 100644
index 0000000000..44ed6f928b
--- /dev/null
+++ b/assets/css/front-end-onboarding.css
@@ -0,0 +1,83 @@
+#prpl-popover-front-end-onboarding {
+
+ padding: 24px 24px 14px 24px;
+ box-sizing: border-box;
+
+ background: #fff;
+ border: 1px solid #9ca3af;
+ border-radius: 8px;
+ font-weight: 400;
+ max-height: 82vh;
+ width: 1200px;
+ max-width: 80vw;
+
+ &::backdrop {
+ background: rgba(0, 0, 0, 0.5);
+ }
+
+ .prpl-btn {
+ display: inline-block;
+ margin: 1rem 0;
+ padding: 0.75rem 1.25rem;
+ color: #fff;
+ text-decoration: none;
+ cursor: pointer;
+ font-size: 16px;
+ background: #dd3244;
+ line-height: 1.25;
+ box-shadow: none;
+ border: none;
+ border-radius: 6px;
+ transition: all 0.25s ease-in-out;
+ font-weight: 600;
+ text-align: center;
+ box-sizing: border-box;
+ position: relative;
+ z-index: 1;
+
+ &:disabled {
+ opacity: 0.5;
+ pointer-events: none;
+ }
+
+ &:not([disabled]):hover,
+ &:not([disabled]):focus {
+ background: #cf2441;
+ }
+ }
+
+ .prpl-complete-task-btn {
+ border: none;
+ background: none;
+ cursor: pointer;
+ padding: 0;
+ margin: 0;
+ font-size: 16px;
+ color: #1e40af;
+ }
+
+ .prpl-complete-task-btn-completed {
+ color: #059669;
+ }
+
+ .prpl-complete-task-btn-error {
+ color: #9f0712;
+ }
+
+ .prpl-complete-task-item {
+ margin-bottom: 1rem;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ }
+
+ #prpl-more-tasks-list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+
+ li:not(:last-child) {
+ margin-bottom: 10px;
+ }
+ }
+}
diff --git a/classes/front-end/class-front-end-onboarding.php b/classes/front-end/class-front-end-onboarding.php
index 8814eb580e..564c0f3654 100644
--- a/classes/front-end/class-front-end-onboarding.php
+++ b/classes/front-end/class-front-end-onboarding.php
@@ -12,25 +12,20 @@
*/
class Front_End_Onboarding {
- /**
- * The popover ID for front end onboarding.
- *
- * @var string
- */
- const POPOVER_ID = 'front-end-onboarding';
-
/**
* Constructor.
*
* @return void
*/
public function __construct() {
+ // Add popover markup.
\add_action( 'wp_footer', [ $this, 'add_popover' ] );
- \add_action( 'wp_footer', [ $this, 'add_popover_style' ] );
-
\add_action( 'wp_footer', [ $this, 'add_popover_inline_script' ] );
+ // Add popover scripts.
+ \add_action( 'wp_enqueue_scripts', [ $this, 'add_popover_scripts' ] );
+
// Add admin toolbar item.
\add_action( 'admin_bar_menu', [ $this, 'add_admin_toolbar_item' ] );
@@ -39,6 +34,15 @@ public function __construct() {
\add_action( 'wp_ajax_progress_planner_tour_save_progress', [ $this, 'ajax_save_tour_progress' ] );
}
+ /**
+ * Add popover scripts.
+ *
+ * @return void
+ */
+ public function add_popover_scripts() {
+ \wp_enqueue_style( 'prpl-popover-front-end-onboarding', \constant( 'PROGRESS_PLANNER_URL' ) . '/assets/css/front-end-onboarding.css', [], \progress_planner()->get_plugin_version() );
+ }
+
/**
* Add admin toolbar item.
*
@@ -127,7 +131,7 @@ public function ajax_complete_task() {
*/
public function add_popover() {
?>
-
+
Date: Mon, 29 Sep 2025 15:49:36 +0200
Subject: [PATCH 21/50] add inline redirect
---
classes/front-end/class-front-end-onboarding.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/classes/front-end/class-front-end-onboarding.php b/classes/front-end/class-front-end-onboarding.php
index 457e1564ad..d0598170d2 100644
--- a/classes/front-end/class-front-end-onboarding.php
+++ b/classes/front-end/class-front-end-onboarding.php
@@ -195,7 +195,7 @@ public function add_popover() {
-
+
Date: Thu, 2 Oct 2025 14:45:05 +0200
Subject: [PATCH 22/50] rename method
---
classes/class-suggested-tasks.php | 4 ++--
classes/front-end/class-front-end-onboarding.php | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/classes/class-suggested-tasks.php b/classes/class-suggested-tasks.php
index d0879a9ba5..fb72ebe9a1 100644
--- a/classes/class-suggested-tasks.php
+++ b/classes/class-suggested-tasks.php
@@ -200,7 +200,7 @@ public function maybe_complete_task() {
return;
}
- $this->complete_task( $task_id );
+ $this->mark_task_as_completed( $task_id );
}
/**
@@ -210,7 +210,7 @@ public function maybe_complete_task() {
*
* @return bool
*/
- public function complete_task( $task_id ) {
+ public function mark_task_as_completed( $task_id ) {
if ( ! $this->was_task_completed( $task_id ) ) {
$task = \progress_planner()->get_suggested_tasks_db()->get_post( $task_id );
diff --git a/classes/front-end/class-front-end-onboarding.php b/classes/front-end/class-front-end-onboarding.php
index d0598170d2..ac7fb216b8 100644
--- a/classes/front-end/class-front-end-onboarding.php
+++ b/classes/front-end/class-front-end-onboarding.php
@@ -167,7 +167,7 @@ public function ajax_complete_task() {
// Note: Completing task will set it it to pending, so user will get celebration.
// Do we want that?
- $result = \progress_planner()->get_suggested_tasks()->complete_task( $task_id );
+ $result = \progress_planner()->get_suggested_tasks()->mark_task_as_completed( $task_id );
if ( ! $result ) {
\error_log( 'Task not completed: ' . $task_id ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
From bdfc8680e9b3bd1e856c050691d31a3c04f4a6c2 Mon Sep 17 00:00:00 2001
From: Filip Ilic
Date: Thu, 2 Oct 2025 15:02:22 +0200
Subject: [PATCH 23/50] update comment
---
classes/front-end/class-front-end-onboarding.php | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/classes/front-end/class-front-end-onboarding.php b/classes/front-end/class-front-end-onboarding.php
index ac7fb216b8..7fd8476d10 100644
--- a/classes/front-end/class-front-end-onboarding.php
+++ b/classes/front-end/class-front-end-onboarding.php
@@ -165,8 +165,7 @@ public function ajax_complete_task() {
$form_values = \json_decode( $form_values, true );
}
- // Note: Completing task will set it it to pending, so user will get celebration.
- // Do we want that?
+ // Note: Marking task as completed will set it it to pending, so user will get celebration. Do we want that?
$result = \progress_planner()->get_suggested_tasks()->mark_task_as_completed( $task_id );
if ( ! $result ) {
From 5a544f353093fb8262f873ec6dae7ac597e7af09 Mon Sep 17 00:00:00 2001
From: Filip Ilic
Date: Thu, 2 Oct 2025 15:03:19 +0200
Subject: [PATCH 24/50] WIP: prototype of how task can be programmatically
completed
---
.../front-end/class-front-end-onboarding.php | 15 +++++++++++++++
.../suggested-tasks/class-tasks-interface.php | 10 ++++++++++
.../providers/class-blog-description.php | 17 +++++++++++++++++
.../suggested-tasks/providers/class-tasks.php | 11 +++++++++++
4 files changed, 53 insertions(+)
diff --git a/classes/front-end/class-front-end-onboarding.php b/classes/front-end/class-front-end-onboarding.php
index 7fd8476d10..2e64b3a127 100644
--- a/classes/front-end/class-front-end-onboarding.php
+++ b/classes/front-end/class-front-end-onboarding.php
@@ -165,6 +165,21 @@ public function ajax_complete_task() {
$form_values = \json_decode( $form_values, true );
}
+ // Get the task.
+ $task = \progress_planner()->get_suggested_tasks_db()->get_post( $task_id );
+ if ( ! $task ) {
+ \wp_send_json_error( [ 'message' => \esc_html__( 'Task not found.', 'progress-planner' ) ] );
+ }
+
+ // To get the provider and complete the task, we need to use the provider.
+ $provider = \progress_planner()->get_suggested_tasks()->get_tasks_manager()->get_task_provider( $task->get_provider_id() );
+ if ( ! $provider ) {
+ \wp_send_json_error( [ 'message' => \esc_html__( 'Provider not found.', 'progress-planner' ) ] );
+ }
+
+ // Complete the task.
+ $provider->complete_task( $form_values, $task_id );
+
// Note: Marking task as completed will set it it to pending, so user will get celebration. Do we want that?
$result = \progress_planner()->get_suggested_tasks()->mark_task_as_completed( $task_id );
diff --git a/classes/suggested-tasks/class-tasks-interface.php b/classes/suggested-tasks/class-tasks-interface.php
index 66c550b221..f93a1b9f6f 100644
--- a/classes/suggested-tasks/class-tasks-interface.php
+++ b/classes/suggested-tasks/class-tasks-interface.php
@@ -129,4 +129,14 @@ public function add_task_actions( $data = [], $actions = [] );
* @return bool
*/
public function task_has_activity( $task_id = '' );
+
+ /**
+ * Complete the task.
+ *
+ * @param array $args The task data.
+ * @param string $task_id The task ID.
+ *
+ * @return void
+ */
+ public function complete_task( $args = [], $task_id = '' );
}
diff --git a/classes/suggested-tasks/providers/class-blog-description.php b/classes/suggested-tasks/providers/class-blog-description.php
index fce46d6dc0..2dbc8fa930 100644
--- a/classes/suggested-tasks/providers/class-blog-description.php
+++ b/classes/suggested-tasks/providers/class-blog-description.php
@@ -139,4 +139,21 @@ public function add_task_actions( $data = [], $actions = [] ) {
return $actions;
}
+
+ /**
+ * Complete the task.
+ *
+ * @param array $args The task data.
+ * @param string $task_id The task ID.
+ *
+ * @return void
+ */
+ public function complete_task( $args = [], $task_id = '' ) {
+
+ if ( ! isset( $args['blogdescription'] ) ) {
+ return;
+ }
+
+ \update_option( 'blogdescription', \sanitize_text_field( $args['blogdescription'] ) );
+ }
}
diff --git a/classes/suggested-tasks/providers/class-tasks.php b/classes/suggested-tasks/providers/class-tasks.php
index 00b18bbb6b..5bc8d239a7 100644
--- a/classes/suggested-tasks/providers/class-tasks.php
+++ b/classes/suggested-tasks/providers/class-tasks.php
@@ -721,4 +721,15 @@ public function task_has_activity( $task_id = '' ) {
return ! empty( $activity );
}
+
+ /**
+ * Complete the task.
+ *
+ * @param array $args The task data.
+ * @param string $task_id The task ID.
+ *
+ * @return void
+ */
+ public function complete_task( $args = [], $task_id = '' ) {
+ }
}
From 4302f41d55b107849bf941ca2dfd940518dd993f Mon Sep 17 00:00:00 2001
From: Filip Ilic
Date: Mon, 6 Oct 2025 11:39:04 +0200
Subject: [PATCH 25/50] blog description as first task
---
.../front-end/class-front-end-onboarding.php | 36 +++++++++++++++++--
views/front-end-onboarding/first-task.php | 10 ++++--
2 files changed, 41 insertions(+), 5 deletions(-)
diff --git a/classes/front-end/class-front-end-onboarding.php b/classes/front-end/class-front-end-onboarding.php
index 2e64b3a127..c2ad0bc7a0 100644
--- a/classes/front-end/class-front-end-onboarding.php
+++ b/classes/front-end/class-front-end-onboarding.php
@@ -221,6 +221,34 @@ public function add_popover() {
* @return void
*/
public function add_popover_step_templates() {
+
+ // First task.
+ $first_task = \progress_planner()->get_suggested_tasks_db()->get_tasks_by( [ 'task_id' => 'core-blogdescription' ] );
+
+ // If there is no 'blog description' task, create it.
+ if ( ! $first_task ) {
+ $first_task_provider = \progress_planner()->get_suggested_tasks()->get_tasks_manager()->get_task_provider( 'core-blogdescription' );
+
+ if ( $first_task_provider ) {
+ $first_task_data = $first_task_provider->get_task_details();
+
+ \progress_planner()->get_suggested_tasks_db()->add( $first_task_data );
+
+ // Now get the task.
+ $first_task = \progress_planner()->get_suggested_tasks_db()->get_tasks_by( [ 'task_id' => 'core-blogdescription' ] );
+ }
+ }
+
+ $first_task = [
+ 'task_id' => $first_task[0]->task_id,
+ 'title' => $first_task[0]->post_title,
+ 'url' => $first_task[0]->url,
+ 'provider_id' => $first_task[0]->get_provider_id(),
+ 'points' => $first_task[0]->points,
+ 'site_description' => \get_bloginfo( 'description' ),
+ ];
+
+ // Other tasks.
$ravis_recommendations = \progress_planner()->get_suggested_tasks_db()->get_tasks_by(
[
'post_status' => 'publish',
@@ -235,7 +263,8 @@ public function add_popover_step_templates() {
],
]
);
- $tasks = [];
+
+ $tasks = [];
foreach ( $ravis_recommendations as $recommendation ) {
$tasks[] = [
@@ -246,10 +275,11 @@ public function add_popover_step_templates() {
'points' => $recommendation->points,
];
}
+
\progress_planner()->the_view( 'front-end-onboarding/welcome.php' );
- \progress_planner()->the_view( 'front-end-onboarding/first-task.php', [ 'task' => $tasks[0] ] ); // WIP: We need only 1 task for this step.
+ \progress_planner()->the_view( 'front-end-onboarding/first-task.php', [ 'task' => $first_task ] ); // WIP: We need only 1 task for this step.
\progress_planner()->the_view( 'front-end-onboarding/badges.php' );
- \progress_planner()->the_view( 'front-end-onboarding/more-tasks.php', [ 'tasks' => array_slice( $tasks, 1, 5 ) ] ); // WIP: We need up to 5 tasks for this step.
+ \progress_planner()->the_view( 'front-end-onboarding/more-tasks.php', [ 'tasks' => $tasks ] ); // WIP: We need up to 5 tasks for this step.
\progress_planner()->the_view( 'front-end-onboarding/finish.php' );
?>
+
+
+
+
diff --git a/views/front-end-onboarding/tasks/blog-description.php b/views/front-end-onboarding/tasks/blog-description.php
new file mode 100644
index 0000000000..16749e5780
--- /dev/null
+++ b/views/front-end-onboarding/tasks/blog-description.php
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet consectetur adipiscing elit, eget interdum nostra tortor vestibulum ultrices, quisque congue nibh ullamcorper sapien natoque.
+
+
+
+ Venenatis parturient suspendisse massa cursus litora dapibus auctor, et vestibulum blandit condimentum quis ultrices sagittis aliquam.
+
+
+
+
diff --git a/views/front-end-onboarding/tasks/select-locale.php b/views/front-end-onboarding/tasks/select-locale.php
new file mode 100644
index 0000000000..f7e8c5061c
--- /dev/null
+++ b/views/front-end-onboarding/tasks/select-locale.php
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet consectetur adipiscing elit, eget interdum nostra tortor vestibulum ultrices, quisque congue nibh ullamcorper sapien natoque.
+
+
+
+ Venenatis parturient suspendisse massa cursus litora dapibus auctor, et vestibulum blandit condimentum quis ultrices sagittis aliquam.
+
+
+
+
+
diff --git a/views/front-end-onboarding/tasks/select-timezone.php b/views/front-end-onboarding/tasks/select-timezone.php
new file mode 100644
index 0000000000..1a151a6409
--- /dev/null
+++ b/views/front-end-onboarding/tasks/select-timezone.php
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet consectetur adipiscing elit, eget interdum nostra tortor vestibulum ultrices, quisque congue nibh ullamcorper sapien natoque.
+
+
+
+ Venenatis parturient suspendisse massa cursus litora dapibus auctor, et vestibulum blandit condimentum quis ultrices sagittis aliquam.
+
+
+
+
+
From e8d945f1bddab84458fd767e228813de297bc7d9 Mon Sep 17 00:00:00 2001
From: Filip Ilic
Date: Mon, 6 Oct 2025 16:46:28 +0200
Subject: [PATCH 27/50] secondary button styling
---
assets/css/front-end-onboarding.css | 11 +++++++++++
classes/front-end/class-front-end-onboarding.php | 2 +-
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/assets/css/front-end-onboarding.css b/assets/css/front-end-onboarding.css
index d5ac31d6bb..8591c325c0 100644
--- a/assets/css/front-end-onboarding.css
+++ b/assets/css/front-end-onboarding.css
@@ -111,6 +111,17 @@
&:not([disabled]):focus {
background: #cf2441;
}
+
+ &.prpl-btn-secondary {
+ background: #f9b23c;
+ color: #4b5563;
+
+ &:not([disabled]):hover,
+ &:not([disabled]):focus {
+ background: #f9b23c;
+ color: #4b5563;
+ }
+ }
}
.prpl-complete-task-btn:not(.prpl-btn) {
diff --git a/classes/front-end/class-front-end-onboarding.php b/classes/front-end/class-front-end-onboarding.php
index 6c068b914c..a94cb03dfb 100644
--- a/classes/front-end/class-front-end-onboarding.php
+++ b/classes/front-end/class-front-end-onboarding.php
@@ -208,7 +208,7 @@ public function add_popover() {
From 2440fd23f025373a6215a028d1d5c638f3c10d2a Mon Sep 17 00:00:00 2001
From: Filip Ilic
Date: Mon, 6 Oct 2025 16:47:47 +0200
Subject: [PATCH 28/50] add permission check
---
classes/front-end/class-front-end-onboarding.php | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/classes/front-end/class-front-end-onboarding.php b/classes/front-end/class-front-end-onboarding.php
index a94cb03dfb..dca0019eb5 100644
--- a/classes/front-end/class-front-end-onboarding.php
+++ b/classes/front-end/class-front-end-onboarding.php
@@ -146,6 +146,10 @@ public function ajax_save_tour_progress() {
*/
public function ajax_complete_task() {
+ if ( ! \current_user_can( 'manage_options' ) ) {
+ \wp_send_json_error( [ 'message' => \esc_html__( 'You do not have permission to complete this task.', 'progress-planner' ) ] );
+ }
+
if ( ! \check_ajax_referer( 'progress_planner', 'nonce', false ) ) {
\wp_send_json_error( [ 'message' => \esc_html__( 'Invalid nonce.', 'progress-planner' ) ] );
}
From 090761c8007f82e75e7160b592a78fc592a0341c Mon Sep 17 00:00:00 2001
From: Filip Ilic
Date: Mon, 6 Oct 2025 17:35:51 +0200
Subject: [PATCH 29/50] wip styling for
---
assets/css/front-end-onboarding.css | 19 +++++++++++++++++++
views/front-end-onboarding/more-tasks.php | 2 +-
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/assets/css/front-end-onboarding.css b/assets/css/front-end-onboarding.css
index 8591c325c0..2a1a788566 100644
--- a/assets/css/front-end-onboarding.css
+++ b/assets/css/front-end-onboarding.css
@@ -159,6 +159,25 @@
border-radius: 0.25rem;
}
+ /* WIP */
+ select {
+ font-size: 14px;
+ line-height: 2;
+ color: #2c3338;
+ border-color: #8c8f94;
+ box-shadow: none;
+ border-radius: 3px;
+ padding: 0 24px 0 8px;
+ min-height: 30px;
+ /* max-width: 25rem; */
+ width: 100%;
+ -webkit-appearance: none;
+ background: #fff url(data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M5%206l5%205%205-5%202%201-7%207-7-7%202-1z%22%20fill%3D%22%23555%22%2F%3E%3C%2Fsvg%3E) no-repeat right 5px top 55%;
+ background-size: 16px 16px;
+ cursor: pointer;
+ vertical-align: middle;
+ }
+
.prpl-complete-task-btn {
flex-shrink: 0;
}
diff --git a/views/front-end-onboarding/more-tasks.php b/views/front-end-onboarding/more-tasks.php
index a2518a0f8a..797ad7bd72 100644
--- a/views/front-end-onboarding/more-tasks.php
+++ b/views/front-end-onboarding/more-tasks.php
@@ -27,7 +27,7 @@
-
+
From 7168e926ea051cb97adb5453551e9e9efec072cb Mon Sep 17 00:00:00 2001
From: Filip Ilic
Date: Tue, 7 Oct 2025 11:31:24 +0200
Subject: [PATCH 30/50] popover inside popover & remove back button
---
assets/css/front-end-onboarding.css | 7 +
assets/js/front-end-onboarding.js | 189 ++++++++++++------
.../front-end/class-front-end-onboarding.php | 1 -
views/front-end-onboarding/more-tasks.php | 46 ++---
.../tasks/blog-description.php | 2 +
.../tasks/select-locale.php | 2 +
.../tasks/select-timezone.php | 9 +-
7 files changed, 155 insertions(+), 101 deletions(-)
diff --git a/assets/css/front-end-onboarding.css b/assets/css/front-end-onboarding.css
index 2a1a788566..45077dca65 100644
--- a/assets/css/front-end-onboarding.css
+++ b/assets/css/front-end-onboarding.css
@@ -169,6 +169,7 @@
border-radius: 3px;
padding: 0 24px 0 8px;
min-height: 30px;
+
/* max-width: 25rem; */
width: 100%;
-webkit-appearance: none;
@@ -183,6 +184,12 @@
}
}
+ .prpl-task-list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ }
+
.prpl-complete-task-item {
display: flex;
gap: 30px;
diff --git a/assets/js/front-end-onboarding.js b/assets/js/front-end-onboarding.js
index 03a3503590..14fd4de50a 100644
--- a/assets/js/front-end-onboarding.js
+++ b/assets/js/front-end-onboarding.js
@@ -2,6 +2,8 @@
* Progress Planner Tour
* Handles the front-end onboarding tour functionality
*/
+/* global ProgressPlannerData */
+
// eslint-disable-next-line no-unused-vars
class ProgressPlannerTour {
constructor( config ) {
@@ -25,7 +27,6 @@ class ProgressPlannerTour {
this.contentWrapper = this.popover.querySelector(
'.tour-content-wrapper'
);
- this.prevBtn = this.popover.querySelector( '.prpl-tour-prev' );
this.nextBtn = this.popover.querySelector( '.prpl-tour-next' );
this.finishBtn = this.popover.querySelector( '#prpl-finish-btn' );
this.dashboardBtn = this.popover.querySelector( '#prpl-dashboard-btn' );
@@ -100,7 +101,10 @@ class ProgressPlannerTour {
formValues = Object.fromEntries( formData.entries() );
}
- this.completeTask( thisBtn.dataset.taskId, formValues )
+ ProgressPlannerTourUtils.completeTask(
+ thisBtn.dataset.taskId,
+ formValues
+ )
.then( () => {
thisBtn.classList.add( 'prpl-complete-task-btn-completed' );
state.data.firstTaskCompleted = {
@@ -122,68 +126,29 @@ class ProgressPlannerTour {
* @param {Object} state
*/
mountMoreTasksStep( state ) {
- const handler = ( e ) => {
- const thisBtn = e.target.closest( 'button' );
-
- const form = thisBtn.closest( 'form' ); // find parent form
- let formValues = {};
-
- if ( form ) {
- const formData = new FormData( form );
+ const moreTasks = this.popover.querySelectorAll(
+ '.prpl-task-item[data-task-id]'
+ );
+ moreTasks.forEach( ( btn ) => {
+ state.data.moreTasksCompleted[ btn.dataset.taskId ] = false;
+ } );
- // Convert to plain object
- formValues = Object.fromEntries( formData.entries() );
- }
+ this.tasks = Array.from(
+ this.popover.querySelectorAll( '[data-popover="task"]' )
+ ).map( ( t ) => new PopoverTask( t ) );
- this.completeTask( thisBtn.dataset.taskId, formValues )
- .then( () => {
- thisBtn.classList.add( 'prpl-complete-task-btn-completed' );
- state.data.moreTasksCompleted[
- thisBtn.dataset.taskId
- ] = true;
- } )
- .catch( ( error ) => {
- console.error( error );
- thisBtn.classList.add( 'prpl-complete-task-btn-error' );
- } );
+ const handler = ( e ) => {
+ // Update state.
+ state.data.moreTasksCompleted[ e.target.dataset.taskId ] = true;
};
- const btns = this.popover.querySelectorAll( 'button[data-task-id]' );
- btns.forEach( ( btn ) => {
- btn.addEventListener( 'click', handler );
- state.data.moreTasksCompleted[ btn.dataset.taskId ] = false;
- } );
+ this.popover.addEventListener( 'taskCompleted', ( e ) => handler( e ) );
return () => {
- btns.forEach( ( btn ) =>
- btn.removeEventListener( 'click', handler )
- );
+ this.popover.removeEventListener( 'taskCompleted', handler );
};
}
- /**
- * Complete a task via AJAX
- * @param {string} taskId
- * @param {Object} formValues
- */
- async completeTask( taskId, formValues = {} ) {
- const response = await fetch( this.config.adminAjaxUrl, {
- method: 'POST',
- body: new URLSearchParams( {
- form_values: JSON.stringify( formValues ),
- task_id: taskId,
- nonce: this.config.nonceProgressPlanner,
- action: 'progress_planner_tour_complete_task',
- } ),
- } );
-
- if ( ! response.ok ) {
- throw new Error( 'Request failed: ' + response.status );
- }
-
- return response.json();
- }
-
/**
* Render current step
*/
@@ -215,12 +180,9 @@ class ProgressPlannerTour {
* Update button visibility states
*/
updateButtonStates() {
- const isFirstStep = this.state.currentStep === 0;
const isLastStep = this.state.currentStep === this.tourSteps.length - 1;
// Toggle button visibility
- this.prevBtn.style.display =
- isFirstStep || isLastStep ? 'none' : 'inline-block';
this.nextBtn.style.display = isLastStep ? 'none' : 'inline-block';
this.finishBtn.style.display = isLastStep ? 'inline-block' : 'none';
this.dashboardBtn.style.display = isLastStep ? 'inline-block' : 'none';
@@ -370,13 +332,6 @@ class ProgressPlannerTour {
} );
}
- if ( this.prevBtn ) {
- this.prevBtn.addEventListener( 'click', () => {
- console.log( 'Prev button clicked!' );
- this.prevStep();
- } );
- }
-
if ( this.finishBtn ) {
this.finishBtn.addEventListener( 'click', () => {
console.log( 'Finish button clicked!' );
@@ -431,3 +386,107 @@ class ProgressPlannerTour {
} );
}
}
+
+// eslint-disable-next-line no-unused-vars
+class PopoverTask {
+ constructor( el ) {
+ this.el = el;
+ this.id = el.dataset.taskId;
+ this.popover = null;
+ this.formValues = {};
+
+ // Register popover open event.
+ this.el
+ .querySelector( '[prpl-open-task-popover]' )
+ ?.addEventListener( 'click', () => this.open() );
+ }
+
+ registerEvents() {
+ this.popover.addEventListener( 'click', ( e ) => {
+ console.log( 'click', e.target );
+ if ( e.target.classList.contains( 'prpl-complete-task-btn' ) ) {
+ const formData = new FormData(
+ this.popover.querySelector( 'form' )
+ );
+
+ // Convert to plain object
+ this.formValues = Object.fromEntries( formData.entries() );
+
+ this.complete();
+ }
+ } );
+ }
+
+ open() {
+ if ( this.popover ) return;
+
+ const content = this.el
+ .querySelector( 'template' )
+ .content.cloneNode( true );
+ this.popover = document.createElement( 'div' );
+ this.popover.className = 'prpl-popover prpl-popover-onboarding';
+ this.popover.setAttribute( 'popover', 'manual' );
+ this.popover.appendChild( content );
+ document.body.appendChild( this.popover );
+
+ // Register events
+ this.registerEvents();
+
+ this.popover.showPopover();
+ }
+
+ close() {
+ this.popover?.remove();
+ this.popover = null;
+ }
+
+ complete() {
+ ProgressPlannerTourUtils.completeTask( this.id, this.formValues )
+ .then( () => {
+ this.el.classList.add( 'completed' );
+ this.el
+ .querySelector( '.prpl-complete-task-btn' )
+ .classList.add( 'prpl-complete-task-btn-completed' );
+
+ this.close();
+ this.notifyParent();
+ } )
+ .catch( ( error ) => {
+ console.error( error );
+ // TODO: Handle error.
+ } );
+ }
+
+ notifyParent() {
+ const event = new CustomEvent( 'taskCompleted', {
+ bubbles: true,
+ detail: { id: this.id, formValues: this.formValues },
+ } );
+ this.el.dispatchEvent( event );
+ }
+}
+
+class ProgressPlannerTourUtils {
+ /**
+ * Complete a task via AJAX
+ * @param {string} taskId
+ * @param {Object} formValues
+ */
+ static async completeTask( taskId, formValues = {} ) {
+ const response = await fetch( ProgressPlannerData.adminAjaxUrl, {
+ method: 'POST',
+ body: new URLSearchParams( {
+ form_values: JSON.stringify( formValues ),
+ task_id: taskId,
+ nonce: ProgressPlannerData.nonceProgressPlanner,
+ action: 'progress_planner_tour_complete_task',
+ } ),
+ } );
+
+ if ( ! response.ok ) {
+ throw new Error( 'Request failed: ' + response.status );
+ }
+
+ return response.json();
+ }
+}
diff --git a/classes/front-end/class-front-end-onboarding.php b/classes/front-end/class-front-end-onboarding.php
index dca0019eb5..81db1d3a5f 100644
--- a/classes/front-end/class-front-end-onboarding.php
+++ b/classes/front-end/class-front-end-onboarding.php
@@ -210,7 +210,6 @@ public function add_popover() {
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+
Complete Task
-
- the_view( 'front-end-onboarding/tasks/' . $prpl_task['task_id'] . '.php', [ 'task' => $prpl_task ] ); ?>
-
-
-
-
-
+
+ the_view( 'front-end-onboarding/tasks/' . $prpl_task['task_id'] . '.php', [ 'task' => $prpl_task ] ); ?>
+
+
+
-
-
-
-
diff --git a/views/front-end-onboarding/tasks/blog-description.php b/views/front-end-onboarding/tasks/blog-description.php
index 16749e5780..9fe671cb8c 100644
--- a/views/front-end-onboarding/tasks/blog-description.php
+++ b/views/front-end-onboarding/tasks/blog-description.php
@@ -3,6 +3,8 @@
* Onboarding task, blog description.
*
* @package Progress_Planner
+ *
+ * @var array $task
*/
// Exit if accessed directly.
diff --git a/views/front-end-onboarding/tasks/select-locale.php b/views/front-end-onboarding/tasks/select-locale.php
index f7e8c5061c..be10f2124a 100644
--- a/views/front-end-onboarding/tasks/select-locale.php
+++ b/views/front-end-onboarding/tasks/select-locale.php
@@ -3,6 +3,8 @@
* Onboarding task, set site locale.
*
* @package Progress_Planner
+ *
+ * @var array $task
*/
// Exit if accessed directly.
diff --git a/views/front-end-onboarding/tasks/select-timezone.php b/views/front-end-onboarding/tasks/select-timezone.php
index 1a151a6409..8fa5955c3b 100644
--- a/views/front-end-onboarding/tasks/select-timezone.php
+++ b/views/front-end-onboarding/tasks/select-timezone.php
@@ -3,6 +3,8 @@
* Onboarding task, set site timezone.
*
* @package Progress_Planner
+ *
+ * @var array $task
*/
// Exit if accessed directly.
@@ -10,9 +12,8 @@
exit;
}
-$prpl_current_offset = \get_option( 'gmt_offset' );
-$prpl_tzstring = \get_option( 'timezone_string' );
-$prpl_was_tzstring_saved = '' !== $prpl_tzstring || '0' !== $prpl_current_offset ? 'true' : 'false';
+$prpl_current_offset = \get_option( 'gmt_offset' );
+$prpl_tzstring = \get_option( 'timezone_string' );
?>
@@ -30,7 +31,7 @@
diff --git a/views/front-end-onboarding/tasks/core-siteicon.php b/views/front-end-onboarding/tasks/core-siteicon.php
new file mode 100644
index 0000000000..cc2e5c8acb
--- /dev/null
+++ b/views/front-end-onboarding/tasks/core-siteicon.php
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet consectetur adipiscing elit, eget interdum nostra tortor vestibulum ultrices, quisque congue nibh ullamcorper sapien natoque.
+
+
+
+ Venenatis parturient suspendisse massa cursus litora dapibus auctor, et vestibulum blandit condimentum quis ultrices sagittis aliquam.
+
+
+
+
+
diff --git a/views/front-end-onboarding/tasks/select-locale.php b/views/front-end-onboarding/tasks/select-locale.php
index f2b361fecf..65a1ed17ab 100644
--- a/views/front-end-onboarding/tasks/select-locale.php
+++ b/views/front-end-onboarding/tasks/select-locale.php
@@ -44,8 +44,8 @@
From 35fa3d585827039348832f0ef0cb6277658a28a9 Mon Sep 17 00:00:00 2001
From: Filip Ilic
Date: Wed, 8 Oct 2025 11:16:11 +0200
Subject: [PATCH 35/50] handle file upload
---
assets/css/front-end-onboarding.css | 2 +
assets/js/front-end-onboarding.js | 88 +++++++++++++------
.../front-end/class-front-end-onboarding.php | 41 +++++++++
.../tasks/core-siteicon.php | 3 +-
4 files changed, 107 insertions(+), 27 deletions(-)
diff --git a/assets/css/front-end-onboarding.css b/assets/css/front-end-onboarding.css
index d372522168..f74cd63dca 100644
--- a/assets/css/front-end-onboarding.css
+++ b/assets/css/front-end-onboarding.css
@@ -136,6 +136,8 @@
.prpl-complete-task-btn-completed:not(.prpl-btn) {
color: #059669;
+ pointer-events: none;
+ opacity: 0.5;
}
.prpl-complete-task-btn-error {
diff --git a/assets/js/front-end-onboarding.js b/assets/js/front-end-onboarding.js
index 6f159263c6..b2b226cdbb 100644
--- a/assets/js/front-end-onboarding.js
+++ b/assets/js/front-end-onboarding.js
@@ -419,6 +419,24 @@ class PopoverTask {
// Initialize upload handling (only if upload field exists)
this.setupFileUpload();
+
+ this.el.addEventListener( 'prplFileUploaded', ( e ) => {
+ // Handle file upload for the 'set site icon' task.
+ if ( 'core-siteicon' === e.detail.fileInput.dataset.taskId ) {
+ // Element which will be used to store the file post ID.
+ const nextElementSibling =
+ e.detail.fileInput.nextElementSibling;
+
+ nextElementSibling.value = e.detail.filePost.id;
+
+ // Trigger change so validation is triggered and "Complete" button is enabled.
+ nextElementSibling.dispatchEvent(
+ new CustomEvent( 'change', {
+ bubbles: true,
+ } )
+ );
+ }
+ } );
}
open() {
@@ -558,12 +576,32 @@ class PopoverTask {
uploadContainer.addEventListener( 'drop', ( e ) => {
const file = e.dataTransfer.files[ 0 ];
- if ( file ) this.uploadFile( file, statusDiv );
+ if ( file ) {
+ this.uploadFile( file, statusDiv ).then( ( response ) => {
+ this.el.dispatchEvent(
+ new CustomEvent( 'prplFileUploaded', {
+ detail: { file, filePost: response, fileInput },
+ bubbles: true,
+ } )
+ );
+ } );
+ }
} );
fileInput?.addEventListener( 'change', ( e ) => {
const file = e.target.files[ 0 ];
- if ( file ) this.uploadFile( file, statusDiv );
+ if ( file ) {
+ this.uploadFile( file, statusDiv, fileInput ).then(
+ ( response ) => {
+ this.el.dispatchEvent(
+ new CustomEvent( 'prplFileUploaded', {
+ detail: { file, filePost: response, fileInput },
+ bubbles: true,
+ } )
+ );
+ }
+ );
+ }
} );
}
@@ -581,32 +619,30 @@ class PopoverTask {
const formData = new FormData();
formData.append( 'file', file );
- formData.append( 'task_id', this.id );
-
- try {
- // TODO: Replace with actual upload endpoint.
- const response = await fetch( ProgressPlannerData.adminAjaxUrl, {
- method: 'POST',
- body: formData,
- credentials: 'same-origin',
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded',
- },
- action: 'progress_planner_tour_upload_file',
- } );
+ formData.append( 'prplFileUpload', '1' );
- if ( response.ok ) {
- const data = await response.json();
+ return fetch( '/wp-json/wp/v2/media', {
+ method: 'POST',
+ headers: {
+ 'X-WP-Nonce': ProgressPlannerData.nonceWPAPI, // usually wp_localize_script adds this
+ },
+ body: formData,
+ credentials: 'same-origin',
+ } )
+ .then( ( res ) => {
+ if ( 201 !== res.status ) {
+ throw new Error( 'Failed to upload file' );
+ }
+ return res.json();
+ } )
+ .then( ( response ) => {
statusDiv.textContent = `${ file.name } uploaded.`;
-
- // Store uploaded file info in formValues
- this.formValues.uploadedFile = data.file_url || file.name;
- } else {
- statusDiv.textContent = `Failed to upload ${ file.name }`;
- }
- } catch ( err ) {
- statusDiv.textContent = `Error: ${ err.message }`;
- }
+ return response;
+ } )
+ .catch( ( error ) => {
+ console.error( error );
+ statusDiv.textContent = `Error: ${ error.message }`;
+ } );
}
/**
diff --git a/classes/front-end/class-front-end-onboarding.php b/classes/front-end/class-front-end-onboarding.php
index 524c7bde4d..d20dae7f17 100644
--- a/classes/front-end/class-front-end-onboarding.php
+++ b/classes/front-end/class-front-end-onboarding.php
@@ -35,6 +35,46 @@ public function __construct() {
// Maybe show user notification that tour is not finished.
\add_action( 'init', [ $this, 'maybe_show_user_notification' ] );
+
+ // Allow only images for the front-end upload.
+ add_filter( 'rest_pre_insert_attachment', [ $this, 'rest_pre_insert_attachment' ], 10, 2 );
+ }
+
+ /**
+ * Allow only images for the front-end upload.
+ *
+ * @param array $attachment The attachment.
+ * @param \WP_REST_Request $request The request.
+ * @return array|\WP_Error The attachment or WP_Error.
+ */
+ public function rest_pre_insert_attachment( $attachment, $request ) {
+
+ // Only run for our file upload.
+ if ( isset( $request['prplFileUpload'] ) && $request['prplFileUpload'] ) {
+
+ $files = $request->get_file_params();
+
+ if ( empty( $files['file'] ) ) {
+ return new \WP_Error(
+ 'rest_no_file',
+ __( 'No file uploaded.', 'progress-planner' ),
+ [ 'status' => 400 ]
+ );
+ }
+
+ $file = $files['file'];
+
+ // Check MIME type.
+ if ( strpos( $file['type'], 'image/' ) !== 0 ) {
+ return new \WP_Error(
+ 'rest_invalid_file_type',
+ __( 'Only images are allowed for this upload.', 'progress-planner' ),
+ [ 'status' => 400 ]
+ );
+ }
+ }
+
+ return $attachment;
}
/**
@@ -80,6 +120,7 @@ public function add_popover_scripts() {
[
'adminAjaxUrl' => \esc_url_raw( admin_url( 'admin-ajax.php' ) ),
'nonceProgressPlanner' => \esc_js( \wp_create_nonce( 'progress_planner' ) ),
+ 'nonceWPAPI' => \esc_js( \wp_create_nonce( 'wp_rest' ) ),
]
);
}
diff --git a/views/front-end-onboarding/tasks/core-siteicon.php b/views/front-end-onboarding/tasks/core-siteicon.php
index 57f40ffb8d..96f025102e 100644
--- a/views/front-end-onboarding/tasks/core-siteicon.php
+++ b/views/front-end-onboarding/tasks/core-siteicon.php
@@ -39,7 +39,8 @@
);
?>
-
+
+
From 549fb546fd0edde2cf329dc3fe28c62ce72c08d2 Mon Sep 17 00:00:00 2001
From: Filip Ilic
Date: Wed, 8 Oct 2025 11:54:51 +0200
Subject: [PATCH 36/50] move assets
---
.../css/front-end-onboarding.css | 0
.../front-end-onboarding/images/badge-gauge.png | Bin 0 -> 41973 bytes
.../js/front-end-onboarding.js | 0
.../front-end/class-front-end-onboarding.php | 4 ++--
views/front-end-onboarding/badges.php | 2 +-
5 files changed, 3 insertions(+), 3 deletions(-)
rename assets/{ => front-end-onboarding}/css/front-end-onboarding.css (100%)
create mode 100644 assets/front-end-onboarding/images/badge-gauge.png
rename assets/{ => front-end-onboarding}/js/front-end-onboarding.js (100%)
diff --git a/assets/css/front-end-onboarding.css b/assets/front-end-onboarding/css/front-end-onboarding.css
similarity index 100%
rename from assets/css/front-end-onboarding.css
rename to assets/front-end-onboarding/css/front-end-onboarding.css
diff --git a/assets/front-end-onboarding/images/badge-gauge.png b/assets/front-end-onboarding/images/badge-gauge.png
new file mode 100644
index 0000000000000000000000000000000000000000..e515d2b5a799cbd936e63e369633c6002ad3e9af
GIT binary patch
literal 41973
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
literal 0
HcmV?d00001
diff --git a/assets/js/front-end-onboarding.js b/assets/front-end-onboarding/js/front-end-onboarding.js
similarity index 100%
rename from assets/js/front-end-onboarding.js
rename to assets/front-end-onboarding/js/front-end-onboarding.js
diff --git a/classes/front-end/class-front-end-onboarding.php b/classes/front-end/class-front-end-onboarding.php
index d20dae7f17..33d4196ac0 100644
--- a/classes/front-end/class-front-end-onboarding.php
+++ b/classes/front-end/class-front-end-onboarding.php
@@ -109,10 +109,10 @@ public function maybe_show_user_notification() {
*/
public function add_popover_scripts() {
// Enqueue front-end-onboarding.css.
- \wp_enqueue_style( 'prpl-popover-front-end-onboarding', \constant( 'PROGRESS_PLANNER_URL' ) . '/assets/css/front-end-onboarding.css', [], \progress_planner()->get_plugin_version() );
+ \wp_enqueue_style( 'prpl-popover-front-end-onboarding', \constant( 'PROGRESS_PLANNER_URL' ) . '/assets/front-end-onboarding/css/front-end-onboarding.css', [], \progress_planner()->get_plugin_version() );
// Enqueue front-end-onboarding.js.
- \wp_enqueue_script( 'prpl-popover-front-end-onboarding', \constant( 'PROGRESS_PLANNER_URL' ) . '/assets/js/front-end-onboarding.js', [], \progress_planner()->get_plugin_version(), true );
+ \wp_enqueue_script( 'prpl-popover-front-end-onboarding', \constant( 'PROGRESS_PLANNER_URL' ) . '/assets/front-end-onboarding/js/front-end-onboarding.js', [], \progress_planner()->get_plugin_version(), true );
\wp_localize_script(
'prpl-popover-front-end-onboarding',
diff --git a/views/front-end-onboarding/badges.php b/views/front-end-onboarding/badges.php
index ccfdf77f79..a4ea4322c2 100644
--- a/views/front-end-onboarding/badges.php
+++ b/views/front-end-onboarding/badges.php
@@ -30,7 +30,7 @@
-
+
From 407131a200c8891d73174fef86b3a78ad482c1e9 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 8 Oct 2025 09:55:44 +0000
Subject: [PATCH 37/50] Optimised images with calibre/image-actions
---
.../images/badge-gauge.png | Bin 41973 -> 11070 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
diff --git a/assets/front-end-onboarding/images/badge-gauge.png b/assets/front-end-onboarding/images/badge-gauge.png
index e515d2b5a799cbd936e63e369633c6002ad3e9af..b31718721475cbf597dc0175954d078e111bbf31 100644
GIT binary patch
literal 11070
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