diff --git a/includes/admin/pages/components/progress.php b/includes/admin/pages/components/progress.php
new file mode 100644
index 00000000..9dd1b7dd
--- /dev/null
+++ b/includes/admin/pages/components/progress.php
@@ -0,0 +1,72 @@
+ }
+ * - string $assets_base
+ * - bool $force_complete_styles
+ */
+if (!defined('ABSPATH')) {
+ exit();
+}
+
+$percent = isset($progress['percent']) ? (int) $progress['percent'] : 0;
+$label = isset($progress['label']) ? (string) $progress['label'] : '';
+$items = isset($progress['items']) && is_array($progress['items']) ? $progress['items'] : [];
+
+$circle_class = $percent >= 100 ? '100' : ($percent >= 67 ? '67' : '33');
+?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - class="">
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/includes/admin/pages/connect-controller.php b/includes/admin/pages/connect-controller.php
new file mode 100644
index 00000000..bc238c93
--- /dev/null
+++ b/includes/admin/pages/connect-controller.php
@@ -0,0 +1,79 @@
+ 'calendar',
+ 'post_status' => 'publish',
+ 'posts_per_page' => 1,
+ 'fields' => 'ids',
+]);
+$has_published_calendar = $calendar_query->have_posts();
+wp_reset_postdata();
+
+// Track when setup first reached 100% so we can hide the progress card after a day.
+$completed_timestamp = (int) get_option('simple-calendar_connect_setup_completed_at', 0);
+if ($has_published_calendar && $completed_timestamp <= 0) {
+ $completed_timestamp = time();
+ update_option('simple-calendar_connect_setup_completed_at', $completed_timestamp);
+}
+$hide_progress_after = DAY_IN_SECONDS;
+$should_hide_progress =
+ $has_published_calendar && $completed_timestamp > 0 && time() - $completed_timestamp >= $hide_progress_after;
+
+// Decide current step.
+$step = 'api_key';
+if ($show_welcome) {
+ $step = 'welcome';
+} elseif ($has_api_key && !$has_published_calendar) {
+ $step = 'add_calendar';
+}
+
+$step_title_map = [
+ 'welcome' => __('Welcome', 'google-calendar-events'),
+ 'api_key' => __('Add API Key', 'google-calendar-events'),
+ 'add_calendar' => __('Add New Calendar', 'google-calendar-events'),
+];
+$step_title = isset($step_title_map[$step]) ? $step_title_map[$step] : __('Connect', 'google-calendar-events');
+
+$step_template_map = [
+ 'welcome' => SIMPLE_CALENDAR_PATH . 'includes/admin/pages/connect/steps/welcome.php',
+ 'api_key' => SIMPLE_CALENDAR_PATH . 'includes/admin/pages/connect/steps/api-key.php',
+ 'add_calendar' => SIMPLE_CALENDAR_PATH . 'includes/admin/pages/connect/steps/add-calendar.php',
+];
+$step_template_path = isset($step_template_map[$step]) ? $step_template_map[$step] : $step_template_map['api_key'];
+
+$context = [
+ // Shared.
+ 'assets_base' => $assets_base,
+ // Step state.
+ 'api_key' => $api_key,
+ 'has_api_key' => $has_api_key,
+ 'has_published_calendar' => $has_published_calendar,
+ 'should_hide_progress' => $should_hide_progress,
+ // Welcome.
+ 'video_url' => apply_filters('simple_calendar_connect_welcome_video_url', 'https://www.youtube.com/embed/VIDEO_ID'),
+ // Sidebar.
+ 'sidebar_template_path' => SIMPLE_CALENDAR_PATH . 'includes/admin/pages/connect/sidebar.php',
+];
+
+include SIMPLE_CALENDAR_PATH . 'includes/admin/pages/connect/layout.php';
diff --git a/includes/admin/pages/connect/layout.php b/includes/admin/pages/connect/layout.php
new file mode 100644
index 00000000..ae1836bf
--- /dev/null
+++ b/includes/admin/pages/connect/layout.php
@@ -0,0 +1,54 @@
+
+
+
diff --git a/includes/admin/pages/connect/sidebar.php b/includes/admin/pages/connect/sidebar.php
new file mode 100644
index 00000000..394d3a77
--- /dev/null
+++ b/includes/admin/pages/connect/sidebar.php
@@ -0,0 +1,123 @@
+ $has_published_calendar ? 100 : ($has_api_key ? 67 : 33),
+ 'label' => $has_published_calendar
+ ? __('100% Ready', 'google-calendar-events')
+ : ($has_api_key
+ ? __('67% Ready', 'google-calendar-events')
+ : __('33% Ready', 'google-calendar-events')),
+ 'items' => [
+ [
+ 'text' => __('Watch Tutorial', 'google-calendar-events'),
+ 'completed' => true,
+ 'icon_src' => $assets_base . 'check.svg',
+ ],
+ [
+ 'id' => 'sc_connect_step_api_key',
+ 'text' => __('Add API Key', 'google-calendar-events'),
+ 'completed' => $has_api_key || $has_published_calendar,
+ 'icon_src' => $assets_base . 'check.svg',
+ ],
+ [
+ 'id' => 'sc_connect_step_calendar',
+ 'text' => __('Add New Calendar', 'google-calendar-events'),
+ 'completed' => $has_published_calendar,
+ 'icon_src' => $assets_base . 'check.svg',
+ ],
+ ],
+ ];
+
+ $force_complete_styles = $has_published_calendar;
+ include SIMPLE_CALENDAR_PATH . 'includes/admin/pages/components/progress.php';
+ return;
+}
+?>
+
+
diff --git a/includes/admin/pages/connect/steps/add-calendar.php b/includes/admin/pages/connect/steps/add-calendar.php
new file mode 100644
index 00000000..90cdb42a
--- /dev/null
+++ b/includes/admin/pages/connect/steps/add-calendar.php
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/includes/admin/pages/connect/steps/welcome.php b/includes/admin/pages/connect/steps/welcome.php
new file mode 100644
index 00000000..5db17b9b
--- /dev/null
+++ b/includes/admin/pages/connect/steps/welcome.php
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
; ?>)
+
+
+
+
+
+
+
+
diff --git a/includes/functions/admin.php b/includes/functions/admin.php
index 9e5de4e6..ce367b02 100644
--- a/includes/functions/admin.php
+++ b/includes/functions/admin.php
@@ -141,6 +141,7 @@ function simcal_is_admin_screen()
$screens = [
'customize',
'calendar',
+ 'calendar_page_simple-calendar_connect',
'calendar_page_simple-calendar_add_ons',
'calendar_page_simple-calendar_settings',
'calendar_page_simple-calendar_tools',
diff --git a/includes/installation.php b/includes/installation.php
index f57c5e87..49b1cf57 100644
--- a/includes/installation.php
+++ b/includes/installation.php
@@ -34,6 +34,9 @@ public static function activate()
self::create_terms();
self::create_options();
+ // Flag to redirect to the Connect page on first admin load after activation.
+ update_option('simple-calendar_redirect_to_connect', 1);
+
// Clear cache on activation.
simcal_delete_feed_transients();
diff --git a/includes/main.php b/includes/main.php
index 5a7f6a67..7f18a3d7 100644
--- a/includes/main.php
+++ b/includes/main.php
@@ -113,6 +113,11 @@ public function __construct()
// Do update call here.
add_action('admin_init', [$this, 'update'], 999);
+ // Redirect to Connect page after activation (only hook when needed).
+ if (is_admin() && get_option('simple-calendar_redirect_to_connect')) {
+ add_action('admin_init', [$this, 'maybe_redirect_to_connect'], 1);
+ }
+
// Init hooks.
add_action('init', [$this, 'init'], 5);
add_action('admin_init', [$this, 'register_settings'], 5);
@@ -321,6 +326,41 @@ public static function update()
{
$update = new Update(SIMPLE_CALENDAR_VERSION);
}
+
+ /**
+ * Redirect to the Connect page on first admin load after activation.
+ *
+ * @since 3.6.3
+ *
+ * @return void
+ */
+ public function maybe_redirect_to_connect()
+ {
+ // Only run in admin and for users who can manage options.
+ if (!is_admin() || !current_user_can('manage_options')) {
+ return;
+ }
+
+ // Do not redirect during AJAX or if no redirect flag is set.
+ if ((defined('DOING_AJAX') && DOING_AJAX) || !get_option('simple-calendar_redirect_to_connect')) {
+ return;
+ }
+
+ // Avoid redirect on bulk activation.
+ if (isset($_GET['activate-multi'])) {
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ delete_option('simple-calendar_redirect_to_connect');
+ return;
+ }
+
+ // Clear the flag so we only redirect once.
+ delete_option('simple-calendar_redirect_to_connect');
+
+ $redirect_url = admin_url('edit.php?post_type=calendar&page=simple-calendar_connect');
+
+ wp_safe_redirect($redirect_url);
+ exit();
+ }
}
/**