functions.php
// 1. Create the Admin Menu Item under "Appearance"
add_action('admin_menu', 'rm_register_custom_css_menu');
function rm_register_custom_css_menu() {
add_theme_page(
'Edit Additional CSS', // Page Title
'Additional CSS Editor', // Menu Title
'edit_theme_options', // Capability required to access
'mirror-additional-css', // Menu Slug
'rm_render_custom_css_page' // Callback function to render interface
);
}
// 2. Render the Page and Handle Two-Way Save Actions
function rm_render_custom_css_page() {
// Verify user has permission to manage theme options
if (!current_user_can('edit_theme_options')) {
wp_die(__('You do not have sufficient permissions to access this page.'));
}
// Get the slug name of the active theme stylesheet
$stylesheet = get_stylesheet();
// Process Form Submission / Save Action
if (isset($_POST['rm_custom_css_nonce']) && wp_verify_nonce($_POST['rm_custom_css_nonce'], 'save_mirror_css')) {
if (isset($_POST['rm_css_content'])) {
// Strip any unintended backslashes added by server configurations
$updated_css = wp_unslash($_POST['rm_css_content']);
// Core WP function: Directly overwrites the data entry used by Customizer
$result = wp_update_custom_css_post($updated_css, array(
'stylesheet' => $stylesheet,
));
if (!is_wp_error($result)) {
echo '<div class="updated notice is-dismissible"><p><strong>Success:</strong> Additional CSS updated and synced across WordPress!</p></div>';
} else {
echo '<div class="error notice"><p><strong>Error:</strong> ' . esc_html($result->get_error_message()) . '</p></div>';
}
}
}
// Fetch the standard Customizer CSS post content using core API
$current_css_post = wp_get_custom_css_post($stylesheet);
$current_css = $current_css_post ? $current_css_post->post_content : '';
// Render the Administration UI
?>
<div class="wrap">
<h1>Additional CSS Engine Portal</h1>
<p class="description">
This workspace acts as a direct, real-time mirror to the
<strong>Appearance > Customize > Additional CSS</strong> database node.
Modifications applied here deploy instantly to your live layout.
</p>
<form method="post" id="rm_css_editor_form" action="" style="margin-top: 20px;">
<?php wp_nonce_field('save_mirror_css', 'rm_custom_css_nonce'); ?>
<div style="margin-bottom: 20px;">
<textarea
name="rm_css_content"
id="rm_css_content"
rows="30"
style="width: 100%; max-width: 100%; font-family: monospace; font-size: 14px; line-height: 1.5; padding: 15px; background: #1d2327; color: #f0f0f1; border-radius: 4px;"
><?php echo esc_textarea($current_css); ?></textarea>
</div>
<?php submit_button('Save & Sync CSS', 'primary', 'submit_btn'); ?>
</form>
</div>
<script>
// Fallback: Allows physical 'Tab' indentation within the textarea if CodeMirror fails to bind
document.getElementById('rm_css_content').addEventListener('keydown', function(e) {
if (e.key === 'Tab') {
e.preventDefault();
var start = this.selectionStart;
var end = this.selectionEnd;
this.value = this.value.substring(0, start) + "\t" + this.value.substring(end);
this.selectionStart = this.selectionEnd = start + 1;
}
});
</script>
<?php
}
// 3. Inject WordPress's Native CodeMirror Editor + Styles, Guards & Hotkeys
add_action('admin_enqueue_scripts', 'rm_enqueue_css_editor_scripts');
function rm_enqueue_css_editor_scripts($hook) {
// Security layer: Only initialize on our custom page viewport
if ($hook !== 'appearance_page_mirror-additional-css') {
return;
}
// Safely query and enqueue the default core code editor configuration for CSS context
$settings = wp_enqueue_code_editor(array('type' => 'text/css'));
if (false === $settings) {
return;
}
// Target CodeMirror elements to fill out the empty white space on the page
$custom_height_css = "
.appearance_page_mirror-additional-css .CodeMirror {
height: 70vh !important; /* Forces layout to fill 70% of viewport height */
min-height: 500px !important;
border: 1px solid #c3c4c7 !important;
border-radius: 4px !important;
}
";
wp_add_inline_style('code-editor', $custom_height_css);
// Attach CodeMirror directly onto our target DOM textarea element ID
wp_add_inline_script(
'code-editor',
sprintf('jQuery(function($){ wp.codeEditor.initialize("rm_css_content", %s); });', wp_json_encode($settings))
);
// Automation Script: Monitors states for changes, protects exit vectors, and maps Save Hotkeys
$guard_and_hotkey_js = "
jQuery(document).ready(function($) {
var isDirty = false;
var form = $('#rm_css_editor_form');
var submitBtn = $('#submit_btn');
// 1. Helper function to execute form submission safely
function triggerHotKeySave() {
isDirty = false; // Mark clean before navigation fires
submitBtn.trigger('click');
}
// 2. Setup standard input tracking listeners
setTimeout(function() {
var editorInstance = $('.CodeMirror')[0] ? $('.CodeMirror')[0].CodeMirror : null;
if (editorInstance) {
// Monitor internal CodeMirror state variations
editorInstance.on('change', function() {
isDirty = true;
});
// Map Ctrl+S / Cmd+S context directly inside the interactive CodeMirror wrapper window
editorInstance.setOption('extraKeys', {
'Ctrl-S': function(cm) { triggerHotKeySave(); },
'Cmd-S': function(cm) { triggerHotKeySave(); }
});
}
}, 500);
// Fallback tracking for raw text adjustments
$('#rm_css_content').on('input change', function() {
isDirty = true;
});
// Neutralize flags upon direct submit button interaction
form.on('submit', function() {
isDirty = false;
});
// 3. Document Level Hotkey Interception (covers clicks anywhere outside CodeMirror area)
$(window).on('keydown', function(e) {
if ((e.ctrlKey || e.metaKey) && String.fromCharCode(e.which).toLowerCase() === 's') {
e.preventDefault();
triggerHotKeySave();
}
});
// 4. Tab / Window Destruction Guard
$(window).on('beforeunload', function(e) {
if (isDirty) {
var message = 'You have unsaved CSS configurations. Are you sure you want to leave?';
e.returnValue = message;
return message;
}
});
});
";
wp_add_inline_script('code-editor', $guard_and_hotkey_js);
}