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/Template.php +274 -57 2.8.3 → 2.15.0 View file →
@@ -5,8 +5,9 @@
5 5 use ImportWP\Common\Attachment\Attachment;
6 6 use ImportWP\Common\Filesystem\Filesystem;
7 7 use ImportWP\Common\Ftp\Ftp;
8 8 use ImportWP\Common\Importer\File\XMLFile;
9 +use ImportWP\Common\Importer\Mapper\AbstractMapper;
9 10 use ImportWP\Common\Importer\ParsedData;
10 11 use ImportWP\Common\Model\ImporterModel;
11 12 use ImportWP\Common\Util\Logger;
12 13 use ImportWP\Container;
@@ -47,8 +48,15 @@
47 48
48 49 protected $default_template_options = [];
49 50
50 51 /**
52 + *
53 + * List of optional fields that are enabled by default
54 + * @var string[]
55 + */
56 + protected $default_enabled_fields = [];
57 +
58 + /**
51 59 * @var \WP_Error[] $errors
52 60 */
53 61 protected $errors = [];
54 62
@@ -104,13 +112,28 @@
104 112 $file = new XMLFile($filePath, $config);
105 113 $file->setRecordPath($base_path);
106 114 $nodes = $file->get_node_list();
107 115
116 + // Nodes that appear as a parent of another path have selectable children.
117 + $parents = [];
108 118 foreach ($nodes as $node) {
119 + $parent = $node;
120 + while (($pos = strrpos($parent, '/')) !== false && $pos > 0) {
121 + $parent = substr($parent, 0, $pos);
122 + $parents[$parent] = true;
123 + }
124 + }
125 +
126 + foreach ($nodes as $node) {
109 127 if (strpos($node, $base_path) !== 0) {
110 128 continue;
111 129 }
112 130
131 + // Skip leaf nodes (e.g. /categories/category) — they have no selectable child nodes.
132 + if (!isset($parents[$node])) {
133 + continue;
134 + }
135 +
113 136 $sub_node = substr($node, strlen($base_path));
114 137
115 138 $results[] = [
116 139 'value' => $sub_node,
@@ -196,12 +219,12 @@
196 219 {
197 220 if (isset($args['row_base']) && true === $args['row_base']) {
198 221
199 222 $fields = array_merge(
200 - [$this->register_field('Repeater Node', 'row_base', [
223 + [$this->register_field(__('Repeater Node', 'jc-importer'), 'row_base', [
201 224 'type' => 'text',
202 225 'options' => 'callback',
203 - 'tooltip' => 'Select the path to the parent node containing values for this record, The preview when selecting data for each record should show a single record. Please note changing this will require updating references in this record.'
226 + 'tooltip' => __('Select the path to the parent node containing values for this record, The preview when selecting data for each record should show a single record. Please note changing this will require updating references in this record.', 'jc-importer')
204 227 ])],
205 228 $fields
206 229 );
207 230 }
@@ -209,15 +232,30 @@
209 232 $tmp = [
210 233 'id' => $key,
211 234 'heading' => $label,
212 235 'type' => isset($args['type']) ? $args['type'] : 'group',
213 - 'fields' => $fields
236 + 'fields' => $fields,
214 237 ];
215 238
239 + if (isset($args['link']) && !empty($args['link'])) {
240 + $tmp['link'] = $args['link'];
241 + }
242 +
216 243 if (isset($args['condition']) && !empty($args['condition'])) {
217 244 $tmp['condition'] = $args['condition'];
218 245 }
219 246
247 + // Allow for setting fields to be registered for the group
248 + // currently only supporting toggle fields.
249 + if (isset($args['settings']) && !empty($args['settings'])) {
250 + $tmp['settings'] = $args['settings'];
251 + }
252 +
253 + // Field ids used to build the collapsed repeater row summary in the UI.
254 + if (isset($args['row_summary']) && !empty($args['row_summary'])) {
255 + $tmp['row_summary'] = array_values((array) $args['row_summary']);
256 + }
257 +
220 258 return $tmp;
221 259 }
222 260
223 261 public function register_core_field($label, $key, $args = [])
@@ -256,107 +294,109 @@
256 294
257 295 $fields = [];
258 296
259 297 if (!in_array('_featured', $disabled_fields)) {
260 - $fields[] = $this->register_field('Is Featured?', '_featured', [
298 + $fields[] = $this->register_field(__('Is Featured?', 'jc-importer'), '_featured', [
261 299 'default' => 'no',
262 300 'options' => [
263 - ['value' => 'no', 'label' => 'No'],
264 - ['value' => 'yes', 'label' => 'Yes'],
301 + ['value' => 'no', 'label' => __('No', 'jc-importer')],
302 + ['value' => 'yes', 'label' => __('Yes', 'jc-importer')],
265 303 ],
266 - 'tooltip' => __('Is the attachment the featured image for the current post.', 'importwp')
304 + 'tooltip' => __('Is the attachment the featured image for the current post.', 'jc-importer')
267 305 ]);
268 306 }
269 307
270 308 $fields = array_merge($fields, [
271 - $this->register_field('Download', '_download', [
309 + $this->register_field(__('Download', 'jc-importer'), '_download', [
272 310 'default' => 'remote',
273 311 'options' => [
274 - ['value' => 'remote', 'label' => 'Remote URL'],
275 - ['value' => 'ftp', 'label' => 'FTP'],
276 - ['value' => 'local', 'label' => 'Local Filesystem'],
277 - ['value' => 'media', 'label' => 'Media Library'],
312 + ['value' => 'remote', 'label' => __('Remote URL', 'jc-importer')],
313 + ['value' => 'ftp', 'label' => __('FTP', 'jc-importer')],
314 + ['value' => 'local', 'label' => __('Local Filesystem', 'jc-importer')],
315 + ['value' => 'media', 'label' => __('Media Library', 'jc-importer')],
278 316 ],
279 - 'tooltip' => __('Select how the attachment is being downloaded.', 'importwp')
317 + 'tooltip' => __('Select how the attachment is being downloaded.', 'jc-importer')
280 318 ]),
281 - $this->register_field('Host', '_ftp_host', [
319 + $this->register_field(__('Host', 'jc-importer'), '_ftp_host', [
282 320 'condition' => ['_download', '==', 'ftp'],
283 - 'tooltip' => __('Enter the FTP hostname', 'importwp')
321 + 'tooltip' => __('Enter the FTP hostname', 'jc-importer')
284 322 ]),
285 - $this->register_field('Username', '_ftp_user', [
323 + $this->register_field(__('Username', 'jc-importer'), '_ftp_user', [
286 324 'condition' => ['_download', '==', 'ftp'],
287 - 'tooltip' => __('Enter the FTP username', 'importwp')
325 + 'tooltip' => __('Enter the FTP username', 'jc-importer')
288 326 ]),
289 - $this->register_field('Password', '_ftp_pass', [
327 + $this->register_field(__('Password', 'jc-importer'), '_ftp_pass', [
290 328 'condition' => ['_download', '==', 'ftp'],
291 - 'tooltip' => __('Enter the FTP password', 'importwp')
329 + 'tooltip' => __('Enter the FTP password', 'jc-importer')
292 330 ]),
293 - $this->register_field('Path', '_ftp_path', [
331 + $this->register_field(__('Path', 'jc-importer'), '_ftp_path', [
294 332 'condition' => ['_download', '==', 'ftp'],
295 - 'tooltip' => __('Enter the FTP base path, this is prefixed onto the Location field, leave empty to be ignore', 'importwp')
333 + 'tooltip' => __('Enter the FTP base path, this is prefixed onto the Location field, leave empty to be ignore', 'jc-importer')
296 334 ]),
297 - $this->register_field('Base URL', '_remote_url', [
335 + $this->register_field(__('Base URL', 'jc-importer'), '_remote_url', [
298 336 'condition' => ['_download', '==', 'remote'],
299 - 'tooltip' => __('Enter the base url, this is prefixed onto the Location field, leave empty to be ignore', 'importwp')
337 + 'tooltip' => __('Enter the base url, this is prefixed onto the Location field, leave empty to be ignore', 'jc-importer')
300 338 ]),
301 - $this->register_field('Base URL', '_local_url', [
339 + $this->register_field(__('Base URL', 'jc-importer'), '_local_url', [
302 340 'condition' => ['_download', '==', 'local'],
303 - 'tooltip' => __('Enter the base path from this servers root file system, this is prefixed onto the Location field, leave empty to be ignore', 'importwp')
341 + 'tooltip' => __('Enter the base path from this servers root file system, this is prefixed onto the Location field, leave empty to be ignore', 'jc-importer')
304 342 ]),
305 343
306 - $this->register_field('Permissions', '_enable_image_hash', [
344 + $this->register_field(__('Permissions', 'jc-importer'), '_enable_image_hash', [
307 345 'condition' => ['_download', '!=', 'media'],
308 346 'default' => 'yes',
309 347 'options' => [
310 - ['value' => 'no', 'label' => 'Always download new files'],
311 - ['value' => 'yes', 'label' => 'Search media library before downloading new files'],
348 + ['value' => 'no', 'label' => __('Always download new files', 'jc-importer')],
349 + ['value' => 'yes', 'label' => __('Search media library before downloading new files', 'jc-importer')],
312 350 ],
313 - 'tooltip' => __('Enable to stop duplicate images by searching the media library before downloading new files.', 'importwp')
351 + 'tooltip' => __('Enable to stop duplicate images by searching the media library before downloading new files.', 'jc-importer')
314 352 ]),
315 - $this->register_field('Delimiter', '_delimiter', [
353 + $this->register_field(__('Delimiter', 'jc-importer'), '_delimiter', [
316 354 'type' => 'text',
317 - 'tooltip' => 'A single character used to seperate attachments when listing multiple, Leave empty to use default: ,'
355 + 'tooltip' => sprintf(__('A single character used to seperate attachments when listing multiple, Leave empty to use the default: %s', 'jc-importer'), ',')
318 356 ]),
319 357
320 358 ]);
321 359
322 360 if (!in_array('_meta', $disabled_fields)) {
323 - $fields[] = $this->register_group('Attachment Meta', '_meta', [
324 - $this->register_field('Enable Meta', '_enabled', [
361 + $fields[] = $this->register_group(__('Attachment Meta', 'jc-importer'), '_meta', [
362 + $this->register_field(__('Enable Meta', 'jc-importer'), '_enabled', [
325 363 'default' => 'no',
326 364 'options' => [
327 - ['value' => 'no', 'label' => 'No'],
328 - ['value' => 'yes', 'label' => 'Yes'],
365 + ['value' => 'no', 'label' => __('No', 'jc-importer')],
366 + ['value' => 'yes', 'label' => __('Yes', 'jc-importer')],
329 367 ],
330 368 'type' => 'select',
331 - 'tooltip' => __('Enable/Disable the fields to import attachment meta data.', 'importwp')
369 + 'tooltip' => __('Enable/Disable the fields to import attachment meta data.', 'jc-importer')
332 370 ]),
333 - $this->register_field('Alt Text', '_alt', [
371 + $this->register_field(__('Alt Text', 'jc-importer'), '_alt', [
334 372 'condition' => ['_enabled', '==', 'yes'],
335 - 'tooltip' => __('Image attachment alt text.', 'importwp'),
373 + 'tooltip' => __('Image attachment alt text.', 'jc-importer'),
336 374 ]),
337 - $this->register_field('Title Text', '_title', [
375 + $this->register_field(__('Title Text', 'jc-importer'), '_title', [
338 376 'condition' => ['_enabled', '==', 'yes'],
339 - 'tooltip' => __('Attachments title text.', 'importwp')
377 + 'tooltip' => __('Attachments title text.', 'jc-importer')
340 378 ]),
341 - $this->register_field('Caption Text', '_caption', [
379 + $this->register_field(__('Caption Text', 'jc-importer'), '_caption', [
342 380 'condition' => ['_enabled', '==', 'yes'],
343 - 'tooltip' => __('Image attachments caption text.', 'importwp')
381 + 'tooltip' => __('Image attachments caption text.', 'jc-importer')
344 382 ]),
345 - $this->register_field('Description Text', '_description', [
383 + $this->register_field(__('Description Text', 'jc-importer'), '_description', [
346 384 'condition' => ['_enabled', '==', 'yes'],
347 - 'tooltip' => __('Attachments description text.', 'importwp')
385 + 'tooltip' => __('Attachments description text.', 'jc-importer')
348 386 ])
349 387 ]);
350 388 }
351 389
352 - return $this->register_group('Settings', 'settings', array_merge($extra_fields, $fields), ['type' => 'settings', 'condition' => $display_conditions]);
390 + return $this->register_group(__('Settings', 'jc-importer'), 'settings', array_merge($extra_fields, $fields), ['type' => 'settings', 'condition' => $display_conditions]);
353 391 }
354 392
355 - public function register_attachment_fields($label = 'Attachments', $name = 'attachments', $field_label = 'Location', $group_args = null, $attachment_args = [])
393 + public function register_attachment_fields($label = 'Images & Attachments', $name = 'attachments', $field_label = 'Location', $group_args = null, $attachment_args = [])
356 394 {
357 395 if (is_null($group_args)) {
358 - $group_args = ['type' => 'repeatable', 'row_base' => true];
396 + $group_args = ['type' => 'repeatable', 'row_base' => true, 'row_summary' => ['location'], 'link' => 'https://www.importwp.com/docs/how-to-import-wordpress-attachments-onto-a-post-type/'];
397 + } else if (!isset($group_args['row_summary'])) {
398 + $group_args['row_summary'] = ['location'];
359 399 }
360 400
361 401 $display_conditions = isset($attachment_args['conditions']) ? $attachment_args['conditions'] : [];
362 402 $extra_fields = isset($attachment_args['extra_fields']) ? $attachment_args['extra_fields'] : [];
@@ -363,9 +403,9 @@
363 403 $disabled_fields = isset($attachment_args['disabled_fields']) ? $attachment_args['disabled_fields'] : [];
364 404
365 405 return $this->register_group($label, $name, [
366 406 $this->register_field($field_label, 'location', [
367 - 'tooltip' => __('The source location of the file being attached.', 'importwp')
407 + 'tooltip' => __('The source location of the file being attached.', 'jc-importer')
368 408 ]),
369 409 $this->_register_attachment_setting_fields($display_conditions, $extra_fields, $disabled_fields)
370 410 ], $group_args);
371 411 }
@@ -469,8 +509,20 @@
469 509 $field_groups['default']['fields'][$field_id] = $field_value;
470 510 }
471 511 }
472 512
513 + if ($this->importer->has_custom_unique_identifier()) {
514 +
515 + $ref = $this->importer->getSetting('unique_identifier_ref');
516 +
517 + $field_groups['iwp'] = [
518 + 'id' => 'iwp',
519 + 'fields' => [
520 + $this->importer->get_iwp_reference_meta_key() => (!is_null($ref) ? $ref : '')
521 + ]
522 + ];
523 + }
524 +
473 525 return $field_groups;
474 526 }
475 527
476 528 /**
@@ -512,19 +564,21 @@
512 564 {
513 565 // Allows virtual groups to be registered
514 566 $this->groups = $this->event_handler->run('template.pre_process_groups', [$this->groups, $data, $this]);
515 567
516 - $map = $data->getData('default');
517 - foreach ($this->groups as $group) {
518 - $group_map = [];
568 + if (is_array($this->groups) && !empty($this->groups)) {
569 + $map = $data->getData('default');
570 + foreach ($this->groups as $group) {
571 + $group_map = [];
519 572
520 - foreach ($map as $field_key => $fields_map) {
521 - if (preg_match('/^' . $group . '\.(.*?)$/', $field_key) === 1) {
522 - $group_map[$field_key] = $fields_map;
573 + foreach ($map as $field_key => $fields_map) {
574 + if (preg_match('/^' . $group . '\.(.*?)$/', $field_key) === 1) {
575 + $group_map[$field_key] = $fields_map;
576 + }
523 577 }
578 +
579 + $data->replace($group_map, $group);
524 580 }
525 -
526 - $data->replace($group_map, $group);
527 581 }
528 582
529 583 return $data;
530 584 }
@@ -657,10 +711,18 @@
657 711 if ($attachment_enable_image_hash == 'yes') {
658 712 $attachment_id = $attachment->get_attachment_by_hash($source);
659 713 }
660 714
715 + // check to see if remote url matches file existing in media library
661 716 if ($attachment_id <= 0) {
717 + $dir = wp_get_upload_dir();
718 + if (str_starts_with($source, $dir['baseurl'] . '/')) {
719 + $attachment_id = attachment_url_to_postid($source);
720 + }
721 + }
662 722
723 + if ($attachment_id <= 0) {
724 +
663 725 $main_zip_file = false;
664 726 if ($base_url === 'iwp_zip') {
665 727 $main_zip = get_post_meta($this->importer->getId(), '_iwp_zip', true);
666 728 if ($main_zip && file_exists($main_zip)) {
@@ -683,9 +745,9 @@
683 745 break;
684 746 }
685 747
686 748 if (!$result) {
687 - $result = new \WP_Error('IWP_HTTP_2', 'Error downloading zip file');
749 + $result = new \WP_Error('IWP_HTTP_2', __('Error downloading zip file', 'jc-importer'));
688 750 break;
689 751 }
690 752 }
691 753
@@ -697,8 +759,40 @@
697 759 break;
698 760 }
699 761 }
700 762
763 + if (apply_filters('iwp/template/process_attachment/enable_file_size_hash', false) === true) {
764 +
765 + // check to see if the remote url image is the same size as the one on disk.
766 + if ($attachment_id > 0 && $attachment_enable_image_hash == 'yes') {
767 +
768 + $existing_file = get_attached_file($attachment_id, true);
769 +
770 + // Remove -scaled from the file name if it exists
771 + if ($existing_file && file_exists($existing_file)) {
772 + $existing_file = str_replace('-scaled.', '.', $existing_file);
773 + }
774 +
775 + if ($existing_file && file_exists($existing_file)) {
776 + $head = wp_remote_head($source);
777 + if (!is_wp_error($head)) {
778 +
779 + // get file size from the header
780 + $header_key = apply_filters('iwp/template/process_attachment/remote_file_size_header_key', 'content-length');
781 + $size = wp_remote_retrieve_header($head, $header_key);
782 + $existing_file_size = filesize($existing_file);
783 +
784 + if ($size != $existing_file_size) {
785 +
786 + // append the size to the attachment salt
787 + $attachment_salt .= $size;
788 + $attachment_id = $attachment->get_attachment_by_hash($source, $attachment_salt);
789 + }
790 + }
791 + }
792 + }
793 + }
794 +
701 795 $custom_filename = apply_filters('iwp/attachment/filename', null, $source);
702 796 if ($attachment_id <= 0) {
703 797 Logger::write(__CLASS__ . '::process__attachments -remote=' . $source . ' -filename=' . $custom_filename);
704 798 $result = $filesystem->download_file($source, null, null, $custom_filename);
@@ -884,8 +978,32 @@
884 978 $attachment_args['caption'] = isset($attachment_captions[$location_counter]) ? $attachment_captions[$location_counter] : null;
885 979 $attachment_args['description'] = isset($attachment_descriptions[$location_counter]) ? $attachment_descriptions[$location_counter] : null;;
886 980 }
887 981
982 + // resize attachment
983 + if ($crop_details = apply_filters('iwp/importer/template/process_attachment/resize', '__return_false')) {
984 +
985 + if (is_array($crop_details) && count($crop_details) == 3 && file_exists($result['dest'])) {
986 +
987 + list($max_w, $max_h, $crop) = $crop_details;
988 +
989 + if (!is_null($max_w)) {
990 + $max_w = absint($max_w);
991 + }
992 + if (!is_null($max_h)) {
993 + $max_h = absint($max_h);
994 + }
995 +
996 + $editor = wp_get_image_editor($result['dest']);
997 + if (!is_wp_error($editor)) {
998 + $editor->resize($max_w, $max_h, (bool)$crop);
999 + $editor->save($result['dest']);
1000 + } else {
1001 + Logger::write(__CLASS__ . '::process__attachments -resize -error=' . $editor->get_error_message());
1002 + }
1003 + }
1004 + }
1005 +
888 1006 $attachment_id = $attachment->insert_attachment($post_id, $result['dest'], $result['mime'], $attachment_args);
889 1007 if (is_wp_error($attachment_id)) {
890 1008 Logger::write(__CLASS__ . '::process__attachments -error=' . $attachment_id->get_error_message());
891 1009 continue;
@@ -939,8 +1057,47 @@
939 1057 return $attachment_ids;
940 1058 }
941 1059
942 1060 /**
1061 + * Remove custom field meta fields from the provided array based on importer permissions.
1062 + *
1063 + * @param string[string] $custom_fields
1064 + * @param ParsedData $data
1065 + * @param string $group_name
1066 + * @param string $permission_key
1067 + * @param string $prefix
1068 + * @return string[string]
1069 + */
1070 + public function process_attachment_meta_permissions($custom_fields, $data, $group_name, $permission_key, $prefix)
1071 + {
1072 + $allowed = $data->permission()->validate([
1073 + $permission_key . '._alt' => '',
1074 + $permission_key . '._title' => '',
1075 + $permission_key . '._caption' => '',
1076 + $permission_key . '._description' => ''
1077 + ], $data->getMethod(), $group_name);
1078 +
1079 + if (!isset($allowed[$permission_key . '._alt'])) {
1080 + // remove alt
1081 + unset($custom_fields[$prefix . 'settings._meta._alt']);
1082 + }
1083 + if (!isset($allowed[$permission_key . '._title'])) {
1084 + // remove title
1085 + unset($custom_fields[$prefix . 'settings._meta._title']);
1086 + }
1087 + if (!isset($allowed[$permission_key . '._caption'])) {
1088 + // remove caption
1089 + unset($custom_fields[$prefix . 'settings._meta._caption']);
1090 + }
1091 + if (!isset($allowed[$permission_key . '._description'])) {
1092 + // remove description
1093 + unset($custom_fields[$prefix . 'settings._meta._description']);
1094 + }
1095 +
1096 + return $custom_fields;
1097 + }
1098 +
1099 + /**
943 1100 * Add error message
944 1101 *
945 1102 * @param string|\WP_Error $error
946 1103 * @return void
@@ -1012,6 +1169,66 @@
1012 1169 $main_zip = get_post_meta($this->importer->getId(), '_iwp_zip', true);
1013 1170 $source = $main_zip . $location;
1014 1171 $base_url .= $main_zip;
1015 1172 }
1173 + }
1174 +
1175 + public function get_permission_fields($importer_model)
1176 + {
1177 + return [];
1178 + }
1179 +
1180 + public function register_settings() {}
1181 +
1182 + public function register_options()
1183 + {
1184 + return [];
1185 + }
1186 +
1187 + public function get_default_enabled_fields()
1188 + {
1189 + return $this->default_enabled_fields;
1190 + }
1191 +
1192 +
1193 + public function get_unique_identifier_options($importer_model, $unique_fields = [])
1194 + {
1195 + $output = [];
1196 + return $output;
1197 + }
1198 +
1199 + public function get_unique_identifier_options_from_map($importer_model, $unique_fields, $field_map, $optional_fields)
1200 + {
1201 + $output = [];
1202 + $mapped_data = $importer_model->getMap();
1203 +
1204 + foreach ($field_map as $field_id => $field_map_key) {
1205 +
1206 + if (isset($output[$field_id])) {
1207 + continue;
1208 + }
1209 +
1210 + $output[$field_id] = [
1211 + 'value' => $field_id,
1212 + 'label' => $field_id,
1213 + 'uid' => false,
1214 + 'active' => false,
1215 + ];
1216 +
1217 + if (in_array($field_id, $unique_fields)) {
1218 + $output[$field_id]['uid'] = true;
1219 + }
1220 +
1221 + if (!isset($mapped_data[$field_map_key]) || empty($mapped_data[$field_map_key])) {
1222 + continue;
1223 + }
1224 +
1225 + if (in_array($field_id, $optional_fields) && true !== $importer_model->isEnabledField($field_map_key)) {
1226 + continue;
1227 + }
1228 +
1229 + $output[$field_id]['active'] = true;
1230 + }
1231 +
1232 + return $output;
1016 1233 }
1017 1234 }