Go Live Update URLS - Version 6.1.0

Version Description

  • Automatically exclude non text database columns.
  • Support email addresses within serialized data.
  • Greatly improve database update performance.
  • Split database update steps into their own class.
  • Support URL counting for upcoming PRO enhancements.
  • Tested to WordPress version 5.5.0
Download this release

Release Info

Developer Mat Lipe
Plugin Icon 128x128 Go Live Update URLS
Version 6.1.0
Comparing to
See all releases

Code changes from version 6.0.1 to 6.1.0

go-live-update-urls.php CHANGED
@@ -5,13 +5,13 @@
5
  * Description: Updates all the URLs in the database to point to a new URL when making your site live or changing domains.
6
  * Author: OnPoint Plugins
7
  * Author URI: https://onpointplugins.com/
8
- * Version: 6.0.1
9
  * Text Domain: go-live-update-urls
10
  *
11
  * @package go-live-update-urls
12
  */
13
 
14
- define( 'GO_LIVE_UPDATE_URLS_VERSION', '6.0.1' );
15
  define( 'GO_LIVE_UPDATE_URLS_REQUIRED_PRO_VERSION', '6.0.0' );
16
  define( 'GO_LIVE_UPDATE_URLS_URL', plugin_dir_url( __FILE__ ) );
17
 
@@ -19,10 +19,11 @@ use Go_Live_Update_Urls\Admin;
19
  use Go_Live_Update_Urls\Core;
20
  use Go_Live_Update_Urls\Database;
21
  use Go_Live_Update_Urls\Serialized;
22
- use Go_Live_Update_Urls\Updaters\Repo;
23
  use Go_Live_Update_Urls\Traits\Singleton;
 
24
  use Go_Live_Update_Urls\Updaters\Updaters_Abstract;
25
  use Go_Live_Update_Urls\Updaters\Url_Encoded;
 
26
 
27
  /**
28
  * Load the plugin
@@ -62,6 +63,7 @@ function go_live_update_urls_autoload( $class ) {
62
  Repo::class => 'Updaters/Repo.php',
63
  Serialized::class => 'Serialized.php',
64
  Singleton::class => 'Traits/Singleton.php',
 
65
  Updaters_Abstract::class => 'Updaters/Updaters_Abstract.php',
66
  Url_Encoded::class => 'Updaters/Url_Encoded.php',
67
  ];
5
  * Description: Updates all the URLs in the database to point to a new URL when making your site live or changing domains.
6
  * Author: OnPoint Plugins
7
  * Author URI: https://onpointplugins.com/
8
+ * Version: 6.1.0
9
  * Text Domain: go-live-update-urls
10
  *
11
  * @package go-live-update-urls
12
  */
13
 
14
+ define( 'GO_LIVE_UPDATE_URLS_VERSION', '6.1.0' );
15
  define( 'GO_LIVE_UPDATE_URLS_REQUIRED_PRO_VERSION', '6.0.0' );
16
  define( 'GO_LIVE_UPDATE_URLS_URL', plugin_dir_url( __FILE__ ) );
17
 
19
  use Go_Live_Update_Urls\Core;
20
  use Go_Live_Update_Urls\Database;
21
  use Go_Live_Update_Urls\Serialized;
 
22
  use Go_Live_Update_Urls\Traits\Singleton;
23
+ use Go_Live_Update_Urls\Updaters\Repo;
24
  use Go_Live_Update_Urls\Updaters\Updaters_Abstract;
25
  use Go_Live_Update_Urls\Updaters\Url_Encoded;
26
+ use Go_Live_Update_Urls\Updates;
27
 
