PluginProbe
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings / 6.3.4
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings v6.3.4
7.2 7.1.2 7.1.1 7.1 7.0.4 7.0.6 7.0.7 6.3.8 6.3.7 6.3.6 6.3.5 6.3.4 6.3.3 6.3.1 trunk 5.7.3 5.7.5 5.8.1 5.8.2 5.8.3 5.8.4 5.8.6 6.0.4 6.0.5 6.0.7 All 35 releases
mlsimport / includes / mlsimport-onboarding.php

mlsimport-onboarding.php in MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings 6.3.4, at includes/mlsimport-onboarding.php

1,040 lines 33.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * MLSImport Onboarding Wizard
4 *
5 * This file contains all the functionality for the onboarding wizard
6 * that guides users through the initial setup of the MLSImport plugin.
7 *includes\mlsimport-onboarding.php
8 * @link https://mlsimport.com/
9 * @since 6.1.0
10 *
11 * @package Mlsimport
12 * @subpackage Mlsimport/includes
13 */
14
15 // If this file is called directly, abort.
16 if (!defined('WPINC')) {
17 die;
18 }
19
20 /**
21 * Initialize the onboarding functionality
22 *
23 * @since 6.1.0
24 */
25 function mlsimport_init_onboarding() {
26 // Only initialize for admin pages
27 if (!is_admin()) {
28 return;
29 }
30
31 // Check if we need to start or continue onboarding
32 mlsimport_check_onboarding_status();
33
34
35 // Register the onboarding page
36 add_action('admin_menu', 'mlsimport_register_onboarding_page');
37
38 // Add menu item to start/resume onboarding
39 add_action('admin_menu', 'mlsimport_add_onboarding_menu_item');
40
41 // Add assets for onboarding
42 add_action('admin_enqueue_scripts', 'mlsimport_enqueue_onboarding_assets');
43
44 // Register AJAX handlers
45 add_action('wp_ajax_mlsimport_test_account_connection', 'mlsimport_ajax_test_account_connection');
46 add_action('wp_ajax_mlsimport_test_mls_connection', 'mlsimport_ajax_test_mls_connection');
47 add_action('wp_ajax_mlsimport_run_test_import', 'mlsimport_ajax_run_test_import');
48 add_action('wp_ajax_mlsimport_save_step_data', 'mlsimport_ajax_save_step_data');
49
50 // Add admin notice for incomplete onboarding
51 add_action('admin_notices', 'mlsimport_onboarding_admin_notice');
52
53 // Intercept form submissions
54 add_action('admin_init', 'mlsimport_handle_step_submission');
55 }
56
57 /**
58 * Check if onboarding is complete or in progress
59 *
60 * @since 6.1.0
61 */
62 function mlsimport_check_onboarding_status() {
63 // Check if onboarding is complete
64 $onboarding_completed = get_option('mlsimport_onboarding_completed', false);
65
66 // If onboarding is complete, we don't need to do anything
67 if ($onboarding_completed) {
68 return;
69 }
70
71 // Redirect to onboarding if activation flag is set
72 if (get_option('mlsimport_do_onboarding_redirect', false)) {
73 delete_option('mlsimport_do_onboarding_redirect');
74 wp_safe_redirect(admin_url('admin.php?page=mlsimport-onboarding'));
75 exit;
76 }
77
78 // Check if we're on the plugin activation page
79 if (isset($_GET['activate']) && $_GET['activate'] == 'true' && isset($_GET['plugin']) && strpos($_GET['plugin'], 'mlsimport') !== false) {
80 // Redirect to onboarding welcome page
81 wp_redirect(admin_url('admin.php?page=mlsimport-onboarding'));
82 exit;
83 }
84 }
85
86 /**
87 * Register the onboarding admin page
88 *
89 * @since 6.1.0
90 */
91 function mlsimport_register_onboarding_page() {
92 add_submenu_page(
93 '', // No parent - won't appear in menu
94 __('MLS Import Setup Wizard', 'mlsimport'),
95 __('Setup Wizard', 'mlsimport'),
96 'manage_options',
97 'mlsimport-onboarding',
98 'mlsimport_render_onboarding_wizard'
99 );
100 }
101
102 /**
103 * Add onboarding menu item to the MLS Import menu
104 *
105 * @since 6.1.0
106 */
107 function mlsimport_add_onboarding_menu_item() {
108 // Only show if onboarding hasn't been completed
109
110 add_submenu_page(
111 'mlsimport_plugin_options',
112 __('Setup Wizard', 'mlsimport'),
113 __('Setup Wizard', 'mlsimport'),
114 'manage_options',
115 'mlsimport-onboarding',
116 'mlsimport_render_onboarding_wizard'
117 );
118
119 }
120
121 /**
122 * Enqueue scripts and styles for the onboarding wizard
123 *
124 * @since 6.1.0
125 * @param string $hook The current admin page
126 */
127 function mlsimport_enqueue_onboarding_assets($hook) {
128 if ($hook != 'admin_page_mlsimport-onboarding' && $hook != 'mlsimport_plugin_options_page_mlsimport-onboarding') {
129 return;
130 }
131 $mls_import_list = mlsimport_saas_request_list();
132 // Enqueue styles
133 wp_enqueue_style(
134 'mlsimport-onboarding-style',
135 MLSIMPORT_PLUGIN_URL . 'admin/css/mlsimport-onboarding.css',
136 array(),
137 MLSIMPORT_VERSION
138 );
139
140 // Enqueue script
141 wp_enqueue_script(
142 'mlsimport-onboarding-script',
143 MLSIMPORT_PLUGIN_URL . 'admin/js/mlsimport-onboarding.js',
144 array('jquery','mlsimport-admin','jquery-ui-autocomplete'),
145 MLSIMPORT_VERSION,
146 true
147 );
148
149 // Localize script with data
150 wp_localize_script(
151 'mlsimport-onboarding-script',
152 'mlsimportOnboarding',
153 array(
154 'ajaxurl' => admin_url('admin-ajax.php'),
155 'nonce' => wp_create_nonce('mlsimport_onboarding_nonce'),
156 'current_step' => mlsimport_get_current_step(),
157 'steps' => mlsimport_get_steps(),
158 'strings' => array(
159 'saving' => __('Saving...', 'mlsimport'),
160 'next' => __('Next', 'mlsimport'),
161 'back' => __('Back', 'mlsimport'),
162 'skip' => __('Skip', 'mlsimport'),
163 'connecting' => __('Connecting...', 'mlsimport'),
164 'testing' => __('Testing...', 'mlsimport'),
165 'importing' => __('Importing...', 'mlsimport'),
166 'success' => __('Success!', 'mlsimport'),
167 'error' => __('Error', 'mlsimport'),
168 )
169 )
170 );
171
172 if ( $hook === 'admin_page_mlsimport-onboarding' &&
173 isset($_GET['page']) && $_GET['page'] === 'mlsimport-onboarding' &&
174 isset($_GET['step']) && $_GET['step'] === 'account') {
175
176 if (!empty($mls_import_list)) {
177
178 $inline_script = 'jQuery(document).ready(function($){ var autofill=' . wp_kses_post($mls_import_list) . '; mlsimport_autocomplte_mls_selection(autofill); });';
179 wp_add_inline_script('mlsimport-onboarding-script', $inline_script);
180 }
181 }
182
183
184
185 }
186
187 /**
188 * Display the onboarding wizard
189 *
190 * @since 6.1.0
191 */
192 function mlsimport_render_onboarding_wizard() {
193 // Check current step
194 $current_step = mlsimport_get_current_step();
195
196 // Get all steps
197 $steps = mlsimport_get_steps();
198
199 // Load the wizard template
200 include MLSIMPORT_PLUGIN_PATH . 'admin/partials/mlsimport-onboarding-wizard.php';
201 }
202
203 /**
204 * Get the current onboarding step
205 *
206 * @since 6.1.0
207 * @return string The current step ID
208 */
209 function mlsimport_get_current_step() {
210 // Check if step is set in URL
211 if (isset($_GET['step']) && !empty($_GET['step'])) {
212 $step = sanitize_text_field($_GET['step']);
213
214 // Validate step
215 $steps = mlsimport_get_steps();
216 if (array_key_exists($step, $steps)) {
217 // Save current step
218 update_option('mlsimport_onboarding_current_step', $step);
219 return $step;
220 }
221 }
222
223 // Check if step is saved in options
224 $saved_step = get_option('mlsimport_onboarding_current_step', '');
225 if (!empty($saved_step)) {
226 return $saved_step;
227 }
228
229 // Default to first step
230 $steps = mlsimport_get_steps();
231 $first_step = array_key_first($steps);
232 update_option('mlsimport_onboarding_current_step', $first_step);
233
234 return $first_step;
235 }
236
237 /**
238 * Get all onboarding steps
239 *
240 * @since 6.1.0
241 * @return array The onboarding steps
242 */
243 function mlsimport_get_steps() {
244 return array(
245 'welcome' => array(
246 'title' => __('Welcome', 'mlsimport'),
247 'description' =>'',
248 'template' => 'step-welcome.php',
249 ),
250 'account' => array(
251 'title' => __('Account & MLS Connection', 'mlsimport'),
252 'description' => __('Connect to your MLS Import account and MLS provider', 'mlsimport'),
253 'template' => 'step-account.php',
254 ),
255 'field-mapping' => array(
256 'title' => __('Field Mapping', 'mlsimport'),
257 'description' => __('Configure how MLS fields map to your website', 'mlsimport'),
258 'template' => 'step-field-mapping.php',
259 ),
260 'import-config' => array(
261 'title' => __('Import Configuration', 'mlsimport'),
262 'description' => __('Set up your first import configuration', 'mlsimport'),
263 'template' => 'step-import-config.php',
264 ),
265 'test-import' => array(
266 'title' => __('Test Import', 'mlsimport'),
267 'description' => __('Run a test import to verify your setup', 'mlsimport'),
268 'template' => 'step-test-import.php',
269 ),
270 'success' => array(
271 'title' => __('Success', 'mlsimport'),
272 'description' => __('Your MLS Import is now configured', 'mlsimport'),
273 'template' => 'step-success.php',
274 ),
275 );
276 }
277
278 /**
279 * Save data for the current step
280 *
281 * @since 6.1.0
282 * @param string $step The step ID
283 * @param array $data The step data to save
284 * @return bool Success or failure
285 */
286 function mlsimport_save_step_data($step, $data) {
287 $user_data = get_option('mlsimport_onboarding_user_data', array());
288
289 // Sanitize data
290 $sanitized_data = array();
291 foreach ($data as $key => $value) {
292 if (is_array($value)) {
293 $sanitized_data[$key] = array_map('sanitize_text_field', $value);
294 } else {
295 $sanitized_data[$key] = sanitize_text_field($value);
296 }
297 }
298
299 // Update user data
300 $user_data[$step] = $sanitized_data;
301
302 // Record onboarding-step completion (lifecycle telemetry).
303 mlsimport_telemetry_mark_onboarding_step( $step );
304
305 // Save user data
306 return update_option('mlsimport_onboarding_user_data', $user_data);
307 }
308
309 /**
310 * Get saved data for a specific step
311 *
312 * @since 6.1.0
313 * @param string $step The step ID
314 * @return array The step data
315 */
316 function mlsimport_get_onboarding_step_data($step) {
317 $user_data = get_option('mlsimport_onboarding_user_data', array());
318
319 if (isset($user_data[$step])) {
320 return $user_data[$step];
321 }
322
323 return array();
324 }
325
326 /**
327 * Redirect to the next step
328 *
329 * @since 6.1.0
330 * @param string $current_step The current step ID
331 */
332 function mlsimport_redirect_to_next_step($current_step) {
333 $next_step = mlsimport_get_next_step($current_step);
334
335 if ($next_step) {
336 wp_redirect(admin_url('admin.php?page=mlsimport-onboarding&step=' . $next_step));
337 exit;
338 }
339 }
340
341 /**
342 * Get the next step ID
343 *
344 * @since 6.1.0
345 * @param string $current_step The current step ID
346 * @return string|null The next step ID or null if there is no next step
347 */
348 function mlsimport_get_next_step($current_step) {
349 $steps = mlsimport_get_steps();
350 $step_keys = array_keys($steps);
351
352 $current_index = array_search($current_step, $step_keys);
353
354 if ($current_index !== false && isset($step_keys[$current_index + 1])) {
355 return $step_keys[$current_index + 1];
356 }
357
358 return null;
359 }
360
361 /**
362 * Get the previous step ID
363 *
364 * @since 6.1.0
365 * @param string $current_step The current step ID
366 * @return string|null The previous step ID or null if there is no previous step
367 */
368 function mlsimport_get_previous_step($current_step) {
369 $steps = mlsimport_get_steps();
370 $step_keys = array_keys($steps);
371
372 $current_index = array_search($current_step, $step_keys);
373
374 if ($current_index !== false && $current_index > 0) {
375 return $step_keys[$current_index - 1];
376 }
377
378 return null;
379 }
380
381 /**
382 * Handle step form submission
383 *
384 * @since 6.1.0
385 */
386 function mlsimport_handle_step_submission() {
387 // Only process on onboarding page
388 if (!isset($_GET['page']) || $_GET['page'] !== 'mlsimport-onboarding') {
389 return;
390 }
391
392 // Check if form was submitted
393 if (!isset($_POST['mlsimport_onboarding_submit'])) {
394 return;
395 }
396
397 // Verify nonce
398 if (!mlsimport_verify_onboarding_nonce()) {
399 wp_die(__('Security check failed. Please try again.', 'mlsimport'));
400 }
401
402 // Get current step
403 $current_step = mlsimport_get_current_step();
404
405 // Process based on step
406 switch ($current_step) {
407 case 'welcome':
408 // Nothing to save, just redirect to next step
409 mlsimport_redirect_to_next_step($current_step);
410 break;
411
412 case 'account':
413 // Save account information only if all required fields are filled
414 $username = isset($_POST['mlsimport_username']) ? trim($_POST['mlsimport_username']) : '';
415 $password = isset($_POST['mlsimport_password']) ? trim($_POST['mlsimport_password']) : '';
416 $mls_id = isset($_POST['mlsimport_mls_name']) ? trim($_POST['mlsimport_mls_name']) : '';
417 $token = isset($_POST['mlsimport_mls_token']) ? trim($_POST['mlsimport_mls_token']) : '';
418
419 // Only save if all fields are non-empty
420 if ($username !== '' && $password !== '' && $mls_id !== '' && $token !== '') {
421 $account_data = array(
422 'username' => $username,
423 'password' => $password,
424 'mls_id' => $mls_id,
425 'mls_token' => $token,
426 );
427
428 mlsimport_save_step_data($current_step, $account_data);
429
430 // Save to plugin options
431 $options = get_option('mlsimport_admin_options', array());
432 $options['mlsimport_username'] = $username;
433 $options['mlsimport_password'] = $password;
434 $options['mlsimport_mls_name'] = $mls_id;
435 $options['mlsimport_mls_token'] = $token;
436 update_option('mlsimport_admin_options', $options);
437
438 // Redirect to next step
439 mlsimport_redirect_to_next_step($current_step);
440 }
441 break;
442
443
444 case 'field-mapping':
445 // Save field mapping template selection
446 $field_data = array(
447 'template' => isset($_POST['mlsimport_field_template']) ? $_POST['mlsimport_field_template'] : 'standard',
448 'custom_fields' => isset($_POST['mlsimport_custom_fields']) ? $_POST['mlsimport_custom_fields'] : array(),
449 );
450
451 mlsimport_save_step_data($current_step, $field_data);
452
453 // Redirect to next step
454 mlsimport_redirect_to_next_step($current_step);
455 break;
456
457 case 'import-config':
458 // Save import configuration
459 $import_data = array(
460 'import_title' => isset($_POST['mlsimport_import_title']) ? $_POST['mlsimport_import_title'] : '',
461 'property_status' => isset($_POST['mlsimport_property_status']) ? $_POST['mlsimport_property_status'] : 'publish',
462 'agent_id' => isset($_POST['mlsimport_agent_id']) ? $_POST['mlsimport_agent_id'] : '',
463 'property_user' => isset($_POST['mlsimport_property_user']) ? $_POST['mlsimport_property_user'] : '',
464 'min_price' => isset($_POST['mlsimport_min_price']) && $_POST['mlsimport_min_price'] !== ''
465 ? $_POST['mlsimport_min_price']
466 : '0',
467 'max_price' => isset($_POST['mlsimport_max_price']) && $_POST['mlsimport_max_price'] !== ''
468 ? $_POST['mlsimport_max_price']
469 : '10000000',
470 'property_cities' => isset($_POST['mlsimport_property_cities']) ? $_POST['mlsimport_property_cities'] : array(),
471 'property_types' => isset($_POST['mlsimport_property_types']) ? $_POST['mlsimport_property_types'] : array(),
472 'auto_update' => isset($_POST['mlsimport_auto_update']) ? 1 : 0,
473 );
474
475 mlsimport_save_step_data($current_step, $import_data);
476
477 // Create import item
478 $import_id = mlsimport_create_initial_import_item($import_data);
479
480 // Save the import ID
481 $user_data = get_option('mlsimport_onboarding_user_data', array());
482 $user_data['import_id'] = $import_id;
483 update_option('mlsimport_onboarding_user_data', $user_data);
484
485 // Redirect to next step
486 mlsimport_redirect_to_next_step($current_step);
487 break;
488
489 case 'test-import':
490 // Nothing to save here, just redirect to next step
491 mlsimport_redirect_to_next_step($current_step);
492 break;
493
494 case 'success':
495 // Mark onboarding as complete
496 mlsimport_mark_onboarding_complete();
497
498 // Redirect to main plugin page
499 wp_redirect(admin_url('admin.php?page=mlsimport_plugin_options'));
500 exit;
501 break;
502 }
503 }
504
505 /**
506 * Verify onboarding nonce
507 *
508 * @since 6.1.0
509 * @return bool True if nonce is valid, false otherwise
510 */
511 function mlsimport_verify_onboarding_nonce() {
512 return isset($_POST['mlsimport_onboarding_nonce']) &&
513 wp_verify_nonce($_POST['mlsimport_onboarding_nonce'], 'mlsimport_onboarding');
514 }
515
516 /**
517 * Mark onboarding as complete
518 *
519 * @since 6.1.0
520 */
521 function mlsimport_mark_onboarding_complete() {
522 update_option('mlsimport_onboarding_completed', true);
523
524 // Log completion event
525 mlsimport_log_onboarding_event('Onboarding completed successfully', 'info');
526 }
527
528 /**
529 * Render a specific onboarding step
530 *
531 * @since 6.1.0
532 * @param string $step The step ID to render
533 */
534 function mlsimport_render_onboarding_step($step) {
535 $steps = mlsimport_get_steps();
536
537 if (!isset($steps[$step])) {
538 return;
539 }
540
541 $template = $steps[$step]['template'];
542 $path = MLSIMPORT_PLUGIN_PATH . 'admin/partials/mlsimport-onboarding-steps/' . $template;
543
544 if (file_exists($path)) {
545 // Get step data
546 $step_data = mlsimport_get_onboarding_step_data($step);
547
548 // Include template
549 include $path;
550 }
551 }
552
553 /**
554 * Create the initial import item
555 *
556 * @since 6.1.0
557 * @param array $import_data The import configuration data
558 * @return int The post ID of the created import item
559 */
560 function mlsimport_create_initial_import_item($import_data) {
561 // Create post
562 $post_data = array(
563 'post_title' => !empty($import_data['import_title']) ? $import_data['import_title'] : __('Initial Import', 'mlsimport'),
564 'post_status' => 'publish',
565 'post_type' => 'mlsimport_item',
566 );
567
568 $post_id = wp_insert_post($post_data);
569
570 if (!is_wp_error($post_id)) {
571 // Set up import item defaults
572 mlsimport_setup_import_item_defaults($post_id, $import_data);
573 }
574
575 return $post_id;
576 }
577
578 /**
579 * Set up default meta values for an import item
580 *
581 * @since 6.1.0
582 * @param int $post_id The post ID of the import item
583 * @param array $import_data The import configuration data
584 * @return bool Success or failure
585 */
586 function mlsimport_setup_import_item_defaults($post_id, $import_data) {
587 // Set basic meta
588 update_post_meta($post_id, 'mlsimport_item_property_status', $import_data['property_status']);
589 update_post_meta($post_id, 'mlsimport_item_agent', $import_data['agent_id']);
590 update_post_meta($post_id, 'mlsimport_item_property_user', $import_data['property_user']);
591 update_post_meta($post_id, 'mlsimport_item_min_price', $import_data['min_price']);
592 update_post_meta($post_id, 'mlsimport_item_max_price', $import_data['max_price']);
593 update_post_meta($post_id, 'mlsimport_item_stat_cron', $import_data['auto_update']);
594
595 // Default statuses and visibility options
596 update_post_meta($post_id, 'mlsimport_item_standardstatus', array('Active'));
597 update_post_meta($post_id, 'mlsimport_item_standardstatusprotect', array('Active', 'ActiveUnderContract', 'ComingSoon', 'Pending'));
598 update_post_meta($post_id, 'mlsimport_item_internetentirelistingdisplayyn', 'yes');
599 update_post_meta($post_id, 'mlsimport_item_internetaddressdisplayyn', 'yes');
600
601 // Set title format
602 update_post_meta($post_id, 'mlsimport_item_title_format', '{Address}, {City}, {CountyOrParish}, {PropertyType}');
603
604 // Set locations
605 if (!empty($import_data['property_cities'])) {
606 update_post_meta($post_id, 'mlsimport_item_city', $import_data['property_cities']);
607 }
608
609 // Set property types
610 if (!empty($import_data['property_types'])) {
611 update_post_meta($post_id, 'mlsimport_item_propertytype', $import_data['property_types']);
612 }
613
614 // Set creation date for reference
615 update_post_meta($post_id, 'mlsimport_item_created_date', current_time('mysql'));
616
617 // Log action
618 mlsimport_log_onboarding_event(
619 sprintf('Created initial import item (ID: %d)', $post_id),
620 'info'
621 );
622
623 return true;
624 }
625
626 /**
627 * Log onboarding event
628 *
629 * @since 6.1.0
630 * @param string $message The log message
631 * @param string $type The log type (info, warning, error)
632 */
633 function mlsimport_log_onboarding_event($message, $type = 'info') {
634 // Format log message
635 $formatted_message = '[' . current_time('mysql') . '] [ONBOARDING] [' . strtoupper($type) . '] ' . $message;
636
637 // Write to plugin logs
638 mlsimport_saas_single_write_import_custom_logs($formatted_message, 'onboarding');
639 }
640
641 /**
642 * Display admin notice for incomplete onboarding
643 *
644 * @since 6.1.0
645 */
646 function mlsimport_onboarding_admin_notice() {
647 // Allow disabling the notice via constant
648 if (defined('MLSIMPORT_HIDE_SETUP_NOTICE') && MLSIMPORT_HIDE_SETUP_NOTICE) {
649 return;
650 }
651 // Only show on plugin pages
652 $screen = get_current_screen();
653 if (!$screen || strpos($screen->id, 'mlsimport') === false) {
654 return;
655 }
656
657 // Don't show on onboarding page
658 if (isset($_GET['page']) && $_GET['page'] === 'mlsimport-onboarding') {
659 return;
660 }
661
662 // Check if onboarding is complete
663 $onboarding_completed = get_option('mlsimport_onboarding_completed', false);
664 if ($onboarding_completed) {
665 return;
666 }
667
668 // Get current step
669 $current_step = get_option('mlsimport_onboarding_current_step', 'welcome');
670 $steps = mlsimport_get_steps();
671
672 // Display notice
673 ?>
674
675 <?php
676 }
677
678 /**
679 * Handle AJAX test account connection
680 *
681 * @since 6.1.0
682 */
683 function mlsimport_ajax_test_account_connection() {
684 // Check nonce
685 if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'mlsimport_onboarding_nonce')) {
686 wp_send_json_error(array('message' => __('Security check failed', 'mlsimport')));
687 }
688
689 // Get credentials
690 $username = isset($_POST['username']) ? sanitize_text_field($_POST['username']) : '';
691 $password = isset($_POST['password']) ? sanitize_text_field($_POST['password']) : '';
692
693 if (empty($username) || empty($password)) {
694 wp_send_json_error(array('message' => __('Username and password are required', 'mlsimport')));
695 }
696
697 // Save to temporary storage for test
698 $options = get_option('mlsimport_admin_options', array());
699 $options['mlsimport_username'] = $username;
700 $options['mlsimport_password'] = $password;
701 update_option('mlsimport_admin_options', $options);
702
703 // Delete token to force fresh request
704 delete_transient('mlsimport_saas_token');
705
706 // Test connection using existing methods
707 global $mlsimport;
708 $token = $mlsimport->admin->mlsimport_saas_get_mls_api_token_from_transient();
709
710 if (empty($token)) {
711 wp_send_json_error(array('message' => __('Unable to connect to MLS Import. Please check your credentials.', 'mlsimport')));
712 }
713
714 // Log success
715 mlsimport_log_onboarding_event('Successfully connected to MLS Import account', 'info');
716
717 wp_send_json_success(array('message' => __('Successfully connected to MLS Import', 'mlsimport')));
718 }
719
720 /**
721 * Handle AJAX test MLS connection
722 *
723 * @since 6.1.0
724 */
725 function mlsimport_ajax_test_mls_connection() {
726 // Check nonce
727 if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'mlsimport_onboarding_nonce')) {
728 wp_send_json_error(array('message' => __('Security check failed', 'mlsimport')));
729 }
730
731 // Get MLS info
732 $mls_id = isset($_POST['mls_id']) ? sanitize_text_field($_POST['mls_id']) : '';
733 $mls_token = isset($_POST['mls_token']) ? sanitize_text_field($_POST['mls_token']) : '';
734
735 if (empty($mls_id)) {
736 wp_send_json_error(array('message' => __('MLS selection is required', 'mlsimport')));
737 }
738
739 // Save to temporary storage for test
740 $options = get_option('mlsimport_admin_options', array());
741 $options['mlsimport_mls_name'] = $mls_id;
742 $options['mlsimport_mls_token'] = $mls_token;
743 update_option('mlsimport_admin_options', $options);
744
745 // Test connection using existing methods
746 global $mlsimport;
747 $connection_result = $mlsimport->admin->mlsimport_saas_check_mls_connection();
748 $is_connected = get_option('mlsimport_connection_test', '');
749
750 if ($is_connected !== 'yes') {
751 wp_send_json_error(array('message' => __('Unable to connect to MLS. Please check your credentials.', 'mlsimport')));
752 }
753
754 // Log success
755 mlsimport_log_onboarding_event('Successfully connected to MLS provider', 'info');
756
757 wp_send_json_success(array('message' => __('Successfully connected to MLS', 'mlsimport')));
758 }
759
760 /**
761 * Handle AJAX run test import
762 *
763 * @since 6.1.0
764 */
765 function mlsimport_ajax_run_test_import() {
766 // Check nonce
767 if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'mlsimport_onboarding_nonce')) {
768 wp_send_json_error(array('message' => __('Security check failed', 'mlsimport')));
769 }
770
771 // Get import ID
772 $user_data = get_option('mlsimport_onboarding_user_data', array());
773 $import_id = isset($user_data['import_id']) ? $user_data['import_id'] : 0;
774
775 if (empty($import_id)) {
776 wp_send_json_error(array('message' => __('No import configuration found', 'mlsimport')));
777 }
778
779 // Set a lower limit for test import
780 update_post_meta($import_id, 'mlsimport_item_how_many', 5);
781
782 // Run a limited import using the admin class methods
783 global $mlsimport;
784
785 try {
786 // Set up import parameters
787 $item_id_array = array(
788 'item_id' => $import_id,
789 'how_many' => 5,
790 'max_number' => 5,
791 'batch_counter' => 1,
792 );
793
794 // Make sure we're starting clean
795 update_option('mlsimport_force_stop_' . $import_id, 'no', false);
796 update_post_meta($import_id, 'mlsimport_attach_to_move_' . $import_id, '');
797
798 // Get listings
799 $mlsrequest = $mlsimport->admin->mlsimport_make_listing_requests($import_id);
800
801 if (!isset($mlsrequest['results']) || $mlsrequest['results'] == 0) {
802 wp_send_json_error(array('message' => __('No listings found with current configuration', 'mlsimport')));
803 }
804
805 $found_items = intval($mlsrequest['results']);
806 if ($found_items > 5) {
807 $found_items = 5;
808 }
809
810 $item_id_array['max_number'] = $found_items;
811
812 // Generate import requests
813 $attachments_to_move = (array)$mlsimport->admin->mlsimport_saas_generate_import_requests_per_item($item_id_array);
814 update_post_meta($import_id, 'mlsimport_attach_to_move_' . $import_id, $attachments_to_move);
815
816 // Prepare background process arguments
817 $attachments_to_send = array(
818 'args' => array(
819 'attachments_to_move' => $import_id,
820 'item_id_array' => $item_id_array,
821 ),
822 );
823
824 // Start background process
825 update_post_meta($import_id, 'mlsimport_spawn_status', 'started');
826 mlsimport_log_onboarding_event('Starting test import of 5 properties', 'info');
827
828 // Use the async action system instead of direct execution
829 as_enqueue_async_action('mlsimport_background_process_per_item', $attachments_to_send);
830 spawn_cron();
831
832 // Return success data without checking import count
833 wp_send_json_success(array(
834 'message' => __('Import process started', 'mlsimport'),
835 'import_id' => $import_id
836 ));
837
838
839 } catch (Exception $e) {
840 mlsimport_log_onboarding_event('Test import failed: ' . $e->getMessage(), 'error');
841 wp_send_json_error(array('message' => __('Import failed: ', 'mlsimport') . $e->getMessage()));
842 }
843 }
844
845 /**
846 * Handle AJAX save step data
847 *
848 * @since 6.1.0
849 */
850 function mlsimport_ajax_save_step_data() {
851 // Check nonce
852 if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'mlsimport_onboarding_nonce')) {
853 wp_send_json_error(array('message' => __('Security check failed', 'mlsimport')));
854 }
855
856 // Get step and data
857 $step = isset($_POST['step']) ? sanitize_text_field($_POST['step']) : '';
858 $data = isset($_POST['data']) ? $_POST['data'] : array();
859
860 if (empty($step)) {
861 wp_send_json_error(array('message' => __('No step specified', 'mlsimport')));
862 }
863
864 // Save step data
865 $result = mlsimport_save_step_data($step, $data);
866
867 if (!$result) {
868 wp_send_json_error(array('message' => __('Failed to save data', 'mlsimport')));
869 }
870
871 wp_send_json_success(array('message' => __('Data saved successfully', 'mlsimport')));
872 }
873
874 /**
875 * Save current onboarding state
876 *
877 * @since 6.1.0
878 * @param string $step_id The current step ID
879 * @param array $form_data The form data
880 * @return bool Success or failure
881 */
882 function mlsimport_save_onboarding_state($step_id, $form_data) {
883 $state = array(
884 'current_step' => $step_id,
885 'form_data' => $form_data,
886 'timestamp' => current_time('timestamp'),
887 );
888
889 return update_option('mlsimport_onboarding_state', $state);
890 }
891
892 /**
893 * Restore onboarding state
894 *
895 * @since 6.1.0
896 * @return array The saved state data
897 */
898 function mlsimport_restore_onboarding_state() {
899 return get_option('mlsimport_onboarding_state', array());
900 }
901
902 /**
903 * Clear onboarding state
904 *
905 * @since 6.1.0
906 * @return bool Success or failure
907 */
908 function mlsimport_clear_onboarding_state() {
909 return delete_option('mlsimport_onboarding_state');
910 }
911
912 /**
913 * Maybe restart wizard
914 *
915 * @since 6.1.0
916 */
917 function mlsimport_maybe_restart_wizard() {
918 if (isset($_GET['restart_wizard']) && $_GET['restart_wizard'] == 1) {
919 // Clear onboarding state
920 mlsimport_clear_onboarding_state();
921
922 // Reset current step
923 update_option('mlsimport_onboarding_current_step', '');
924
925 // Clear user data
926 delete_option('mlsimport_onboarding_user_data');
927
928 // Mark onboarding as not completed
929 update_option('mlsimport_onboarding_completed', false);
930
931 // Redirect to first step
932 wp_redirect(admin_url('admin.php?page=mlsimport-onboarding'));
933 exit;
934 }
935 }
936 add_action('admin_init', 'mlsimport_maybe_restart_wizard');
937 /**
938 * Get a template configuration based on MLS provider
939 *
940 * @since 6.1.0
941 * @param int $mls_id The MLS provider ID
942 * @return array Default settings for the specified MLS
943 */
944 function mlsimport_get_import_item_template($mls_id) {
945 // Default template
946 $template = array(
947 'title_format' => '{Address}, {City}, {CountyOrParish}, {PropertyType}',
948 'property_status' => 'publish',
949 'auto_update' => 1,
950 'standard_status' => array('Active', 'Coming Soon'),
951 'property_types' => array('Residential', 'Condo/Townhome/Row Home/Co-Op'),
952 );
953
954 // Customize based on MLS ID if needed
955 switch ($mls_id) {
956 // Add MLS-specific customizations here
957 case '111': // Example - Rae Edmonton
958 $template['standard_status'] = array('Active');
959 break;
960
961 default:
962 // Use defaults
963 break;
964 }
965
966 return $template;
967 }
968
969 /**
970 * Display a condensed log summary
971 *
972 * @since 6.1.0
973 * @param int $num_entries Number of entries to show
974 * @return string HTML output of log summary
975 */
976 function mlsimport_display_onboarding_log_summary($num_entries = 10) {
977 $path = WP_PLUGIN_DIR . '/mlsimport/logs/onboarding_logs.log';
978
979 if (!file_exists($path)) {
980 return '<div class="mlsimport-log-summary empty">' . __('No logs available', 'mlsimport') . '</div>';
981 }
982
983 // Get the last N lines
984 $lines = file($path);
985 $lines = array_slice($lines, -$num_entries);
986
987 $output = '<div class="mlsimport-log-summary">';
988 $output .= '<h4>' . __('Recent Activity', 'mlsimport') . '</h4>';
989 $output .= '<ul class="mlsimport-logs">';
990
991 foreach ($lines as $line) {
992 // Extract log type for styling
993 if (strpos($line, '[INFO]') !== false) {
994 $class = 'info';
995 } elseif (strpos($line, '[WARNING]') !== false) {
996 $class = 'warning';
997 } elseif (strpos($line, '[ERROR]') !== false) {
998 $class = 'error';
999 } else {
1000 $class = '';
1001 }
1002
1003 $output .= '<li class="log-item ' . $class . '">' . esc_html($line) . '</li>';
1004 }
1005
1006 $output .= '</ul>';
1007 $output .= '</div>';
1008
1009 return $output;
1010 }
1011
1012 /**
1013 * Register onboarding-specific log types with logging system
1014 *
1015 * @since 6.1.0
1016 */
1017 function mlsimport_register_onboarding_logs() {
1018 // Create logs directory if it doesn't exist
1019 $log_dir = WP_PLUGIN_DIR . '/mlsimport/logs';
1020 if (!file_exists($log_dir)) {
1021 mkdir($log_dir, 0755, true);
1022 }
1023
1024 // Create onboarding log file if it doesn't exist
1025 $log_file = $log_dir . '/onboarding_logs.log';
1026 if (!file_exists($log_file)) {
1027 touch($log_file);
1028 }
1029 }
1030
1031 // Initialize onboarding
1032 add_action('init', 'mlsimport_init_onboarding');
1033
1034 // Register activation hook to redirect to onboarding
1035 function mlsimport_activation_redirect() {
1036 // Set a flag so the next admin request redirects to the onboarding wizard
1037 update_option('mlsimport_do_onboarding_redirect', true);
1038 }
1039 register_activation_hook(MLSIMPORT_PLUGIN_PATH . 'mlsimport.php', 'mlsimport_activation_redirect');
1040