Changeset 3392035
- Timestamp:
- 11/08/2025 05:04:23 AM (5 months ago)
- Location:
- enable-classic-editor
- Files:
-
- 7 edited
-
. (modified) (1 prop)
-
trunk (modified) (1 prop)
-
trunk/assets/js/admin.js (modified) (1 diff)
-
trunk/classic-editor-admin.css (modified) (3 diffs)
-
trunk/enable-classic-editor.php (modified) (17 diffs)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/uninstall.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
enable-classic-editor
-
Property
svn:ignore
set to
.claude
.git
.gitignore
-
Property
svn:ignore
set to
-
enable-classic-editor/trunk
-
Property
svn:ignore
set to
.claude
-
Property
svn:ignore
set to
-
enable-classic-editor/trunk/assets/js/admin.js
r3295721 r3392035 3 3 */ 4 4 jQuery(document).ready(function($) { 5 // Constants for timing delays (in milliseconds) 6 const TOAST_SHOW_DELAY = 100; 7 const TOAST_AUTO_HIDE_DELAY = 3000; 8 const TOAST_FADE_OUT_DELAY = 300; 9 const BUTTON_RESET_DELAY = 2000; 10 const MODAL_FADE_DURATION = 200; 11 const SETTINGS_SCROLL_DURATION = 300; 12 const ADVANCED_SETTINGS_FADE_DURATION = 300; 13 14 // Quick Edit functionality for editor choice column 15 if (typeof inlineEditPost !== 'undefined') { 16 // Save the original quick edit function 17 var $wp_inline_edit = inlineEditPost.edit; 18 19 // Override the quick edit function 20 inlineEditPost.edit = function(id) { 21 // Call the original function 22 $wp_inline_edit.apply(this, arguments); 23 24 // Get the post ID 25 var post_id = 0; 26 if (typeof(id) === 'object') { 27 post_id = parseInt(this.getId(id)); 28 } 29 30 if (post_id > 0) { 31 // Get the row 32 var $row = $('#post-' + post_id); 33 34 // Get the editor choice 35 var editor_choice = ''; 36 var $editor_icon = $row.find('td.editor_choice .dashicons'); 37 38 if ($editor_icon.hasClass('dashicons-editor-kitchensink')) { 39 editor_choice = 'classic'; 40 } else if ($editor_icon.hasClass('dashicons-block-default')) { 41 editor_choice = 'block'; 42 } else { 43 editor_choice = 'default'; 44 } 45 46 // Set the value in the quick edit form 47 var $edit_row = $('#edit-' + post_id); 48 $edit_row.find('select[name="ecew_editor_choice"]').val(editor_choice); 49 } 50 }; 51 } 52 5 53 // Toggle advanced settings visibility 6 54 $('#ecew_show_settings').on('change', function() { 7 55 if ($(this).is(':checked')) { 8 $('.advanced-settings').fadeIn( 300);56 $('.advanced-settings').fadeIn(ADVANCED_SETTINGS_FADE_DURATION); 9 57 } else { 10 $('.advanced-settings').fadeOut(300); 11 } 12 }); 13 14 // Reset defaults button 58 $('.advanced-settings').fadeOut(ADVANCED_SETTINGS_FADE_DURATION); 59 } 60 }); 61 62 // Per-Post Toggle is now independent of Advanced Settings 63 // No need to auto-enable Advanced Settings when Per-Post Toggle is checked 64 // Both features work independently in simple and advanced modes 65 66 // Handle dependency: Per-Post Toggle requires main plugin to be enabled 67 function updatePerPostToggleState() { 68 var $perPostToggle = $('#ecew_per_post_toggle'); 69 var $perPostRow = $perPostToggle.closest('tr'); 70 71 if (!$('#ecew_enabled').is(':checked')) { 72 // Main plugin is disabled, visually disable per-post toggle 73 // NOTE: We don't use .prop('disabled', true) because disabled fields 74 // are excluded from form submission, causing save bugs 75 $perPostRow.addClass('disabled-setting'); 76 77 // If it was checked, uncheck it 78 if ($perPostToggle.is(':checked')) { 79 $perPostToggle.prop('checked', false); 80 } 81 } else { 82 // Main plugin is enabled, enable per-post toggle 83 $perPostRow.removeClass('disabled-setting'); 84 } 85 } 86 87 // Handle dependency: Advanced Settings requires main plugin to be enabled 88 function updateAdvancedSettingsState() { 89 var $advancedToggle = $('#ecew_show_settings'); 90 var $advancedRow = $advancedToggle.closest('tr'); 91 92 if (!$('#ecew_enabled').is(':checked')) { 93 // Main plugin is disabled, visually disable advanced settings 94 // NOTE: We don't use .prop('disabled', true) because disabled fields 95 // are excluded from form submission, causing save bugs 96 $advancedRow.addClass('disabled-setting'); 97 98 // If it was checked, uncheck it and trigger change to hide sections 99 if ($advancedToggle.is(':checked')) { 100 $advancedToggle.prop('checked', false).trigger('change'); 101 } 102 } else { 103 // Main plugin is enabled, enable advanced settings 104 $advancedRow.removeClass('disabled-setting'); 105 } 106 } 107 108 // Run on page load 109 updatePerPostToggleState(); 110 updateAdvancedSettingsState(); 111 112 // Run when main toggle changes 113 $('#ecew_enabled').on('change', function() { 114 updatePerPostToggleState(); 115 updateAdvancedSettingsState(); 116 }); 117 118 // Toast notification function 119 function showToast(message, type) { 120 var $toast = $('<div class="ecew-toast ecew-toast-' + type + '">' + message + '</div>'); 121 $('body').append($toast); 122 123 setTimeout(function() { 124 $toast.addClass('show'); 125 }, TOAST_SHOW_DELAY); 126 127 setTimeout(function() { 128 $toast.removeClass('show'); 129 setTimeout(function() { 130 $toast.remove(); 131 }, TOAST_FADE_OUT_DELAY); 132 }, TOAST_AUTO_HIDE_DELAY); 133 } 134 135 // Unsaved changes detection 136 var formChanged = false; 137 var originalFormData = $('.classic-editor-plus-settings form').serialize(); 138 139 function updateUnsavedIndicator() { 140 if (formChanged) { 141 if ($('.unsaved-indicator').length === 0) { 142 $('.submit-buttons #submit').before('<span class="unsaved-indicator">● Unsaved changes</span>'); 143 } 144 } else { 145 $('.unsaved-indicator').remove(); 146 } 147 } 148 149 // Track form changes 150 $('.classic-editor-plus-settings form :input').on('change', function() { 151 var currentFormData = $('.classic-editor-plus-settings form').serialize(); 152 formChanged = (originalFormData !== currentFormData); 153 updateUnsavedIndicator(); 154 }); 155 156 // Warn on navigation if there are unsaved changes 157 $(window).on('beforeunload', function(e) { 158 if (formChanged) { 159 var message = ecewSettings.i18n.unsavedChanges; 160 e.returnValue = message; 161 return message; 162 } 163 }); 164 165 // Animated save button 166 $('.classic-editor-plus-settings form').on('submit', function(e) { 167 var $form = $(this); 168 var $submitBtn = $('#submit'); 169 var originalText = $submitBtn.val(); 170 171 // Disable button and show loading 172 $submitBtn.prop('disabled', true).val('Saving...').addClass('saving'); 173 174 // Clear the unsaved changes flag (form is being saved) 175 formChanged = false; 176 177 // Note: Form will submit normally, we just show the animation 178 // The page will reload, showing WordPress's success message 179 // We can't prevent default here because we need WordPress to save the settings 180 181 // Store that we're saving (for after page reload) with error handling 182 try { 183 sessionStorage.setItem('ecew_just_saved', 'true'); 184 } catch (e) { 185 // Silently fail if sessionStorage is not available (privacy mode, etc.) 186 } 187 }); 188 189 // Check if we just saved (after page reload) with error handling 190 var justSaved = false; 191 try { 192 justSaved = (sessionStorage.getItem('ecew_just_saved') === 'true'); 193 if (justSaved) { 194 sessionStorage.removeItem('ecew_just_saved'); 195 } 196 } catch (e) { 197 // Silently fail if sessionStorage is not available 198 } 199 200 if (justSaved) { 201 202 // Show success animation on the save button 203 var $submitBtn = $('#submit'); 204 var originalText = $submitBtn.val(); 205 206 $submitBtn.val('✓ Settings Saved!').addClass('saved'); 207 showToast(ecewSettings.i18n.settingsSaved, 'success'); 208 209 // Reset button after delay 210 setTimeout(function() { 211 $submitBtn.removeClass('saved').val(originalText); 212 }, BUTTON_RESET_DELAY); 213 214 // Scroll to top to show any messages 215 $('html, body').animate({ scrollTop: 0 }, SETTINGS_SCROLL_DURATION); 216 } 217 218 // Post Type/Role Selection Improvements 219 function updatePostTypeCount() { 220 var checked = $('input[name="ecew_settings[post_types][]"]:checked').length; 221 var total = $('input[name="ecew_settings[post_types][]"]').length; 222 $('.post-types-count').text(ecewSettings.i18n.postTypesSelected.replace('%d', checked).replace('%d', total)); 223 } 224 225 function updateRoleCount() { 226 var checked = $('input[name="ecew_settings[user_roles][]"]:checked').length; 227 var total = $('input[name="ecew_settings[user_roles][]"]').length; 228 $('.roles-count').text(ecewSettings.i18n.userRolesSelected.replace('%d', checked).replace('%d', total)); 229 } 230 231 // Select All / Deselect All for post types 232 $('.select-all-post-types').on('click', function() { 233 $('input[name="ecew_settings[post_types][]"]').prop('checked', true).trigger('change'); 234 updatePostTypeCount(); 235 }); 236 237 $('.deselect-all-post-types').on('click', function() { 238 $('input[name="ecew_settings[post_types][]"]').prop('checked', false).trigger('change'); 239 updatePostTypeCount(); 240 }); 241 242 // Update count when checkboxes change 243 $('input[name="ecew_settings[post_types][]"]').on('change', function() { 244 updatePostTypeCount(); 245 }); 246 247 // Select All / Deselect All for user roles 248 $('.select-all-roles').on('click', function() { 249 $('input[name="ecew_settings[user_roles][]"]').prop('checked', true).trigger('change'); 250 updateRoleCount(); 251 }); 252 253 $('.deselect-all-roles').on('click', function() { 254 $('input[name="ecew_settings[user_roles][]"]').prop('checked', false).trigger('change'); 255 updateRoleCount(); 256 }); 257 258 // Update count when checkboxes change 259 $('input[name="ecew_settings[user_roles][]"]').on('change', function() { 260 updateRoleCount(); 261 }); 262 263 // Reset defaults button with custom modal 15 264 $('#reset-defaults').on('click', function(e) { 16 265 e.preventDefault(); 17 18 if (confirm(ecewSettings.resetConfirmMessage)) { 266 267 // Create modal HTML with accessibility attributes 268 var modalHTML = ` 269 <div class="ecew-modal-overlay" role="dialog" aria-modal="true" aria-labelledby="ecew-modal-title"> 270 <div class="ecew-modal"> 271 <div class="ecew-modal-header"> 272 <h2 id="ecew-modal-title">Reset All Settings to Defaults?</h2> 273 </div> 274 <div class="ecew-modal-body"> 275 <p>This will reset all plugin settings to their default values:</p> 276 <ul> 277 <li><strong>Classic Editor:</strong> Enabled</li> 278 <li><strong>Advanced Settings:</strong> Disabled (Simple Mode)</li> 279 <li><strong>Per-Post Toggle:</strong> Enabled</li> 280 <li><strong>Classic Widgets:</strong> Enabled</li> 281 <li><strong>All post types:</strong> Selected</li> 282 <li><strong>All user roles:</strong> Selected</li> 283 </ul> 284 <p><strong>Note:</strong> Per-post editor preferences will not be affected.</p> 285 </div> 286 <div class="ecew-modal-footer"> 287 <button type="button" class="button ecew-modal-cancel" aria-label="Cancel reset">Cancel</button> 288 <button type="button" class="button button-primary button-danger ecew-modal-confirm" aria-label="Confirm reset">Reset All Settings</button> 289 </div> 290 </div> 291 </div> 292 `; 293 294 $('body').append(modalHTML); 295 $('.ecew-modal-overlay').fadeIn(MODAL_FADE_DURATION); 296 297 // Set focus to the confirm button for accessibility 298 $('.ecew-modal-confirm').focus(); 299 300 // Handle cancel (clicking cancel button or overlay) 301 $('.ecew-modal-cancel, .ecew-modal-overlay').on('click', function(e) { 302 if (e.target === this) { 303 $('.ecew-modal-overlay').fadeOut(MODAL_FADE_DURATION, function() { 304 $(this).remove(); 305 }); 306 } 307 }); 308 309 // Handle confirm 310 $('.ecew-modal-confirm').on('click', function() { 19 311 // Reset all form elements 20 $('#ecew_enabled').prop('checked', true) ;312 $('#ecew_enabled').prop('checked', true).trigger('change'); 21 313 $('#ecew_show_settings').prop('checked', false).trigger('change'); 22 314 $('#ecew_per_post_toggle').prop('checked', true); 23 $('#ecew_classic_widgets ').prop('checked', true);24 315 $('#ecew_classic_widgets_global').prop('checked', true); 316 25 317 // Check all post type checkboxes 26 318 $('input[name="ecew_settings[post_types][]"]').prop('checked', true); 27 319 updatePostTypeCount(); 320 28 321 // Check all role checkboxes 29 322 $('input[name="ecew_settings[user_roles][]"]').prop('checked', true); 30 } 323 updateRoleCount(); 324 325 // Close modal 326 $('.ecew-modal-overlay').fadeOut(MODAL_FADE_DURATION, function() { 327 $(this).remove(); 328 }); 329 330 // Show toast 331 showToast(ecewSettings.i18n.resetToDefaults, 'success'); 332 }); 31 333 }); 32 334 }); -
enable-classic-editor/trunk/classic-editor-admin.css
r3295733 r3392035 5 5 .classic-editor-plus-settings { 6 6 max-width: 950px; 7 } 8 9 /* Mode Indicator */ 10 .ecew-mode-indicator { 11 margin-bottom: 20px; 12 padding: 12px 15px; 13 border-left: 4px solid #dcdcde; 14 background-color: #f6f7f7; 15 border-radius: 4px; 16 } 17 18 .ecew-mode-indicator.advanced { 19 border-left-color: #2271b1; 20 background-color: #e7f3ff; 21 } 22 23 .ecew-mode-indicator.simple { 24 border-left-color: #7cb342; 25 background-color: #f0f5eb; 26 } 27 28 .mode-badge { 29 display: inline-block; 30 padding: 4px 12px; 31 border-radius: 3px; 32 font-weight: 600; 33 font-size: 12px; 34 text-transform: uppercase; 35 letter-spacing: 0.5px; 36 margin-bottom: 8px; 37 } 38 39 .ecew-mode-indicator.advanced .mode-badge { 40 background-color: #2271b1; 41 color: white; 42 } 43 44 .ecew-mode-indicator.simple .mode-badge { 45 background-color: #7cb342; 46 color: white; 47 } 48 49 .mode-description { 50 margin: 0; 51 color: #50575e; 52 font-size: 13px; 53 line-height: 1.5; 7 54 } 8 55 … … 162 209 flex: 0 0 100%; 163 210 } 164 211 165 212 .submit-buttons { 166 213 flex-direction: column; 167 214 } 168 215 169 216 .submit-buttons .button { 170 217 width: 100%; … … 172 219 } 173 220 } 221 222 /* Disabled setting style (for dependency management) */ 223 .classic-editor-plus-settings .form-table tr.disabled-setting { 224 opacity: 0.5; 225 pointer-events: none; 226 } 227 228 .classic-editor-plus-settings .form-table tr.disabled-setting th, 229 .classic-editor-plus-settings .form-table tr.disabled-setting td { 230 color: #a7aaad; 231 } 232 233 /* Save button states */ 234 .classic-editor-plus-settings #submit { 235 transition: all 0.3s ease; 236 min-width: 120px; 237 } 238 239 .classic-editor-plus-settings #submit.saving { 240 background: #2271b1; 241 border-color: #2271b1; 242 opacity: 0.8; 243 cursor: wait; 244 } 245 246 .classic-editor-plus-settings #submit.saved { 247 background: #00a32a !important; 248 border-color: #00a32a !important; 249 box-shadow: none !important; 250 } 251 252 .classic-editor-plus-settings #submit.error { 253 background: #d63638; 254 border-color: #d63638; 255 } 256 257 /* Toast notifications */ 258 .ecew-toast { 259 position: fixed; 260 top: 50px; 261 right: 20px; 262 background: white; 263 border-left: 4px solid #00a32a; 264 padding: 15px 20px; 265 box-shadow: 0 3px 10px rgba(0,0,0,0.2); 266 border-radius: 4px; 267 z-index: 999999; 268 transform: translateX(400px); 269 transition: transform 0.3s ease; 270 font-size: 14px; 271 font-weight: 500; 272 max-width: 350px; 273 } 274 275 .ecew-toast.show { 276 transform: translateX(0); 277 } 278 279 .ecew-toast.ecew-toast-error { 280 border-left-color: #d63638; 281 color: #d63638; 282 } 283 284 .ecew-toast.ecew-toast-warning { 285 border-left-color: #dba617; 286 color: #dba617; 287 } 288 289 .ecew-toast.ecew-toast-success { 290 border-left-color: #00a32a; 291 color: #1d2327; 292 } 293 294 /* Unsaved changes indicator */ 295 .unsaved-indicator { 296 color: #dba617; 297 margin-right: 10px; 298 font-size: 13px; 299 animation: pulse 2s infinite; 300 display: inline-block; 301 } 302 303 @keyframes pulse { 304 0%, 100% { opacity: 1; } 305 50% { opacity: 0.5; } 306 } 307 308 /* Modal overlay and dialog */ 309 .ecew-modal-overlay { 310 display: none; 311 position: fixed; 312 top: 0; 313 left: 0; 314 right: 0; 315 bottom: 0; 316 background: rgba(0, 0, 0, 0.7); 317 z-index: 999998; 318 align-items: center; 319 justify-content: center; 320 } 321 322 .ecew-modal { 323 background: white; 324 border-radius: 4px; 325 box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); 326 max-width: 550px; 327 width: 90%; 328 margin: 50px auto; 329 position: relative; 330 top: 50%; 331 transform: translateY(-50%); 332 } 333 334 .ecew-modal-header { 335 padding: 20px 24px; 336 border-bottom: 1px solid #dcdcde; 337 } 338 339 .ecew-modal-header h2 { 340 margin: 0; 341 font-size: 18px; 342 color: #1d2327; 343 } 344 345 .ecew-modal-body { 346 padding: 20px 24px; 347 color: #1d2327; 348 } 349 350 .ecew-modal-body p { 351 margin: 12px 0; 352 line-height: 1.6; 353 } 354 355 .ecew-modal-body ul { 356 margin: 15px 0; 357 padding-left: 25px; 358 } 359 360 .ecew-modal-body li { 361 margin: 10px 0; 362 line-height: 1.5; 363 } 364 365 .ecew-modal-footer { 366 padding: 15px 24px; 367 border-top: 1px solid #dcdcde; 368 text-align: right; 369 display: flex; 370 gap: 10px; 371 justify-content: flex-end; 372 background: #f6f7f7; 373 } 374 375 .button-danger { 376 background: #d63638 !important; 377 border-color: #d63638 !important; 378 color: white !important; 379 text-shadow: none !important; 380 } 381 382 .button-danger:hover, 383 .button-danger:focus { 384 background: #c92c2f !important; 385 border-color: #c92c2f !important; 386 color: white !important; 387 } 388 389 @media screen and (max-width: 600px) { 390 .ecew-modal { 391 width: 95%; 392 margin: 20px auto; 393 } 394 395 .ecew-modal-footer { 396 flex-direction: column; 397 } 398 399 .ecew-modal-footer .button { 400 width: 100%; 401 text-align: center; 402 } 403 } 404 405 /* Help tooltips */ 406 .ecew-help-tooltip { 407 position: relative; 408 display: inline-block; 409 cursor: help; 410 color: #787c82; 411 margin-left: 5px; 412 vertical-align: middle; 413 } 414 415 .ecew-help-tooltip .dashicons { 416 width: 16px; 417 height: 16px; 418 font-size: 16px; 419 } 420 421 .ecew-help-tooltip:hover { 422 color: #2271b1; 423 } 424 425 .ecew-help-tooltip::after { 426 content: attr(data-tooltip); 427 position: absolute; 428 bottom: 125%; 429 left: 50%; 430 transform: translateX(-50%); 431 padding: 10px 14px; 432 background: #1d2327; 433 color: white; 434 font-size: 13px; 435 line-height: 1.5; 436 border-radius: 4px; 437 white-space: normal; 438 width: 280px; 439 max-width: 280px; 440 opacity: 0; 441 pointer-events: none; 442 transition: opacity 0.2s ease; 443 z-index: 10000; 444 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); 445 text-align: left; 446 } 447 448 .ecew-help-tooltip::before { 449 content: ''; 450 position: absolute; 451 bottom: 115%; 452 left: 50%; 453 transform: translateX(-50%); 454 border: 6px solid transparent; 455 border-top-color: #1d2327; 456 opacity: 0; 457 pointer-events: none; 458 transition: opacity 0.2s ease; 459 z-index: 10000; 460 } 461 462 .ecew-help-tooltip:hover::after, 463 .ecew-help-tooltip:hover::before { 464 opacity: 1; 465 } 466 467 @media screen and (max-width: 782px) { 468 .ecew-help-tooltip::after { 469 width: 220px; 470 max-width: 220px; 471 } 472 } -
enable-classic-editor/trunk/enable-classic-editor.php
r3301448 r3392035 4 4 Plugin URI: https://www.ayonm.com 5 5 Description: A simple & lightweight plugin to enable the classic editor on WordPress with advanced configuration options. 6 Version: 3. 16 Version: 3.2 7 7 Author: ayonm 8 8 Author URI: https://www.ayonm.com … … 25 25 */ 26 26 27 defined( 'ABSPATH' ) || die( 'No Entry!' ); 27 defined( 'ABSPATH' ) || die( 'No Entry!' ); 28 29 // Define plugin constants 30 if (!defined('ECEW_VERSION')) { 31 define('ECEW_VERSION', '3.4'); 32 } 33 if (!defined('ECEW_PLUGIN_DIR')) { 34 define('ECEW_PLUGIN_DIR', plugin_dir_path(__FILE__)); 35 } 36 if (!defined('ECEW_PLUGIN_URL')) { 37 define('ECEW_PLUGIN_URL', plugin_dir_url(__FILE__)); 38 } 39 if (!defined('ECEW_TEXT_DOMAIN')) { 40 define('ECEW_TEXT_DOMAIN', 'enable-classic-editor'); 41 } 28 42 29 43 /** … … 42 56 43 57 /** 58 * Cached current user for performance 59 */ 60 private $current_user_cache = null; 61 62 /** 44 63 * Get plugin instance 45 64 */ … … 55 74 */ 56 75 private function __construct() { 57 // Get plugin settings or use defaults76 // Get plugin settings with safe defaults (no function calls that may not be available yet) 58 77 $this->settings = get_option('ecew_settings', array( 59 78 'enabled' => true, 60 'post_types' => array _keys(get_post_types(array('public' => true), 'names')),61 'user_roles' => array _keys(wp_roles()->roles),79 'post_types' => array(), // Will be populated with actual post types if empty 80 'user_roles' => array(), // Will be populated with actual roles if empty 62 81 'use_classic_widgets' => true, 63 82 'show_settings_page' => false, … … 65 84 )); 66 85 86 // Populate empty post_types and user_roles with safe defaults 87 if (empty($this->settings['post_types']) && function_exists('get_post_types')) { 88 $this->settings['post_types'] = array_keys(get_post_types(array('public' => true), 'names')); 89 } 90 if (empty($this->settings['user_roles']) && function_exists('wp_roles')) { 91 $this->settings['user_roles'] = array_keys(wp_roles()->roles); 92 } 93 67 94 // Initialize plugin 68 95 $this->init(); … … 75 102 // Legacy mode - if settings page is not enabled, use the original simple behavior 76 103 if (empty($this->settings['show_settings_page'])) { 77 add_filter('use_block_editor_for_post', '__return_false'); 78 add_action('after_setup_theme', array($this, 'disable_block_widgets')); 104 // In simple mode, check per-post overrides if enabled, otherwise default to classic 105 if (!empty($this->settings['allow_per_post_toggle'])) { 106 add_filter('use_block_editor_for_post', array($this, 'disable_gutenberg_for_post_simple_mode'), 10, 2); 107 } else { 108 // Use a callback that checks enabled state instead of __return_false 109 add_filter('use_block_editor_for_post', array($this, 'disable_gutenberg_simple_mode_no_toggle'), 10, 2); 110 } 79 111 } else { 80 112 // Advanced mode - use settings to determine behavior 81 113 add_filter('use_block_editor_for_post', array($this, 'disable_gutenberg_for_post'), 10, 2); 82 114 add_filter('use_block_editor_for_post_type', array($this, 'disable_gutenberg_for_post_type'), 10, 2); 83 84 if (!empty($this->settings['use_classic_widgets'])) { 85 add_action('after_setup_theme', array($this, 'disable_block_widgets')); 86 } 87 88 // Add per-post toggle if enabled 89 if (!empty($this->settings['allow_per_post_toggle'])) { 90 // Add meta box to post edit screen 91 add_action('add_meta_boxes', array($this, 'add_editor_choice_meta_box')); 92 // Save post meta 93 add_action('save_post', array($this, 'save_editor_choice')); 94 // Add column to post list 95 add_filter('manage_posts_columns', array($this, 'add_editor_column')); 96 add_filter('manage_pages_columns', array($this, 'add_editor_column')); 97 add_action('manage_posts_custom_column', array($this, 'display_editor_column'), 10, 2); 98 add_action('manage_pages_custom_column', array($this, 'display_editor_column'), 10, 2); 99 // Add quick edit option 100 add_action('quick_edit_custom_box', array($this, 'add_quick_edit_field'), 10, 2); 101 add_action('admin_footer', array($this, 'quick_edit_javascript')); 102 } 103 } 104 115 } 116 117 // Classic Widgets toggle is now independent - works in both simple and advanced modes 118 // Only disable block widgets if the setting is enabled 119 if (!empty($this->settings['use_classic_widgets'])) { 120 add_action('after_setup_theme', array($this, 'disable_block_widgets')); 121 } 122 123 // Per-post toggle is now independent of advanced settings 124 // It works in both simple and advanced modes 125 // BUT it requires the main plugin to be enabled to have any effect 126 if (!empty($this->settings['allow_per_post_toggle']) && !empty($this->settings['enabled'])) { 127 // Add meta box to post edit screen 128 add_action('add_meta_boxes', array($this, 'add_editor_choice_meta_box')); 129 // Save post meta 130 add_action('save_post', array($this, 'save_editor_choice')); 131 // Add column to post list 132 add_filter('manage_posts_columns', array($this, 'add_editor_column')); 133 add_filter('manage_pages_columns', array($this, 'add_editor_column')); 134 add_action('manage_posts_custom_column', array($this, 'display_editor_column'), 10, 2); 135 add_action('manage_pages_custom_column', array($this, 'display_editor_column'), 10, 2); 136 // Add quick edit option 137 add_action('quick_edit_custom_box', array($this, 'add_quick_edit_field'), 10, 2); 138 add_action('admin_enqueue_scripts', array($this, 'quick_edit_javascript')); 139 } 140 105 141 // Always add settings page and links 106 142 add_action('admin_menu', array($this, 'add_settings_page')); 107 143 add_action('admin_init', array($this, 'register_settings')); 108 144 add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_styles')); 109 145 110 146 // Add settings link to plugins page 111 147 add_filter('plugin_action_links_' . plugin_basename(__FILE__), array($this, 'add_settings_link')); … … 120 156 121 157 /** 122 * Check if post should use classic editor based on post meta 123 */ 124 public function disable_gutenberg_for_post($use_block_editor, $post) { 158 * Simple mode without per-post toggle - always use classic editor if plugin is enabled 159 */ 160 public function disable_gutenberg_simple_mode_no_toggle($use_block_editor, $post) { 161 // If classic editor is not enabled, don't change the status 162 if (empty($this->settings['enabled'])) { 163 return $use_block_editor; 164 } 165 166 // Plugin is enabled, use classic editor 167 return false; 168 } 169 170 /** 171 * Handle per-post overrides in simple mode 172 * In simple mode, classic editor is default but per-post toggle allows overrides 173 */ 174 public function disable_gutenberg_for_post_simple_mode($use_block_editor, $post) { 175 // If classic editor is not enabled, don't change the status 176 if (empty($this->settings['enabled'])) { 177 return $use_block_editor; 178 } 179 125 180 // Check if we have a post-specific setting 126 181 $editor_choice = get_post_meta($post->ID, '_ecew_editor_choice', true); 127 182 128 183 if ($editor_choice === 'block') { 129 184 // Post explicitly wants to use block editor … … 133 188 return false; 134 189 } 135 136 // No post-specific setting, use post type setting 190 191 // No post-specific setting, default to classic editor in simple mode 192 return false; 193 } 194 195 /** 196 * Check if post should use classic editor based on post meta 197 */ 198 public function disable_gutenberg_for_post($use_block_editor, $post) { 199 // If classic editor is not enabled, don't change the status 200 if (empty($this->settings['enabled'])) { 201 return $use_block_editor; 202 } 203 204 // Check if we have a post-specific setting (only if per-post toggle is enabled) 205 if (!empty($this->settings['allow_per_post_toggle'])) { 206 $editor_choice = get_post_meta($post->ID, '_ecew_editor_choice', true); 207 208 if ($editor_choice === 'block') { 209 // Post explicitly wants to use block editor 210 return true; 211 } elseif ($editor_choice === 'classic') { 212 // Post explicitly wants to use classic editor 213 return false; 214 } 215 } 216 217 // No post-specific setting, use post type setting (advanced mode only) 218 // In simple mode with per-post toggle, we already return false in init() 137 219 return $this->disable_gutenberg_for_post_type($use_block_editor, $post->post_type); 138 220 } … … 188 270 // Add nonce for security 189 271 wp_nonce_field('ecew_editor_choice_nonce', 'ecew_editor_choice_nonce'); 190 272 191 273 // Get current value 192 274 $editor_choice = get_post_meta($post->ID, '_ecew_editor_choice', true); 193 275 194 276 // Default to post type setting if not set 195 277 if (empty($editor_choice)) { 196 278 $editor_choice = 'default'; 197 279 } 280 281 // Determine what "default" means for this post 282 $default_editor = $this->get_actual_editor_for_post($post); 283 $default_editor_label = $default_editor === 'classic' ? __('Classic Editor', 'enable-classic-editor') : __('Block Editor', 'enable-classic-editor'); 198 284 ?> 199 285 <p> … … 201 287 <input type="radio" name="ecew_editor_choice" value="default" <?php checked($editor_choice, 'default'); ?>> 202 288 <?php _e('Use default setting', 'enable-classic-editor'); ?> 289 <span class="description">(<?php echo esc_html($default_editor_label); ?>)</span> 203 290 </label> 204 291 </p> … … 225 312 */ 226 313 public function save_editor_choice($post_id) { 227 // Check if nonce is set228 if (!isset($_POST['ecew_editor_choice_nonce'])) {229 return;230 }231 232 // Verify nonce233 if (!wp_verify_nonce($_POST['ecew_editor_choice_nonce'], 'ecew_editor_choice_nonce')) {234 return;235 }236 237 314 // Check if autosave 238 315 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { 239 316 return; 240 317 } 241 318 242 319 // Check permissions 243 320 if (!current_user_can('edit_post', $post_id)) { 244 321 return; 245 322 } 246 323 324 // Determine if this is a quick edit or meta box save 325 $is_quick_edit = isset($_POST['_inline_edit']); 326 $is_meta_box = isset($_POST['ecew_editor_choice_nonce']); 327 328 // Verify nonces based on the save type 329 if ($is_quick_edit) { 330 // Quick edit uses WordPress's built-in nonce 331 if (!check_ajax_referer('inlineeditnonce', '_inline_edit', false)) { 332 return; 333 } 334 } elseif ($is_meta_box) { 335 // Meta box uses our custom nonce 336 if (!wp_verify_nonce($_POST['ecew_editor_choice_nonce'], 'ecew_editor_choice_nonce')) { 337 return; 338 } 339 } else { 340 // No valid nonce found, exit 341 return; 342 } 343 247 344 // Save editor choice 248 345 if (isset($_POST['ecew_editor_choice'])) { … … 276 373 return; 277 374 } 278 375 279 376 $editor_choice = get_post_meta($post_id, '_ecew_editor_choice', true); 280 377 $post = get_post($post_id); 378 379 // Determine actual editor that will be used 380 $actual_editor = $this->get_actual_editor_for_post($post); 381 281 382 switch ($editor_choice) { 282 383 case 'classic': 283 echo '<span class="dashicons dashicons-editor-kitchensink" title="' . esc_attr__('Classic Editor ', 'enable-classic-editor') . '"></span>';384 echo '<span class="dashicons dashicons-editor-kitchensink" title="' . esc_attr__('Classic Editor (Forced)', 'enable-classic-editor') . '" style="color: #2271b1;"></span>'; 284 385 break; 285 386 case 'block': 286 echo '<span class="dashicons dashicons-block-default" title="' . esc_attr__('Block Editor ', 'enable-classic-editor') . '"></span>';387 echo '<span class="dashicons dashicons-block-default" title="' . esc_attr__('Block Editor (Forced)', 'enable-classic-editor') . '" style="color: #2271b1;"></span>'; 287 388 break; 288 389 default: 289 echo '<span class="dashicons dashicons-admin-generic" title="' . esc_attr__('Default Editor', 'enable-classic-editor') . '"></span>'; 390 // Show the actual editor that will be used 391 $icon = $actual_editor === 'classic' ? 'editor-kitchensink' : 'block-default'; 392 $editor_name = $actual_editor === 'classic' ? __('Classic Editor', 'enable-classic-editor') : __('Block Editor', 'enable-classic-editor'); 393 $title = sprintf( 394 __('Default (%s)', 'enable-classic-editor'), 395 $editor_name 396 ); 397 echo '<span class="dashicons dashicons-' . esc_attr($icon) . '" title="' . esc_attr($title) . '" style="opacity: 0.6;"></span>'; 290 398 break; 291 399 } … … 316 424 317 425 /** 318 * Add JavaScript for quick edit426 * Enqueue JavaScript for quick edit on post list screens 319 427 */ 320 428 public function quick_edit_javascript() { 321 429 $screen = get_current_screen(); 322 430 323 431 if (!$screen || !in_array($screen->base, array('edit', 'edit-tags'))) { 324 432 return; 325 433 } 326 ?> 327 <script type="text/javascript"> 328 jQuery(document).ready(function($) { 329 // Save the original quick edit function 330 var $wp_inline_edit = inlineEditPost.edit; 331 332 // Override the quick edit function 333 inlineEditPost.edit = function(id) { 334 // Call the original function 335 $wp_inline_edit.apply(this, arguments); 336 337 // Get the post ID 338 var post_id = 0; 339 if (typeof(id) === 'object') { 340 post_id = parseInt(this.getId(id)); 341 } 342 343 if (post_id > 0) { 344 // Get the row 345 var $row = $('#post-' + post_id); 346 347 // Get the editor choice 348 var editor_choice = ''; 349 var $editor_icon = $row.find('td.editor_choice .dashicons'); 350 351 if ($editor_icon.hasClass('dashicons-editor-kitchensink')) { 352 editor_choice = 'classic'; 353 } else if ($editor_icon.hasClass('dashicons-block-default')) { 354 editor_choice = 'block'; 355 } else { 356 editor_choice = 'default'; 357 } 358 359 // Set the value in the quick edit form 360 var $edit_row = $('#edit-' + post_id); 361 $edit_row.find('select[name="ecew_editor_choice"]').val(editor_choice); 362 } 363 }; 364 }); 365 </script> 366 <?php 434 435 // Check if user has capability to edit posts 436 if (!current_user_can('edit_posts')) { 437 return; 438 } 439 440 // Enqueue the admin.js file which contains the quick edit functionality 441 wp_enqueue_script( 442 'classic-editor-admin-js', 443 ECEW_PLUGIN_URL . 'assets/js/admin.js', 444 array('jquery', 'inline-edit-post'), 445 ECEW_VERSION, 446 true 447 ); 367 448 } 368 449 … … 408 489 public function sanitize_settings($input) { 409 490 $sanitized_input = array(); 410 491 411 492 // Sanitize enabled status 412 493 $sanitized_input['enabled'] = isset($input['enabled']) ? 1 : 0; 413 414 // Sanitize post types 494 495 // Sanitize post types with validation against actual registered post types 415 496 if (isset($input['post_types']) && is_array($input['post_types'])) { 416 $sanitized_input['post_types'] = array_map('sanitize_text_field', $input['post_types']); 497 $valid_post_types = array_keys(get_post_types(array('public' => true), 'names')); 498 $sanitized_input['post_types'] = array_intersect( 499 array_map('sanitize_text_field', $input['post_types']), 500 $valid_post_types 501 ); 417 502 } else { 418 503 $sanitized_input['post_types'] = array(); 419 504 } 420 421 // Sanitize user roles 505 506 // Sanitize user roles with validation against actual registered roles 422 507 if (isset($input['user_roles']) && is_array($input['user_roles'])) { 423 $sanitized_input['user_roles'] = array_map('sanitize_text_field', $input['user_roles']); 508 $valid_roles = array_keys(wp_roles()->roles); 509 $sanitized_input['user_roles'] = array_intersect( 510 array_map('sanitize_text_field', $input['user_roles']), 511 $valid_roles 512 ); 424 513 } else { 425 514 $sanitized_input['user_roles'] = array(); 426 515 } 427 516 428 517 // Sanitize classic widgets toggle 429 518 $sanitized_input['use_classic_widgets'] = isset($input['use_classic_widgets']) ? 1 : 0; 430 431 // Sanitize settings page toggle 519 520 // Sanitize settings page toggle (Advanced Settings) 432 521 $sanitized_input['show_settings_page'] = isset($input['show_settings_page']) ? 1 : 0; 433 522 434 523 // Sanitize per-post toggle 435 524 $sanitized_input['allow_per_post_toggle'] = isset($input['allow_per_post_toggle']) ? 1 : 0; 436 525 526 // Enforce dependencies: If main plugin is disabled, force dependent features OFF 527 // This ensures data integrity regardless of JavaScript state or disabled form fields 528 if (empty($sanitized_input['enabled'])) { 529 $sanitized_input['allow_per_post_toggle'] = 0; 530 $sanitized_input['show_settings_page'] = 0; 531 } 532 533 // Store last saved timestamp 534 update_option('ecew_settings_last_saved', current_time('timestamp')); 535 437 536 return $sanitized_input; 438 537 } … … 448 547 wp_enqueue_style( 449 548 'classic-editor-admin', 450 plugin_dir_url(__FILE__) . 'classic-editor-admin.css', 451 array() 549 ECEW_PLUGIN_URL . 'classic-editor-admin.css', 550 array(), 551 ECEW_VERSION 452 552 ); 453 553 … … 455 555 wp_enqueue_script( 456 556 'classic-editor-admin-js', 457 plugin_dir_url(__FILE__). 'assets/js/admin.js',557 ECEW_PLUGIN_URL . 'assets/js/admin.js', 458 558 array('jquery'), 459 null,559 ECEW_VERSION, 460 560 true 461 561 ); 462 562 463 // Pass settings to JavaScript563 // Pass translatable strings and settings to JavaScript 464 564 wp_localize_script( 465 565 'classic-editor-admin-js', 466 566 'ecewSettings', 467 567 array( 468 'resetConfirmMessage' => __('Are you sure you want to reset all settings to default values?', 'enable-classic-editor') 568 // Legacy setting (kept for compatibility) 569 'resetConfirmMessage' => __('Are you sure you want to reset all settings to default values?', ECEW_TEXT_DOMAIN), 570 571 // Translatable strings for admin.js 572 'i18n' => array( 573 'unsavedChanges' => __('You have unsaved changes. Leave anyway?', ECEW_TEXT_DOMAIN), 574 'postTypesSelected' => __('%d of %d post types selected', ECEW_TEXT_DOMAIN), 575 'userRolesSelected' => __('%d of %d user roles selected', ECEW_TEXT_DOMAIN), 576 'settingsSaved' => __('Settings saved successfully!', ECEW_TEXT_DOMAIN), 577 'resetToDefaults' => __('Settings reset to defaults. Click "Save Settings" to apply.', ECEW_TEXT_DOMAIN) 578 ) 469 579 ) 470 580 ); … … 481 591 482 592 /** 593 * Helper function to output help tooltip 594 */ 595 private function help_tooltip($text) { 596 $tooltip_id = 'ecew-tooltip-' . md5($text); 597 ?> 598 <span class="ecew-help-tooltip" 599 data-tooltip="<?php echo esc_attr($text); ?>" 600 tabindex="0" 601 role="button" 602 aria-label="<?php echo esc_attr__('Help', ECEW_TEXT_DOMAIN); ?>" 603 aria-describedby="<?php echo esc_attr($tooltip_id); ?>"> 604 <span class="dashicons dashicons-editor-help"></span> 605 <span id="<?php echo esc_attr($tooltip_id); ?>" class="screen-reader-text"><?php echo esc_html($text); ?></span> 606 </span> 607 <?php 608 } 609 610 /** 611 * Helper to determine actual editor for a post 612 * This is what will actually be used when "Default" is selected 613 */ 614 private function get_actual_editor_for_post($post) { 615 // If plugin is disabled, WordPress default is Block Editor 616 if (empty($this->settings['enabled'])) { 617 return 'block'; 618 } 619 620 // Simple mode - Classic Editor for everything 621 if (empty($this->settings['show_settings_page'])) { 622 return 'classic'; 623 } 624 625 // Advanced mode - check post type and user role 626 $post_type = is_object($post) ? $post->post_type : get_post_type($post); 627 628 // Cache current user for performance (avoids multiple wp_get_current_user() calls) 629 if ($this->current_user_cache === null) { 630 $this->current_user_cache = wp_get_current_user(); 631 } 632 633 $post_type_enabled = in_array($post_type, $this->settings['post_types']); 634 $user_role_enabled = !empty(array_intersect($this->current_user_cache->roles, $this->settings['user_roles'])); 635 636 return ($post_type_enabled && $user_role_enabled) ? 'classic' : 'block'; 637 } 638 639 /** 640 * Get validation warnings for current settings 641 */ 642 private function get_settings_warnings() { 643 $warnings = array(); 644 645 // Check if plugin is disabled 646 if (empty($this->settings['enabled'])) { 647 $warnings[] = array( 648 'type' => 'info', 649 'message' => __('Classic Editor is currently disabled. WordPress will use the Block Editor by default.', 'enable-classic-editor') 650 ); 651 } 652 653 // Check Advanced Mode with no selections 654 if (!empty($this->settings['show_settings_page']) && !empty($this->settings['enabled'])) { 655 if (empty($this->settings['post_types'])) { 656 $warnings[] = array( 657 'type' => 'warning', 658 'message' => __('Advanced Mode is enabled but no post types are selected. Classic Editor will not be applied to any content.', ECEW_TEXT_DOMAIN) 659 ); 660 } 661 if (empty($this->settings['user_roles'])) { 662 $warnings[] = array( 663 'type' => 'warning', 664 'message' => __('Advanced Mode is enabled but no user roles are selected. Classic Editor will not be applied to any users.', ECEW_TEXT_DOMAIN) 665 ); 666 } 667 668 // Check if per-post toggle is enabled with Advanced Mode 669 if (!empty($this->settings['allow_per_post_toggle'])) { 670 $warnings[] = array( 671 'type' => 'info', 672 'message' => __('Per-Post Toggle is enabled in Advanced Mode. Individual post editor preferences can override Post Type and User Role restrictions. Consider disabling Per-Post Toggle if you want strict role-based control.', ECEW_TEXT_DOMAIN) 673 ); 674 } 675 } 676 677 return $warnings; 678 } 679 680 /** 681 * Render mode indicator section 682 */ 683 private function render_mode_indicator($is_advanced_mode) { 684 $current_mode = $is_advanced_mode ? __('Advanced Mode', ECEW_TEXT_DOMAIN) : __('Simple Mode', ECEW_TEXT_DOMAIN); 685 ?> 686 <div class="ecew-mode-indicator <?php echo esc_attr($is_advanced_mode ? 'advanced' : 'simple'); ?>"> 687 <span class="mode-badge"><?php echo esc_html($current_mode); ?></span> 688 <p class="mode-description"> 689 <?php if ($is_advanced_mode): ?> 690 <?php _e('You are using Advanced Mode. Configure specific post types and user roles.', ECEW_TEXT_DOMAIN); ?> 691 <?php else: ?> 692 <?php _e('You are using Simple Mode. Classic editor is enabled for all content. Enable "Advanced Settings" for granular control.', ECEW_TEXT_DOMAIN); ?> 693 <?php endif; ?> 694 </p> 695 </div> 696 <?php 697 } 698 699 /** 700 * Render validation warnings 701 */ 702 private function render_validation_warnings() { 703 $warnings = $this->get_settings_warnings(); 704 if (empty($warnings)) { 705 return; 706 } 707 708 foreach ($warnings as $warning): 709 $notice_class = $warning['type'] === 'warning' ? 'notice-warning' : 'notice-info'; 710 ?> 711 <div class="notice <?php echo esc_attr($notice_class); ?> inline"> 712 <p><?php echo esc_html($warning['message']); ?></p> 713 </div> 714 <?php 715 endforeach; 716 } 717 718 /** 719 * Render global settings section 720 */ 721 private function render_global_settings_section() { 722 ?> 723 <div class="postbox"> 724 <h2 class="hndle"><span><?php _e('Global Settings', ECEW_TEXT_DOMAIN); ?></span></h2> 725 <div class="inside"> 726 <table class="form-table"> 727 <tbody> 728 <tr> 729 <th scope="row"> 730 <label for="ecew_enabled"> 731 <?php _e('Enable Classic Editor', ECEW_TEXT_DOMAIN); ?> 732 <?php $this->help_tooltip(__('When enabled, WordPress will use the Classic Editor instead of the Block Editor (Gutenberg) based on your configuration below.', ECEW_TEXT_DOMAIN)); ?> 733 </label> 734 </th> 735 <td> 736 <label class="toggle-switch" for="ecew_enabled" aria-label="<?php esc_attr_e('Toggle Classic Editor', ECEW_TEXT_DOMAIN); ?>"> 737 <input type="checkbox" 738 id="ecew_enabled" 739 name="ecew_settings[enabled]" 740 value="1" 741 <?php checked(!empty($this->settings['enabled'])); ?>> 742 <span class="slider round"></span> 743 </label> 744 <p class="description"> 745 <?php _e('Uncheck to use Block Editor as the default editor.', ECEW_TEXT_DOMAIN); ?> 746 </p> 747 </td> 748 </tr> 749 <tr> 750 <th scope="row"> 751 <label for="ecew_show_settings"> 752 <?php _e('Advanced Settings', ECEW_TEXT_DOMAIN); ?> 753 <?php $this->help_tooltip(__('Enable this to configure Classic Editor by specific post types and user roles. When disabled, Classic Editor is enabled for all content (Simple Mode).', ECEW_TEXT_DOMAIN)); ?> 754 </label> 755 </th> 756 <td> 757 <label class="toggle-switch" for="ecew_show_settings" aria-label="<?php esc_attr_e('Toggle Advanced Settings', ECEW_TEXT_DOMAIN); ?>"> 758 <input type="checkbox" 759 id="ecew_show_settings" 760 name="ecew_settings[show_settings_page]" 761 value="1" 762 <?php checked(!empty($this->settings['show_settings_page'])); ?> 763 <?php disabled(empty($this->settings['enabled'])); ?>> 764 <span class="slider round"></span> 765 </label> 766 <p class="description"> 767 <?php _e('Enable to configure the classic editor by specific post types and user roles. When disabled, the plugin uses the classic editor for all content and users (Simple Mode).', ECEW_TEXT_DOMAIN); ?> 768 <?php if (empty($this->settings['enabled'])): ?> 769 <br><strong style="color: #d63638;">⚠️ <?php _e('Note: Advanced Settings requires "Enable Classic Editor" to be ON.', ECEW_TEXT_DOMAIN); ?></strong> 770 <?php endif; ?> 771 </p> 772 </td> 773 </tr> 774 <tr> 775 <th scope="row"> 776 <label for="ecew_classic_widgets_global"> 777 <?php _e('Classic Widgets', ECEW_TEXT_DOMAIN); ?> 778 <?php $this->help_tooltip(__('Restores the traditional widgets interface from before WordPress 5.8. This is independent of the editor settings and works in both Simple and Advanced modes.', ECEW_TEXT_DOMAIN)); ?> 779 </label> 780 </th> 781 <td> 782 <label class="toggle-switch" for="ecew_classic_widgets_global" aria-label="<?php esc_attr_e('Toggle Classic Widgets', ECEW_TEXT_DOMAIN); ?>"> 783 <input type="checkbox" 784 id="ecew_classic_widgets_global" 785 name="ecew_settings[use_classic_widgets]" 786 value="1" 787 <?php checked(!empty($this->settings['use_classic_widgets'])); ?>> 788 <span class="slider round"></span> 789 </label> 790 <p class="description"> 791 <?php _e('Use Classic Widgets interface instead of block-based widgets (applies in all modes).', ECEW_TEXT_DOMAIN); ?> 792 <br> 793 <em style="color: #646970; font-size: 12px;"> 794 <?php _e('Note: This setting only applies to themes that support widgets. Most themes include widget areas, but some modern block themes may not have widget support.', ECEW_TEXT_DOMAIN); ?> 795 </em> 796 </p> 797 </td> 798 </tr> 799 <tr> 800 <th scope="row"> 801 <label for="ecew_per_post_toggle"> 802 <?php _e('Per-Post Toggle', ECEW_TEXT_DOMAIN); ?> 803 <?php $this->help_tooltip(__('Adds a meta box to each post/page edit screen allowing you to override the default editor choice for that specific post. Works in both Simple and Advanced modes. Priority: Per-post settings override Advanced Settings (Post Type & User Role).', ECEW_TEXT_DOMAIN)); ?> 804 </label> 805 </th> 806 <td> 807 <label class="toggle-switch" for="ecew_per_post_toggle" aria-label="<?php esc_attr_e('Toggle Per-Post Editor Selection', ECEW_TEXT_DOMAIN); ?>"> 808 <input type="checkbox" 809 id="ecew_per_post_toggle" 810 name="ecew_settings[allow_per_post_toggle]" 811 value="1" 812 <?php checked(!empty($this->settings['allow_per_post_toggle'])); ?> 813 <?php disabled(empty($this->settings['enabled'])); ?>> 814 <span class="slider round"></span> 815 </label> 816 <p class="description"> 817 <?php _e('Allows you to choose which editor (Classic or Block) to use for individual posts/pages. A meta box will appear on post edit screens. Works in both simple and advanced modes.', ECEW_TEXT_DOMAIN); ?> 818 <?php if (empty($this->settings['enabled'])): ?> 819 <br><strong style="color: #d63638;">⚠️ <?php _e('Note: This feature requires "Enable Classic Editor" to be ON.', ECEW_TEXT_DOMAIN); ?></strong> 820 <?php endif; ?> 821 <?php if (!empty($this->settings['show_settings_page'])): ?> 822 <br><strong style="color: #d63638;">⚠️ <?php _e('Important: Per-post overrides take precedence over Advanced Settings (Post Type and User Role restrictions).', ECEW_TEXT_DOMAIN); ?></strong> 823 <?php endif; ?> 824 </p> 825 </td> 826 </tr> 827 </tbody> 828 </table> 829 </div> 830 </div> 831 <?php 832 } 833 834 /** 835 * Render post type control section 836 */ 837 private function render_post_type_control_section($post_types) { 838 ?> 839 <div class="postbox"> 840 <h2 class="hndle"><span><?php _e('Post Type Control', ECEW_TEXT_DOMAIN); ?></span></h2> 841 <div class="inside"> 842 <?php if (!empty($this->settings['allow_per_post_toggle'])): ?> 843 <div class="notice notice-info inline" style="margin: 0 0 15px 0; padding: 8px 12px;"> 844 <p style="margin: 0.5em 0;"> 845 <span class="dashicons dashicons-info" style="color: #2271b1;"></span> 846 <strong><?php _e('Note:', ECEW_TEXT_DOMAIN); ?></strong> 847 <?php _e('Per-Post Toggle is enabled. Individual post editor preferences will override the Post Type and User Role settings below.', ECEW_TEXT_DOMAIN); ?> 848 </p> 849 </div> 850 <?php endif; ?> 851 <div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 15px; gap: 15px;"> 852 <p class="description" style="margin: 0; flex: 1;"> 853 <?php _e('Select which post types should use the Classic Editor instead of Gutenberg.', ECEW_TEXT_DOMAIN); ?> 854 </p> 855 <div class="selection-controls" style="display: flex; gap: 8px; flex-shrink: 0;"> 856 <button type="button" class="button button-small select-all-post-types"><?php _e('Select All', ECEW_TEXT_DOMAIN); ?></button> 857 <button type="button" class="button button-small deselect-all-post-types"><?php _e('Deselect All', ECEW_TEXT_DOMAIN); ?></button> 858 </div> 859 </div> 860 <div class="selection-count" style="margin-bottom: 12px; font-size: 13px; color: #646970;"> 861 <span class="post-types-count"> 862 <?php 863 $selected_count = count($this->settings['post_types']); 864 $total_count = count($post_types); 865 printf(__('%d of %d post types selected', ECEW_TEXT_DOMAIN), $selected_count, $total_count); 866 ?> 867 </span> 868 </div> 869 <div class="post-type-checkboxes"> 870 <?php foreach ($post_types as $post_type) : ?> 871 <div class="checkbox-item"> 872 <label for="ecew_post_type_<?php echo esc_attr($post_type->name); ?>"> 873 <input type="checkbox" 874 id="ecew_post_type_<?php echo esc_attr($post_type->name); ?>" 875 name="ecew_settings[post_types][]" 876 value="<?php echo esc_attr($post_type->name); ?>" 877 <?php checked(in_array($post_type->name, $this->settings['post_types'])); ?>> 878 <?php echo esc_html($post_type->label); ?> 879 </label> 880 </div> 881 <?php endforeach; ?> 882 </div> 883 </div> 884 </div> 885 <?php 886 } 887 888 /** 889 * Render user role control section 890 */ 891 private function render_user_role_control_section($roles) { 892 ?> 893 <div class="postbox"> 894 <h2 class="hndle"><span><?php _e('User Role Control', ECEW_TEXT_DOMAIN); ?></span></h2> 895 <div class="inside"> 896 <div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 15px; gap: 15px;"> 897 <p class="description" style="margin: 0; flex: 1;"> 898 <?php _e('Select which user roles should use the Classic Editor instead of Gutenberg.', ECEW_TEXT_DOMAIN); ?> 899 </p> 900 <div class="selection-controls" style="display: flex; gap: 8px; flex-shrink: 0;"> 901 <button type="button" class="button button-small select-all-roles"><?php _e('Select All', ECEW_TEXT_DOMAIN); ?></button> 902 <button type="button" class="button button-small deselect-all-roles"><?php _e('Deselect All', ECEW_TEXT_DOMAIN); ?></button> 903 </div> 904 </div> 905 <div class="selection-count" style="margin-bottom: 12px; font-size: 13px; color: #646970;"> 906 <span class="roles-count"> 907 <?php 908 $selected_count_roles = count($this->settings['user_roles']); 909 $total_count_roles = count($roles); 910 printf(__('%d of %d user roles selected', ECEW_TEXT_DOMAIN), $selected_count_roles, $total_count_roles); 911 ?> 912 </span> 913 </div> 914 <div class="role-checkboxes"> 915 <?php foreach ($roles as $role_key => $role) : ?> 916 <div class="checkbox-item"> 917 <label for="ecew_role_<?php echo esc_attr($role_key); ?>"> 918 <input type="checkbox" 919 id="ecew_role_<?php echo esc_attr($role_key); ?>" 920 name="ecew_settings[user_roles][]" 921 value="<?php echo esc_attr($role_key); ?>" 922 <?php checked(in_array($role_key, $this->settings['user_roles'])); ?>> 923 <?php echo esc_html(translate_user_role($role['name'])); ?> 924 </label> 925 </div> 926 <?php endforeach; ?> 927 </div> 928 </div> 929 </div> 930 <?php 931 } 932 933 /** 483 934 * Render settings page 484 935 */ 485 936 public function render_settings_page() { 486 // Get all registered post types 937 // Get all registered post types and roles 487 938 $post_types = get_post_types(array('public' => true), 'objects'); 488 489 // Get all user roles490 939 $roles = wp_roles()->roles; 940 $is_advanced_mode = !empty($this->settings['show_settings_page']); 491 941 ?> 492 942 <div class="wrap classic-editor-plus-settings"> 493 <h1><?php _e('Enable Classic Editor Settings', 'enable-classic-editor'); ?></h1> 494 943 <!-- Page Header --> 944 <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;"> 945 <h1 style="margin: 0;"><?php _e('Enable Classic Editor Settings', ECEW_TEXT_DOMAIN); ?></h1> 946 <?php 947 $last_saved = get_option('ecew_settings_last_saved', false); 948 if ($last_saved): 949 ?> 950 <div class="ecew-last-saved" style="color: #646970; font-size: 13px;"> 951 <?php 952 printf( 953 __('Last saved: %s ago', ECEW_TEXT_DOMAIN), 954 human_time_diff($last_saved, current_time('timestamp')) 955 ); 956 ?> 957 </div> 958 <?php endif; ?> 959 </div> 960 961 <!-- Mode Indicator --> 962 <?php $this->render_mode_indicator($is_advanced_mode); ?> 963 964 <!-- Validation Warnings --> 965 <?php $this->render_validation_warnings(); ?> 966 967 <!-- WordPress Settings Errors --> 495 968 <?php settings_errors('ecew_settings'); ?> 496 969 970 <!-- Settings Form --> 497 971 <form method="post" action="options.php"> 498 972 <?php settings_fields('ecew_settings_group'); ?> 499 973 500 974 <div class="metabox-holder"> 501 975 <!-- Global Settings Section --> 502 <div class="postbox"> 503 <h2 class="hndle"><span><?php _e('Global Settings', 'enable-classic-editor'); ?></span></h2> 504 <div class="inside"> 505 <table class="form-table"> 506 <tbody> 507 <tr> 508 <th scope="row"> 509 <label for="ecew_enabled"> 510 <?php _e('Enable Classic Editor', 'enable-classic-editor'); ?> 511 </label> 512 </th> 513 <td> 514 <label class="toggle-switch" for="ecew_enabled"> 515 <input type="checkbox" 516 id="ecew_enabled" 517 name="ecew_settings[enabled]" 518 value="1" 519 <?php checked(!empty($this->settings['enabled'])); ?>> 520 <span class="slider round"></span> 521 </label> 522 <p class="description"> 523 <?php _e('Uncheck to use Block Editor as the default editor.', 'enable-classic-editor'); ?> 524 </p> 525 </td> 526 </tr> 527 <tr> 528 <th scope="row"> 529 <label for="ecew_show_settings"> 530 <?php _e('Advanced Settings', 'enable-classic-editor'); ?> 531 </label> 532 </th> 533 <td> 534 <label class="toggle-switch" for="ecew_show_settings"> 535 <input type="checkbox" 536 id="ecew_show_settings" 537 name="ecew_settings[show_settings_page]" 538 value="1" 539 <?php checked(!empty($this->settings['show_settings_page'])); ?>> 540 <span class="slider round"></span> 541 </label> 542 <p class="description"> 543 <?php _e('When disabled, the plugin will use the classic editor for all content (original behavior).', 'enable-classic-editor'); ?> 544 </p> 545 </td> 546 </tr> 547 <tr> 548 <th scope="row"> 549 <label for="ecew_per_post_toggle"> 550 <?php _e('Per-Post Toggle', 'enable-classic-editor'); ?> 551 </label> 552 </th> 553 <td> 554 <label class="toggle-switch" for="ecew_per_post_toggle"> 555 <input type="checkbox" 556 id="ecew_per_post_toggle" 557 name="ecew_settings[allow_per_post_toggle]" 558 value="1" 559 <?php checked(!empty($this->settings['allow_per_post_toggle'])); ?>> 560 <span class="slider round"></span> 561 </label> 562 <p class="description"> 563 <?php _e('When enabled, a meta box will be added to the post/page edit screen to select which editor to use.', 'enable-classic-editor'); ?> 564 </p> 565 </td> 566 </tr> 567 </tbody> 568 </table> 569 </div> 570 </div> 571 976 <?php $this->render_global_settings_section(); ?> 977 572 978 <!-- Advanced Settings Sections --> 573 979 <div class="advanced-settings" <?php echo empty($this->settings['show_settings_page']) ? 'style="display:none;"' : ''; ?>> 574 <!-- Post Type Control Section --> 575 <div class="postbox"> 576 <h2 class="hndle"><span><?php _e('Post Type Control', 'enable-classic-editor'); ?></span></h2> 577 <div class="inside"> 578 <p class="description"> 579 <?php _e('Select which post types should use the Classic Editor instead of Gutenberg.', 'enable-classic-editor'); ?> 580 </p> 581 <div class="post-type-checkboxes"> 582 <?php foreach ($post_types as $post_type) : ?> 583 <div class="checkbox-item"> 584 <label for="ecew_post_type_<?php echo esc_attr($post_type->name); ?>"> 585 <input type="checkbox" 586 id="ecew_post_type_<?php echo esc_attr($post_type->name); ?>" 587 name="ecew_settings[post_types][]" 588 value="<?php echo esc_attr($post_type->name); ?>" 589 <?php checked(in_array($post_type->name, $this->settings['post_types'])); ?>> 590 <?php echo esc_html($post_type->label); ?> 591 </label> 592 </div> 593 <?php endforeach; ?> 594 </div> 595 </div> 596 </div> 597 598 <!-- User Role Control Section --> 599 <div class="postbox"> 600 <h2 class="hndle"><span><?php _e('User Role Control', 'enable-classic-editor'); ?></span></h2> 601 <div class="inside"> 602 <p class="description"> 603 <?php _e('Select which user roles should use the Classic Editor instead of Gutenberg.', 'enable-classic-editor'); ?> 604 </p> 605 <div class="role-checkboxes"> 606 <?php foreach ($roles as $role_key => $role) : ?> 607 <div class="checkbox-item"> 608 <label for="ecew_role_<?php echo esc_attr($role_key); ?>"> 609 <input type="checkbox" 610 id="ecew_role_<?php echo esc_attr($role_key); ?>" 611 name="ecew_settings[user_roles][]" 612 value="<?php echo esc_attr($role_key); ?>" 613 <?php checked(in_array($role_key, $this->settings['user_roles'])); ?>> 614 <?php echo esc_html(translate_user_role($role['name'])); ?> 615 </label> 616 </div> 617 <?php endforeach; ?> 618 </div> 619 </div> 620 </div> 621 622 <!-- Classic Widgets Toggle Section --> 623 <div class="postbox"> 624 <h2 class="hndle"><span><?php _e('Classic Widgets Control', 'enable-classic-editor'); ?></span></h2> 625 <div class="inside"> 626 <table class="form-table"> 627 <tbody> 628 <tr> 629 <th scope="row"> 630 <label for="ecew_classic_widgets"> 631 <?php _e('Widget Interface', 'enable-classic-editor'); ?> 632 </label> 633 </th> 634 <td> 635 <label class="toggle-switch" for="ecew_classic_widgets"> 636 <input type="checkbox" 637 id="ecew_classic_widgets" 638 name="ecew_settings[use_classic_widgets]" 639 value="1" 640 <?php checked(!empty($this->settings['use_classic_widgets'])); ?>> 641 <span class="slider round"></span> 642 </label> 643 <p class="description"> 644 <?php _e('Use Classic Widgets interface instead of block-based widgets', 'enable-classic-editor'); ?> 645 </p> 646 </td> 647 </tr> 648 </tbody> 649 </table> 650 </div> 651 </div> 980 <?php $this->render_post_type_control_section($post_types); ?> 981 <?php $this->render_user_role_control_section($roles); ?> 652 982 </div> 653 983 </div> 654 984 985 <!-- Submit Buttons --> 655 986 <div class="submit-buttons"> 656 <button type="button" class="button button-secondary" id="reset-defaults"><?php _e('Reset Defaults', 'enable-classic-editor'); ?></button>657 <?php submit_button(__('Save Settings', 'enable-classic-editor'), 'primary', 'submit', false); ?>987 <button type="button" class="button button-secondary" id="reset-defaults"><?php _e('Reset Defaults', ECEW_TEXT_DOMAIN); ?></button> 988 <?php submit_button(__('Save Settings', ECEW_TEXT_DOMAIN), 'primary', 'submit', false); ?> 658 989 </div> 659 990 </form> -
enable-classic-editor/trunk/readme.txt
r3301448 r3392035 5 5 Requires at least: 4.9 6 6 Requires PHP: 5.6 7 Tested up to: 6.8. 17 Tested up to: 6.8.3 8 8 Stable tag: trunk 9 9 License: GPLv2+ … … 53 53 == Changelog == 54 54 55 = 3.1 = 55 = 3.2 = 56 * New Feature: Animated save button with success confirmation 57 * New Feature: Toast notifications for better user feedback 58 * New Feature: Unsaved changes detection with warning before navigating away 59 * New Feature: Select All/Deselect All buttons for post types and user roles 60 * New Feature: Dynamic selection count for post types and user roles 61 * New Feature: Contextual help tooltips with detailed explanations 62 * New Feature: Last saved timestamp display 63 * Improvement: Per-Post Toggle now properly disabled when main plugin is OFF 64 * Improvement: Advanced Settings now properly disabled when main plugin is OFF 65 * Improvement: Settings validation warnings for conflicting configurations 66 * Improvement: "Default" editor choice now shows what editor will actually be used 67 * Improvement: Post list column shows actual editor (not just setting) with visual distinction 68 * Improvement: Classic Widgets setting includes theme compatibility note 69 * Improvement: Custom modal dialog for Reset Defaults (replaces browser confirm) 70 * Improvement: Better visual feedback with disabled setting styling 71 * Code quality: Improved inline documentation and code organization 72 * Major refactoring: Per-Post Toggle and Classic Widgets toggles are now truly independent 73 * Fixed critical bug: Classic Widgets toggle now works correctly in simple mode 74 * Fixed critical bug: Per-Post Toggle now works correctly in simple mode when Advanced Settings is disabled 75 * Improved UX: Added visual mode indicator (Simple vs Advanced) on settings page 76 * Improved UX: Enhanced help text for all settings 77 * Improved UX: Better JavaScript to prevent auto-enabling Advanced Settings 78 * Fixed: Reset Defaults button now correctly resets all toggles including Classic Widgets 79 * Code quality improvements and better inline documentation 80 * And of course, General maintenance 81 82 = 3.1 = 56 83 * General maintenance 57 84 -
enable-classic-editor/trunk/uninstall.php
r3295733 r3392035 13 13 // Delete plugin options 14 14 delete_option('ecew_settings'); 15 delete_option('ecew_settings_last_saved'); 15 16 16 // Delete post meta data 17 // Delete post meta data using prepared statement for security 17 18 global $wpdb; 18 $wpdb->query("DELETE FROM {$wpdb->postmeta} WHERE meta_key = '_ecew_editor_choice'"); 19 $wpdb->query( 20 $wpdb->prepare( 21 "DELETE FROM {$wpdb->postmeta} WHERE meta_key = %s", 22 '_ecew_editor_choice' 23 ) 24 );
Note: See TracChangeset
for help on using the changeset viewer.