Merge pull request #26454 from woocommerce/enhancement/verify-db
Add `verify_base_db` method to check if all base tables are present.
This commit is contained in:
commit
6564847802
|
@ -40,6 +40,7 @@ class WC_Admin_Notices {
|
|||
'maxmind_license_key' => 'maxmind_missing_license_key_notice',
|
||||
'redirect_download_method' => 'redirect_download_method_notice',
|
||||
'uploads_directory_is_unprotected' => 'uploads_directory_is_unprotected_notice',
|
||||
'base_tables_missing' => 'base_tables_missing_notice',
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -506,6 +507,21 @@ class WC_Admin_Notices {
|
|||
include dirname( __FILE__ ) . '/views/html-notice-uploads-directory-is-unprotected.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Notice about base tables missing.
|
||||
*/
|
||||
public static function base_tables_missing_notice() {
|
||||
$notice_dismissed = apply_filters(
|
||||
'woocommerce_hide_base_tables_missing_nag',
|
||||
get_user_meta( get_current_user_id(), 'dismissed_base_tables_missing_notice', true )
|
||||
);
|
||||
if ( $notice_dismissed ) {
|
||||
self::remove_notice( 'base_tables_missing' );
|
||||
}
|
||||
|
||||
include dirname( __FILE__ ) . '/views/html-notice-base-table-missing.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the store is running SSL.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* Admin View: Notice - Base table missing.
|
||||
*
|
||||
* @package WooCommerce\Admin
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
?>
|
||||
<div class="updated woocommerce-message">
|
||||
<a class="woocommerce-message-close notice-dismiss" href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'wc-hide-notice', 'base_tables_missing' ), 'woocommerce_hide_notices_nonce', '_wc_notice_nonce' ) ); ?>">
|
||||
<?php esc_html_e( 'Dismiss', 'woocommerce' ); ?>
|
||||
</a>
|
||||
|
||||
<p>
|
||||
<strong><?php esc_html_e( 'Database tables missing', 'woocommerce' ); ?></strong>
|
||||
</p>
|
||||
<p>
|
||||
<?php
|
||||
$verify_db_tool_available = array_key_exists( 'verify_db_tables', WC_Admin_Status::get_tools() );
|
||||
$missing_tables = get_option( 'woocommerce_schema_missing_tables' );
|
||||
if ( $verify_db_tool_available ) {
|
||||
echo wp_kses_post(
|
||||
sprintf(
|
||||
/* translators: %1%s: Missing tables (seperated by ",") %2$s: Link to check again */
|
||||
__( 'One or more tables required for WooCommerce to function are missing, some features may not work as expected. Missing tables: %1$s. <a href="%2$s">Check again.</a>', 'woocommerce' ),
|
||||
esc_html( implode( ', ', $missing_tables ) ),
|
||||
wp_nonce_url( admin_url( 'admin.php?page=wc-status&tab=tools&action=verify_db_tables' ), 'debug_action' )
|
||||
)
|
||||
);
|
||||
} else {
|
||||
echo wp_kses_post(
|
||||
sprintf(
|
||||
/* translators: %1%s: Missing tables (seperated by ",") */
|
||||
__( 'One or more tables required for WooCommerce to function are missing, some features may not work as expected. Missing tables: %1$s.', 'woocommerce' ),
|
||||
esc_html( implode( ', ', $missing_tables ) )
|
||||
)
|
||||
);
|
||||
}
|
||||
?>
|
||||
</p>
|
||||
</div>
|
|
@ -287,6 +287,7 @@ class WC_Install {
|
|||
WC()->wpdb_table_fix();
|
||||
self::remove_admin_notices();
|
||||
self::create_tables();
|
||||
self::verify_base_tables();
|
||||
self::create_options();
|
||||
self::create_roles();
|
||||
self::setup_environment();
|
||||
|
@ -303,6 +304,43 @@ class WC_Install {
|
|||
do_action( 'woocommerce_installed' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if all the base tables are present.
|
||||
*
|
||||
* @param bool $modify_notice Whether to modify notice based on if all tables are present.
|
||||
* @param bool $execute Whether to execute get_schema queries as well.
|
||||
*
|
||||
* @return array List of querues.
|
||||
*/
|
||||
public static function verify_base_tables( $modify_notice = true, $execute = false ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
|
||||
|
||||
if ( $execute ) {
|
||||
self::create_tables();
|
||||
}
|
||||
$queries = dbDelta( self::get_schema(), false );
|
||||
$missing_tables = array();
|
||||
foreach ( $queries as $table_name => $result ) {
|
||||
if ( "Created table $table_name" === $result ) {
|
||||
$missing_tables[] = $table_name;
|
||||
}
|
||||
}
|
||||
|
||||
if ( 0 < count( $missing_tables ) ) {
|
||||
if ( $modify_notice ) {
|
||||
WC_Admin_Notices::add_notice( 'base_tables_missing' );
|
||||
}
|
||||
update_option( 'woocommerce_schema_missing_tables', $missing_tables );
|
||||
} else {
|
||||
if ( $modify_notice ) {
|
||||
WC_Admin_Notices::remove_notice( 'base_tables_missing' );
|
||||
}
|
||||
update_option( 'woocommerce_schema_version', WC()->db_version );
|
||||
delete_option( 'woocommerce_schema_missing_tables' );
|
||||
}
|
||||
return $missing_tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset any notices added to admin.
|
||||
*
|
||||
|
@ -621,6 +659,11 @@ class WC_Install {
|
|||
|
||||
/**
|
||||
* Set up the database tables which the plugin needs to function.
|
||||
* WARNING: If you are modifying this method, make sure that its safe to call regardless of the state of database.
|
||||
*
|
||||
* This is called from `install` method and is executed in-sync when WC is installed or updated. This can also be called optionally from `verify_base_tables`.
|
||||
*
|
||||
* TODO: Add all crucial tables that we have created from workers in the past.
|
||||
*
|
||||
* Tables:
|
||||
* woocommerce_attribute_taxonomies - Table for storing attribute taxonomies - these are user defined
|
||||
|
|
|
@ -22,6 +22,15 @@ final class WooCommerce {
|
|||
*/
|
||||
public $version = '4.3.0';
|
||||
|
||||
/**
|
||||
* WooCommerce Schema version.
|
||||
*
|
||||
* @since 4.3 started with version string 430.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $db_version = '430';
|
||||
|
||||
/**
|
||||
* The single instance of the class.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
/**
|
||||
* Class WCInstallTest file.
|
||||
*
|
||||
* @package WooCommerce|Tests|WCInstallTest.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce;
|
||||
|
||||
/**
|
||||
* Class WC_Tests_WC_Helper.
|
||||
*/
|
||||
class WCInstallTest extends \WC_Unit_Test_Case {
|
||||
|
||||
/**
|
||||
* Test if verify base table can detect missing table and adds/remove a notice.
|
||||
*/
|
||||
public function test_verify_base_tables_adds_and_remove_notice() {
|
||||
global $wpdb;
|
||||
|
||||
// Remove drop filter because we do want to drop temp table if it exists.
|
||||
// This filter was added to only allow dropping temporary tables which will then be rollbacked after the test.
|
||||
remove_filter( 'query', array( $this, '_drop_temporary_tables' ) );
|
||||
|
||||
$original_table_name = "{$wpdb->prefix}wc_tax_rate_classes";
|
||||
$changed_table_name = "{$wpdb->prefix}wc_tax_rate_classes_2";
|
||||
$clear_query = 'DROP TABLE IF EXISTS %s;';
|
||||
$rename_table_query = 'RENAME TABLE %s to %s;';
|
||||
|
||||
// Workaround to call a private function.
|
||||
$schema = function () {
|
||||
return static::get_schema();
|
||||
};
|
||||
|
||||
// Rename a base table to simulate it as non-existing.
|
||||
dbDelta( $schema->call( new \WC_Install() ) ); // Restore correct state.
|
||||
$wpdb->query( sprintf( $clear_query, $changed_table_name ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||
$wpdb->query( sprintf( $rename_table_query, $original_table_name, $changed_table_name ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||
|
||||
$missing_tables = \WC_Install::verify_base_tables();
|
||||
|
||||
$wpdb->query( sprintf( $rename_table_query, $changed_table_name, $original_table_name ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||
add_filter( 'query', array( $this, '_drop_temporary_tables' ) );
|
||||
|
||||
$this->assertContains( $original_table_name, $missing_tables );
|
||||
$this->assertContains( 'base_tables_missing', \WC_Admin_Notices::get_notices() );
|
||||
|
||||
// Ideally, no missing table anymore because we have switched back table name.
|
||||
$missing_tables = \WC_Install::verify_base_tables();
|
||||
|
||||
$this->assertNotContains( $original_table_name, $missing_tables );
|
||||
$this->assertNotContains( 'base_tables_missing', \WC_Admin_Notices::get_notices() );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test if verify base table can fix the table as well.
|
||||
*/
|
||||
public function test_verify_base_tables_fix_tables() {
|
||||
global $wpdb;
|
||||
|
||||
// Remove drop filter because we do want to drop temp table if it exists.
|
||||
// This filter was added to only allow dropping temporary tables which will then be rollbacked after the test.
|
||||
remove_filter( 'query', array( $this, '_drop_temporary_tables' ) );
|
||||
|
||||
$original_table_name = "{$wpdb->prefix}wc_tax_rate_classes";
|
||||
$changed_table_name = "{$wpdb->prefix}wc_tax_rate_classes_2";
|
||||
$clear_query = 'DROP TABLE IF EXISTS %s;';
|
||||
$rename_table_query = 'RENAME TABLE %s to %s;';
|
||||
|
||||
// Workaround to call a private function.
|
||||
$schema = function () {
|
||||
return static::get_schema();
|
||||
};
|
||||
|
||||
// Rename a base table to simulate it as non-existing.
|
||||
dbDelta( $schema->call( new \WC_Install() ) ); // Restore correct state.
|
||||
$wpdb->query( sprintf( $clear_query, $changed_table_name ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||
$wpdb->query( sprintf( $rename_table_query, $original_table_name, $changed_table_name ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||
|
||||
$missing_tables = \WC_Install::verify_base_tables( true, true );
|
||||
|
||||
$wpdb->query( sprintf( $clear_query, $original_table_name ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||
$wpdb->query( sprintf( $rename_table_query, $changed_table_name, $original_table_name ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||
add_filter( 'query', array( $this, '_drop_temporary_tables' ) );
|
||||
|
||||
// Ideally, no missing table because verify base tables created the table as well.
|
||||
$this->assertNotContains( $original_table_name, $missing_tables );
|
||||
$this->assertNotContains( 'base_tables_missing', \WC_Admin_Notices::get_notices() );
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue