Add Code settings group: custom admin CSS/JS + header/footer scripts
New Settings > Code group (Custom CSS & JS + Header & footer scripts) driven by admin/src/Code/CodeInjection.php: - Admin CSS → <style> in the admin <head> (</style> stripped to prevent breakout) - Admin JS → <script> in the admin footer (</script> neutralized) - Header scripts → printed verbatim in the front-end <head> - Footer scripts → printed verbatim before the front-end </body> Header/footer scripts are raw admin-authored markup by design (analytics, meta, etc.), settable only by manage_options users on the settings page. SettingsField gains a `mono` flag for monospace textareas (no CodeMirror dependency). All four injection points verified on PHP 8.5. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
f0bc04a110
commit
f5c48bced9
@@ -47,6 +47,7 @@ use AuroraAdmin\Media\SvgUploads;
|
|||||||
use AuroraAdmin\Media\MediaFolders;
|
use AuroraAdmin\Media\MediaFolders;
|
||||||
use AuroraAdmin\ImageFormats\ImageFormats;
|
use AuroraAdmin\ImageFormats\ImageFormats;
|
||||||
use AuroraAdmin\Security\Security;
|
use AuroraAdmin\Security\Security;
|
||||||
|
use AuroraAdmin\Code\CodeInjection;
|
||||||
use AuroraAdmin\Rest\MediaFolderData;
|
use AuroraAdmin\Rest\MediaFolderData;
|
||||||
use AuroraAdmin\Rest\BugReportData;
|
use AuroraAdmin\Rest\BugReportData;
|
||||||
use AuroraAdmin\Rest\CompanionPluginData;
|
use AuroraAdmin\Rest\CompanionPluginData;
|
||||||
@@ -99,6 +100,7 @@ class AuroraAdmin
|
|||||||
new MediaFolders();
|
new MediaFolders();
|
||||||
new ImageFormats();
|
new ImageFormats();
|
||||||
new Security();
|
new Security();
|
||||||
|
new CodeInjection();
|
||||||
new MediaFolderData();
|
new MediaFolderData();
|
||||||
new BugReportData();
|
new BugReportData();
|
||||||
new CompanionPluginData();
|
new CompanionPluginData();
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
namespace AuroraAdmin\Code;
|
||||||
|
|
||||||
|
use AuroraAdmin\Options\Settings;
|
||||||
|
|
||||||
|
defined("ABSPATH") || exit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom code injection (Settings > Code).
|
||||||
|
*
|
||||||
|
* Four admin-authored fields, only settable by manage_options users on the
|
||||||
|
* settings page:
|
||||||
|
* - Admin CSS → wrapped in a <style> in the admin <head>
|
||||||
|
* - Admin JS → wrapped in a <script> in the admin footer
|
||||||
|
* - Header scripts → printed raw in the front-end <head>
|
||||||
|
* - Footer scripts → printed raw before the front-end </body>
|
||||||
|
*
|
||||||
|
* Header/footer scripts are printed verbatim (they're meant to hold full
|
||||||
|
* <script>/<meta> tags — analytics, verification, etc.), the same trusted-
|
||||||
|
* admin model as any "insert headers and footers" tool. Admin CSS/JS is the
|
||||||
|
* user's own code too, but is wrapped in the right tag for them and guarded
|
||||||
|
* against accidentally breaking out of that tag.
|
||||||
|
*/
|
||||||
|
class CodeInjection
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
add_action("admin_head", [self::class, "admin_css"], 999);
|
||||||
|
add_action("admin_print_footer_scripts", [self::class, "admin_js"], 999);
|
||||||
|
add_action("wp_head", [self::class, "header_scripts"], 999);
|
||||||
|
add_action("wp_footer", [self::class, "footer_scripts"], 999);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function admin_css()
|
||||||
|
{
|
||||||
|
$css = trim((string) Settings::get("custom_admin_css", ""));
|
||||||
|
if ($css === "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Keep the CSS from breaking out of its own <style> element.
|
||||||
|
$css = str_ireplace("</style>", "", $css);
|
||||||
|
echo "\n<style id=\"aurora-custom-admin-css\">\n" . $css . "\n</style>\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- admin-authored stylesheet, output raw inside a <style> tag by design; </style> stripped above to prevent breakout.
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function admin_js()
|
||||||
|
{
|
||||||
|
$js = trim((string) Settings::get("custom_admin_js", ""));
|
||||||
|
if ($js === "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$js = str_ireplace("</script>", "<\\/script>", $js);
|
||||||
|
echo "\n<script id=\"aurora-custom-admin-js\">\n" . $js . "\n</script>\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- admin-authored script, output raw inside a <script> tag by design.
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function header_scripts()
|
||||||
|
{
|
||||||
|
$code = trim((string) Settings::get("header_scripts", ""));
|
||||||
|
if ($code === "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
echo "\n" . $code . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- admin-authored header markup (scripts/meta), printed verbatim by design.
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function footer_scripts()
|
||||||
|
{
|
||||||
|
$code = trim((string) Settings::get("footer_scripts", ""));
|
||||||
|
if ($code === "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
echo "\n" . $code . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- admin-authored footer markup (scripts), printed verbatim by design.
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -138,6 +138,7 @@ const installCompanion = async () => {
|
|||||||
<textarea
|
<textarea
|
||||||
v-else-if="field.type === 'textarea'"
|
v-else-if="field.type === 'textarea'"
|
||||||
class="field__input field__textarea"
|
class="field__input field__textarea"
|
||||||
|
:class="{ 'field__textarea--mono': field.mono }"
|
||||||
:placeholder="field.placeholder || ''"
|
:placeholder="field.placeholder || ''"
|
||||||
:rows="field.rows || 6"
|
:rows="field.rows || 6"
|
||||||
:value="val || ''"
|
:value="val || ''"
|
||||||
@@ -346,6 +347,11 @@ const installCompanion = async () => {
|
|||||||
}
|
}
|
||||||
.field__input:focus { outline: none; border-color: var(--aurora-accent); }
|
.field__input:focus { outline: none; border-color: var(--aurora-accent); }
|
||||||
.field__textarea { resize: vertical; font-family: inherit; line-height: 1.5; }
|
.field__textarea { resize: vertical; font-family: inherit; line-height: 1.5; }
|
||||||
|
.field__textarea--mono {
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
tab-size: 2;
|
||||||
|
}
|
||||||
|
|
||||||
.field__color { display: flex; align-items: center; gap: 10px; }
|
.field__color { display: flex; align-items: center; gap: 10px; }
|
||||||
.field__color input[type='color'] {
|
.field__color input[type='color'] {
|
||||||
|
|||||||
@@ -388,6 +388,69 @@ export const settingsGroups = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'code',
|
||||||
|
title: 'Code',
|
||||||
|
icon: 'dashicons-editor-code',
|
||||||
|
categories: [
|
||||||
|
{
|
||||||
|
id: 'custom-code',
|
||||||
|
title: 'Custom CSS & JS',
|
||||||
|
subtitle: 'Inject your own CSS and JavaScript into the WordPress admin',
|
||||||
|
icon: 'dashicons-admin-customizer',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
key: 'custom_admin_css',
|
||||||
|
type: 'textarea',
|
||||||
|
mono: true,
|
||||||
|
rows: 10,
|
||||||
|
label: 'Admin CSS',
|
||||||
|
description:
|
||||||
|
'CSS added to every wp-admin page, inside a <style> tag in the admin <head>. Enter CSS only — no <style> tags needed.',
|
||||||
|
placeholder: '.wrap { max-width: 1200px; }',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'custom_admin_js',
|
||||||
|
type: 'textarea',
|
||||||
|
mono: true,
|
||||||
|
rows: 10,
|
||||||
|
label: 'Admin JavaScript',
|
||||||
|
description:
|
||||||
|
'JavaScript added to the admin footer, inside a <script> tag. Enter JS only — no <script> tags needed.',
|
||||||
|
placeholder: "console.log('Hello from Aurora');",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'header-footer',
|
||||||
|
title: 'Header & footer scripts',
|
||||||
|
subtitle: 'Inject raw code into your site’s front-end <head> and footer',
|
||||||
|
icon: 'dashicons-editor-code',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
key: 'header_scripts',
|
||||||
|
type: 'textarea',
|
||||||
|
mono: true,
|
||||||
|
rows: 8,
|
||||||
|
label: 'Header scripts',
|
||||||
|
description:
|
||||||
|
'Raw HTML/JS printed in the front-end <head> — analytics snippets, verification meta tags, etc. Include the full <script>/<meta> tags.',
|
||||||
|
placeholder: '<!-- e.g. analytics -->\n<script>…</script>',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'footer_scripts',
|
||||||
|
type: 'textarea',
|
||||||
|
mono: true,
|
||||||
|
rows: 8,
|
||||||
|
label: 'Footer scripts',
|
||||||
|
description:
|
||||||
|
'Raw HTML/JS printed just before </body> on the front end. Include the full <script> tags.',
|
||||||
|
placeholder: '<script>…</script>',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'add-ons',
|
id: 'add-ons',
|
||||||
title: 'Add-ons',
|
title: 'Add-ons',
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ require AURORA_ADMIN_PATH . "admin/src/Media/SvgUploads.php";
|
|||||||
require AURORA_ADMIN_PATH . "admin/src/Media/MediaFolders.php";
|
require AURORA_ADMIN_PATH . "admin/src/Media/MediaFolders.php";
|
||||||
require AURORA_ADMIN_PATH . "admin/src/ImageFormats/ImageFormats.php";
|
require AURORA_ADMIN_PATH . "admin/src/ImageFormats/ImageFormats.php";
|
||||||
require AURORA_ADMIN_PATH . "admin/src/Security/Security.php";
|
require AURORA_ADMIN_PATH . "admin/src/Security/Security.php";
|
||||||
|
require AURORA_ADMIN_PATH . "admin/src/Code/CodeInjection.php";
|
||||||
require AURORA_ADMIN_PATH . "admin/src/Rest/MediaFolderData.php";
|
require AURORA_ADMIN_PATH . "admin/src/Rest/MediaFolderData.php";
|
||||||
require AURORA_ADMIN_PATH . "admin/src/Rest/BugReportData.php";
|
require AURORA_ADMIN_PATH . "admin/src/Rest/BugReportData.php";
|
||||||
require AURORA_ADMIN_PATH . "admin/src/Rest/CompanionPluginData.php";
|
require AURORA_ADMIN_PATH . "admin/src/Rest/CompanionPluginData.php";
|
||||||
|
|||||||
Reference in New Issue
Block a user