WordPress Plugin  ·  v1.7.0

Inject custom JavaScript
the right way.

Scriptomatic gives WordPress administrators full control over custom scripts in the <head> and footer — with conditional loading, revision history, one-click rollback, and a complete audit trail.

⬇ Download Latest ★ View on GitHub
WordPress 5.3+ PHP 7.2+ GPL v2 No dependencies Multisite ready

Everything you need, nothing you don't

A complete toolkit for managing custom JavaScript on any WordPress site — built for administrators who care about control and correctness.

⌨️

Inline Script Editor

Write JavaScript directly in the admin. A live character counter colour-codes at 75% and 90% of the 100 KB limit so you always know where you stand.

🔗

External Script URLs

Manage multiple remote <script src> tags per location via a chiclet UI. URLs are validated, deduplicated, and loaded before the inline block.

🎯

Conditional Loading

Eight condition types — All Pages, Front Page, Singular, Post Type, Page ID, URL Contains, Logged In, Logged Out — per location, independently configured.

🔁

Revision History & Rollback

Every save creates a timestamped revision. Restore any prior version in one AJAX click — no page reload, no data loss. View any revision's content in a lightbox.

📋

Audit Log

All saves, rollbacks, and URL changes are recorded with timestamp, username, action type, and character count or URL. Configurable limit of 10–1000 entries per location.

🔒

Security-First Architecture

Dual nonce verification, capability checks on every callback, rate limiting (10-second cooldown), open-redirect hardening, and singleton deserialization guards.

📚

Contextual Help Tabs

Built-in help tabs on every admin page covering usage, load conditions, security tips, and troubleshooting — no need to leave the dashboard.

🌐

Multisite Compatible

Fully per-site within a network. Install and activate network-wide. Uninstall iterates every sub-site to clean up option data correctly.

🏗️

Trait-Based Architecture

Eight focused PHP traits — menus, sanitizer, history, settings, renderer, pages, enqueue, injector — in separate files for clean separation of concerns.

Up and running in minutes

From install to injected script, Scriptomatic keeps every step straightforward.

1

Install & Activate

Upload the plugin zip via WordPress admin or drop the folder into wp-content/plugins/. Activate normally.

2

Open Head or Footer Scripts

Navigate to Scriptomatic → Head Scripts or Footer Scripts in your WordPress admin.

3

Write or Add URLs

Paste your JavaScript into the inline editor, or add remote script URLs. No <script> tags needed — they are added automatically.

4

Set Load Conditions

Optionally restrict injection to specific pages, post types, URL patterns, or user state. Leave blank to load everywhere.

5

Save & Verify

Click Save. Visit the front-end and check the page source. Use the revision history to roll back at any time.

Revision History & Audit Log are always there

The revision history panel and location-filtered audit log are embedded at the bottom of every Head Scripts and Footer Scripts page. You can view any revision's content in a lightbox, restore it in one click, and see a full record of who changed what and when — all without leaving the settings page.

Common use cases

Paste any of these into the inline editor. Scriptomatic wraps the code in <script> tags automatically.

// Google Analytics (GA4) window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-XXXXXXXXXX');
// Meta (Facebook) Pixel !function(f,b,e,v,n,t,s){ if(f.fbq)return;n=f.fbq=function(){ n.callMethod ? n.callMethod.apply(n,arguments) : n.queue.push(arguments) }; if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0'; n.queue=[];t=b.createElement(e);t.async=!0; t.src=v;s=b.getElementsByTagName(e)[0]; s.parentNode.insertBefore(t,s) }(window,document,'script','https://connect.facebook.net/en_US/fbevents.js'); fbq('init', 'YOUR_PIXEL_ID'); fbq('track', 'PageView');
// Custom jQuery — runs after DOM is ready jQuery(document).ready(function($) { console.log('Scriptomatic loaded.'); $('.my-button').on('click', function() { $('.my-panel').toggleClass('active'); }); });
// Google Tag Manager — add to Head Scripts (function(w,d,s,l,i){ w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'}); var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:''; j.async=true; j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl; f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-XXXXXXX');

