wpmudev-sls
11/19/2017 - 12:38 AM

[WordPress General] - Replace urls in db

[WordPress General] - Replace urls in db

<?php
/**
* Plugin Name: [WordPress General] - Replace urls in db
* Plugin URI: https://premium.wpmudev.org/
* Description: A custom solution to replace urls or strings in WordPress DB
* Author: Panos Lyrakis @ WPMUDEV
* Author URI: https://premium.wpmudev.org/
* License: GPLv2 or later
*/
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

if ( ! class_exists( 'WPMUDEV_DB_Replace' ) ) {
    
    class WPMUDEV_DB_Replace {
        private static $_instance = null;
        private static $field_id = 'wpmudev-source-table';

        public static function get_instance() {
            if( is_null( self::$_instance ) ){
                self::$_instance = new WPMUDEV_DB_Replace();
            }
            return self::$_instance;
            
        }

        private function __construct() {

            add_action( 'admin_menu', array( $this, 'admin_menu' ) );
            add_action( 'wp_ajax_wpmudev_db_replace_str', array( $this, 'db_replace' ), 10 );
            add_action( 'wp_ajax_wpmudev_db_get_table_columns', array( $this, 'get_table_columns' ), 10 );

        }

        public function admin_menu(){

            add_submenu_page(
                'tools.php',
                __( 'DB Replace', 'wpmudevdbreplace' ),
                __( 'DB Replace', 'wpmudevdbreplace' ),
                'manage_options',
                'wpmudevdbreplace',
                array( $this, 'page_layout' )
             );
      
             
        }


        public function page_layout(){

            $db_replace_log = array_reverse( get_option( 'wpmudev_db_replace_log', array() ) );

            ?>
            <div class="wrap">
                <div class="card header-card">
                    <h1><?php _e( 'DB Replace' ); ?></h1>
                    <em><?php _e( 'Select the database table you need to replace and fill the fields with the appropriate values' ); ?></em>
                    <div class="notice notice-warning"> <?php _e( 'It\'s important you keep a backup of these tables first!' ); ?> </div>
                </div>

                <div class="card content-card">
                    <?php echo $this->list_db_tables( 'dropdown' ); ?>
                    <?php echo $this->list_db_actions(); ?>
                    <?php echo $this->raw_js(); ?>
                </div>

                <?php
                if( ! empty( $db_replace_log ) ){
                    ?>
                    <h3><?php _e( 'Pevious replacements log' ); ?></h3>
                    <?php
                    foreach( $db_replace_log as $log_box ){
                        ?>
                        <div class="card report-card">
                            <div>Time: <code><?php echo $log_box['date']; ?></code></div>
                            <div>Query: <code><?php echo $log_box['last_query']; ?></code></div>
                            <div>Rows affected: <code><?php echo $log_box['rows_affected']; ?></code></div></div>
                        <?php
                    }
                }
                ?>
                
            </div>
            <?php
            
        }

        public function list_db_tables( $style ){

            $tables = self::get_db_tables();            
            $out = null;

            switch( $style ){
                case 'dropdown':
                default:
                $out = $this->create_dropdown( array( 'options' => $tables ) );
            }

            return $out;

        }

        public function list_db_actions(){

            $out = '';

            ob_start();
            ?>
            <div class="wpmudev-db-actions wrap hidden">

                <div class="table-col wrap">
                    <label>
                        <?php _e( 'Table column' ); ?>
                    </label>
                    <select id="wpmudev-table-column">
                        <option value="none"><?php _e( 'Please select a table' ); ?></option>
                    </select>
                    <div class="tooltip-line">
                        <small><?php _e( 'Select the table column.' ) ?></small>
                    </div>
                </div>

                <div class="target-wrap wrap">
                    <label>
                        <?php _e( 'Existing string' ); ?>
                    </label>
                    <input type="text" id="wpmudev-target-str" value="" />
                    <div class="tooltip-line">
                        <small><?php _e( 'The string you need to be replaced.' ) ?></small>
                    </div>
                </div>

                <div class="new-wrap wrap">
                    <label>
                        <?php _e( 'New string' ); ?>
                    </label>
                    <input type="text" id="wpmudev-new-str" value="" />
                    <div class="tooltip-line">
                        <small><?php _e( 'The new string you need use.' ) ?></small>
                    </div>
                </div>

                <div class="action-btn-wrap wrap">
                    <a class="button" id="wpmudev-replace-btn"><?php _e( 'Replace' ); ?></a>
                </div>

            </div>
            <?php
            $out = ob_get_clean();

            return $out;

        }

        public static function get_db_tables( $normalize_array=true ){

            global $wpdb;
            $db_tables = $wpdb->get_results( "SHOW TABLES" );

            if( $normalize_array ){

                $normalized_tables_array = array();

                foreach( $db_tables as $index => $table_object ) {
                    
                    foreach($table_object as $table_name ) {
                        $normalized_tables_array[] = $table_name;
                    }

                }
               
                return $normalized_tables_array;

            }
            
            return $db_tables;

        }

        public function create_dropdown( $args = array() ){
            
            $out = '';
            $options = isset( $args['options'] ) ? $args['options'] : '';
            $class = isset( $args['class'] ) ? $args['class'] : self::$field_id;
            $id = isset( $args['id'] ) ? $args['id'] : $class;
            $name = isset( $args['name'] ) ? $args['name'] : '';
            $selected = isset( $args['selected'] ) ? $args['selected'] : '';
            $class = isset( $args['class'] ) ? $args['class'] : '';

            ob_start();

            ?>
            <div class="select-title">
                <label><?php _e( 'Select a table' ); ?></label>
            </div>

            <div class="select-content">
                <select id="<?php echo $id; ?>" name="<?php echo $name ?>" class="<?php echo $class ?>">
                <option value="none"><?php _e( 'Please select a DB table' ); ?></option>
                    <?php
                    foreach( $options as $option ){
                        ?>
                        <option value="<?php echo $option ?>" <?php selected( $option, $selected ); ?>><?php echo $option ?></option>
                        <?php
                    }
                    ?>
                </select>
            </div>

            <?php
            $out = ob_get_clean();
            return $out;
        }


        public function db_replace(){

            check_ajax_referer( 'wpmudev_db_replace_str', 'security' );

            global $wpdb;
            $return = array(
                'success'	    => false,
            );

            $table = sanitize_text_field( $_POST[ 'table' ] );
            $column = sanitize_text_field( $_POST[ 'column' ] );
            $target_str = sanitize_text_field( $_POST[ 'target_str' ] );
            $new_str = sanitize_text_field( $_POST[ 'new_str' ] );

            $query = $wpdb->prepare( 
                "UPDATE {$table} 
                SET {$column}=REPLACE({$column},%s,%s) 
                WHERE {$column} LIKE %s", 
                    $target_str, 
                    $new_str, 
                    '%' . $wpdb->esc_like( $target_str ) . '%' 
            );

            $execute_query = $wpdb->query( $query );
            
            if( ! is_wp_error( $execute_query ) ){

                $last_query     = $wpdb->last_query;
                $rows_affected  = $wpdb->rows_affected;
                $date           = date( 'F j, Y, H:i:s' );

                $db_replace_log = get_option( 'wpmudev_db_replace_log', array() );
                $db_replace_log[] = array( 
                                        'last_query'    => $last_query,
                                        'rows_affected' => $rows_affected,
                                        'date'          => $date
                                    );
                
                //Keep 20 last updates in options table
                if( count( $db_replace_log ) > 20 ){
                    array_shift( $db_replace_log );
                }
                update_option( 'wpmudev_db_replace_log', $db_replace_log );

                $return = array(
                    'success'	    => true,
                    'last_query'    => $last_query,
                    'rows_affected' => $rows_affected,
                    'date'          => $date
                );
            }

            wp_send_json($return);

        }

        public function get_table_columns(){

            check_ajax_referer( 'wpmudev_db_replace_str', 'security' );

            global $wpdb;
            $return = array(
                'success'	    => false,
            );

            $columns = array();
            $table = sanitize_text_field( $_POST[ 'table' ] );
            //$cols_sql = $wpdb->prepare( "DESCRIBE %s", $table );            
            $columns_result = $wpdb->get_results( "DESCRIBE {$table}" );

            foreach( $columns_result as $key => $column_items ) {

                if( strpos( $column_items->Type, 'int' ) === false ){
                    $columns[] = $column_items->Field;
                }

            }

            if( ! is_wp_error( $columns_result ) && ! empty( $columns ) ){
                $return[ 'success' ] = true;
                $return[ 'columns' ] = $columns;
            }

            wp_send_json($return);

        }

        public function raw_js(){

            $out = '';

            ob_start();
            ?>
            <script type="text/javascript">
            (function($){
                $(document).ready(function(){
                    const replace_button = $( '#wpmudev-replace-btn' ),
                    db_table_field = $( '#<?php echo self::$field_id ?>' ),
                    actions_area = $( '.wpmudev-db-actions' ); 
                    let columns_select = $( '#wpmudev-table-column' );                   

                    db_table_field.val( 'none' );

                    db_table_field.on( 'change', function(){
                        $this = $( this );
                        actions_area.fadeOut( 350 );

                        if( $this.val() == 'none' ){
                            alert( 'Please select one of the tables' );
                            actions_area.fadeOut( 350 );
                            return;
                        }

                        let data = {
                            action: 'wpmudev_db_get_table_columns',
                            security: '<?php echo wp_create_nonce( "wpmudev_db_replace_str" ); ?>',
                            table: $this.val()
                        };

                        $.post(ajaxurl, data, function(response) {
                            
                            if( response.success ){                            

                                let columns_options;                                

                                //Remove old options from the columns dropdown
                                columns_select.find('option').remove();

                                $.each( response.columns, function() {
                                    let column_option = $( '<option />',{
                                        value: this,
                                        text: this,
                                    });

                                    columns_select.append( column_option );


                                });

                                actions_area.show( 300 );
                            }
                            else{
                                alert( 'Query error or no text columns in this table' );
                            }
                            
                        });

                        //actions_area.show( 350 );

                    });

                    replace_button.on( 'click', function(evt){
                        evt.preventDefault();
                        
                        let db_table = db_table_field.val(),
                            table_column = columns_select.val(),
                            target_str = $( '#wpmudev-target-str' ).val(),
                            new_str = $( '#wpmudev-new-str' ).val();

                        let data = {
                            action: 'wpmudev_db_replace_str',
                            security: '<?php echo wp_create_nonce( "wpmudev_db_replace_str" ); ?>',
                            table: db_table,
                            column: table_column,
                            target_str: target_str,
                            new_str: new_str
                        };

                        $.post(ajaxurl, data, function(response) {
                            
                            if( response.success ){
                                let affected_rows   = response.rows_affected,
                                    last_query      = response.last_query,
                                    query_date      = response.date;
                                    
                                let box = $('<div />', {
                                    'class'       : 'card report-card',
                                    'html'        : '<div>Time: <code>' + query_date + '</code></div>'+
                                                    '<div>Query: <code>' + last_query + '</code></div>'+
                                                    '<div>Rows affected: <code>' + affected_rows + '</code></div>'
                                });

                                $( '.content-card' ).after( box );
                            }
                            else{
                                alert( 'Some error...' );
                            }
                            
                        });
                    });
                });
            })(jQuery);
            </script>
            <?php
            $out = ob_get_clean();

            return $out;

        }
       

    }

    add_action( 'plugins_loaded', function(){
        $GLOBALS['WPMUDEV_DB_Replace'] = WPMUDEV_DB_Replace::get_instance();
    }, 10 );

}