PostgreSQL-For-Wordpress / postgresql-for-wordpress

A maintained fork of https://wordpress.org/plugins/postgresql-for-wordpress/
GNU General Public License v2.0
220 stars 71 forks source link

Make this work like a normal WP plugin #32

Open mattbucci opened 10 months ago

mattbucci commented 10 months ago

Because this plugin has to start so early in the app lifecycle it requires that we copy db.php to wp-content but this process is weird and cumbersome.

It would be great if this plugin could somehow act like a standard WordPress plugin which can be installed and activated

mattbucci commented 10 months ago

https://wordpress.org/plugins/sqlite-database-integration/ can be used as reference.

The basic idea is that on activation we should copy the file db.php

Here's their code for reference

<?php
/**
 * Handle the SQLite activation.
 *
 * @since 1.0.0
 * @package wp-sqlite-integration
 */

/**
 * Redirect to the plugin's admin screen on activation.
 *
 * @since 1.0.0
 *
 * @param string $plugin The plugin basename.
 */
function sqlite_plugin_activation_redirect( $plugin ) {
    if ( plugin_basename( SQLITE_MAIN_FILE ) === $plugin ) {
        wp_redirect( admin_url( 'options-general.php?page=sqlite-integration' ) );
        exit;
    }
}
add_action( 'activated_plugin', 'sqlite_plugin_activation_redirect' );

/**
 * Check the URL to ensure we're on the plugin page,
 * the user has clicked the button to install SQLite,
 * and the nonce is valid.
 * If the above conditions are met, run the sqlite_plugin_copy_db_file() function,
 * and redirect to the install screen.
 *
 * @since 1.0.0
 */
function sqlite_activation() {
    global $current_screen;
    if ( isset( $current_screen->base ) && 'settings_page_sqlite-integration' === $current_screen->base ) {
        return;
    }
    if ( isset( $_GET['confirm-install'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'sqlite-install' ) ) {

        // Handle upgrading from the performance-lab plugin.
        if ( isset( $_GET['upgrade-from-pl'] ) ) {
            global $wp_filesystem;
            require_once ABSPATH . '/wp-admin/includes/file.php';
            // Delete the previous db.php file.
            $wp_filesystem->delete( WP_CONTENT_DIR . '/db.php' );
            // Deactivate the performance-lab SQLite module.
            $pl_option_name = defined( 'PERFLAB_MODULES_SETTING' ) ? PERFLAB_MODULES_SETTING : 'perflab_modules_settings';
            $pl_option      = get_option( $pl_option_name, array() );
            unset( $pl_option['database/sqlite'] );
            update_option( $pl_option_name, $pl_option );
        }
        sqlite_plugin_copy_db_file();
        // WordPress will automatically redirect to the install screen here.
        wp_redirect( admin_url() );
        exit;
    }
}
add_action( 'admin_init', 'sqlite_activation' );

// Flush the cache at the last moment before the redirect.
add_filter(
    'x_redirect_by',
    function ( $result ) {
        wp_cache_flush();
        return $result;
    },
    PHP_INT_MAX,
    1
);

/**
 * Add the db.php file in wp-content.
 *
 * When the plugin gets merged in wp-core, this is not to be ported.
 */
function sqlite_plugin_copy_db_file() {
    // 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( 'SQLITE_DB_DROPIN_VERSION' ) && ! file_exists( $destination ) ) {
        // Init the filesystem to allow copying the file.
        global $wp_filesystem;

        require_once ABSPATH . '/wp-admin/includes/file.php';

        // Init the filesystem if needed, then copy the file, replacing contents as needed.
        if ( ( $wp_filesystem || WP_Filesystem() ) && $wp_filesystem->touch( $destination ) ) {

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

            $wp_filesystem->put_contents( $destination, $file_contents );
        }
    }
}
mattbucci commented 10 months ago

Here's what the deactivate code looks like

<?php
/**
 * Handle the SQLite deactivation.
 *
 * @since 1.0.0
 * @package wp-sqlite-integration
 */

/**
 * Delete the db.php file in wp-content.
 *
 * When the plugin gets merged in wp-core, this is not to be ported.
 */
function sqlite_plugin_remove_db_file() {
    if ( ! defined( 'SQLITE_DB_DROPIN_VERSION' ) || ! file_exists( WP_CONTENT_DIR . '/db.php' ) ) {
        return;
    }

    global $wp_filesystem;

    require_once ABSPATH . '/wp-admin/includes/file.php';

    // Init the filesystem if needed, then delete custom drop-in.
    if ( $wp_filesystem || WP_Filesystem() ) {
        // Flush any persistent cache.
        wp_cache_flush();
        // Delete the drop-in.
        $wp_filesystem->delete( WP_CONTENT_DIR . '/db.php' );
        // Flush the cache again to mitigate a possible race condition.
        wp_cache_flush();
    }

    // Run an action on `shutdown`, to deactivate the option in the MySQL database.
    add_action(
        'shutdown',
        function() {
            global $table_prefix;

            // Get credentials for the MySQL database.
            $dbuser     = defined( 'DB_USER' ) ? DB_USER : '';
            $dbpassword = defined( 'DB_PASSWORD' ) ? DB_PASSWORD : '';
            $dbname     = defined( 'DB_NAME' ) ? DB_NAME : '';
            $dbhost     = defined( 'DB_HOST' ) ? DB_HOST : '';

            // Init a connection to the MySQL database.
            $wpdb_mysql = new wpdb( $dbuser, $dbpassword, $dbname, $dbhost );
            $wpdb_mysql->set_prefix( $table_prefix );

            // Get the perflab options, remove the database/sqlite module and update the option.
            $row = $wpdb_mysql->get_row( $wpdb_mysql->prepare( "SELECT option_value FROM $wpdb_mysql->options WHERE option_name = %s LIMIT 1", 'active_plugins' ) );
            if ( is_object( $row ) ) {
                $value = maybe_unserialize( $row->option_value );
                if ( is_array( $value ) ) {
                    $value_flipped = array_flip( $value );
                    $items         = array_reverse( explode( DIRECTORY_SEPARATOR, SQLITE_MAIN_FILE ) );
                    $item          = $items[1] . DIRECTORY_SEPARATOR . $items[0];
                    unset( $value_flipped[ $item ] );
                    $value = array_flip( $value_flipped );
                    $wpdb_mysql->update( $wpdb_mysql->options, array( 'option_value' => maybe_serialize( $value ) ), array( 'option_name' => 'active_plugins' ) );
                }
            }
        },
        PHP_INT_MAX
    );
    // Flush any persistent cache.
    wp_cache_flush();
}
register_deactivation_hook( SQLITE_MAIN_FILE, 'sqlite_plugin_remove_db_file' ); // Remove db.php file on plugin deactivation.