PluginProbe
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings / 6.0.4
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings v6.0.4
7.2.1 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 All 36 releases
mlsimport / includes / mlsimport-onboarding.php

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

1,053 lines 33.5 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 // Save user data
303 return update_option('mlsimport_onboarding_user_data', $user_data);
304 }
305
306 /**
307 * Get saved data for a specific step
308 *
309 * @since 6.1.0
310 * @param string $step The step ID
311 * @return array The step data
312 */
313 function mlsimport_get_onboarding_step_data($step) {
314 $user_data = get_option('mlsimport_onboarding_user_data', array());
315
316 if (isset($user_data[$step])) {
317 return $user_data[$step];
318 }
319
320 return array();
321 }
322
323 /**
324 * Redirect to the next step
325 *
326 * @since 6.1.0
327 * @param string $current_step The current step ID
328 */
329 function mlsimport_redirect_to_next_step($current_step) {
330 $next_step = mlsimport_get_next_step($current_step);
331
332 if ($next_step) {
333 wp_redirect(admin_url('admin.php?page=mlsimport-onboarding&step=' . $next_step));
334 exit;
335 }
336 }
337
338 /**
339 * Get the next step ID
340 *
341 * @since 6.1.0
342 * @param string $current_step The current step ID
343 * @return string|null The next step ID or null if there is no next step
344 */
345 function mlsimport_get_next_step($current_step) {
346 $steps = mlsimport_get_steps();
347 $step_keys = array_keys($steps);
348
349 $current_index = array_search($current_step, $step_keys);
350
351 if ($current_index !== false && isset($step_keys[$current_index + 1])) {
352 return $step_keys[$current_index + 1];
353 }
354
355 return null;
356 }
357
358 /**
359 * Get the previous step ID
360 *
361 * @since 6.1.0
362 * @param string $current_step The current step ID
363 * @return string|null The previous step ID or null if there is no previous step
364 */
365 function mlsimport_get_previous_step($current_step) {
366 $steps = mlsimport_get_steps();
367 $step_keys = array_keys($steps);
368
369 $current_index = array_search($current_step, $step_keys);
370
371 if ($current_index !== false && $current_index > 0) {
372 return $step_keys[$current_index - 1];
373 }
374
375 return null;
376 }
377
378 /**
379 * Handle step form submission
380 *
381 * @since 6.1.0
382 */
383 function mlsimport_handle_step_submission() {
384 // Only process on onboarding page
385 if (!isset($_GET['page']) || $_GET['page'] !== 'mlsimport-onboarding') {
386 return;
387 }
388
389 // Check if form was submitted
390 if (!isset($_POST['mlsimport_onboarding_submit'])) {
391 return;
392 }
393
394 // Verify nonce
395 if (!mlsimport_verify_onboarding_nonce()) {
396 wp_die(__('Security check failed. Please try again.', 'mlsimport'));
397 }
398
399 // Get current step
400 $current_step = mlsimport_get_current_step();
401
402 // Process based on step
403 switch ($current_step) {
404 case 'welcome':
405 // Nothing to save, just redirect to next step
406 mlsimport_redirect_to_next_step($current_step);
407 break;
408
409 case 'account':
410 // Save account information only if all required fields are filled
411 $username = isset($_POST['mlsimport_username']) ? trim($_POST['mlsimport_username']) : '';
412 $password = isset($_POST['mlsimport_password']) ? trim($_POST['mlsimport_password']) : '';
413 $mls_id = isset($_POST['mlsimport_mls_name']) ? trim($_POST['mlsimport_mls_name']) : '';
414 $token = isset($_POST['mlsimport_mls_token']) ? trim($_POST['mlsimport_mls_token']) : '';
415
416 // Only save if all fields are non-empty
417 if ($username !== '' && $password !== '' && $mls_id !== '' && $token !== '') {
418 $account_data = array(
419 'username' => $username,
420 'password' => $password,
421 'mls_id' => $mls_id,
422 'mls_token' => $token,
423 );
424
425 mlsimport_save_step_data($current_step, $account_data);
426
427 // Save to plugin options
428 $options = get_option('mlsimport_admin_options', array());
429 $options['mlsimport_username'] = $username;
430 $options['mlsimport_password'] = $password;
431 $options['mlsimport_mls_name'] = $mls_id;
432 $options['mlsimport_mls_token'] = $token;
433 update_option('mlsimport_admin_options', $options);
434
435 // Redirect to next step
436 mlsimport_redirect_to_next_step($current_step);
437 }
438 break;
439
440
441 case 'field-mapping':
442 // Save field mapping template selection
443 $field_data = array(
444 'template' => isset($_POST['mlsimport_field_template']) ? $_POST['mlsimport_field_template'] : 'standard',
445 'custom_fields' => isset($_POST['mlsimport_custom_fields']) ? $_POST['mlsimport_custom_fields'] : array(),
446 );
447
448 mlsimport_save_step_data($current_step, $field_data);
449
450 // Redirect to next step
451 mlsimport_redirect_to_next_step($current_step);
452 break;
453
454 case 'import-config':
455 // Save import configuration
456 $import_data = array(
457 'import_title' => isset($_POST['mlsimport_import_title']) ? $_POST['mlsimport_import_title'] : '',
458 'property_status' => isset($_POST['mlsimport_property_status']) ? $_POST['mlsimport_property_status'] : 'publish',
459 'agent_id' => isset($_POST['mlsimport_agent_id']) ? $_POST['mlsimport_agent_id'] : '',
460 'property_user' => isset($_POST['mlsimport_property_user']) ? $_POST['mlsimport_property_user'] : '',
461 'min_price' => isset($_POST['mlsimport_min_price']) && $_POST['mlsimport_min_price'] !== ''
462 ? $_POST['mlsimport_min_price']
463 : '0',
464 'max_price' => isset($_POST['mlsimport_max_price']) && $_POST['mlsimport_max_price'] !== ''
465 ? $_POST['mlsimport_max_price']
466 : '10000000',
467 'property_cities' => isset($_POST['mlsimport_property_cities']) ? $_POST['mlsimport_property_cities'] : array(),
468 'property_types' => isset($_POST['mlsimport_property_types']) ? $_POST['mlsimport_property_types'] : array(),
469 'auto_update' => isset($_POST['mlsimport_auto_update']) ? 1 : 0,
470 );
471
472 mlsimport_save_step_data($current_step, $import_data);
473
474 // Create import item
475 $import_id = mlsimport_create_initial_import_item($import_data);
476
477 // Save the import ID
478 $user_data = get_option('mlsimport_onboarding_user_data', array());
479 $user_data['import_id'] = $import_id;
480 update_option('mlsimport_onboarding_user_data', $user_data);
481
482 // Redirect to next step
483 mlsimport_redirect_to_next_step($current_step);
484 break;
485
486 case 'test-import':
487 // Nothing to save here, just redirect to next step
488 mlsimport_redirect_to_next_step($current_step);
489 break;
490
491 case 'success':
492 // Mark onboarding as complete
493 mlsimport_mark_onboarding_complete();
494
495 // Redirect to main plugin page
496 wp_redirect(admin_url('admin.php?page=mlsimport_plugin_options'));
497 exit;
498 break;
499 }
500 }
501
502 /**
503 * Verify onboarding nonce
504 *
505 * @since 6.1.0
506 * @return bool True if nonce is valid, false otherwise
507 */
508 function mlsimport_verify_onboarding_nonce() {
509 return isset($_POST['mlsimport_onboarding_nonce']) &&
510 wp_verify_nonce($_POST['mlsimport_onboarding_nonce'], 'mlsimport_onboarding');
511 }
512
513 /**
514 * Mark onboarding as complete
515 *
516 * @since 6.1.0
517 */
518 function mlsimport_mark_onboarding_complete() {
519 update_option('mlsimport_onboarding_completed', true);
520
521 // Log completion event
522 mlsimport_log_onboarding_event('Onboarding completed successfully', 'info');
523 }
524
525 /**
526 * Render a specific onboarding step
527 *
528 * @since 6.1.0
529 * @param string $step The step ID to render
530 */
531 function mlsimport_render_onboarding_step($step) {
532 $steps = mlsimport_get_steps();
533
534 if (!isset($steps[$step])) {
535 return;
536 }
537
538 $template = $steps[$step]['template'];
539 $path = MLSIMPORT_PLUGIN_PATH . 'admin/partials/mlsimport-onboarding-steps/' . $template;
540
541 if (file_exists($path)) {
542 // Get step data
543 $step_data = mlsimport_get_onboarding_step_data($step);
544
545 // Include template
546 include $path;
547 }
548 }
549
550 /**
551 * Create the initial import item
552 *
553 * @since 6.1.0
554 * @param array $import_data The import configuration data
555 * @return int The post ID of the created import item
556 */
557 function mlsimport_create_initial_import_item($import_data) {
558 // Create post
559 $post_data = array(
560 'post_title' => !empty($import_data['import_title']) ? $import_data['import_title'] : __('Initial Import', 'mlsimport'),
561 'post_status' => 'publish',
562 'post_type' => 'mlsimport_item',
563 );
564
565 $post_id = wp_insert_post($post_data);
566
567 if (!is_wp_error($post_id)) {
568 // Set up import item defaults
569 mlsimport_setup_import_item_defaults($post_id, $import_data);
570 }
571
572 return $post_id;
573 }
574
575 /**
576 * Set up default meta values for an import item
577 *
578 * @since 6.1.0
579 * @param int $post_id The post ID of the import item
580 * @param array $import_data The import configuration data
581 * @return bool Success or failure
582 */
583 function mlsimport_setup_import_item_defaults($post_id, $import_data) {
584 // Set basic meta
585 update_post_meta($post_id, 'mlsimport_item_property_status', $import_data['property_status']);
586 update_post_meta($post_id, 'mlsimport_item_agent', $import_data['agent_id']);
587 update_post_meta($post_id, 'mlsimport_item_property_user', $import_data['property_user']);
588 update_post_meta($post_id, 'mlsimport_item_min_price', $import_data['min_price']);
589 update_post_meta($post_id, 'mlsimport_item_max_price', $import_data['max_price']);
590 update_post_meta($post_id, 'mlsimport_item_stat_cron', $import_data['auto_update']);
591
592 // Default statuses and visibility options
593 update_post_meta($post_id, 'mlsimport_item_standardstatus', array('Active'));
594 update_post_meta(
595 $post_id,
596 'mlsimport_item_standardstatusdelete',
597 array(
598 'Active',
599 'ActiveUnderContract',
600 'Canceled',
601 'Closed',
602 'ComingSoon',
603 'Delete',
604 'Expired',
605 'Hold',
606 'Incomplete',
607 'Pending',
608 'Withdrawn'
609 )
610 );
611 update_post_meta($post_id, 'mlsimport_item_internetentirelistingdisplayyn', 'yes');
612 update_post_meta($post_id, 'mlsimport_item_internetaddressdisplayyn', 'yes');
613
614 // Set title format
615 update_post_meta($post_id, 'mlsimport_item_title_format', '{Address}, {City}, {CountyOrParish}, {PropertyType}');
616
617 // Set locations
618 if (!empty($import_data['property_cities'])) {
619 update_post_meta($post_id, 'mlsimport_item_city', $import_data['property_cities']);
620 }
621
622 // Set property types
623 if (!empty($import_data['property_types'])) {
624 update_post_meta($post_id, 'mlsimport_item_propertytype', $import_data['property_types']);
625 }
626
627 // Set creation date for reference
628 update_post_meta($post_id, 'mlsimport_item_created_date', current_time('mysql'));
629
630 // Log action
631 mlsimport_log_onboarding_event(
632 sprintf('Created initial import item (ID: %d)', $post_id),
633 'info'
634 );
635
636 return true;
637 }
638
639 /**
640 * Log onboarding event
641 *
642 * @since 6.1.0
643 * @param string $message The log message
644 * @param string $type The log type (info, warning, error)
645 */
646 function mlsimport_log_onboarding_event($message, $type = 'info') {
647 // Format log message
648 $formatted_message = '[' . current_time('mysql') . '] [ONBOARDING] [' . strtoupper($type) . '] ' . $message;
649
650 // Write to plugin logs
651 mlsimport_saas_single_write_import_custom_logs($formatted_message, 'onboarding');
652 }
653
654 /**
655 * Display admin notice for incomplete onboarding
656 *
657 * @since 6.1.0
658 */
659 function mlsimport_onboarding_admin_notice() {
660 // Allow disabling the notice via constant
661 if (defined('MLSIMPORT_HIDE_SETUP_NOTICE') && MLSIMPORT_HIDE_SETUP_NOTICE) {
662 return;
663 }
664 // Only show on plugin pages
665 $screen = get_current_screen();
666 if (!$screen || strpos($screen->id, 'mlsimport') === false) {
667 return;
668 }
669
670 // Don't show on onboarding page
671 if (isset($_GET['page']) && $_GET['page'] === 'mlsimport-onboarding') {
672 return;
673 }
674
675 // Check if onboarding is complete
676 $onboarding_completed = get_option('mlsimport_onboarding_completed', false);
677 if ($onboarding_completed) {
678 return;
679 }
680
681 // Get current step
682 $current_step = get_option('mlsimport_onboarding_current_step', 'welcome');
683 $steps = mlsimport_get_steps();
684
685 // Display notice
686 ?>
687
688 <?php
689 }
690
691 /**
692 * Handle AJAX test account connection
693 *
694 * @since 6.1.0
695 */
696 function mlsimport_ajax_test_account_connection() {
697 // Check nonce
698 if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'mlsimport_onboarding_nonce')) {
699 wp_send_json_error(array('message' => __('Security check failed', 'mlsimport')));
700 }
701
702 // Get credentials
703 $username = isset($_POST['username']) ? sanitize_text_field($_POST['username']) : '';
704 $password = isset($_POST['password']) ? sanitize_text_field($_POST['password']) : '';
705
706 if (empty($username) || empty($password)) {
707 wp_send_json_error(array('message' => __('Username and password are required', 'mlsimport')));
708 }
709
710 // Save to temporary storage for test
711 $options = get_option('mlsimport_admin_options', array());
712 $options['mlsimport_username'] = $username;
713 $options['mlsimport_password'] = $password;
714 update_option('mlsimport_admin_options', $options);
715
716 // Delete token to force fresh request
717 delete_transient('mlsimport_saas_token');
718
719 // Test connection using existing methods
720 global $mlsimport;
721 $token = $mlsimport->admin->mlsimport_saas_get_mls_api_token_from_transient();
722
723 if (empty($token)) {
724 wp_send_json_error(array('message' => __('Unable to connect to MLS Import. Please check your credentials.', 'mlsimport')));
725 }
726
727 // Log success
728 mlsimport_log_onboarding_event('Successfully connected to MLS Import account', 'info');
729
730 wp_send_json_success(array('message' => __('Successfully connected to MLS Import', 'mlsimport')));
731 }
732
733 /**
734 * Handle AJAX test MLS connection
735 *
736 * @since 6.1.0
737 */
738 function mlsimport_ajax_test_mls_connection() {
739 // Check nonce
740 if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'mlsimport_onboarding_nonce')) {
741 wp_send_json_error(array('message' => __('Security check failed', 'mlsimport')));
742 }
743
744 // Get MLS info
745 $mls_id = isset($_POST['mls_id']) ? sanitize_text_field($_POST['mls_id']) : '';
746 $mls_token = isset($_POST['mls_token']) ? sanitize_text_field($_POST['mls_token']) : '';
747
748 if (empty($mls_id)) {
749 wp_send_json_error(array('message' => __('MLS selection is required', 'mlsimport')));
750 }
751
752 // Save to temporary storage for test
753 $options = get_option('mlsimport_admin_options', array());
754 $options['mlsimport_mls_name'] = $mls_id;
755 $options['mlsimport_mls_token'] = $mls_token;
756 update_option('mlsimport_admin_options', $options);
757
758 // Test connection using existing methods
759 global $mlsimport;
760 $connection_result = $mlsimport->admin->mlsimport_saas_check_mls_connection();
761 $is_connected = get_option('mlsimport_connection_test', '');
762
763 if ($is_connected !== 'yes') {
764 wp_send_json_error(array('message' => __('Unable to connect to MLS. Please check your credentials.', 'mlsimport')));
765 }
766
767 // Log success
768 mlsimport_log_onboarding_event('Successfully connected to MLS provider', 'info');
769
770 wp_send_json_success(array('message' => __('Successfully connected to MLS', 'mlsimport')));
771 }
772
773 /**
774 * Handle AJAX run test import
775 *
776 * @since 6.1.0
777 */
778 function mlsimport_ajax_run_test_import() {
779 // Check nonce
780 if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'mlsimport_onboarding_nonce')) {
781 wp_send_json_error(array('message' => __('Security check failed', 'mlsimport')));
782 }
783
784 // Get import ID
785 $user_data = get_option('mlsimport_onboarding_user_data', array());
786 $import_id = isset($user_data['import_id']) ? $user_data['import_id'] : 0;
787
788 if (empty($import_id)) {
789 wp_send_json_error(array('message' => __('No import configuration found', 'mlsimport')));
790 }
791
792 // Set a lower limit for test import
793 update_post_meta($import_id, 'mlsimport_item_how_many', 5);
794
795 // Run a limited import using the admin class methods
796 global $mlsimport;
797
798 try {
799 // Set up import parameters
800 $item_id_array = array(
801 'item_id' => $import_id,
802 'how_many' => 5,
803 'max_number' => 5,
804 'batch_counter' => 1,
805 );
806
807 // Make sure we're starting clean
808 update_option('mlsimport_force_stop_' . $import_id, 'no', false);
809 update_post_meta($import_id, 'mlsimport_attach_to_move_' . $import_id, '');
810
811 // Get listings
812 $mlsrequest = $mlsimport->admin->mlsimport_make_listing_requests($import_id);
813
814 if (!isset($mlsrequest['results']) || $mlsrequest['results'] == 0) {
815 wp_send_json_error(array('message' => __('No listings found with current configuration', 'mlsimport')));
816 }
817
818 $found_items = intval($mlsrequest['results']);
819 if ($found_items > 5) {
820 $found_items = 5;
821 }
822
823 $item_id_array['max_number'] = $found_items;
824
825 // Generate import requests
826 $attachments_to_move = (array)$mlsimport->admin->mlsimport_saas_generate_import_requests_per_item($item_id_array);
827 update_post_meta($import_id, 'mlsimport_attach_to_move_' . $import_id, $attachments_to_move);
828
829 // Prepare background process arguments
830 $attachments_to_send = array(
831 'args' => array(
832 'attachments_to_move' => $import_id,
833 'item_id_array' => $item_id_array,
834 ),
835 );
836
837 // Start background process
838 update_post_meta($import_id, 'mlsimport_spawn_status', 'started');
839 mlsimport_log_onboarding_event('Starting test import of 5 properties', 'info');
840
841 // Use the async action system instead of direct execution
842 as_enqueue_async_action('mlsimport_background_process_per_item', $attachments_to_send);
843 spawn_cron();
844
845 // Return success data without checking import count
846 wp_send_json_success(array(
847 'message' => __('Import process started', 'mlsimport'),
848 'import_id' => $import_id
849 ));
850
851
852 } catch (Exception $e) {
853 mlsimport_log_onboarding_event('Test import failed: ' . $e->getMessage(), 'error');
854 wp_send_json_error(array('message' => __('Import failed: ', 'mlsimport') . $e->getMessage()));
855 }
856 }
857
858 /**
859 * Handle AJAX save step data
860 *
861 * @since 6.1.0
862 */
863 function mlsimport_ajax_save_step_data() {
864 // Check nonce
865 if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'mlsimport_onboarding_nonce')) {
866 wp_send_json_error(array('message' => __('Security check failed', 'mlsimport')));
867 }
868
869 // Get step and data
870 $step = isset($_POST['step']) ? sanitize_text_field($_POST['step']) : '';
871 $data = isset($_POST['data']) ? $_POST['data'] : array();
872
873 if (empty($step)) {
874 wp_send_json_error(array('message' => __('No step specified', 'mlsimport')));
875 }
876
877 // Save step data
878 $result = mlsimport_save_step_data($step, $data);
879
880 if (!$result) {
881 wp_send_json_error(array('message' => __('Failed to save data', 'mlsimport')));
882 }
883
884 wp_send_json_success(array('message' => __('Data saved successfully', 'mlsimport')));
885 }
886
887 /**
888 * Save current onboarding state
889 *
890 * @since 6.1.0
891 * @param string $step_id The current step ID
892 * @param array $form_data The form data
893 * @return bool Success or failure
894 */
895 function mlsimport_save_onboarding_state($step_id, $form_data) {
896 $state = array(
897 'current_step' => $step_id,
898 'form_data' => $form_data,
899 'timestamp' => current_time('timestamp'),
900 );
901
902 return update_option('mlsimport_onboarding_state', $state);
903 }
904
905 /**
906 * Restore onboarding state
907 *
908 * @since 6.1.0
909 * @return array The saved state data
910 */
911 function mlsimport_restore_onboarding_state() {
912 return get_option('mlsimport_onboarding_state', array());
913 }
914
915 /**
916 * Clear onboarding state
917 *
918 * @since 6.1.0
919 * @return bool Success or failure
920 */
921 function mlsimport_clear_onboarding_state() {
922 return delete_option('mlsimport_onboarding_state');
923 }
924
925 /**
926 * Maybe restart wizard
927 *
928 * @since 6.1.0
929 */
930 function mlsimport_maybe_restart_wizard() {
931 if (isset($_GET['restart_wizard']) && $_GET['restart_wizard'] == 1) {
932 // Clear onboarding state
933 mlsimport_clear_onboarding_state();
934
935 // Reset current step
936 update_option('mlsimport_onboarding_current_step', '');
937
938 // Clear user data
939 delete_option('mlsimport_onboarding_user_data');
940
941 // Mark onboarding as not completed
942 update_option('mlsimport_onboarding_completed', false);
943
944 // Redirect to first step
945 wp_redirect(admin_url('admin.php?page=mlsimport-onboarding'));
946 exit;
947 }
948 }
949 add_action('admin_init', 'mlsimport_maybe_restart_wizard');
950 /**
951 * Get a template configuration based on MLS provider
952 *
953 * @since 6.1.0
954 * @param int $mls_id The MLS provider ID
955 * @return array Default settings for the specified MLS
956 */
957 function mlsimport_get_import_item_template($mls_id) {
958 // Default template
959 $template = array(
960 'title_format' => '{Address}, {City}, {CountyOrParish}, {PropertyType}',
961 'property_status' => 'publish',
962 'auto_update' => 1,
963 'standard_status' => array('Active', 'Coming Soon'),
964 'property_types' => array('Residential', 'Condo/Townhome/Row Home/Co-Op'),
965 );
966
967 // Customize based on MLS ID if needed
968 switch ($mls_id) {
969 // Add MLS-specific customizations here
970 case '111': // Example - Rae Edmonton
971 $template['standard_status'] = array('Active');
972 break;
973
974 default:
975 // Use defaults
976 break;
977 }
978
979 return $template;
980 }
981
982 /**
983 * Display a condensed log summary
984 *
985 * @since 6.1.0
986 * @param int $num_entries Number of entries to show
987 * @return string HTML output of log summary
988 */
989 function mlsimport_display_onboarding_log_summary($num_entries = 10) {
990 $path = WP_PLUGIN_DIR . '/mlsimport/logs/onboarding_logs.log';
991
992 if (!file_exists($path)) {
993 return '<div class="mlsimport-log-summary empty">' . __('No logs available', 'mlsimport') . '</div>';
994 }
995
996 // Get the last N lines
997 $lines = file($path);
998 $lines = array_slice($lines, -$num_entries);
999
1000 $output = '<div class="mlsimport-log-summary">';
1001 $output .= '<h4>' . __('Recent Activity', 'mlsimport') . '</h4>';
1002 $output .= '<ul class="mlsimport-logs">';
1003
1004 foreach ($lines as $line) {
1005 // Extract log type for styling
1006 if (strpos($line, '[INFO]') !== false) {
1007 $class = 'info';
1008 } elseif (strpos($line, '[WARNING]') !== false) {
1009 $class = 'warning';
1010 } elseif (strpos($line, '[ERROR]') !== false) {
1011 $class = 'error';
1012 } else {
1013 $class = '';
1014 }
1015
1016 $output .= '<li class="log-item ' . $class . '">' . esc_html($line) . '</li>';
1017 }
1018
1019 $output .= '</ul>';
1020 $output .= '</div>';
1021
1022 return $output;
1023 }
1024
1025 /**
1026 * Register onboarding-specific log types with logging system
1027 *
1028 * @since 6.1.0
1029 */
1030 function mlsimport_register_onboarding_logs() {
1031 // Create logs directory if it doesn't exist
1032 $log_dir = WP_PLUGIN_DIR . '/mlsimport/logs';
1033 if (!file_exists($log_dir)) {
1034 mkdir($log_dir, 0755, true);
1035 }
1036
1037 // Create onboarding log file if it doesn't exist
1038 $log_file = $log_dir . '/onboarding_logs.log';
1039 if (!file_exists($log_file)) {
1040 touch($log_file);
1041 }
1042 }
1043
1044 // Initialize onboarding
1045 add_action('init', 'mlsimport_init_onboarding');
1046
1047 // Register activation hook to redirect to onboarding
1048 function mlsimport_activation_redirect() {
1049 // Set a flag so the next admin request redirects to the onboarding wizard
1050 update_option('mlsimport_do_onboarding_redirect', true);
1051 }
1052 register_activation_hook(MLSIMPORT_PLUGIN_PATH . 'mlsimport.php', 'mlsimport_activation_redirect');
1053