Changeset 3250638
- Timestamp:
- 03/04/2025 07:13:52 PM (12 months ago)
- Location:
- multi-connect
- Files:
-
- 21 added
- 3 edited
-
tags/1.0.48 (added)
-
tags/1.0.48/.editorconfig (added)
-
tags/1.0.48/assets (added)
-
tags/1.0.48/assets/css (added)
-
tags/1.0.48/assets/css/admin.css (added)
-
tags/1.0.48/assets/js (added)
-
tags/1.0.48/assets/js/admin.js (added)
-
tags/1.0.48/includes (added)
-
tags/1.0.48/includes/class-admin.php (added)
-
tags/1.0.48/includes/class-multi-connect-api.php (added)
-
tags/1.0.48/includes/class-multi-connect-upgrader-skin.php (added)
-
tags/1.0.48/includes/public.key (added)
-
tags/1.0.48/languages (added)
-
tags/1.0.48/languages/multi-connect-es.mo (added)
-
tags/1.0.48/languages/multi-connect-es.po (added)
-
tags/1.0.48/languages/multi-connect.pot (added)
-
tags/1.0.48/logo.png (added)
-
tags/1.0.48/multi-connect.php (added)
-
tags/1.0.48/phpcs.xml (added)
-
tags/1.0.48/readme.txt (added)
-
tags/1.0.48/uninstall.php (added)
-
trunk/includes/class-multi-connect-api.php (modified) (11 diffs)
-
trunk/multi-connect.php (modified) (1 diff)
-
trunk/readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
multi-connect/trunk/includes/class-multi-connect-api.php
r3244924 r3250638 32 32 add_action( 'rest_api_init', array( $this, 'register_rest_routes' ), 0 ); 33 33 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' ) ); 36 35 } 37 36 38 37 public function add_woocommerce_admin_rest_controllers( $controllers ) { 39 38 $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 47 48 return $controllers; 48 49 } 49 50 50 public function allow_auto_login( $errors) {51 public function allow_auto_login( $errors ) { 51 52 return null; 52 53 } 54 53 55 /** 54 56 * Register REST routes. … … 156 158 array( 157 159 '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' ), 160 162 ) 161 163 ); … … 166 168 array( 167 169 'methods' => 'GET', 168 'callback' => [ $this, 'process_auto_login' ],170 'callback' => array( $this, 'process_auto_login' ), 169 171 'permission_callback' => '__return_true', 170 172 ) … … 176 178 array( 177 179 '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' ), 179 191 'permission_callback' => array( $this, 'check_update_permission' ), 180 192 ) … … 241 253 break; 242 254 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 ); 245 259 break; 246 260 } … … 613 627 wp_update_themes(); 614 628 615 616 629 $updates = array( 617 630 'core' => false, … … 634 647 get_plugin_updates(); 635 648 try { 636 $transient = (object) [649 $transient = (object) array( 637 650 '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' ); 642 655 } catch ( Throwable $e ) { 643 656 $transient; … … 660 673 get_theme_updates(); 661 674 try { 662 $transient = (object) [675 $transient = (object) array( 663 676 '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' ); 668 681 } catch ( Throwable $e ) { 669 682 $updatesFromHook = $transient; … … 1084 1097 } 1085 1098 1086 public function check_authentication( $request) {1099 public function check_authentication( $request ) { 1087 1100 // 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 ) { 1092 1105 // Generar token único 1093 $token = wp_generate_password( $this->token_length, false);1106 $token = wp_generate_password( $this->token_length, false ); 1094 1107 1095 1108 // 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, 1098 1111 '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() ); 1112 1125 exit; 1113 1126 } 1114 1127 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() ); 1119 1132 exit; 1120 1133 } 1121 1134 1122 1135 // Eliminar el token usado 1123 delete_transient( 'multi_wp_login_token_' . $token);1136 delete_transient( 'multi_wp_login_token_' . $token ); 1124 1137 1125 1138 // 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 ); 1130 1143 1131 1144 // Redirigir al admin 1132 wp_redirect( admin_url());1145 wp_redirect( admin_url() ); 1133 1146 exit; 1134 1147 } 1135 1148 1136 wp_redirect( wp_login_url());1149 wp_redirect( wp_login_url() ); 1137 1150 exit; 1138 1151 } 1139 1152 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(); 1144 1157 $systemChecks = WP_Site_Health::get_tests(); 1145 1158 $systemChecks = $systemChecks['direct']; 1146 1159 1147 $requiredChecks = [1160 $requiredChecks = array( 1148 1161 'wordpress_version', 1149 1162 'php_version', … … 1155 1168 'available_updates_disk_space', 1156 1169 'autoloaded_options', 1157 ];1170 ); 1158 1171 1159 1172 foreach ( $requiredChecks as $checkName ) { 1160 if ( !isset($systemChecks[ $checkName ])) {1173 if ( ! isset( $systemChecks[ $checkName ] ) ) { 1161 1174 continue; 1162 1175 } 1163 $checkLabel = $systemChecks[ $checkName ]['test'];1176 $checkLabel = $systemChecks[ $checkName ]['test']; 1164 1177 $checkFunction = 'get_test_' . $checkLabel; 1165 1178 … … 1173 1186 return $systemInfo; 1174 1187 } 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 } 1175 1368 } -
multi-connect/trunk/multi-connect.php
r3244924 r3250638 4 4 * Plugin URI: https://multi-wp.com 5 5 * Description: Connect your WordPress site with Multi-WP for centralized management and updates. 6 * Version: 1.0.4 76 * Version: 1.0.48 7 7 * Requires at least: 5.8 8 8 * Requires PHP: 7.4 -
multi-connect/trunk/readme.txt
r3244924 r3250638 5 5 Tested up to: 6.7 6 6 Requires PHP: 7.4 7 Stable tag: 1.0.4 77 Stable tag: 1.0.48 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 44 44 45 45 == Changelog == 46 47 = 1.0.48 = 48 * Update safely several plugins by uploading only once in Multi WP. 46 49 47 50 = 1.0.47 =
Note: See TracChangeset
for help on using the changeset viewer.