PluginProbe
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings / 7.2
MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings v7.2
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 6.0.7 All 35 releases
← All changes | includes/help_functions.php +28 -17 7.17.2 View file →
@@ -2873,8 +2873,15 @@
2873 2873
2874 2874 // Success: reshape the list into autocomplete {label,value} pairs.
2875 2875 if ( isset( $answer['success'] ) && true === $answer['success'] ) {
2876 2876 $mls_data = $answer['mls_list'];
2877 +
2878 + // Fresh catalogue in hand: refresh registered connections' display
2879 + // names so an MLS renamed upstream shows its new name everywhere
2880 + // (Connections table, import task picker) after a cache clear.
2881 + if ( is_array( $mls_data ) && class_exists( 'Mlsimport_Connections' ) ) {
2882 + Mlsimport_Connections::sync_names( $mls_data );
2883 + }
2877 2884 // Prepend the "not listed" opt-out choice.
2878 2885 $mls_data['0'] = esc_html__( 'My MLS is not on this list', 'mlsimport' );
2879 2886
2880 2887 $autofill_array = array();
@@ -2952,14 +2959,17 @@
2952 2959 /**
2953 2960 * Cron entry point for the daily SaaS reconciliation pass.
2954 2961 *
2955 2962 * Bails out early unless at least one non-trashed import task has a title, then
2956 - * calls the one deep reconciliation interface when an MLS name is configured.
2963 + * hands off to the per-connection runner (#279) when an MLS name is configured:
2964 + * one sub-run of the deep reconciliation module per registered connection,
2965 + * or the single legacy unscoped run while no connections are registered.
2957 2966 *
2958 - * The same function handles the deduplicated one-hour retry hook. Trigger code
2959 - * intentionally owns no snapshot, status, batching, or deletion decisions.
2967 + * The same function handles the deduplicated one-hour retry hook — a retry
2968 + * re-runs all connections, and completed ones converge to no-op keeps. Trigger
2969 + * code intentionally owns no snapshot, status, batching, or deletion decisions.
2960 2970 *
2961 - * @return array<string, int|string>|null Reconciliation Outcome, or null when ineligible.
2971 + * @return array<int, array<string, int|string>>|null Outcome per connection, or null when ineligible.
2962 2972 */
2963 2973 function mlsimport_saas_reconciliation_event_function() {
2964 2974
2965 2975 // Pull the API token (side effect: ensures a fresh token) and plugin options.
@@ -2979,19 +2989,13 @@
2979 2989 if ( ! $has_titled_task ) {
2980 2990 return null;
2981 2991 }
2982 2992
2983 - // Only reconcile when an MLS name is configured.
2993 + // Only reconcile when an MLS name is configured. The runner sequences one
2994 + // scoped sub-run per registered connection (legacy unscoped run when the
2995 + // registry is empty) and records/logs every outcome itself.
2984 2996 if ( isset( $options['mlsimport_mls_name'] ) && '' !== $options['mlsimport_mls_name'] ) {
2985 - $environment = new Mlsimport_Reconciliation_WordPress_Environment(
2986 - static function () use ( $mlsimport ): array {
2987 - return $mlsimport->admin->mlsimport_saas_get_mls_reconciliation_data();
2988 - }
2989 - );
2990 -
2991 - $outcome = ( new Mlsimport_Reconciliation( $environment ) )->reconcile_current_listings();
2992 - error_log( 'MLSImport reconciliation outcome: ' . wp_json_encode( $outcome ) );
2993 - return $outcome;
2997 + return mlsimport_reconciliation_run_connections();
2994 2998 }
2995 2999
2996 3000 return null;
2997 3001 }
@@ -3095,11 +3099,12 @@
3095 3099 * @param int $postID Import Task post ID.
3096 3100 * @return void Output is echoed directly.
3097 3101 */
3098 3102 function mlsimport_populate_columns_params_display( $postID ) {
3099 - // Field definitions come from the admin class.
3103 + // Field definitions come from the admin class, scoped to the TASK's own
3104 + // connection (#277) so each row's parameters render against its MLS.
3100 3105 global $mlsimport;
3101 - $field_import = $mlsimport->admin->mlsimport_saas_return_mls_fields();
3106 + $field_import = $mlsimport->admin->mlsimport_saas_return_mls_fields( mlsimport_task_mls_id( (int) $postID ) );
3102 3107
3103 3108 // Fields whose stored value is always shown verbatim (never collapsed to "ALL").
3104 3109 $select_all_none = array(
3105 3110 'InternetAddressDisplayYN',
@@ -3229,9 +3234,15 @@
3229 3234 1 === (int) get_post_meta( $post->ID, 'mlsimport_item_stat_cron', true ),
3230 3235 time(),
3231 3236 // Watermarks are stored with wp_date() in site-local time, so
3232 3237 // the overdue cutoff must be built the same way to compare.
3233 - wp_date( 'Y-m-d\TH:i', time() - MLSIMPORT_TASK_HEALTH_OVERDUE_AFTER )
3238 + wp_date( 'Y-m-d\TH:i', time() - MLSIMPORT_TASK_HEALTH_OVERDUE_AFTER ),
3239 + // The hourly runner's own eligibility rule (GitHub issue #330):
3240 + // a task it will never pick up must not read as merely overdue.
3241 + mlsimport_cron_task_is_eligible(
3242 + (int) get_post_meta( $post->ID, 'mlsimport_initial_import_completed', true ),
3243 + (string) get_post_meta( $post->ID, 'mlsimport_spawn_status', true )
3244 + )
3234 3245 );
3235 3246 ?>
3236 3247 <span class="mlsimport-task-health mlsimport-task-health--<?php echo esc_attr( $health['level'] ); ?>">
3237 3248 <?php echo esc_html( $health['label'] ); ?>