28
  /**
29
  * Load the plugin
63
  Repo::class => 'Updaters/Repo.php',
64
  Serialized::class => 'Serialized.php',
65
  Singleton::class => 'Traits/Singleton.php',
66
+ Updates::class => 'Updates.php',
67
  Updaters_Abstract::class => 'Updaters/Updaters_Abstract.php',
68
  Url_Encoded::class => 'Updaters/Url_Encoded.php',
69
  ];
readme.txt CHANGED
@@ -3,9 +3,9 @@ Contributors: Mat Lipe, onpointplugins
3
  Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=paypal%40onpointplugins%2ecom&lc=US&item_name=Go%20Live%20Update%20Urls&no_note=0&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHostedGuest
4
  Tags: urls, launching, site changes, tools, domain, domains, domain changes, url changes
5
  Requires at least: 4.8.0
6
- Tested up to: 5.4.2
7
  Requires PHP: 5.6.0
8
- Stable tag: 6.0.1
9
 
10
  == Description ==
11
 
@@ -70,12 +70,12 @@ Send pull requests via the <a href="https://github.com/lipemat/go-live-update-ur
70
 
71
  Use the standard WordPress plugins search and installer.
72
  Activate the plugin.
73
- Use the plugin under the Tools menu in the WordPress admin
74
 
75
  Manual Installation
76
 
77
- 1. Upload the `go-live-upload-urls` folder to the `/wp-content/plugins/` directory
78
- 2. Activate the plugin through the 'Plugins' menu in WordPress
79
 
80
 
81
  == Frequently Asked Questions ==
@@ -91,17 +91,20 @@ Some plugins will store the data in the database serialized which does not allow
91
  = How do I know which tables I should not update? =
92
 
93
  Most tables will be just fine to update. This plugin will tell you which ones not to update.
94
- If you wish to try to update tables mentioned as not safe anyway, you may make a backup of your database, run this on all tables and if you run into trouble, restore your database, un-check tables in sections, and rerun this until you find the culprit. If you find you are running into issues often with custom table you may want to check out the <a href="https://onpointplugins.com/product/go-live-update-urls-pro/" target="_blank">Pro Version</a> of this plugin which works with any table.
95
 
96
  == Screenshots ==
97
 
98
- 1. Typical settings page. The verbiage will change slightly depending on your database structure
99
 
100
  == Changelog ==
101
- = 6.0.1 -
102
- * Improve compatibility with very old versions of PRO.
103
- * Improve readme.
104
- * Add links for documenation and troubleshooting.
 
 
 
105
 
106
  = 6.0.0 =
107
  * Entirely new code structure.
@@ -128,7 +131,7 @@ If you wish to try to update tables mentioned as not safe anyway, you may make a
128
  = 5.1.0 =
129
  * Added new languages including French, German, and Spanish
130
  * Support upcoming blogmeta table in WP 5.0.0+
131
- * Support updating urlencdode urls
132
  * Improved support for Visual Composer
133
  * Add PHP composer support
134
 
@@ -168,10 +171,10 @@ If you wish to try to update tables mentioned as not safe anyway, you may make a
168
  Major version update. Not backward compatible with version 5 filters or code. Please remove any custom filters or extensions before updating.
169
 
170
  = 5.0.6 =
171
- Fixes bug with submit button in a small number of browsers
172
 
173
  = 5.0.4 =
174
- Fixes bug with database not updating properly
175
 
176
  = 5.0.1 =
177
  For full functionality of PRO version 2.2.0
3
  Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=paypal%40onpointplugins%2ecom&lc=US&item_name=Go%20Live%20Update%20Urls&no_note=0&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHostedGuest
4
  Tags: urls, launching, site changes, tools, domain, domains, domain changes, url changes
5
  Requires at least: 4.8.0
6
+ Tested up to: 5.5.0
7
  Requires PHP: 5.6.0
8
+ Stable tag: 6.1.0
9
 
10
  == Description ==
11
 
70
 
71
  Use the standard WordPress plugins search and installer.
72
  Activate the plugin.
73
+ Use the "Go Live" page, located under the Tools menu, in the WordPress admin.
74
 
75
  Manual Installation
76
 
77
+ 1. Upload the `go-live-upload-urls` folder to the `/wp-content/plugins/` directory.
78
+ 2. Activate the plugin through the 'Plugins' menu in WordPress.
79
 
80
 
81
  == Frequently Asked Questions ==
91
  = How do I know which tables I should not update? =
92
 
93
  Most tables will be just fine to update. This plugin will tell you which ones not to update.
94
+ If you wish to try to update tables mentioned as not safe anyway, you may make a backup of your database, run this on all tables and if you run into trouble, restore your database, un-check tables in sections, and rerun this until you find the culprit. If you find you are running into issues with custom tables, you may want to check out the <a href="https://onpointplugins.com/product/go-live-update-urls-pro/" target="_blank">Pro Version</a> of this plugin which works with any table.
95
 
96
  == Screenshots ==
97
 
98
+ 1. Typical settings page. The verbiage will change slightly depending on your database structure.
99
 
100
  == Changelog ==
101
+ = 6.1.0 =
102
+ * Automatically exclude non text database columns.
103
+ * Support email addresses within serialized data.
104
+ * Greatly improve database update performance.
105
+ * Split database update steps into their own class.
106
+ * Support URL counting for upcoming <a href="https://onpointplugins.com/product/go-live-update-urls-pro/" target="_blank">PRO</a> enhancements.
107
+ * Tested to WordPress version 5.5.0
108
 
109
  = 6.0.0 =
110
  * Entirely new code structure.
131
  = 5.1.0 =
132
  * Added new languages including French, German, and Spanish
133
  * Support upcoming blogmeta table in WP 5.0.0+
134
+ * Support updating urlencoded urls
135
  * Improved support for Visual Composer
136
  * Add PHP composer support
137
 
171
  Major version update. Not backward compatible with version 5 filters or code. Please remove any custom filters or extensions before updating.
172
 
173
  = 5.0.6 =
174
+ Fixes bug with the submit button in some browsers
175
 
176
  = 5.0.4 =
177
+ Fixes bug with the database not updating properly
178
 
179
  = 5.0.1 =
180
  For full functionality of PRO version 2.2.0
src/Core.php CHANGED
@@ -69,7 +69,7 @@ class Core {
69
  *
70
  * @since 5.0.1
71
  *
72
- * @return bool
73
  */
