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/Migration/Migrations.php +154 -21 2.7.7 → 2.15.0 View file →
@@ -1,8 +1,9 @@
1 1 <?php
2 2
3 3 namespace ImportWP\Common\Migration;
4 4
5 +use ImportWP\Common\Filesystem\Filesystem;
5 6 use ImportWP\Common\Importer\ImporterManager;
6 7 use ImportWP\Common\Model\ImporterModel;
7 8 use ImportWP\Common\Util\Logger;
8 9 use ImportWP\Container;
@@ -14,9 +15,9 @@
14 15
15 16 public function __construct()
16 17 {
17 18
18 - $starting_version = intval(get_site_option('iwp_db_version', 0));
19 + $starting_version = intval(get_option('iwp_db_version', 0));
19 20 if ($starting_version <= 3 && $starting_version > 0) {
20 21 // v1 migrations
21 22 $this->_migrations[] = array($this, 'migration_01');
22 23 $this->_migrations[] = array($this, 'migration_02');
@@ -35,8 +36,10 @@
35 36 $this->_migrations[] = array($this, 'migration_06_cron_update');
36 37 $this->_migrations[] = array($this, 'migration_07_add_session_table');
37 38 $this->_migrations[] = array($this, 'migration_08_migrate_taxonomy_settings');
38 39 $this->_migrations[] = array($this, 'migration_09_migrate_attachment_settings');
40 + $this->_migrations[] = array($this, 'migration_10_relative_importer_file_paths');
41 + $this->_migrations[] = array($this, 'migration_11_prefix_custom_methods');
39 42
40 43 $this->_version = count($this->_migrations);
41 44 }
42 45
@@ -41,9 +44,9 @@
41 44 }
42 45
43 46 public function isSetup()
44 47 {
45 - $version = intval(get_site_option('iwp_db_version', get_site_option('jci_db_version', 0)));
48 + $version = intval(get_option('iwp_db_version', get_option('jci_db_version', 0)));
46 49 if ($version < count($this->_migrations)) {
47 50 return false;
48 51 }
49 52 return true;
@@ -60,11 +63,11 @@
60 63 {
61 64 global $wpdb;
62 65 $wpdb->query("DROP TABLE IF EXISTS `" . $wpdb->prefix . "importer_log`;");
63 66 $wpdb->query("DROP TABLE IF EXISTS `" . $wpdb->prefix . "importer_files`;");
64 - delete_site_option('iwp_db_version');
65 - delete_site_option('jci_db_version');
66 - delete_site_option('iwp_is_migrating');
67 + delete_option('iwp_db_version');
68 + delete_option('jci_db_version');
69 + delete_option('iwp_is_migrating');
67 70 }
68 71
69 72 public function migrate($migrate_data = true)
70 73 {
@@ -69,10 +72,10 @@
69 72 public function migrate($migrate_data = true)
70 73 {
71 74
72 75 $verion_key = 'iwp_db_version';
73 - $version = intval(get_site_option('iwp_db_version', get_site_option('jci_db_version', 0)));
74 - $migrating = get_site_option('iwp_is_migrating', 'no');
76 + $version = intval(get_option('iwp_db_version', get_option('jci_db_version', 0)));
77 + $migrating = get_option('iwp_is_migrating', 'no');
75 78 if ('yes' === $migrating) {
76 79 return;
77 80 }
78 81
@@ -84,9 +87,9 @@
84 87
85 88 $migration_version = $i + 1;
86 89 if ($version < $migration_version) {
87 90
88 - update_site_option('iwp_is_migrating', 'yes');
91 + update_option('iwp_is_migrating', 'yes');
89 92
90 93 set_time_limit(0);
91 94
92 95 // Run migration
@@ -94,15 +97,15 @@
94 97 call_user_func($this->_migrations[$i], $migrate_data);
95 98 }
96 99
97 100 // Flag as migrated
98 - update_site_option($verion_key, $migration_version);
99 - update_site_option('iwp_is_migrating', 'no');
101 + update_option($verion_key, $migration_version);
102 + update_option('iwp_is_migrating', 'no');
100 103 }
101 104 }
102 105 }
103 106
104 - // update_site_option('iwp_is_setup', 'yes');
107 + // update_option('iwp_is_setup', 'yes');
105 108 }
106 109
107 110 public function get_charset()
108 111 {
@@ -708,11 +711,9 @@
708 711 unset($data['settings']['cron_disabled']);
709 712
710 713 $data['settings']['cron'] = $cron;
711 714
712 - remove_filter('content_save_pre', 'wp_filter_post_kses');
713 - wp_update_post(['ID' => $id, 'post_content' => serialize($data)]);
714 - add_filter('content_save_pre', 'wp_filter_post_kses');
715 + $this->update_importer_post_content($id, $data);
715 716 }
716 717 }
717 718
718 719 public function migration_06_cron_update()
@@ -784,8 +785,9 @@
784 785 'session' => $post['meta_value']
785 786 ];
786 787 $format = ['%d', '%d', '%s', '%s'];
787 788
789 + // TODO: is this needed as blog_id is more relevant since there is a sessions table per site?
788 790 if (is_multisite()) {
789 791 $data['site_id'] = $wpdb->siteid;
790 792 $format[] = '%d';
791 793 }
@@ -810,8 +812,9 @@
810 812 'session' => $post['meta_value']
811 813 ];
812 814 $format = ['%d', '%d', '%s', '%s'];
813 815
816 + // TODO: is this needed as blog_id is more relevant since there is a sessions table per site?
814 817 if (is_multisite()) {
815 818 $data['site_id'] = $wpdb->siteid;
816 819 $format[] = '%d';
817 820 }
@@ -836,8 +839,9 @@
836 839 'session' => $post['meta_value']
837 840 ];
838 841 $format = ['%d', '%d', '%s', '%s'];
839 842
843 + // TODO: is this needed as blog_id is more relevant since there is a sessions table per site?
840 844 if (is_multisite()) {
841 845 $data['site_id'] = $wpdb->siteid;
842 846 $format[] = '%d';
843 847 }
@@ -876,12 +880,9 @@
876 880 }
877 881
878 882 $data['map'] = $tmp;
879 883
880 -
881 - remove_filter('content_save_pre', 'wp_filter_post_kses');
882 - wp_update_post(['ID' => $importer['ID'], 'post_content' => serialize($data)]);
883 - add_filter('content_save_pre', 'wp_filter_post_kses');
884 + $this->update_importer_post_content($importer['ID'], $data);
884 885 }
885 886 }
886 887
887 888 // TODO: do we need this? can we get around this with manipulating the data if it exists?
@@ -933,11 +934,143 @@
933 934 }
934 935
935 936 $data['map'] = $tmp;
936 937
938 + $this->update_importer_post_content($importer['ID'], $data);
939 + }
940 + }
937 941
938 - remove_filter('content_save_pre', 'wp_filter_post_kses');
939 - wp_update_post(['ID' => $importer['ID'], 'post_content' => serialize($data)]);
940 - add_filter('content_save_pre', 'wp_filter_post_kses');
942 + /**
943 + * Convert stored absolute importer file paths to uploads-relative paths.
944 + *
945 + * Prevents open_basedir warnings after hosting path / WordPress root changes.
946 + *
947 + * @param bool $migrate_data
948 + * @return void
949 + */
950 + public function migration_10_relative_importer_file_paths($migrate_data = true)
951 + {
952 + if (!$migrate_data) {
953 + return;
941 954 }
955 +
956 + /**
957 + * @var \wpdb $wpdb
958 + */
959 + global $wpdb;
960 +
961 + $results = $wpdb->get_results(
962 + "SELECT meta_id, post_id, meta_key, meta_value
963 + FROM {$wpdb->postmeta}
964 + WHERE meta_key LIKE '\\_importer\\_file\\_%'",
965 + ARRAY_A
966 + );
967 +
968 + if (empty($results)) {
969 + return;
970 + }
971 +
972 + foreach ($results as $row) {
973 + $stored = $row['meta_value'];
974 + if (!Filesystem::is_absolute_path($stored)) {
975 + continue;
976 + }
977 +
978 + $resolved = Filesystem::resolve_importer_file_path($stored);
979 + if (!$resolved) {
980 + continue;
981 + }
982 +
983 + $relative = Filesystem::to_uploads_relative_path($resolved);
984 + if ($relative === '' || $relative === $stored) {
985 + continue;
986 + }
987 +
988 + update_post_meta((int) $row['post_id'], $row['meta_key'], $relative);
989 + }
990 + }
991 +
992 + /**
993 + * Prefix custom method calls with [iwp:...] so they do not collide with
994 + * shortcodes or Gutenberg content that uses [name(...)].
995 + *
996 + * Rewrites [strtoupper("x")] → [iwp:strtoupper("x")] in importer maps,
997 + * filters, and other stored string settings. Already-prefixed calls are left alone.
998 + *
999 + * @param bool $migrate_data
1000 + * @return void
1001 + */
1002 + public function migration_11_prefix_custom_methods($migrate_data = true)
1003 + {
1004 + if (!$migrate_data) {
1005 + return;
1006 + }
1007 +
1008 + /**
1009 + * @var \wpdb $wpdb
1010 + */
1011 + global $wpdb;
1012 +
1013 + $importers = $wpdb->get_results("SELECT * FROM {$wpdb->posts} WHERE post_type='" . IWP_POST_TYPE . "'", ARRAY_A);
1014 + if (empty($importers)) {
1015 + return;
1016 + }
1017 +
1018 + foreach ($importers as $importer) {
1019 + $data = maybe_unserialize($importer['post_content']);
1020 + if (!is_array($data)) {
1021 + continue;
1022 + }
1023 +
1024 + $migrated = $this->migration_11_prefix_custom_methods_in_value($data);
1025 + if ($migrated === $data) {
1026 + continue;
1027 + }
1028 +
1029 + $this->update_importer_post_content($importer['ID'], $migrated);
1030 + }
1031 + }
1032 +
1033 + /**
1034 + * Persist serialized importer settings without corrupting backslashes.
1035 + *
1036 + * wp_update_post() only slashes the existing DB row, then merges in the
1037 + * caller-supplied fields. Those fields must already be slashed or
1038 + * wp_insert_post() will stripslashes() the payload and break serialize()
1039 + * strings such as the CSV escape character "\".
1040 + *
1041 + * @param int $id
1042 + * @param array $data
1043 + * @return void
1044 + */
1045 + private function update_importer_post_content($id, array $data)
1046 + {
1047 + remove_filter('content_save_pre', 'wp_filter_post_kses');
1048 + wp_update_post([
1049 + 'ID' => $id,
1050 + 'post_content' => wp_slash(serialize($data)),
1051 + ]);
1052 + add_filter('content_save_pre', 'wp_filter_post_kses');
1053 + }
1054 +
1055 + /**
1056 + * Recursively rewrite [method( → [iwp:method( in strings.
1057 + *
1058 + * @param mixed $value
1059 + * @return mixed
1060 + */
1061 + private function migration_11_prefix_custom_methods_in_value($value)
1062 + {
1063 + if (is_array($value)) {
1064 + foreach ($value as $key => $item) {
1065 + $value[$key] = $this->migration_11_prefix_custom_methods_in_value($item);
1066 + }
1067 + return $value;
1068 + }
1069 +
1070 + if (!is_string($value) || $value === '' || strpos($value, '[') === false) {
1071 + return $value;
1072 + }
1073 +
1074 + return preg_replace('/\[(?!iwp:)(\w+)\(/', '[iwp:$1(', $value);
942 1075 }
943 1076 }