💡 Never include <script> tags — Scriptomatic adds them automatically. Do not use eval() or inject untrusted input.

Defence in depth

Scriptomatic applies multiple independent security layers so that a failure in any one layer does not expose the site.

🛡️

Capability Gates

Every save callback verifies manage_options before processing any input. No data is written without this check passing.

🔑

Dual Nonce Verification

Both the WordPress Settings API nonce and a secondary per-location nonce must validate. One expired or missing nonce aborts the save.

⏱️

Rate Limiting

A transient-based 10-second per-user, per-location cooldown prevents rapid repeated saves or brute-force form submissions.

Input Validation

Maximum 100 KB enforced. Invalid UTF-8 and control characters rejected. <script> tags stripped. Dangerous HTML tags flagged with admin notice.

🔗

URL Validation

External script URLs are validated with wp_http_validate_url() and deduplicated before storage and before injection.

📋

Audit Logging

All saves, rollbacks, url_added, and url_removed events are all logged with timestamp and user identity. Configurable retention limit (3–1000). Oldest entries are discarded automatically once the cap is reached.

↩️

Open Redirect Hardening

Post-action redirects use a constructed admin_url() rather than the HTTP Referer header, which can be spoofed by an attacker.

🧱

Singleton Guards

__clone() and __wakeup() methods prevent the singleton from being duplicated via object cloning or PHP unserialize().

🔒

Directory Index Files

Both the plugin root and includes/ directory contain an index.php that returns HTTP 403, preventing directory listing if web server options are misconfigured.

Three focused admin pages

Each page is scoped to one location or purpose, keeping the interface clean and avoiding ambiguity.

Page Menu Path What's Here
Head Scripts Scriptomatic → Head Scripts Inline JS editor, external URL manager, load conditions, revision history lightbox, audit log (head entries only)
Footer Scripts Scriptomatic → Footer Scripts Inline JS editor, external URL manager, load conditions, revision history lightbox, audit log (footer entries only)
Preferences Scriptomatic → Preferences History revision limit, audit log entry limit (10–1000), uninstall data-retention toggle

Three ways to install

Choose whichever method fits your workflow.

📤 Upload via Admin

  1. Download the latest ZIP from the Releases page
  2. Go to Plugins → Add New
  3. Click Upload Plugin and select the ZIP
  4. Click Install Now then Activate

📁 Manual Upload

  1. Download and extract the ZIP
  2. Upload the scriptomatic folder to /wp-content/plugins/ via FTP or SFTP
  3. Go to Plugins in WordPress admin
  4. Find Scriptomatic and click Activate

💻 Git Clone

$ cd /path/to/wp-content/plugins/ $ git clone https://github.com/richardkentgates/scriptomatic.git

Then activate via WordPress admin.

Requirements

WordPress 5.3 or higher
PHP 7.2 or higher
Administrator role (manage_options)
No external dependencies

Changelog

Selected highlights — see the full CHANGELOG.md on GitHub.

Unreleased

Security hardening, view lightbox for history, Preferences rename, audit log improvements

Six security fixes across sanitizer, settings, pages, and injector traits. View button on history entries opens a lightbox. Audit log now filters by location. "General Settings" renamed to "Preferences". Load Conditions section moved above External Script URLs.

v1.7.0

Configurable audit log limit; fixed addUrl() clone bug; network admin UI removed

Audit log cap moved from a hard-coded constant to a Preferences setting (10–1000, default 200). Fixed the JS addUrl() function that was producing an empty set. All network-admin-specific code removed — plugin is now strictly per-site.

v1.6.0

Per-URL load conditions

Every external script URL in the list now has its own independent load-condition picker, replacing the previous model where a single condition controlled every URL in a location.

v1.5.0

URL audit log; double-invocation guard; AJAX rollback fix

url_added / url_removed audit events added. Static double-call guard prevents Settings API duplicate invocations. AJAX rollback switched to direct $wpdb write to bypass sanitize callbacks in AJAX context.

View full changelog →