PluginProbe
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings / 6.3.8
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings v6.3.8
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 6.1.0 All 34 releases
mlsimport / mlsimport.php

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

650 lines 21.7 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.8
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.8');
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/mlsimport-provider-map.php';
145 require_once plugin_dir_path( __FILE__ ) . 'includes/mlsimport-status-taxonomy.php';
146 require_once plugin_dir_path( __FILE__ ) . 'includes/mlsimport-status-normalize.php';
147 require_once plugin_dir_path( __FILE__ ) . 'includes/class-mlsimport.php';
148 require_once plugin_dir_path( __FILE__ ) . 'includes/ThemeImport.php';
149 require_once plugin_dir_path( __FILE__ ) . 'enviroment/ResidenceClass.php';
150 require_once plugin_dir_path( __FILE__ ) . 'enviroment/EstateClass.php';
151 require_once plugin_dir_path( __FILE__ ) . 'enviroment/HouzezClass.php';
152 require_once plugin_dir_path( __FILE__ ) . 'enviroment/RealHomesClass.php';
153 require_once plugin_dir_path( __FILE__ ) . 'enviroment/ResoBase.php';
154 require_once plugin_dir_path( __FILE__ ) . 'enviroment/SparkResoClass.php';
155 require_once plugin_dir_path( __FILE__ ) . 'enviroment/BridgeResoClass.php';
156 require_once plugin_dir_path( __FILE__ ) . 'enviroment/TresleResoClass.php';
157 require_once plugin_dir_path( __FILE__ ) . 'enviroment/MlsgridResoClass.php';
158 require_once plugin_dir_path( __FILE__ ) . 'enviroment/MlsgridResoClass.php';
159 require_once plugin_dir_path( __FILE__ ) . 'includes/addons/agents_offices.php';
160 require_once plugin_dir_path( __FILE__ ) . 'includes/mlsimport-onboarding.php';
161
162 require_once plugin_dir_path( __FILE__ ) . 'includes/mlsimport-field-selector-functions.php';
163 require_once plugin_dir_path( __FILE__ ) . 'includes/mlsimport-progressive-save.php';
164 require_once plugin_dir_path( __FILE__ ) . 'includes/mlsimport-telemetry.php';
165 require_once plugin_dir_path( __FILE__ ) . 'includes/mlsimport-activity-log.php';
166
167 if ( ! wp_next_scheduled( 'event_mls_import_auto' ) ) {
168 wp_schedule_event( time(), 'hourly', 'event_mls_import_auto' );
169 }
170
171
172 /**
173 * Scheduled event: Processes MLSimport items marked for cron processing, in memory-safe batches.
174 *
175 * This function is triggered by the 'event_mls_import_auto' action.
176 * It fetches mlsimport_item post IDs in small batches (not all at once!) to minimize memory usage.
177 * Only posts with meta 'mlsimport_item_stat_cron' = 1 are processed.
178 * For each item, calls mlsimport_saas_start_cron_links_per_item().
179 *
180 * Optimizations:
181 * - Uses 'fields' => 'ids' so only post IDs are loaded (saves memory)
182 * - Batches with posts_per_page/paged, so memory does not spike for large data sets
183 * - Calls gc_collect_cycles() periodically to further reduce memory leaks
184 * - Skips processing if MLS is not connected or token is missing
185 *
186 * @return void
187 */
188 add_action('event_mls_import_auto', 'mlsimport_saas_event_mls_import_auto_function');
189 /**
190 * Scheduled event handler for MLS Import Auto (runs via WP Cron).
191 * Processes mlsimport_item posts in batches and logs memory usage.
192 */
193 function mlsimport_saas_event_mls_import_auto_function() {
194 global $mlsimport;
195
196 //error_log('[AutoCron] Start: ' . (memory_get_usage(true) / 1024 / 1024) . ' MB');
197
198 // 1. Get the API token from transient - exit if not set
199 $token = $mlsimport->admin->mlsimport_saas_get_mls_api_token_from_transient();
200 //error_log('[AutoCron] After token fetch: ' . (memory_get_usage(true) / 1024 / 1024) . ' MB');
201 if (trim($token) === '') {
202 //error_log('[AutoCron] No token, exiting.');
203 return;
204 }
205
206 // 2. Check if MLS connection is valid - exit if not
207 $is_mls_connected = get_option('mlsimport_connection_test', '');
208 //error_log('[AutoCron] After connection check: ' . (memory_get_usage(true) / 1024 / 1024) . ' MB');
209 if ('yes' !== $is_mls_connected) {
210 //error_log('[AutoCron] No valid connection, exiting.');
211 return;
212 }
213
214 // Record sync attempt in telemetry
215 mlsimport_telemetry_bump( 'syncs' );
216 mlsimport_telemetry_set( 'last_sync_attempt', time() );
217
218 // 3. Set batch size for processing and initialize loop variables
219 $batch_size = 100;
220 $paged = 1;
221 $total_processed = 0;
222
223 // 4. Process in batches until no more items are found
224 do {
225 // Prepare query: only IDs, filter by meta key, batch, paged, no_found_rows speeds up query
226 $args = array(
227 'post_type' => 'mlsimport_item',
228 'post_status' => 'any',
229 'posts_per_page' => $batch_size,
230 'paged' => $paged,
231 'fields' => 'ids',
232 'meta_query' => array(
233 array(
234 'key' => 'mlsimport_item_stat_cron',
235 'value' => 1,
236 'compare' => '=',
237 ),
238 ),
239 'no_found_rows' => true,
240 );
241
242 // Get post IDs for this batch
243 $post_ids = get_posts($args);
244 //error_log("[AutoCron] Batch {$paged} fetched " . count($post_ids) . " items, memory: " . (memory_get_usage(true) / 1024 / 1024) . ' MB');
245
246 // If nothing is returned, break the loop
247 if (empty($post_ids)) {
248 break;
249 }
250
251 // 5. Loop through each post ID in this batch
252 foreach ($post_ids as $prop_id) {
253 $logs = 'Loop custom post: ' . $prop_id . PHP_EOL;
254 mlsimport_debuglogs_per_plugin($logs);
255
256 // Call processing function for this item. The feed count it pulls
257 // is recorded inside mlsimport_make_listing_requests() (last_feed_found).
258 $mlsimport->admin->mlsimport_saas_start_cron_links_per_item($prop_id);
259
260 $total_processed++;
261
262 // Free memory every 100 processed items
263 if ($total_processed % 100 === 0) {
264 gc_collect_cycles();
265 //error_log("[AutoCron] Processed {$total_processed} total, memory: " . (memory_get_usage(true) / 1024 / 1024) . ' MB');
266 }
267 }
268
269 // 6. Prepare next batch
270 $paged++;
271 unset($post_ids); // Free memory
272 gc_collect_cycles(); // Trigger garbage collection
273 //error_log("[AutoCron] After batch {$paged}, memory: " . (memory_get_usage(true) / 1024 / 1024) . ' MB');
274
275 } while (true);
276
277 mlsimport_telemetry_set( 'last_sync_success', time() );
278
279 //error_log('[AutoCron] Done, total processed: ' . $total_processed . ', end memory: ' . (memory_get_usage(true) / 1024 / 1024) . ' MB');
280 }
281
282
283
284 /*
285 * Reconciliation Mechanism
286 *
287 *
288 *
289 **/
290
291 if ( ! wp_next_scheduled( 'mlsimport_reconciliation_event' ) ) {
292 wp_schedule_event( time(), 'daily', 'mlsimport_reconciliation_event' );
293 }
294
295 add_action( 'mlsimport_reconciliation_event', 'mlsimport_saas_reconciliation_event_function' );
296
297 if ( ! wp_next_scheduled( 'mlsimport_daily_telemetry_event' ) ) {
298 wp_schedule_event( time(), 'daily', 'mlsimport_daily_telemetry_event' );
299 }
300
301 add_action( 'mlsimport_daily_telemetry_event', 'mlsimport_telemetry_run_daily' );
302
303
304 /*
305 * Force use of transient
306 *
307 *
308 *
309 **/
310
311 function mlsimport_force_use_transient( $value ) {
312 return $value;
313 // return false;
314 }
315
316
317
318
319 global $mlsimport;
320 $mlsimport = new Mlsimport();
321 $mlsimport->run();
322
323
324
325
326
327 $supported_theme = array(
328 991 => 'WpResidence',
329 992 => 'Houzez',
330 993 => 'Real Homes',
331 994 => 'Wpestate',
332
333 );
334
335 define( 'MLSIMPORT_THEME', $supported_theme );
336
337 add_filter( 'action_scheduler_failure_period', 'mlsimport_saas_filter_timelimit' );
338 function mlsimport_saas_filter_timelimit( $time_limit ) {
339 return 3000;
340 }
341
342
343
344 /*
345 *
346 * Write logs
347 *
348 **/
349
350 function mlsimport_saas_single_write_import_custom_logs( $message, $tip_import = 'normal' ) {
351 // Check if logging is enabled
352 $enable_logs = intval( get_option( 'mlsimport_disable_logs' ) );
353 if ( 1 !== $enable_logs) {
354 return;
355 }
356
357 if ( is_array( $message ) ) {
358 $message = wp_json_encode( $message );
359 }
360
361 $formatted_message = gmdate( 'F j, Y, g:i a' ) . ' -> ' . $message;
362
363 // Determine the log file path based on the import type
364 $log_file_name = 'cron' === $tip_import ? 'cron_logs' :
365 ( 'delete' === $tip_import ? 'delete_logs' :
366 ( 'server_cron' === $tip_import ? 'server_cron_logs' : 'import_logs' ) );
367
368 // Construct the full path with a date suffix
369 $log_file_path = WP_PLUGIN_DIR . "/mlsimport/logs/{$log_file_name}-" . gmdate( 'Y-m-d' ) . '.log';
370
371 // Error handling for file operations
372 try {
373 // Check and create the directory for logs if it does not exist
374 $log_dir = dirname( $log_file_path );
375 if ( ! file_exists( $log_dir ) ) {
376 mkdir( $log_dir, 0755, true );
377 }
378
379 // Append the formatted message to the log file
380 file_put_contents( $log_file_path, $formatted_message, FILE_APPEND | LOCK_EX );
381 } catch ( Exception $e ) {
382 // Handle the exception, such as logging the error elsewhere or sending a notification
383 }
384 }
385
386
387
388 /*
389 *
390 *
391 * Write Status logs
392 *
393 *
394 **/
395
396
397
398 function mlsimport_debuglogs_per_plugin_old( $message ) {
399
400 if ( is_array( $message ) ) {
401 $message = wp_json_encode( $message );
402 }
403
404 global $wp_filesystem;
405 if ( empty( $wp_filesystem ) ) {
406 require_once ABSPATH . '/wp-admin/includes/file.php';
407 WP_Filesystem();
408 }
409
410 $path_status = WP_PLUGIN_DIR . '/mlsimport/logs/status_logs.log';
411 file_put_contents( $path_status, $message, LOCK_EX );
412 }
413 function mlsimport_debuglogs_per_plugin( $message ) {
414
415 if ( is_array( $message ) ) {
416 $message = wp_json_encode( $message );
417 }
418
419 if ( empty( $message ) ) {
420 return; // Exit the function if there's nothing to log
421 }
422
423 $log_file_path = WP_PLUGIN_DIR . '/mlsimport/logs/status_logs.log';
424
425 // Check and create the directory for logs if it does not exist
426 $log_dir = dirname( $log_file_path );
427 if ( ! file_exists( $log_dir ) ) {
428 mkdir( $log_dir, 0755, true );
429 }
430
431 // Error handling for file operations
432 try {
433 // Append the message to the log file with a newline and acquire an exclusive lock during writing
434 file_put_contents( $log_file_path, $message . PHP_EOL, LOCK_EX );
435 } catch ( Exception $e ) {
436 // Handle the exception, such as logging the error elsewhere or sending a notification
437 }
438 }
439
440
441
442
443
444 /*
445 * Cron job trigger
446 *
447 *
448 *
449 **/
450
451
452 // */5 * * * * wget http://example.com/check */2
453 add_action( 'init', 'mlsimport_trigger_cron_job' );
454 function mlsimport_trigger_cron_job() {
455 // ?mlsimport_cron=yes
456 if ( isset( $_REQUEST['mlsimport_cron'] ) && 'yes' === sanitize_text_field( wp_unslash( $_REQUEST['mlsimport_cron'] ) ) ) {
457 $last_run = intval( get_option( 'mlsimport_last_server_cron' ) );
458 $now = time();
459 if ( 0 === intval($last_run) ) {
460 update_option( 'mlsimport_last_server_cron', $now );
461 }
462
463 if ( $last_run < $now - ( 60 * 60 * 2 ) ) {
464 $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;
465 // mlsimport_saas_event_mls_import_auto_function();
466 update_option( 'mlsimport_last_server_cron', $now );
467 } else {
468 $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;
469 }
470
471 mlsimport_saas_single_write_import_custom_logs( $log, 'server_cron' );
472 }
473 }
474
475
476
477 function mlsimport_show_signup() {
478 $affiliate_url = 'https://mlsimport.com';
479 if ( function_exists( 'wp_estate_init' ) ) {
480 $affiliate_url = 'https://mlsimport.com/ref/1/?campaign=wpresidence';
481 }
482 ?>
483 <div class="mlsimport_signup">
484 <h3><?php esc_html_e('Import MLS Listings into your Real Estate website', 'mlsimport'); ?></h3>
485 <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>
486 <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>
487 </div>
488 <?php
489 }
490
491
492 //add_action('admin_init', 'force_recount_all_terms');
493 function force_recount_all_terms() {
494 global $wpdb;
495
496 // Get all taxonomies
497 $taxonomies = get_taxonomies([], 'names');
498
499 foreach ($taxonomies as $taxonomy) {
500 // Get all terms for the taxonomy
501 $terms = get_terms([
502 'taxonomy' => $taxonomy,
503 'hide_empty' => false, // Include terms with 0 count
504 'fields' => 'ids', // Get only the term IDs
505 ]);
506
507 if (!is_wp_error($terms) && !empty($terms)) {
508 // Get term_taxonomy_ids for these terms
509 $term_taxonomy_ids = $wpdb->get_col($wpdb->prepare(
510 "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE term_id IN (" . implode(',', array_map('intval', $terms)) . ")"
511 ));
512
513 // Update term counts
514 if (!empty($term_taxonomy_ids)) {
515 wp_update_term_count_now($term_taxonomy_ids, $taxonomy);
516 }
517 }
518 }
519
520 echo "Term counts have been recalculated for all taxonomies.";
521 }
522
523
524 /*
525 *
526 * create dropdown list
527 *
528 *
529 */
530 function mlsiport_mls_select_list( $key, $value, $data_array ) {
531 $select = '<select class="mlsimport-2025-select" id="' . esc_attr( $key ) . '" name="mlsimport_admin_options[' . $key . ']">';
532 if ( is_array( $data_array ) ) :
533 foreach ( $data_array as $key => $mls_item ) {
534 $select .= '<option value="' .esc_attr( $key ). '"';
535 if ( intval( $value ) === intval( $key ) ) {
536 $select .= ' selected ';
537 }
538 $select .= '>' .esc_html( $mls_item ). '</option>';
539 }
540 endif;
541 $select .= '</select>';
542 return $select;
543 }
544
545
546
547 add_action('wp_ajax_mlsimport_save_account', 'mlsimport_save_account_callback');
548 function mlsimport_save_account_callback() {
549 check_ajax_referer('mlsimport_onboarding_nonce', 'security');
550
551 $options = get_option('mlsimport_admin_options', []);
552 if ( ! empty($_POST['mlsimport_username']) && ! empty($_POST['mlsimport_password']) ) {
553 $options['mlsimport_username'] = sanitize_text_field($_POST['mlsimport_username']);
554 $options['mlsimport_password'] = sanitize_text_field($_POST['mlsimport_password']);
555 update_option('mlsimport_admin_options', $options);
556 }
557
558 global $mlsimport;
559
560 // Refresh token
561 $token = $mlsimport->admin->mlsimport_saas_get_mls_api_token_from_transient();
562
563 if (trim($token) === '') {
564 ob_start();
565
566 ?>
567 <div class="mlsimport_warning">
568 <?php esc_html_e('You are not connected to MlsImport - Please check your Username and Password.', 'mlsimport'); ?>
569 </div>
570 <?php
571 $html = ob_get_clean();
572
573 wp_send_json_success([
574 'message' => __('You are not connected.', 'mlsimport'),
575 'html' => $html,
576 'connected' => false
577 ]);
578 } else {
579 ob_start();
580 ?>
581 <div class="mlsimport_warning mlsimport_validated">
582 <?php esc_html_e('You are connected to your MlsImport account!', 'mlsimport'); ?>
583 </div>
584 <?php
585 $html = ob_get_clean();
586
587 wp_send_json_success([
588 'message' => __('Connected successfully!', 'mlsimport'),
589 'html' => $html,
590 'connected' => true
591 ]);
592 }
593 }
594
595
596
597
598
599
600
601
602 add_action('wp_ajax_mlsimport_save_mls_data', 'mlsimport_save_mls_data_callback');
603 function mlsimport_save_mls_data_callback() {
604 check_ajax_referer('mlsimport_onboarding_nonce', 'security');
605
606 $options = get_option('mlsimport_admin_options', []);
607
608 foreach ($_POST as $key => $value) {
609 if (strpos($key, 'mlsimport_') === 0 && $key !== 'mlsimport_username' && $key !== 'mlsimport_password') {
610 $options[$key] = sanitize_text_field($value);
611 }
612 }
613
614 update_option('mlsimport_admin_options', $options);
615
616 // Run MLS connection check
617 global $mlsimport;
618 $is_mls_connected = get_option('mlsimport_connection_test', '');
619 $mlsimport->admin->mlsimport_saas_setting_up();
620
621 if ('yes' !== $is_mls_connected) {
622 $mlsimport->admin->mlsimport_saas_check_mls_connection();
623 $is_mls_connected = get_option('mlsimport_connection_test', '');
624 }
625
626 ob_start();
627 if ('yes' === $is_mls_connected) {
628 ?>
629 <div class="mlsimport_warning mlsimport_validated">
630 <?php esc_html_e('You’re now connected to your MLS.', 'mlsimport'); ?>
631 </div>
632 <?php
633 } else {
634 ?>
635 <div class="mlsimport_warning">
636 <?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'); ?>
637 </div>
638 <?php
639 }
640 $html = ob_get_clean();
641
642 wp_send_json_success([
643 'message' => __('MLS data saved', 'mlsimport'),
644 'html' => $html,
645 'connected' => $is_mls_connected === 'yes',
646 ]);
647 }
648
649
650