Plugin Directory

Changeset 3250638


Ignore:
Timestamp:
03/04/2025 07:13:52 PM (12 months ago)
Author:
MrViSiOn
Message:

1.0.48

  • Update safely several plugins by uploading only once in Multi WP.
Location:
multi-connect
Files:
21 added
3 edited

Legend:

Unmodified
Added
Removed
  • multi-connect/trunk/includes/class-multi-connect-api.php

    r3244924 r3250638  
    3232        add_action( 'rest_api_init', array( $this, 'register_rest_routes' ), 0 );
    3333        add_filter( 'wp_is_application_passwords_available', '__return_true', PHP_INT_MAX );
    34         add_filter( 'woocommerce_admin_rest_controllers', array($this, 'add_woocommerce_admin_rest_controllers') );
    35 
     34        add_filter( 'woocommerce_admin_rest_controllers', array( $this, 'add_woocommerce_admin_rest_controllers' ) );
    3635    }
    3736
    3837    public function add_woocommerce_admin_rest_controllers( $controllers ) {
    3938        $rest_route = $GLOBALS['wp']->query_vars['rest_route'] ?? '';
    40         if (str_contains($rest_route, $this->namespace)) {
    41             if(str_contains($rest_route, 'auto-login')) {
    42                 add_filter('rest_authentication_errors', array($this, 'allow_auto_login'), PHP_INT_MAX);
    43             }
    44             return [];
    45 
    46         }
     39        if ( str_contains( $rest_route, $this->namespace ) ) {
     40            if ( str_contains( $rest_route, 'auto-login' ) ) {
     41                add_filter( 'rest_authentication_errors', array( $this, 'allow_auto_login' ), PHP_INT_MAX );
     42            }
     43
     44            return array();
     45
     46        }
     47
    4748        return $controllers;
    4849    }
    4950
    50     public function allow_auto_login($errors) {
     51    public function allow_auto_login( $errors ) {
    5152        return null;
    5253    }
     54
    5355    /**
    5456     * Register REST routes.
     
    156158            array(
    157159                'methods'             => 'POST',
    158                 'callback'            => [ $this, 'generate_login_token' ],
    159                 'permission_callback' => [ $this, 'check_authentication' ],
     160                'callback'            => array( $this, 'generate_login_token' ),
     161                'permission_callback' => array( $this, 'check_authentication' ),
    160162            )
    161163        );
     
    166168            array(
    167169                'methods'             => 'GET',
    168                 'callback'            => [ $this, 'process_auto_login' ],
     170                'callback'            => array( $this, 'process_auto_login' ),
    169171                'permission_callback' => '__return_true',
    170172            )
     
    176178            array(
    177179                'methods'             => 'GET',
    178                 'callback'            => [ $this, 'get_site_info' ],
     180                'callback'            => array( $this, 'get_site_info' ),
     181                'permission_callback' => array( $this, 'check_update_permission' ),
     182            )
     183        );
     184
     185        register_rest_route(
     186            $this->namespace,
     187            '/plugin-update',
     188            array(
     189                'methods'             => 'POST',
     190                'callback'            => array( $this, 'handle_plugin_update' ),
    179191                'permission_callback' => array( $this, 'check_update_permission' ),
    180192            )
     
    241253                            break;
    242254                        case 'core':
    243                             $selected_folders = array_merge( $selected_folders,
    244                                 glob( MULTICONNECT_PLUGIN_ABSPATH . 'wp-*.php' ) );
     255                            $selected_folders = array_merge(
     256                                $selected_folders,
     257                                glob( MULTICONNECT_PLUGIN_ABSPATH . 'wp-*.php' )
     258                            );
    245259                            break;
    246260                    }
     
    613627        wp_update_themes();
    614628
    615 
    616629        $updates = array(
    617630            'core'         => false,
     
    634647        get_plugin_updates();
    635648        try {
    636             $transient = (object) [
     649            $transient = (object) array(
    637650                'last_checked' => time() - ( 13 * 3600 ),
    638                 'checked'      => [ 'default' => 'none' ],
    639                 'response'     => [ 'default' => 'none' ],
    640             ];
    641             apply_filters( "pre_set_site_transient_update_plugins", $transient, "update_plugins" );
     651                'checked'      => array( 'default' => 'none' ),
     652                'response'     => array( 'default' => 'none' ),
     653            );
     654            apply_filters( 'pre_set_site_transient_update_plugins', $transient, 'update_plugins' );
    642655        } catch ( Throwable $e ) {
    643656            $transient;
     
    660673        get_theme_updates();
    661674        try {
    662             $transient       = (object) [
     675            $transient       = (object) array(
    663676                'last_checked' => time() - ( 13 * 3600 ),
    664                 'checked'      => [ 'default' => 'none' ],
    665                 'response'     => [ 'default' => 'none' ],
    666             ];
    667             $updatesFromHook = apply_filters( "pre_set_site_transient_update_themes", $transient, "update_themes" );
     677                'checked'      => array( 'default' => 'none' ),
     678                'response'     => array( 'default' => 'none' ),
     679            );
     680            $updatesFromHook = apply_filters( 'pre_set_site_transient_update_themes', $transient, 'update_themes' );
    668681        } catch ( Throwable $e ) {
    669682            $updatesFromHook = $transient;
     
    10841097    }
    10851098
    1086     public function check_authentication($request) {
     1099    public function check_authentication( $request ) {
    10871100        // Verificar la autenticación por Application Password
    1088         return current_user_can('administrator');
    1089     }
    1090 
    1091     public function generate_login_token($request) {
     1101        return current_user_can( 'administrator' );
     1102    }
     1103
     1104    public function generate_login_token( $request ) {
    10921105        // Generar token único
    1093         $token = wp_generate_password($this->token_length, false);
     1106        $token = wp_generate_password( $this->token_length, false );
    10941107
    10951108        // Guardar el token en las opciones de WordPress con tiempo de expiración
    1096         $token_data = [
    1097             'token' => $token,
     1109        $token_data = array(
     1110            'token'   => $token,
    10981111            'expires' => time() + $this->token_expiry,
    1099             'user_id' => get_current_user_id()
    1100         ];
    1101 
    1102         set_transient('multi_wp_login_token_' . $token, $token_data, $this->token_expiry);
    1103 
    1104         return rest_ensure_response(['token' => $token]);
    1105     }
    1106 
    1107     public function process_auto_login($request) {
    1108         $token = $request->get_param('token');
    1109 
    1110         if (!$token) {
    1111             wp_redirect(wp_login_url());
     1112            'user_id' => get_current_user_id(),
     1113        );
     1114
     1115        set_transient( 'multi_wp_login_token_' . $token, $token_data, $this->token_expiry );
     1116
     1117        return rest_ensure_response( array( 'token' => $token ) );
     1118    }
     1119
     1120    public function process_auto_login( $request ) {
     1121        $token = $request->get_param( 'token' );
     1122
     1123        if ( ! $token ) {
     1124            wp_redirect( wp_login_url() );
    11121125            exit;
    11131126        }
    11141127
    1115         $token_data = get_transient('multi_wp_login_token_' . $token);
    1116 
    1117         if (!$token_data || time() > $token_data['expires']) {
    1118             wp_redirect(wp_login_url());
     1128        $token_data = get_transient( 'multi_wp_login_token_' . $token );
     1129
     1130        if ( ! $token_data || time() > $token_data['expires'] ) {
     1131            wp_redirect( wp_login_url() );
    11191132            exit;
    11201133        }
    11211134
    11221135        // Eliminar el token usado
    1123         delete_transient('multi_wp_login_token_' . $token);
     1136        delete_transient( 'multi_wp_login_token_' . $token );
    11241137
    11251138        // Realizar el login
    1126         $user = get_user_by('id', $token_data['user_id']);
    1127         if ($user) {
    1128             wp_set_current_user($user->ID);
    1129             wp_set_auth_cookie($user->ID);
     1139        $user = get_user_by( 'id', $token_data['user_id'] );
     1140        if ( $user ) {
     1141            wp_set_current_user( $user->ID );
     1142            wp_set_auth_cookie( $user->ID );
    11301143
    11311144            // Redirigir al admin
    1132             wp_redirect(admin_url());
     1145            wp_redirect( admin_url() );
    11331146            exit;
    11341147        }
    11351148
    1136         wp_redirect(wp_login_url());
     1149        wp_redirect( wp_login_url() );
    11371150        exit;
    11381151    }
    11391152
    1140     public function get_site_info($request) {
    1141         $systemInfo = [];
    1142 
    1143         $siteChecker = WP_Site_Health::get_instance();
     1153    public function get_site_info( $request ) {
     1154        $systemInfo = array();
     1155
     1156        $siteChecker  = WP_Site_Health::get_instance();
    11441157        $systemChecks = WP_Site_Health::get_tests();
    11451158        $systemChecks = $systemChecks['direct'];
    11461159
    1147         $requiredChecks = [
     1160        $requiredChecks = array(
    11481161            'wordpress_version',
    11491162            'php_version',
     
    11551168            'available_updates_disk_space',
    11561169            'autoloaded_options',
    1157         ];
     1170        );
    11581171
    11591172        foreach ( $requiredChecks as $checkName ) {
    1160             if (!isset($systemChecks[ $checkName ])) {
     1173            if ( ! isset( $systemChecks[ $checkName ] ) ) {
    11611174                continue;
    11621175            }
    1163             $checkLabel = $systemChecks[ $checkName ]['test'];
     1176            $checkLabel    = $systemChecks[ $checkName ]['test'];
    11641177            $checkFunction = 'get_test_' . $checkLabel;
    11651178
     
    11731186        return $systemInfo;
    11741187    }
     1188
     1189    /**
     1190     * Verifica si un archivo ZIP es un plugin válido de WordPress
     1191     *
     1192     * @param string $zip_file Ruta al archivo ZIP
     1193     *
     1194     * @return bool|WP_Error True si es válido, WP_Error si no lo es
     1195     */
     1196    private function verify_wordpress_plugin( $zip_file ): bool|WP_Error {
     1197        // Verificar que WP_Filesystem está disponible
     1198        if ( ! function_exists( 'WP_Filesystem' ) ) {
     1199            require_once ABSPATH . 'wp-admin/includes/file.php';
     1200        }
     1201        WP_Filesystem();
     1202
     1203        // Crear directorio temporal
     1204        $temp_dir = wp_tempnam();
     1205        unlink( $temp_dir ); // Eliminar el archivo temporal
     1206        mkdir( $temp_dir ); // Crear directorio con el mismo nombre
     1207
     1208        // Extraer el ZIP
     1209        $unzip_result = unzip_file( $zip_file, $temp_dir );
     1210        if ( is_wp_error( $unzip_result ) ) {
     1211            // Limpiar
     1212            $this->rrmdir( $temp_dir );
     1213
     1214            return new WP_Error( 'invalid_plugin', 'No se pudo extraer el archivo ZIP' );
     1215        }
     1216
     1217        // Buscar archivo PHP principal con encabezado de plugin
     1218        $plugin_files = glob( $temp_dir . '/*.php' );
     1219        $plugin_files = array_merge( $plugin_files,
     1220            glob( $temp_dir . '/*/*.php' ) ); // Buscar también en subdirectorios
     1221
     1222        $is_plugin = false;
     1223        foreach ( $plugin_files as $plugin_file ) {
     1224            $plugin_data = get_plugin_data( $plugin_file, false, false );
     1225            if ( ! empty( $plugin_data['Name'] ) ) {
     1226                $is_plugin = true;
     1227                break;
     1228            }
     1229        }
     1230
     1231        // Limpiar
     1232        $this->rrmdir( $temp_dir );
     1233
     1234        if ( ! $is_plugin ) {
     1235            return new WP_Error( 'invalid_plugin', 'El archivo ZIP no contiene un plugin válido de WordPress' );
     1236        }
     1237
     1238        return true;
     1239    }
     1240
     1241    /**
     1242     * Elimina recursivamente un directorio y su contenido
     1243     *
     1244     * @param string $dir Ruta al directorio
     1245     *
     1246     * @return void
     1247     */
     1248    private function rrmdir( $dir ): void {
     1249        if ( is_dir( $dir ) ) {
     1250            $objects = scandir( $dir );
     1251            foreach ( $objects as $object ) {
     1252                if ( $object != '.' && $object != '..' ) {
     1253                    if ( is_dir( $dir . '/' . $object ) ) {
     1254                        $this->rrmdir( $dir . '/' . $object );
     1255                    } else {
     1256                        unlink( $dir . '/' . $object );
     1257                    }
     1258                }
     1259            }
     1260            rmdir( $dir );
     1261        }
     1262    }
     1263
     1264    public function handle_plugin_update( $request ): WP_Error|array {
     1265        // Check if the upload is valid
     1266        if ( ! function_exists( 'wp_handle_upload' ) ) {
     1267            require_once ABSPATH . 'wp-admin/includes/file.php';
     1268        }
     1269
     1270        // Get the uploaded file
     1271        $files = $request->get_file_params();
     1272
     1273        if ( empty( $files['plugin_zip'] ) ) {
     1274            return new WP_Error( 'no_file', 'No file was uploaded', array( 'status' => 400 ) );
     1275        }
     1276
     1277        $file = $files['plugin_zip'];
     1278
     1279        // Check if the file is a ZIP
     1280        if ( $file['type'] !== 'application/zip' ) {
     1281            return new WP_Error( 'invalid_file', 'The uploaded file is not a ZIP file', array( 'status' => 400 ) );
     1282        }
     1283
     1284        // Handle the upload
     1285        $upload = wp_handle_upload( $file, array( 'test_form' => false ) );
     1286
     1287        if ( isset( $upload['error'] ) ) {
     1288            return new WP_Error( 'upload_error', $upload['error'], array( 'status' => 500 ) );
     1289        }
     1290
     1291        // Verificar si es un plugin válido de WordPress
     1292        $verify_result = $this->verify_wordpress_plugin( $upload['file'] );
     1293        if ( is_wp_error( $verify_result ) ) {
     1294            @unlink( $upload['file'] ); // Eliminar archivo temporal
     1295
     1296            return $verify_result;
     1297        }
     1298
     1299        // Include necessary files for plugin installation
     1300        require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
     1301        require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
     1302        require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
     1303        require_once ABSPATH . 'wp-admin/includes/plugin.php';
     1304
     1305        // Use the Plugin_Upgrader class to install the plugin
     1306        $upgrader = new Plugin_Upgrader( new WP_Ajax_Upgrader_Skin() );
     1307
     1308        // Install the plugin
     1309        $result = $upgrader->install( $upload['file'], array( 'overwrite_package' => true ) );
     1310
     1311        // Delete the temporary file
     1312        @unlink( $upload['file'] );
     1313
     1314        if ( is_wp_error( $result ) ) {
     1315            return new WP_Error( 'installation_error', $result->get_error_message(), array( 'status' => 500 ) );
     1316        } elseif ( $result === false ) {
     1317            return new WP_Error( 'installation_error', 'Plugin installation failed', array( 'status' => 500 ) );
     1318        }
     1319
     1320        // Get the plugin data
     1321        $plugin_slug    = $request->get_param( 'plugin_slug' );
     1322        $plugin_name    = $request->get_param( 'plugin_name' );
     1323        $plugin_version = $request->get_param( 'plugin_version' );
     1324
     1325        // Activate the plugin if it was previously active
     1326        $all_plugins = get_plugins();
     1327        $plugin_file = '';
     1328
     1329        foreach ( $all_plugins as $file => $plugin ) {
     1330            if ( strpos( $file, $plugin_slug . '/' ) === 0 || $file === $plugin_slug . '.php' ) {
     1331                $plugin_file = $file;
     1332                break;
     1333            }
     1334        }
     1335
     1336        if ( ! empty( $plugin_file ) && is_plugin_inactive( $plugin_file ) ) {
     1337            activate_plugin( $plugin_file );
     1338        }
     1339
     1340        // Log the update
     1341        $this->multi_connect_log_plugin_update( $plugin_name, $plugin_version );
     1342
     1343        return array(
     1344            'success'     => true,
     1345            'message'     => sprintf( 'Plugin %s updated successfully to version %s', $plugin_name, $plugin_version ),
     1346            'plugin_file' => $plugin_file,
     1347        );
     1348    }
     1349
     1350    // Log plugin update
     1351    public function multi_connect_log_plugin_update( $plugin_name, $plugin_version ): void {
     1352        $logs = get_option( 'multi_connect_update_logs', array() );
     1353
     1354        $logs[] = array(
     1355            'type'    => 'plugin',
     1356            'name'    => $plugin_name,
     1357            'version' => $plugin_version,
     1358            'date'    => current_time( 'mysql' ),
     1359        );
     1360
     1361        // Keep only the last 50 logs
     1362        if ( count( $logs ) > 50 ) {
     1363            $logs = array_slice( $logs, - 50 );
     1364        }
     1365
     1366        update_option( 'multi_connect_update_logs', $logs );
     1367    }
    11751368}
  • multi-connect/trunk/multi-connect.php

    r3244924 r3250638  
    44 * Plugin URI: https://multi-wp.com
    55 * Description: Connect your WordPress site with Multi-WP for centralized management and updates.
    6  * Version: 1.0.47
     6 * Version: 1.0.48
    77 * Requires at least: 5.8
    88 * Requires PHP: 7.4
  • multi-connect/trunk/readme.txt

    r3244924 r3250638  
    55Tested up to: 6.7
    66Requires PHP: 7.4
    7 Stable tag: 1.0.47
     7Stable tag: 1.0.48
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    4444
    4545== Changelog ==
     46
     47= 1.0.48 =
     48* Update safely several plugins by uploading only once in Multi WP.
    4649
    4750= 1.0.47 =
Note: See TracChangeset for help on using the changeset viewer.