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 / includes / class-mlsimport-stored-listing-fields.php

class-mlsimport-stored-listing-fields.php in MLSImport: IDX Plugin & MLS Plugin for Real Estate Listings 7.1.1, at includes/class-mlsimport-stored-listing-fields.php

198 lines 6.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Prepare selected RESO fields for one Stored Listing Write.
4 *
5 * This implementation owns the rules formerly copied across theme adapters:
6 * selection, scalar/array normalization, Rooms formatting, custom post-meta and
7 * taxonomy mapping, labels, administrator visibility, and configured ordering.
8 * It performs no WordPress writes; the listing module passes its projection to
9 * the persistence boundary and the active theme adapter.
10 *
11 * @package MLSImport
12 */
13
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit;
16 }
17
18 /**
19 * Convert raw extra_meta into common and theme-specific persistence groups.
20 */
21 final class Mlsimport_Stored_Listing_Fields {
22
23 /**
24 * Prepare every enabled extra_meta field in one ordered pass.
25 *
26 * Mapped values leave the adapter seam as common post meta or taxonomy data.
27 * Unmapped values retain their display label, administrator flag, and order
28 * so the adapter can store only its genuine repeater/custom-field variation.
29 *
30 * @param array<string, mixed> $property Incoming raw MLS property.
31 * @param array<string, mixed> $configuration Active Field Configuration.
32 * @return array<string, array<mixed>> Common and adapter field groups.
33 */
34 public function prepare( array $property, array $configuration ): array {
35 $result = array(
36 'post_meta' => array(),
37 'taxonomies' => array(),
38 'theme_fields' => array(),
39 );
40 $extra = is_array( $property['extra_meta'] ?? null ) ? $property['extra_meta'] : array();
41 $selected = is_array( $configuration['mls-fields'] ?? null )
42 ? $configuration['mls-fields']
43 : array();
44 $postmeta_map = is_array( $configuration['mls-fields-map-postmeta'] ?? null )
45 ? $configuration['mls-fields-map-postmeta']
46 : array();
47 $taxonomy_map = is_array( $configuration['mls-fields-map-taxonomy'] ?? null )
48 ? $configuration['mls-fields-map-taxonomy']
49 : array();
50 $labels = is_array( $configuration['mls-fields-label'] ?? null )
51 ? $configuration['mls-fields-label']
52 : array();
53 $admin = is_array( $configuration['mls-fields-admin'] ?? null )
54 ? $configuration['mls-fields-admin']
55 : array();
56 $order = $this->order_map( $configuration['field_order'] ?? array() );
57
58 foreach ( $extra as $field => $raw_value ) {
59 $field = (string) $field;
60 if ( 1 !== (int) ( $selected[ $field ] ?? 0 ) ) {
61 continue;
62 }
63
64 // Rooms has one cross-theme string format and one stable common key.
65 if ( 'Rooms' === $field && is_array( $raw_value ) ) {
66 $rooms = $this->format_rooms( $raw_value );
67 if ( '' !== $rooms ) {
68 $result['post_meta']['rooms'] = $rooms;
69 }
70 continue;
71 }
72
73 $value = $this->normalize_value( $raw_value );
74 $postmeta_key = trim( (string) ( $postmeta_map[ $field ] ?? '' ) );
75 if ( '' !== $postmeta_key ) {
76 $result['post_meta'][ $postmeta_key ] = $value;
77 continue;
78 }
79
80 $taxonomy = trim( (string) ( $taxonomy_map[ $field ] ?? '' ) );
81 if ( '' !== $taxonomy ) {
82 $label = trim( (string) ( $labels[ $field ] ?? '' ) );
83 if ( 'none' === strtolower( $label ) ) {
84 $label = '';
85 }
86 $term = trim( $label . ' ' . $value );
87 if ( '' !== $term ) {
88 $result['taxonomies'][ $taxonomy ] = array( $term );
89 }
90 continue;
91 }
92
93 $result['theme_fields'][] = array(
94 'field' => $field,
95 'label' => '' !== trim( (string) ( $labels[ $field ] ?? '' ) )
96 ? trim( (string) $labels[ $field ] )
97 : $field,
98 'value' => $value,
99 'admin' => 1 === (int) ( $admin[ $field ] ?? 0 ),
100 'order' => $order[ $field ] ?? PHP_INT_MAX,
101 );
102 }
103
104 usort(
105 $result['theme_fields'],
106 static function ( array $left, array $right ): int {
107 $order_compare = (int) $left['order'] <=> (int) $right['order'];
108 return 0 !== $order_compare ? $order_compare : strcmp( $left['field'], $right['field'] );
109 }
110 );
111 return $result;
112 }
113
114 /**
115 * Normalize scalar, list, and nested-array values to one stored string.
116 *
117 * @param mixed $value Raw RESO field value.
118 * @return string Trimmed single-line value with normalized comma spacing.
119 */
120 public function normalize_value( $value ): string {
121 if ( ! is_array( $value ) ) {
122 return (string) preg_replace( '/\s*,\s*/', ', ', trim( (string) $value ) );
123 }
124
125 $parts = array();
126 foreach ( $value as $part ) {
127 if ( is_array( $part ) ) {
128 $encoded = function_exists( 'wp_json_encode' ) ? wp_json_encode( $part ) : json_encode( $part );
129 if ( false !== $encoded && null !== $encoded ) {
130 $parts[] = $encoded;
131 }
132 continue;
133 }
134 $part = trim( (string) $part );
135 if ( '' !== $part ) {
136 $parts[] = $part;
137 }
138 }
139 return implode( ', ', $parts );
140 }
141
142 /**
143 * Format RESO Rooms as readable pipe-separated summaries.
144 *
145 * @param array<int, mixed> $rooms Raw RESO Rooms collection.
146 * @return string Formatted rooms, or an empty string when no row is usable.
147 */
148 private function format_rooms( array $rooms ): string {
149 $formatted = array();
150 foreach ( $rooms as $room ) {
151 if ( ! is_array( $room ) ) {
152 continue;
153 }
154 $type = trim( (string) ( $room['RoomType'] ?? '' ) );
155 if ( '' === $type ) {
156 continue;
157 }
158 $details = array();
159 $level = trim( (string) ( $room['RoomLevel'] ?? '' ) );
160 if ( '' !== $level ) {
161 $details[] = $level;
162 }
163 $length = trim( (string) ( $room['RoomLength'] ?? '' ) );
164 $width = trim( (string) ( $room['RoomWidth'] ?? '' ) );
165 $units = trim( (string) ( $room['RoomLengthWidthUnits'] ?? '' ) );
166 $size = '' !== $length && '' !== $width ? $length . ' x ' . $width : $length . $width;
167 if ( '' !== $size ) {
168 $details[] = trim( $size . ' ' . $units );
169 } elseif ( '' !== $units ) {
170 $details[] = $units;
171 }
172 $formatted[] = $type . ( empty( $details ) ? '' : ': ' . implode( ', ', $details ) );
173 }
174 return implode( ' | ', $formatted );
175 }
176
177 /**
178 * Accept both ordered field-name lists and older field=>position maps.
179 *
180 * @param mixed $saved_order Field Configuration order value.
181 * @return array<string, int> Field name to zero-based order.
182 */
183 private function order_map( $saved_order ): array {
184 if ( ! is_array( $saved_order ) ) {
185 return array();
186 }
187 $map = array();
188 foreach ( $saved_order as $key => $value ) {
189 if ( is_int( $key ) ) {
190 $map[ (string) $value ] = $key;
191 } else {
192 $map[ (string) $key ] = (int) $value;
193 }
194 }
195 return $map;
196 }
197 }
198