0 Day Analytics – WP Panel Module Developer Documentation
Table of Contents
1. Overview & Architecture
The WP Panel module provides a centralised admin page for toggling 40+ WordPress core behaviours. Unlike the plugin’s REST API endpoints (which use the 0-day/v1 namespace), the WP Panel uses a traditional WordPress form submission flow via admin_post_ actions.
Key Characteristics
- Single static class:
ADVAN\Helpers\WP_Panel - Settings stored in a dedicated
wp_optionsrow (separate from the main plugin settings) - No REST API endpoints — uses
admin-post.phpform POST - No AJAX handlers — all operations are synchronous page reloads
- No separate JavaScript files — only inline JS for accordion toggling and conditional field display
- Settings enforcement happens at runtime via WordPress filters and actions registered during
init - Requires
manage_optionscapability (Administrator role)
Technology Stack
- PHP 7.4+ (strict types)
- WordPress Options API for persistence
- WordPress
admin_post_action for form handling - Nonce-protected form submission
- Inline JavaScript for UI interactions
2. File Map
advanced-analytics/
├── classes/
│ ├── class-advanced-analytics.php — Module activation check
│ └── vendor/
│ ├── helpers/
│ │ ├── class-wp-panel.php — Main WP Panel class (~1,680 lines)
│ │ └── class-settings.php — Plugin settings (module default + menu registration)
│ └── settings/
│ └── settings-options/
│ └── wp-panel.php — Settings tab: "Enable WP Panel module" checkbox
└── css/
└── admin/
└── style.css — Shared admin styles (includes WP Panel CSS classes)
3. WP_Panel Class Reference
3.1 Constants
<?php
namespace ADVAN\Helpers;
class WP_Panel {
public const PAGE_SLUG = ADVAN_INNER_SLUG . '_page_advan_wp_panel'; // Screen base
public const MENU_SLUG = 'advan_wp_panel'; // Submenu slug
public const OPTION_NAME = ADVAN_PREFIX . 'wp_panel_settings'; // wp_options key
private const SAVE_ACTION = 'advan_wp_panel_save'; // admin_post action
private const NONCE_ACTION = 'advan_wp_panel_nonce'; // Nonce action string
private const NONCE_FIELD = '_advan_wp_panel_nonce'; // Nonce field name
private const LAST_LOGIN_META = '_advan_last_login'; // User meta key
}| Constant | Visibility | Value | Purpose |
|---|---|---|---|
PAGE_SLUG |
public | ADVAN_INNER_SLUG . '_page_advan_wp_panel' |
WordPress screen base identifier |
MENU_SLUG |
public | 'advan_wp_panel' |
Submenu page slug used in URL |
OPTION_NAME |
public | ADVAN_PREFIX . 'wp_panel_settings' |
Database option key in wp_options |
SAVE_ACTION |
private | 'advan_wp_panel_save' |
Used with admin_post_ hook |
NONCE_ACTION |
private | 'advan_wp_panel_nonce' |
Nonce verification action |
NONCE_FIELD |
private | '_advan_wp_panel_nonce' |
Hidden form field name for nonce |
LAST_LOGIN_META |
private | '_advan_last_login' |
User meta key storing last login timestamp |
3.2 Settings Methods
| Method | Visibility | Return | Description |
|---|---|---|---|
get_defaults() |
public static | array | Returns an associative array of all 46 setting keys with their default values (all booleans default to false). |
get_settings() |
public static | array | Retrieves stored settings from database and merges with defaults via wp_parse_args(). Result is cached in a static property. |
store_settings(array $settings) |
private static | void | Persists the settings array to wp_options with autoload=no. Updates the static cache. |
Default Values Structure
<?php
public static function get_defaults(): array {
return array(
// Content & editing — all boolean, default false.
'disable_comments' => false,
'disable_post_revisions' => false,
'post_revisions_limit' => 10, // int, 1–100
'disable_autosave' => false,
'disable_block_editor' => false,
'disable_file_editing' => false,
// Security & API — all boolean, default false.
'disable_xmlrpc' => false,
'disable_rest_api_public' => false,
'disable_application_passwords' => false,
// ... 7 more boolean keys ...
// Updates — all boolean, default false.
'disable_auto_updates_core' => false,
// ... 3 more keys ...
// Front-end / performance — all boolean, default false.
'disable_emojis' => false,
// ... 7 more keys ...
// Dequeue frontend assets — all boolean, default false.
'dequeue_wp_embed' => false,
// ... 8 more keys ...
// Media — boolean.
'disable_attachment_pages' => false,
// Admin — boolean.
'disable_admin_bar_frontend' => false,
// Heartbeat control.
'heartbeat_control' => 'default', // 'default' | 'disable' | 'modify'
'heartbeat_frequency' => 60, // int, 15–300
'heartbeat_admin_disable' => false,
'heartbeat_editor_disable' => false,
'heartbeat_frontend_disable' => false,
// WP back-end extend.
'enable_last_login_column' => false,
'enable_registration_date_column' => false,
);
}3.3 Runtime Enforcement (apply_settings())
Called during init(), this method reads the stored settings and attaches the appropriate WordPress filters and actions. Each setting key maps to a specific set of hooks.
Enforcement Techniques Used
| Technique | Settings That Use It |
|---|---|
Return false via filter |
disable_xmlrpc, disable_block_editor, disable_application_passwords, disable_rest_jsonp, disable_admin_bar_frontend, auto-update toggles |
| Define PHP constant | disable_post_revisions (WP_POST_REVISIONS), disable_file_editing (DISALLOW_FILE_EDIT) |
remove_action() / remove_filter() |
Emoji, embed, feed, generator, WLW manifest, RSD link, shortlink, REST link head/header, adjacent posts |
wp_deregister_script() |
disable_autosave, heartbeat_control (disable), per-location heartbeat |
wp_dequeue_script/style() |
All dequeue_* settings |
Custom callback with wp_die() |
disable_rss_feeds |
| 301 redirect | disable_attachment_pages |
| HTTP headers | enable_security_headers, remove_x_pingback_header |
| REST authentication error | disable_rest_api_public |
| User meta tracking + list table columns | enable_last_login_column, enable_registration_date_column |
WP_POST_REVISIONS, DISALLOW_FILE_EDIT) will not take effect if those constants are already defined elsewhere (e.g., in wp-config.php).3.4 Save Handler (handle_save())
Processes the form POST submitted from the WP Panel admin page.
Security Checks
current_user_can('manage_options')— capability checkwp_verify_nonce()— nonce verification usingNONCE_FIELDandNONCE_ACTION
Sanitisation Logic
| Setting Key | Sanitisation | Clamping |
|---|---|---|
post_revisions_limit |
absint() |
Min 1, Max 100 |
heartbeat_control |
sanitize_text_field() + whitelist check |
Must be default, disable, or modify |
heartbeat_frequency |
absint() |
Min 15, Max 300 |
| All other keys | filter_var(FILTER_VALIDATE_BOOLEAN) |
Absent = false |
Post-save Redirect
<?php
\wp_safe_redirect(
\add_query_arg(
array(
'page' => self::MENU_SLUG,
'updated' => '1',
),
\admin_url( 'admin.php' )
)
);
exit;3.5 Rendering Methods
| Method | Visibility | Description |
|---|---|---|
render_admin_page() |
public static | Renders the full admin page HTML: header, success notice, form with 8 collapsible sections, save button, and inline JS. |
render_card_toggle(string $key, string $label, string $description, array $settings) |
private static | Outputs a single card with a label, description paragraph, and a toggle switch checkbox. |
Card Toggle HTML Structure
<div class="advan-wp-panel-card">
<div class="advan-wp-panel-card-main">
<div class="advan-wp-panel-card-text">
<h3>Setting Label</h3>
Setting description text.
</div>
<div class="advan-wp-panel-card-control">
<label class="advan-wp-panel-switch" for="setting_key">
<input type="checkbox" id="setting_key" name="setting_key" value="1" />
<span class="advan-wp-panel-slider"></span>
</label>
</div>
</div>
</div>CSS Classes Used
| Class | Element | Purpose |
|---|---|---|
.advan-wp-panel-wrap |
Container | Main wrapper for the page |
.advan-wp-panel-header |
Header | Page title and subtitle area |
.advan-wp-panel-grid |
Grid | Layout container for sections |
.advan-wp-panel-section |
Section | Collapsible section wrapper; has data-section attribute |
.advan-wp-panel-section-header |
Section header | Clickable header with icon, title, chevron |
.advan-wp-panel-section-body |
Section body | Contains the toggle cards |
.advan-wp-panel-card |
Card | Individual setting card |
.advan-wp-panel-switch |
Label | Toggle switch wrapper |
.advan-wp-panel-slider |
Span | Visual slider for toggle |
.advan-wp-panel-select |
Select | Dropdown control (heartbeat mode) |
.advan-wp-panel-number |
Input | Numeric input control |
.advan-wp-panel-card-group |
Div | Groups related cards (heartbeat locations) |
.is-collapsed |
Section | Added when section is collapsed |
3.6 User List Column Helpers
When enabled, the module adds sortable columns to the wp-admin/users.php list table.
Last Login Column
| Method | Hook | Description |
|---|---|---|
add_last_login_column(array $columns) |
manage_users_columns |
Adds advan_last_login column |
render_last_login_column($output, $column_name, $user_id) |
manage_users_custom_column |
Renders formatted date or “Never” |
sortable_last_login_column(array $columns) |
manage_users_sortable_columns |
Registers as sortable |
sort_by_last_login($query) |
pre_get_users |
Sets meta_key for sorting |
Login timestamps are stored as Unix timestamps in user meta (_advan_last_login) via the wp_login action.
Registration Date Column
| Method | Hook | Description |
|---|---|---|
add_registration_date_column(array $columns) |
manage_users_columns |
Adds advan_registered column |
render_registration_date_column($output, $column_name, $user_id) |
manage_users_custom_column |
Renders user_registered date |
sortable_registration_date_column(array $columns) |
manage_users_sortable_columns |
Registers as sortable |
sort_by_registration_date($query) |
pre_get_users |
Sets orderby to registered |
3.7 Asset Helpers
| Method | Hook | Description |
|---|---|---|
dequeue_wp_assets() |
wp_enqueue_scripts (priority 100000) |
Conditionally dequeues/deregisters front-end scripts and styles based on dequeue_* settings |
strip_version_query($src) |
style_loader_src, script_loader_src (priority 9999) |
Removes ?ver= from asset URLs when remove_version_query_strings is enabled |
4. Data Model & Storage
All WP Panel settings are stored in a single row in the wp_options table.
| Property | Value |
|---|---|
| Table | wp_options |
| Option Name | {ADVAN_PREFIX}wp_panel_settings |
| Autoload | no |
| Format | Serialised PHP array |
| Size | 46 keys (boolean, integer, and string values) |
Reading Settings Programmatically
<?php
// Get all WP Panel settings (merged with defaults).
$settings = \ADVAN\Helpers\WP_Panel::get_settings();
// Check a specific setting.
if ( ! empty( $settings['disable_comments'] ) ) {
// Comments are disabled.
}
// Get raw stored value (without defaults).
$raw = get_option( \ADVAN\Helpers\WP_Panel::OPTION_NAME, array() );5. Settings Key Reference
| Key | Type | Default | Section |
|---|---|---|---|
disable_comments |
bool | false |
Content & Editing |
disable_post_revisions |
bool | false |
Content & Editing |
post_revisions_limit |
int | 10 |
Content & Editing |
disable_autosave |
bool | false |
Content & Editing |
disable_block_editor |
bool | false |
Content & Editing |
disable_file_editing |
bool | false |
Content & Editing |
disable_xmlrpc |
bool | false |
Security & API |
disable_rest_api_public |
bool | false |
Security & API |
disable_application_passwords |
bool | false |
Security & API |
disable_rest_output_link_wp_head |
bool | false |
Security & API |
disable_adjacent_posts_rel_link |
bool | false |
Security & API |
disable_rest_jsonp |
bool | false |
Security & API |
disable_rest_output_link_header |
bool | false |
Security & API |
remove_version_query_strings |
bool | false |
Security & API |
remove_x_pingback_header |
bool | false |
Security & API |
enable_security_headers |
bool | false |
Security & API |
disable_auto_updates_core |
bool | false |
Updates |
disable_auto_updates_plugins |
bool | false |
Updates |
disable_auto_updates_themes |
bool | false |
Updates |
disable_update_notifications |
bool | false |
Updates |
disable_emojis |
bool | false |
Front-end & Performance |
disable_embeds |
bool | false |
Front-end & Performance |
disable_rss_feeds |
bool | false |
Front-end & Performance |
disable_self_pingbacks |
bool | false |
Front-end & Performance |
disable_wp_generator |
bool | false |
Front-end & Performance |
disable_wlw_manifest |
bool | false |
Front-end & Performance |
disable_rsd_link |
bool | false |
Front-end & Performance |
disable_shortlink |
bool | false |
Front-end & Performance |
dequeue_wp_embed |
bool | false |
Dequeue Frontend Assets |
dequeue_wp_block_library |
bool | false |
Dequeue Frontend Assets |
dequeue_wp_block_library_theme |
bool | false |
Dequeue Frontend Assets |
dequeue_wc_block_style |
bool | false |
Dequeue Frontend Assets |
dequeue_jquery |
bool | false |
Dequeue Frontend Assets |
dequeue_jquery_migrate |
bool | false |
Dequeue Frontend Assets |
dequeue_global_styles |
bool | false |
Dequeue Frontend Assets |
dequeue_classic_styles |
bool | false |
Dequeue Frontend Assets |
dequeue_core_block_supports |
bool | false |
Dequeue Frontend Assets |
disable_attachment_pages |
bool | false |
Media |
disable_admin_bar_frontend |
bool | false |
Admin |
heartbeat_control |
string | 'default' |
Heartbeat Control |
heartbeat_frequency |
int | 60 |
Heartbeat Control |
heartbeat_admin_disable |
bool | false |
Heartbeat Control |
heartbeat_editor_disable |
bool | false |
Heartbeat Control |
heartbeat_frontend_disable |
bool | false |
Heartbeat Control |
enable_last_login_column |
bool | false |
WP Back-end Extend |
enable_registration_date_column |
bool | false |
WP Back-end Extend |
6. Module Activation Flow
The WP Panel module is conditionally loaded based on a plugin-level setting.
<?php
// 1. Settings tab (wp-panel.php) registers checkbox:
// Option ID: 'wp_panel_module_enabled'
// Default: true (enabled)
// 2. Main plugin class checks this setting:
// In class-advanced-analytics.php:
if ( Settings::get_option( 'wp_panel_module_enabled' ) ) {
WP_Panel::init();
}
// 3. Menu registration (in class-settings.php):
if ( get_option( 'wp_panel_module_enabled' ) ) {
WP_Panel::menu_add();
}Initialisation Sequence
WP_Panel::init()is called from the main plugin classinit()registers theadmin_post_advan_wp_panel_savehandlerinit()callsapply_settings()which reads settings and hooks into WordPress- Separately,
WP_Panel::menu_add()registers the admin submenu page under Error Logs
7. Admin Form Submission Flow
User clicks "Save Changes"
│
▼
POST to wp-admin/admin-post.php
action = advan_wp_panel_save
_advan_wp_panel_nonce = {nonce}
{setting_key} = {value} (for each enabled toggle)
│
▼
WordPress dispatches admin_post_advan_wp_panel_save
│
▼
WP_Panel::handle_save()
├── Check: current_user_can('manage_options')
├── Check: wp_verify_nonce()
├── Loop through get_defaults() keys:
│ ├── post_revisions_limit → absint() + clamp 1–100
│ ├── heartbeat_control → whitelist (default/disable/modify)
│ ├── heartbeat_frequency → absint() + clamp 15–300
│ └── all others → filter_var(FILTER_VALIDATE_BOOLEAN)
├── store_settings($sanitised)
└── wp_safe_redirect(admin.php?page=advan_wp_panel&updated=1)8. WordPress Hooks & Filters Used
The following is a comprehensive list of WordPress hooks and filters that WP Panel interacts with.
Filters (return value modifications)
| Filter | Triggered By | Return |
|---|---|---|
comments_open |
disable_comments |
false |
pings_open |
disable_comments |
false |
comments_array |
disable_comments |
array() |
use_block_editor_for_post |
disable_block_editor |
false |
use_block_editor_for_post_type |
disable_block_editor |
false |
xmlrpc_enabled |
disable_xmlrpc |
false |
rest_authentication_errors |
disable_rest_api_public |
WP_Error for unauthenticated |
wp_is_application_passwords_available |
disable_application_passwords |
false |
rest_jsonp_enabled |
disable_rest_jsonp |
false |
wp_headers |
disable_xmlrpc, remove_x_pingback_header |
Unsets X-Pingback |
style_loader_src |
remove_version_query_strings |
URL without ?ver= |
script_loader_src |
remove_version_query_strings |
URL without ?ver= |
auto_update_core |
disable_auto_updates_core |
false |
allow_major_auto_core_updates |
disable_auto_updates_core |
false |
allow_minor_auto_core_updates |
disable_auto_updates_core |
false |
auto_update_plugin |
disable_auto_updates_plugins |
false |
auto_update_theme |
disable_auto_updates_themes |
false |
tiny_mce_plugins |
disable_emojis, disable_embeds |
Removes wpemoji/wpembed |
wp_resource_hints |
disable_emojis, disable_embeds |
Filters DNS prefetch URLs |
embed_oembed_discover |
disable_embeds |
false |
the_generator |
disable_wp_generator |
Empty string |
show_admin_bar |
disable_admin_bar_frontend |
false |
heartbeat_settings |
heartbeat_control (modify) |
Modified interval |
manage_users_columns |
Login/registration columns | Adds column |
manage_users_custom_column |
Login/registration columns | Column HTML |
manage_users_sortable_columns |
Login/registration columns | Adds sortable entry |
Actions (side effects)
| Action | Triggered By | Effect |
|---|---|---|
admin_post_advan_wp_panel_save |
Form submission | Processes and saves settings |
init |
disable_comments |
Removes post type support for comments/trackbacks |
admin_menu |
disable_comments |
Removes Comments menu page |
wp_before_admin_bar_render |
disable_comments |
Removes comments admin bar item |
admin_enqueue_scripts |
disable_autosave, heartbeat per-location |
Deregisters scripts |
admin_head |
disable_update_notifications |
Removes update nag |
send_headers |
enable_security_headers |
Sends security HTTP headers |
do_feed (and variants) |
disable_rss_feeds |
wp_die() with 404 |
pre_ping |
disable_self_pingbacks |
Removes self-referencing links |
template_redirect |
disable_attachment_pages |
301 redirect |
wp_enqueue_scripts |
Dequeue settings, heartbeat front-end | Dequeues assets |
wp_login |
enable_last_login_column |
Stores login timestamp in user meta |
pre_get_users |
Column sorting | Modifies user query orderby |
9. Extending the Module
Reading Settings From Other Code
<?php
// Check if a specific WP Panel setting is active.
$settings = \ADVAN\Helpers\WP_Panel::get_settings();
if ( ! empty( $settings['disable_comments'] ) ) {
// Comments are disabled via WP Panel.
}Checking If the Module Is Active
<?php
// Check if the WP Panel module is enabled.
$module_enabled = \ADVAN\Helpers\Settings::get_option( 'wp_panel_module_enabled' );
if ( $module_enabled ) {
// WP Panel is active and enforcing settings.
}Overriding Settings Programmatically
<?php
// Override WP Panel settings via wp_options directly.
// Warning: This bypasses the module's sanitisation.
$settings = get_option( \ADVAN\Helpers\WP_Panel::OPTION_NAME, array() );
$settings['disable_emojis'] = true;
update_option( \ADVAN\Helpers\WP_Panel::OPTION_NAME, $settings );10. Code Examples
Check if Comments Are Disabled Before Rendering
<?php
/**
* Conditionally render a comment form only if WP Panel hasn't disabled comments.
*/
function my_theme_maybe_show_comments() {
if ( class_exists( '\ADVAN\Helpers\WP_Panel' ) ) {
$settings = \ADVAN\Helpers\WP_Panel::get_settings();
if ( ! empty( $settings['disable_comments'] ) ) {
return; // WP Panel has disabled comments.
}
}
comments_template();
}Check if REST API Is Restricted
<?php
/**
* Check if the REST API is restricted to logged-in users.
*/
function is_rest_api_restricted(): bool {
if ( ! class_exists( '\ADVAN\Helpers\WP_Panel' ) ) {
return false;
}
$settings = \ADVAN\Helpers\WP_Panel::get_settings();
return ! empty( $settings['disable_rest_api_public'] );
}Log When WP Panel Settings Are Saved
<?php
/**
* Hook into WordPress option update to log WP Panel setting changes.
*/
\add_action( 'update_option_' . \ADVAN\Helpers\WP_Panel::OPTION_NAME, function ( $old, $new ) {
$changes = array_diff_assoc( $new, $old );
if ( ! empty( $changes ) ) {
error_log( 'WP Panel settings changed: ' . \wp_json_encode( $changes ) );
}
}, 10, 2 );Export WP Panel Settings via WP-CLI
# Export current WP Panel settings to a JSON file.
wp option get advan_wp_panel_settings --format=json > wp-panel-settings.json
# Import WP Panel settings from a JSON file.
wp option update advan_wp_panel_settings --format=json < wp-panel-settings.jsonConditionally Load Assets Based on WP Panel Dequeue Settings
<?php
/**
* Only enqueue jQuery in your theme if WP Panel hasn't dequeued it.
*/
add_action( 'wp_enqueue_scripts', function () {
if ( class_exists( '\ADVAN\Helpers\WP_Panel' ) ) {
$settings = \ADVAN\Helpers\WP_Panel::get_settings();
if ( ! empty( $settings['dequeue_jquery'] ) ) {
// WP Panel has dequeued jQuery; use a vanilla JS alternative.
wp_enqueue_script( 'my-theme-vanilla', get_template_directory_uri() . '/js/vanilla.js', array(), '1.0', true );
return;
}
}
wp_enqueue_script( 'my-theme-scripts', get_template_directory_uri() . '/js/scripts.js', array( 'jquery' ), '1.0', true );
}, 20 );Need User Guide documentation?
See WP Panel Module User Guide for more details about configuration, practical usage and information.