PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.7.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.7.0
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
← All changes | includes/class-wp-optimize-database-information.php +226 -65 3.2.5 → 4.7.0 View file →
@@ -19,8 +19,21 @@
19 19 const ARIA_ENGINE = 'Aria'; // MariaDB
20 20 const VIEW = 'VIEW';
21 21
22 22 /**
23 + * Returns singleton instance object
24 + *
25 + * @return WP_Optimize_Database_Information Returns `WP_Optimize_Database_Information` object
26 + */
27 + public static function instance() {
28 + static $_instance = null;
29 + if (null === $_instance) {
30 + $_instance = new self();
31 + }
32 + return $_instance;
33 + }
34 +
35 + /**
23 36 * Returns server type MySQL or MariaDB if mysql database or Unknown if not mysql.
24 37 *
25 38 * @return string
26 39 */
@@ -67,15 +80,16 @@
67 80 return false;
68 81 }
69 82
70 83 /**
71 - * Return table type by $table_name.
84 + * Return the table type by $table_name.
72 85 *
73 - * @param String $table_name Database table name.
74 - * @return String|Boolean - returns false upon failure
86 + * @param string $table_name Database table name.
87 + * @param object|null $table_info Optional pre-fetched table status object (e.g. from a bulk fetch), to avoid a redundant lookup.
88 + * @return string|boolean - returns false upon failure
75 89 */
76 - public function get_table_type($table_name) {
77 - $table_info = $this->get_table_status($table_name);
90 + public function get_table_type($table_name, $table_info = null) {
91 + if (null === $table_info) $table_info = $this->get_table_status($table_name);
78 92
79 93 if ($table_info) {
80 94 if (!$table_info->Engine && $this->is_view($table_name)) return self::VIEW;
81 95
@@ -89,15 +103,15 @@
89 103 * Returns information about database table.
90 104 *
91 105 * @param string $table_name
92 106 * @param bool $update if true, then force request to database and don't use cached values.
93 - * @return bool|mixed
107 + * @return mixed
94 108 */
95 109 public function get_table_status($table_name, $update = false) {
96 110 $tables_info = $this->get_show_table_status($update, $table_name);
97 111
98 112 foreach ($tables_info as $table_info) {
99 - if ($table_name == $table_info->Name) return $table_info;
113 + if ($table_name === $table_info->Name) return $table_info;
100 114 }
101 115
102 116 return false;
103 117 }
@@ -102,12 +116,73 @@
102 116 return false;
103 117 }
104 118
105 119 /**
120 + * Count the tables in the database
121 + *
122 + * @param string $prefix The generic prefix of the tables in the database
123 + * @param bool $update if true, then force request to database and don't use cached values.
124 + * @return int
125 + */
126 + public function get_table_count($prefix = '', $update = false) {
127 + global $wpdb;
128 + static $table_counts = array();
129 +
130 + if (!$update && isset($table_counts[$prefix])) return $table_counts[$prefix];
131 +
132 + $table_counts[$prefix] = (int) $wpdb->get_var(
133 + $wpdb->prepare(
134 + "SELECT COUNT(1)
135 + FROM INFORMATION_SCHEMA.TABLES
136 + WHERE TABLE_SCHEMA = %s
137 + AND TABLE_NAME LIKE %s",
138 + DB_NAME,
139 + $prefix . '%'
140 + )
141 + );
142 +
143 + return $table_counts[$prefix];
144 + }
145 +
146 + /**
147 + * Get all tables names from information_schema
148 + *
149 + * @param string $prefix The global table prefix
150 + * @param int $offset Paginate the result to avoid request timeout for large table counts
151 + * @param int $limit Pagination size
152 + * @return array
153 + */
154 + public function get_tables_names($prefix = '', $offset = 0, $limit = null) {
155 + global $wpdb;
156 +
157 + $sql = "SELECT *
158 + FROM INFORMATION_SCHEMA.TABLES
159 + WHERE TABLE_SCHEMA = %s
160 + AND TABLE_NAME LIKE %s";
161 +
162 + $params = array(DB_NAME, $prefix . '_%');
163 +
164 + if (null !== $limit) {
165 + $sql .= " LIMIT %d, %d";
166 + $params[] = (int) $offset;
167 + $params[] = (int) $limit;
168 + }
169 +
170 + $result = $wpdb->get_results($wpdb->prepare($sql, $params)); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $sql only contains static text and %s/%d placeholders, passed through $wpdb->prepare()
171 +
172 + $names = array();
173 + foreach ($result as $row) {
174 + $names[] = $row->TABLE_NAME;
175 + }
176 +
177 + return $names;
178 + }
179 +
180 + /**
106 181 * Returns result for query SHOW TABLE STATUS.
107 182 *
108 183 * @param bool $update refresh or no cached data
109 - * @return array
184 + * @return array|object|stdClass[]|null
110 185 */
111 186 public function get_show_table_status($update = false, $table_name = '') {
112 187 global $wpdb;
113 188 static $tables_info = array();
@@ -112,19 +187,22 @@
112 187 global $wpdb;
113 188 static $tables_info = array();
114 189 static $fetched_all_tables = false;
115 190
191 + if ($fetched_all_tables && !$update) {
192 + return $tables_info;
193 + }
194 +
116 195 // If a table name is provided, and the whole record hasn't been fetched yet, only fetch the information for the current table.
117 - // This allows for a big preformance gain when using WP-CLI or doing single optimizations.
196 + // This allows for a big performance gain when using WP-CLI or doing single optimizations.
118 197 if ($table_name && !$fetched_all_tables) {
119 - $sql = $wpdb->prepare("SHOW TABLE STATUS LIKE '%s'", $table_name);
120 - $tables_info = $wpdb->get_results($sql);
198 + $tables_info = $wpdb->get_results($wpdb->prepare("SHOW TABLE STATUS LIKE %s", $table_name));
121 199 } else {
122 200 if ($update || empty($tables_info) || !is_array($tables_info) || !$fetched_all_tables) {
123 201 $tables_info = $wpdb->get_results('SHOW TABLE STATUS');
124 202 $fetched_all_tables = true;
125 203 foreach ($tables_info as $i => $table) {
126 - $rows_count = get_transient($table->Name . '_count');
204 + $rows_count = get_transient('wpo_' . $table->Name . '_count');
127 205 if (false === $rows_count) break;
128 206 $tables_info[$i]->Rows = $rows_count;
129 207 }
130 208 }
@@ -132,9 +210,9 @@
132 210
133 211 // If option innodb_file_per_table is disabled then Data_free column will have summary overhead value for all table.
134 212 if (!empty($tables_info)) {
135 213 foreach ($tables_info as $i => $table) {
136 - if (self::INNODB_ENGINE == $table->Engine && false == $this->is_option_enabled('innodb_file_per_table')) {
214 + if (self::INNODB_ENGINE == $table->Engine && !$this->is_option_enabled('innodb_file_per_table')) {
137 215 $tables_info[$i]->Data_free = 0;
138 216 }
139 217 }
140 218 }
@@ -144,8 +222,10 @@
144 222
145 223 /**
146 224 * Whether a table exists
147 225 *
226 + * @param string $table_name Name of the table
227 + * @param bool $use_default_prefix Whether to use default prefix
148 228 * @return boolean
149 229 */
150 230 public function table_exists($table_name, $use_default_prefix = true) {
151 231 global $wpdb;
@@ -185,9 +265,9 @@
185 265 $tables_info = $this->get_show_full_tables();
186 266
187 267 if (!array_key_exists($table_name, $tables_info)) return false;
188 268
189 - return ('VIEW' == $tables_info[$table_name]);
269 + return ('VIEW' === $tables_info[$table_name]);
190 270 }
191 271
192 272 /**
193 273 * Returns true if DDL supported.
@@ -194,15 +274,15 @@
194 274 *
195 275 * @return bool
196 276 */
197 277 public function has_online_ddl() {
198 - if (self::MYSQL_DB == $this->get_server_type()) {
278 + if (self::MYSQL_DB === $this->get_server_type()) {
199 279 if (version_compare($this->get_version(), '5.7', '>=')) {
200 280 return true;
201 281 } else {
202 282 return false;
203 283 }
204 - } elseif (self::MARIA_DB == $this->get_server_type()) {
284 + } elseif (self::MARIA_DB === $this->get_server_type()) {
205 285 if (version_compare($this->get_version(), '10.0.0', '>=')) {
206 286 return true;
207 287 } else {
208 288 return false;
@@ -244,38 +324,38 @@
244 324 */
245 325 public function is_option_enabled($option_name) {
246 326 $option_value = $this->get_option_value($option_name);
247 327
248 - if ('ON' == strtoupper($option_value)) return true;
249 - return false;
328 + return 'ON' === strtoupper($option_value);
250 329 }
251 330
252 331 /**
253 332 * Returns true if table $table_name is optimizable
254 333 *
255 - * @param string $table_name Name of database table
334 + * @param string $table_name Name of database table
335 + * @param string|bool $table_type Optional pre-resolved table engine/type, to avoid a redundant lookup.
256 336 * @return bool
257 337 */
258 - public function is_table_optimizable($table_name) {
338 + public function is_table_optimizable($table_name, $table_type = null) {
259 339 $server_type = $this->get_server_type();
260 340 $server_version = $this->get_version();
261 - $table_type = $this->get_table_type($table_name);
341 + $table_type = null !== $table_type ? $table_type : $this->get_table_type($table_name);
262 342
263 343 // return true if table is MyISAM.
264 - if (self::MYISAM_ENGINE == $table_type) return true;
344 + if (self::MYISAM_ENGINE === $table_type) return true;
265 345
266 346 // return true if table is Archive or Aria.
267 - if (self::ARCHIVE_ENGINE == $table_type || self::ARIA_ENGINE == $table_type) return true;
347 + if (self::ARCHIVE_ENGINE === $table_type || self::ARIA_ENGINE === $table_type) return true;
268 348
269 349 // if InnoDB then check if we can optimize.
270 - if (self::INNODB_ENGINE == $table_type) {
350 + if (self::INNODB_ENGINE === $table_type) {
271 351 // check for MysqlDB.
272 - if (self::MYSQL_DB == $server_type && $this->has_online_ddl()) {
352 + if (self::MYSQL_DB === $server_type && $this->has_online_ddl()) {
273 353 return true;
274 354 }
275 355
276 356 // check for MariaDB.
277 - if (self::MARIA_DB == $server_type) {
357 + if (self::MARIA_DB === $server_type) {
278 358 // if innodb_file_per_table enabled or version not older than 10.1.1 and innodb_defragment enabled.
279 359 if ($this->is_option_enabled('innodb_file_per_table') || (version_compare($server_version, '10.1.1', '>=') && $this->is_option_enabled('innodb_defragment'))) {
280 360 return true;
281 361 }
@@ -286,15 +366,16 @@
286 366 return false;
287 367 }
288 368
289 369 /**
290 - * Returns true if table type is supported for optimization.
370 + * Returns true if the table type is supported for optimization.
291 371 *
292 - * @param string $table_name Name of database table
372 + * @param string $table_name Name of database table
373 + * @param string|bool $table_type Optional pre-resolved table engine/type, to avoid a redundant lookup.
293 374 * @return bool
294 375 */
295 - public function is_table_type_optimize_supported($table_name) {
296 - $table_type = $this->get_table_type($table_name);
376 + public function is_table_type_optimize_supported($table_name, $table_type = null) {
377 + $table_type = null !== $table_type ? $table_type : $this->get_table_type($table_name);
297 378
298 379 $supported_table_types = array(
299 380 self::MYISAM_ENGINE,
300 381 self::INNODB_ENGINE,
@@ -307,13 +388,14 @@
307 388
308 389 /**
309 390 * Returns true if table type is supported for repair.
310 391 *
311 - * @param string $table_name
392 + * @param string $table_name
393 + * @param string|bool $table_type Optional pre-resolved table engine/type, to avoid a redundant lookup.
312 394 * @return bool
313 395 */
314 - public function is_table_type_repair_supported($table_name) {
315 - $table_type = $this->get_table_type($table_name);
396 + public function is_table_type_repair_supported($table_name, $table_type = null) {
397 + $table_type = null !== $table_type ? $table_type : $this->get_table_type($table_name);
316 398
317 399 $supported_table_types = array(
318 400 self::MYISAM_ENGINE,
319 401 self::ARCHIVE_ENGINE,
@@ -326,8 +408,9 @@
326 408 /**
327 409 * Run CHECK TABLE query and returns statuses for single or list of tables.
328 410 *
329 411 * @param array|string $table
412 + * @return array
330 413 */
331 414 public function check_table($table) {
332 415 global $wpdb;
333 416
@@ -338,9 +421,9 @@
338 421 $result = array();
339 422
340 423 if (empty($table)) return $result;
341 424
342 - $query_result = $wpdb->get_results('CHECK TABLE `'.$table.'`;');
425 + $query_result = $wpdb->get_results('CHECK TABLE `'. esc_sql($table).'`;');
343 426
344 427 if (empty($query_result)) return $result;
345 428
346 429 foreach ($query_result as $row) {
@@ -353,9 +436,9 @@
353 436 'corrupted' => false,
354 437 );
355 438 }
356 439
357 - if ('error' == $row->Msg_type) {
440 + if ('error' === $row->Msg_type) {
358 441 $result[$table_name]['status'] = $row->Msg_type;
359 442
360 443 if (preg_match('/corrupt/i', $row->Msg_text)) {
361 444 $result[$table_name]['corrupted'] = true;
@@ -363,9 +446,9 @@
363 446 $result[$table_name]['message'] = $row->Msg_text;
364 447 }
365 448 }
366 449
367 - if ('status' == $row->Msg_type) {
450 + if ('status' === $row->Msg_type) {
368 451 $result[$table_name]['status'] = $row->Msg_text;
369 452 }
370 453 }
371 454
@@ -385,9 +468,9 @@
385 468 $tables = $this->get_show_table_status();
386 469 $supported_tables = array();
387 470
388 471 foreach ($tables as $table) {
389 - if ('' == $table->Engine || $this->is_table_type_repair_supported($table->Name)) {
472 + if ('' === $table->Engine || $this->is_table_type_repair_supported($table->Name, $table->Engine)) {
390 473 $supported_tables[] = $table->Name;
391 474 }
392 475 }
393 476
@@ -398,39 +481,35 @@
398 481
399 482 /**
400 483 * Returns true if table needing repair.
401 484 *
402 - * @param string $table_name Database table name.
485 + * @param string $table_name Database table name.
486 + * @param string|bool $table_type Optional pre-resolved table engine/type, to avoid a redundant lookup.
403 487 */
404 - public function is_table_needing_repair($table_name) {
488 + public function is_table_needing_repair($table_name, $table_type = null) {
405 489 $table_statuses = $this->check_all_tables();
406 490
407 - if (!$this->is_table_type_repair_supported($table_name)) return false;
491 + if (!$this->is_table_type_repair_supported($table_name, $table_type)) return false;
408 492
409 - if (is_array($table_statuses) && array_key_exists($table_name, $table_statuses) && $table_statuses[$table_name]['corrupted']) {
410 - return true;
411 - } else {
412 - return false;
413 - }
493 + return (array_key_exists($table_name, $table_statuses) && $table_statuses[$table_name]['corrupted']);
414 494 }
415 495
416 496 /**
417 - * Check if $table using by any of installed plugins.
497 + * Check if any of plugins from $plugin_names is installed.
418 498 *
419 - * @param string $table
499 + * @param array $plugin_names
420 500 * @return bool
421 501 */
422 - public function is_table_using_by_plugin($table) {
423 - $plugin_names = $this->get_table_plugin($table);
502 + public function is_any_plugin_installed($plugin_names) {
424 503
425 - // if we can't determine which plugin use $table then return true.
426 - if (false == $plugin_names) {
427 - return true;
504 + if (empty($plugin_names)) {
505 + return false;
428 506 }
429 507
430 508 // is WordPress core table or using by any of installed plugins then return true.
431 509 foreach ($plugin_names as $plugin_name) {
432 - if (__('WordPress core', 'wp-optimize') == $plugin_name || in_array($plugin_name, $this->get_all_installed_plugins())) {
510 + // $plugin_name is a translatable string, so we compare it with a translated string
511 + if (__('WordPress core', 'wp-optimize') === $plugin_name || in_array($plugin_name, $this->get_all_installed_plugins())) {
433 512 return true;
434 513 }
435 514 }
436 515
@@ -451,9 +530,9 @@
451 530
452 531 // if match with base_prefix_(number)_
453 532 if (preg_match('/^'.$wpdb->base_prefix.'(\d+)_/', $table_name, $match)) {
454 533 // check if matched number in available sites.
455 - if (false !== array_search($match[1], $blogs_ids)) return $match[1];
534 + if (in_array($match[1], $blogs_ids)) return absint($match[1]);
456 535 }
457 536 }
458 537
459 538 return 1;
@@ -510,11 +589,20 @@
510 589 $plugin_tables[$table][] = __('WordPress core', 'wp-optimize');
511 590 }
512 591
513 592 // add WP-Optimize tables.
514 - $plugin_tables['tm_taskmeta'][] = 'wp-optimize';
515 - $plugin_tables['tm_tasks'][] = 'wp-optimize';
593 + $wpo = 'wp-optimize';
594 + $plugin_tables['tm_taskmeta'] = $plugin_tables['tm_taskmeta'] ?? array();
595 + $plugin_tables['tm_tasks'] = $plugin_tables['tm_tasks'] ?? array();
516 596
597 + if (!in_array($wpo, $plugin_tables['tm_taskmeta'], true)) {
598 + $plugin_tables['tm_taskmeta'][] = $wpo;
599 + }
600 +
601 + if (!in_array($wpo, $plugin_tables['tm_tasks'], true)) {
602 + $plugin_tables['tm_tasks'][] = $wpo;
603 + }
604 +
517 605 return $plugin_tables;
518 606 }
519 607
520 608 /**
@@ -525,16 +613,32 @@
525 613 */
526 614 public function get_table_plugin($table) {
527 615 global $wpdb;
528 616
617 + $plugins = array();
618 + $original_table = $table;
529 619 // delete table prefix.
530 620 $table = preg_replace('/^'.$wpdb->prefix.'([0-9]+_)?/', '', $table);
531 621 $plugins_tables = $this->get_all_plugin_tables_relationship();
532 622
623 + // If a direct match exists.
533 624 if (array_key_exists($table, $plugins_tables)) {
534 - return $plugins_tables[$table];
625 + $plugins = $plugins_tables[$table];
535 626 }
536 627
628 + // if has pro_quiz in name then try to match with learndash tables.
629 + if (false !== stripos($original_table, 'pro_quiz')) {
630 + $match_learndash_tables_plugin = $this->match_learndash_tables_plugin($original_table);
631 +
632 + if (!empty($match_learndash_tables_plugin)) {
633 + $plugins = array_merge($plugins, $match_learndash_tables_plugin);
634 + }
635 + }
636 +
637 + if (!empty($plugins)) {
638 + return array_unique($plugins);
639 + }
640 +
537 641 return false;
538 642 }
539 643
540 644 /**
@@ -543,9 +647,10 @@
543 647 * @return string
544 648 */
545 649 private function get_plugin_json_file_path() {
546 650 $uploads_dir = wp_upload_dir(null, false);
547 - return apply_filters('wpo_get_plugin_json_file_path', trailingslashit($uploads_dir['basedir']).'wpo-plugins-tables-list.json');
651 + $filtered_path = apply_filters('wpo_get_plugin_json_file_path', trailingslashit($uploads_dir['basedir']).'wpo/wpo-plugins-tables-list.json');
652 + return is_string($filtered_path) ? $filtered_path : '';
548 653 }
549 654
550 655 /**
551 656 * Get all installed plugin slugs.
@@ -563,9 +668,9 @@
563 668
564 669 $plugins = get_plugins();
565 670
566 671 foreach ($plugins as $plugin_file => $plugin_data) {
567 - if ('' != $plugin_data['TextDomain']) {
672 + if ('' !== $plugin_data['TextDomain']) {
568 673 $installed_plugins[] = $plugin_data['TextDomain'];
569 674 } else {
570 675 $plugin_file_parts = explode('/', $plugin_file);
571 676 $installed_plugins[]= $plugin_file_parts[0];
@@ -586,9 +691,9 @@
586 691 if (!function_exists('get_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
587 692 $plugins = get_plugins();
588 693
589 694 // return true for wp-optimize without checking.
590 - if ('wp-optimize' == $plugin) {
695 + if ('wp-optimize' === $plugin) {
591 696 return array(
592 697 'installed' => true,
593 698 'active' => true,
594 699 );
@@ -598,11 +703,11 @@
598 703 $active = false;
599 704
600 705 foreach ($plugins as $plugin_file => $plugin_data) {
601 706 $plugin_file_parts = explode('/', $plugin_file);
602 - $plugin_slug = $plugin_file_parts[0];
707 + $plugin_slug = $plugin_file_parts[0] ?? '';
603 708
604 - if ($plugin == $plugin_slug) {
709 + if ($plugin === $plugin_slug) {
605 710 $installed = true;
606 711 $active = is_plugin_active($plugin_file);
607 712 }
608 713 }
@@ -625,13 +730,36 @@
625 730 $update_request = wp_remote_get('https://plugins.svn.wordpress.org/wp-optimize/trunk/plugin.json', array('timeout' => 3000));
626 731 if (200 !== wp_remote_retrieve_response_code($update_request)) return;
627 732 $json_content = wp_remote_retrieve_body($update_request);
628 733 if (json_decode($json_content)) {
629 - file_put_contents($this->get_plugin_json_file_path(), $json_content);
734 + // phpcs:disable
735 + // WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- WP_Filesystem not available this early
736 + // Generic.PHP.NoSilencedErrors.Discouraged -- suppress PHP warning in case of failure
737 + if (false === @file_put_contents($this->get_plugin_json_file_path(), $json_content)) {
738 + error_log("WP-Optimize: wpo-plugins-tables-list.json couldn't be updated");
739 + return;
740 + }
741 + // phpcs:enable
742 + $this->change_plugin_json_permissions();
630 743 }
631 744 }
632 745
633 746 /**
747 + * Set permissions to 640 for plugin.json
748 + *
749 + * @return void
750 + */
751 + public function change_plugin_json_permissions() {
752 + $plugin_json_file_path = $this->get_plugin_json_file_path();
753 + // phpcs:disable
754 + // Generic.PHP.NoSilencedErrors.Discouraged -- suppress PHP warning in case of failure
755 + if (is_file($plugin_json_file_path)) {
756 + @chmod($plugin_json_file_path, 0640);
757 + }
758 + // phpcs:enable
759 + }
760 +
761 + /**
634 762 * Cache all table rows count
635 763 */
636 764 public function wpo_update_record_count() {
637 765 global $wpdb;
@@ -636,9 +764,42 @@
636 764 public function wpo_update_record_count() {
637 765 global $wpdb;
638 766 $tables_info = $wpdb->get_results('SHOW TABLE STATUS');
639 767 foreach ($tables_info as $table) {
640 - $rows_count = $wpdb->get_var("SELECT COUNT(*) FROM `$table->Name`");
641 - set_transient($table->Name . '_count', $rows_count, 24*60*60);
768 + $rows_count = $wpdb->get_var("SELECT COUNT(*) FROM `" . esc_sql($table->Name) . "`");
769 + set_transient('wpo_' . $table->Name . '_count', $rows_count, 24*60*60);
642 770 }
771 + }
772 +
773 + /**
774 + * Check if the give table name belongs to a LearnDash plugin table and return the plugin slug.
775 + *
776 + * @param string $table_name The original table name with prefix to check if it belongs to LearnDash plugin.
777 + * @return array
778 + */
779 + private function match_learndash_tables_plugin($table_name) {
780 +
781 + $table_names = array(
782 + 'pro_quiz_category',
783 + 'pro_quiz_form',
784 + 'pro_quiz_lock',
785 + 'pro_quiz_prerequisite',
786 + 'pro_quiz_question',
787 + 'pro_quiz_statistic',
788 + 'pro_quiz_statistic_ref',
789 + 'pro_quiz_template',
790 + 'pro_quiz_toplist',
791 + );
792 +
793 + $learndash_slug = 'sfwd-lms';
794 +
795 + foreach ($table_names as $learndash_table) {
796 + $table_suffix = substr($table_name, -strlen($learndash_table));
797 +
798 + if ($table_suffix === $learndash_table) {
799 + return array($learndash_slug);
800 + }
801 + }
802 +
803 + return array();
643 804 }
644 805 }