UNPKG

wp-host

Version:

Automated WordPress hosting deployment tool for bulk site creation with MySQL database management

379 lines (365 loc) โ€ข 14.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.ConfigManager = void 0; const fs = __importStar(require("fs-extra")); const path = __importStar(require("path")); const crypto = __importStar(require("crypto")); class ConfigManager { constructor(config) { this.config = config; } /** * Generate wp-config.php files for all sites */ async generateAllConfigs() { console.log(`\nโš™๏ธ Generating wp-config.php files for ${this.config.sites.length} site(s)...`); const results = []; for (let i = 0; i < this.config.sites.length; i++) { const site = this.config.sites[i]; console.log(`\n๐Ÿ“ [${i + 1}/${this.config.sites.length}] Generating config: ${site.site_name}`); try { const result = await this.generateSiteConfig(site); results.push(result); if (result.status === 'success') { console.log(`โœ… ${site.site_name}: wp-config.php generated successfully`); } else { console.log(`โš ๏ธ ${site.site_name}: wp-config.php generation completed with warnings`); } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); console.error(`โŒ ${site.site_name}: wp-config.php generation failed - ${errorMessage}`); results.push({ site_name: site.site_name, status: 'failed', errors: [errorMessage] }); } } return results; } /** * Generate wp-config.php for a single site */ async generateSiteConfig(site) { const targetDir = path.resolve(site.directory_path); const configPath = path.join(targetDir, 'wp-config.php'); console.log(` Target: ${configPath}`); try { // Step 1: Verify WordPress installation exists await this.verifyWordPressInstallation(targetDir); // Step 2: Check if wp-config.php already exists if (await fs.pathExists(configPath)) { console.log(` โš ๏ธ wp-config.php already exists`); // Backup existing config const backupPath = `${configPath}.backup.${Date.now()}`; await fs.copy(configPath, backupPath); console.log(` ๐Ÿ“ Backed up to ${path.basename(backupPath)}`); } // Step 3: Generate wp-config.php content const configContent = await this.generateConfigContent(site); // Step 4: Write wp-config.php file await fs.writeFile(configPath, configContent, 'utf8'); // Step 5: Set appropriate permissions (644) await fs.chmod(configPath, 0o644); console.log(` โœ… wp-config.php generated successfully`); return { site_name: site.site_name, status: 'success', wordpress_path: targetDir, wordpress_info: { site_url: this.generateSiteUrl(targetDir), admin_user: 'admin', admin_password: this.config.wordpress.adminPassword, admin_email: this.config.wordpress.adminEmail } }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); throw new Error(`Config generation failed: ${errorMessage}`); } } /** * Verify that WordPress is installed in the target directory */ async verifyWordPressInstallation(targetDir) { const requiredFiles = [ 'wp-blog-header.php', 'wp-config-sample.php', 'wp-includes/version.php' ]; for (const file of requiredFiles) { const filePath = path.join(targetDir, file); if (!await fs.pathExists(filePath)) { throw new Error(`WordPress not properly installed - missing ${file}`); } } } /** * Generate wp-config.php content with database credentials and security keys */ async generateConfigContent(site) { const databaseName = site.database_name; const username = site.db_user; const password = this.config.mysql.sharedDbPassword; const host = this.config.mysql.host; const port = this.config.mysql.port; // Generate security keys and salts const securityKeys = this.generateSecurityKeys(); // Generate table prefix (use site name for uniqueness if multiple sites share a database) const tablePrefix = this.generateTablePrefix(site.site_name); // Database host with port (if not default) const dbHost = port === 3306 ? host : `${host}:${port}`; const configTemplate = `<?php /** * The base configuration for WordPress * * This file is generated by wp-hosting-automation tool * Generated on: ${new Date().toISOString()} * Site: ${site.site_name} * * @link https://wordpress.org/support/article/editing-wp-config-php/ * * @package WordPress */ // ** Database settings - Generated automatically ** // /** The name of the database for WordPress */ define( 'DB_NAME', '${databaseName}' ); /** Database username */ define( 'DB_USER', '${username}' ); /** Database password */ define( 'DB_PASSWORD', '${password}' ); /** Database hostname */ define( 'DB_HOST', '${dbHost}' ); /** Database charset to use in creating database tables. */ define( 'DB_CHARSET', 'utf8mb4' ); /** The database collate type. Don't change this if in doubt. */ define( 'DB_COLLATE', '' ); /**#@+ * Authentication unique keys and salts. * * Change these to different unique phrases! You can generate these using * the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service}. * * You can change these at any point in time to invalidate all existing cookies. * This will force all users to have to log in again. * * @since 2.6.0 */ ${securityKeys} /**#@-*/ /** * WordPress database table prefix. * * You can have multiple installations in one database if you give each * a unique prefix. Only numbers, letters, and underscores please! */ $table_prefix = '${tablePrefix}'; /** * For developers: WordPress debugging mode. * * Change this to true to enable the display of notices during development. * It is strongly recommended that plugin and theme developers use WP_DEBUG * in their development environments. * * For information on other constants that can be used for debugging, * visit the documentation. * * @link https://wordpress.org/support/article/debugging-in-wordpress/ */ define( 'WP_DEBUG', false ); /* Add any custom values between this line and the "stop editing" comment. */ /* That's all, stop editing! Happy publishing. */ /** Absolute path to the WordPress directory. */ if ( ! defined( 'ABSPATH' ) ) { define( 'ABSPATH', __DIR__ . '/' ); } /** Sets up WordPress vars and included files. */ require_once ABSPATH . 'wp-settings.php'; `; return configTemplate; } /** * Generate WordPress security keys and salts */ generateSecurityKeys() { const keyNames = [ 'AUTH_KEY', 'SECURE_AUTH_KEY', 'LOGGED_IN_KEY', 'NONCE_KEY', 'AUTH_SALT', 'SECURE_AUTH_SALT', 'LOGGED_IN_SALT', 'NONCE_SALT' ]; return keyNames.map(keyName => { const key = crypto.randomBytes(32).toString('base64'); return `define( '${keyName}', '${key}' );`; }).join('\n'); } /** * Generate a unique table prefix based on site name */ generateTablePrefix(siteName) { // Clean site name to only contain letters and numbers const cleanName = siteName.replace(/[^a-zA-Z0-9]/g, '').toLowerCase(); // Take first 6 characters and add underscore const prefix = cleanName.substring(0, 6) + '_'; // Ensure it starts with a letter return prefix.match(/^[a-z]/) ? prefix : `wp${prefix}`; } /** * Generate site URL based on directory path */ generateSiteUrl(targetDir) { const resolvedPath = path.resolve(targetDir); // Check if it's in common web directories if (resolvedPath.includes('/var/www/html')) { const relativePath = resolvedPath.replace('/var/www/html', ''); return `http://localhost${relativePath}`; } else if (resolvedPath.includes('/var/www')) { const relativePath = resolvedPath.replace('/var/www', ''); return `http://localhost${relativePath}`; } else { // Local development directory return `http://localhost:8080`; } } /** * Check wp-config.php status for all sites */ async checkAllConfigs() { console.log('\n๐Ÿ“Š wp-config.php Status Report'); console.log('=============================='); for (let i = 0; i < this.config.sites.length; i++) { const site = this.config.sites[i]; console.log(`\n${i + 1}. ${site.site_name}`); try { const status = await this.checkSiteConfig(site); console.log(` wp-config.php: ${status.exists ? 'โœ… Exists' : 'โŒ Missing'}`); console.log(` WordPress: ${status.hasWordPress ? 'โœ… Installed' : 'โŒ Not found'}`); if (status.exists && status.isValid) { console.log(` Database Config: โœ… Valid`); console.log(` Security Keys: โœ… Present`); console.log(` Status: ๐ŸŸข Ready`); } else if (status.exists) { console.log(` Status: ๐ŸŸก Invalid configuration`); } else if (status.hasWordPress) { console.log(` Status: ๐ŸŸก WordPress installed, needs configuration`); } else { console.log(` Status: ๐Ÿ”ด WordPress not installed`); } } catch (error) { console.log(` Status: โŒ Error checking status`); console.log(` Error: ${error instanceof Error ? error.message : String(error)}`); } } } /** * Check wp-config.php status for a single site */ async checkSiteConfig(site) { const targetDir = path.resolve(site.directory_path); const configPath = path.join(targetDir, 'wp-config.php'); try { const exists = await fs.pathExists(configPath); // Check if WordPress is installed const hasWordPress = await fs.pathExists(path.join(targetDir, 'wp-includes')); let isValid = false; if (exists) { // Check if config contains required database settings const configContent = await fs.readFile(configPath, 'utf8'); const hasDbName = configContent.includes("define( 'DB_NAME'"); const hasDbUser = configContent.includes("define( 'DB_USER'"); const hasDbPassword = configContent.includes("define( 'DB_PASSWORD'"); const hasDbHost = configContent.includes("define( 'DB_HOST'"); isValid = hasDbName && hasDbUser && hasDbPassword && hasDbHost; } return { exists, hasWordPress, isValid }; } catch (error) { console.error(`Error checking config: ${error instanceof Error ? error.message : String(error)}`); return { exists: false, hasWordPress: false, isValid: false }; } } /** * Clean up wp-config.php files * WARNING: This will delete all wp-config.php files! */ async cleanupAllConfigs() { console.log('\n๐Ÿงน Cleaning up wp-config.php files...'); console.log('โš ๏ธ WARNING: This will permanently delete all wp-config.php files!'); for (const site of this.config.sites) { const targetDir = path.resolve(site.directory_path); const configPath = path.join(targetDir, 'wp-config.php'); try { console.log(`\n๐Ÿ—‘๏ธ Cleaning up ${site.site_name}:`); if (await fs.pathExists(configPath)) { await fs.remove(configPath); console.log(` โœ… wp-config.php removed`); } else { console.log(` โ„น๏ธ wp-config.php doesn't exist`); } } catch (error) { console.error(` โŒ Error cleaning up ${site.site_name}: ${error instanceof Error ? error.message : String(error)}`); } } console.log('\nโœ… Cleanup completed.'); } /** * Get configuration generation summary */ getSummary(results) { const total = results.length; const successful = results.filter(r => r.status === 'success').length; const failed = results.filter(r => r.status === 'failed').length; const skipped = results.filter(r => r.status === 'skipped').length; return { total, successful, failed, skipped }; } } exports.ConfigManager = ConfigManager; //# sourceMappingURL=config-manager.js.map