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
mlsimport / includes / mlsimport-settings-transfer.php

mlsimport-settings-transfer.php in MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings 7.2, at includes/mlsimport-settings-transfer.php

156 lines 6.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Settings export/import payload transfer (issue #275, spec #273/#264).
4 *
5 * WHY THIS FILE EXISTS
6 * --------------------
7 * The plugin's settings import feature accepts one JSON payload (pasted into
8 * the administrative/import options) and restores the field-mapping and sync
9 * option groups from it. Historically that payload carried ONE flat copy of
10 * each group. With multi-MLS, field selection and sync settings are
11 * per-connection (#264), so the payload must round-trip one section PER
12 * CONNECTION, keyed by mls_id.
13 *
14 * PAYLOAD SHAPE
15 * -------------
16 * New exports carry:
17 * mlsimport_connections_settings: {
18 * "<mls_id>": {
19 * mlsimport_admin_fields_select: {...}, // that connection's mapping
20 * mlsimport_admin_mls_sync: {...} // that connection's sync settings
21 * }, ...
22 * }
23 * plus the legacy flat keys for the CURRENT connection (old importers can
24 * still read a new export) and the untouched global groups
25 * (mlsimport_admin_import_options, mlsimport_admin_use_transients).
26 *
27 * IMPORT RULE (one rule): when the per-connection block is present it is
28 * authoritative and the legacy flat keys are ignored; an old flat-only
29 * payload restores into the CURRENT connection exactly as before.
30 *
31 * Both legacy import entry points in the admin class delegate here so the
32 * decode-and-restore logic exists once.
33 *
34 * @since 7.2.0
35 * @package Mlsimport
36 */
37
38 if ( ! defined( 'ABSPATH' ) ) {
39 exit;
40 }
41
42 /**
43 * Build the complete exportable settings payload.
44 *
45 * Step by step:
46 * 1. Start with the two global (connection-agnostic) groups, unchanged.
47 * 2. Add the legacy flat sections holding the CURRENT connection's values so
48 * a pre-multi-MLS site can still import a payload exported here.
49 * 3. Add one section per registered connection, keyed by mls_id, each
50 * carrying that connection's field selection and sync settings read
51 * through the per-connection resolver.
52 *
53 * @return array JSON-encodable settings payload.
54 */
55 function mlsimport_export_settings_payload(): array {
56 // Step 1: global groups are not per-connection (#264 leaves them alone).
57 $payload = array(
58 'mlsimport_admin_import_options' => get_option( 'mlsimport_admin_import_options', array() ),
59 'mlsimport_admin_use_transients' => get_option( 'mlsimport_admin_use_transients', '' ),
60 );
61
62 // Step 2: legacy flat sections = the current connection's values.
63 $payload['mlsimport_admin_fields_select'] = mlsimport_get_connection_option( 'mlsimport_admin_fields_select', array() );
64 $payload['mlsimport_admin_mls_sync'] = mlsimport_get_connection_option( 'mlsimport_admin_mls_sync', array() );
65
66 // Step 3: one authoritative section per connection, keyed by mls_id
67 // (JSON-encoding turns the keys into strings; import casts them back).
68 $payload['mlsimport_connections_settings'] = array();
69 foreach ( Mlsimport_Connections::all() as $mls_id => $record ) {
70 $payload['mlsimport_connections_settings'][ $mls_id ] = array(
71 'mlsimport_admin_fields_select' => mlsimport_get_connection_option( 'mlsimport_admin_fields_select', array(), $mls_id ),
72 'mlsimport_admin_mls_sync' => mlsimport_get_connection_option( 'mlsimport_admin_mls_sync', array(), $mls_id ),
73 );
74 }
75
76 return $payload;
77 }
78
79 /**
80 * Restore settings from a decoded import payload.
81 *
82 * Step by step:
83 * 1. Global groups restore as-is when present (unchanged behavior).
84 * 2. A payload WITH the per-connection block restores each listed
85 * connection's field selection (through that connection's own
86 * Field Configuration module, so normalization/revision rules apply)
87 * and sync settings into its suffixed options.
88 * 3. A payload WITHOUT the block is a legacy flat export: its two flat
89 * sections restore into the CURRENT connection, exactly as before.
90 *
91 * @param array $decode Decoded JSON payload.
92 * @return void
93 */
94 function mlsimport_import_settings_payload( array $decode ): void {
95 // Step 1: connection-agnostic groups.
96 if ( isset( $decode['mlsimport_admin_import_options'] ) && is_array( $decode['mlsimport_admin_import_options'] ) ) {
97 update_option( 'mlsimport_admin_import_options', $decode['mlsimport_admin_import_options'] );
98 }
99 if ( isset( $decode['mlsimport_admin_use_transients'] ) ) {
100 update_option( 'mlsimport_admin_use_transients', $decode['mlsimport_admin_use_transients'] );
101 }
102
103 // Step 2: multi-MLS payload — the per-connection block is authoritative.
104 if ( isset( $decode['mlsimport_connections_settings'] ) && is_array( $decode['mlsimport_connections_settings'] ) ) {
105 foreach ( $decode['mlsimport_connections_settings'] as $mls_id => $sections ) {
106 $mls_id = (int) $mls_id;
107 if ( $mls_id <= 0 || ! is_array( $sections ) ) {
108 continue;
109 }
110 if ( isset( $sections['mlsimport_admin_fields_select'] ) && is_array( $sections['mlsimport_admin_fields_select'] ) ) {
111 mlsimport_import_field_configuration( $sections['mlsimport_admin_fields_select'], $mls_id );
112 }
113 if ( isset( $sections['mlsimport_admin_mls_sync'] ) && is_array( $sections['mlsimport_admin_mls_sync'] ) ) {
114 mlsimport_update_connection_option( 'mlsimport_admin_mls_sync', $sections['mlsimport_admin_mls_sync'], $mls_id );
115 }
116 }
117 return;
118 }
119
120 // Step 3: legacy flat payload — restore into the current connection.
121 if ( isset( $decode['mlsimport_admin_fields_select'] ) && is_array( $decode['mlsimport_admin_fields_select'] ) ) {
122 mlsimport_import_field_configuration( $decode['mlsimport_admin_fields_select'] );
123 }
124 if ( isset( $decode['mlsimport_admin_mls_sync'] ) ) {
125 mlsimport_update_connection_option( 'mlsimport_admin_mls_sync', $decode['mlsimport_admin_mls_sync'] );
126 }
127 }
128
129 /**
130 * Validate and import a settings JSON document from the admin UI.
131 *
132 * Keeping JSON decoding outside the renderer gives every future UI the same
133 * all-or-nothing boundary: malformed input is rejected before the payload
134 * importer can update a single option.
135 *
136 * @param string $json Raw JSON document.
137 * @return array{success: bool, code: string}
138 */
139 function mlsimport_import_settings_json( string $json ): array {
140 $decoded_object = json_decode( trim( $json ) );
141 if ( JSON_ERROR_NONE !== json_last_error() || ! is_object( $decoded_object ) ) {
142 return array(
143 'success' => false,
144 'code' => 'invalid_json_object',
145 );
146 }
147
148 $decoded = json_decode( trim( $json ), true );
149 mlsimport_import_settings_payload( is_array( $decoded ) ? $decoded : array() );
150
151 return array(
152 'success' => true,
153 'code' => 'imported',
154 );
155 }
156