PluginProbe
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings / 6.3.3
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings v6.3.3
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 / mlsimport.php

mlsimport.php in MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings 6.3.3, at mlsimport.php

647 lines 21.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: MlsImport
4 * Plugin URI: https://mlsimport.com/
5 * Description: MLS Import - The MLSImport plugin facilitates the connection to your real estate MLS database, allowing you to download and synchronize real estate property data from the MLS.
6 * Version: 6.3.3
7 * Requires at least: 5.2
8 * Requires PHP: 7.4
9 * License: GPLv3
10 * License URI: https://www.gnu.org/licenses/gpl-3.0.html
11 * Author: MlsImport
12 * Text Domain: mlsimport
13 * Domain Path: /languages
14 */
15
16 // If this file is called directly, abort.
17
18 if ( ! defined( 'WPINC' ) ) {
19 die;
20 }
21
22
23 define( 'MLSIMPORT_VERSION', '6.3.3');
24 define( 'MLSIMPORT_CLUBLINK', 'mlsimport.com' );
25 define( 'MLSIMPORT_CLUBLINKSSL', 'https' );
26 define( 'MLSIMPORT_CRON_STEP', 20 );
27 define( 'MLSIMPORT_PLUGIN_PATH', plugin_dir_path( __FILE__ ) );
28 define( 'MLSIMPORT_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
29
30
31 //define( 'MLSIMPORT_API_URL', 'https://requests.mlsimport.com/' );
32 //define( 'MLSIMPORT_API_URL', 'https://pyjzsilw7b.execute-api.us-east-1.amazonaws.com/dev/' );
33 define( 'MLSIMPORT_API_URL', 'https://srky9ddikl.execute-api.us-east-1.amazonaws.com/blue/');
34
35
36
37
38
39
40 if ( ! defined( 'MLSIMPORT_HIDE_SETUP_NOTICE' ) ) {
41 define( 'MLSIMPORT_HIDE_SETUP_NOTICE', false );
42 }
43
44
45
46 /**
47 * The code that runs during plugin activation.
48 * This action is documented in includes/class-mlsimport-activator.php
49 */
50 function mlsimport_activate() {
51 require_once plugin_dir_path( __FILE__ ) . 'includes/class-mlsimport-activator.php';
52 Mlsimport_Activator::activate();
53 mlsimport_telemetry_set_once( 'installed_at', time() );
54 }
55
56
57
58 /**
59 * The code that runs during plugin deactivation.
60 * This action is documented in includes/class-mlsimport-deactivator.php
61 */
62 function mlsimport_deactivate() {
63 require_once plugin_dir_path( __FILE__ ) . 'includes/class-mlsimport-deactivator.php';
64 wp_clear_scheduled_hook( 'event_mls_import_auto' );
65 wp_clear_scheduled_hook( 'mlsimport_reconciliation_event' );
66 wp_clear_scheduled_hook( 'mlsimport_daily_telemetry_event' );
67 Mlsimport_Deactivator::deactivate();
68 }
69
70
71
72 register_activation_hook( __FILE__, 'mlsimport_activate' );
73 register_deactivation_hook( __FILE__, 'mlsimport_deactivate' );
74
75 /**
76 * Show one-time modal about the switch from Delete Statuses to Protected Statuses.
77 */
78 add_action( 'admin_footer', 'mlsimport_protected_statuses_upgrade_modal' );
79 function mlsimport_protected_statuses_upgrade_modal() {
80 if ( get_option( 'mlsimport_dismiss_protected_status_notice' ) ) {
81 return;
82 }
83 // Only show for sites that had a version before 6.2 (not fresh installs)
84 $show_modal = get_option( 'mlsimport_show_protected_status_modal' );
85 if ( ! $show_modal ) {
86 return;
87 }
88 $nonce = wp_create_nonce( 'mlsimport_dismiss_protected_notice' );
89 $import_tasks_url = admin_url( 'edit.php?post_type=mlsimport_item' );
90 ?>
91 <div id="mlsimport-protected-status-modal" style="position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);z-index:999999;display:flex;align-items:center;justify-content:center;">
92 <div style="background:#fff;max-width:520px;width:90%;border-radius:8px;padding:30px;box-shadow:0 4px 20px rgba(0,0,0,0.3);">
93 <h2 style="margin-top:0;color:#d63638;">MLSImport - Important Change</h2>
94 <p><strong>"Delete Statuses"</strong> have been removed. The plugin now uses <strong>Protected Statuses</strong> only.</p>
95 <p>Properties with a Protected Status will be kept during reconciliation. All other properties no longer found in MLS <strong>will be deleted</strong>.</p>
96 <p style="background:#fff3cd;border-left:4px solid #dba617;padding:10px 14px;"><strong>Action required:</strong> Go to each of your <a href="<?php echo esc_url( $import_tasks_url ); ?>">Import Tasks</a> and set the Protected Statuses field to the statuses you want to keep (e.g. Active, Pending, Coming Soon).</p>
97 <button id="mlsimport-acknowledge-btn" class="button button-primary" style="margin-top:10px;font-size:14px;padding:6px 24px;">I acknowledge</button>
98 </div>
99 </div>
100 <script>
101 document.getElementById('mlsimport-acknowledge-btn').addEventListener('click', function() {
102 var btn = this;
103 btn.disabled = true;
104 btn.textContent = 'Saving...';
105 var xhr = new XMLHttpRequest();
106 xhr.open('POST', ajaxurl);
107 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
108 xhr.onload = function() {
109 document.getElementById('mlsimport-protected-status-modal').style.display = 'none';
110 };
111 xhr.send('action=mlsimport_dismiss_protected_notice&_wpnonce=<?php echo esc_js( $nonce ); ?>');
112 });
113 </script>
114 <?php
115 }
116 add_action( 'wp_ajax_mlsimport_dismiss_protected_notice', 'mlsimport_handle_dismiss_protected_notice' );
117 function mlsimport_handle_dismiss_protected_notice() {
118 check_ajax_referer( 'mlsimport_dismiss_protected_notice' );
119 update_option( 'mlsimport_dismiss_protected_status_notice', true );
120 delete_option( 'mlsimport_show_protected_status_modal' );
121 wp_send_json_success();
122 }
123
124 /**
125 * Track installed version and flag upgrade modals.
126 * Fresh installs get current version immediately, so no upgrade modal.
127 * Upgrades from < 6.2 flag the protected status modal.
128 */
129 $mlsimport_prev_version = get_option( 'mlsimport_installed_version', '' );
130 if ( $mlsimport_prev_version !== MLSIMPORT_VERSION ) {
131 if ( ! empty( $mlsimport_prev_version ) && version_compare( $mlsimport_prev_version, '6.2', '<' ) ) {
132 update_option( 'mlsimport_show_protected_status_modal', true );
133 }
134 update_option( 'mlsimport_installed_version', MLSIMPORT_VERSION );
135 }
136
137 /**
138 * The core plugin class that is used to define internationalization,
139 * admin-specific hooks, and public-facing site hooks.
140 */
141
142 require 'vendor/autoload.php';
143 require_once plugin_dir_path( __FILE__ ) . 'includes/help_functions.php';
144 require_once plugin_dir_path( __FILE__ ) . 'includes/class-mlsimport.php';
145 require_once plugin_dir_path( __FILE__ ) . 'includes/ThemeImport.php';
146 require_once plugin_dir_path( __FILE__ ) . 'enviroment/ResidenceClass.php';
147 require_once plugin_dir_path( __FILE__ ) . 'enviroment/EstateClass.php';
148 require_once plugin_dir_path( __FILE__ ) . 'enviroment/HouzezClass.php';
149 require_once plugin_dir_path( __FILE__ ) . 'enviroment/RealHomesClass.php';
150 require_once plugin_dir_path( __FILE__ ) . 'enviroment/ResoBase.php';
151 require_once plugin_dir_path( __FILE__ ) . 'enviroment/SparkResoClass.php';
152 require_once plugin_dir_path( __FILE__ ) . 'enviroment/BridgeResoClass.php';
153 require_once plugin_dir_path( __FILE__ ) . 'enviroment/TresleResoClass.php';
154 require_once plugin_dir_path( __FILE__ ) . 'enviroment/MlsgridResoClass.php';
155 require_once plugin_dir_path( __FILE__ ) . 'enviroment/MlsgridResoClass.php';
156 require_once plugin_dir_path( __FILE__ ) . 'includes/addons/agents_offices.php';
157 require_once plugin_dir_path( __FILE__ ) . 'includes/mlsimport-onboarding.php';
158
159 require_once plugin_dir_path( __FILE__ ) . 'includes/mlsimport-field-selector-functions.php';
160 require_once plugin_dir_path( __FILE__ ) . 'includes/mlsimport-progressive-save.php';
161 require_once plugin_dir_path( __FILE__ ) . 'includes/mlsimport-telemetry.php';
162 require_once plugin_dir_path( __FILE__ ) . 'includes/mlsimport-activity-log.php';
163
164 if ( ! wp_next_scheduled( 'event_mls_import_auto' ) ) {
165 wp_schedule_event( time(), 'hourly', 'event_mls_import_auto' );
166 }
167
168
169 /**
170 * Scheduled event: Processes MLSimport items marked for cron processing, in memory-safe batches.
171 *
172 * This function is triggered by the 'event_mls_import_auto' action.
173 * It fetches mlsimport_item post IDs in small batches (not all at once!) to minimize memory usage.
174 * Only posts with meta 'mlsimport_item_stat_cron' = 1 are processed.
175 * For each item, calls mlsimport_saas_start_cron_links_per_item().
176 *
177 * Optimizations:
178 * - Uses 'fields' => 'ids' so only post IDs are loaded (saves memory)
179 * - Batches with posts_per_page/paged, so memory does not spike for large data sets
180 * - Calls gc_collect_cycles() periodically to further reduce memory leaks
181 * - Skips processing if MLS is not connected or token is missing
182 *
183 * @return void
184 */
185 add_action('event_mls_import_auto', 'mlsimport_saas_event_mls_import_auto_function');
186 /**
187 * Scheduled event handler for MLS Import Auto (runs via WP Cron).
188 * Processes mlsimport_item posts in batches and logs memory usage.
189 */
190 function mlsimport_saas_event_mls_import_auto_function() {
191 global $mlsimport;
192
193 //error_log('[AutoCron] Start: ' . (memory_get_usage(true) / 1024 / 1024) . ' MB');
194
195 // 1. Get the API token from transient - exit if not set
196 $token = $mlsimport->admin->mlsimport_saas_get_mls_api_token_from_transient();
197 //error_log('[AutoCron] After token fetch: ' . (memory_get_usage(true) / 1024 / 1024) . ' MB');
198 if (trim($token) === '') {
199 //error_log('[AutoCron] No token, exiting.');
200 return;
201 }
202
203 // 2. Check if MLS connection is valid - exit if not
204 $is_mls_connected = get_option('mlsimport_connection_test', '');
205 //error_log('[AutoCron] After connection check: ' . (memory_get_usage(true) / 1024 / 1024) . ' MB');
206 if ('yes' !== $is_mls_connected) {
207 //error_log('[AutoCron] No valid connection, exiting.');
208 return;
209 }
210
211 // Record sync attempt in telemetry
212 mlsimport_telemetry_bump( 'syncs' );
213 mlsimport_telemetry_set( 'last_sync_attempt', time() );
214
215 // 3. Set batch size for processing and initialize loop variables
216 $batch_size = 100;
217 $paged = 1;
218 $total_processed = 0;
219
220 // 4. Process in batches until no more items are found
221 do {
222 // Prepare query: only IDs, filter by meta key, batch, paged, no_found_rows speeds up query
223 $args = array(
224 'post_type' => 'mlsimport_item',
225 'post_status' => 'any',
226 'posts_per_page' => $batch_size,
227 'paged' => $paged,
228 'fields' => 'ids',
229 'meta_query' => array(
230 array(
231 'key' => 'mlsimport_item_stat_cron',
232 'value' => 1,
233 'compare' => '=',
234 ),
235 ),
236 'no_found_rows' => true,
237 );
238
239 // Get post IDs for this batch
240 $post_ids = get_posts($args);
241 //error_log("[AutoCron] Batch {$paged} fetched " . count($post_ids) . " items, memory: " . (memory_get_usage(true) / 1024 / 1024) . ' MB');
242
243 // If nothing is returned, break the loop
244 if (empty($post_ids)) {
245 break;
246 }
247
248 // 5. Loop through each post ID in this batch
249 foreach ($post_ids as $prop_id) {
250 $logs = 'Loop custom post: ' . $prop_id . PHP_EOL;
251 mlsimport_debuglogs_per_plugin($logs);
252
253 // Call processing function for this item. The feed count it pulls
254 // is recorded inside mlsimport_make_listing_requests() (last_feed_found).
255 $mlsimport->admin->mlsimport_saas_start_cron_links_per_item($prop_id);
256
257 $total_processed++;
258
259 // Free memory every 100 processed items
260 if ($total_processed % 100 === 0) {
261 gc_collect_cycles();
262 //error_log("[AutoCron] Processed {$total_processed} total, memory: " . (memory_get_usage(true) / 1024 / 1024) . ' MB');
263 }
264 }
265
266 // 6. Prepare next batch
267 $paged++;
268 unset($post_ids); // Free memory
269 gc_collect_cycles(); // Trigger garbage collection
270 //error_log("[AutoCron] After batch {$paged}, memory: " . (memory_get_usage(true) / 1024 / 1024) . ' MB');
271
272 } while (true);
273
274 mlsimport_telemetry_set( 'last_sync_success', time() );
275
276 //error_log('[AutoCron] Done, total processed: ' . $total_processed . ', end memory: ' . (memory_get_usage(true) / 1024 / 1024) . ' MB');
277 }
278
279
280
281 /*
282 * Reconciliation Mechanism
283 *
284 *
285 *
286 **/
287
288 if ( ! wp_next_scheduled( 'mlsimport_reconciliation_event' ) ) {
289 wp_schedule_event( time(), 'daily', 'mlsimport_reconciliation_event' );
290 }
291
292 add_action( 'mlsimport_reconciliation_event', 'mlsimport_saas_reconciliation_event_function' );
293
294 if ( ! wp_next_scheduled( 'mlsimport_daily_telemetry_event' ) ) {
295 wp_schedule_event( time(), 'daily', 'mlsimport_daily_telemetry_event' );
296 }
297
298 add_action( 'mlsimport_daily_telemetry_event', 'mlsimport_telemetry_run_daily' );
299
300
301 /*
302 * Force use of transient
303 *
304 *
305 *
306 **/
307
308 function mlsimport_force_use_transient( $value ) {
309 return $value;
310 // return false;
311 }
312
313
314
315
316 global $mlsimport;
317 $mlsimport = new Mlsimport();
318 $mlsimport->run();
319
320
321
322
323
324 $supported_theme = array(
325 991 => 'WpResidence',
326 992 => 'Houzez',
327 993 => 'Real Homes',
328 994 => 'Wpestate',
329
330 );
331
332 define( 'MLSIMPORT_THEME', $supported_theme );
333
334 add_filter( 'action_scheduler_failure_period', 'mlsimport_saas_filter_timelimit' );
335 function mlsimport_saas_filter_timelimit( $time_limit ) {
336 return 3000;
337 }
338
339
340
341 /*
342 *
343 * Write logs
344 *
345 **/
346
347 function mlsimport_saas_single_write_import_custom_logs( $message, $tip_import = 'normal' ) {
348 // Check if logging is enabled
349 $enable_logs = intval( get_option( 'mlsimport_disable_logs' ) );
350 if ( 1 !== $enable_logs) {
351 return;
352 }
353
354 if ( is_array( $message ) ) {
355 $message = wp_json_encode( $message );
356 }
357
358 $formatted_message = gmdate( 'F j, Y, g:i a' ) . ' -> ' . $message;
359
360 // Determine the log file path based on the import type
361 $log_file_name = 'cron' === $tip_import ? 'cron_logs' :
362 ( 'delete' === $tip_import ? 'delete_logs' :
363 ( 'server_cron' === $tip_import ? 'server_cron_logs' : 'import_logs' ) );
364
365 // Construct the full path with a date suffix
366 $log_file_path = WP_PLUGIN_DIR . "/mlsimport/logs/{$log_file_name}-" . gmdate( 'Y-m-d' ) . '.log';
367
368 // Error handling for file operations
369 try {
370 // Check and create the directory for logs if it does not exist
371 $log_dir = dirname( $log_file_path );
372 if ( ! file_exists( $log_dir ) ) {
373 mkdir( $log_dir, 0755, true );
374 }
375
376 // Append the formatted message to the log file
377 file_put_contents( $log_file_path, $formatted_message, FILE_APPEND | LOCK_EX );
378 } catch ( Exception $e ) {
379 // Handle the exception, such as logging the error elsewhere or sending a notification
380 }
381 }
382
383
384
385 /*
386 *
387 *
388 * Write Status logs
389 *
390 *
391 **/
392
393
394
395 function mlsimport_debuglogs_per_plugin_old( $message ) {
396
397 if ( is_array( $message ) ) {
398 $message = wp_json_encode( $message );
399 }
400
401 global $wp_filesystem;
402 if ( empty( $wp_filesystem ) ) {
403 require_once ABSPATH . '/wp-admin/includes/file.php';
404 WP_Filesystem();
405 }
406
407 $path_status = WP_PLUGIN_DIR . '/mlsimport/logs/status_logs.log';
408 file_put_contents( $path_status, $message, LOCK_EX );
409 }
410 function mlsimport_debuglogs_per_plugin( $message ) {
411
412 if ( is_array( $message ) ) {
413 $message = wp_json_encode( $message );
414 }
415
416 if ( empty( $message ) ) {
417 return; // Exit the function if there's nothing to log
418 }
419
420 $log_file_path = WP_PLUGIN_DIR . '/mlsimport/logs/status_logs.log';
421
422 // Check and create the directory for logs if it does not exist
423 $log_dir = dirname( $log_file_path );
424 if ( ! file_exists( $log_dir ) ) {
425 mkdir( $log_dir, 0755, true );
426 }
427
428 // Error handling for file operations
429 try {
430 // Append the message to the log file with a newline and acquire an exclusive lock during writing
431 file_put_contents( $log_file_path, $message . PHP_EOL, LOCK_EX );
432 } catch ( Exception $e ) {
433 // Handle the exception, such as logging the error elsewhere or sending a notification
434 }
435 }
436
437
438
439
440
441 /*
442 * Cron job trigger
443 *
444 *
445 *
446 **/
447
448
449 // */5 * * * * wget http://example.com/check */2
450 add_action( 'init', 'mlsimport_trigger_cron_job' );
451 function mlsimport_trigger_cron_job() {
452 // ?mlsimport_cron=yes
453 if ( isset( $_REQUEST['mlsimport_cron'] ) && 'yes' === sanitize_text_field( wp_unslash( $_REQUEST['mlsimport_cron'] ) ) ) {
454 $last_run = intval( get_option( 'mlsimport_last_server_cron' ) );
455 $now = time();
456 if ( 0 === intval($last_run) ) {
457 update_option( 'mlsimport_last_server_cron', $now );
458 }
459
460 if ( $last_run < $now - ( 60 * 60 * 2 ) ) {
461 $log = 'Server Cron Job triggered on ' . date( 'l jS \of F Y h:i:s A', $last_run ) . ' vs ' . gmdate( 'l jS \of F Y h:i:s A', $now ) . PHP_EOL;
462 // mlsimport_saas_event_mls_import_auto_function();
463 update_option( 'mlsimport_last_server_cron', $now );
464 } else {
465 $log = 'Server Cron Job Called but not triggered. Last run on ' . gmdate( 'l jS \of F Y h:i:s A', $last_run ) . ' vs ' . gmdate( 'l jS \of F Y h:i:s A', $now ) . PHP_EOL;
466 }
467
468 mlsimport_saas_single_write_import_custom_logs( $log, 'server_cron' );
469 }
470 }
471
472
473
474 function mlsimport_show_signup() {
475 $affiliate_url = 'https://mlsimport.com';
476 if ( function_exists( 'wp_estate_init' ) ) {
477 $affiliate_url = 'https://mlsimport.com/ref/1/?campaign=wpresidence';
478 }
479 ?>
480 <div class="mlsimport_signup">
481 <h3><?php esc_html_e('Import MLS Listings into your Real Estate website', 'mlsimport'); ?></h3>
482 <p><?php esc_html_e('Signup now and get 30-Days Free trial, no setup fee & cancel anytime at ', 'mlsimport'); ?><a href="https://mlsimport.com/mls-import-plugin-pricing/" target="_blank">MLSImport.com</a></p>
483 <a href="https://mlsimport.com/mls-import-plugin-pricing" class="button mlsimport_button mlsimport_signup_button" target="_blank"><?php esc_html_e('Create My Account', 'mlsimport'); ?></a>
484 </div>
485 <?php
486 }
487
488
489 //add_action('admin_init', 'force_recount_all_terms');
490 function force_recount_all_terms() {
491 global $wpdb;
492
493 // Get all taxonomies
494 $taxonomies = get_taxonomies([], 'names');
495
496 foreach ($taxonomies as $taxonomy) {
497 // Get all terms for the taxonomy
498 $terms = get_terms([
499 'taxonomy' => $taxonomy,
500 'hide_empty' => false, // Include terms with 0 count
501 'fields' => 'ids', // Get only the term IDs
502 ]);
503
504 if (!is_wp_error($terms) && !empty($terms)) {
505 // Get term_taxonomy_ids for these terms
506 $term_taxonomy_ids = $wpdb->get_col($wpdb->prepare(
507 "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE term_id IN (" . implode(',', array_map('intval', $terms)) . ")"
508 ));
509
510 // Update term counts
511 if (!empty($term_taxonomy_ids)) {
512 wp_update_term_count_now($term_taxonomy_ids, $taxonomy);
513 }
514 }
515 }
516
517 echo "Term counts have been recalculated for all taxonomies.";
518 }
519
520
521 /*
522 *
523 * create dropdown list
524 *
525 *
526 */
527 function mlsiport_mls_select_list( $key, $value, $data_array ) {
528 $select = '<select class="mlsimport-2025-select" id="' . esc_attr( $key ) . '" name="mlsimport_admin_options[' . $key . ']">';
529 if ( is_array( $data_array ) ) :
530 foreach ( $data_array as $key => $mls_item ) {
531 $select .= '<option value="' .esc_attr( $key ). '"';
532 if ( intval( $value ) === intval( $key ) ) {
533 $select .= ' selected ';
534 }
535 $select .= '>' .esc_html( $mls_item ). '</option>';
536 }
537 endif;
538 $select .= '</select>';
539 return $select;
540 }
541
542
543
544 add_action('wp_ajax_mlsimport_save_account', 'mlsimport_save_account_callback');
545 function mlsimport_save_account_callback() {
546 check_ajax_referer('mlsimport_onboarding_nonce', 'security');
547
548 $options = get_option('mlsimport_admin_options', []);
549 if ( ! empty($_POST['mlsimport_username']) && ! empty($_POST['mlsimport_password']) ) {
550 $options['mlsimport_username'] = sanitize_text_field($_POST['mlsimport_username']);
551 $options['mlsimport_password'] = sanitize_text_field($_POST['mlsimport_password']);
552 update_option('mlsimport_admin_options', $options);
553 }
554
555 global $mlsimport;
556
557 // Refresh token
558 $token = $mlsimport->admin->mlsimport_saas_get_mls_api_token_from_transient();
559
560 if (trim($token) === '') {
561 ob_start();
562
563 ?>
564 <div class="mlsimport_warning">
565 <?php esc_html_e('You are not connected to MlsImport - Please check your Username and Password.', 'mlsimport'); ?>
566 </div>
567 <?php
568 $html = ob_get_clean();
569
570 wp_send_json_success([
571 'message' => __('You are not connected.', 'mlsimport'),
572 'html' => $html,
573 'connected' => false
574 ]);
575 } else {
576 ob_start();
577 ?>
578 <div class="mlsimport_warning mlsimport_validated">
579 <?php esc_html_e('You are connected to your MlsImport account!', 'mlsimport'); ?>
580 </div>
581 <?php
582 $html = ob_get_clean();
583
584 wp_send_json_success([
585 'message' => __('Connected successfully!', 'mlsimport'),
586 'html' => $html,
587 'connected' => true
588 ]);
589 }
590 }
591
592
593
594
595
596
597
598
599 add_action('wp_ajax_mlsimport_save_mls_data', 'mlsimport_save_mls_data_callback');
600 function mlsimport_save_mls_data_callback() {
601 check_ajax_referer('mlsimport_onboarding_nonce', 'security');
602
603 $options = get_option('mlsimport_admin_options', []);
604
605 foreach ($_POST as $key => $value) {
606 if (strpos($key, 'mlsimport_') === 0 && $key !== 'mlsimport_username' && $key !== 'mlsimport_password') {
607 $options[$key] = sanitize_text_field($value);
608 }
609 }
610
611 update_option('mlsimport_admin_options', $options);
612
613 // Run MLS connection check
614 global $mlsimport;
615 $is_mls_connected = get_option('mlsimport_connection_test', '');
616 $mlsimport->admin->mlsimport_saas_setting_up();
617
618 if ('yes' !== $is_mls_connected) {
619 $mlsimport->admin->mlsimport_saas_check_mls_connection();
620 $is_mls_connected = get_option('mlsimport_connection_test', '');
621 }
622
623 ob_start();
624 if ('yes' === $is_mls_connected) {
625 ?>
626 <div class="mlsimport_warning mlsimport_validated">
627 <?php esc_html_e('You’re now connected to your MLS.', 'mlsimport'); ?>
628 </div>
629 <?php
630 } else {
631 ?>
632 <div class="mlsimport_warning">
633 <?php esc_html_e('The connection to your MLS was NOT successful. Please check the authentication token is correct and check your MLS Data Access Application is approved.', 'mlsimport'); ?>
634 </div>
635 <?php
636 }
637 $html = ob_get_clean();
638
639 wp_send_json_success([
640 'message' => __('MLS data saved', 'mlsimport'),
641 'html' => $html,
642 'connected' => $is_mls_connected === 'yes',
643 ]);
644 }
645
646
647