PluginProbe ʕ •ᴥ•ʔ
WP All Import – Drag & Drop Import for CSV, XML, Excel & Google Sheets / trunk
WP All Import – Drag & Drop Import for CSV, XML, Excel & Google Sheets vtrunk
4.1.1 3.9.5 3.9.6 4.0.0 4.0.1 4.1.0 trunk 2.12 2.13 2.14 3.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.6 3.4.7 3.4.8 3.4.9 3.5.0 3.5.1 3.5.2 3.5.3 3.5.4 3.5.5 3.5.6 3.5.7 3.5.8 3.5.9 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.6.9 3.7.0 3.7.1 3.7.2 3.7.3 3.7.3-beta-1.0 3.7.4 3.7.4-beta-1.0 3.7.5 3.7.6 3.7.7 3.7.8 3.7.9 3.8.0 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4
wp-all-import / addon-api / fields / repeater.php
wp-all-import / addon-api / fields Last commit date
checkbox.php 1 month ago date.php 1 month ago datetime.php 1 month ago field.php 1 month ago gallery.php 1 month ago map.php 1 month ago media-url.php 1 month ago media.php 1 month ago number.php 1 month ago post.php 1 month ago radio.php 1 month ago repeater.php 1 month ago select.php 1 month ago switcher.php 1 month ago text.php 1 month ago time.php 1 month ago toggle.php 1 month ago user.php 1 month ago
repeater.php
252 lines
1 <?php
2
3 namespace Wpai\AddonAPI;
4
5 if ( ! defined( 'ABSPATH' ) ) exit;
6
7 class PMXI_Addon_Repeater_Field extends PMXI_Addon_Field {
8
9 /*
10 * Parse the repeater and its subfields
11 */
12 public function beforeImport($postId, $value, $data, $logger, $rawData) {
13 $mode = $value['mode'] ?? 'fixed';
14 $ignore_blanks = (bool) ($value['ignore_blanks'] ?? false);
15
16 $parseFunction = [
17 'variable-xml' => 'parseVariableXml',
18 'variable-csv' => 'parseVariableCsv',
19 'fixed' => 'parseFixed'
20 ][$mode];
21
22 $rows = $this->$parseFunction($postId, $value, $data, $logger, $rawData);
23
24 return $ignore_blanks ? $this->filterOutBlankRows($rows) : $rows;
25 }
26
27 /*
28 * Determine whether a row can be imported by checking if it has any non-empty values
29 * @param $row array
30 * @return bool
31 */
32 public static function canImportRow($row) {
33 $filtered = array_filter($row, fn ($value) => !empty($value));
34 return count($filtered) > 0;
35 }
36
37 /*
38 * Get the row field value given a xpath.
39 * @param $xml string
40 * @param $rootNodeXPath string
41 * @param $xpath string|array
42 * @return mixed
43 */
44 public function getRowFieldValue($xml, $rootNodeXPath, $xpath, $index) {
45 if (is_array($xpath)) {
46 $values = [];
47 foreach ($xpath as $key => $nestedXpath) {
48 // For some reason, the XML parsed doesn't like empty strings and will go into an infinite loop.
49 $values[$key] = $nestedXpath ? $this->getRowFieldValue($xml, $rootNodeXPath, $nestedXpath, $index) : $nestedXpath;
50 }
51 return $values;
52 }
53
54 $file = false;
55 $parsed = \XmlImportParser::factory($xml, $rootNodeXPath . '[' . ($index + 1) . ']', $xpath, $file)->parse();
56 wp_delete_file($file);
57
58 return $parsed[0] ?? '';
59 }
60
61 /*
62 * Parse XML rows
63 * @param $xml string
64 * @param $cxpath string
65 * @param $template array
66 * @return array
67 */
68 public function parseXmlRows($xml, $rootNodeXPath, $template) {
69 $file = false;
70 $parsed_rows = \XmlImportParser::factory($xml, $rootNodeXPath, "{.}", $file)->parse();
71 wp_delete_file($file);
72
73 $rows = [];
74
75 for ($i = 0; $i < count($parsed_rows); $i++) {
76 $row = [];
77
78 foreach ($template as $key => $xpath) {
79 $row[$key] = $this->getRowFieldValue($xml, $rootNodeXPath, $xpath, $i);
80 }
81
82 $rows[$i] = $row;
83 }
84
85 return $rows;
86 }
87
88 /*
89 * Parse Variable XML
90 * @param $postId int
91 * @param $value array
92 * @param $data array
93 * @param $logger callable
94 * @param $rawData array
95 * @return array
96 */
97 public function parseVariableXml($postId, $value, $data, $logger, $rawData) {
98 $template_rows = $rawData['rows'] ?? [];
99 $template = array_shift($template_rows);
100 $xml_for_each = ltrim(trim($rawData['foreach'] ?? '', '{}!'), '/');
101
102 // Empty foreach must not leave a trailing slash on the xpath.
103 $repeater_xpath = '[' . ($data['i'] + 1) . ']' . ($xml_for_each !== '' ? '/' . $xml_for_each : '');
104 $xpath = $data['xpath_prefix'] . $data['import']->xpath . $repeater_xpath;
105
106 $row_data = [];
107 $rows = $this->parseXmlRows($data['xml'], $xpath, $template);
108
109 foreach ($rows as $index => $row) {
110 foreach ($this->subfields as $subfield) {
111 $field_instance = PMXI_Addon_Field::from($subfield, $this->view, $this);
112 $field_value = $row[$subfield['key']];
113 $field_value_raw = $template[$subfield['key']];
114
115 $row_data[$index][$subfield['key']] = $field_instance->beforeImport(
116 $postId,
117 $field_value,
118 $data,
119 $logger,
120 $field_value_raw
121 );
122 }
123 }
124
125 return $row_data;
126 }
127
128 /*
129 * Handle complex field types like Media, Gallery, and Posts.
130 */
131 public function formatFieldValue($value, $delimiter, $repeater_path) {
132 if (isset($repeater_path)) {
133 $nested_path_values = explode($delimiter, $value[$repeater_path]);
134 $new_value = [];
135
136 foreach ($nested_path_values as $nested_value) {
137 $new_value[] = array_merge(
138 $value,
139 [$repeater_path => $nested_value]
140 );
141 }
142
143 return $new_value;
144 }
145
146 if (is_array($value)) {
147 return $value;
148 }
149
150 return explode($delimiter, $value);
151 }
152
153 /*
154 * Parse Variable CSV
155 * @param $postId int
156 * @param $value array
157 * @param $data array
158 * @param $logger callable
159 * @param $rawData array
160 * @return array
161 */
162 public function parseVariableCsv($postId, $value, $data, $logger, $rawData) {
163 $rows = $value['rows'] ?? [];
164 $row = array_shift($rows);
165 $template_rows = $rawData['rows'] ?? [];
166 $template = array_shift($template_rows);
167 $delimiter = $value['separator'] ?? '|';
168 $row_data = [];
169
170 foreach ($this->subfields as $subfield) {
171 if (empty($row)) continue;
172 if (empty($row[$subfield['key']])) continue;
173
174 $field_instance = PMXI_Addon_Field::from($subfield, $this->view, $this);
175 $field_value = $row[$subfield['key']];
176 $field_value = $this->formatFieldValue(
177 $field_value,
178 $delimiter,
179 $field_instance::$repeater_path
180 );
181 $field_value_raw = $template[$subfield['key']];
182
183 // Loop through each value and parse it as a field.
184 $current_row = array_map(
185 fn ($value) =>
186 $field_instance->beforeImport(
187 $postId,
188 $value,
189 $data,
190 $logger,
191 $field_value_raw
192 ),
193 $field_value
194 );
195
196
197 foreach ($current_row as $index => $v) {
198 $row_data[$index][$subfield['key']] = $v;
199 }
200 }
201
202 return $row_data;
203 }
204
205 /*
206 * Parse Fixed Mode
207 * @param $postId int
208 * @param $value array
209 * @param $data array
210 * @param $logger callable
211 * @param $rawData array
212 * @return array
213 */
214 public function parseFixed($postId, $value, $data, $logger, $rawData) {
215 $template_rows = $rawData['rows'] ?? [];
216 $template = array_shift($template_rows);
217 $rows = $value['rows'] ?? [];
218 $row_data = [];
219
220 foreach ($rows as $index => $row) {
221 foreach ($this->subfields as $subfield) {
222 if (empty($row)) continue;
223
224 $field_instance = PMXI_Addon_Field::from($subfield, $this->view, $this);
225 $field_value = $row[$subfield['key']];
226 $field_value_raw = $template[$subfield['key']];
227
228 $current_row = $field_instance->beforeImport(
229 $postId,
230 $field_value,
231 $data,
232 $logger,
233 $field_value_raw
234 );
235
236 $row_data[$index][$subfield['key']] = $current_row;
237 }
238 }
239
240 return $row_data;
241 }
242
243 public function filterOutBlankRows($rows) {
244 return array_values(
245 array_filter(
246 $rows,
247 [__CLASS__, 'canImportRow']
248 )
249 );
250 }
251 }
252