Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement new experimental SQLite integration module #547

Merged
merged 129 commits into from
Dec 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
129 commits
Select commit Hold shift + click to select a range
5cd411a
Initial commit for SQLite integration
aristath Sep 29, 2022
02bde7e
CS & cleanup
aristath Oct 18, 2022
9cfa54e
fix activation & deactivation
aristath Oct 18, 2022
290d750
Improve description
aristath Oct 18, 2022
eb86c15
styling for the notice
aristath Oct 18, 2022
e070ede
Should be a string
aristath Oct 18, 2022
82eb030
Update modules/sqlite/integration/load.php
aristath Oct 25, 2022
f959a16
Change since x.x.x to n.e.x.t.
aristath Oct 25, 2022
5b47b71
Add return doc
aristath Oct 25, 2022
092ad1c
Move SQLite3 check to can-load.php
aristath Oct 25, 2022
93cea99
Rename module folder
aristath Oct 25, 2022
e126b35
forgot to rename these
aristath Oct 25, 2022
af7b7a6
make the option filtering more future-proof
aristath Oct 25, 2022
f246126
Another tweak for db.copy options filtering
aristath Oct 25, 2022
25fa3a0
Check if PERFLAB_VERSION is defined, and bail early
aristath Oct 25, 2022
42c2108
Prefix all classes as Perflab_SQLite_*
aristath Oct 25, 2022
7a048e8
prefix all functions with perflab_sqlite
aristath Oct 25, 2022
fe3d69f
Bring wp_install function up to date with Core.
aristath Oct 25, 2022
80bf847
Add inline doc to explain the difference between Core and this function
aristath Oct 25, 2022
862f266
Revert change for warning
aristath Oct 25, 2022
152cc95
Redirect on successful db.php file copy
aristath Oct 25, 2022
b362d00
some additional inline comments
aristath Oct 25, 2022
ef97c63
Fix warning in site-health screen
aristath Oct 25, 2022
746b2f5
simplify error reporting
aristath Oct 25, 2022
070c90d
reduce nesting by reversing the check
aristath Oct 25, 2022
d1f1220
Fix return type & value of command_tokenizer
aristath Oct 25, 2022
bc7b5b4
code-quality tweaks
aristath Oct 25, 2022
83af9e2
No reason to set $_wpdb to null, we don't use it as a global var
aristath Oct 25, 2022
bd368de
another fix for setting a $_wpdb var
aristath Oct 25, 2022
92546ff
more readability fixes
aristath Oct 25, 2022
92d816b
more tweaks
aristath Oct 25, 2022
e20cebb
fix logic error in error-reporting, from earlier commit
aristath Oct 25, 2022
6710cb8
Move constants to a separate file.
aristath Oct 26, 2022
b727bde
Add a "notice" header to modules
aristath Oct 26, 2022
b4192e0
load must-load.php files
aristath Nov 1, 2022
282f2c6
Move perflab_sqlite_module_deactivation to must-load.php
aristath Nov 1, 2022
17261de
refactor a bit how activation/deactivation are structured
aristath Nov 1, 2022
e55a315
Run on update_option instead of pre_update_option
aristath Nov 1, 2022
5696598
failed experiment
aristath Nov 1, 2022
61cfcb2
Improvements on the db.php file
aristath Nov 1, 2022
f79d9f0
Revert "failed experiment"
aristath Nov 1, 2022
1e242cf
move functions to load.php
aristath Nov 1, 2022
285348f
Additional inline docs
aristath Nov 1, 2022
5213e9f
implement activate.php & deactivate.php
aristath Nov 1, 2022
44f4c4d
fix some failing PHPUnit tests
aristath Nov 1, 2022
eacef52
Remove the perflab_sqlite_pdo_log_error function
aristath Nov 2, 2022
6604cab
improve errors reporting if PDO is missing
aristath Nov 2, 2022
f33b118
add some inline docs
aristath Nov 2, 2022
e828e3b
Improve the activation of the plugin & option after switching to sqlite
aristath Nov 2, 2022
7473497
Check if WP_CONTENT_DIR is writable before activating the module
aristath Nov 2, 2022
b5f5be4
separate enabled/disabled notices
aristath Nov 2, 2022
96e3613
fix rebase error
aristath Nov 8, 2022
059c880
Allow setting a message to be displayed if the module can't be loaded
aristath Nov 9, 2022
1218425
$table_query is immediately overridden
aristath Nov 9, 2022
12dd79d
typo
aristath Nov 9, 2022
e7694cb
fix return type
aristath Nov 9, 2022
44da73e
Revert "Allow setting a message to be displayed if the module can't b…
aristath Nov 9, 2022
56e82f2
Hardcode messages for the SQLite module
aristath Nov 14, 2022
5341c69
CS: remove void-return
aristath Nov 14, 2022
1649f07
require the site-health tweaks
aristath Nov 14, 2022
3316286
script no longer required
aristath Nov 14, 2022
187933d
fix hook for activation/deactivation
aristath Nov 14, 2022
d43828d
Run module activation actions when the option is added
aristath Nov 14, 2022
e0d55d0
Simplify query on deactivation
aristath Nov 14, 2022
82eb1c0
Update load.php
aristath Nov 15, 2022
7183106
Remove extension_loaded check
aristath Nov 15, 2022
4ff1e45
Hardcode enabled/disabled notices
aristath Nov 15, 2022
c5e808d
bugfix for activation/deactivation
aristath Nov 15, 2022
8e7d50c
remove unused variable
aristath Nov 15, 2022
c0d5f50
Update modules/database/sqlite/wp-includes/sqlite/db.php
aristath Nov 15, 2022
d6adc47
Update modules/database/sqlite/wp-includes/sqlite/class-perflab-sqlit…
aristath Nov 15, 2022
a17e8ad
Make activation/deactivation routines testable, and add phpunit tests
aristath Nov 15, 2022
8b7a1b2
typo
aristath Nov 15, 2022
44032b0
no reason to define a var here
aristath Nov 15, 2022
96de862
improve messages & escaping
aristath Nov 15, 2022
fadb42b
Add plugin header to the dropin file.
aristath Nov 24, 2022
4badb58
Merge branch 'trunk' into module/sqlite
aristath Nov 24, 2022
13d4abd
Update modules/database/sqlite/db.copy
aristath Nov 30, 2022
d9000d5
Update modules/database/sqlite/db.copy
aristath Nov 30, 2022
aa57a9c
simplify drop-in file headers
aristath Nov 30, 2022
243f108
Update modules/database/sqlite/activate.php
aristath Nov 30, 2022
ce60303
Implement a PERFLAB_SQLITE_DB_DROPIN_VERSION constant
aristath Nov 30, 2022
e9f276c
Fix checks for admin notices
aristath Nov 30, 2022
2455e67
Update modules/database/sqlite/wp-includes/sqlite/class-perflab-sqlit…
aristath Nov 30, 2022
c02f750
Update modules/database/sqlite/wp-includes/sqlite/class-perflab-sqlit…
aristath Nov 30, 2022
44009c1
CS fix
aristath Nov 30, 2022
46eb7b6
whitespace fixes
aristath Nov 30, 2022
23e364f
rename $t var to $time, and remove the useless $output var
aristath Nov 30, 2022
255e624
replace "or" with "||" in condition
aristath Nov 30, 2022
0bf3e3c
If SQLite DB does not exist, install WordPress in it right away with …
felixarntz Nov 30, 2022
6410eae
Merge branch 'module/sqlite' of github.com:WordPress/performance into…
felixarntz Nov 30, 2022
3cec69b
Enhance SQLite module activation to properly sync modules option.
felixarntz Nov 30, 2022
9f0e428
Simplify SQLite deactivation query logic and bring it more in line wi…
felixarntz Nov 30, 2022
0da9cc1
Add warning for multi-server environments
aristath Dec 1, 2022
e0cb993
Oops... wording
aristath Dec 1, 2022
0c390d6
use the PERFLAB_MODULES_SCREEN constant
aristath Dec 1, 2022
3dae29a
Update modules/database/sqlite/wp-includes/sqlite/class-perflab-sqlit…
aristath Dec 1, 2022
c36350f
Update modules/database/sqlite/wp-includes/sqlite/class-perflab-sqlit…
aristath Dec 5, 2022
bcf5bb6
Add missing return doc
aristath Dec 5, 2022
fa18bd7
remove duplicate $wpdb
aristath Dec 5, 2022
263371d
Update modules/database/sqlite/wp-includes/sqlite/class-perflab-sqlit…
aristath Dec 5, 2022
ed59cc9
Update modules/database/sqlite/wp-includes/sqlite/class-perflab-sqlit…
aristath Dec 5, 2022
3c9ca04
Update modules/database/sqlite/wp-includes/sqlite/class-perflab-sqlit…
aristath Dec 5, 2022
6ec5312
Update modules/database/sqlite/wp-includes/sqlite/class-perflab-sqlit…
aristath Dec 5, 2022
4824e31
Update modules/database/sqlite/wp-includes/sqlite/class-perflab-sqlit…
aristath Dec 5, 2022
fa5ad07
Update modules/database/sqlite/wp-includes/sqlite/class-perflab-sqlit…
aristath Dec 5, 2022
d0b7865
Remove empty line
aristath Dec 5, 2022
dd31a9b
Update admin/load.php
aristath Dec 5, 2022
96dea18
Tweak the 2nd notice class
aristath Dec 5, 2022
0989cdb
Update modules/database/sqlite/activate.php
aristath Dec 5, 2022
9502f28
Update modules/database/sqlite/activate.php
aristath Dec 5, 2022
1a5a2da
fix PHP notice
aristath Dec 5, 2022
85e59ab
Revert "remove duplicate $wpdb"
aristath Dec 5, 2022
accb7f8
fix admin notice
aristath Dec 7, 2022
c5d73a3
Update modules/database/sqlite/wp-includes/sqlite/db.php
aristath Dec 7, 2022
7458780
Update modules/database/sqlite/wp-includes/sqlite/db.php
aristath Dec 7, 2022
d019817
Update modules/database/sqlite/wp-includes/sqlite/db.php
aristath Dec 7, 2022
eb77632
address issues with site-health when db.php is missing
aristath Dec 7, 2022
77f294c
Update admin/load.php
aristath Dec 12, 2022
ef10d2f
Update modules/database/sqlite/load.php
aristath Dec 12, 2022
3ae41f9
Update modules/database/sqlite/load.php
aristath Dec 12, 2022
7a2647e
rename db.copy file
aristath Dec 12, 2022
8f698b9
Split install functions to separate file
aristath Dec 12, 2022
aafe8ea
Merge remote-tracking branch 'origin/module/sqlite' into module/sqlite
aristath Dec 12, 2022
fd3fb8d
move file
aristath Dec 12, 2022
d64c36c
Update modules/database/sqlite/activate.php
aristath Dec 12, 2022
2dcf03e
Merge remote-tracking branch 'origin/module/sqlite' into module/sqlite
aristath Dec 12, 2022
14fae02
Merge branch 'trunk' into module/sqlite
felixarntz Dec 12, 2022
2b2fad2
Move global wpdb adjustment back into db.php file.
felixarntz Dec 12, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions admin/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,17 +156,48 @@ function perflab_render_modules_page_field( $module_slug, $module_data, $module_
<input type="checkbox" id="<?php echo esc_attr( "{$base_id}_enabled" ); ?>" aria-describedby="<?php echo esc_attr( "{$base_id}_description" ); ?>" disabled>
<input type="hidden" name="<?php echo esc_attr( "{$base_name}[enabled]" ); ?>" value="<?php echo $enabled ? '1' : '0'; ?>">
<?php
if ( 'database/sqlite' === $module_slug && file_exists( WP_CONTENT_DIR . '/db.php' ) && ! defined( 'PERFLAB_SQLITE_DB_DROPIN_VERSION' ) ) {
printf(
/* translators: %s: db.php drop-in path */
esc_html__( 'The SQLite module cannot be activated because a different %s drop-in already exists.', 'performance-lab' ),
'<code>' . esc_html( basename( WP_CONTENT_DIR ) ) . '/db.php</code>'
);
} elseif ( 'database/sqlite' === $module_slug && ! wp_is_writable( WP_CONTENT_DIR ) ) {
printf(
/* translators: %s: db.php drop-in path */
esc_html__( 'The SQLite module cannot be activated because the %s directory is not writable.', 'performance-lab' ),
'<code>' . esc_html( basename( WP_CONTENT_DIR ) ) . '</code>'
);
} elseif ( 'database/sqlite' === $module_slug && ! class_exists( 'SQLite3' ) ) {
esc_html_e( 'The SQLite module cannot be activated because the SQLite extension is not loaded.', 'performance-lab' );
} else {
printf(
/* translators: %s: module name */
__( '%s is already part of your WordPress version and therefore cannot be loaded as part of the plugin.', 'performance-lab' ),
esc_html( $module_data['name'] )
);
}
?>
<?php } ?>
</label>
<p id="<?php echo esc_attr( "{$base_id}_description" ); ?>" class="description">
<?php echo esc_html( $module_data['description'] ); ?>
</p>
<?php if ( 'database/sqlite' === $module_slug ) : ?>
<?php if ( $enabled ) : ?>
<?php if ( defined( 'PERFLAB_SQLITE_DB_DROPIN_VERSION' ) ) : ?>
<?php // Don't use the WP notice classes here, as that makes them move to the top of the page. ?>
<p class="notice notice-warning" style="padding:1em;max-width:50em;">
<?php esc_html_e( 'Your site is currently using an SQLite database. You can disable this module to get back to your previous MySQL database, with all your previous data intact.', 'performance-lab' ); ?>
</p>
<?php endif; ?>
<?php else : ?>
<?php // Don't use the WP notice classes here, as that makes them move to the top of the page. ?>
<p class="notice notice-warning" style="padding:1em;max-width:50em;">
<?php esc_html_e( 'Enabling this module will switch to a separate database and install WordPress in it. You will need to reconfigure your site, and start with a fresh site. Disabling the module you will get back to your previous MySQL database, with all your previous data intact. Warning: Do not activate if your site is implemented in a multi-server environment.', 'performance-lab' ); ?>
</p>
<?php endif; ?>
<?php endif; ?>
</fieldset>
<?php
}
Expand Down
94 changes: 94 additions & 0 deletions load.php
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,97 @@ function perflab_load_active_and_valid_modules() {
if ( is_admin() ) {
require_once PERFLAB_PLUGIN_DIR_PATH . 'admin/load.php';
}

/**
* Trigger actions when a module gets activated or deactivated.
*
* @since n.e.x.t
*
* @param mixed $old_value Old value of the option.
* @param mixed $value New value of the option.
*/
function perflab_run_module_activation_deactivation( $old_value, $value ) {
aristath marked this conversation as resolved.
Show resolved Hide resolved
$old_value = (array) $old_value;
$value = (array) $value;

// Get the list of modules that were activated, and load the activate.php files if they exist.
if ( ! empty( $value ) ) {
foreach ( $value as $module => $module_settings ) {
if ( ! empty( $module_settings['enabled'] ) && ( empty( $old_value[ $module ] ) || empty( $old_value[ $module ]['enabled'] ) ) ) {
perflab_activate_module( PERFLAB_PLUGIN_DIR_PATH . 'modules/' . $module );
}
}
}

// Get the list of modules that were deactivated, and load the deactivate.php files if they exist.
if ( ! empty( $old_value ) ) {
foreach ( $old_value as $module => $module_settings ) {
if ( ! empty( $module_settings['enabled'] ) && ( empty( $value[ $module ] ) || empty( $value[ $module ]['enabled'] ) ) ) {
perflab_deactivate_module( PERFLAB_PLUGIN_DIR_PATH . 'modules/' . $module );
}
}
}

return $value;
}

/**
* Activate a module.
*
* Runs the activate.php file if it exists.
*
* @since n.e.x.t
*
* @param string $module_dir_path The module's directory path.
*/
function perflab_activate_module( $module_dir_path ) {
$module_activation_file = $module_dir_path . '/activate.php';
if ( ! file_exists( $module_activation_file ) ) {
return;
}
$module = require $module_activation_file;
if ( ! is_callable( $module ) ) {
return;
}
$module();
}

/**
* Deactivate a module.
*
* Runs the deactivate.php file if it exists.
*
* @since n.e.x.t
*
* @param string $module_dir_path The module's directory path.
*/
function perflab_deactivate_module( $module_dir_path ) {
$module_deactivation_file = $module_dir_path . '/deactivate.php';
if ( ! file_exists( $module_deactivation_file ) ) {
return;
}
$module = require $module_deactivation_file;
if ( ! is_callable( $module ) ) {
return;
}
$module();
}

// Run the module activation & deactivation actions when the option is updated.
add_action( 'update_option_' . PERFLAB_MODULES_SETTING, 'perflab_run_module_activation_deactivation', 10, 2 );

// Run the module activation & deactivation actions when the option is added.
add_action(
'add_option_' . PERFLAB_MODULES_SETTING,
/**
* Fires after the option has been added.
*
* @param string $option Name of the option to add.
* @param mixed $value Value of the option.
*/
function( $option, $value ) {
perflab_run_module_activation_deactivation( perflab_get_modules_setting_default(), $value );
},
10,
2
);
169 changes: 169 additions & 0 deletions modules/database/sqlite/activate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
<?php
/**
* Actions to run when the module gets activated.
*
* @since n.e.x.t
* @package performance-lab
*/

/**
* Copies the db.php file in wp-content and reloads the page.
*
* @since n.e.x.t
*/
return function() {
// Bail early if the SQLite3 class does not exist.
if ( ! class_exists( 'SQLite3' ) ) {
return;
}

$destination = WP_CONTENT_DIR . '/db.php';

// Place database drop-in if not present yet, except in case there is
// another database drop-in present already.
if ( ! defined( 'PERFLAB_SQLITE_DB_DROPIN_VERSION' ) && ! file_exists( $destination ) ) {
// Init the filesystem to allow copying the file.
global $wp_filesystem;
if ( ! $wp_filesystem ) {
require_once ABSPATH . '/wp-admin/includes/file.php';
WP_Filesystem();
}

// Copy the file, replacing contents as needed.
if ( $wp_filesystem->touch( $destination ) ) {

// Get the db.copy.php file contents, replace placeholders and write it to the destination.
$file_contents = str_replace(
'{SQLITE_IMPLEMENTATION_FOLDER_PATH}',
__DIR__,
file_get_contents( __DIR__ . '/db.copy.php' )
);

$wp_filesystem->put_contents( $destination, $file_contents );
}
}

// As an extra safety check, bail if the current user cannot update
// (or install) WordPress core.
if ( ! current_user_can( 'update_core' ) ) {
return;
}

// Otherwise install WordPress in the SQLite database before the redirect,
// so that the user does not end up on the WordPress installation screen
// but rather remains in the Performance Lab modules screen.
add_filter(
'wp_redirect',
function( $redirect_location ) {
if ( ! defined( 'DATABASE_TYPE' ) ) {
define( 'DATABASE_TYPE', 'sqlite' );
}
require_once __DIR__ . '/constants.php';

// If the SQLite DB already exists, simply ensure the module is
// active there.
if ( file_exists( FQDB ) ) {
require_once __DIR__ . '/wp-includes/sqlite/db.php';
wp_set_wpdb_vars();
global $wpdb;
$row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", PERFLAB_MODULES_SETTING ) );
if ( is_object( $row ) ) {
$value = maybe_unserialize( $row->option_value );
if ( is_array( $value ) && ( ! isset( $value['database/sqlite'] ) || ! $value['database/sqlite']['enabled'] ) ) {
$value['database/sqlite'] = array( 'enabled' => true );
$wpdb->update( $wpdb->options, array( 'option_value' => maybe_serialize( $value ) ), array( 'option_name' => PERFLAB_MODULES_SETTING ) );
}
}
return $redirect_location;
}

// Get current basic setup data to install WordPress in the new DB.
$blog_title = get_bloginfo( 'name' );
$is_public = (bool) get_option( 'blog_public' );
$language = get_option( 'WPLANG' );
$user_email = get_option( 'admin_email' );
$admin_user = get_user_by( 'email', $user_email );
if ( ! $admin_user ) {
$admin_user = wp_get_current_user();
}

// If the current user is not the admin email user, look up the
// data for the current user. Additionally, attempt to keep them
// logged-in by retaining their current session. Depending on the
// site configuration, this is not 100% reliable as sites may store
// session tokens outside of user meta. However that does not lead
// to any problem, the user would simply be required to sign in
// again.
$current_user = null;
$current_user_id = get_current_user_id();
if ( $current_user_id !== (int) $admin_user->ID ) {
$current_user = wp_get_current_user();
}
$user_sessions = get_user_meta( $current_user_id, 'session_tokens', true );

// Get current data to keep the Performance Lab plugin and relevant
// modules active in the new DB.
$active_plugins_option = array( plugin_basename( PERFLAB_MAIN_FILE ) );
$active_modules_option = get_option( PERFLAB_MODULES_SETTING, array() );

// Load and set up SQLite database.
require_once __DIR__ . '/wp-includes/sqlite/db.php';
wp_set_wpdb_vars();

// Load WordPress installation API functions.
require_once ABSPATH . 'wp-admin/includes/upgrade.php';

// Install WordPress in the SQLite database with the same base
// configuration as the MySQL database.
// Since $admin_user->user_pass is already hashed, add a filter to
// ensure it is inserted into the database like that, instead of
// being re-hashed.
$unhash_user_pass = function( $data, $update, $user_id, $userdata ) use ( $admin_user, $current_user ) {
// Double check this is actually the already hashed password,
// to prevent any chance of accidentally putting another
// password into the database which would then be plain text.
if (
! empty( $userdata['user_pass'] )
&& (
$userdata['user_pass'] === $admin_user->user_pass
|| $current_user && $userdata['user_pass'] === $current_user->user_pass
)
) {
$data['user_pass'] = $userdata['user_pass'];
}
return $data;
};
add_filter( 'wp_pre_insert_user_data', $unhash_user_pass, 10, 4 );
wp_install( $blog_title, $admin_user->user_login, $user_email, $is_public, '', $admin_user->user_pass, $language );
if ( $current_user ) { // Also "copy" current admin user if it's not the admin email owner.
wp_create_user( $current_user->user_login, $current_user->user_pass, $current_user->user_email );
}
remove_filter( 'wp_pre_insert_user_data', $unhash_user_pass );

// If user sessions are found, migrate them over so that the
// current user remains logged in.
if ( $user_sessions ) {
$session_user = get_user_by( 'login', $current_user ? $current_user->user_login : $admin_user->user_login );
if ( $session_user ) {
update_user_meta( $session_user->ID, 'session_tokens', $user_sessions );
}
}

// Activate the Performance Lab plugin and its modules.
// Use direct database query for Performance Lab modules to
// prevent module activation logic from firing again.
update_option( 'active_plugins', $active_plugins_option );
global $wpdb;
aristath marked this conversation as resolved.
Show resolved Hide resolved
$wpdb->insert(
$wpdb->options,
array(
'option_name' => PERFLAB_MODULES_SETTING,
'option_value' => maybe_serialize( $active_modules_option ),
'autoload' => 'yes',
)
);

return $redirect_location;
}
);
};
36 changes: 36 additions & 0 deletions modules/database/sqlite/can-load.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php
/**
* Can load function to determine if SQLite can be activated.
*
* @since n.e.x.t
* @package performance-lab
*/

/**
* Checks whether the given module can be activated.
*
* @since n.e.x.t
*/
return function() {

// If the PERFLAB_SQLITE_DB_DROPIN_VERSION constant is defined, then the module is already active.
if ( defined( 'PERFLAB_SQLITE_DB_DROPIN_VERSION' ) ) {
return true;
}

// If a db.php file already exists in the wp-content directory, then the module cannot be activated.
if ( file_exists( WP_CONTENT_DIR . '/db.php' ) ) {
return false;
}

// If the SQLite3 class does not exist, then the module cannot be activated.
if ( ! class_exists( 'SQLite3' ) ) {
return false;
}

// If the db.php file can't be written to the wp-content directory, then the module cannot be activated.
if ( ! wp_is_writable( WP_CONTENT_DIR ) ) {
return false;
}
return true;
};
Loading