PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / trunk
Pods – Custom Content Types and Fields vtrunk
trunk 1.14.8 2.7.31.3 2.8.23.3 2.9.19.3 3.0.10.3 3.1.4.1 3.2.0 3.2.1 3.2.1.1 3.2.2 3.2.4 3.2.5 3.2.6 3.2.7 3.2.7.1 3.2.8 3.2.8.1 3.2.8.2 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
pods / classes / PodsMigrate.php
pods / classes Last commit date
cli 4 months ago fields 4 months ago widgets 4 months ago Pods.php 4 months ago PodsAPI.php 4 months ago PodsAdmin.php 4 months ago PodsArray.php 4 months ago PodsComponent.php 4 months ago PodsComponents.php 4 months ago PodsData.php 4 months ago PodsField.php 4 months ago PodsForm.php 4 months ago PodsI18n.php 4 months ago PodsInit.php 4 months ago PodsMeta.php 4 months ago PodsMigrate.php 4 months ago PodsRESTFields.php 4 months ago PodsRESTHandlers.php 4 months ago PodsTermSplitting.php 4 months ago PodsUI.php 4 months ago PodsView.php 4 months ago
PodsMigrate.php
1396 lines
1 <?php
2
3 // Don't load directly.
4 if ( ! defined( 'ABSPATH' ) ) {
5 die( '-1' );
6 }
7
8 /**
9 * @package Pods
10 */
11 class PodsMigrate {
12
13 /**
14 * @var null|string
15 */
16 public $type = 'php';
17
18 /**
19 * @var array
20 */
21 public $types = array( 'php', 'json', 'sv', 'xml' );
22
23 /**
24 * @var array
25 */
26 public $mimes = array(
27 'json' => 'application/json',
28 'csv' => 'text/csv',
29 'tsv' => 'text/tsv',
30 'xml' => 'text/xml',
31 );
32
33 /**
34 * @var null|string
35 */
36 public $delimiter = ',';
37
38 /**
39 * @var null
40 */
41 public $data = array(
42 'items' => array(),
43 'columns' => array(),
44 'fields' => array(),
45 'single' => false,
46 );
47
48 /**
49 * @var null
50 */
51 public $input;
52
53 /**
54 * @var
55 */
56 public $parsed;
57
58 /**
59 * @var
60 */
61 public $built;
62
63 /**
64 * Migrate Data to and from Pods
65 *
66 * @param string $type Export Type (php, json, sv, xml)
67 * @param string $delimiter Delimiter for export type 'sv'
68 * @param array $data Array of data settings
69 *
70 * @return \PodsMigrate
71 *
72 * @license http://www.gnu.org/licenses/gpl-2.0.html
73 * @since 2.0.0
74 */
75 public function __construct( $type = null, $delimiter = null, $data = null ) {
76
77 if ( ! empty( $type ) ) {
78 if ( 'csv' === $type ) {
79 $type = 'sv';
80
81 if ( null === $delimiter ) {
82 $delimiter = ',';
83 }
84 } elseif ( 'tsv' === $type ) {
85 $type = 'sv';
86
87 if ( null === $delimiter ) {
88 $delimiter = "\t";
89 }
90 }
91
92 if ( in_array( $type, $this->types, true ) ) {
93 $this->type = $type;
94 }
95 }
96
97 if ( ! empty( $delimiter ) ) {
98 $this->delimiter = $delimiter;
99 }
100
101 if ( ! empty( $data ) ) {
102 $this->set_data( $data );
103 }
104 }
105
106 /**
107 * @param $data
108 */
109 public function set_data( $data ) {
110
111 $defaults = array(
112 'items' => array(),
113 'columns' => array(),
114 'fields' => array(),
115 );
116
117 $this->data = array_merge( $defaults, (array) $data );
118 }
119
120 /**
121 * Get items.
122 *
123 * @since 2.7.17
124 *
125 * @return array List of data items.
126 */
127 private function get_items() {
128
129 return empty( $this->data['single'] ) ?
130 $this->data['items'] :
131 array( $this->data['items'] );
132
133 }
134
135 /**
136 * Importing / Parsing / Validating Code
137 *
138 * @param array $data Array of data
139 * @param string $type Export Type (php, json, sv, xml)
140 * @param string $delimiter Delimiter for export type 'sv'
141 *
142 * @return bool
143 */
144 public function import( $data = null, $type = null, $delimiter = null ) {
145
146 $this->parse( $data, $type, $delimiter );
147
148 return $this->import_pod_items();
149
150 }
151
152 /**
153 * @param array $data Array of data
154 * @param string $type Export Type (php, json, sv, xml)
155 *
156 * @return bool
157 */
158 public function import_pod_items( $data = null, $type = null ) {
159
160 if ( ! empty( $data ) ) {
161 $this->input = $data;
162 }
163
164 if ( ! empty( $type ) && in_array( $type, $this->types, true ) ) {
165 $this->type = $type;
166 }
167
168 return false;
169 }
170
171 /**
172 * @param array $data Array of data
173 * @param string $type Parse Type (php, json, sv, xml)
174 * @param string $delimiter Delimiter for export type 'sv'
175 *
176 * @return null
177 */
178 public function parse( $data = null, $type = null, $delimiter = null ) {
179
180 if ( ! empty( $data ) ) {
181 $this->input = $data;
182 }
183
184 if ( ! empty( $type ) && in_array( $type, $this->types, true ) ) {
185 $this->type = $type;
186 }
187
188 if ( !empty( $delimiter ) )
189 $this->delimiter = $delimiter;
190
191 if ( method_exists( $this, "parse_{$this->type}" ) ) {
192 return call_user_func( array( $this, 'parse_' . $this->type ) );
193 }
194
195 return $this->parsed;
196 }
197
198 /**
199 * @param array $data Array of data
200 *
201 * @return bool
202 */
203 public function parse_json( $data = null ) {
204
205 if ( ! empty( $data ) ) {
206 $this->input = $data;
207 }
208
209 $items = @json_decode( $this->input, true );
210
211 if ( ! is_array( $items ) ) {
212 return false;
213 }
214
215 // Only export to a basic object if building for a single item.
216 if ( ! empty( $this->data['single'] ) ) {
217 $data = $items;
218 } else {
219 $data = array(
220 'columns' => array(),
221 'items' => array(),
222 'fields' => array(),
223 );
224
225 foreach ( $items as $key => $item ) {
226 if ( ! is_array( $item ) ) {
227 continue;
228 }
229
230 foreach ( $item as $column => $value ) {
231 if ( ! in_array( $column, $data['columns'], true ) ) {
232 $data['columns'][] = $column;
233 }
234 }
235
236 $data['items'][ $key ] = $item;
237 }
238 }
239
240 $this->parsed = $data;
241
242 return $this->parsed;
243 }
244
245 /**
246 * @param array $data Array of data
247 * @param string $delimiter Delimiter for export type 'sv'
248 *
249 * @return bool
250 */
251 public function parse_sv( $data = null, $delimiter = null ) {
252
253 if ( ! empty( $data ) ) {
254 $this->input = $data;
255 }
256
257 if ( ! empty( $delimiter ) ) {
258 $this->delimiter = $delimiter;
259 }
260
261 $rows = $this->str_getcsv( $this->input, '\n' );
262
263 if ( empty( $rows ) || 2 > count( $rows ) ) {
264 return false;
265 }
266
267 $data = array(
268 'columns' => array(),
269 'items' => array(),
270 );
271
272 foreach ( $rows as $key => $row ) {
273 if ( 0 === $key ) {
274 $data['columns'] = $this->str_getcsv( $row, $this->delimiter );
275 } else {
276 $row = $this->str_getcsv( $row, $this->delimiter );
277
278 $data['items'][ $key ] = array();
279
280 foreach ( $data['columns'] as $ckey => $column ) {
281 $column_value = (string) ( isset( $row[ $ckey ] ) ? $row[ $ckey ] : '' );
282
283 if ( 'NULL' === $column_value ) {
284 // Maybe set the value as null.
285 $column_value = null;
286 } elseif (
287 0 === strpos( $column_value, '\\=' )
288 || 0 === strpos( $column_value, '\\+' )
289 || 0 === strpos( $column_value, '\\-' )
290 || 0 === strpos( $column_value, '\\@' )
291 ) {
292 // Maybe remove the first backslash.
293 $column_value = substr( $column_value, 1 );
294 }
295
296 $data['items'][ $key ][ $column ] = $column_value;
297 }
298 }
299 }
300
301 $this->parsed = $data;
302
303 return $this->parsed;
304 }
305
306 /**
307 * Handle str_getcsv for cases where it's not set
308 *
309 * @param $line
310 * @param string $delimiter
311 * @param string $enclosure
312 * @param string $escape
313 *
314 * @return array|mixed
315 */
316 public function str_getcsv( $line, $delimiter = ',', $enclosure = '"', $escape = '\\' ) {
317
318 $line = str_replace( "\r\n", "\n", $line );
319 $line = str_replace( "\r", "\n", $line );
320
321 if ( '\n' !== $delimiter && function_exists( 'str_getcsv' ) ) {
322 return str_getcsv( $line, $delimiter, $enclosure, $escape );
323 }
324
325 $delimiter = str_replace( '/', '\/', $delimiter );
326 $enclosure = preg_quote( $enclosure, '/' );
327
328 $split = "/{$delimiter}(?=(?:[^{$enclosure}]*{$enclosure}[^{$enclosure}]*{$enclosure})*(?![^{$enclosure}]*{$enclosure}))/";
329
330 $data = preg_split( $split, trim( $line ), - 1, PREG_SPLIT_NO_EMPTY );
331
332 if ( '\n' !== $delimiter ) {
333 $data = preg_replace( "/^{$enclosure}(.*){$enclosure}$/s", '$1', $data );
334 }
335
336 return $data;
337 }
338
339 /**
340 * @param array $data Array of data
341 *
342 * @return bool
343 */
344 public function parse_xml( $data = null ) {
345
346 if ( ! empty( $data ) ) {
347 $this->input = $data;
348 }
349
350 $xml = new SimpleXMLElement( $this->input );
351
352 if ( ! isset( $xml->items ) ) {
353 return false;
354 }
355
356 $data = array(
357 'columns' => array(),
358 'items' => array(),
359 );
360
361 /**
362 * @var $child SimpleXMLElement
363 * @var $item_child SimpleXMLElement
364 * @var $data_child SimpleXMLElement
365 */
366
367 if ( isset( $xml->columns ) ) {
368 foreach ( $xml->columns->children() as $child ) {
369 $sub = $child->getName();
370
371 if ( empty( $sub ) || 'column' !== $sub ) {
372 continue;
373 }
374
375 if ( isset( $child->name ) ) {
376 if ( is_array( $child->name ) ) {
377 $column = $child->name[0];
378 } else {
379 $column = $child->name;
380 }
381
382 $data['columns'][] = $column;
383 }
384 }
385 }
386
387 foreach ( $xml->items->children() as $child ) {
388 $sub = $child->getName();
389
390 if ( empty( $sub ) || 'item' !== $sub ) {
391 continue;
392 }
393
394 $item = array();
395
396 $attributes = $child->attributes();
397
398 if ( ! empty( $attributes ) ) {
399 foreach ( $attributes as $column => $value ) {
400 if ( ! in_array( $column, $data['columns'], true ) ) {
401 $data['columns'][] = $column;
402 }
403
404 $item[ $column ] = $value;
405 }
406 }
407
408 $item_child = $child->children();
409
410 if ( ! empty( $item_child ) ) {
411 foreach ( $item_child->children() as $data_child ) {
412 $column = $data_child->getName();
413
414 if ( ! in_array( $column, $data['columns'], true ) ) {
415 $data['columns'][] = $column;
416 }
417
418 $item[ $column ] = $item_child->$column;
419 }
420 }
421
422 if ( ! empty( $item ) ) {
423 $data['items'][] = $item;
424 }
425 }//end foreach
426
427 $this->parsed = $data;
428
429 return $this->parsed;
430 }
431
432 /**
433 * @param array $data Array of data
434 *
435 * @return mixed
436 *
437 * @todo For much much later
438 */
439 public function parse_sql( $data = null ) {
440
441 if ( ! empty( $data ) ) {
442 $this->input = $data;
443 }
444
445 $this->parsed = $data;
446
447 return $this->parsed;
448 }
449
450 /**
451 * Exporting / Building Code
452 *
453 * @param array $data Array of data
454 * @param string $type Export Type (php, json, sv, xml)
455 * @param string $delimiter Delimiter for export type 'sv'
456 *
457 * @return mixed
458 */
459 public function export( $data = null, $type = null, $delimiter = null ) {
460
461 if ( ! empty( $data ) ) {
462 $this->set_data( $data );
463 }
464
465 if ( ! empty( $type ) && in_array( $type, $this->types, true ) ) {
466 $this->type = $type;
467 }
468
469 if ( ! empty( $delimiter ) ) {
470 $this->delimiter = $delimiter;
471 }
472
473 if ( method_exists( $this, "build_{$this->type}" ) ) {
474 call_user_func( array( $this, 'build_' . $this->type ) );
475 }
476
477 return $this->built;
478 }
479
480 /**
481 * @param array $data Array of data
482 */
483 public function export_pod_items( $data = null ) {
484
485 if ( ! empty( $data ) ) {
486 $this->set_data( $data );
487 }
488 }
489
490 /**
491 * @param array $data Array of data
492 * @param string $type Export Type (php, json, sv, xml)
493 *
494 * @return null
495 */
496 public function build( $data = null, $type = null ) {
497
498 if ( ! empty( $data ) ) {
499 $this->set_data( $data );
500 }
501
502 if ( ! empty( $type ) && in_array( $type, $this->types, true ) ) {
503 $this->type = $type;
504 }
505
506 if ( method_exists( $this, "build_{$this->type}" ) ) {
507 call_user_func( array( $this, 'build_' . $this->type ) );
508 }
509
510 return $this->data;
511 }
512
513 /**
514 * @param array $data Array of data
515 *
516 * @return bool
517 */
518 public function build_json( $data = null ) {
519
520 if ( ! empty( $data ) ) {
521 $this->set_data( $data );
522 }
523
524 if ( empty( $this->data ) || ! is_array( $this->data ) ) {
525 return false;
526 }
527
528 // Only export to a basic object if building for a single item.
529 if ( ! empty( $this->data['single'] ) ) {
530 $data = $this->data['items'];
531 } else {
532 $data = array(
533 'items' => array(
534 'count' => count( $this->data['items'] ),
535 'item' => array(),
536 ),
537 );
538
539 foreach ( $this->data['items'] as $item ) {
540 $row = array();
541
542 foreach ( $this->data['columns'] as $column => $label ) {
543 if ( is_numeric( $column ) && ( ( is_object( $item ) && ! isset( $item->$column ) ) || ( is_array( $item ) && ! isset( $item[ $column ] ) ) ) ) {
544 $column = $label;
545 }
546
547 $value = '';
548
549 if ( is_object( $item ) ) {
550 if ( ! isset( $item->$column ) ) {
551 $item->$column = '';
552 }
553
554 $value = $item->$column;
555 } elseif ( is_array( $item ) ) {
556 if ( ! isset( $item[ $column ] ) ) {
557 $item[ $column ] = '';
558 }
559
560 $value = $item[ $column ];
561 }
562
563 $row[ $column ] = $value;
564 }//end foreach
565
566 $data['items']['item'][] = $row;
567 }//end foreach
568 }
569
570 $this->built = @json_encode( $data );
571
572 return $this->built;
573 }
574
575 /**
576 * @param array $data Array of data
577 * @param string $delimiter Delimiter for export type 'sv'
578 *
579 * @return bool
580 */
581 public function build_sv( $data = null, $delimiter = null ) {
582
583 if ( ! empty( $data ) ) {
584 $this->set_data( $data );
585 }
586
587 if ( ! empty( $delimiter ) ) {
588 $this->delimiter = $delimiter;
589 }
590
591 if ( empty( $this->data ) || ! is_array( $this->data ) ) {
592 return false;
593 }
594
595 $head = '';
596 $lines = '';
597
598 foreach ( $this->data['columns'] as $column => $label ) {
599 $head .= '"' . $label . '"' . $this->delimiter;
600 }
601
602 $head = substr( $head, 0, - 1 );
603
604 $items = $this->get_items();
605
606 foreach ( $items as $item ) {
607 $line = '';
608
609 foreach ( $this->data['columns'] as $column => $label ) {
610 if ( is_numeric( $column ) && ( ( is_object( $item ) && ! isset( $item->$column ) ) || ( is_array( $item ) && ! isset( $item[ $column ] ) ) ) ) {
611 $column = $label;
612 }
613
614 $value = '';
615
616 if ( is_object( $item ) ) {
617 if ( ! isset( $item->$column ) ) {
618 $item->$column = '';
619 }
620
621 $value = $item->$column;
622 } elseif ( is_array( $item ) ) {
623 if ( ! isset( $item[ $column ] ) ) {
624 $item[ $column ] = '';
625 }
626
627 $value = $item[ $column ];
628 }
629
630 if ( is_array( $value ) || is_object( $value ) ) {
631 $value = pods_serial_comma(
632 $value, array(
633 'field' => $column,
634 'fields' => pods_var_raw( $column, $this->data['fields'] ),
635 'and' => '',
636 )
637 );
638 }
639
640 $value = (string) str_replace( array( '"', "\r\n", "\r", "\n" ), array( '\\"', "\n", "\n", '\n' ), $value );
641
642 // Maybe escape the first character to prevent formulas from getting used when opening the file with a spreadsheet app.
643 if (
644 0 === strpos( $value, '=' )
645 || 0 === strpos( $value, '+' )
646 || 0 === strpos( $value, '-' )
647 || 0 === strpos( $value, '@' )
648 ) {
649 $value = '\\' . $value;
650 }
651
652 $line .= '"' . $value . '"' . $this->delimiter;
653 }//end foreach
654
655 $lines .= substr( $line, 0, - 1 ) . "\n";
656 }//end foreach
657
658 if ( ! empty( $lines ) ) {
659 $lines = "\n" . substr( $lines, 0, - 1 );
660 }
661
662 $this->built = $head . $lines;
663
664 return $this->built;
665 }
666
667 /**
668 * @param array $data Array of data
669 *
670 * @return bool
671 */
672 public function build_xml( $data = null ) {
673
674 if ( ! empty( $data ) ) {
675 $this->set_data( $data );
676 }
677
678 if ( empty( $this->data ) || ! is_array( $this->data ) ) {
679 return false;
680 }
681
682 $items = $this->get_items();
683
684 $head = '<' . '?' . 'xml version="1.0" encoding="utf-8" ' . '?' . '>' . "\r\n<items count=\"" . count( $items ) . "\">\r\n";
685 $lines = '';
686
687 foreach ( $items as $item ) {
688 $line = "\t<item>\r\n";
689
690 foreach ( $this->data['columns'] as $column => $label ) {
691 if ( is_numeric( $column ) && ( ( is_object( $item ) && ! isset( $item->$column ) ) || ( is_array( $item ) && ! isset( $item[ $column ] ) ) ) ) {
692 $column = $label;
693 }
694
695 $line .= $this->build_xml_level( $item, $column );
696 }
697
698 $line .= "\t</item>\r\n";
699 $lines .= $line;
700 }
701
702 $foot = '</items>';
703
704 $this->built = $head . $lines . $foot;
705
706 return $this->built;
707 }
708
709 /**
710 * @param array|object $item
711 * @param string $column
712 * @param int $level
713 * @param string $column_name
714 *
715 * @return string
716 */
717 public function build_xml_level( $item, $column, $level = 2, $column_name = '' ) {
718
719 $column = pods_clean_name( $column, false, false );
720
721 $line = '';
722
723 $value = '';
724
725 if ( is_object( $item ) ) {
726 if ( ! isset( $item->$column ) ) {
727 $item->$column = '';
728 }
729
730 $value = $item->$column;
731 } elseif ( is_array( $item ) ) {
732 if ( ! isset( $item[ $column ] ) ) {
733 $item[ $column ] = '';
734 }
735
736 $value = $item[ $column ];
737 }
738
739 if ( ! empty( $column_name ) ) {
740 $column = $column_name;
741 }
742
743 $tabs = str_repeat( "\t", $level );
744
745 $line .= $tabs . "<{$column}>";
746
747 if ( is_array( $value ) || is_object( $value ) ) {
748 if ( is_object( $value ) ) {
749 $value = get_object_vars( $value );
750 }
751
752 foreach ( $value as $k => $v ) {
753 if ( is_int( $k ) ) {
754 $line .= $this->build_xml_level( $value, $k, $level + 1, 'value' );
755 } else {
756 $line .= $this->build_xml_level( $value, $k, $level + 1 );
757 }
758 }
759 } elseif ( false !== strpos( $value, '<' ) ) {
760 $value = str_replace( array( '<![CDATA[', ']]>' ), array( '&lt;![CDATA[', ']]&gt;' ), $value );
761
762 $line .= '<![CDATA[' . $value . ']]>';
763 } else {
764 $line .= str_replace( '&', '&amp;', $value );
765 }
766
767 $line .= "</{$column}>\r\n";
768
769 return $line;
770 }
771
772 /**
773 * @param array $data Array of data
774 *
775 * @return mixed
776 */
777 public function build_sql( $data = null ) {
778
779 if ( ! empty( $data ) ) {
780 $this->set_data( $data );
781 }
782
783 $this->built = $data;
784
785 return $this->built;
786 }
787
788 /**
789 * Save export to a file.
790 *
791 * @param array $params Additional options for saving.
792 *
793 * @return string The URL of the saved file, a path if not attached.
794 */
795 public function save( $params = array() ) {
796
797 $defaults = array(
798 'file' => null,
799 'path' => null,
800 'attach' => false,
801 );
802
803 $params = array_merge( $defaults, $params );
804
805 $extension = 'txt';
806
807 if ( ! empty( $params['file'] ) ) {
808 $export_file = (string) $params['file'];
809
810 if ( false !== strpos( $export_file, '.' ) ) {
811 $extension = explode( '.', $export_file );
812 $extension = end( $extension );
813 }
814 } else {
815 if ( 'sv' === $this->type ) {
816 if ( ',' === $this->delimiter ) {
817 $extension = 'csv';
818 } elseif ( "\t" === $this->delimiter ) {
819 $extension = 'tsv';
820 }
821 } else {
822 $extension = $this->type;
823 }
824
825 $export_file = sprintf(
826 'pods_export_%s.%s',
827 wp_create_nonce( date_i18n( 'm-d-Y_h-i-sa' ) ),
828 $extension
829 );
830 }
831
832 if ( ! empty( $params['path'] ) ) {
833 $new_file = sprintf(
834 '%s/%s',
835 untrailingslashit( $params['path'] ),
836 $export_file
837 );
838
839 $filename = $export_file;
840 } else {
841 $uploads = wp_upload_dir( current_time( 'mysql' ) );
842
843 if ( ! $uploads || false !== $uploads['error'] ) {
844 return pods_error( __( 'There was an issue saving the export file in your uploads folder.', 'pods' ), true );
845 }
846
847 // Generate unique file name
848 $filename = wp_unique_filename( $uploads['path'], $export_file );
849
850 // move the file to the uploads dir
851 $new_file = $uploads['path'] . '/' . $filename;
852 }
853
854 file_put_contents( $new_file, $this->built );
855
856 // Set correct file permissions
857 $stat = stat( dirname( $new_file ) );
858 $perms = $stat['mode'] & 0000666;
859
860 require_once ABSPATH . '/wp-admin/includes/file.php';
861
862 /** @var WP_Filesystem_Base $wp_filesystem */
863 global $wp_filesystem;
864
865 if ( ! WP_Filesystem() || ! $wp_filesystem ) {
866 return pods_error( __( 'Error: There was a problem accessing the filesystem.', 'pods' ) );
867 }
868
869 $wp_filesystem->chmod( $new_file, $perms );
870
871 // Only attach if we want to and don't have a custom path.
872 if ( $params['attach'] && empty( $params['path'] ) ) {
873 // Get the file type
874 $wp_filetype = wp_check_filetype( $filename, $this->mimes );
875
876 // construct the attachment array
877 $attachment = array(
878 'post_mime_type' => 'text/' . $extension,
879 'guid' => $uploads['url'] . '/' . $filename,
880 'post_parent' => null,
881 'post_title' => 'Pods Export (' . $export_file . ')',
882 'post_content' => '',
883 'post_status' => 'private'
884 );
885
886 if ( $wp_filetype['type'] ) {
887 $attachment['post_mime_type'] = $wp_filetype['type'];
888 }
889
890 // insert attachment
891 /* @var int|WP_Error $attachment_id */
892 $attachment_id = wp_insert_attachment( $attachment, $new_file );
893
894 // error!
895 if ( $attachment_id instanceof WP_Error ) {
896 return pods_error( __( 'There was an issue saving the export file in your uploads folder.', 'pods' ), true );
897 }
898
899 $url = $attachment['guid'];
900 } else {
901 $url = $new_file;
902 }
903
904 return $url;
905
906 }
907
908 /*
909 The real enchilada!
910
911 EXAMPLES
912 //// minimal import (if your fields match on both your pods and tables)
913 $import = array('my_pod' => array('table' => 'my_table')); // if your table name doesn't match the pod name
914 $import = array('my_pod'); // if your table name matches your pod name
915
916 //// advanced import
917 $import = array();
918 $import['my_pod'] = array();
919 $import['my_pod']['fields']['this_field'] = 'field_name_in_table'; // if the field name doesn't match on table and pod
920 $import['my_pod']['fields'][] = 'that_field'; // if the field name matches on table and pod
921 $import['my_pod']['fields']['this_other_field'] = array('filter' => 'wpautop'); // if you want the value to be different than is provided, set a filter function to use [filter uses = filter_name($value,$rowdata)]
922 $import['my_pod']['fields']['another_field'] = array('field' => 'the_real_field_in_table','filter' => 'my_custom_function'); // if you want the value to be filtered, and the field name doesn't match on the table and pod
923 $import[] = 'my_other_pod'; // if your table name matches your pod name
924 $import['another_pod'] = array('update_on' => 'main_field'); // you can update a pod item if the value of this field is the same on both tables
925 $import['another_pod'] = array('reset' => true); // you can choose to reset all data in a pod before importing
926
927 //// run import
928 pods_import_it($import);
929 */
930 /**
931 * @param $import
932 * @param bool $output
933 */
934 public function heres_the_beef( $import, $output = true ) {
935
936 global $wpdb;
937
938 $api = pods_api();
939
940 for ( $i = 0; $i < 40000; $i ++ ) {
941 echo " \t";
942 // extra spaces
943 }
944
945 $default_data = array(
946 'pod' => null,
947 'table' => null,
948 'reset' => null,
949 'update_on' => null,
950 'where' => null,
951 'fields' => array(),
952 'row_filter' => null,
953 'pre_save' => null,
954 'post_save' => null,
955 'sql' => null,
956 'sort' => null,
957 'limit' => null,
958 'page' => null,
959 'output' => null,
960 'page_var' => 'ipg',
961 'bypass_helpers' => false,
962 );
963
964 $default_field_data = array(
965 'field' => null,
966 'filter' => null,
967 );
968
969 if ( ! is_array( $import ) ) {
970 $import = array( $import );
971 } elseif ( empty( $import ) ) {
972 die( '<h1 style="color:red;font-weight:bold;">ERROR: No imports configured</h1>' );
973 }
974
975 $import_counter = 0;
976 $total_imports = count( $import );
977 $paginated = false;
978 $avg_time = - 1;
979 $total_time = 0;
980 $counter = 0;
981 $avg_unit = 100;
982 $avg_counter = 0;
983
984 foreach ( $import as $datatype => $data ) {
985 $import_counter ++;
986
987 flush();
988 @ob_end_flush();
989 usleep( 50000 );
990
991 if ( ! is_array( $data ) ) {
992 $datatype = $data;
993 $data = array( 'table' => $data );
994 }
995
996 if ( isset( $data[0] ) ) {
997 $data = array( 'table' => $data[0] );
998 }
999
1000 $data = array_merge( $default_data, $data );
1001
1002 $data['limit'] = absint( $data['limit'] );
1003
1004 if ( null === $data['pod'] ) {
1005 $data['pod'] = array( 'name' => $datatype );
1006 }
1007
1008 if ( false !== $output ) {
1009 echo '<br />' . esc_html( date_i18n( 'Y-m-d h:i:sa' ) ) . ' - <em>' . esc_html( $data['pod']['name'] ) . '</em> - <em>' . esc_html( $data['pod']['name'] ) . '</em> - <strong>Loading Pod: ' . esc_html( $data['pod']['name'] ) . "</strong>\n";
1010 }
1011
1012 if ( 2 > count( $data['pod'] ) ) {
1013 $data['pod'] = $api->load_pod( array( 'name' => $data['pod']['name'] ) );
1014 }
1015
1016 if ( empty( $data['pod']['fields'] ) ) {
1017 continue;
1018 }
1019
1020 if ( null === $data['table'] ) {
1021 $data['table'] = $data['pod']['name'];
1022 }
1023
1024 if ( $data['reset'] === true ) {
1025 if ( false !== $output ) {
1026 echo '<br />' . esc_html( date_i18n( 'Y-m-d h:i:sa' ) ) . ' - <em>' . esc_html( $data['pod']['name'] ) . "</em> - <strong style='color:blue;'>Resetting Pod: " . esc_html( $data['pod']['name'] ) . "</strong>\n";
1027 }
1028
1029 $api->reset_pod(
1030 array(
1031 'id' => $data['pod']['id'],
1032 'name' => $data['pod']['name'],
1033 )
1034 );
1035 }
1036
1037 if ( null === $data['sort'] && null !== $data['update_on'] && isset( $data['fields'][ $data['update_on'] ] ) ) {
1038 if ( isset( $data['fields'][ $data['update_on'] ]['field'] ) ) {
1039 $data['sort'] = $data['fields'][ $data['update_on'] ]['field'];
1040 } else {
1041 $data['sort'] = $data['update_on'];
1042 }
1043 }
1044
1045 $page = 1;
1046
1047 if ( false !== $data['page_var'] && 0 < (int) pods_v( $data['page_var'] ) ) {
1048 $page = (int) pods_v( $data['page_var'] );
1049 }
1050
1051 if ( null === $data['sql'] ) {
1052 $data['sql'] = "SELECT * FROM {$data['table']}" . ( null !== $data['where'] ? " WHERE {$data['where']}" : '' ) . ( null !== $data['sort'] ? " ORDER BY {$data['sort']}" : '' ) . ( null !== $data['limit'] ? ' LIMIT ' . ( 1 < $page ? ( ( $page - 1 ) * $data['limit'] ) . ',' : '' ) . "{$data['limit']}" : '' );
1053 }
1054
1055 if ( false !== $output ) {
1056 echo '<br />' . esc_html( date_i18n( 'Y-m-d h:i:sa' ) ) . ' - <em>' . esc_html( $data['pod']['name'] ) . '</em> - Getting Results: ' . esc_html( $data['pod']['name'] ) . "\n";
1057 }
1058
1059 if ( false !== $output ) {
1060 echo '<br />' . esc_html( date_i18n( 'Y-m-d h:i:sa' ) ) . ' - <em>' . esc_html( $data['pod']['name'] ) . '</em> - Using Query: <small><code>' . esc_html( $data['sql'] ) . "</code></small>\n";
1061 }
1062
1063 $result = $wpdb->get_results( // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter
1064 $data['sql'], // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1065 ARRAY_A
1066 );
1067
1068 if ( false !== $output ) {
1069 echo '<br />' . esc_html( date_i18n( 'Y-m-d h:i:sa' ) ) . ' - <em>' . esc_html( $data['pod']['name'] ) . '</em> - Results Found: ' . count( $result ) . "\n";
1070 }
1071
1072 $avg_time = - 1;
1073 $total_time = 0;
1074 $counter = 0;
1075 $avg_unit = 100;
1076 $avg_counter = 0;
1077 $result_count = count( $result );
1078 $paginated = false;
1079
1080 if ( false !== $data['page_var'] && $result_count === $data['limit'] ) {
1081 $paginated = "<input type=\"button\" onclick=\"document.location=\'" . esc_js( add_query_arg( [ $data['page_var'] => $page + 1 ] ) ) . "\';\" value=\" Continue Import &raquo; \" />";
1082 }
1083
1084 if ( $result_count < $avg_unit && 5 < $result_count ) {
1085 $avg_unit = number_format( $result_count / 5, 0, '', '' );
1086 } elseif ( 2000 < $result_count && 10 < count( $data['pod']['fields'] ) ) {
1087 $avg_unit = 40;
1088 }
1089
1090 $data['count'] = $result_count;
1091 timer_start();
1092
1093 if ( false !== $output && 1 === $import_counter ) {
1094 echo "<div style='width:50%;background-color:navy;padding:10px 10px 30px 10px;color:#FFF;position:absolute;top:10px;left:25%;text-align:center;'><p id='progress_status' align='center'>" . esc_html( date_i18n( 'Y-m-d h:i:sa' ) ) . ' - <em>' . esc_html( $data['pod']['name'] ) . '</em> - Running Importer..</p><br /><small>This will automatically update every ' . esc_html( $avg_unit ) . " rows</small></div>\n";
1095 }
1096
1097 foreach ( $result as $k => $row ) {
1098 flush();
1099 @ob_end_flush();
1100 usleep( 50000 );
1101
1102 if ( false !== $output ) {
1103 echo '<br />' . esc_html( date_i18n( 'Y-m-d h:i:sa' ) ) . ' - <em>' . esc_html( $data['pod']['name'] ) . '</em> - Processing Row #' . esc_html( $k + 1 ) . "\n";
1104 }
1105
1106 if ( null !== $data['row_filter'] && function_exists( $data['row_filter'] ) ) {
1107 if ( false !== $output ) {
1108 echo '<br />' . esc_html( date_i18n( 'Y-m-d h:i:sa' ) ) . ' - <em>' . esc_html( $data['pod']['name'] ) . '</em> - Filtering <strong>' . esc_html( $data['row_filter'] ) . '</strong> on Row #' . esc_html( $k + 1 ) . "\n";
1109 }
1110
1111 $row = $data['row_filter']( $row, $data );
1112 }
1113
1114 if ( ! is_array( $row ) ) {
1115 continue;
1116 }
1117
1118 $params = array(
1119 'datatype' => $data['pod']['name'],
1120 'columns' => array(),
1121 'bypass_helpers' => $data['bypass_helpers'],
1122 );
1123
1124 foreach ( $data['pod']['fields'] as $fk => $field_info ) {
1125 $field = $field_info['name'];
1126
1127 if ( ! empty( $data['fields'] ) && ! isset( $data['fields'][ $field ] ) && ! in_array( $field, $data['fields'], true ) ) {
1128 continue;
1129 }
1130
1131 if ( isset( $data['fields'][ $field ] ) ) {
1132 if ( is_array( $data['fields'][ $field ] ) ) {
1133 $field_data = $data['fields'][ $field ];
1134 } else {
1135 $field_data = array( 'field' => $data['fields'][ $field ] );
1136 }
1137 } else {
1138 $field_data = array();
1139 }
1140
1141 if ( ! is_array( $field_data ) ) {
1142 $field = $field_data;
1143 $field_data = array();
1144 }
1145
1146 $field_data = pods_config_merge_data( $default_field_data, $field_data );
1147
1148 if ( null === $field_data['field'] ) {
1149 $field_data['field'] = $field;
1150 }
1151
1152 $data['fields'][ $field ] = $field_data;
1153 $value = '';
1154
1155 if ( isset( $row[ $field_data['field'] ] ) ) {
1156 $value = $row[ $field_data['field'] ];
1157 }
1158
1159 if ( null !== $field_data['filter'] ) {
1160 if ( function_exists( $field_data['filter'] ) ) {
1161 if ( false !== $output ) {
1162 echo '<br />' . esc_html( date_i18n( 'Y-m-d h:i:sa' ) ) . ' - <em>' . esc_html( $data['pod']['name'] ) . '</em> - Filtering <strong>' . esc_html( $field_data['filter'] ) . '</strong> on Field: ' . esc_html( $field ) . "\n";
1163 }
1164
1165 $value = $field_data['filter']( $value, $row, $data );
1166 } else {
1167 $value = '';
1168 }
1169 }
1170
1171 if ( 1 === $field_info['required'] && ( ! is_string( $value ) || strlen( $value ) < 1 ) ) {
1172 die( '<h1 style="color:red;font-weight:bold;">ERROR: Field Required for <strong>' . esc_html( $field ) . '</strong></h1>' );
1173 }
1174
1175 $params['columns'][ $field ] = $value;
1176
1177 unset( $value, $field_data, $field_info, $fk );
1178 }//end foreach
1179
1180 if ( empty( $params['columns'] ) ) {
1181 continue;
1182 }
1183
1184 $params['columns'] = pods_sanitize( $params['columns'] );
1185
1186 if ( null !== $data['update_on'] && isset( $params['columns'][ $data['update_on'] ] ) ) {
1187 if ( false !== $output ) {
1188 echo '<br />' . esc_html( date_i18n( 'Y-m-d h:i:sa' ) ) . ' - <em>' . esc_html( $data['pod']['name'] ) . "</em> - Checking for Existing Item\n";
1189 }
1190
1191 $check = pods( $data['pod']['name'] );
1192 $check->find(
1193 [
1194 'orderby' => 't.id',
1195 'limit' => 1,
1196 'where' => "t.{$data['update_on']} = '{$params['columns'][$data['update_on']]}'",
1197 'search' => false,
1198 'page' => 1,
1199 ]
1200 );
1201
1202 if ( $check->fetch() ) {
1203 $params['id'] = $check->id();
1204 $params['pod'] = $check->pod;
1205 $params['pod_id'] = $check->pod_id;
1206
1207 if ( false !== $output ) {
1208 echo '<br />' . esc_html( date_i18n( 'Y-m-d h:i:sa' ) ) . ' - <em>' . esc_html( $data['pod']['name'] ) . '</em> - Found Existing Item w/ ID: ' . esc_html( $params['id'] ) . "\n";
1209 }
1210
1211 unset( $check );
1212 }
1213
1214 if ( ! isset( $params['id'] ) && false !== $output ) {
1215 echo '<br />' . esc_html( date_i18n( 'Y-m-d h:i:sa' ) ) . ' - <em>' . esc_html( $data['pod']['name'] ) . "</em> - Existing item not found - Creating New\n";
1216 }
1217 }//end if
1218
1219 if ( null !== $data['pre_save'] && function_exists( $data['pre_save'] ) ) {
1220 if ( false !== $output ) {
1221 echo '<br />' . esc_html( date_i18n( 'Y-m-d h:i:sa' ) ) . ' - <em>' . esc_html( $data['pod']['name'] ) . '</em> - Running Pre Save <strong>' . esc_html( $data['pre_save'] ) . '</strong> on ' . esc_html( $data['pod']['name'] ) . "\n";
1222 }
1223
1224 $params = $data['pre_save']( $params, $row, $data );
1225 }
1226
1227 $id = $api->save_pod_item( $params );
1228
1229 if ( false !== $output ) {
1230 echo '<br />' . esc_html( date_i18n( 'Y-m-d h:i:sa' ) ) . ' - <em>' . esc_html( $data['pod']['name'] ) . '</em> - <strong>Saved Row #' . esc_html( $k + 1 ) . ' w/ ID: ' . esc_html( $id ) . "</strong>\n";
1231 }
1232
1233 $params['id'] = $id;
1234
1235 if ( null !== $data['post_save'] && function_exists( $data['post_save'] ) ) {
1236 if ( false !== $output ) {
1237 echo '<br />' . esc_html( date_i18n( 'Y-m-d h:i:sa' ) ) . ' - <em>' . esc_html( $data['pod']['name'] ) . '</em> - Running Post Save <strong>' . esc_html( $data['post_save'] ) . '</strong> on ' . esc_html( $data['pod']['name'] ) . "\n";
1238 }
1239
1240 $data['post_save']( $params, $row, $data );
1241 }
1242
1243 unset( $params, $result[ $k ], $row );
1244
1245 wp_cache_flush();
1246 $wpdb->queries = array();
1247
1248 $avg_counter ++;
1249 $counter ++;
1250
1251 if ( $avg_counter === $avg_unit && false !== $output ) {
1252 $avg_counter = 0;
1253 $avg_time = timer_stop( 0, 10 );
1254 $total_time += $avg_time;
1255 $rows_left = $result_count - $counter;
1256 $estimated_time_left = ( ( $total_time / $counter ) * $rows_left ) / 60;
1257 $percent_complete = 100 - ( ( $rows_left * 100 ) / $result_count );
1258
1259 echo "<script type='text/javascript'>document.getElementById('progress_status').innerHTML = '" . esc_js( date_i18n( 'Y-m-d h:i:sa' ) ) . ' - <em>' . esc_js( $data['pod']['name'] ) . '</em><br /><strong>' . esc_js( $percent_complete ) . '% Complete</strong><br /><strong>Estimated Time Left:</strong> ' . esc_js( $estimated_time_left ) . ' minute(s) or ' . esc_js( $estimated_time_left / 60 ) . ' hours(s)<br /><strong>Time Spent:</strong> ' . esc_js( $total_time / 60 ) . ' minute(s)<br /><strong>Rows Done:</strong> ' . esc_js( $result_count - $rows_left ) . '/' . esc_js( $result_count ) . '<br /><strong>Rows Left:</strong> ' . esc_js( $rows_left ) . "';</script>\n";
1260 echo '<br />' . esc_html( date_i18n( 'Y-m-d h:i:sa' ) ) . ' - <em>' . esc_html( $data['pod']['name'] ) . '</em> - <strong>Updated Status:</strong> ' . esc_html( $percent_complete ) . "% Complete</strong>\n";
1261 }
1262 }//end foreach
1263
1264 if ( false !== $output ) {
1265 $avg_counter = 0;
1266 $avg_time = timer_stop( 0, 10 );
1267 $total_time += $avg_time;
1268 $rows_left = $result_count - $counter;
1269 $estimated_time_left = ( ( $total_time / $counter ) * $rows_left ) / 60;
1270 $percent_complete = 100 - ( ( $rows_left * 100 ) / $result_count );
1271
1272 echo "<script type='text/javascript'>document.getElementById('progress_status').innerHTML = '" . esc_js( date_i18n( 'Y-m-d h:i:sa' ) ) . ' - <em>' . esc_html( $data['pod']['name'] ) . "</em><br /><strong style=\'color:green;\'>100% Complete</strong><br /><br /><strong>Time Spent:</strong> " . esc_html( $total_time / 60 ) . ' minute(s)<br /><strong>Rows Imported:</strong> ' . esc_html( $result_count ) . ( false !== $paginated ? '<br /><br />' . wp_kses_post( $paginated ) : '' ) . "';</script>\n";
1273 echo '<br />' . esc_html( date_i18n( 'Y-m-d h:i:sa' ) ) . ' - <em>' . esc_html( $data['pod']['name'] ) . "</em> - <strong style='color:green;'>Done Importing: " . esc_html( $data['pod']['name'] ) . "</strong>\n";
1274 }
1275
1276 unset( $result, $import[ $datatype ], $datatype, $data );
1277
1278 wp_cache_flush();
1279 $wpdb->queries = array();
1280 }//end foreach
1281
1282 if ( false !== $output ) {
1283 $avg_counter = 0;
1284 $avg_time = timer_stop( 0, 10 );
1285 $total_time += $avg_time;
1286 $rows_left = $result_count - $counter;
1287
1288 echo "<script type='text/javascript'>document.getElementById('progress_status').innerHTML = '" . esc_js( date_i18n( 'Y-m-d h:i:sa' ) ) . " - <strong style=\'color:green;\'>Import Complete</strong><br /><br /><strong>Time Spent:</strong> " . esc_html( $total_time / 60 ) . ' minute(s)<br /><strong>Rows Imported:</strong> ' . esc_html( $result_count ) . ( false !== $paginated ? '<br /><br />' . wp_kses_post( $paginated ) : '' ) . "';</script>\n";
1289 echo '<br />' . esc_html( date_i18n( 'Y-m-d h:i:sa' ) ) . " - <strong style='color:green;'>Import Complete</strong>\n";
1290 }
1291 }
1292
1293 /**
1294 * Export data to a file.
1295 *
1296 * @param string $file File to export to.
1297 * @param array $data Data to export.
1298 * @param bool $single Whether this is a single item export.
1299 *
1300 * @return mixed
1301 */
1302 public static function export_data_to_file( $file, $data, $single = false ) {
1303
1304 $path = ABSPATH;
1305
1306 // Detect path if it is set in the file param.
1307 if ( false !== strpos( (string) $file, '/' ) ) {
1308 $path = dirname( (string) $file );
1309 $file = basename( (string) $file );
1310 }
1311
1312 $format = 'json';
1313
1314 // Detect the export format.
1315 if ( false !== strpos( (string) $file, '.' ) ) {
1316 $format = explode( '.', (string) $file );
1317 $format = end( $format );
1318 }
1319
1320 $migrate_data = array(
1321 'items' => $data,
1322 'single' => $single,
1323 );
1324
1325 // Try to guess the column labels based on the supplied data.
1326 $first_item = null;
1327
1328 if ( $single ) {
1329 $first_item = $data;
1330 } elseif ( is_array( $data ) ) {
1331 $first_item = reset( $data );
1332 }
1333
1334 if ( is_array( $first_item ) ) {
1335 $fields = array_keys( $first_item );
1336 $migrate_data['columns'] = array_combine( $fields, $fields );
1337 }
1338
1339 $migrate = new self( $format, null, $migrate_data );
1340
1341 // Handle processing the data into the format needed.
1342 $migrate->export();
1343
1344 $save_params = array(
1345 'path' => $path,
1346 'file' => $file,
1347 'attach' => true,
1348 );
1349
1350 return $migrate->save( $save_params );
1351
1352 }
1353
1354 /**
1355 * Get data from a file.
1356 *
1357 * @param string $file File to get data from.
1358 * @param bool $single Whether this is a single item.
1359 *
1360 * @return mixed
1361 */
1362 public static function get_data_from_file( $file, $single = false ) {
1363
1364 $path = ABSPATH;
1365
1366 // Detect path if it is set in the file param.
1367 if ( false !== strpos( (string) $file, DIRECTORY_SEPARATOR ) ) {
1368 $path = dirname( (string) $file );
1369 $file = basename( (string) $file );
1370 }
1371
1372 $format = 'json';
1373
1374 // Detect the export format.
1375 if ( false !== strpos( (string) $file, '.' ) ) {
1376 $format = explode( '.', (string) $file );
1377 $format = end( $format );
1378 }
1379
1380 $migrate_data = array(
1381 'single' => $single,
1382 );
1383
1384 $migrate = new self( $format, null, $migrate_data );
1385
1386 $raw_data = file_get_contents( $path . DIRECTORY_SEPARATOR . $file );
1387
1388 // Handle processing the raw data from the format needed.
1389 $data = $migrate->parse( $raw_data );
1390
1391 return $data;
1392
1393 }
1394
1395 }
1396