PluginProbe
Import WP – CSV & XML Import Export for WordPress / 2.15.0
Import WP – CSV & XML Import Export for WordPress v2.15.0
2.15.1 2.15.0 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 All 144 releases
← All changes | class/Common/Importer/Template/PostTemplate.php +341 -108 2.8.3 → 2.15.0 View file →
@@ -17,12 +17,12 @@
17 17 protected $name = 'Post';
18 18 protected $mapper = 'post';
19 19 protected $field_map = [
20 20 'ID' => 'post.ID',
21 + 'post_name' => 'post.post_name',
21 22 'post_title' => 'post.post_title',
22 23 'post_content' => 'post.post_content',
23 24 'post_excerpt' => 'post.post_excerpt',
24 - 'post_name' => 'post.post_name',
25 25 'post_status' => 'post.post_status',
26 26 'menu_order' => 'post.menu_order',
27 27 'post_password' => 'post.post_password',
28 28 'post_date' => 'post.post_date',
@@ -61,8 +61,10 @@
61 61 $this->field_options = array_merge($this->field_options, [
62 62 'post._parent.parent' => [$this, 'get_post_parent_options'],
63 63 'taxonomies.*.tax' => [$this, 'get_taxonomy_options'],
64 64 ]);
65 +
66 + $this->default_enabled_fields[] = 'post.post_status';
65 67 }
66 68
67 69 /**
68 70 * @param string $message
@@ -80,9 +82,9 @@
80 82 }
81 83 }
82 84
83 85 if (!empty($this->_attachments)) {
84 - $message .= ', Attachments: (' . implode(', ', $this->_attachments) . ')';
86 + $message .= sprintf(__(', Attachments: (%s)', 'jc-importer'), implode(', ', $this->_attachments));
85 87 }
86 88
87 89 return $message;
88 90 }
@@ -91,98 +93,98 @@
91 93 {
92 94 $groups = [];
93 95
94 96 // Post
95 - $groups[] = $this->register_group('Post Fields', 'post', [
96 - $this->register_field('ID', 'ID', [
97 - 'tooltip' => __('ID is only used to reference existing records', 'importwp')
97 + $groups[] = $this->register_group(__('Post Fields', 'jc-importer'), 'post', [
98 + $this->register_field(__('ID', 'jc-importer'), 'ID', [
99 + 'tooltip' => __('ID is only used to reference existing records', 'jc-importer')
98 100 ]),
99 - $this->register_core_field('Title', 'post_title', [
100 - 'tooltip' => __('Title of the post.', 'importwp')
101 + $this->register_core_field(__('Title', 'jc-importer'), 'post_title', [
102 + 'tooltip' => __('Title of the post.', 'jc-importer')
101 103 ]),
102 - $this->register_core_field('Content', 'post_content', [
103 - 'tooltip' => __('Main WYSIWYG editor content of the post.', 'importwp')
104 + $this->register_core_field(__('Content', 'jc-importer'), 'post_content', [
105 + 'tooltip' => __('Main WYSIWYG editor content of the post.', 'jc-importer')
104 106 ]),
105 - $this->register_field('Excerpt', 'post_excerpt', [
106 - 'tooltip' => __('A custom short extract for the post.', 'importwp')
107 + $this->register_field(__('Excerpt', 'jc-importer'), 'post_excerpt', [
108 + 'tooltip' => __('A custom short extract for the post.', 'jc-importer')
107 109 ]),
108 - $this->register_field('Slug', 'post_name', [
109 - 'tooltip' => __('The slug is the user friendly and URL valid name of the post.', 'importwp')
110 + $this->register_field(__('Slug', 'jc-importer'), 'post_name', [
111 + 'tooltip' => __('The slug is the user friendly and URL valid name of the post.', 'jc-importer')
110 112 ]),
111 - $this->register_field('Status', 'post_status', [
113 + $this->register_field(__('Status', 'jc-importer'), 'post_status', [
112 114 'default' => 'publish',
113 115 'options' => [
114 - ['value' => 'draft', 'label' => 'Draft'],
115 - ['value' => 'publish', 'label' => 'Published'],
116 - ['value' => 'pending', 'label' => 'Pending'],
117 - ['value' => 'future', 'label' => 'Future'],
118 - ['value' => 'private', 'label' => 'Private'],
119 - ['value' => 'trash', 'label' => 'Trash']
116 + ['value' => 'draft', 'label' => __('Draft', 'jc-importer')],
117 + ['value' => 'publish', 'label' => __('Published', 'jc-importer')],
118 + ['value' => 'pending', 'label' => __('Pending', 'jc-importer')],
119 + ['value' => 'future', 'label' => __('Future', 'jc-importer')],
120 + ['value' => 'private', 'label' => __('Private', 'jc-importer')],
121 + ['value' => 'trash', 'label' => __('Trash', 'jc-importer')]
120 122 ],
121 - 'tooltip' => __('Whether the post can accept comments. Accepts open or closed', 'importwp')
123 + 'tooltip' => __('The status of a given post determines how WordPress handles that post', 'jc-importer')
122 124 ]),
123 - $this->register_group('Parent Settings', '_parent', [
124 - $this->register_field('Parent', 'parent', [
125 + $this->register_group(__('Parent Settings', 'jc-importer'), '_parent', [
126 + $this->register_field(__('Parent', 'jc-importer'), 'parent', [
125 127 'default' => '',
126 128 'options' => 'callback',
127 - 'tooltip' => __('Set this for the post it belongs to', 'importwp')
129 + 'tooltip' => __('Set this for the post it belongs to', 'jc-importer')
128 130 ]),
129 - $this->register_field('Parent Field Type', '_parent_type', [
131 + $this->register_field(__('Parent Field Type', 'jc-importer'), '_parent_type', [
130 132 'default' => 'id',
131 133 'options' => [
132 - ['value' => 'id', 'label' => 'ID'],
133 - ['value' => 'slug', 'label' => 'Slug'],
134 - ['value' => 'name', 'label' => 'Name'],
135 - ['value' => 'column', 'label' => 'Reference Column'],
134 + ['value' => 'id', 'label' => __('ID', 'jc-importer')],
135 + ['value' => 'slug', 'label' => __('Slug', 'jc-importer')],
136 + ['value' => 'name', 'label' => __('Name', 'jc-importer')],
137 + ['value' => 'column', 'label' => __('Reference Column', 'jc-importer')],
136 138 ],
137 139 'type' => 'select',
138 - 'tooltip' => __('Select how the parent field should be handled', 'importwp')
140 + 'tooltip' => __('Select how the parent field should be handled', 'jc-importer')
139 141 ]),
140 - $this->register_field('Parent Reference Column', '_parent_ref', [
142 + $this->register_field(__('Parent Reference Column', 'jc-importer'), '_parent_ref', [
141 143 'condition' => ['_parent_type', '==', 'column'],
142 - 'tooltip' => __('Select the column/node that the parent field is referencing', 'importwp')
144 + 'tooltip' => __('Select the column/node that the parent field is referencing', 'jc-importer')
143 145 ])
144 146 ]),
145 - $this->register_field('Order', 'menu_order', [
146 - 'tooltip' => __('The order the post should be displayed in', 'importwp')
147 + $this->register_field(__('Order', 'jc-importer'), 'menu_order', [
148 + 'tooltip' => __('The order the post should be displayed in', 'jc-importer')
147 149 ]),
148 - $this->register_group('Author Settings', '_author', [
149 - $this->register_field('Author', 'post_author', [
150 - 'tooltip' => __('The user of who added this post', 'importwp')
150 + $this->register_group(__('Author Settings', 'jc-importer'), '_author', [
151 + $this->register_field(__('Author', 'jc-importer'), 'post_author', [
152 + 'tooltip' => __('The user of who added this post', 'jc-importer')
151 153 ]),
152 - $this->register_field('Author Field Type', '_author_type', [
154 + $this->register_field(__('Author Field Type', 'jc-importer'), '_author_type', [
153 155 'default' => 'id',
154 156 'options' => [
155 - ['value' => 'id', 'label' => 'ID'],
156 - ['value' => 'login', 'label' => 'Login'],
157 - ['value' => 'email', 'label' => 'Email'],
157 + ['value' => 'id', 'label' => __('ID', 'jc-importer')],
158 + ['value' => 'login', 'label' => __('Login', 'jc-importer')],
159 + ['value' => 'email', 'label' => __('Email', 'jc-importer')],
158 160 ],
159 - 'tooltip' => __('Select how the author field should be handled', 'importwp')
161 + 'tooltip' => __('Select how the author field should be handled', 'jc-importer')
160 162 ])
161 163 ]),
162 - $this->register_field('Password', 'post_password', [
163 - 'tooltip' => __('The password to access the post', 'importwp')
164 + $this->register_field(__('Password', 'jc-importer'), 'post_password', [
165 + 'tooltip' => __('The password to access the post', 'jc-importer')
164 166 ]),
165 - $this->register_field('Date', 'post_date', [
166 - 'tooltip' => __('The date of the post , enter in the format "YYYY-MM-DD HH:ii:ss"', 'importwp')
167 + $this->register_field(__('Date', 'jc-importer'), 'post_date', [
168 + 'tooltip' => __('The date of the post , enter in the format "YYYY-MM-DD HH:ii:ss"', 'jc-importer')
167 169 ]),
168 - $this->register_field('Allow Comments', 'comment_status', [
170 + $this->register_field(__('Allow Comments', 'jc-importer'), 'comment_status', [
169 171 'options' => [
170 - ['value' => '0', 'label' => 'Disabled'],
171 - ['value' => '1', 'label' => 'Enabled']
172 + ['value' => '0', 'label' => __('Disabled', 'jc-importer')],
173 + ['value' => '1', 'label' => __('Enabled', 'jc-importer')]
172 174 ],
173 175 'default' => '0',
174 - 'tooltip' => __('Whether the post can accept comments', 'importwp')
176 + 'tooltip' => __('Whether the post can accept comments', 'jc-importer')
175 177 ]),
176 - $this->register_field('Allow Pingbacks', 'ping_status', [
178 + $this->register_field(__('Allow Pingbacks', 'jc-importer'), 'ping_status', [
177 179 'options' => [
178 - ['value' => 'closed', 'label' => 'Closed'],
179 - ['value' => 'open', 'label' => 'Open']
180 + ['value' => 'closed', 'label' => __('Closed', 'jc-importer')],
181 + ['value' => 'open', 'label' => __('Open', 'jc-importer')]
180 182 ],
181 183 'default' => 'closed',
182 - 'tooltip' => __('Whether the post can accept pings', 'importwp')
184 + 'tooltip' => __('Whether the post can accept pings', 'jc-importer')
183 185 ])
184 - ]);
186 + ], ['link' => 'https://www.importwp.com/docs/wordpress-page-importer-template/']);
185 187
186 188 // Taxonomies
187 189 $groups[] = $this->register_taxonomy_fields();
188 190
@@ -193,59 +195,72 @@
193 195 }
194 196
195 197 public function register_taxonomy_fields()
196 198 {
197 - return $this->register_group('Taxonomies', 'taxonomies', [
198 - $this->register_field('Taxonomy', 'tax', [
199 + return $this->register_group(__('Taxonomies', 'jc-importer'), 'taxonomies', [
200 + $this->register_field(__('Taxonomy', 'jc-importer'), 'tax', [
199 201 'default' => 'category',
200 202 'options' => 'callback',
201 - 'tooltip' => __('Select the type of taxonomy you are importing to.', 'importwp')
203 + 'tooltip' => __('Select the type of taxonomy you are importing to.', 'jc-importer')
202 204 ]),
203 - $this->register_field('Terms', 'term', [
204 - 'tooltip' => __('Name of the taxonomy term or terms (entered as a comma seperated list).', 'importwp')
205 + $this->register_field(__('Terms', 'jc-importer'), 'term', [
206 + 'tooltip' => __('Name of the taxonomy term or terms (entered as a comma seperated list).', 'jc-importer')
205 207 ]),
206 - $this->register_group('Settings', 'settings', [
207 - $this->register_field('Delimiter', '_delimiter', [
208 + $this->register_group(__('Settings', 'jc-importer'), 'settings', [
209 + $this->register_field(__('Delimiter', 'jc-importer'), '_delimiter', [
208 210 'type' => 'text',
209 - 'tooltip' => 'A single character used to seperate terms when listing multiple, Leave empty to use default: ,'
211 + 'tooltip' => sprintf(__('A single character used to seperate terms when listing multiple, Leave empty to use default: %s', 'jc-importer'), ',')
210 212 ]),
211 - $this->register_field('Term Type', '_type', [
212 - 'tooltip' => 'Select what type the term values are (e.g. Name, Slug, or ID)',
213 + $this->register_field(__('Term Type', 'jc-importer'), '_type', [
214 + 'tooltip' => __('Select what type the term values are (e.g. Name, Slug, or ID)', 'jc-importer'),
213 215 'default' => 'name',
214 216 'options' => [
215 - ['value' => 'name', 'label' => 'Name'],
216 - ['value' => 'slug', 'label' => 'Slug'],
217 - ['value' => 'term_id', 'label' => 'ID'],
217 + ['value' => 'name', 'label' => __('Name', 'jc-importer')],
218 + ['value' => 'slug', 'label' => __('Slug', 'jc-importer')],
219 + ['value' => 'term_id', 'label' => __('ID', 'jc-importer')],
220 + ['value' => 'custom_field', 'label' => __('Custom Field', 'jc-importer')],
218 221 ],
219 222 'type' => 'select'
220 223 ]),
221 - $this->register_field('Enable Hierarchy', '_hierarchy', [
224 + $this->register_field(__('Custom Field', 'jc-importer'), '_type_cf', [
225 + 'condition' => [
226 + ['_type', '==', 'custom_field']
227 + ]
228 + ]),
229 + $this->register_field(__('Enable Hierarchy', 'jc-importer'), '_hierarchy', [
222 230 'default' => 'no',
223 231 'options' => [
224 - ['value' => 'no', 'label' => 'No'],
225 - ['value' => 'yes', 'label' => 'Yes'],
232 + ['value' => 'no', 'label' => __('No', 'jc-importer')],
233 + ['value' => 'yes', 'label' => __('Yes', 'jc-importer')],
226 234 ],
227 235 'type' => 'select'
228 236 ]),
229 - $this->register_field('Hierarchy Character', '_hierarchy_character', [
237 + $this->register_field(__('Hierarchy Character', 'jc-importer'), '_hierarchy_character', [
230 238 'default' => '>',
231 239 'condition' => ['_hierarchy', '==', 'yes'],
232 240 ]),
233 - $this->register_field('Append Terms', '_append', [
241 + $this->register_field(__('Hierarchy Relationship', 'jc-importer'), '_hierarchy_relationship', [
242 + 'default' => 'all',
243 + 'options' => [
244 + ['value' => 'all', 'label' => __('Connect all terms', 'jc-importer')],
245 + ['value' => 'last', 'label' => __('Connect last term', 'jc-importer')],
246 + ],
247 + 'type' => 'select',
248 + 'condition' => ['_hierarchy', '==', 'yes'],
249 + ]),
250 + $this->register_field(__('Append Terms', 'jc-importer'), '_append', [
234 251 'default' => 'no',
235 252 'options' => [
236 - ['value' => 'no', 'label' => 'No'],
237 - ['value' => 'yes', 'label' => 'Yes'],
253 + ['value' => 'no', 'label' => __('No', 'jc-importer')],
254 + ['value' => 'yes', 'label' => __('Yes', 'jc-importer')],
238 255 ],
239 256 'type' => 'select'
240 257 ]),
241 258 ], ['type' => 'settings'])
242 - ], ['type' => 'repeatable', 'row_base' => true]);
259 + ], ['type' => 'repeatable', 'row_base' => true, 'row_summary' => ['tax', 'term'], 'link' => 'https://www.importwp.com/docs/how-to-import-wordpress-taxonomies-onto-a-post-type/']);
243 260 }
244 261
245 - public function register_settings()
246 - {
247 - }
262 + public function register_settings() {}
248 263
249 264 public function register_options()
250 265 {
251 266 return [];
@@ -359,9 +374,9 @@
359 374 // // set flag to say slug has been generated
360 375 // $data->add(['post_name' => 'yes'], '_generated');
361 376 // }
362 377
363 - if ($this->importer->isEnabledField('post._parent') && isset($post_field_map['post_parent'])) {
378 + if ($this->importer->isEnabledField('post._parent') && isset($post_field_map['post_parent']) && !empty($post_field_map['post_parent'])) {
364 379
365 380 $parent_id = 0;
366 381 $parent_field_type = $data->getValue('post._parent._parent_type');
367 382
@@ -421,9 +436,9 @@
421 436 'key' => '_iwp_ref_' . $field,
422 437 'value' => $value
423 438 )
424 439 ),
425 - 'post_status' => 'any'
440 + 'post_status' => 'any, trash, future'
426 441 ));
427 442 if ($query->have_posts()) {
428 443 return $query->posts[0];
429 444 }
@@ -455,9 +470,8 @@
455 470 * @var Attachment $attachment
456 471 */
457 472 $attachment = Container::getInstance()->get('attachment');
458 473
459 - $this->featured_set = false;
460 474 $this->process_taxonomies($post_id, $data);
461 475 $this->process_attachments($post_id, $data, $filesystem, $ftp, $attachment);
462 476
463 477 parent::post_process($post_id, $data);
@@ -508,12 +522,15 @@
508 522
509 523 $delimiter = apply_filters('iwp/taxonomy=' . $tax . '/value_delimiter', $base_delimiter);
510 524
511 525 $term_types[$tax] = isset($row[$prefix . 'settings._type']) && !empty($row[$prefix . 'settings._type']) ? $row[$prefix . 'settings._type'] : 'name';
526 + $term_types_cf[$tax] = isset($row[$prefix . 'settings._type_cf']) && !empty($row[$prefix . 'settings._type_cf']) ? $row[$prefix . 'settings._type_cf'] : '';
512 527
513 528 $hierarchy_enabled = isset($row[$prefix . 'settings._hierarchy']) && $row[$prefix . 'settings._hierarchy'] === 'yes' ? true : false;
514 529 $hierarchy_character = isset($row[$prefix . 'settings._hierarchy_character']) ? $row[$prefix . 'settings._hierarchy_character'] : null;
530 + $hierarchy_terms = isset($row[$prefix . 'settings._hierarchy_relationship']) ? $row[$prefix . 'settings._hierarchy_relationship'] : null;
515 531
532 +
516 533 $delimiter = isset($row[$prefix . 'settings._delimiter']) && strlen(trim($row[$prefix . 'settings._delimiter'])) === 1 ? trim($row[$prefix . 'settings._delimiter']) : $delimiter;
517 534
518 535 if (empty($hierarchy_character)) {
519 536 $hierarchy_enabled = false;
@@ -529,9 +546,9 @@
529 546 if ($data->permission()) {
530 547 $allowed = $data->permission()->validate([$permission_key => ''], $data->getMethod(), $group);
531 548 $is_allowed = isset($allowed[$permission_key]) ? true : false;
532 549
533 - if (!$is_allowed || empty($term)) {
550 + if (!$is_allowed || ($term_append[$tax] == true && empty($term))) {
534 551 continue;
535 552 }
536 553 }
537 554
@@ -565,39 +582,59 @@
565 582 // TODO: Process term hierarchy
566 583 foreach ($term_hierarchy as $processed_tax => $term_hierarchy_list) {
567 584
568 585 // clear existing taxonomies
569 - if (!isset($term_append[$processed_tax]) || !$term_append[$processed_tax]) {
570 - wp_set_object_terms($post_id, null, $processed_tax);
571 - }
586 + $clear_existing_terms = !isset($term_append[$processed_tax]) || !$term_append[$processed_tax];
572 587
573 588 if (empty($term_hierarchy_list)) {
574 589 continue;
575 590 }
576 591
592 + $new_terms = [];
593 +
577 594 foreach ($term_hierarchy_list as $hierarchy_list) {
578 595
579 596 $prev_term = isset($term_hierarchy_enabled[$processed_tax]) ? 0 : null;
580 597 $type = $term_types[$processed_tax];
581 598
582 - foreach ($hierarchy_list as $term) {
599 + foreach ($hierarchy_list as $term_i => $term) {
583 600 if (!isset($this->_taxonomies[$processed_tax])) {
584 601 $this->_taxonomies[$processed_tax] = [];
585 602 }
586 603
587 - $term_result = $this->create_or_get_taxonomy_term($post_id, $processed_tax, $term, $prev_term, $type);
604 + $connect_terms = true;
605 + if ($hierarchy_enabled && $hierarchy_terms === 'last') {
606 + $connect_terms = $term_i == count($hierarchy_list) - 1;
607 + }
608 +
609 + $search_term = $term;
610 + if ($type === 'custom_field') {
611 + $search_term = [
612 + $term_types_cf[$processed_tax],
613 + $term
614 + ];
615 + }
616 +
617 + $term_result = $this->create_or_get_taxonomy_term($post_id, $processed_tax, $search_term, $prev_term, $type, false);
588 618 if ($term_result) {
589 619 $prev_term = $term_result->term_id;
590 620 $this->_taxonomies[$processed_tax][] = $term_result->name;
591 621 }
622 +
623 + if ($connect_terms && $term_result) {
624 + $new_terms[] = $term_result->term_id;
625 + }
592 626 }
593 627 }
628 +
629 + // Connect all terms in one go.
630 + wp_set_object_terms($post_id, $new_terms, $processed_tax, !$clear_existing_terms);
594 631 }
595 632 }
596 633
597 - private function create_or_get_taxonomy_term($post_id, $tax, $term, $parent, $term_type = 'name')
634 + public function create_or_get_taxonomy_term($post_id, $tax, $term, $parent, $term_type = 'name', $set = true)
598 635 {
599 - if (!in_array($term_type, ['slug', 'name', 'term_id'])) {
636 + if (!in_array($term_type, ['slug', 'name', 'term_id', 'custom_field'])) {
600 637 $term_type = 'name';
601 638 }
602 639
603 640 if (is_null($parent)) {
@@ -602,11 +639,35 @@
602 639
603 640 if (is_null($parent)) {
604 641
605 642 // we do not care about parent, just fetch first
606 - $tmp_term = get_term_by($term_type, $term, $tax);
643 +
644 + if ($term_type === 'custom_field') {
645 +
646 + if (!isset($term[0], $term[1]) || empty($term[0]) || empty($term[1])) {
647 + return false;
648 + }
649 +
650 + $terms = get_terms([
651 + 'taxonomy' => $tax,
652 + 'meta_key' => $term[0],
653 + 'meta_value' => $term[1],
654 + 'hide_empty' => false
655 + ]);
656 + if (empty($terms)) {
657 + return false;
658 + }
659 +
660 + $tmp_term = $terms[0];
661 + } else {
662 + $tmp_term = get_term_by($term_type, $term, $tax);
663 + }
664 +
607 665 if ($tmp_term) {
608 - wp_set_object_terms($post_id, $tmp_term->term_id, $tax, true);
666 + $tmp_term = apply_filters('iwp/importer/template/post_term', $tmp_term, $tax);
667 + if ($set) {
668 + wp_set_object_terms($post_id, $tmp_term->term_id, $tax, true);
669 + }
609 670 return $tmp_term;
610 671 }
611 672 } else {
612 673
@@ -624,8 +685,20 @@
624 685 $tmp_term = get_term_by($term_type, $term, $tax);
625 686 if ($tmp_term) {
626 687 $terms[] = $tmp_term;
627 688 }
689 + } else if ($term_type === 'custom_field') {
690 +
691 + if (!isset($term[0], $term[1]) || empty($term[0]) || empty($term[1])) {
692 + return false;
693 + }
694 +
695 + $terms = get_terms([
696 + 'taxonomy' => $tax,
697 + 'meta_key' => $term[0],
698 + 'meta_value' => $term[1],
699 + 'hide_empty' => false
700 + ]);
628 701 } else {
629 702
630 703 $terms = get_terms([
631 704 'taxonomy' => $tax,
@@ -638,9 +711,12 @@
638 711 foreach ($terms as $tmp_term) {
639 712 if (intval($tmp_term->parent) === intval($parent)) {
640 713
641 714 // attach term to post
642 - wp_set_object_terms($post_id, $tmp_term->term_id, $tax, true);
715 + $tmp_term = apply_filters('iwp/importer/template/post_term', $tmp_term, $tax);
716 + if ($set) {
717 + wp_set_object_terms($post_id, $tmp_term->term_id, $tax, true);
718 + }
643 719 return $tmp_term;
644 720 }
645 721 }
646 722 }
@@ -646,16 +722,23 @@
646 722 }
647 723 }
648 724
649 725 // should not create new term since we are using the term_id
650 - if ($term_type === 'term_id') {
726 + if ($term_type === 'term_id' || $term_type === 'custom_field') {
651 727 return false;
652 728 }
653 729
730 + // allow the option to disable the creation of terms
731 + if (false === apply_filters('iwp/importer/template/post_create_term', true)) {
732 + return false;
733 + }
734 +
654 735 // add term
655 736 $term_id = wp_insert_term($term, $tax, ['parent' => $parent]);
656 737 if (!is_wp_error($term_id)) {
657 - wp_set_object_terms($post_id, $term_id['term_id'], $tax, true);
738 + if ($set) {
739 + wp_set_object_terms($post_id, $term_id['term_id'], $tax, true);
740 + }
658 741 return get_term($term_id['term_id'], $tax);
659 742 }
660 743
661 744 return false;
@@ -704,8 +787,10 @@
704 787 $sub_rows = $data->getData($sub_group_id);
705 788 }
706 789
707 790 foreach ($sub_rows as $row) {
791 +
792 + $row = $this->process_attachment_meta_permissions($row, $data, $group, $permission_key, $row_prefix);
708 793 $ids = $this->process_attachment($post_id, $row, $row_prefix, $filesystem, $ftp, $attachment);
709 794 $attachment_ids = array_merge($attachment_ids, $ids);
710 795 }
711 796 }
@@ -806,9 +891,9 @@
806 891 'map' => []
807 892 ];
808 893 }
809 894
810 - $attachments['image']['map'][$matches[1]] = sprintf('{%d}', $index);
895 + $attachments['image']['map'][$matches[1]] = sprintf('{%s}', $index);
811 896 $attachments['image']['map']['featured'] = 'yes';
812 897 } elseif (preg_match('/^tax_([a-zA-Z0-9_]+)\.(.*?)$/', $field, $matches) === 1) {
813 898
814 899 // Capture Taxonomies.
@@ -820,9 +905,9 @@
820 905 'map' => []
821 906 ];
822 907 }
823 908
824 - $taxonomies[$taxonomy]['map'][$matches[2]] = sprintf('{%d}', $index);
909 + $taxonomies[$taxonomy]['map'][$matches[2]] = sprintf('{%s}', $index);
825 910 } elseif (preg_match('/^author\.(.*?)$/', $field, $matches) === 1) {
826 911
827 912 // Capture author.
828 913 // author.ID, author.user_login,author.user_nicename,author.user_email,author.user_url,author.display_name
@@ -829,9 +914,9 @@
829 914 if (!isset($author['map'])) {
830 915 $author['map'] = [];
831 916 }
832 917
833 - $author['map'][$matches[1]] = sprintf('{%d}', $index);
918 + $author['map'][$matches[1]] = sprintf('{%s}', $index);
834 919 } elseif (preg_match('/^parent\.(.*?)$/', $field, $matches) === 1) {
835 920
836 921 // Capture parent
837 922 // parent.id,parent.name,parent.slug
@@ -838,14 +923,14 @@
838 923 if (!isset($parent['map'])) {
839 924 $parent['map'] = [];
840 925 }
841 926
842 - $parent['map'][$matches[1]] = sprintf('{%d}', $index);
927 + $parent['map'][$matches[1]] = sprintf('{%s}', $index);
843 928 } elseif (isset($this->field_map[$field])) {
844 929
845 930 // Handle core fields
846 931 $field_key = $this->field_map[$field];
847 - $map[$field_key] = sprintf('{%d}', $index);
932 + $map[$field_key] = sprintf('{%s}', $index);
848 933
849 934 if (in_array($field, $this->optional_fields)) {
850 935 $enabled[] = $field_key;
851 936 }
@@ -871,23 +956,39 @@
871 956 'settings._append' => 'no',
872 957 'settings._delimiter' => '',
873 958 'settings._hierarchy' => 'no',
874 959 'settings._hierarchy_character' => '>',
960 + 'settings._type' => 'name',
875 961 ];
876 962
877 963 foreach ($taxonomies as $taxonomy => $taxonomy_data) {
964 + $term_map = isset($taxonomy_data['map']) && is_array($taxonomy_data['map']) ? $taxonomy_data['map'] : [];
878 965 $data = [];
879 966
880 - if (isset($taxonomy_data['map']['hierarchy::name'])) {
881 - $data['term'] = $taxonomy_data['map']['hierarchy::name'];
967 + // Prefer name/slug over hierarchy::* (those extra columns are always
968 + // present on a full CSV export). Always store term type so IDs are
969 + // not imported as names.
970 + if (isset($term_map['name'])) {
971 + $data['term'] = $term_map['name'];
972 + $data['settings._type'] = 'name';
973 + } elseif (isset($term_map['slug'])) {
974 + $data['term'] = $term_map['slug'];
975 + $data['settings._type'] = 'slug';
976 + } elseif (isset($term_map['hierarchy::name'])) {
977 + $data['term'] = $term_map['hierarchy::name'];
882 978 $data['settings._hierarchy'] = 'yes';
883 - } elseif (isset($taxonomy_data['map']['hierarchy::slug'])) {
884 - $data['term'] = $taxonomy_data['map']['hierarchy::slug'];
979 + $data['settings._type'] = 'name';
980 + } elseif (isset($term_map['hierarchy::slug'])) {
981 + $data['term'] = $term_map['hierarchy::slug'];
885 982 $data['settings._hierarchy'] = 'yes';
886 - } elseif (isset($taxonomy_data['map']['name'])) {
887 - $data['term'] = $taxonomy_data['map']['name'];
888 - } elseif (isset($taxonomy_data['map']['slug'])) {
889 - $data['term'] = $taxonomy_data['map']['slug'];
983 + $data['settings._type'] = 'slug';
984 + } elseif (isset($term_map['id'])) {
985 + $data['term'] = $term_map['id'];
986 + $data['settings._type'] = 'term_id';
987 + } elseif (isset($term_map['hierarchy::id'])) {
988 + $data['term'] = $term_map['hierarchy::id'];
989 + $data['settings._hierarchy'] = 'yes';
990 + $data['settings._type'] = 'term_id';
890 991 } else {
891 992 continue;
892 993 }
893 994
@@ -892,8 +993,14 @@
892 993 }
893 994
894 995 $data['tax'] = $taxonomy;
895 996
997 + $row_base = $this->find_exporter_loop_row_base($fields, 'tax_' . $taxonomy);
998 + if ($row_base !== '') {
999 + $data['row_base'] = $row_base;
1000 + $data['term'] = $this->relative_exporter_map($data['term'], $row_base);
1001 + }
1002 +
896 1003 $data = wp_parse_args($data, $defaults);
897 1004
898 1005 $map = array_merge($map, array_reduce(array_keys($data), function ($carry, $key) use ($data, $taxonomy_counter) {
899 1006 $carry[sprintf('taxonomies.%d.%s', $taxonomy_counter, $key)] = $data[$key];
@@ -1025,6 +1132,132 @@
1025 1132 return [
1026 1133 'map' => $map,
1027 1134 'enabled' => $enabled
1028 1135 ];
1136 + }
1137 +
1138 + public function get_permission_fields($importer_model)
1139 + {
1140 + $permission_fields = parent::get_permission_fields($importer_model);
1141 +
1142 + $permission_fields['core'] = [
1143 + 'ID' => __('ID', 'jc-importer'),
1144 + 'post_title' => __('Title', 'jc-importer'),
1145 + 'post_content' => __('Content', 'jc-importer'),
1146 + 'post_excerpt' => __('Excerpt', 'jc-importer'),
1147 + 'post_name' => __('Slug', 'jc-importer'),
1148 + 'post_status' => __('Post Status', 'jc-importer'),
1149 + 'menu_order' => __('Menu order', 'jc-importer'),
1150 + 'post_password' => __('password', 'jc-importer'),
1151 + 'post_date' => __('Date', 'jc-importer'),
1152 + 'comment_status' => __('Comment Status', 'jc-importer'),
1153 + 'ping_status' => __('Ping Status', 'jc-importer'),
1154 + 'post_parent' => __('Parent', 'jc-importer'),
1155 + 'post_author' => __('Author', 'jc-importer'),
1156 + ];
1157 +
1158 + $permission_fields['taxonomies'] = [];
1159 + $taxonomies = $this->get_taxonomy_options($importer_model);
1160 + foreach ($taxonomies as $taxonomy) {
1161 + $permission_fields['taxonomies']['taxonomy.' . $taxonomy['value']] = $taxonomy['label'];
1162 + }
1163 +
1164 + $field_map = $importer_model->getMap();
1165 + if (isset($field_map['attachments._index']) && $field_map['attachments._index'] > 0) {
1166 + $permission_fields['attachments'] = [];
1167 + for ($i = 0; $i < $field_map['attachments._index']; $i++) {
1168 + $permission_fields['attachments']['attachments.' . $i] = 'Attachment Row ' . ($i + 1);
1169 +
1170 + // Meta fields
1171 + $permission_fields['attachments']['attachments.' . $i . '._alt'] = 'Attachment Row ' . ($i + 1) . ' - Alt Text';
1172 + $permission_fields['attachments']['attachments.' . $i . '._title'] = 'Attachment Row ' . ($i + 1) . ' - Title Text';
1173 + $permission_fields['attachments']['attachments.' . $i . '._caption'] = 'Attachment Row ' . ($i + 1) . ' - Caption Text';
1174 + $permission_fields['attachments']['attachments.' . $i . '._description'] = 'Attachment Row ' . ($i + 1) . ' - Description Text';
1175 + }
1176 + }
1177 +
1178 + return $permission_fields;
1179 + }
1180 +
1181 + public function get_unique_identifier_options($importer_model, $unique_fields = [])
1182 + {
1183 + $output = parent::get_unique_identifier_options($importer_model, $unique_fields);
1184 +
1185 + return array_merge(
1186 + $output,
1187 + $this->get_unique_identifier_options_from_map($importer_model, $unique_fields, $this->field_map, $this->optional_fields)
1188 + );
1189 + }
1190 +
1191 + /**
1192 + * XML/JSON from-exporter headings are path => selection; CSV is a numeric list.
1193 + *
1194 + * @param array $fields
1195 + * @return bool
1196 + */
1197 + protected function headings_are_paths($fields)
1198 + {
1199 + if (!is_array($fields) || empty($fields)) {
1200 + return false;
1201 + }
1202 +
1203 + foreach (array_keys($fields) as $key) {
1204 + if (is_string($key) && $key !== '' && !is_numeric($key) && strpos($key, '/') !== false) {
1205 + return true;
1206 + }
1207 + }
1208 +
1209 + return false;
1210 + }
1211 +
1212 + /**
1213 + * Loop node path used as row_base when creating an importer from an XML/JSON export.
1214 + *
1215 + * @param array $fields
1216 + * @param string $loop_selection
1217 + * @return string
1218 + */
1219 + protected function find_exporter_loop_row_base($fields, $loop_selection)
1220 + {
1221 + if ($loop_selection === '' || !$this->headings_are_paths($fields)) {
1222 + return '';
1223 + }
1224 +
1225 + foreach ($fields as $path => $selection) {
1226 + if ($selection === $loop_selection && is_string($path) && strpos($path, '/') !== false) {
1227 + return $path;
1228 + }
1229 + }
1230 +
1231 + return '';
1232 + }
1233 +
1234 + /**
1235 + * Rewrite a mapped path so it is relative to the exporter loop node.
1236 + *
1237 + * @param string $mapped
1238 + * @param string $row_base
1239 + * @return string
1240 + */
1241 + protected function relative_exporter_map($mapped, $row_base)
1242 + {
1243 + if ($row_base === '' || !is_string($mapped) || $mapped === '') {
1244 + return $mapped;
1245 + }
1246 +
1247 + if (preg_match('/^\{(.*)\}$/', $mapped, $matches) !== 1) {
1248 + return $mapped;
1249 + }
1250 +
1251 + $path = $matches[1];
1252 + if (strpos($path, $row_base) !== 0 || $path === $row_base) {
1253 + return $mapped;
1254 + }
1255 +
1256 + $relative = substr($path, strlen($row_base));
1257 + if ($relative !== '' && $relative[0] !== '/') {
1258 + $relative = '/' . $relative;
1259 + }
1260 +
1261 + return '{' . $relative . '}';
1029 1262 }
1030 1263 }