PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / 6.2.1
MainWP Dashboard: Self-hosted WordPress Management for Agencies v6.2.1
6.2.2 6.2.1 6.2 6.1.8 6.1.7 6.1.6 6.1.5 6.1.4 6.1.3 6.1.2 6.1.1 6.1 6.0.12 6.0.11 4.6.0.1 5.0 5.0.1 5.0.2 5.0.3 5.0.3.1 5.0.3.2 5.1 5.1.1 5.2 5.2.1 All 155 releases
← All changes | class/class-mainwp-install.php +219 -32 6.1.6 → 6.2.1 View file →
@@ -30,9 +30,9 @@
30 30 * Private variable to hold the database version info.
31 31 *
32 32 * @var string DB version info.
33 33 */
34 - protected $mainwp_db_version = '9.0.2.3'; // NOSONAR - no IP. Bumped for MWP-1566 sibling-dir chmod migration (MWP-1558 follow-up). Original 9.0.2.0 bump for MWP-1557/1558.
34 + protected $mainwp_db_version = '9.0.2.5'; // NOSONAR - no IP. 9.0.2.4 drops the stray unique index on backup progress task_id. Bumped for MWP-1566 sibling-dir chmod migration (MWP-1558 follow-up). Original 9.0.2.0 bump for MWP-1557/1558.
35 35
36 36 /**
37 37 * Protected variable to hold the database option name.
38 38 *
@@ -40,8 +40,18 @@
40 40 */
41 41 protected $option_db_key = 'mainwp_db_version';
42 42
43 43 /**
44 + * Network-scoped like mainwp_db_version, so every blog on a multisite sees the pending repair.
45 + */
46 + const BACKUP_PROGRESS_INDEX_REPAIR_PENDING = 'mainwp_backup_progress_index_repair_pending';
47 +
48 + /**
49 + * Network-scoped like mainwp_db_version, so every blog on a multisite sees the pending repair.
50 + */
51 + const WP_GROUP_MISSING_PRIMARY_KEY_REPAIR_PENDING = 'mainwp_wp_group_missing_primary_key_repair_pending';
52 +
53 + /**
44 54 * Private static variable to hold the single instance of the class.
45 55 *
46 56 * @static
47 57 *
@@ -98,8 +108,14 @@
98 108 $currentVersion = false;
99 109 }
100 110
101 111 if ( $currentVersion === $this->mainwp_db_version ) {
112 + // The index repair keeps its own marker so a failed DROP is retried at
113 + // most hourly, without holding the DB version back and re-running every
114 + // older migration on each load.
115 + $this->maybe_retry_backup_progress_index_repair();
116 +
117 + $this->maybe_retry_repair_wp_group_primary_key();
102 118 return;
103 119 }
104 120
105 121 $this->pre_update_tables();
@@ -280,14 +296,12 @@
280 296 wp_group_id int(11) NOT NULL auto_increment,
281 297 wpid int(11) NOT NULL,
282 298 groupid int(11) NOT NULL,
283 299 KEY idx_wpid (wpid),
284 - KEY idx_groupid (groupid)';
285 - if ( empty( $currentVersion ) || version_compare( $currentVersion, '8.57', '<=' ) ) {
286 - $tbl .= ',
287 - PRIMARY KEY (wp_group_id) ';
288 - }
289 - $tbl .= ') ' . $charset_collate;
300 + KEY idx_groupid (groupid),
301 + PRIMARY KEY (wp_group_id)
302 + ) ' . $charset_collate;
303 +
290 304 $sql[] = $tbl;
291 305
292 306 $tbl = 'CREATE TABLE ' . $this->table_name( 'lookup_item_objects' ) . ' (
293 307 lookup_id bigint(20) unsigned NOT NULL auto_increment,
@@ -304,9 +318,9 @@
304 318 }
305 319 $tbl .= ') ' . $charset_collate . ';';
306 320 $sql[] = $tbl;
307 321
308 - $tbl = 'CREATE TABLE ' . $this->table_name( 'wp_backup_progress' ) . " (
322 + $tbl = 'CREATE TABLE ' . $this->table_name( 'wp_backup_progress' ) . " (
309 323 task_id int(11) NOT NULL,
310 324 wp_id int(11) NOT NULL,
311 325 dtsFetched int(11) NOT NULL DEFAULT 0,
312 326 fetchResult text NOT NULL DEFAULT '',
@@ -318,12 +332,8 @@
318 332 attempts int(11) NOT NULL DEFAULT 0,
319 333 last_error text NOT NULL DEFAULT '',
320 334 pid int(11) NOT NULL DEFAULT 0,
321 335 KEY idx_task_id (task_id)";
322 - if ( empty( $currentVersion ) || version_compare( $currentVersion, '8.53', '<=' ) ) {
323 - $tbl .= ',
324 - UNIQUE (task_id)';
325 - }
326 336 $tbl .= ') ' . $charset_collate;
327 337 $sql[] = $tbl;
328 338
329 339 $tbl = 'CREATE TABLE ' . $this->table_name( 'wp_backup' ) . ' (
@@ -493,12 +503,12 @@
493 503 $sslColumns = array(
494 504 'nossl',
495 505 'nosslkey',
496 506 );
497 - $wp_table = esc_sql( $this->table_name( 'wp' ) );
507 + $wp_table = esc_sql( $this->table_name( 'wp' ) );
498 508 foreach ( $sslColumns as $col ) {
499 509 $col = esc_sql( $col );
500 - // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter -- Column name escaped via esc_sql, table name escaped separately.
510 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Column name escaped via esc_sql, table name escaped separately.
501 511 $this->wpdb->query( "ALTER TABLE {$wp_table} DROP COLUMN {$col}" );
502 512 }
503 513 }
504 514
@@ -515,17 +525,17 @@
515 525 );
516 526
517 527 foreach ( $rankColumns as $rankColumn ) {
518 528 $rankColumn = esc_sql( $rankColumn );
519 - // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter -- Column name escaped via esc_sql, table name escaped separately.
529 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Column name escaped via esc_sql, table name escaped separately.
520 530 $this->wpdb->query( "ALTER TABLE {$wp_table} DROP COLUMN {$rankColumn}" );
521 531 }
522 532
523 - $syncColumns = array( 'uptodate' );
533 + $syncColumns = array( 'uptodate' );
524 534 $wp_sync_table = esc_sql( $this->table_name( 'wp_sync' ) );
525 535 foreach ( $syncColumns as $column ) {
526 536 $column = esc_sql( $column );
527 - // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter -- Column name escaped via esc_sql, table name escaped separately.
537 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Column name escaped via esc_sql, table name escaped separately.
528 538 $this->wpdb->query( "ALTER TABLE {$wp_sync_table} DROP COLUMN {$column}" );
529 539 }
530 540 }
531 541
@@ -533,16 +543,16 @@
533 543 if ( version_compare( $currentVersion, '8.35', '<' ) ) {
534 544 $delColumns = array( 'offline_checks' );
535 545 foreach ( $delColumns as $column ) {
536 546 $column = esc_sql( $column );
537 - // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter -- Column name escaped via esc_sql, table name escaped separately.
547 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Column name escaped via esc_sql, table name escaped separately.
538 548 $this->wpdb->query( "ALTER TABLE {$wp_table} DROP COLUMN {$column}" );
539 549 }
540 - $delColumns = array( 'heatMap' );
550 + $delColumns = array( 'heatMap' );
541 551 $users_table = esc_sql( $this->table_name( 'users' ) );
542 552 foreach ( $delColumns as $column ) {
543 553 $column = esc_sql( $column );
544 - // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter -- Column name escaped via esc_sql, table name escaped separately.
554 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Column name escaped via esc_sql, table name escaped separately.
545 555 $this->wpdb->query( "ALTER TABLE {$users_table} DROP COLUMN {$column}" );
546 556 }
547 557 }
548 558
@@ -550,9 +560,9 @@
550 560 if ( version_compare( $currentVersion, '8.42', '<' ) ) {
551 561 $delColumns = array( 'offlineChecksOnlineNotification' );
552 562 foreach ( $delColumns as $column ) {
553 563 $column = esc_sql( $column );
554 - // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter -- Column name escaped via esc_sql, table name escaped separately.
564 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Column name escaped via esc_sql, table name escaped separately.
555 565 $this->wpdb->query( "ALTER TABLE {$users_table} DROP COLUMN {$column}" );
556 566 }
557 567 }
558 568
@@ -557,20 +567,29 @@
557 567 }
558 568
559 569 // fix missing PRIMARY keys.
560 570 if ( version_compare( $currentVersion, '8.53', '<=' ) ) {
561 - $wp_options_table = esc_sql( $this->table_name( 'wp_options' ) );
571 + $wp_options_table = esc_sql( $this->table_name( 'wp_options' ) );
562 572 $wp_settings_backup_table = esc_sql( $this->table_name( 'wp_settings_backup' ) );
563 - // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name escaped via esc_sql.
573 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name escaped via esc_sql.
564 574 $this->wpdb->query( "ALTER TABLE {$wp_options_table} ADD opt_id int NOT NULL AUTO_INCREMENT PRIMARY KEY" );
565 - // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name escaped via esc_sql.
575 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name escaped via esc_sql.
566 576 $this->wpdb->query( "ALTER TABLE {$wp_settings_backup_table} ADD set_id int NOT NULL AUTO_INCREMENT PRIMARY KEY" );
567 - // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name escaped via esc_sql.
577 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name escaped via esc_sql.
568 578 $this->wpdb->query( "ALTER TABLE {$wp_sync_table} ADD sync_id int NOT NULL AUTO_INCREMENT PRIMARY KEY" );
569 579 }
570 580
571 581 $this->update_optimize_indexes_55( $currentVersion );
572 582
583 + // dbDelta never drops an index, so the stray unique key needs an explicit migration.
584 + if ( version_compare( $currentVersion, '9.0.2.4', '<' ) ) { // NOSONAR - no ip.
585 + $this->repair_backup_progress_index();
586 + }
587 +
588 + if ( ! empty( $currentVersion ) && version_compare( $currentVersion, '9.0.2.5', '<' ) ) { // NOSONAR - no ip.
589 + $this->repair_wp_group_primary_key();
590 + }
591 +
573 592 $this->wpdb->suppress_errors( $suppress );
574 593 MainWP_DB_Client::instance()->check_to_updates_reports_data_861( $currentVersion );
575 594 }
576 595
@@ -621,8 +640,176 @@
621 640 }
622 641 }
623 642
624 643 /**
644 + * Retry a pending backup progress index repair, no more than once an hour.
645 + *
646 + * A DB user without ALTER never clears the marker, so an unthrottled retry
647 + * would run two SHOW INDEX plus a failing ALTER on every single request.
648 + *
649 + * @return bool True when a repair attempt was made.
650 + */
651 + public function maybe_retry_repair_wp_group_primary_key() {
652 + $pending = (int) get_site_option( self::WP_GROUP_MISSING_PRIMARY_KEY_REPAIR_PENDING );
653 + if ( empty( $pending ) || time() - $pending < HOUR_IN_SECONDS ) {
654 + return false;
655 + }
656 +
657 + $suppress = $this->wpdb->suppress_errors();
658 + $this->repair_wp_group_primary_key();
659 + $this->wpdb->suppress_errors( $suppress );
660 +
661 + return true;
662 + }
663 +
664 + /**
665 + * Repair the wp_group table primary key for legacy installations.
666 + *
667 + * To fix MWP-1794.
668 + *
669 + * @return void
670 + */
671 + private function repair_wp_group_primary_key() {
672 + $wp_group_table = esc_sql( $this->table_name( 'wp_group' ) );
673 +
674 + $column_exists = $this->wpdb->get_var(
675 + "SHOW COLUMNS FROM {$wp_group_table} LIKE 'wp_group_id'" // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Table name is escaped and query contains no user input.
676 + );
677 +
678 + if ( empty( $column_exists ) ) {
679 + $this->wpdb->query(
680 + "ALTER TABLE {$wp_group_table}
681 + ADD COLUMN wp_group_id int(11) NOT NULL auto_increment PRIMARY KEY FIRST" // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Table name is escaped and query contains no user input.
682 + );
683 + } else {
684 + $primary_key = $this->wpdb->get_var(
685 + "SHOW INDEX FROM {$wp_group_table}
686 + WHERE Key_name = 'PRIMARY'
687 + AND Column_name = 'wp_group_id'" // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Table name is escaped and query contains no user input.
688 + );
689 +
690 + if ( empty( $primary_key ) ) {
691 + $this->wpdb->query(
692 + "ALTER TABLE {$wp_group_table}
693 + ADD PRIMARY KEY (wp_group_id)" // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Table name is escaped and query contains no user input.
694 + );
695 + }
696 + }
697 +
698 + $primary_key = $this->wpdb->get_var(
699 + "SHOW INDEX FROM {$wp_group_table}
700 + WHERE Key_name = 'PRIMARY'
701 + AND Column_name = 'wp_group_id'" // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Table name is escaped and query contains no user input.
702 + );
703 +
704 + if ( ! empty( $primary_key ) ) {
705 + delete_site_option( self::WP_GROUP_MISSING_PRIMARY_KEY_REPAIR_PENDING );
706 + } else {
707 + // A timestamp, not a formatted date: the retry throttle compares it against time().
708 + update_site_option( self::WP_GROUP_MISSING_PRIMARY_KEY_REPAIR_PENDING, time() );
709 + }
710 + }
711 +
712 + /**
713 + * Retry a pending backup progress index repair, no more than once an hour.
714 + *
715 + * A DB user without ALTER never clears the marker, so an unthrottled retry
716 + * would run two SHOW INDEX plus a failing ALTER on every single request.
717 + *
718 + * @return bool True when a repair attempt was made.
719 + */
720 + public function maybe_retry_backup_progress_index_repair() {
721 + $pending = (int) get_site_option( self::BACKUP_PROGRESS_INDEX_REPAIR_PENDING );
722 + if ( empty( $pending ) || time() - $pending < HOUR_IN_SECONDS ) {
723 + return false;
724 + }
725 +
726 + $this->repair_backup_progress_index();
727 +
728 + return true;
729 + }
730 +
731 + /**
732 + * Run the backup progress index repair and remember whether it still needs a retry.
733 + *
734 + * @return bool True when the repair is confirmed complete.
735 + */
736 + public function repair_backup_progress_index() {
737 + // The retry from install() runs outside post_update()'s suppression; a
738 + // persistently failing ALTER must not log or print on every request.
739 + $suppress = $this->wpdb->suppress_errors();
740 + $repaired = $this->drop_backup_progress_unique_index();
741 + $this->wpdb->suppress_errors( $suppress );
742 + if ( $repaired ) {
743 + delete_site_option( self::BACKUP_PROGRESS_INDEX_REPAIR_PENDING );
744 + } else {
745 + // A timestamp, not a formatted date: the retry throttle compares it against time().
746 + update_site_option( self::BACKUP_PROGRESS_INDEX_REPAIR_PENDING, time() );
747 + }
748 + return $repaired;
749 + }
750 +
751 + /**
752 + * Drop a stray unique index on the backup progress task_id column.
753 + *
754 + * Fresh installs made between DB 8.53 and the schema fix created
755 + * wp_backup_progress with UNIQUE (task_id). Progress rows are per task and
756 + * per site, so a task covering two or more sites could never insert its
757 + * second row. dbDelta never drops an index, so the stray key has to go here.
758 + *
759 + * @return bool True when no such key remains, false when one survived a failed DROP.
760 + */
761 + public function drop_backup_progress_unique_index() {
762 + $table = $this->table_name( 'wp_backup_progress' );
763 + $keys = $this->find_backup_progress_task_id_unique_keys();
764 + if ( null === $keys ) {
765 + return false;
766 + }
767 +
768 + foreach ( $keys as $key_name ) {
769 + $this->wpdb->query( "ALTER TABLE {$table} DROP INDEX `{$key_name}`" ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- DDL statement; table name is a hardcoded internal identifier, key name comes from SHOW INDEX and is allowlisted below.
770 + }
771 +
772 + // suppress_errors() hides a failed DROP, so the table is the only source of truth.
773 + return array() === $this->find_backup_progress_task_id_unique_keys();
774 + }
775 +
776 + /**
777 + * Names of the unique keys on the backup progress table that cover task_id alone.
778 + *
779 + * A composite unique key over task_id and wp_id is legitimate and is left out.
780 + *
781 + * @return array|null Key names, or null when the lookup itself failed and nothing can be concluded.
782 + */
783 + protected function find_backup_progress_task_id_unique_keys() {
784 + $table = $this->table_name( 'wp_backup_progress' );
785 +
786 + // suppress_errors() is on in post_update(), so a failed SHOW INDEX looks like an empty index list; last_error is the only tell.
787 + $this->wpdb->last_error = '';
788 + $indexes = $this->wpdb->get_results( "SHOW INDEX FROM {$table} WHERE Non_unique = 0", ARRAY_A ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- DDL introspection; table name is a hardcoded internal identifier, no user input involved.
789 + if ( '' !== $this->wpdb->last_error ) {
790 + return null;
791 + }
792 +
793 + $key_columns = array();
794 + foreach ( (array) $indexes as $index ) {
795 + if ( 'PRIMARY' === $index['Key_name'] ) {
796 + continue;
797 + }
798 + $key_columns[ $index['Key_name'] ][] = $index['Column_name'];
799 + }
800 +
801 + $keys = array();
802 + foreach ( $key_columns as $key_name => $columns ) {
803 + if ( array( 'task_id' ) === $columns && preg_match( '/^[A-Za-z0-9_]+$/', $key_name ) ) {
804 + $keys[] = $key_name;
805 + }
806 + }
807 +
808 + return $keys;
809 + }
810 +
811 + /**
625 812 * Method pre_update_tables()
626 813 *
627 814 * Handle pre update tables.
628 815 *
@@ -639,9 +826,9 @@
639 826 $suppress = $this->wpdb->suppress_errors();
640 827
641 828 if ( version_compare( $currentVersion, '8.98', '<=' ) ) {
642 829 $wp_table = esc_sql( $this->table_name( 'wp' ) );
643 - $existing_columns = $this->wpdb->get_col( "SHOW COLUMNS FROM {$wp_table}", 0 ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- DDL introspection; table name is a hardcoded internal identifier escaped via esc_sql(), no user input involved.
830 + $existing_columns = $this->wpdb->get_col( "SHOW COLUMNS FROM {$wp_table}", 0 ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- DDL introspection; table name is a hardcoded internal identifier escaped via esc_sql(), no user input involved.
644 831 foreach ( array( 'backups', 'note_lastupdate', 'pages' ) as $column ) {
645 832 if ( in_array( $column, $existing_columns, true ) ) {
646 833 $this->wpdb->query( 'ALTER TABLE ' . $wp_table . ' DROP COLUMN ' . esc_sql( $column ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- DDL statement; table and column names are hardcoded internal identifiers escaped via esc_sql(), no user input involved.
647 834 }
@@ -676,13 +863,13 @@
676 863 'dtsSyncStart',
677 864 'dtsAutomaticSync',
678 865 'dtsAutomaticSyncStart',
679 866 );
680 - $wp_table = esc_sql( $this->table_name( 'wp' ) );
867 + $wp_table = esc_sql( $this->table_name( 'wp' ) );
681 868 $wp_sync_table = esc_sql( $this->table_name( 'wp_sync' ) );
682 869 foreach ( $wpSyncColumns as $wpSyncColumn ) {
683 870 $wpSyncColumn = esc_sql( $wpSyncColumn );
684 - // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter -- Column name escaped via esc_sql, table name escaped separately.
871 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Column name escaped via esc_sql, table name escaped separately.
685 872 $rslts = $this->wpdb->get_results( "SELECT id,{$wpSyncColumn} FROM {$wp_table}", ARRAY_A );
686 873 if ( empty( $rslts ) ) {
687 874 continue;
688 875 }
@@ -687,9 +874,9 @@
687 874 continue;
688 875 }
689 876
690 877 foreach ( $rslts as $rslt ) {
691 - // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name escaped via esc_sql and query uses proper prepare.
878 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name escaped via esc_sql and query uses proper prepare.
692 879 $exists = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT wpid FROM {$wp_sync_table} WHERE wpid = %d", $rslt['id'] ), ARRAY_A );
693 880 if ( empty( $exists ) ) {
694 881 $this->wpdb->insert(
695 882 $this->table_name( 'wp_sync' ),
@@ -703,9 +890,9 @@
703 890 }
704 891 }
705 892
706 893 $suppress = $this->wpdb->suppress_errors();
707 - // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter -- Column name escaped via esc_sql, table name escaped separately.
894 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Column name escaped via esc_sql, table name escaped separately.
708 895 $this->wpdb->query( "ALTER TABLE {$wp_table} DROP COLUMN {$wpSyncColumn}" );
709 896 $this->wpdb->suppress_errors( $suppress );
710 897 }
711 898
@@ -719,9 +906,9 @@
719 906 'recent_pages',
720 907 );
721 908 foreach ( $optionColumns as $optionColumn ) {
722 909 $optionColumn = esc_sql( $optionColumn );
723 - // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter -- Column name escaped via esc_sql, table name escaped separately.
910 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Column name escaped via esc_sql, table name escaped separately.
724 911 $rslts = $this->wpdb->get_results( "SELECT id,{$optionColumn} FROM {$wp_table}", ARRAY_A );
725 912 if ( empty( $rslts ) ) {
726 913 continue;
727 914 }
@@ -730,9 +917,9 @@
730 917 static::update_website_option( (object) $rslt, $optionColumn, $rslt[ $optionColumn ] );
731 918 }
732 919
733 920 $suppress = $this->wpdb->suppress_errors();
734 - // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter -- Column name escaped via esc_sql, table name escaped separately.
921 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Column name escaped via esc_sql, table name escaped separately.
735 922 $this->wpdb->query( "ALTER TABLE {$wp_table} DROP COLUMN {$optionColumn}" );
736 923 $this->wpdb->suppress_errors( $suppress );
737 924 }
738 925 }