PluginProbe
Import WP – CSV & XML Import Export for WordPress / trunk
Import WP – CSV & XML Import Export for WordPress vtrunk
2.14.24 2.14.23 2.7.0 2.7.1 2.7.10 2.7.11 2.7.12 2.7.13 2.7.14 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.8.0 2.8.1 2.8.2 2.8.3 2.9.0 2.9.1 trunk 0.1.6 All 142 releases
jc-importer / class / Common / Exporter / File / XMLFile.php

XMLFile.php in Import WP – CSV & XML Import Export for WordPress trunk, at class/Common/Exporter/File/XMLFile.php

331 lines 10.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace ImportWP\Common\Exporter\File;
4
5 use ImportWP\Common\Exporter\Mapper\MapperData;
6
7 class XMLFile extends File
8 {
9 private $template;
10 private $template_loops;
11 private $template_sections = [];
12 private $template_data = [];
13 private $i = -1;
14 private $setup = false;
15
16 public function start()
17 {
18 // Generating a template, allows at a later date for custom templates to be added via user.
19 $this->template = $this->generateTemplate();
20
21 // Parse Template <!-- ewp:loop {"loop": "post"} -->
22 preg_match_all('/<!--\s*(\/?)ewp:loop\s*(\{.*?\})?\s*-->/', $this->template, $this->template_loops, PREG_OFFSET_CAPTURE);
23
24 // generate template loop data from matches
25 $last = $this->template_loops[0][count($this->template_loops[0]) - 1];
26 $this->template_sections['start'] = substr($this->template, 0, $this->template_loops[0][0][1]); // + strlen($this->template_loops[0][0][0]));
27 $this->template_sections['end'] = substr($this->template, $last[1] + strlen($last[0]));
28
29 fputs($this->fh, $this->template_sections['start'] . PHP_EOL);
30
31 $data = $this->buildTemplateDataStructure([]);
32 $this->template_data = $data[0];
33
34 update_option('iwp_exporter_xml_config', [
35 'template' => $this->template,
36 'template_sections' => $this->template_sections,
37 'template_data' => $this->template_data
38 ]);
39 }
40
41 public function loadConfig()
42 {
43
44 if (!$this->setup) {
45 $config = get_option('iwp_exporter_xml_config');
46 $this->template = $config['template'];
47 $this->template_sections = $config['template_sections'];
48 $this->template_data = $config['template_data'];
49 $this->setup = true;
50 }
51 }
52
53 public function buildTemplateDataStructure($data)
54 {
55 $this->i++;
56
57 if (count($this->template_loops[0]) < $this->i + 1) {
58 return $data;
59 }
60
61 $is_opener = $this->template_loops[1][$this->i][0] !== '/';
62 if ($is_opener) {
63
64 $row = [];
65 $row['id'] = $this->template_loops[0][$this->i][0];
66 $row['args'] = json_decode($this->template_loops[2][$this->i][0], true);
67 $row['start'] = $this->template_loops[0][$this->i][1];
68 $row['children'] = $this->buildTemplateDataStructure([]);
69 $row['end'] = $this->template_loops[0][$this->i][1];
70
71 $start_with_offset = $row['start'] + strlen($row['id']);
72
73 $row['template'] = [];
74
75 if (!empty($row['children'])) {
76
77 // start
78 $row['template']['open'] = trim(substr($this->template, $start_with_offset, $row['children'][0]['start'] - $start_with_offset));
79
80 // inbetween parts
81 if (count($row['children']) > 1) {
82
83 $tmp = [];
84 $tmp[] = $row['children'][0];
85
86 for ($i = 1; $i < count($row['children']); $i++) {
87 $prev = $row['children'][$i - 1];
88 $current = $row['children'][$i];
89 $end_with_offset = $prev['end'] + strlen($this->template_loops[0][$this->i][0]);
90 $tmp[] = trim(substr($this->template, $end_with_offset, $current['start'] - $end_with_offset));
91 $tmp[] = $row['children'][$i];
92 }
93
94 $row['children'] = $tmp;
95 }
96
97 // end
98
99 $prev_index = $this->i - 1;
100
101 $end_start = $this->template_loops[0][$prev_index][1] + strlen($this->template_loops[0][$prev_index][0]);
102 $end_end = $this->template_loops[0][$this->i][1];
103
104 $row['template']['close'] = trim(substr($this->template, $end_start, $end_end - $end_start));
105
106 // $next_index = $this->i + 1 == count($this->template_loops[0]) ? -1 : $this->i + 1;
107 // $end_with_offset = $row['end'] + strlen($this->template_loops[0][$this->i][0]);
108 // if ($next_index == -1) {
109 // $row['template'][] = trim(substr($this->template, $end_with_offset));
110 // } else {
111 // $row['template'][] = trim(substr($this->template, $end_with_offset, $this->template_loops[0][$next_index][1] - $end_with_offset));
112 // }
113 } else {
114 $row['template']['main'] = trim(substr($this->template, $start_with_offset, $row['end'] - $start_with_offset));
115 }
116
117 $data[] = $row;
118
119 return $this->buildTemplateDataStructure($data);
120 }
121
122 return $data;
123 }
124
125 public function generateTemplate()
126 {
127 $fields = $this->exporter->getFields();
128 $template = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL;
129 $template .= $this->recursivelyGenerateXML($fields);
130 return $template;
131 }
132
133 public function recursivelyGenerateXML($fields, $parent = 0, $schema = '', $loop = null)
134 {
135 $current_items = array_filter($fields, function ($item) use ($parent) {
136 return intval($item['parent']) == $parent;
137 });
138
139 // move attributes to top
140 usort($current_items, function ($a, $b) {
141
142 $found_a = isset($a['label']) && strpos($a['label'], '@') === 0;
143 $found_b = isset($b['label']) && strpos($b['label'], '@') === 0;
144
145 if ($found_a && !$found_b) {
146 return -1;
147 } elseif (!$found_a && $found_b) {
148 return 1;
149 }
150
151 return 0;
152 });
153
154
155
156 if (!empty($current_items)) {
157 foreach ($current_items as $current_item) {
158
159 $label = $this->getFieldLabel($current_item);
160
161 $is_attr = strpos($label, '@') === 0;
162
163 if ($is_attr) {
164
165 $label = $this->esc_attr($label);
166
167 // we are an attribute
168 if (isset($current_item['selection']) && !empty($current_item['selection'])) {
169
170 $selection = $current_item['selection'];
171 if (!isset($current_item['custom']) || $current_item['custom'] !== 'true') {
172 $selection = '{' . $selection . ' | ' . wp_json_encode(["escape" => true]) . '}';
173 }
174
175 $schema .= ' ' . $label . '="' . $selection . '"';
176 }
177 continue;
178 }
179
180 if (!$this->hasClosingTag($schema)) {
181 $schema = $this->checkForClosingTag($schema);
182 $schema .= "\n";
183 }
184
185 $label = $this->esc_label($label);
186
187 if (isset($current_item['loop']) && ($current_item['loop'] === 'true' || $current_item['loop'] === true)) {
188
189 $schema .= '<!-- ewp:loop ' . wp_json_encode(['loop' => $current_item['selection']]) . ' -->' . "\n";
190
191 $schema .= '<' . $label;
192 $schema = $this->recursivelyGenerateXML($fields, $current_item['id'], $schema, $current_item['selection']);
193 $schema = $this->checkForClosingTag($schema) . "\n";
194
195 $schema .= '</' . $label . '>' . "\n";
196
197 $schema .= '<!-- /ewp:loop -->' . "\n";
198 } else {
199
200 //TODO: if data is array, repeat
201 $schema .= '<' . $label;
202
203 $schema = $this->recursivelyGenerateXML($fields, $current_item['id'], $schema, $loop);
204
205 $schema = $this->checkForClosingTag($schema);
206
207 if (isset($current_item['selection']) && !empty($current_item['selection'])) {
208
209 $selection = $current_item['selection'];
210 if (!isset($current_item['custom']) || $current_item['custom'] !== 'true') {
211 $selection = '<![CDATA[{' . $selection . '}]]>';
212 }
213
214 $schema .= $selection;
215 }
216
217 $schema .= '</' . $label . '>' . "\n";
218 }
219 }
220 }
221
222 return $schema;
223 }
224
225 public function esc_label($label)
226 {
227
228 $label = str_replace(' ', '_', $label);
229 return $label;
230 }
231
232 public function esc_attr($attr)
233 {
234
235 // remove @ from start
236 $attr = substr($attr, 1);
237 $attr = str_replace(' ', '_', $attr);
238 return $attr;
239 }
240
241 /**
242 * @param MapperData $mapper
243 * @return void
244 */
245 public function add($mapper)
246 {
247 $this->loadConfig();
248 $output = $this->processLoop($this->template_data, $mapper);
249 fputs($this->fh, $output);
250 }
251
252 /**
253 * @param array $template_data
254 * @param MapperData $mapper
255 */
256 public function processLoop($template_data, $mapper, $loop_args = [], $depth = 0)
257 {
258 $output = '';
259
260 if (isset($template_data['args']) && $depth > 0) {
261 $loop_args = $template_data['args'];
262 }
263
264 $output .= PHP_EOL . '<!-- processLoop ' . wp_json_encode($loop_args) . ' -->' . PHP_EOL;
265
266 // TODO: get loop data and replace template variables
267 $loop_data = $mapper->data($loop_args);
268 foreach ($loop_data as $data) {
269
270 if (isset($template_data['template']['open'])) {
271 $output .= $mapper->template($template_data['template']['open'], $data);
272 }
273
274 if (!empty($template_data['children'])) {
275 foreach ($template_data['children'] as $child) {
276 if (is_array($child)) {
277 $output .= $this->processLoop($child, $mapper, $loop_args, $depth + 1);
278 } else {
279 $output .= $mapper->template($child, $data);
280 }
281 }
282 } elseif (isset($template_data['template']['main'])) {
283 $output .= $mapper->template($template_data['template']['main'], $data);
284 }
285
286 if (isset($template_data['template']['close'])) {
287 $output .= $mapper->template($template_data['template']['close'], $data);
288 }
289 }
290
291 $output .= PHP_EOL . '<!-- /processLoop -->' . PHP_EOL;
292
293 return $output;
294 }
295
296 public function checkForClosingTag($output)
297 {
298 $tmp = trim($output);
299 if (strlen($tmp) > 1 && substr($tmp, -1) !== '>') {
300 $output .= '>';
301 }
302 return $output;
303 }
304
305 public function hasClosingTag($output)
306 {
307 $tmp = trim($output);
308 if (strlen($tmp) > 1 && substr($tmp, -1) !== '>') {
309 return false;
310 }
311 return true;
312 }
313
314 public function indent($depth)
315 {
316 return str_repeat("\t", $depth + 1);
317 }
318
319 public function end()
320 {
321 $this->loadConfig();
322 fputs($this->fh, $this->template_sections['end'] . PHP_EOL);
323 fclose($this->fh);
324 }
325
326 public function get_file_name()
327 {
328 return $this->exporter->getId() . '.xml';
329 }
330 }
331