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