PluginProbe
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings / 6.3.1
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings v6.3.1
7.2.2 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 All 37 releases
mlsimport / includes / mlsimport-progressive-save.php

mlsimport-progressive-save.php in MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings 6.3.1, at includes/mlsimport-progressive-save.php

676 lines 21.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * MLS Import Progressive Save Handlers
4 *
5 * Server-side handlers for the progressive save system:
6 * - Initial save detection and chunked saving
7 * - Individual field option saving
8 * - Optimized field order saving
9 *
10 * @package MLSImport
11 * @subpackage MLSImport/includes
12 */
13
14 // Exit if accessed directly
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit;
17 }
18
19
20 /**
21 * AJAX handler for saving field order
22 * This stores the order directly in the mlsimport_admin_fields_select option
23 */
24 function mlsimport_ajax_save_field_order() {
25 // Add detailed logging for debugging
26
27 // Check nonce
28 if (!isset($_POST['security']) || !wp_verify_nonce($_POST['security'], 'mlsimport_field_selector_nonce')) {
29 //error_log('Invalid security token in field order save');
30 wp_send_json_error('Invalid security token');
31 return;
32 }
33
34 // Check for both parameter formats
35 $field_order = array();
36
37 // Check for standard array format (field_order[])
38 if (isset($_POST['field_order']) && is_array($_POST['field_order'])) {
39 $field_order = $_POST['field_order'];
40 //error_log('Using field_order parameter: ' . count($field_order) . ' items');
41 }
42 // Check for older format (fields[])
43 else if (isset($_POST['fields']) && is_array($_POST['fields'])) {
44 $field_order = $_POST['fields'];
45 //error_log('Using fields parameter: ' . count($field_order) . ' items');
46 }
47 // Otherwise, try to get values directly by key pattern
48 else {
49 //error_log('No direct array found, checking for field_order[] pattern');
50 // Check if we need to manually extract from the POST data (for field_order[])
51 foreach ($_POST as $key => $value) {
52 if (preg_match('/^field_order(\[.*\])?$/', $key)) {
53 if (is_array($value)) {
54 $field_order = $value;
55 //error_log('Found field_order as array with ' . count($field_order) . ' items');
56 break;
57 }
58 }
59 }
60
61 // If we still don't have field order data, try to extract it directly from POST
62 if (empty($field_order)) {
63 //error_log('Trying to manually build array from field_order[]');
64 foreach ($_POST as $key => $value) {
65 if (strpos($key, 'field_order[') === 0) {
66 $field_order[] = $value;
67 }
68 }
69 //error_log('Manually built array with ' . count($field_order) . ' items');
70 }
71 }
72
73 // Check if we have any field order data
74 if (empty($field_order)) {
75 //error_log('No field order data found in request');
76 wp_send_json_error('No field order provided');
77 return;
78 }
79
80 // Log field count for debugging
81 //error_log('Saving ' . count($field_order) . ' fields in order');
82
83 // Get current options
84 $options = get_option('mlsimport_admin_fields_select', array());
85
86 // Make sure $options is an array
87 if (!is_array($options)) {
88 $options = array();
89 }
90
91 // Store the field order directly in the options
92 $options['field_order'] = array_map('sanitize_text_field', $field_order);
93
94 // Save the updated options
95 $result = update_option('mlsimport_admin_fields_select', $options);
96
97 if ($result) {
98 global $mlsimport;
99 if ( isset( $mlsimport->admin->env_data ) && method_exists( $mlsimport->admin->env_data, 'enviroment_custom_fields' ) ) {
100 $mlsimport->admin->env_data->enviroment_custom_fields( $mlsimport->get_plugin_name() );
101 }
102 //error_log('Field order saved successfully');
103 wp_send_json_success('Field order saved successfully');
104 } else {
105 //error_log('Failed to save field order - update_option returned false');
106 wp_send_json_error('Failed to save field order - update_option returned false');
107 }
108 }
109
110
111
112 /**
113 * Add this function to your mlsimport-admin-fields-select.php file
114 * Outputs the nonce field needed for field ordering
115 */
116 function mlsimport_add_field_selector_nonce() {
117 wp_nonce_field('mlsimport_field_selector_nonce', 'mlsimport_field_selector_nonce');
118 }
119
120
121
122
123
124
125 /**
126 * Register AJAX handlers for progressive saving
127 */
128 function mlsimport_register_progressive_save_handlers() {
129 // Check if initial save is needed
130 add_action('wp_ajax_mlsimport_check_initial_save_needed', 'mlsimport_ajax_check_initial_save_needed');
131
132 // Save a chunk of fields
133 add_action('wp_ajax_mlsimport_save_field_chunk', 'mlsimport_ajax_save_field_chunk');
134
135 // Save an individual field option
136 add_action('wp_ajax_mlsimport_save_field_option', 'mlsimport_ajax_save_field_option');
137
138 // Bulk save import selections
139 add_action('wp_ajax_mlsimport_save_bulk_import', 'mlsimport_ajax_save_bulk_import');
140
141 // Bulk save admin visibility selections
142 add_action('wp_ajax_mlsimport_save_bulk_admin', 'mlsimport_ajax_save_bulk_admin');
143 }
144 add_action('init', 'mlsimport_register_progressive_save_handlers');
145
146
147
148
149
150
151 function mlsimport_ajax_save_field_chunk() {
152 // Check nonce
153 if (!isset($_POST['security']) || !wp_verify_nonce($_POST['security'], 'mlsimport_field_selector_nonce')) {
154 wp_send_json_error('Invalid security token');
155 return;
156 }
157
158 // Check if fields were provided
159 if (!isset($_POST['fields']) || !is_array($_POST['fields'])) {
160 wp_send_json_error('No field data provided');
161 return;
162 }
163
164 // Get chunk info
165 $chunk_index = isset($_POST['chunk_index']) ? intval($_POST['chunk_index']) : 0;
166 $total_chunks = isset($_POST['total_chunks']) ? intval($_POST['total_chunks']) : 1;
167 $is_last_chunk = ($chunk_index + 1) == $total_chunks;
168
169 // Get current options
170 $options = get_option('mlsimport_admin_fields_select', array());
171
172 // Initialize arrays if they don't exist
173 if (!is_array($options)) {
174 $options = array();
175 }
176
177 if (!isset($options['mls-fields'])) {
178 $options['mls-fields'] = array();
179 }
180
181 if (!isset($options['mls-fields-admin'])) {
182 $options['mls-fields-admin'] = array();
183 }
184
185 if (!isset($options['mls-fields-label'])) {
186 $options['mls-fields-label'] = array();
187 }
188
189 if (!isset($options['mls-fields-map-postmeta'])) {
190 $options['mls-fields-map-postmeta'] = array();
191 }
192
193 if (!isset($options['mls-fields-map-taxonomy'])) {
194 $options['mls-fields-map-taxonomy'] = array();
195 }
196
197 if (!isset($options['field_order'])) {
198 $options['field_order'] = array();
199 $i = 0;
200 }else{
201 $i = count($options['field_order'] );
202 }
203
204
205
206 // Process fields in the chunk
207 foreach ($_POST['fields'] as $field_key => $field_data) {
208
209
210 // Process field data as before
211 if (isset($field_data['import'])) {
212 $options['mls-fields'][$field_key] = intval($field_data['import']);
213 }
214
215 if (isset($field_data['admin'])) {
216 $options['mls-fields-admin'][$field_key] = intval($field_data['admin']);
217 }
218
219 if (isset($field_data['label'])) {
220 $options['mls-fields-label'][$field_key] = $field_data['label'];
221 }
222
223 if (isset($field_data['postmeta'])) {
224 $options['mls-fields-map-postmeta'][$field_key] = $field_data['postmeta'];
225 }
226
227 if (isset($field_data['taxonomy'])) {
228 $options['mls-fields-map-taxonomy'][$field_key] = $field_data['taxonomy'];
229 }
230
231
232 $options['field_order'][$field_key] = $i++;
233
234 }
235
236
237
238
239 // Save the options
240 $saved = update_option('mlsimport_admin_fields_select', $options);
241 if ( $saved ) {
242 global $mlsimport;
243 if ( isset( $mlsimport->admin->env_data ) && method_exists( $mlsimport->admin->env_data, 'enviroment_custom_fields' ) ) {
244 $mlsimport->admin->env_data->enviroment_custom_fields( $mlsimport->get_plugin_name() );
245 }
246 }
247
248 wp_send_json_success(array(
249
250 'field_order'=> $options['field_order'],
251 'message' => 'Field chunk ' . ($chunk_index + 1) . ' of ' . $total_chunks . ' saved successfully',
252 'chunkIndex' => $chunk_index,
253 'totalChunks' => $total_chunks,
254 'isLastChunk' => $is_last_chunk,
255
256 ));
257 }
258
259 /**
260 * AJAX handler to save import selections in bulk
261 */
262 function mlsimport_ajax_save_bulk_import() {
263 if (!isset($_POST['security']) || !wp_verify_nonce($_POST['security'], 'mlsimport_field_selector_nonce')) {
264 wp_send_json_error('Invalid security token');
265 }
266
267 if (!isset($_POST['fields']) || !is_array($_POST['fields'])) {
268 wp_send_json_error('No field data provided');
269 }
270
271 $options = get_option('mlsimport_admin_fields_select', array());
272 if (!isset($options['mls-fields']) || !is_array($options['mls-fields'])) {
273 $options['mls-fields'] = array();
274 }
275
276 foreach ($_POST['fields'] as $key => $value) {
277 $options['mls-fields'][sanitize_text_field($key)] = intval($value);
278 }
279
280 $result = update_option('mlsimport_admin_fields_select', $options);
281 if ($result) {
282 global $mlsimport;
283 if ( isset( $mlsimport->admin->env_data ) && method_exists( $mlsimport->admin->env_data, 'enviroment_custom_fields' ) ) {
284 $mlsimport->admin->env_data->enviroment_custom_fields( $mlsimport->get_plugin_name() );
285 }
286 wp_send_json_success('Bulk import selections saved');
287 } else {
288 wp_send_json_error('Failed to save selections');
289 }
290 }
291
292 /**
293 * AJAX handler to save admin visibility selections in bulk
294 */
295 function mlsimport_ajax_save_bulk_admin() {
296 if (!isset($_POST['security']) || !wp_verify_nonce($_POST['security'], 'mlsimport_field_selector_nonce')) {
297 wp_send_json_error('Invalid security token');
298 }
299
300 if (!isset($_POST['fields']) || !is_array($_POST['fields'])) {
301 wp_send_json_error('No field data provided');
302 }
303
304 $options = get_option('mlsimport_admin_fields_select', array());
305 if (!isset($options['mls-fields-admin']) || !is_array($options['mls-fields-admin'])) {
306 $options['mls-fields-admin'] = array();
307 }
308
309 foreach ($_POST['fields'] as $key => $value) {
310 $options['mls-fields-admin'][sanitize_text_field($key)] = intval($value);
311 }
312
313 $result = update_option('mlsimport_admin_fields_select', $options);
314 if ($result) {
315 global $mlsimport;
316 if ( isset( $mlsimport->admin->env_data ) && method_exists( $mlsimport->admin->env_data, 'enviroment_custom_fields' ) ) {
317 $mlsimport->admin->env_data->enviroment_custom_fields( $mlsimport->get_plugin_name() );
318 }
319 wp_send_json_success('Bulk admin selections saved');
320 } else {
321 wp_send_json_error('Failed to save selections');
322 }
323 }
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347 /**
348 * AJAX handler to check if initial save is needed
349 */
350 function mlsimport_ajax_check_initial_save_needed() {
351 // Check nonce
352 if ( ! isset( $_POST['security'] ) || ! wp_verify_nonce( $_POST['security'], 'mlsimport_field_selector_nonce' ) ) {
353 wp_send_json_error( 'Invalid security token' );
354 }
355
356 // Check if option exists and has content
357 $options = get_option( 'mlsimport_admin_fields_select' );
358 $mlsimport_mls_metadata_mls_data = get_option( 'mlsimport_mls_metadata_mls_data', '' );
359
360 // Decode MLS data
361 $mls_data = json_decode( $mlsimport_mls_metadata_mls_data, true );
362
363 // Check if we need an initial save
364 $initial_save_needed = false;
365
366 // If MLS data exists but option is empty/incomplete
367 // had !empty( $mls_data ) &&
368 if ( (
369 empty( $options ) ||
370 empty( $options['mls-fields'] )
371 ) ) {
372 $initial_save_needed = true;
373 }
374
375 wp_send_json_success( array(
376 'initialSaveNeeded' => $initial_save_needed,
377
378 'options'=>$options,
379 'fieldsInOption' => is_array( $options ) && isset( $options['mls-fields'] ) ? count( $options['mls-fields'] ) : 0,
380 'fieldsInMlsData' => is_array( $mls_data ) ? count( $mls_data ) : 0
381 ) );
382 }
383
384 /**
385 * AJAX handler to save an individual field option
386 */
387 function mlsimport_ajax_save_field_ssswsd2option() {
388 // Check nonce
389 if ( ! isset( $_POST['security'] ) || ! wp_verify_nonce( $_POST['security'], 'mlsimport_field_selector_nonce' ) ) {
390 wp_send_json_error( 'Invalid security token' );
391 }
392
393 // Check if field key and option type were provided
394 if ( ! isset( $_POST['field_key'] ) || ! isset( $_POST['option_type'] ) ) {
395 wp_send_json_error( 'Missing field key or option type' );
396 }
397
398 // Sanitize inputs
399 $field_key = sanitize_text_field( $_POST['field_key'] );
400 $option_type = sanitize_text_field( $_POST['option_type'] );
401 $value = isset( $_POST['value'] ) ? $_POST['value'] : '';
402
403 // Validate option type
404 $valid_option_types = array( 'import', 'admin', 'label', 'postmeta', 'taxonomy' );
405
406 if ( ! in_array( $option_type, $valid_option_types ) ) {
407 wp_send_json_error( 'Invalid option type' );
408 }
409
410 // Get current options
411 $options = get_option( 'mlsimport_admin_fields_select', array() );
412 // Keep a copy of the original options to detect changes
413 $original_options = $options;
414
415 // Map option type to options array key
416 $option_map = array(
417 'import' => 'mls-fields',
418 'admin' => 'mls-fields-admin',
419 'label' => 'mls-fields-label',
420 'postmeta' => 'mls-fields-map-postmeta',
421 'taxonomy' => 'mls-fields-map-taxonomy'
422 );
423
424 $option_key = $option_map[ $option_type ];
425
426 // Initialize array if it doesn't exist
427 if ( ! isset( $options[ $option_key ] ) ) {
428 $options[ $option_key ] = array();
429 }
430
431 // Sanitize and update value based on option type
432 switch ( $option_type ) {
433 case 'import':
434 case 'admin':
435 $options[ $option_key ][ $field_key ] = intval( $value );
436 break;
437
438 case 'label':
439 case 'postmeta':
440 case 'taxonomy':
441 $options[ $option_key ][ $field_key ] = sanitize_text_field( $value );
442 break;
443 }
444
445 // If nothing changed, treat as success without calling update_option
446 if ( $options === $original_options ) {
447 wp_send_json_success( array(
448 'message' => 'Field option saved successfully',
449 'fieldKey' => $field_key,
450 'optionType' => $option_type,
451 'value' => $value,
452 ) );
453 }
454
455 // Save updated options
456 $result = update_option( 'mlsimport_admin_fields_select', $options );
457
458 if ( false !== $result ) {
459 wp_send_json_success( array(
460 'message' => 'Field option saved successfully',
461 'fieldKey' => $field_key,
462 'optionType' => $option_type,
463 'value' => $value,
464 ) );
465 } else {
466 wp_send_json_error( 'Failed to save field option' );
467 }
468 }
469 function mlsimport_ajax_save_field_option() {
470 // Check nonce
471 if ( ! isset( $_POST['security'] ) || ! wp_verify_nonce( $_POST['security'], 'mlsimport_field_selector_nonce' ) ) {
472 //error_log( '[mlsimport] Invalid security token' );
473 wp_send_json_error( 'Invalid security token' );
474 }
475
476 // Check if field key and option type were provided
477 if ( ! isset( $_POST['field_key'] ) || ! isset( $_POST['option_type'] ) ) {
478 //error_log( '[mlsimport] Missing field key or option type' );
479 wp_send_json_error( 'Missing field key or option type' );
480 }
481
482 // Sanitize inputs
483 $field_key = sanitize_text_field( $_POST['field_key'] );
484 $option_type = sanitize_text_field( $_POST['option_type'] );
485 $value = isset( $_POST['value'] ) ? $_POST['value'] : '';
486
487 // Error log for debugging
488 //error_log( '[mlsimport] Field Key: ' . $field_key );
489 //error_log( '[mlsimport] Option Type: ' . $option_type );
490 //error_log( '[mlsimport] Raw Value: ' . print_r( $value, true ) );
491
492 // Validate option type
493 $valid_option_types = array( 'import', 'admin', 'label', 'postmeta', 'taxonomy' );
494 if ( ! in_array( $option_type, $valid_option_types ) ) {
495 //error_log( '[mlsimport] Invalid option type: ' . $option_type );
496 wp_send_json_error( 'Invalid option type' );
497 }
498
499 // Get current options
500 $options = get_option( 'mlsimport_admin_fields_select', array() );
501 $original_options = $options;
502
503 // Map option type to options array key
504 $option_map = array(
505 'import' => 'mls-fields',
506 'admin' => 'mls-fields-admin',
507 'label' => 'mls-fields-label',
508 'postmeta' => 'mls-fields-map-postmeta',
509 'taxonomy' => 'mls-fields-map-taxonomy'
510 );
511
512 $option_key = $option_map[ $option_type ];
513
514 if ( ! isset( $options[ $option_key ] ) ) {
515 $options[ $option_key ] = array();
516 //error_log( '[mlsimport] Initialized option key: ' . $option_key );
517 }
518
519 // Sanitize and update value
520 switch ( $option_type ) {
521 case 'import':
522 case 'admin':
523 $options[ $option_key ][ $field_key ] = intval( $value );
524 break;
525
526 case 'label':
527 case 'postmeta':
528 case 'taxonomy':
529 $options[ $option_key ][ $field_key ] = sanitize_text_field( $value );
530 break;
531 }
532
533 // //error_log( '[mlsimport] Updated Options: ' . print_r( $options, true ) );
534
535 // No changes
536 if ( $options === $original_options ) {
537 //error_log( '[mlsimport] No changes detected for option update.' );
538 wp_send_json_success( array(
539 'message' => 'Field option saved successfully',
540 'fieldKey' => $field_key,
541 'optionType' => $option_type,
542 'value' => $value,
543 ) );
544 }
545 //error_log('saving mls-fields '.count($options['mls-fields']));
546 //error_log('saving mls-fields-admin '.count($options['mls-fields-admin']));
547 //error_log('saving mls-fields-label '.count($options['mls-fields-label']));
548 //error_log('saving mls-fields-map-postmeta '.count($options['mls-fields-map-postmeta']));
549 //error_log('saving mls-fields-map-taxonomy '.count($options['mls-fields-map-taxonomy']));
550 //error_log('saving field_order '.count($options['field_order']));
551
552 // Save updated options
553 $result = update_option( 'mlsimport_admin_fields_select', $options );
554
555 if ( false !== $result ) {
556 //error_log( '[mlsimport] Options updated successfully.' );
557 wp_send_json_success( array(
558 'message' => 'Field option saved successfully',
559 'fieldKey' => $field_key,
560 'optionType' => $option_type,
561 'value' => $value,
562 ) );
563 } else {
564 //error_log( '[mlsimport] Failed to update options.' );
565 wp_send_json_error( 'Failed to save field option' );
566 }
567 }
568
569
570
571 function mlsimport_ajax_save_field_position() {
572 // Verify nonce
573 if (!isset($_POST['security']) || !wp_verify_nonce($_POST['security'], 'mlsimport_field_selector_nonce')) {
574 wp_send_json_error('Invalid security token');
575 }
576
577 // Validate required fields
578 if (!isset($_POST['moving_index'], $_POST['target_index'], $_POST['position'])) {
579 wp_send_json_error('Missing parameters');
580 }
581
582 $moving_index = intval($_POST['moving_index']);
583 $target_index = intval($_POST['target_index']);
584 $position = sanitize_text_field($_POST['position']); // 'before' or 'after'
585
586 // Load current options
587 $options = get_option('mlsimport_admin_fields_select', []);
588
589 if (empty($options['field_order']) || !is_array($options['field_order'])) {
590 wp_send_json_error('Field order not found');
591 }
592
593
594
595
596 // Normalize field_order to ensure correct index order
597 $order_map = $options['field_order'];
598
599 asort($order_map); // Sort by index
600 $ordered_keys = array_keys($order_map);
601
602 // Safety checks
603 if (!isset($ordered_keys[$moving_index]) || !isset($ordered_keys[$target_index])) {
604 wp_send_json_error('Invalid indexes');
605 }
606
607 $moving_key = $ordered_keys[$moving_index];
608 $target_key = $ordered_keys[$target_index];
609
610 // Remove moving key
611 array_splice($ordered_keys, $moving_index, 1);
612
613 // Adjust target index if needed
614 if ($position === 'after' && $moving_index < $target_index) {
615 $target_index--;
616 }
617
618 // Calculate new position
619 $insert_index = ($position === 'before') ? $target_index : $target_index + 1;
620
621 // Insert the field key at the new position
622 array_splice($ordered_keys, $insert_index, 0, $moving_key);
623
624 // Rebuild the new order map
625 $new_order = [];
626 foreach ($ordered_keys as $i => $key) {
627 $new_order[$key] = $i;
628 }
629
630 // Save new field order
631 $options['field_order'] = $new_order;
632
633 // Apply order to all related field maps
634 $targets = [
635 'mls-fields',
636 'mls-fields-map-taxonomy',
637 'mls-fields-map-postmeta',
638 'mls-fields-map-admin',
639 'mls-fields-map-label',
640 ];
641
642 foreach ($targets as $target) {
643 if (!empty($options[$target]) && is_array($options[$target])) {
644 $reordered = [];
645
646 foreach ($new_order as $field_key => $index) {
647 if (isset($options[$target][$field_key])) {
648 $reordered[$field_key] = $options[$target][$field_key];
649 }
650 }
651
652 // Preserve any extra keys not in field_order
653 foreach ($options[$target] as $key => $value) {
654 if (!isset($reordered[$key])) {
655 $reordered[$key] = $value;
656 }
657 }
658
659 $options[$target] = $reordered;
660 }
661 }
662
663 // Save the updated options
664 $saved = update_option('mlsimport_admin_fields_select', $options);
665 if ( $saved ) {
666 global $mlsimport;
667 if ( isset( $mlsimport->admin->env_data ) && method_exists( $mlsimport->admin->env_data, 'enviroment_custom_fields' ) ) {
668 $mlsimport->admin->env_data->enviroment_custom_fields( $mlsimport->get_plugin_name() );
669 }
670 }
671
672 wp_send_json_success('Field order updated');
673 }
674
675 // Register the AJAX handler
676 add_action('wp_ajax_mlsimport_save_field_position', 'mlsimport_ajax_save_field_position');