PluginProbe
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings / 7.1.1
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings v7.1.1
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 / admin / partials / mlsimport-onboarding-steps / step-test-import.php

step-test-import.php in MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings 7.1.1, at admin/partials/mlsimport-onboarding-steps/step-test-import.php

538 lines 17.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Template for the Test Import step of the MLSImport onboarding wizard
4 *
5 * Runs a small verification import (a handful of listings) against the
6 * configured MLS. Shows the import name, current status, and the count of
7 * listings matching the saved filters, then offers a "Run Test Import" button
8 * that fires the mlsimport_run_test_import AJAX action and polls status via the
9 * mlsimport_logger_per_item AJAX action. This PHP region prepares the display
10 * data; the button/polling logic lives in the inline <script> below.
11 *
12 * NOTE: comments here live only inside PHP regions; the inline HTML/JS/CSS
13 * below is emitted verbatim and is intentionally left uncommented.
14 *
15 * @link https://mlsimport.com/
16 * @since 6.1.0
17 *
18 * @package Mlsimport
19 * @subpackage Mlsimport/admin/partials/mlsimport-onboarding-steps
20 */
21
22 // If this file is called directly, abort.
23 if (!defined('WPINC')) {
24 die;
25 }
26
27 // Load the import id created by the earlier onboarding steps (0 if none).
28 // Get saved data
29 $user_data = get_option('mlsimport_onboarding_user_data', array());
30 $import_id = isset($user_data['import_id']) ? $user_data['import_id'] : 0;
31
32 // Read the import's spawn (run) status meta when an import exists.
33 // Get import status
34 $spawn_status = '';
35 if ($import_id) {
36 $spawn_status = get_post_meta($import_id, 'mlsimport_spawn_status', true);
37 }
38
39 // Determine whether any properties were already imported for this import.
40 // Check if test has been run
41 $test_completed = false;
42 if ($import_id) {
43 // Resolve the theme's property post type via the environment adapter.
44 global $mlsimport;
45 $post_type = $mlsimport->admin->env_data->get_property_post_type();
46
47 // Query all properties stamped with this import id.
48 $args = array(
49 'post_type' => $post_type,
50 'post_status' => 'any',
51 'posts_per_page' => -1,
52 'meta_query' => array(
53 array(
54 'key' => 'MLSimport_item_inserted',
55 'value' => $import_id,
56 'compare' => '=',
57 ),
58 ),
59 );
60
61 // Test counts as completed when at least one property was imported.
62 $query = new WP_Query($args);
63 $test_completed = $query->found_posts > 0;
64 $imported_count = $query->found_posts;
65 wp_reset_postdata();
66 }
67
68 // The theme name this step drops into its copy. One shared resolver, so the
69 // wizard never disagrees with itself about which theme the site runs (#242).
70 $detected_theme = mlsimport_theme_copy_label();
71
72 // Read today's import log so recent lines/errors can be surfaced.
73 // Get log file content if it exists
74 $log_content = '';
75 $log_path = WP_PLUGIN_DIR . '/mlsimport/logs/import_logs-' . date('Y-m-d') . '.log';
76 if (file_exists($log_path)) {
77 $log_content = file_get_contents($log_path);
78 // Get the last few lines (up to 20)
79 // Split into lines, drop blanks, and keep only the last 20.
80 $log_lines = explode(PHP_EOL, $log_content);
81 $log_lines = array_filter($log_lines); // Remove empty lines
82 $log_lines = array_slice($log_lines, -20); // Get last 20 lines
83 $log_content = implode(PHP_EOL, $log_lines);
84 }
85
86 // Extract any "ERROR:" lines from the recent log into a list.
87 // Get any import errors
88 $import_errors = array();
89 if (!empty($log_content)) {
90 // Extract error messages
91 // Capture the text after each "ERROR:" marker.
92 if (preg_match_all('/ERROR: (.+?)(?=\n|$)/i', $log_content, $matches)) {
93 $import_errors = $matches[1];
94 }
95 }
96 ?>
97
98 <div class="mlsimport-test-import-content">
99 <div class="mlsimport-section">
100 <p class="mlsimport-test-intro">
101 <?php _e('Now let\'s run a small test import to verify everything is working properly. We will import 5 listings from your MLS.', 'mlsimport'); ?>
102 </p>
103
104 <?php if (!$import_id) : /* no import configured: show error and stop */ ?>
105 <div class="mlsimport-error-message">
106 <p>
107 <?php _e('No import configuration found. Please go back to the previous step and try again.', 'mlsimport'); ?>
108 </p>
109 </div>
110 <?php else : ?>
111
112
113
114 <div class="mlsimport-section-inner">
115 <h3><?php _e('Import Configuration', 'mlsimport'); ?></h3>
116 <div class="mlsimport-import-summary">
117 <p>
118 <strong><?php _e('Import Name:', 'mlsimport'); ?></strong>
119 <?php echo esc_html(get_the_title($import_id)); ?>
120 </p>
121 <p>
122 <strong><?php _e('Status:', 'mlsimport'); ?></strong>
123 <?php
124 // Status label: completed, in-progress, or ready to test.
125 if ($test_completed) {
126 echo '<span class="mlsimport-status-success">' . esc_html__('Test Completed 2', 'mlsimport') . '</span>';
127 } elseif ($spawn_status === 'started') {
128 echo '<span class="mlsimport-status-progress">' . esc_html__('In Progress', 'mlsimport') . '</span>';
129 } else {
130 echo '<span class="mlsimport-status-pending">' . esc_html__('Ready to Test', 'mlsimport') . '</span>';
131 }
132 ?>
133 </p>
134
135 <?php
136 // Get listing count based on filters
137 // Ask the MLS how many listings match this import's filters.
138 global $mlsimport;
139 $listing_count = 0;
140
141 if ($import_id) {
142 // Query the SaaS/MLS for a result count for this import.
143 $mlsrequest = $mlsimport->admin->mlsimport_make_listing_requests($import_id);
144
145 // Read the numeric results count, defaulting to 0.
146 $listing_count = isset($mlsrequest['results']) ? intval($mlsrequest['results']) : 0;
147 }
148 ?>
149
150 <p>
151 <strong><?php _e('Listings Found:', 'mlsimport'); ?></strong>
152 <span class="mlsimport-listing-count"><?php echo esc_html($listing_count); ?></span>
153 <?php if ($listing_count === 0): /* warn when nothing matches the filters */ ?>
154 <span class="mlsimport-zero-warning"><?php _e('(No listings match your current filters)', 'mlsimport'); ?></span>
155 <?php endif; ?>
156 </p>
157
158 <?php if ($test_completed) : /* show imported count once the test has run */ ?>
159 <p>
160 <strong><?php _e('Properties Imported:', 'mlsimport'); ?></strong>
161 <?php echo esc_html($imported_count); ?>
162 </p>
163 <?php endif; ?>
164 </div>
165
166 <?php if ($listing_count === 0): /* no listings: prompt user to broaden filters */ ?>
167 <div class="mlsimport-zero-listings-warning">
168 <p>
169 <?php _e('Please go back and adjust your filters to broaden your search.', 'mlsimport'); ?>
170 </p>
171 <a href="<?php echo admin_url('admin.php?page=mlsimport-onboarding&step=import-config'); ?>" class="button mlsimport_button secondary ">
172 <?php _e('Back to Import Configuration', 'mlsimport'); ?>
173 </a>
174 </div>
175 <?php endif; ?>
176
177 <?php if (!$test_completed && $spawn_status !== 'started' && $listing_count > 0) : /* show the Run button only when: not already completed, not currently running, and there are listings to import */ ?>
178 <div class="mlsimport-test-actions">
179 <button type="button" id="mlsimport-run-test" data-post-number="<?php echo intval($listing_count);?>" data-post_id="<?php echo intval($import_id)?>" class="button mlsimport_button">
180 <?php _e('Run Test Import', 'mlsimport'); ?>
181 </button>
182 <input type="hidden" id="mlsimport_item_actions" value="<?php echo esc_attr(wp_create_nonce("mlsimport_item_actions")); ?>"/>
183 <span id="mlsimport-test-spinner" class="mlsimport-spinner" style="display: none;"></span>
184 </div>
185 <?php endif; ?>
186 </div>
187
188
189
190
191
192
193
194
195 <div class="mlsimport-test-recommendations">
196 <h3><?php _e('Next Steps', 'mlsimport'); ?></h3>
197
198 <?php if ($test_completed) : /* completed: success copy and next actions */ ?>
199 <p>
200 <?php echo sprintf(
201 __('Congratulations! You\'ve successfully imported properties from your MLS into %s.', 'mlsimport'),
202 $detected_theme
203 ); ?>
204 </p>
205 <ul>
206 <li><?php _e('Click "Continue" to complete the setup', 'mlsimport'); ?></li>
207 <li><?php _e('Your import configuration has been saved and will update automatically', 'mlsimport'); ?></li>
208 <li><?php _e('You can create additional import configurations with different criteria later', 'mlsimport'); ?></li>
209 </ul>
210 <?php elseif ($spawn_status === 'started') : /* running: ask user to wait */ ?>
211 <p>
212 <?php _e('The import is currently in progress. Please wait for it to complete before continuing.', 'mlsimport'); ?>
213 </p>
214 <?php else : /* not yet run: prompt to start the test */ ?>
215 <p>
216 <?php _e('Please run the test import to verify your MLS connection and configuration.', 'mlsimport'); ?>
217 </p>
218 <?php endif; ?>
219 </div>
220 <?php endif; ?>
221 </div>
222 </div>
223
224 <script>
225 jQuery(document).ready(function($) {
226 var testIntervalId;
227 var importId = <?php echo intval($import_id); ?>;
228 var testStarted = <?php echo ($spawn_status === 'started') ? 'true' : 'false'; ?>;
229 var testCompleted = <?php echo $test_completed ? 'true' : 'false'; ?>;
230
231 // If import already started, check status
232 if (testStarted && !testCompleted) {
233 // startStatusCheck();
234 }
235
236 // Run test import
237 $('#mlsimport-run-test').on('click', function() {
238 $(this).prop('disabled', true);
239 $('#mlsimport-test-spinner').show();
240
241 $('.mlsimport-status-message')
242 .removeClass('pending')
243 .addClass('progress')
244 .html('<p><?php _e("Starting import... Please wait.", "mlsimport"); ?></p>');
245
246 // Send AJAX request
247 $.ajax({
248 url: ajaxurl,
249 type: 'POST',
250 data: {
251 action: 'mlsimport_run_test_import',
252 nonce: mlsimportOnboarding.nonce
253 },
254 success: function(response) {
255 if (response.success) {
256 testStarted = true;
257 startStatusCheck();
258 } else {
259 $('.mlsimport-status-message')
260 .removeClass('pending progress')
261 .addClass('error')
262 .html('<p>' + response.data.message + '</p>');
263
264 $('#mlsimport-run-test').prop('disabled', false);
265 $('#mlsimport-test-spinner').hide();
266 }
267 },
268 error: function() {
269 $('.mlsimport-status-message')
270 .removeClass('pending progress')
271 .addClass('error')
272 .html('<p><?php _e("Connection failed. Please try again.", "mlsimport"); ?></p>');
273
274 $('#mlsimport-run-test').prop('disabled', false);
275 $('#mlsimport-test-spinner').hide();
276 }
277 });
278 });
279
280 // Check test status periodically
281 function startStatusCheck() {
282 function checkStatus() {
283 jQuery.ajax({
284 url: ajaxurl,
285 type: 'POST',
286 dataType: 'json',
287 data: {
288 action: 'mlsimport_logger_per_item',
289 post_id: importId,
290 security: mlsimportOnboarding.nonce
291 },
292 success: function(response) {
293 console.log("Status response:", response);
294
295 if (response.is_done === 'done' || response.status === 'completed') {
296
297 clearInterval(testIntervalId);
298 testIntervalId = null;
299
300 // Hide spinner and get imported count
301 jQuery('#mlsimport-test-spinner,#mlsimport-run-test').hide();
302
303
304 // Update next steps
305 jQuery('.mlsimport-test-recommendations').html(
306 '<h3><Next Steps</h3>' +
307 '<p>Congratulations! You\'ve successfully imported properties from your MLS ! </p>'
308
309 );
310
311
312 }
313 },
314 error: function() {
315 // Error checking status
316 }
317 });
318 }
319
320 // Check immediately, then every 5 seconds
321 checkStatus();
322 testIntervalId = setInterval(checkStatus, 5000);
323 }
324
325
326
327
328
329
330
331 });
332
333
334
335 </script>
336
337 <style>
338 .mlsimport-test-import-content {
339 max-width: 800px;
340 }
341
342 .mlsimport-test-intro {
343 font-size: 15px;
344 margin-bottom: 25px;
345 }
346
347 .mlsimport-section-inner {
348 margin-bottom: 40px;
349 }
350
351 .mlsimport-section-inner h3 {
352 margin-top: 0;
353 border-bottom: 1px solid var(--border-color);
354 padding-bottom: 10px;
355 margin-bottom: 15px;
356 }
357
358 .mlsimport-import-summary {
359 background-color: var(--background-soft);
360 padding: 15px;
361 border-radius: 4px;
362 margin-bottom: 20px;
363 }
364
365 .mlsimport-import-summary p {
366 margin: 5px 0;
367 }
368
369 .mlsimport-status-success {
370 color: var(--success-deep);
371 font-weight: 600;
372 }
373
374 .mlsimport-status-progress {
375 color: var(--accent-color);
376 font-weight: 600;
377 }
378
379 .mlsimport-status-pending {
380 color: var(--text-secondary);
381 font-weight: 600;
382 }
383
384 .mlsimport-test-actions {
385 margin-top: 20px;
386 display: flex;
387 flex-direction: row;
388 flex-wrap: nowrap;
389 justify-content: flex-start;
390 align-items: center;
391 }
392
393 .mlsimport-spinner {
394 display: inline-block;
395 width: 20px;
396 height: 20px;
397 margin-left: 10px;
398 vertical-align: middle;
399 border: 2px solid rgba(0, 0, 0, 0.1);
400 border-radius: 50%;
401 border-top-color: var(--primary-color);
402 animation: mlsimport-spin 1s linear infinite;
403 order:2;
404 }
405
406 @keyframes mlsimport-spin {
407 to {
408 transform: rotate(360deg);
409 }
410 }
411
412 /* Status message styling */
413 .mlsimport-status-message {
414 padding: 15px;
415 border-radius: 4px;
416 margin-bottom: 20px;
417 }
418
419 .mlsimport-status-message.success {
420 background-color: var(--success-soft);
421 border-left: 4px solid var(--success-deep);
422 }
423
424 .mlsimport-status-message.error {
425 background-color: var(--error-soft);
426 border-left: 4px solid var(--error-color);
427 }
428
429 .mlsimport-status-message.warning {
430 background-color: var(--warning-soft);
431 border-left: 4px solid var(--warning-color);
432 }
433
434 .mlsimport-status-message.progress {
435 background-color: var(--background-light);
436 border-left: 4px solid var(--primary-color);
437 }
438
439 .mlsimport-status-message.pending {
440 background-color: var(--background-soft);
441 border-left: 4px solid var(--border-color);
442 }
443
444 .mlsimport-status-message p {
445 margin: 0 0 10px 0;
446 }
447
448 .mlsimport-status-message p:last-child {
449 margin-bottom: 0;
450 }
451
452 /* Progress bar */
453 /* Log container */
454 .mlsimport-log-container {
455 max-height: 300px;
456 overflow-y: auto;
457 background-color: var(--background-soft);
458 border: 1px solid var(--border-color);
459 border-radius: 3px;
460 padding: 10px;
461 margin-bottom: 20px;
462 }
463
464 .mlsimport-log-content {
465 font-family: monospace;
466 font-size: 12px;
467 line-height: 1.5;
468 margin: 0;
469 white-space: pre-wrap;
470 }
471
472 .mlsimport-log-empty {
473 color: var(--text-secondary);
474 font-style: italic;
475 }
476
477 .mlsimport-view-properties {
478 margin-top: 20px;
479 }
480
481 /* Error list */
482 .mlsimport-error-list {
483 background-color: var(--error-soft);
484 padding: 15px;
485 border-radius: 4px;
486 margin-top: 20px;
487 }
488
489 .mlsimport-error-list h4 {
490 margin-top: 0;
491 margin-bottom: 10px;
492 color: var(--error-color);
493 }
494
495 .mlsimport-error-list ul {
496 margin-top: 10px;
497 margin-left: 20px;
498 }
499
500 .mlsimport-error-list li {
501 margin-bottom: 5px;
502 }
503
504 /* Error message */
505 .mlsimport-error-message {
506 background-color: var(--error-soft);
507 border-left: 4px solid var(--error-color);
508 padding: 15px;
509 margin-bottom: 20px;
510 }
511
512 .mlsimport-error-message p {
513 margin: 0;
514 }
515
516 /* Next steps */
517 .mlsimport-test-recommendations {
518 background-color: var(--background-soft);
519 border-left: 4px solid var(--primary-color);
520 padding: 15px;
521 margin-top: 20px;
522 }
523
524 .mlsimport-test-recommendations h3 {
525 margin-top: 0;
526 margin-bottom: 15px;
527 border-bottom: none;
528 padding-bottom: 0;
529 }
530
531 .mlsimport-test-recommendations ul {
532 margin-left: 20px;
533 }
534
535 .mlsimport-test-recommendations li {
536 margin-bottom: 8px;
537 }
538 </style>