74
  public function update( $old_url, $new_url ) {
75
  $db = Database::instance();
69
  *
70
  * @since 5.0.1
71
  *
72
+ * @return int[]
73
  */
74
  public function update( $old_url, $new_url ) {
75
  $db = Database::instance();
src/Database.php CHANGED
@@ -3,8 +3,6 @@
3
  namespace Go_Live_Update_Urls;
4
 
5
  use Go_Live_Update_Urls\Traits\Singleton;
6
- use Go_Live_Update_Urls\Updaters\Repo;
7
- use Go_Live_Update_Urls\Updaters\Updaters_Abstract;
8
 
9
  /**
10
  * Database manipulation.
@@ -105,6 +103,29 @@ class Database {
105
  }
106
 
107
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  /**
109
  * Get the names of every table in this blog
110
  * If we are multisite, we also get the global tables
@@ -140,79 +161,98 @@ class Database {
140
  *
141
  * @since 5.0.0
142
  *
143
- * @return bool
144
  */
145
  public function update_the_database( $old_url, $new_url, array $tables ) {
146
- global $wpdb;
147
  do_action( 'go-live-update-urls/database/before-update', $old_url, $new_url, $tables, $this );
148
  $tables = apply_filters( 'go-live-update-urls/database/update-tables', $tables, $this );
149
- $updaters = (array) Repo::instance()->get_updaters();
150
 
151
- // If the new domain is the old one with a new sub-domain like www.
152
- if ( strpos( $new_url, $old_url ) !== false ) {
153
- list( $subdomain ) = explode( '.', $new_url );
154
- $double_subdomain = $subdomain . '.' . $new_url;
155
- }
156
-
157
- $serialized = new Serialized( $old_url, $new_url );
158
- $serialized->update_all_serialized_tables( $tables );
159
- if ( ! empty( $double_subdomain ) ) {
160
- $serialized = new Serialized( $double_subdomain, $new_url );
161
- $serialized->update_all_serialized_tables( $tables );
162
- }
163
-
164
- $get_columns_query = "SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='{$wpdb->dbname}' AND TABLE_NAME=%s";
165
-
166
- foreach ( (array) $tables as $table ) {
167
- $columns = $wpdb->get_col( $wpdb->prepare( $get_columns_query, $table ) );
168
- foreach ( $columns as $_column ) {
169
- $this->update_column( $table, $_column, $old_url, $new_url );
170
-
171
- foreach ( $updaters as $_updater_class ) {
172
- if ( class_exists( $_updater_class ) ) {
173
- /* @var Updaters_Abstract $_updater - Individual updater class */
174
- $_updater = $_updater_class::factory( $table, $_column, $old_url, $new_url );
175
- $_updater->update_data();
176
- if ( ! empty( $double_subdomain ) ) {
177
- $_updater = new $_updater_class( $table, $_column, $double_subdomain, $new_url );
178
- $_updater->update_data();
179
- }
180
- }
181
- }
182
-
183
- // Fix the double up if this was the old domain with a new subdomain.
184
- if ( ! empty( $double_subdomain ) ) {
185
- $this->update_column( $table, $_column, $double_subdomain, $new_url );
186
- // Fix the emails breaking by being appended the new subdomain.
187
- $this->update_column( $table, $_column, '@' . $new_url, '@' . $old_url );
188
- }
189
  }
 
190
  }
191
 
192
  wp_cache_flush();
193
 
194
  do_action( 'go-live-update-urls/database/after-update', $old_url, $new_url, $tables, $this );
195
 
196
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  }
198
 
199
 
200
  /**
201
  * Update an individual table's column.
202
  *
203
- * @param string $table Table to update.
204
- * @param string $column Column to update.
205
- * @param string $old_url Old URL.
206
- * @param string $new_url New URL.
207
  *
208
  * @since 5.3.0
209
  *
210
- * @return void
211
  */
212
  public function update_column( $table, $column, $old_url, $new_url ) {
213
  global $wpdb;
214
 
 
215
  $update_query = 'UPDATE ' . $table . ' SET `' . $column . '` = replace(`' . $column . '`, %s, %s)';
216
  $wpdb->query( $wpdb->prepare( $update_query, [ $old_url, $new_url ] ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
217
  }
218
  }
3
  namespace Go_Live_Update_Urls;
4
 
5
  use Go_Live_Update_Urls\Traits\Singleton;
 
 
6
 
7
  /**
8
  * Database manipulation.
103
  }
104
 
105
 
106
+ /**
107
+ * Get types of MySQL fields which may contain URLS.
108
+ *
109
+ * Only fields of these types will be updated.
110
+ *
111
+ * @since 6.1.0
112
+ *
113
+ * @return array
114
+ */
115
+ public function get_column_types() {
116
+ $types = [
117
+ 'char',
118
+ 'longtext',
119
+ 'longtext',
120
+ 'mediumtext',
121
+ 'text',
122
+ 'tinytext',
123
+ 'varchar',
124
+ ];
125
+ return apply_filters( 'go-live-update-urls/database/core-tables', $types, $this );
126
+ }
127
+
128
+
129
  /**
130
  * Get the names of every table in this blog
131
  * If we are multisite, we also get the global tables
161
  *
162
  * @since 5.0.0
163
  *
164
+ * @return int[]
165
  */
166
  public function update_the_database( $old_url, $new_url, array $tables ) {
 
167
  do_action( 'go-live-update-urls/database/before-update', $old_url, $new_url, $tables, $this );
168
  $tables = apply_filters( 'go-live-update-urls/database/update-tables', $tables, $this );
 
169
 
170
+ $updates = Updates::factory( $old_url, $new_url, $tables );
171
+ $counts = $updates->update_serialized_values();
172
+ foreach ( (array) $tables as $_table ) {
173
+ if ( ! array_key_exists( $_table, $counts ) ) {
174
+ $counts[ $_table ] = 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  }
176
+ $counts[ $_table ] += $updates->update_table_columns( $_table );
177
  }
178
 
179
  wp_cache_flush();
180
 
181
  do_action( 'go-live-update-urls/database/after-update', $old_url, $new_url, $tables, $this );
182
 
183
+ return apply_filters( 'go-live-update-urls/database/updated/counts', $counts, $old_url, $new_url, $tables, $this );
184
+ }
185
+
186
+
187
+ /**
188
+ * Count all occurrences of the old URL within a provided
189
+ * list of tables.
190
+ *
191
+ * @param string $old_url - the old URL.
192
+ * @param string $new_url - the new URL.
193
+ * @param array $tables - the tables we are going to update.
194
+ *
195
+ * @since 5.0.0
196
+ *
197
+ * @return int[]
198
+ */
199
+ public function count_database_urls( $old_url, $new_url, array $tables ) {
200
+ $tables = apply_filters( 'go-live-update-urls/database/update-tables', $tables, $this );
201
+
202
+ $updates = Updates::factory( $old_url, $new_url, $tables );
203
+ $counts = [];
204
+ foreach ( (array) $tables as $_table ) {
205
+ $counts[ $_table ] = $updates->count_table_urls( $_table );
206
+ }
207
+
208
+ return apply_filters( 'go-live-update-urls/database/counted/counts', $counts, $old_url, $new_url, $tables, $this );
209
  }
210
 
211
 
212
  /**
213
  * Update an individual table's column.
214
  *
215
+ * @param string $table - Table to update.
216
+ * @param string $column - Column to update.
217
+ * @param string $old_url - Old URL.
218
+ * @param string $new_url - New URL.
219
  *
220
  * @since 5.3.0
221
  *
222
+ * @return int
223
  */
224
  public function update_column( $table, $column, $old_url, $new_url ) {
225
  global $wpdb;
226
 
227
+ $count = $this->count_column_urls( $table, $column, $old_url );
228
  $update_query = 'UPDATE ' . $table . ' SET `' . $column . '` = replace(`' . $column . '`, %s, %s)';
229
  $wpdb->query( $wpdb->prepare( $update_query, [ $old_url, $new_url ] ) );
230
+ return $count;
231
+ }
232
+
233
+
234
+ /**
235
+ * Count of number of rows in a table which contain the old URL.
236
+ *
237
+ * When updating, the serialized data is updated first and this
238
+ * counts the left overs.
239
+ *
240
+ * When dry-run counting, this will count all occurrences in the
241
+ * database.
242
+ *
243
+ * @param string $table - Table to update.
244
+ * @param string $column - Column to update.
245
+ * @param string $old_url - Old URL.
246
+ *
247
+ * @since 6.1.0
248
+ *
249
+ * @return int
250
+ */
251
+ public function count_column_urls( $table, $column, $old_url ) {
252
+ global $wpdb;
253
+
254
+ $update_query = "SELECT SUM( ROUND( ( LENGTH( `${column}` ) - LENGTH( REPLACE( `${column}`, %s, '' ) ) ) / LENGTH( %s ) ) ) from `${table}`";
255
+
256
+ return (int) $wpdb->get_var( $wpdb->prepare( $update_query, [ $old_url, $old_url ] ) );
257
  }
258
  }
src/Serialized.php CHANGED
@@ -17,6 +17,7 @@ class Serialized {
17
  * @var string
18
  */
19
  protected $new;
 
20
  /**
21
  * Old URL
22
  *
@@ -24,6 +25,25 @@ class Serialized {
24
  */
25
  protected $old;
26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
  /**
29
  * Serialized constructor.
@@ -44,32 +64,36 @@ class Serialized {
44
  *
45
  * @since 5.2.5 - Only update provided tables.
46
  *
47
- * @return void
48
  */
49
  public function update_all_serialized_tables( array $tables ) {
50
  $serialized_tables = Database::instance()->get_serialized_tables();
51
 
 
52
  foreach ( $serialized_tables as $table => $columns ) {
53
  if ( ! in_array( $table, $tables, true ) ) {
54
  continue;
55
  }
56
- foreach ( (array) $columns as $_column ) {
57
- $this->update_table( $table, $_column );
58
- }
59
  }
 
60
  }
61
 
62
 
63
  /**
64
- * Query all serialized rows from a database table and update them one by one
 
65
  *
66
- * @param string $table - Database table.
67
  * @param string $column - Database column.
68
  *
69
- * @return void
70
  */
71
  protected function update_table( $table, $column ) {
72
  global $wpdb;
 
73
  $column = (string) esc_sql( $column );
74
  $table = (string) esc_sql( $table );
75
  $pk = $wpdb->get_results( 'SHOW KEYS FROM `' . $table . "` WHERE Key_name = 'PRIMARY'" );
@@ -77,15 +101,15 @@ class Serialized {
77
  $pk = $wpdb->get_results( 'SHOW KEYS FROM `' . $table . '`' );
78
  if ( empty( $pk[0] ) ) {
79
  // Fail.
80
- return;
81
  }
82
  }
83
  $primary_key_column = $pk[0]->Column_name;
84
 
85
  // Get all serialized rows.
86
- $rows = $wpdb->get_results( "SELECT $primary_key_column, {$column} FROM {$table} WHERE {$column} LIKE 'a:%' OR {$column} LIKE 'O:%'" ); //phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
87
 
88
- foreach ( $rows as $row ) {
89
  if ( ! $this->has_data_to_update( $row->{$column} ) ) {
90
  continue;
91
  }
@@ -95,8 +119,13 @@ class Serialized {
95
  $clean = @serialize( $clean );
96
  //phpcs:enable
97
 
98
- $wpdb->query( $wpdb->prepare( "UPDATE {$table} SET {$column}=%s WHERE {$primary_key_column}=%s", $clean, $row->{$primary_key_column} ) ); //phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
 
 
 
99
  }
 
 
100
  }
101
 
102
 
@@ -144,11 +173,17 @@ class Serialized {
144
  * @return string
145
  */
146
  protected function replace( $mysql_value ) {
 
 
147
  foreach ( Repo::instance()->get_updaters() as $_updater ) {
148
- $mysql_value = str_replace( $_updater::apply_rule_to_url( $this->old ), $_updater::apply_rule_to_url( $this->new ), $mysql_value );
 
 
 
 
149
  }
150
 
151
- return trim( str_replace( $this->old, $this->new, $mysql_value ) );
152
  }
153
 
154
 
@@ -179,4 +214,29 @@ class Serialized {
179
  return false;
180
  }
181
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  }
17
  * @var string
18
  */
19
  protected $new;
20
+
21
  /**
22
  * Old URL
23
  *
25
  */
26
  protected $old;
27
 
28
+ /**
29
+ * Hold replacement count during a table update.
30
+ * We may replace multiple per table row so we count
31
+ * the actual str_replace() instead of mysql affected.
32
+ *
33
+ * @var int
34
+ */
35
+ protected $count = 0;
36
+
37
+ /**
38
+ * Setting dry run to `true` will prevent any data
39
+ * from being updated in the database but still run
40
+ * through the process and return counts of would
41
+ * have been updated of dry run was `false`.
42
+ *
43
+ * @var bool
44
+ */
45
+ protected $dry_run = false;
46
+
47
 
48
  /**
49
  * Serialized constructor.
64
  *
65
  * @since 5.2.5 - Only update provided tables.
66
  *
67
+ * @return int[]
68
  */
69
  public function update_all_serialized_tables( array $tables ) {
70
  $serialized_tables = Database::instance()->get_serialized_tables();
71
 
72
+ $counts = [];
73
  foreach ( $serialized_tables as $table => $columns ) {
74
  if ( ! in_array( $table, $tables, true ) ) {
75
  continue;
76
  }
77
+ $counts[ $table ] = array_sum( array_map( function ( $column ) use ( $table ) {
78
+ return $this->update_table( $table, $column );
79
+ }, (array) $columns ) );
80
  }
81
+ return $counts;
82
  }
83
 
84
 
85
  /**
86
+ * Query all serialized rows from a database table and
87
+ * update them one by one.
88
  *
89
+ * @param string $table - Database table.
90
  * @param string $column - Database column.
91
  *
92
+ * @return int
93
  */
94
  protected function update_table( $table, $column ) {
95
  global $wpdb;
96
+ $this->count = 0;
97
  $column = (string) esc_sql( $column );
98
  $table = (string) esc_sql( $table );
99
  $pk = $wpdb->get_results( 'SHOW KEYS FROM `' . $table . "` WHERE Key_name = 'PRIMARY'" );
101
  $pk = $wpdb->get_results( 'SHOW KEYS FROM `' . $table . '`' );
102
  if ( empty( $pk[0] ) ) {
103
  // Fail.
104
+ return 0;
105
  }
106
  }
107
  $primary_key_column = $pk[0]->Column_name;
108
 
109
  // Get all serialized rows.
110
+ $rows = $wpdb->get_results( "SELECT `$primary_key_column`, `{$column}` FROM `{$table}` WHERE `{$column}` LIKE 'a:%' OR `{$column}` LIKE 'O:%'" ); //phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
111
 
112
+ foreach ( $rows as $k => $row ) {
113
  if ( ! $this->has_data_to_update( $row->{$column} ) ) {
114
  continue;
115
  }
119
  $clean = @serialize( $clean );
120
  //phpcs:enable
121
 
122
+ if ( ! $this->dry_run ) {
123
+ //phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
124
+ $wpdb->query( $wpdb->prepare( "UPDATE `{$table}` SET `{$column}`=%s WHERE `{$primary_key_column}` = %s", $clean, $row->{$primary_key_column} ) );
125
+ }
126
  }
127
+
128
+ return $this->count;
129
  }
130
 
131
 
173
  * @return string
174
  */
175
  protected function replace( $mysql_value ) {
176
+ $mysql_value = trim( str_replace( $this->old, $this->new, $mysql_value, $count ) );
177
+ $this->count += $count;
178
  foreach ( Repo::instance()->get_updaters() as $_updater ) {
179
+ $formatted = $_updater::apply_rule_to_url( $this->old );
180
+ if ( $formatted !== $this->old ) {
181
+ $mysql_value = (string) str_replace( $formatted, $_updater::apply_rule_to_url( $this->new ), $mysql_value, $count );
182
+ $this->count += $count;
183
+ }
184
  }
185
 
186
+ return trim( $mysql_value );
187
  }
188
 
189
 
214
  return false;
215
  }
216
 
217
+
218
+ /**
219
+ * Getter for current count.
220
+ *
221
+ * @since 6.1.0
222
+ *
223
+ * @return int
224
+ */
225
+ public function get_count() {
226
+ return $this->count;
227
+ }
228
+
229
+
230
+ /**
231
+ * Set the property to determine if we are
232
+ * doing a dry run for counts, or actually updating
233
+ * the database.
234
+ *
235
+ * @since 6.1.0
236
+ *
237
+ * @param bool $dry_run - Is this a dry run or not.
238
+ */
239
+ public function set_dry_run( $dry_run ) {
240
+ $this->dry_run = $dry_run;
241
+ }
242
  }
src/Updaters/Repo.php CHANGED
@@ -9,8 +9,6 @@ use Go_Live_Update_Urls\Traits\Singleton;
9
  *
10
  * @author OnPoint Plugins
11
  * @since 6.0.0
12
- *
13
- * @package Go_Live_Update_Urls\Updates
14
  */
15
  class Repo {
16
  use Singleton;
@@ -19,8 +17,6 @@ class Repo {
19
  * Get all registered updaters by classname
20
  * This list will grow over time as things are converted over
21
  *
22
- * @filter go_live_update_urls_updaters
23
- *
24
  * @return Updaters_Abstract[]
25
  */
26
  public function get_updaters() {
9
  *
10
  * @author OnPoint Plugins
11
  * @since 6.0.0
 
 
12
  */
13
  class Repo {
14
  use Singleton;
17
  * Get all registered updaters by classname
18
  * This list will grow over time as things are converted over
19
  *
 
 
20
  * @return Updaters_Abstract[]
21
  */
22
  public function get_updaters() {
src/Updaters/Updaters_Abstract.php CHANGED
@@ -60,7 +60,7 @@ abstract class Updaters_Abstract {
60
  * The method which is called to actually run the update
61
  * using this updater.
62
  *
63
- * @return bool
64
  */
65
  abstract public function update_data();
66
 
@@ -68,13 +68,27 @@ abstract class Updaters_Abstract {
68
  /**
69
  * Update this table and column.
70
  *
71
- * @param string $old_url Old URL.
72
- * @param string $new_url New URL.
73
  *
74
- * @return void
75
  */
76
  protected function update_column( $old_url, $new_url ) {
77
- Database::instance()->update_column( $this->table, $this->column, $old_url, $new_url );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  }
79
 
80
 
60
  * The method which is called to actually run the update
61
  * using this updater.
62
  *
63
+ * @return int
64
  */
65
  abstract public function update_data();
66
 
68
  /**
69
  * Update this table and column.
70
  *
71
+ * @param string $old_url - Old URL.
72
+ * @param string $new_url - New URL.
73
  *
74
+ * @return int
75
  */
76
  protected function update_column( $old_url, $new_url ) {
77
+ return Database::instance()->update_column( $this->table, $this->column, $old_url, $new_url );
78
+ }
79
+
80
+
81
+ /**
82
+ * Count occurrences of the old URL in this table's column.
83
+ *
84
+ * @return int
85
+ */
86
+ public function count_urls() {
87
+ $old_url = static::apply_rule_to_url( $this->old );
88
+ if ( $old_url === $this->old ) {
89
+ return 0;
90
+ }
91
+ return Database::instance()->count_column_urls( $this->table, $this->column, $old_url );
92
  }
93
 
94
 
src/Updaters/Url_Encoded.php CHANGED
@@ -29,17 +29,15 @@ class Url_Encoded extends Updaters_Abstract {
29
  * Update the old encoded URL with the new encoded URL if the entered
30
  * old URL is different than the encoded version.
31
  *
32
- * @return bool
33
  */
34
  public function update_data() {
35
  $old = self::apply_rule_to_url( $this->old );
36
  if ( $old === $this->old ) {
37
- return false;
38
  }
39
 
40
- $this->update_column( $old, self::apply_rule_to_url( $this->new ) );
41
-
42
- return true;
43
  }
44
 
45
  }
29
  * Update the old encoded URL with the new encoded URL if the entered
30
  * old URL is different than the encoded version.
31
  *
32
+ * @return int
33
  */
34
  public function update_data() {
35
  $old = self::apply_rule_to_url( $this->old );
36
  if ( $old === $this->old ) {
37
+ return 0;
38
  }
39
 
40
+ return $this->update_column( $old, self::apply_rule_to_url( $this->new ) );
 
 
41
  }
42
 
43
  }
src/Updates.php ADDED
@@ -0,0 +1,265 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Go_Live_Update_Urls;
4
+
5
+ use Go_Live_Update_Urls\Updaters\Repo;
6
+
7
+ /**
8
+ * Translated provided URLS into various steps to update the database.
9
+ *
10
+ * While no updates to the database are done within this class,
11
+ * all calls to the methods which update the database go through here
12
+ * except for serialized data.
13
+ *
14
+ * This class determines which data needs to be updated in which way
15
+ * and makes necessary calls.
16
+ *
17
+ * @since 6.1.0
18
+ */
19
+ class Updates {
20
+ /**
21
+ * Entered OLD URL.
22
+ *
23
+ * @var string
24
+ */
25
+ protected $old_url;
26
+
27
+ /**
28
+ * Entered OLD URL.
29
+ *
30
+ * @var string
31
+ */
32
+ protected $new_url;
33
+
34
+ /**
35
+ * List of selected tables.
36
+ *
37
+ * @var string[]
38
+ */
39
+ protected $tables;
40
+
41
+
42
+ /**
43
+ * Updates constructor.
44
+ *
45
+ * @param string $old - Entered old URL.
46
+ * @param string $new - Entered new URL.
47
+ * @param string[] $tables - List of tables to interact with.
48
+ */
49
+ public function __construct( $old, $new, array $tables ) {
50
+ $this->old_url = $old;
51
+ $this->new_url = $new;
52
+ $this->tables = $tables;
53
+ }
54
+
55
+
56
+ /**
57
+ * Update all instances of the URLS within a provided table.
58
+ *
59
+ * Takes care of all calls related to necessary updates.
60
+ *
61
+ * @param string $table - Table to update.
62
+ *
63
+ * @return int
64
+ */
65
+ public function update_table_columns( $table ) {
66
+ $doubled = $this->get_doubled_up_subdomain();
67
+ $columns = $this->get_table_columns( $table );
68
+ $count = 0;
69
+ array_walk( $columns, function ( $column ) use ( $table, $doubled, &$count ) {
70
+ $count += (int) Database::instance()->update_column( $table, $column, $this->old_url, $this->new_url );
71
+ $count += (int) $this->update_column_with_updaters( $table, $column );
72
+ $this->update_email_addresses( $table, $column );
73
+
74
+ if ( null !== $doubled ) {
75
+ Database::instance()->update_column( $table, $column, $doubled, $this->new_url );
76
+ }
77
+ } );
78
+
79
+ return $count;
80
+ }
81
+
82
+
83
+ /**
84
+ * Counts all instances of the URLS within a provided table.
85
+ *
86
+ * @param string $table - Table to count.
87
+ *
88
+ * @return int
89
+ */
90
+ public function count_table_urls( $table ) {
91
+ $columns = $this->get_table_columns( $table );
92
+ $count = 0;
93
+ array_walk( $columns, function ( $column ) use ( $table, &$count ) {
94
+ $count += (int) Database::instance()->count_column_urls( $table, $column, $this->old_url );
95
+ $count += (int) $this->count_column_urls_with_updaters( $table, $column );
96
+ } );
97
+
98
+ return $count;
99
+ }
100
+
101
+
102
+ /**
103
+ * Remove any prepended subdomain from email addresses.
104
+ *
105
+ * If we change a domain to a subdomain like www, and an email address
106
+ * is using the original domain we end up with an email address that
107
+ * includes @www We remove the prepended www from email addresses
108
+ * here.
109
+ *
110
+ * @param string $table - Any database table.
111
+ * @param string $column - Any column within the provided table.
112
+ *
113
+ * @return int
114
+ */
115
+ protected function update_email_addresses( $table, $column ) {
116
+ $url = wp_parse_url( $this->old_url );
117
+ $doubled = $this->get_doubled_up_subdomain();
118
+ if ( null === $doubled || ! empty( $url['scheme'] ) ) {
119
+ return 0;
120
+ }
121
+ return Database::instance()->update_column( $table, $column, '@' . $this->new_url, '@' . $this->old_url );
122
+ }
123
+
124
+
125
+ /**
126
+ * Using all registered updaters, replace the Updater's variation
127
+ * of the URL.
128
+ *
129
+ * Actual translation and updating is handled by each updater.
130
+ * We simply load and call them here.
131
+ *
132
+ * @param string $table - Any database table.
133
+ * @param string $column - Any column within the provided table.
134
+ *
135
+ * @return int
136
+ */
137
+ protected function update_column_with_updaters( $table, $column ) {
138
+ $doubled = $this->get_doubled_up_subdomain();
139
+ $count = 0;
140
+ array_map( function ( $class ) use ( $doubled, $table, $column, &$count ) {
141
+ if ( class_exists( $class ) ) {
142
+ $updater = $class::factory( $table, $column, $this->old_url, $this->new_url );
143
+ $count += (int) $updater->update_data();
144
+ if ( null !== $doubled ) {
145
+ $updater = $class::factory( $table, $column, $doubled, $this->new_url );
146
+ $updater->update_data();
147
+ }
148
+ }
149
+ }, Repo::instance()->get_updaters() );
150
+ return $count;
151
+ }
152
+
153
+
154
+ /**
155
+ * Using all registered updaters, count the Updater's variation
156
+ * of the URL.
157
+ *
158
+ * Actual counting is handled by each updater.
159
+ * We simply load and call them here.
160
+ *
161
+ * @param string $table - Any database table.
162
+ * @param string $column - Any column within the provided table.
163
+ *
164
+ * @return int
165
+ */
166
+ protected function count_column_urls_with_updaters( $table, $column ) {
167
+ $count = 0;
168
+ array_map( function ( $class ) use ( $table, $column, &$count ) {
169
+ if ( class_exists( $class ) ) {
170
+ $updater = $class::factory( $table, $column, $this->old_url, $this->new_url );
171
+ $count += (int) $updater->count_urls();
172
+ }
173
+ }, Repo::instance()->get_updaters() );
174
+ return $count;
175
+ }
176
+
177
+
178
+ /**
179
+ * Update values in all serialized columns within the specified tables.
180
+ *
181
+ * Detection of which columns are possibly serialized is handled within
182
+ * the Serialized class. We simply provide the OLD and NEW URL and the
183
+ * list of tables we are updating.
184
+ *
185
+ * @return int[]
186
+ */
187
+ public function update_serialized_values() {
188
+ $serialized = new Serialized( $this->old_url, $this->new_url );
189
+ $counts = $serialized->update_all_serialized_tables( $this->tables );
190
+
191
+ $doubled = $this->get_doubled_up_subdomain();
192
+ if ( null !== $doubled ) {
193
+ $serialized = new Serialized( $doubled, $this->new_url );
194
+ $serialized->update_all_serialized_tables( $this->tables );
195
+ // Remove an prepended subdomain like www. from email addresses.
196
+ $serialized = new Serialized( '@' . $this->new_url, '@' . $this->old_url );
197
+ $serialized->update_all_serialized_tables( $this->tables );
198
+ }
199
+
200
+ return $counts;
201
+ }
202
+
203
+
204
+ /**
205
+ * If the new domain is the old one with a new sub-domain like www.
206
+ * the first round of updates will create double sub-domains in
207
+ * the database like www.www.
208
+ *
209
+ * If we doubled up some domains we get the result, or null
210
+ * if the entered values would not create doubles.
211
+ *
212
+ * @since 6.1.0
213
+ *
214
+ * @return string|null
215
+ */
216
+ protected function get_doubled_up_subdomain() {
217
+ if ( strpos( $this->new_url, $this->old_url ) !== false ) {
218
+ list( $subdomain ) = explode( '.', $this->new_url );
219
+ return $subdomain . '.' . $this->new_url;
220
+ }
221
+ return null;
222
+ }
223
+
224
+
225
+ /**
226
+ * Return all database columns for a specified table that
227
+ * match the column types we update.
228
+ *
229
+ * We include any varchar or char which are 21 characters
230
+ * or above which takes care of a lot of core columns which
231
+ * don't store URLs.
232
+ *
233
+ * @param string $table - Database table to retrieve from.
234
+ *
235
+ * @since 6.1.0
236
+ *
237
+ * @return string[]
238
+ */
239
+ protected function get_table_columns( $table ) {
240
+ global $wpdb;
241
+
242
+ $all = $wpdb->get_results( $wpdb->prepare( "SELECT COLUMN_NAME as name, COLUMN_TYPE as type FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='{$wpdb->dbname}' AND TABLE_NAME=%s", $table ) );
243
+ $types = Database::instance()->get_column_types();
244
+
245
+ return wp_list_pluck( array_filter( $all, function ( $column ) use ( $types ) {
246
+ // Strip the (\d) from varchar and char with (21) and over.
247
+ return in_array( preg_replace( '/\((\d{3}|[3-9][\d]|[2][1-9])[\d]*?\)/', '', $column->type ), $types, true );
248
+ } ), 'name' );
249
+ }
250
+
251
+
252
+ /**
253
+ * Construct the Updates class.
254
+ *
255
+ * @param string $old_url - Entered old URL.
256
+ * @param string $new_url - Entered new URL.
257
+ *
258
+ * @param string[] $tables - List of tables to interact with.
259
+ *
260
+ * @return static
261
+ */
262
+ public static function factory( $old_url, $new_url, array $tables ) {
263
+ return new static( $old_url, $new_url, $tables );
264
+ }
265
+ }