Introduction
Must-Have Tweaks is a modular WordPress administration plugin that combines 45+ essential tools into a single, lightweight package. It replaces the need for dozens of individual plugins by providing security, development, performance, media, email, database, and user management features — all managed from a unified settings dashboard.
The plugin follows a strict "only load what you use" philosophy. Every feature is independently toggleable, and disabled features add zero overhead — no database queries, no hooks, no file includes. This makes it safe to activate on production sites of any size.
Key Highlights
- Modular architecture — 45+ features, each independently enabled/disabled
- AI-powered snippet editor — Claude, OpenAI, and Gemini integration with code generation and autocomplete
- Built-in file manager — browse, edit, and upload files directly from the admin with PHP safety checks
- Role & capability editor — create/edit roles, per-role and per-user capabilities, content restrictions, widget and nav menu visibility
- Email logging — log, search, view, resend emails with open tracking
- Database tools — phpMyAdmin-style database manager, SQL editor, export/import, optimizer, cleanup wizard, cron manager
- Login security — 2FA, biometric login, magic links, brute-force protection
- Full WP-CLI support — manage everything from the command line
- Extensible — 12+ WordPress filters for developers to customize behavior
Requirements
- WordPress 5.9 or higher
- PHP 7.4 or higher (PHP 8.0+ recommended)
- MySQL 5.7+ or MariaDB 10.3+
Getting Started
Installation & Licensing
- Download the plugin ZIP from your account at musthaveplugins.com
- In WordPress, go to Plugins > Add New > Upload Plugin
- Select the ZIP, click Install Now, then Activate
- Navigate to Tools > Must-Have Tweaks to configure
On first visit to the Tools > Must-Have Tweaks settings page, you are automatically redirected to musthaveplugins.com to connect your site. After completing the connect flow, you are redirected back and the plugin is activated. You can disconnect your site at any time from the System tab.
Updates are delivered automatically as long as your site is connected. You can also update manually by uploading a new ZIP.
Settings Overview
All settings are organized into tabbed categories. The tabs are:
- Login & Security — Login page design, 2FA, biometric, magic links, user switching, redirects, brute-force protection, hide login errors
- User — Role editor, activity logging, temporary users, local avatars, admin bar visibility, custom user permalink
- Admin Area — Color skins, custom logo, notice organizer, admin menu manager, web CLI
- Content — Classic editor, disable comments, duplication, public preview, missed schedule fix, external links, revisions, maintenance mode, 404 page
- Media — Folder organizer, replace media, image sizes, WebP conversion, JPEG quality, MIME types, safe SVG, CDN URL rewrite
- Performance — Disable updates, XML-RPC, emoji, embeds, query strings, heartbeat, jQuery Migrate, author archives, disable RSS feeds, remove WordPress version meta tag, disable self-pingbacks
- Mailing — Disable default emails, SMTP, email logging with open tracking
- Snippets — Snippet manager toggle, AI provider config, editor theme
- Misc — File manager, admin email check, maintenance mode, custom 404, database manager, cron manager
- System — Settings export/import
Each feature has an independent toggle switch. Features with sub-options show them only when the parent feature is enabled — this uses a dependency system that evaluates in real-time as you toggle settings.
Export / Import Settings
In the System tab:
- Export — downloads all settings as a JSON file named
{hostname}-mhtweaks-settings.json - Import — upload a previously exported JSON file. A confirmation dialog warns that importing overwrites all current settings. After import, the page reloads to reflect changes.
Settings can also be managed via WP-CLI:
wp mhtweaks settings export --file=backup.json
wp mhtweaks settings import --file=backup.json
Only options that exist in the plugin's whitelist (MH_Tweaks_Config::$user_settings) are imported — unknown keys are silently ignored.
Login & Security
Login Customizer
Redesign the WordPress login page without writing code. When enabled, a visual editor is accessible from the settings page.
Available Options
- Logo source — use the site icon (from Customizer), upload a custom image from the media library, or hide the logo entirely
- Logo dimensions — set explicit width and height in pixels. Always visible regardless of logo source.
- Form position — center (default), left, or right alignment. Includes SVG preview icons for each position.
- Page background — choose between:
- None — default WordPress gray
- Pattern — select from built-in SVG patterns
- Image — upload a background image with optional width/height for
background-size - Color — solid color picker
- Button color — the primary login button background color
- Link color — affects the "Lost your password?" and "Back to site" links
- Hide elements — selectively hide the back-to-blog link, "Remember Me" checkbox, or language switcher using a multiselect
- Custom CSS — full CodeMirror editor (v5, monokai theme) for advanced styling. Changes save automatically via AJAX.
All settings save individually via AJAX with a loading spinner animation — no page reload needed.
Two-Factor Authentication
Adds a mandatory second verification step after password login. Two methods are available and can be enabled independently:
Email OTP
Sends a 6-digit numeric code to the user's registered email address. The code expires after 10 minutes. If the code is incorrect, the user can request a new one.
Authenticator App (TOTP)
Time-based One-Time Password compatible with any TOTP app: Google Authenticator, Microsoft Authenticator, Authy, 1Password, Bitwarden, etc. Users scan a QR code from their profile page to set up. The QR code is generated browser-side using JavaScript (qrcode-generator.js).
Users configure their preferred method from their WordPress profile page. If both methods are enabled globally, the user chooses which one to use during the 2FA challenge.
Biometric Login (Passkeys)
Allows users to register a passkey and log in without a password using fingerprint, Face ID, or Windows Hello. Built on the WebAuthn standard using an internal CBOR decoder for attestation and assertion parsing.
- Users register passkeys from their WordPress profile page
- Multiple passkeys can be registered per user (e.g., laptop + phone)
- The login page shows a "Login with passkey" button when biometric login is enabled
- Works in Chrome, Firefox, Safari, Edge, and all Chromium-based browsers
- Credentials are stored as user meta — no external services required
Magic Link Login
Adds a "Login with magic link" option below the login form. The user enters their email address and receives a one-time login link valid for 15 minutes.
Security features:
- The response message is identical whether the email exists or not — prevents user enumeration
- Each token is single-use and stored as a transient
- If 2FA is enabled, magic link login counts as email verification and skips the email OTP challenge
User Switching
Administrators can instantly switch to any user account without knowing their password. Available from:
- The Users list page ("Switch To" row action)
- The user edit page
- WooCommerce order list (if WooCommerce is active)
- WooCommerce order edit page
- WooCommerce subscriptions list (if WCS is active)
After switching, a "Switch Back" button appears in the admin bar (on both admin and frontend). The original admin user ID is stored in user meta for the switched session.
Login / Logout Redirects
Set custom redirect URLs after successful login or logout. Both fields accept:
- Absolute URLs:
https://example.com/dashboard - Relative paths:
/my-account/
Leave empty for default WordPress behavior. The value is validated as a URL or path starting with / before applying. Uses the login_redirect and logout_redirect WordPress filters.
Login Attempt Limiter
Protects against brute-force attacks by blocking IP addresses after too many failed login attempts.
Configuration
- Max Attempts — number of failed logins before lockout (default: 5)
- Lockout Duration — minutes the IP is blocked (default: 15)
How It Works
- Each failed login increments a counter stored as a WordPress transient, keyed by IP address
- When the counter reaches the max, a lockout transient is created with the expiry timestamp
- During lockout, the
authenticatefilter returns aWP_Errorwith a message showing remaining lockout time - On successful login, all counters for that IP are cleared
The module detects the real client IP behind proxies by checking HTTP_CF_CONNECTING_IP (Cloudflare), HTTP_X_FORWARDED_FOR, and HTTP_X_REAL_IP headers.
Developer filter: Use mhtweaks/login_limit/should_check to exempt specific IPs:
add_filter('mhtweaks/login_limit/should_check', function($should, $ip, $username) {
if ($ip === '192.168.1.100') return false; // whitelist this IP
return $should;
}, 10, 3);
The mhtweaks/login_lockout action fires when an IP is locked out — useful for logging or notification:
add_action('mhtweaks/login_lockout', function($ip, $username, $attempts) {
error_log("Locked out {$ip} after {$attempts} attempts for user {$username}");
}, 10, 3);
Hide Login Errors
By default, WordPress shows different error messages for an invalid username ("Unknown username") and a wrong password ("The password you entered is incorrect"). This reveals whether a given username exists on the site — a valuable piece of information for attackers.
When enabled, all login error messages are replaced with a single generic message:
Invalid username or password.
This applies to both invalid usernames and incorrect passwords, preventing user enumeration through the login form. Uses the login_errors WordPress filter.
User Management
Role & Capability Editor
A comprehensive role management system accessible under Users > Role Editor. Provides two editing modes:
Edit Role Mode
Select any registered role from the dropdown. The editor provides these tabs:
- Capabilities — all WordPress capabilities organized into collapsible groups: Core, Posts, Pages, Users, Media, Themes, Plugins, plus auto-detected Custom Post Type groups. Each group has Select All / Deselect All buttons. A search field filters capabilities in real-time. Custom capabilities can be added via the text input at the bottom.
- Import / Export — export all roles as JSON, import with merge (keep existing, add new) or overwrite mode.
Role CRUD
- New — create a role with a slug, display name, and optionally copy capabilities from an existing role
- Clone — duplicate the selected role with a new slug and name
- Rename — change the display name (slug remains unchanged)
- Delete — remove custom roles only. The five built-in WordPress roles (administrator, editor, author, contributor, subscriber) cannot be deleted. The Delete button is hidden for built-in roles.
Edit User Mode
Switch to "Edit User" mode via the mode bar. Search for a user by name, email, or ID using the autocomplete field. Once selected, edit their roles (multiple roles supported) and individual capabilities.
Users List Enhancements
The WordPress Users list table gains:
- An "All Roles" column showing every role assigned to each user
- Bulk actions to add or remove any role for selected users
Developer filter: Customize capability grouping:
add_filter('mhtweaks/role_manager/cap_groups', function($groups) {
$groups['my_plugin'] = array(
'label' => 'My Plugin',
'caps' => array('my_cap_1', 'my_cap_2'),
);
return $groups;
});
Content View Restrictions
When enabled, a "View Restrictions" meta box appears in the sidebar of all public post types (posts, pages, custom post types). Select which roles are allowed to view the content.
- Empty selection = public (everyone can view)
- Roles selected = only those roles can view; others get a 404 response
- Administrators always have access regardless of selection
- Logged-out users see 404 if any restriction is set
Stored as post meta _mhtweaks_view_roles (serialized array of role slugs).
Developer filter:
add_filter('mhtweaks/content_access/allowed_roles', function($roles, $post_id) {
// Allow 'vip' role on all posts
$roles[] = 'vip';
return $roles;
}, 10, 2);
Widget Visibility
When enabled, every widget in the admin Widgets screen gets a "Visible to roles" checkbox list. On the frontend, widget_display_callback filter checks the current user's roles — if the user's role is not in the allowed list, the widget is hidden.
Leave all checkboxes unchecked = visible to everyone. Stored in a single option mhtweaks_widget_access.
Nav Menu Visibility
When enabled, each navigation menu item in the menu editor gains role checkboxes. On the frontend, wp_nav_menu_objects filter removes menu items where the current user's role is not in the allowed list. Stored as nav menu item post meta _mhtweaks_nav_roles.
User Activity Logging
Comprehensive tracking of admin actions. Creates a mht_user_log database table with columns: user_id, action, details, created_at.
Logged Events
- Authentication — login, logout
- Admin pages — visited pages with hierarchical labels (e.g., "WooCommerce – Orders" built from
$menu/$submenuglobals) - Posts — published, trashed, restored, unpublished, scheduled, set to private, pending review, permanently deleted. Includes post title and ID.
- Plugins — activated, deactivated, installed, updated, deleted (with plugin name + version captured before deletion via
delete_pluginhook) - Themes — activated, installed, updated, deleted
- Users — registered, deleted, password reset, profile updated (only when admin edits another user)
- Media — uploaded, deleted
- Core — WordPress core updated
Log Viewer
Under Users > Logging. Fully AJAX-driven interface:
- Search by user (name, email, or ID with autocomplete), action text, details text
- Date range picker (default: last 30 days) with visual calendar
- Sortable columns: Date, User, Action
- Pagination (50 per page)
- Result count
Options
- Log User Roles — multiselect to restrict logging to specific roles. Empty = log all roles.
- Log Expiry — auto-delete entries older than: 1 day, 1 week, 1 month, 3 months, 6 months, 1 year, or never. Runs via daily WP-Cron.
- Clear Logs — button to truncate all log entries immediately.
Developer filters:
// Skip logging specific actions
add_filter('mhtweaks/user_log/should_log', function($should, $action, $user_id, $details) {
if ($action === 'Dashboard') return false; // don't log dashboard visits
return $should;
}, 10, 4);
// Modify details before insert
add_filter('mhtweaks/user_log/details', function($details, $action, $user_id) {
return $details . ' [custom note]';
}, 10, 3);
Temporary Users
Create user accounts with automatic expiration dates. Ideal for giving time-limited access to clients, contractors, or support staff.
- Created from the Users list page via a dialog
- Configurable expiry duration in hours
- A one-time login link is generated for each temporary user and can optionally be sent via email
- The login link is also visible on the temporary user's profile page, with an option to regenerate it
- Auto-cleanup runs via WP-Cron — expired users are blocked on login and cleaned up periodically
Local User Avatar
Users can upload a profile picture directly from their WordPress profile page — no media library access or upload_files capability required.
- Stored in
wp-content/must-have-tweaks/avatars/{username}.{ext} - Supported formats: JPG, PNG, WebP, AVIF, GIF
- Max file size: 2 MB
- If Auto WebP Conversion is enabled, uploaded images are automatically converted to WebP
- The avatar URL is stored in user meta
mhtweaks_local_avatar— if set, overrides Gravatar via theget_avatar_urlfilter - The Gravatar description text on the profile page is replaced with upload/remove buttons
- Upload goes through a custom AJAX endpoint (not the media library)
Hide Admin Bar
Hides the WordPress admin bar on the frontend. Two modes:
- No roles selected (multiselect empty) — hides for all users
- Specific roles selected — only hides for those roles; others see the bar normally
Custom User Permalink
Allow users to set a custom URL slug for their author archive page. The field appears on the user profile page under "Custom Permalink". Only lowercase letters, numbers and hyphens are allowed.
The slug is validated against reserved words (login, admin, wp-admin, etc.), existing posts, pages, other users' custom permalinks, and WordPress usernames. Invalid slugs are rejected with a descriptive error message. On the frontend, the custom slug replaces the default /author/username/ URL via WordPress rewrite rules.
Code & Development
Snippet Manager
A full code snippet manager under Tools > Snippets. Create and manage PHP, JavaScript, CSS, and HTML snippets that execute within WordPress.
Interface
Two views:
- List view — full-width table with inline status dropdown and priority number editing. Searchable by name/filename, filterable by type and status.
- Editor view — three-panel layout: settings panel (left), CodeMirror code editor (center), compact snippet list sidebar (right). Switching between snippets checks for unsaved changes.
Snippet Settings
- Name and optional description
- Type — PHP, JavaScript, CSS, or HTML
- Priority — execution order (lower number = runs earlier, default 10)
- Location (CSS/JS/HTML only) — Frontend Header, Frontend Footer, Admin Header, Admin Footer
- Shortcode (PHP only) — register as a WordPress shortcode. Output captured via
ob_start()/ob_get_clean(). - Filename — auto-generated hex string or user-specified. Must be unique.
- Status:
- Active — runs on every page load
- Inactive — disabled, does not load
- Preview — loads only when
?mht_snippet_previewis in the URL. No capability check is performed — anyone with the URL can trigger preview snippets. This is by design for easy testing and sharing of preview links.
PHP Snippet Execution
Active PHP snippets are loaded at the plugins_loaded hook, priority 0 — before most other plugins initialize. This is handled by MH_Tweaks_Snippets::load_active_snippets() which reads the option directly via get_option() (Config is not yet initialized at priority 0). Snippets are ordered by priority ASC.
New PHP snippets include an ABSPATH guard by default:
<?php
if (!defined('ABSPATH')){
die;
}
CSS / JS / HTML Snippets
- CSS — enqueued via
wp_enqueue_style()with auto-versioning - JS — enqueued via
wp_enqueue_script()(header or footer based on location) - HTML — output via
wp_head/wp_footer/admin_head/admin_footer
Export / Import
Export: creates a ZIP containing snippets.json (manifest with all metadata) and a files/ directory with the snippet files. Import: uploads the ZIP, auto-renames conflicting filenames, and always sets imported snippets to inactive for safety.
Developer filters:
// Block specific snippets from executing
add_filter('mhtweaks/snippets/should_execute', function($should, $snippet) {
if ($snippet->filename === 'dangerous.php') return false;
return $should;
}, 10, 2);
// Modify the list of active snippets
add_filter('mhtweaks/snippets/active_snippets', function($snippets) {
// Remove snippets by condition
return $snippets;
});
AI Code Generation
Configure an AI provider in the Snippets settings tab. Each provider has independent API key, large model (code generation), and small model (autocomplete) settings.
Supported Providers
- Claude (Anthropic) — Large: Opus 4.6, Sonnet 4.6, Opus 4.5, Sonnet 4.5, Opus 4, Sonnet 4. Small: Haiku 4.5, Sonnet 4.6, 4.5, 4.
- OpenAI — Large: GPT-5.4, GPT-5.2 Pro, GPT-5.2, GPT-5.1, GPT-5, GPT-4.1, o4-mini, o3. Small: GPT-5.4 Mini, GPT-5.1 Mini, GPT-5 Mini, GPT-4.1 Mini.
- Google Gemini — Large: Gemini 3.1 Pro, Gemini 2.5 Pro. Small: Gemini 3 Flash, Gemini 2.5 Flash, Gemini 2.5 Flash Lite.
Code Generation
The prompt bar at the bottom of the editor accepts natural language instructions. The AI receives: a system prompt (WordPress snippet context), the current code, and your prompt. The response replaces the editor content. A loading overlay with cancel button is shown during generation. set_time_limit(0) ensures long generations don't timeout.
Autocomplete
After 1.2 seconds of inactivity, the plugin sends the code before and after the cursor to the small model. A suggestion popup appears below the cursor. Press Tab to accept, Esc to dismiss. Press Tab at any time to trigger a suggestion immediately. For files over 4000 characters, the large model is used automatically.
Developer filters:
// Modify AI system prompt
add_filter('mhtweaks/ai/system_prompt', function($prompt, $provider, $size) {
return $prompt . "\nAlways use WordPress coding standards.";
}, 10, 3);
// Add a custom AI provider
add_filter('mhtweaks/ai/custom_provider', function($result, $provider, $key, $model, $system, $msg) {
if ($provider === 'mistral') {
// Call Mistral API and return the response text
return my_mistral_call($key, $model, $system, $msg);
}
return $result;
}, 10, 6);
Safe Mode & Error Handling
If an active PHP snippet causes a fatal error (E_ERROR, E_PARSE, E_COMPILE_ERROR, E_CORE_ERROR), the plugin's shutdown handler automatically:
- Detects the error via
error_get_last() - Verifies the error occurred in a file within the snippets directory
- Sets the snippet's status to inactive in the database
- Records the error message in the snippet's
errorfield - Invalidates OPcache for the file
The current request still fails, but the next request will skip the broken snippet. Error messages appear as red indicators in the snippet list.
Preview Status
Set a snippet to "Preview" to test without affecting visitors. Preview snippets execute when ?mht_snippet_preview is in the URL. No capability check is performed — anyone with the URL can trigger preview snippets, making it easy to test and share preview links.
Emergency Safe Mode
If a snippet breaks your site and you can't access the admin, add this to wp-config.php:
define('MHT_SAFE_MODE', true);
This disables ALL snippet execution. A yellow banner appears in the Snippets admin. Remove the line when done.
File Manager
Under Tools > File Manager. A full file manager restricted to the WordPress installation directory (ABSPATH).
Features
- Views — list view and icon view (with image thumbnails for JPG/PNG/WebP/GIF/SVG)
- Navigation — breadcrumb path, double-click to enter folders, single-click ".." to go up
- Editing — CodeMirror editor with auto mode detection (PHP, JS, CSS, HTML, XML, JSON)
- Upload — single files, multiple files, or entire folders (via
webkitdirectory). Drag & drop supported. Uploads go one file at a time with progress bar to avoid PHP limits. Conflict handling: Overwrite or Keep Both (auto-rename). - Context menu — right-click for: Open, Edit, Download, Rename, Permissions, Zip, Unzip, Delete
- Permissions — visual chmod editor with Owner/Group/Public checkboxes, synced with an octal input field
- Zip/Unzip — create ZIP archives from selected files/folders, extract with auto-rename on conflicts
- State persistence — remembers last directory, view mode, hidden files toggle, and open file in localStorage
- Show/hide hidden files — toggle for dotfiles
- Keyboard shortcuts — Delete, F2 (rename), Enter (open), Escape (close editor)
PHP File Safety
When saving a PHP file, the file manager:
- Backs up the original content in memory
- Writes the new content to disk
- Invalidates OPcache (
opcache_invalidate) and file stat cache - Makes an authenticated
wp_remote_getrequest toadmin_url('/')with the current session cookies - If the response is HTTP 500+ or a connection error, automatically restores the backup
This prevents you from accidentally breaking your site through a PHP edit.
Email & SMTP
Disable WordPress Emails
Selectively suppress default WordPress email notifications using a multiselect. Available email types:
- New user registration (to admin)
- New user welcome (to user)
- Password changed (to user)
- Password changed (to admin)
- Email address changed (to user)
- Password reset link (to user)
- Auto-update results (plugins & themes)
- Core update notification
- Comment moderation (to admin)
- New comment (to post author)
The module only loads if at least one email type is selected.
Custom SMTP
Route all WordPress emails through a custom SMTP server. Configurable: host, port (default 587), encryption (TLS/SSL), username, password, sender name, sender email, sender priority, reply-to name, reply-to email, reply-to priority. A Send Test button verifies the configuration by sending a test email to a specified address.
Email Logging
Logs every outgoing wp_mail() call to a mht_maillog database table. The log viewer is accessible from the Mailing settings tab.
Features
- Search by email address, subject, and date range (with visual calendar picker, default last 30 days)
- Sortable columns: date, recipient, subject, opens
- View — opens the email in a wide popup. HTML emails are sanitized via
wp_kses()with extended allowed tags (tables, fonts, etc.). The tracking pixel is stripped before display to prevent false opens. - Resend — re-sends the email to the original recipient after confirmation. The resent email is also logged.
- Delete / Clear All — with confirmation popups
- Log Expiry — auto-delete via daily cron: 1 day, 1 week, 1 month (default), 3 months, 6 months, 1 year, or never
The sender ("From") is extracted from email headers. If no From header exists, the WordPress defaults (wp_mail_from + wp_mail_from_name filters) are used.
Developer filter:
// Don't log password reset emails
add_filter('mhtweaks/mail_log/should_log', function($should, $args) {
if (strpos($args['subject'], 'Password Reset') !== false) return false;
return $should;
}, 10, 2);
Open Tracking
When enabled, a 1×1 transparent GIF tracking pixel is injected into every outgoing HTML email. Plain text emails are automatically converted to HTML (with nl2br + htmlspecialchars) and the Content-Type: text/html header is added.
The pixel URL contains a unique 32-character hash. When loaded, the init hook handler increments the open counter and records first/last opened timestamps. The mail log shows an opens badge (green if >0, gray if 0).
Content
Classic Editor
Disables the Gutenberg block editor and restores the classic TinyMCE editor for all post types.
Disable Comments
Selectively disable comments on any combination of public post types using a multiselect. For each selected type, the plugin:
- Removes
commentsandtrackbackspost type support - Closes comments and pings via filters (
comments_open,pings_open) - Returns an empty comments array on the frontend
- Hides the comments column and meta boxes in the admin
If all public post types have comments disabled, the Comments menu item and admin bar icon are also removed.
Post Duplication
Adds a "Duplicate" row action to posts and pages. The duplicate is created as a draft and includes all post meta fields and taxonomy assignments.
Public Preview for Drafts
Share draft, pending, and scheduled posts with anyone via a secret link — no login required.
- A cryptographic token (
bin2hex(random_bytes(20))) is generated per post - The preview URL looks like:
site.com/post-slug/?mht_preview=TOKEN - Tokens expire after 48 hours (stored in post meta
_mhtweaks_preview_expiry) - "Public Preview" link appears in the post list row actions and in the Publish meta box
- Click the URL field in the editor to copy it to clipboard
- Check "Refresh link" and save the post to generate a new token (invalidates the old one)
- Token comparison uses
hash_equals()for timing-attack safety
Missed Schedule Fix
WordPress uses WP-Cron for publishing scheduled posts, but cron is triggered by site visits — on low-traffic sites, scheduled posts can be missed. This feature checks every 5 minutes (via a transient-based throttle) for posts with post_status = 'future' and post_date <= now(), then publishes them.
The mhtweaks/missed_schedule_published action fires for each published post.
External Links in New Tab
Automatically adds target="_blank" and rel="noopener noreferrer" to all external links in post and page content. Internal links (same domain) are not affected. Existing target attributes are preserved.
Revision Limit
Set the maximum number of revisions to keep per post. -1 = unlimited (WordPress default), 0 = revisions disabled entirely, any positive number = keep that many. Only loads if the value differs from the default.
Maintenance Mode
Shows a maintenance page to all non-admin visitors.
- Maintenance Page — select any published page, or use the default "scheduled maintenance" message
- HTTP Status Code — 503 Service Unavailable (recommended, includes
Retry-After: 3600header), 200 OK, 307 Temporary Redirect, 403 Forbidden, or 451 Unavailable For Legal Reasons - The login page is always accessible
- Users with
manage_optionscapability bypass maintenance
Developer filter:
// Bypass maintenance for specific IPs
add_filter('mhtweaks/maintenance/should_show', function($should) {
if ($_SERVER['REMOTE_ADDR'] === '1.2.3.4') return false;
return $should;
});
Custom 404 Page
Replace the default 404 error page with any published page. The selected page is rendered using your theme's page template.
Media
Media Folder Organizer
Adds a folder tree to the media library using a custom taxonomy. Create folders with parent-child hierarchy and assign media files by dragging or via the attachment editor. Folder assignments are preserved when the feature is disabled (the taxonomy is always registered).
Replace Media
Adds a "Replace file" button to the attachment details panel. Upload a new file — the original URL and attachment ID are preserved, only the file content changes. Useful for updating images without breaking existing links.
Image Sizes Panel
When editing an image attachment, a panel shows all generated sizes with their dimensions and URLs. Click any URL to copy it to clipboard. Useful for quickly getting the URL of a specific size (thumbnail, medium, large, full, and any custom sizes).
WebP Auto-Conversion
Converts uploaded JPEG and PNG images to WebP format during upload. The original file is deleted — only the WebP version is kept. The conversion happens via the wp_handle_upload filter, before WordPress generates thumbnails, so all sizes are also WebP.
- Tries Imagick first (if available with WebP delegate), falls back to GD
- Configurable WebP quality (1-100, default 80)
- Also applies to user avatar uploads
- Disabled checkbox with error message if neither Imagick nor GD supports WebP
JPEG Quality
Set the compression quality for JPEG images generated by WordPress (thumbnails, scaled images). Range: 1-100. Default: 82. Applied via jpeg_quality and wp_editor_set_quality filters. Only loads if value differs from default.
Additional MIME Types
Enable uploading of file types that WordPress blocks by default. Available types include SVG, WebP, AVIF, and others. A multiselect lets you pick which types to allow. Warning displayed about SVG security.
Safe SVG Upload
When SVG is enabled in the MIME Types setting, uploaded SVG files are automatically sanitized. The sanitizer parses the file with DOMDocument and removes potentially dangerous content:
<script>tags — blocked entirely (upload rejected)- Event handler attributes (
onload,onclick, etc.) — blocked entirely javascript:URLs — blocked entirelydata:URIs (exceptdata:image/) — blocked entirely- Disallowed elements and attributes — silently removed
If the SVG cannot be sanitized safely, the upload is rejected with an error message. The feature can be disabled from the Media settings tab while keeping SVG uploads enabled.
CDN URL Rewrite
Enter a CDN URL in the Media settings tab to automatically rewrite static asset URLs on the frontend. The plugin uses output buffering to replace your site's host with the CDN host for files matching these extensions: CSS, JS, PNG, JPG, JPEG, GIF, ICO, SVG, WebP, AVIF, WOFF, WOFF2, TTF, EOT, MP4, WebM, OGG, MP3, PDF.
Both absolute (https://example.com/...) and protocol-relative (//example.com/...) URLs are rewritten. The admin area is never affected — only frontend output is processed. Leave the field empty to disable.
Performance
Disable All Updates
Completely turns off WordPress core, plugin, and theme updates. Disables update checks, auto-updates, dashboard notices, admin bar update count, and all update-related emails. Uses filters on pre_site_transient_update_core, pre_site_transient_update_plugins, pre_site_transient_update_themes and removes update check cron actions.
Disable XML-RPC
Disables the XML-RPC API entirely and removes RSD and WLW manifest links from the page head.
Disable Emoji
Removes the emoji detection script and inline styles that WordPress adds to every page. Emojis still work via native browser rendering. Removes from frontend, admin, RSS feeds, and emails.
Disable Embeds
Disables oEmbed discovery and the embed system. Other sites will not be able to embed your content.
Remove Query Strings
Strips version query strings (?ver=x.y.z) from static CSS and JS resources. Improves caching by CDNs and proxies that don't cache URLs with query parameters.
Heartbeat Control
Disable or reduce the frequency of the WordPress Heartbeat API on selected admin pages (dashboard, posts, media, comments, menus, widgets, editor). A custom interval can be set between 15 and 300 seconds. The default WordPress interval is 15 seconds on post edit screens and 60 seconds elsewhere.
Disable RSS Feeds
Disables all RSS and Atom feeds on the site. Requests to feed URLs return a 404 error instead of XML output. Useful for sites that don't need syndication and want to reduce the attack surface. Removes the feed link tags from the HTML head as well.
Remove WordPress Version
Removes the WordPress version number from the HTML <meta name="generator"> tag and RSS feed output. Prevents attackers from easily identifying the WordPress version to target known vulnerabilities. Note: version query strings on CSS/JS assets are handled separately by the Remove Query Strings option.
Disable Self-Pingbacks
Prevents WordPress from sending pingback requests to your own site when you link to your own content. Self-pingbacks create unnecessary database entries and processing. This filter removes your site's URL from the pingback list before they are sent.
Disable jQuery Migrate
Removes the jQuery Migrate compatibility script from the frontend. Modern themes and plugins don't need it. Only affects the frontend — the admin retains jQuery Migrate for plugin compatibility. If you notice JavaScript errors after enabling, disable this option.
Disable Author Archives
Disables author archive pages and returns a 404 error. Also overrides author_link to return the home URL. Prevents username enumeration through author URL patterns.
Database
Database Manager
A phpMyAdmin-style database manager accessible under Tools > Database Manager. Provides two levels of navigation:
Global View
The top-level view shows five tabs:
- Tables — lists all database tables with engine, row count, size, and collation. Total table count and combined database size shown at the top. Each table has Browse, Truncate, and Drop actions.
- SQL — full SQL query editor (see SQL Editor)
- Export — full database export (see Export / Import)
- Import — SQL file import (see Export / Import)
- Maintenance — cleanup wizard and table optimization (see Cleanup & Optimize)
Table View
Click any table name or the Browse button to open it. The header switches to show the table name, a back button, and table-level tabs:
- Browse — displays rows in a sortable, paginated table (50 rows per page). An editable SQL bar above the results shows the current query — modify it and click Run to execute custom queries against this table. A query info line shows "Showing X–Y / Z rows". Click any column header to sort. Result tables include CSV and SQL export buttons in the navigation bar.
- Structure — shows column definitions (name, type, nullable, key, default, extra) and index information (name, column, uniqueness, type)
- SQL — dark-themed SQL editor for running arbitrary queries against the current table. Pre-populated with
SELECT * FROM `table` LIMIT 50;. Press Ctrl+Enter to execute. - Search — search all columns simultaneously with a text input. Results appear instantly with debounced input (400ms delay).
- Insert — a form with one field per column. Leave fields empty for NULL values. Success message shown after insert.
- Export — download the current table as CSV or SQL format
The header also includes Truncate and Drop buttons (red) for destructive table operations, both with confirmation dialogs.
Inline Editing
When browsing a table that has a primary key, cells are editable — click any cell to enter edit mode. Press Enter to save, Escape to cancel. Changes are saved immediately via AJAX. NULL values are displayed in italic gray. Each row also has a delete button (×) with a confirmation dialog.
SQL Editor
Two SQL editors are available:
- Global SQL (in the SQL tab) — dark-themed textarea for running any SQL query against the entire database. Supports SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, and all other SQL statements.
- Table SQL (in the table-level SQL tab) — pre-populated with a SELECT query for the current table
Both editors support Ctrl+Enter (or Cmd+Enter on Mac) to execute. Query results show:
- SELECT queries — result table with all columns and rows, execution time, and row count
- Non-SELECT queries — number of affected rows and execution time
- Errors — red error message box with the MySQL error text
Export / Import
Full Database Export
Downloads the entire database as a SQL dump file named {database}-{date}.sql. Includes DROP TABLE IF EXISTS, CREATE TABLE, and INSERT statements for every table. Sets FOREIGN_KEY_CHECKS=0 during import for safety.
Table Export
From the table-level Export tab or the result navigation bar, export individual tables in two formats:
- CSV — comma-separated values with headers, streamed in 500-row chunks for large tables
- SQL — includes
DROP TABLE,CREATE TABLE, and row-by-rowINSERTstatements
SQL Import
Upload a .sql file to execute. Statements are split by semicolons and executed sequentially. A report shows the number of successful queries and any errors. A confirmation dialog warns that importing may modify your database.
Cleanup & Optimize
In the Maintenance tab:
- Cleanup — select items to remove:
- Expired transients (from
wp_options) - Post revisions
- Trashed posts
- Spam comments
- Trashed comments
- Orphaned post meta (meta entries pointing to deleted posts)
- Orphaned comment meta
- Expired transients (from
- Optimize All Tables — runs
OPTIMIZE TABLEon every table in the database. Reclaims unused space and defragments data. Does not delete any data.
WP Cron Manager
When enabled, accessible under Tools > Cron Manager. Lists all scheduled WordPress cron events in a table with:
- Hook name
- Schedule (interval label or "One-time")
- Next run time (overdue events highlighted in red)
- Run button — execute the event immediately via
do_action_ref_array() - Delete button — remove the event via
wp_unschedule_event()
Useful for debugging missing cron events, identifying plugins that create excessive schedules, and manually triggering events during development.
Admin Area
Admin Skins
Change the WordPress admin color scheme. 12 built-in color schemes are available, applied via admin CSS.
- Select any of the 12 built-in skins, or choose Custom to define your own
- The Custom option provides 8 individual color pickers: admin bar background, admin bar text, admin bar hover, menu background, menu text, menu hover, accent color, and submenu background
- Changes apply immediately via AJAX save — no page reload needed
- The selected skin is a global setting that affects all admin users
Custom Admin Logo
Replace the WordPress logo in the admin bar with your own image. Select an image from the media library using the image picker in the Admin Area settings tab. The image is displayed at 20x20 pixels in the admin bar, replacing the default WordPress icon. To remove the custom logo, click the Remove button and the default WordPress logo will be restored.
Organize Admin Notices
Collects all admin notices (success, warning, error, info) into a single dropdown in the admin bar instead of stacking them at the top of every admin page. The admin bar shows a bell icon with a count badge indicating the number of notices. Click the icon to open a grouped dropdown panel where notices are organized by their source plugin, with the plugin icon displayed next to each group. Core WordPress notices are grouped separately. The original notice elements are hidden from the page to keep the admin area clean.
- A count badge in the admin bar shows the number of active notices
- Notices are grouped by source plugin
- Displayed in a clean dropdown panel when clicked
Disable Admin Email Verification
Removes the periodic "Please verify your administration email address" screen that WordPress shows to site administrators. Uses admin_email_check_interval filter returning false.
Admin Menu Manager
When enabled, a visual menu editor appears under Appearance > Admin Menu Manager. Drag items to reorder, click the eye icon to show/hide, and click any label to rename it. Expand a menu item to manage its submenu entries individually.
Changes are saved to a single option and applied globally via the custom_menu_order and menu_order filters at priority 999. Hidden items are removed with remove_menu_page(). Use the Reset to Default button to restore the original WordPress menu.
Web CLI
Run WP-CLI commands directly from your browser without SSH or terminal access. When enabled, a code icon appears in the admin bar. Click it or press Ctrl+` to open a terminal overlay.
How It Works
Web CLI creates a small mu-plugin that defines a WP_CLI shim class. This shim captures all WP_CLI::add_command() registrations from every active plugin, so their CLI commands become available in the browser. Commands run natively within WordPress using the same callbacks — no shell access or proc_open needed.
Built-in Commands
option get|set|delete|list— manage WordPress optionspost list|get|delete— manage posts and pagesuser list|get— list and inspect usersplugin list|activate|deactivate— manage pluginstheme list— list installed themescache flush— flush object cache and OPcachetransient get|delete [--all]— manage transientscron event list— view scheduled cron eventsdb tables|query "SQL"— list tables or run SQL querieseval "php code"— evaluate PHP expressionssite url|home|info— display site informationrewrite flush— flush rewrite rules
Plugin Commands
Any plugin that registers WP-CLI commands (e.g. wp rankmath sitemap generate, wp mhtweaks status) automatically works in Web CLI. Type help to see all available commands. Command history (last 50) is preserved across sessions using localStorage.
The mu-plugin shim is created when Web CLI is enabled and deleted when disabled or when the plugin is uninstalled. Only users with the mhtweaks_admin capability can access Web CLI. This capability is granted to administrators by default and can be revoked per-user via the Role Editor's Edit User mode.
WP-CLI
Overview
Must-Have Tweaks registers a comprehensive wp mhtweaks command with subcommands for managing all major features from the command line. Most list commands support --format=table|json|csv for output formatting.
Commands
Status
wp mhtweaks status # Table of all features and their enabled/disabled state
Options
wp mhtweaks option list # All options with values
wp mhtweaks option get login_customizer # Get single option
wp mhtweaks option set login_customizer 1 # Enable a feature
wp mhtweaks option set login_customizer "" # Disable
wp mhtweaks option delete some_option # Reset to empty
Snippets
wp mhtweaks snippet list --format=json
wp mhtweaks snippet get 1
wp mhtweaks snippet create --name="My Snippet" --type=php --code="<?php // code"
wp mhtweaks snippet create --name="Style Fix" --type=css --code="body{margin:0}"
wp mhtweaks snippet activate 1
wp mhtweaks snippet deactivate 1
wp mhtweaks snippet preview 1
wp mhtweaks snippet delete 1
Roles
wp mhtweaks role list
wp mhtweaks role caps editor
wp mhtweaks role create custom_role --name="Custom Role" --copy-from=editor
wp mhtweaks role clone editor --name="Senior Editor"
wp mhtweaks role delete custom_role
wp mhtweaks role add-cap editor --cap=manage_options --grant
wp mhtweaks role add-cap subscriber --cap=upload_files --revoke
Maintenance
wp mhtweaks maintenance status
wp mhtweaks maintenance on
wp mhtweaks maintenance on --page=42 --code=503
wp mhtweaks maintenance off
Logs
wp mhtweaks log --user=admin --limit=50 --format=json
wp mhtweaks log --action="Logged in"
wp mhtweaks mail-log [email protected] --limit=100
Settings & Utilities
wp mhtweaks settings export --file=settings.json
wp mhtweaks settings import --file=settings.json
wp mhtweaks flush-opcache
Developer Reference
Filters
| Filter | Args | Description |
|---|---|---|
mhtweaks/snippets/active_snippets | $snippets | Modify the list of active snippets before execution |
mhtweaks/snippets/should_execute | $should, $snippet | Block a specific snippet from executing |
mhtweaks/ai/system_prompt | $prompt, $provider, $size | Modify the AI system prompt |
mhtweaks/ai/user_prompt | $msg, $provider, $size | Modify the AI user prompt |
mhtweaks/ai/custom_provider | $result, $provider, $key, $model, $system, $msg | Add a custom AI provider |
mhtweaks/mail_log/should_log | $should, $args | Skip logging specific emails |
mhtweaks/content_access/allowed_roles | $roles, $post_id | Modify content access roles |
mhtweaks/login_limit/should_check | $should, $ip, $username | Exempt IPs from login limiting |
mhtweaks/user_log/should_log | $should, $action, $user_id, $details | Skip specific log entries |
mhtweaks/user_log/details | $details, $action, $user_id | Modify log details before insert |
mhtweaks/role_manager/cap_groups | $groups | Add or modify capability groups |
mhtweaks/maintenance/should_show | $should | Bypass maintenance mode |
Actions
| Action | Args | Description |
|---|---|---|
mhtweaks/login_lockout | $ip, $username, $attempts | Fires when an IP is locked out |
mhtweaks/missed_schedule_published | $post_id | Fires when a missed scheduled post is auto-published |
mhtweaks/option/{key}/updated | $value | Fires when a specific option is updated |
mhtweaks/option/updated | $key, $value | Fires when any option is updated |
Custom Capability
The plugin uses a custom mhtweaks_admin capability to control access to all plugin admin pages, settings, and AJAX handlers. On activation, this capability is granted to the Administrator role.
To restrict a specific admin user from accessing the plugin, remove the mhtweaks_admin capability from that user via the Role Editor's Edit User mode. The capability appears in the "Other" group.
Changelog
0.1.0 – 2026.04.04.
Initial release