PluginProbe
Import WP – CSV & XML Import Export for WordPress / 2.7.1
Import WP – CSV & XML Import Export for WordPress v2.7.1
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
jc-importer / class / Common / Importer / Template / PostTemplate.php

PostTemplate.php in Import WP – CSV & XML Import Export for WordPress 2.7.1, at class/Common/Importer/Template/PostTemplate.php

725 lines 25.0 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\Importer\Template;
4
5 use ImportWP\Common\Attachment\Attachment;
6 use ImportWP\Common\Filesystem\Filesystem;
7 use ImportWP\Common\Ftp\Ftp;
8 use ImportWP\Common\Importer\ParsedData;
9 use ImportWP\Common\Importer\TemplateInterface;
10 use ImportWP\Common\Model\ImporterModel;
11 use ImportWP\Common\Util\Logger;
12 use ImportWP\Container;
13 use ImportWP\EventHandler;
14
15 class PostTemplate extends Template implements TemplateInterface
16 {
17 protected $name = 'Post';
18 protected $mapper = 'post';
19 protected $field_map = [
20 'ID' => 'post.ID',
21 'post_title' => 'post.post_title',
22 'post_content' => 'post.post_content',
23 'post_excerpt' => 'post.post_excerpt',
24 'post_name' => 'post.post_name',
25 'post_status' => 'post.post_status',
26 'menu_order' => 'post.menu_order',
27 'post_password' => 'post.post_password',
28 'post_date' => 'post.post_date',
29 'comment_status' => 'post.comment_status',
30 'ping_status' => 'post.ping_status',
31 'post_parent' => 'post._parent.parent',
32 ];
33
34 protected $_taxonomies = [];
35 protected $_attachments = [];
36
37 private $virtual_fields = [];
38
39 public function __construct(EventHandler $event_handler)
40 {
41 parent::__construct($event_handler);
42
43 $this->groups[] = 'post';
44 $this->groups[] = 'taxonomies';
45 $this->groups[] = 'attachments';
46
47 $this->default_template_options['post_type'] = 'post';
48
49 $this->field_options = array_merge($this->field_options, [
50 'post._parent.parent' => [$this, 'get_post_parent_options'],
51 'taxonomies.*.tax' => [$this, 'get_taxonomy_options'],
52 ]);
53 }
54
55 /**
56 * @param string $message
57 * @param int $id
58 * @param ParsedData $data
59 * @return $string
60 */
61 public function display_record_info($message, $id, $data)
62 {
63 $message = parent::display_record_info($message, $id, $data);
64
65 if (!empty($this->_taxonomies)) {
66 foreach ($this->_taxonomies as $tax => $terms) {
67 $message .= ', ' . $tax . ': (' . implode(', ', $terms) . ')';
68 }
69 }
70
71 if (!empty($this->_attachments)) {
72 $message .= ', Attachments: (' . implode(', ', $this->_attachments) . ')';
73 }
74
75 return $message;
76 }
77
78 public function register()
79 {
80 $groups = [];
81
82 // Post
83 $groups[] = $this->register_group('Post Fields', 'post', [
84 $this->register_field('ID', 'ID', [
85 'tooltip' => __('ID is only used to reference existing records', 'importwp')
86 ]),
87 $this->register_core_field('Title', 'post_title', [
88 'tooltip' => __('Title of the post.', 'importwp')
89 ]),
90 $this->register_core_field('Content', 'post_content', [
91 'tooltip' => __('Main WYSIWYG editor content of the post.', 'importwp')
92 ]),
93 $this->register_field('Excerpt', 'post_excerpt', [
94 'tooltip' => __('A custom short extract for the post.', 'importwp')
95 ]),
96 $this->register_field('Slug', 'post_name', [
97 'tooltip' => __('The slug is the user friendly and URL valid name of the post.', 'importwp')
98 ]),
99 $this->register_field('Status', 'post_status', [
100 'default' => 'publish',
101 'options' => [
102 ['value' => 'draft', 'label' => 'Draft'],
103 ['value' => 'publish', 'label' => 'Published'],
104 ['value' => 'pending', 'label' => 'Pending'],
105 ['value' => 'future', 'label' => 'Future'],
106 ['value' => 'private', 'label' => 'Private'],
107 ['value' => 'trash', 'label' => 'Trash']
108 ],
109 'tooltip' => __('Whether the post can accept comments. Accepts open or closed', 'importwp')
110 ]),
111 $this->register_group('Parent Settings', '_parent', [
112 $this->register_field('Parent', 'parent', [
113 'default' => '',
114 'options' => 'callback',
115 'tooltip' => __('Set this for the post it belongs to', 'importwp')
116 ]),
117 $this->register_field('Parent Field Type', '_parent_type', [
118 'default' => 'id',
119 'options' => [
120 ['value' => 'id', 'label' => 'ID'],
121 ['value' => 'slug', 'label' => 'Slug'],
122 ['value' => 'name', 'label' => 'Name'],
123 ['value' => 'column', 'label' => 'Reference Column'],
124 ],
125 'type' => 'select',
126 'tooltip' => __('Select how the parent field should be handled', 'importwp')
127 ]),
128 $this->register_field('Parent Reference Column', '_parent_ref', [
129 'condition' => ['_parent_type', '==', 'column'],
130 'tooltip' => __('Select the column/node that the parent field is referencing', 'importwp')
131 ])
132 ]),
133 $this->register_field('Order', 'menu_order', [
134 'tooltip' => __('The order the post should be displayed in', 'importwp')
135 ]),
136 $this->register_group('Author Settings', '_author', [
137 $this->register_field('Author', 'post_author', [
138 'tooltip' => __('The user of who added this post', 'importwp')
139 ]),
140 $this->register_field('Author Field Type', '_author_type', [
141 'default' => 'id',
142 'options' => [
143 ['value' => 'id', 'label' => 'ID'],
144 ['value' => 'login', 'label' => 'Login'],
145 ['value' => 'email', 'label' => 'Email'],
146 ],
147 'tooltip' => __('Select how the author field should be handled', 'importwp')
148 ])
149 ]),
150 $this->register_field('Password', 'post_password', [
151 'tooltip' => __('The password to access the post', 'importwp')
152 ]),
153 $this->register_field('Date', 'post_date', [
154 'tooltip' => __('The date of the post , enter in the format "YYYY-MM-DD HH:ii:ss"', 'importwp')
155 ]),
156 $this->register_field('Allow Comments', 'comment_status', [
157 'options' => [
158 ['value' => '0', 'label' => 'Disabled'],
159 ['value' => '1', 'label' => 'Enabled']
160 ],
161 'default' => '0',
162 'tooltip' => __('Whether the post can accept comments', 'importwp')
163 ]),
164 $this->register_field('Allow Pingbacks', 'ping_status', [
165 'options' => [
166 ['value' => 'closed', 'label' => 'Closed'],
167 ['value' => 'open', 'label' => 'Open']
168 ],
169 'default' => 'closed',
170 'tooltip' => __('Whether the post can accept pings', 'importwp')
171 ])
172 ]);
173
174 // Taxonomies
175 $groups[] = $this->register_taxonomy_fields();
176
177 // Attachments
178 $groups[] = $this->register_attachment_fields();
179
180 return $groups;
181 }
182
183 public function register_taxonomy_fields()
184 {
185 return $this->register_group('Taxonomies', 'taxonomies', [
186 $this->register_field('Taxonomy', 'tax', [
187 'default' => 'category',
188 'options' => 'callback',
189 'tooltip' => __('Select the type of taxonomy you are importing to.', 'importwp')
190 ]),
191 $this->register_field('Terms', 'term', [
192 'tooltip' => __('Name of the taxonomy term or terms (entered as a comma seperated list).', 'importwp')
193 ]),
194 $this->register_field('Enable Hierarchy', '_hierarchy', [
195 'default' => 'no',
196 'options' => [
197 ['value' => 'no', 'label' => 'No'],
198 ['value' => 'yes', 'label' => 'Yes'],
199 ],
200 'type' => 'select'
201 ]),
202 $this->register_field('Hierarchy Character', '_hierarchy_character', [
203 'default' => '>',
204 'condition' => ['_hierarchy', '==', 'yes'],
205 ]),
206 $this->register_field('Append Terms', '_append', [
207 'default' => 'no',
208 'options' => [
209 ['value' => 'no', 'label' => 'No'],
210 ['value' => 'yes', 'label' => 'Yes'],
211 ],
212 'type' => 'select'
213 ]),
214 ], ['type' => 'repeatable', 'row_base' => true]);
215 }
216
217 public function register_settings()
218 {
219 }
220
221 public function register_options()
222 {
223 return [];
224 }
225
226 /**
227 * Alter fields before they are parsed
228 *
229 * @param array $fields
230 * @return array
231 */
232 public function field_map($fields)
233 {
234 if ($this->importer->isEnabledField('post._parent') && $fields['post._parent._parent_type'] === 'column' && !empty($fields["post._parent._parent_ref"])) {
235 $fields['_iwp_ref_post_parent'] = $fields["post._parent._parent_ref"];
236 $this->virtual_fields[] = '_iwp_ref_post_parent';
237 }
238 return $fields;
239 }
240
241 /**
242 * Process data before record is importer.
243 *
244 * Alter data that is passed to the mapper.
245 *
246 * @param ParsedData $data
247 * @return ParsedData
248 */
249 public function pre_process(ParsedData $data)
250 {
251 $data = parent::pre_process($data);
252
253 $post_field_map = [];
254 foreach ($this->field_map as $field_id => $field_map_key) {
255 $post_field_map[$field_id] = $data->getValue($field_map_key);
256 }
257
258 // remove fields that have not been set
259 foreach ($post_field_map as $field_key => $field_map) {
260
261 if ($field_map === false) {
262 unset($post_field_map[$field_key]);
263 continue;
264 }
265 }
266
267 $optional_fields = [
268 'ID',
269 'post_excerpt',
270 'post_name',
271 'post_status',
272 'menu_order',
273 'post_password',
274 'post_date',
275 'comment_status',
276 'ping_status'
277 ];
278 foreach ($optional_fields as $optional_field) {
279 if (true !== $this->importer->isEnabledField('post.' . $optional_field)) {
280 unset($post_field_map[$optional_field]);
281 }
282 }
283
284 if (true !== $this->importer->isEnabledField('post._parent')) {
285 unset($post_field_map['post_parent']);
286 }
287
288 if (true !== $this->importer->isEnabledField('post._author')) {
289 unset($post_field_map['post_author']);
290 }
291
292 if (!empty($this->virtual_fields)) {
293 foreach ($this->virtual_fields as $virtual_field) {
294 $value = $data->getValue($virtual_field);
295 if (false !== $value) {
296 $post_field_map[$virtual_field] = $value;
297 }
298 }
299 }
300
301 if ($this->importer->isEnabledField('post._author')) {
302 $post_author = $data->getValue('post._author.post_author');
303 $post_author_type = $data->getValue('post._author._author_type');
304
305 $user_id = 0;
306
307 if ($post_author_type === 'id') {
308
309 $user = get_user_by('ID', $post_author);
310 if ($user) {
311 $user_id = intval($user->ID);
312 }
313 } elseif ($post_author_type === 'login') {
314
315 $user = get_user_by('login', $post_author);
316 if ($user) {
317 $user_id = intval($user->ID);
318 }
319 } elseif ($post_author_type === 'email') {
320
321 $user = get_user_by('email', $post_author);
322 if ($user) {
323 $user_id = intval($user->ID);
324 }
325 }
326
327 if ($user_id > 0) {
328 $post_field_map['post_author'] = $user_id;
329 } else {
330 $post_field_map['post_author'] = '';
331 }
332 }
333
334 // post_name is a unique field, so generate slug from title if no slug present
335 // if (!isset($post_field_map['post_name']) || empty($post_field_map['post_name'])) {
336 // $post_field_map['post_name'] = sanitize_title($post_field_map['post_title']);
337
338 // // set flag to say slug has been generated
339 // $data->add(['post_name' => 'yes'], '_generated');
340 // }
341
342 if ($this->importer->isEnabledField('post._parent') && isset($post_field_map['post_parent'])) {
343
344 $parent_id = 0;
345 $parent_field_type = $data->getValue('post._parent._parent_type');
346
347 if ($parent_field_type === 'name' || $parent_field_type === 'slug') {
348
349 // name or slug
350 $page = get_posts(array('name' => sanitize_title($post_field_map['post_parent']), 'post_type' => $this->importer->getSetting('post_type')));
351 if ($page) {
352 $parent_id = intval($page[0]->ID);
353 }
354 } elseif ($parent_field_type === 'id') {
355
356 // ID
357 $parent_id = intval($post_field_map['post_parent']);
358 } elseif ($parent_field_type === 'column') {
359
360 // reference column
361 $temp_id = $this->get_post_by_cf('post_parent', $post_field_map['post_parent']);
362 if (intval($temp_id > 0)) {
363 $parent_id = intval($temp_id);
364 }
365 }
366
367 if ($parent_id > 0) {
368 $post_field_map['post_parent'] = $parent_id;
369 }
370 }
371
372 foreach ($post_field_map as $key => $value) {
373 $post_field_map[$key] = apply_filters('iwp/template/process_field', $value, $key, $this->importer);
374 }
375
376 $data->replace($post_field_map, 'default');
377
378 return $data;
379 }
380
381 /**
382 * Find existing post/page/custom by reference field
383 *
384 * @param string $field Reference Field Name
385 * @param string $value Value to check against reference
386 *
387 * @return bool
388 */
389 public function get_post_by_cf($field, $value)
390 {
391
392 $query = new \WP_Query(array(
393 'post_type' => $this->importer->getSetting('post_type'),
394 'posts_per_page' => 1,
395 'fields' => 'ids',
396 'cache_results' => false,
397 'update_post_meta_cache' => false,
398 'meta_query' => array(
399 array(
400 'key' => '_iwp_ref_' . $field,
401 'value' => $value
402 )
403 ),
404 'post_status' => 'any'
405 ));
406 if ($query->have_posts()) {
407 return $query->posts[0];
408 }
409 return false;
410 }
411
412 /**
413 * Process data after record is importer.
414 *
415 * Use data that is returned from the mapper.
416 *
417 * @param int $post_id
418 * @param ParsedData $data
419 * @return void
420 */
421 public function post_process($post_id, ParsedData $data)
422 {
423 /**
424 * @var Filesystem $filesystem
425 */
426 $filesystem = Container::getInstance()->get('filesystem');
427
428 /**
429 * @var Ftp $ftp
430 */
431 $ftp = Container::getInstance()->get('ftp');
432
433 /**
434 * @var Attachment $attachment
435 */
436 $attachment = Container::getInstance()->get('attachment');
437
438 $this->featured_set = false;
439 $this->process_taxonomies($post_id, $data);
440 $this->process_attachments($post_id, $data, $filesystem, $ftp, $attachment);
441
442 parent::post_process($post_id, $data);
443 }
444
445 /**
446 * Process taxonomy group
447 *
448 * TODO: Possibly move this into parser?
449 *
450 * @param int $post_id
451 * @param ParsedData $data
452 * @return void
453 */
454 public function process_taxonomies($post_id, $data)
455 {
456 // reset list of taxonomies
457 $this->_taxonomies = [];
458
459 $group = 'taxonomies';
460 $taxonomes_data = $data->getData($group);
461 $total_rows = isset($taxonomes_data[$group . '._index']) ? intval($taxonomes_data[$group . '._index']) : 0;
462 $base_delimiter = apply_filters('iwp/value_delimiter', ',');
463 $base_delimiter = apply_filters('iwp/taxonomy/value_delimiter', $base_delimiter);
464
465 $processed_taxonomies = [];
466 $term_hierarchy = [];
467 $term_hierarchy_enabled = [];
468 $term_append = [];
469
470 // Pre-Process taxonomy data
471 for ($i = 0; $i < $total_rows; $i++) {
472
473 $prefix = $group . '.' . $i . '.';
474
475 $sub_rows = [$taxonomes_data];
476 if (isset($taxonomes_data[$prefix . 'row_base']) && !empty($taxonomes_data[$prefix . 'row_base'])) {
477 $sub_group_id = $group . '.' . $i;
478 $sub_rows = $data->getData($sub_group_id);
479 }
480
481 foreach ($sub_rows as $row) {
482 $tax = isset($row[$prefix . 'tax']) ? $row[$prefix . 'tax'] : null;
483 $terms = isset($row[$prefix . 'term']) ? $row[$prefix . 'term'] : null;
484
485 $term_append[$tax] = isset($row[$prefix . '_append']) && $row[$prefix . '_append'] == 'yes';
486
487 $delimiter = apply_filters('iwp/taxonomy=' . $tax . '/value_delimiter', $base_delimiter);
488
489 $hierarchy_enabled = isset($row[$prefix . '_hierarchy']) && $row[$prefix . '_hierarchy'] === 'yes' ? true : false;
490 $hierarchy_character = isset($row[$prefix . '_hierarchy_character']) ? $row[$prefix . '_hierarchy_character'] : null;
491
492 if (empty($hierarchy_character)) {
493 $hierarchy_enabled = false;
494 }
495
496 if (!is_null($tax) && !is_null($terms)) {
497 $terms = explode($delimiter, $terms);
498 foreach ($terms as $term) {
499
500 $term = trim($term);
501 $permission_key = 'taxonomy.' . $tax; //taxonomy.category | taxonomy.post_tag
502
503 if ($data->permission()) {
504 $allowed = $data->permission()->validate([$permission_key => ''], $data->getMethod(), $group);
505 $is_allowed = isset($allowed[$permission_key]) ? true : false;
506
507 if (!$is_allowed || empty($term)) {
508 continue;
509 }
510 }
511
512 // handle taxonomies
513 if (!isset($processed_taxonomies[$tax])) {
514 $processed_taxonomies[$tax] = [];
515 }
516
517 $processed_taxonomies[$tax][] = $term;
518
519 // Handle hierarchy
520 if (!isset($term_hierarchy[$tax])) {
521 $term_hierarchy[$tax] = [];
522 }
523
524 if ($hierarchy_enabled) {
525 $hierarchy_parts = explode($hierarchy_character, $term);
526 if (count($hierarchy_parts) > 0) {
527 $hierarchy_parts = array_filter(array_map('trim', $hierarchy_parts));
528 $term_hierarchy[$tax][] = $hierarchy_parts;
529 $term_hierarchy_enabled[$tax] = true;
530 }
531 } else {
532 $term_hierarchy[$tax][] = [$term];
533 }
534 }
535 }
536 }
537 }
538
539 // TODO: Process term hierarchy
540 foreach ($term_hierarchy as $processed_tax => $term_hierarchy_list) {
541
542 // clear existing taxonomies
543 if (!isset($term_append[$processed_tax]) || !$term_append[$processed_tax]) {
544 wp_set_object_terms($post_id, null, $processed_tax);
545 }
546
547 if (empty($term_hierarchy_list)) {
548 continue;
549 }
550
551 foreach ($term_hierarchy_list as $hierarchy_list) {
552
553 $prev_term = isset($term_hierarchy_enabled[$processed_tax]) ? 0 : null;
554
555 foreach ($hierarchy_list as $term) {
556 if (!isset($this->_taxonomies[$processed_tax])) {
557 $this->_taxonomies[$processed_tax] = [];
558 }
559
560 $term_result = $this->create_or_get_taxonomy_term($post_id, $processed_tax, $term, $prev_term);
561 if ($term_result) {
562 $prev_term = $term_result->term_id;
563 $this->_taxonomies[$processed_tax][] = $term_result->name;
564 }
565 }
566 }
567 }
568 }
569
570 private function create_or_get_taxonomy_term($post_id, $tax, $term, $parent)
571 {
572
573 if (is_null($parent)) {
574
575 // we do not care about parent, just fetch first
576 $tmp_term = get_term_by('name', $term, $tax);
577 if ($tmp_term) {
578 wp_set_object_terms($post_id, $tmp_term->term_id, $tax, true);
579 return $tmp_term;
580 }
581 } else {
582 $terms = get_terms([
583 'taxonomy' => $tax,
584 'name' => $term,
585 'hide_empty' => false
586 ]);
587 if (!empty($terms)) {
588 foreach ($terms as $tmp_term) {
589 if (intval($tmp_term->parent) === intval($parent)) {
590
591 // attach term to post
592 wp_set_object_terms($post_id, $tmp_term->term_id, $tax, true);
593 return $tmp_term;
594 }
595 }
596 }
597 }
598
599 // add term
600 $term_id = wp_insert_term($term, $tax, ['parent' => $parent]);
601 if (!is_wp_error($term_id)) {
602 wp_set_object_terms($post_id, $term_id['term_id'], $tax, true);
603 return get_term($term_id['term_id'], $tax);
604 }
605
606 return false;
607 }
608
609 /**
610 * Process attachments group
611 *
612 * TODO: Possibly move this into parser?
613 *
614 * @param int $post_id
615 * @param ParsedData $data
616 * @param Filesystem $filesystem
617 * @param FTP $ftp
618 * @param Attachment $attachment
619 * @return void
620 */
621 public function process_attachments($post_id, $data, $filesystem, $ftp, $attachment, $group = 'attachments')
622 {
623 // reset list of attachments
624 $this->_attachments = [];
625 $attachment_ids = [];
626
627 $attachment_data = $data->getData($group);
628 $total_rows = isset($attachment_data[$group . '._index']) ? intval($attachment_data[$group . '._index']) : 0;
629 $skipped = 0;
630
631 for ($i = 0; $i < $total_rows; $i++) {
632
633 $permission_key = $group . '.' . $i; //attachment.0 | attachment.1
634 if ($data->permission()) {
635 $allowed = $data->permission()->validate([$permission_key => ''], $data->getMethod(), $group);
636 $is_allowed = isset($allowed[$permission_key]) ? true : false;
637 if (!$is_allowed) {
638 $skipped++;
639 continue;
640 }
641 }
642
643 // Process Attachments
644 $row_prefix = $group . '.' . $i . '.';
645
646 $sub_rows = [$attachment_data];
647 if (isset($attachment_data[$row_prefix . 'row_base']) && !empty($attachment_data[$row_prefix . 'row_base'])) {
648 $sub_group_id = $group . '.' . $i;
649 $sub_rows = $data->getData($sub_group_id);
650 }
651
652 foreach ($sub_rows as $row) {
653 $ids = $this->process_attachment($post_id, $row, $row_prefix, $filesystem, $ftp, $attachment);
654 $attachment_ids = array_merge($attachment_ids, $ids);
655 }
656 }
657
658 if ($skipped == $total_rows) {
659 return false;
660 }
661
662 return $attachment_ids;
663 }
664
665 /**
666 * Get list of posts
667 *
668 * @param ImporterModel $importer_model
669 *
670 * @return array
671 */
672 public function get_post_parent_options($importer_model)
673 {
674 $query = new \WP_Query(array(
675 'post_type' => $importer_model->getSetting('post_type'),
676 'posts_per_page' => -1,
677 'cache_results' => false,
678 'update_post_meta_cache' => false,
679 ));
680
681 if (is_wp_error($query)) {
682 return $query;
683 }
684
685 $result = [];
686 foreach ($query->posts as $post) {
687 $result[] = [
688 'value' => '' . $post->ID,
689 'label' => $post->post_title
690 ];
691 }
692
693 return $result;
694 }
695
696 /**
697 * Get list taxonomies
698 *
699 * @param ImporterModel $importer_model
700 *
701 * @return array
702 */
703 public function get_taxonomy_options($importer_model)
704 {
705 $taxonomies = get_object_taxonomies($importer_model->getSetting('post_type'), 'objects');
706
707 if (empty($taxonomies)) {
708 return [];
709 }
710
711 $result = [];
712 /**
713 * @var \WP_Taxonomy[] $taxonomies
714 */
715 foreach ($taxonomies as $key => $taxonomy) {
716 $result[] = [
717 'value' => '' . $key,
718 'label' => $taxonomy->label
719 ];
720 }
721
722 return $result;
723 }
724 }
725