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

  1. Download the plugin ZIP from your account at musthaveplugins.com
  2. In WordPress, go to Plugins > Add New > Upload Plugin
  3. Select the ZIP, click Install Now, then Activate
  4. 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

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

  1. Each failed login increments a counter stored as a WordPress transient, keyed by IP address
  2. When the counter reaches the max, a lockout transient is created with the expiry timestamp
  3. During lockout, the authenticate filter returns a WP_Error with a message showing remaining lockout time
  4. 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.

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/$submenu globals)
  • 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_plugin hook)
  • 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 the get_avatar_url filter
  • 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

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_preview is 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:

  1. Detects the error via error_get_last()
  2. Verifies the error occurred in a file within the snippets directory
  3. Sets the snippet's status to inactive in the database
  4. Records the error message in the snippet's error field
  5. 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:

  1. Backs up the original content in memory
  2. Writes the new content to disk
  3. Invalidates OPcache (opcache_invalidate) and file stat cache
  4. Makes an authenticated wp_remote_get request to admin_url('/') with the current session cookies
  5. 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 comments and trackbacks post 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.

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: 3600 header), 200 OK, 307 Temporary Redirect, 403 Forbidden, or 451 Unavailable For Legal Reasons
  • The login page is always accessible
  • Users with manage_options capability 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 entirely
  • data: URIs (except data: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-row INSERT statements

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
    Shows a report of how many items were removed per category.
  • Optimize All Tables — runs OPTIMIZE TABLE on 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

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 options
  • post list|get|delete — manage posts and pages
  • user list|get — list and inspect users
  • plugin list|activate|deactivate — manage plugins
  • theme list — list installed themes
  • cache flush — flush object cache and OPcache
  • transient get|delete [--all] — manage transients
  • cron event list — view scheduled cron events
  • db tables|query "SQL" — list tables or run SQL queries
  • eval "php code" — evaluate PHP expressions
  • site url|home|info — display site information
  • rewrite 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

FilterArgsDescription
mhtweaks/snippets/active_snippets$snippetsModify the list of active snippets before execution
mhtweaks/snippets/should_execute$should, $snippetBlock a specific snippet from executing
mhtweaks/ai/system_prompt$prompt, $provider, $sizeModify the AI system prompt
mhtweaks/ai/user_prompt$msg, $provider, $sizeModify the AI user prompt
mhtweaks/ai/custom_provider$result, $provider, $key, $model, $system, $msgAdd a custom AI provider
mhtweaks/mail_log/should_log$should, $argsSkip logging specific emails
mhtweaks/content_access/allowed_roles$roles, $post_idModify content access roles
mhtweaks/login_limit/should_check$should, $ip, $usernameExempt IPs from login limiting
mhtweaks/user_log/should_log$should, $action, $user_id, $detailsSkip specific log entries
mhtweaks/user_log/details$details, $action, $user_idModify log details before insert
mhtweaks/role_manager/cap_groups$groupsAdd or modify capability groups
mhtweaks/maintenance/should_show$shouldBypass maintenance mode

Actions

ActionArgsDescription
mhtweaks/login_lockout$ip, $username, $attemptsFires when an IP is locked out
mhtweaks/missed_schedule_published$post_idFires when a missed scheduled post is auto-published
mhtweaks/option/{key}/updated$valueFires when a specific option is updated
mhtweaks/option/updated$key, $valueFires 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

This website uses cookies to enhance your browsing experience and ensure the site functions properly. By continuing to use this site, you acknowledge and accept our use of cookies.

Accept All Accept Required Only