pxlbsadminify_options();
parent::__construct( (array) get_option( $this->prefix ) );
add_action( 'network_admin_menu', [$this, 'network_panel'] );
// Freemius's _prepare_admin_menu (admin_menu @ 999999999, x2 via
// parallel_activation) strips the per-site "wp-adminify-settings" menu on
// multisite (SDK 2.13.1+), so individual site admins hit
// "Cannot load wp-adminify-settings". Snapshot the menu just before Freemius
// runs and restore it just after — this keeps the menu registered at the
// normal priority (so submenu URLs stay correct) yet survives Freemius's
// removal pass.
add_action( 'admin_menu', [$this, 'pxlbsadminify_capture_settings_menu'], 999999998 );
add_action( 'admin_menu', [$this, 'pxlbsadminify_restore_settings_menu'], PHP_INT_MAX );
add_filter(
'pxlbsadminify_render_field_html',
array($this, 'render_pro_locked_field'),
10,
2
);
// System mode shows BOTH header logos (see system_mode_logo_styles). Run after
// the framework registers its 'adminify' stylesheet (default priority 10).
add_action( 'admin_enqueue_scripts', array($this, 'system_mode_logo_styles'), 100 );
}
/**
* Fix the settings-header logo in System mode.
*
* The header prints both a light and a dark logo; the framework CSS hides one
* based on the body's .adminify-light-mode / .adminify-dark-mode class. System
* mode adds NEITHER class, so neither hide-rule fires and both logos show.
*
* These fallbacks are scoped under .wp-adminify-settings with lower specificity
* than the mode-class rules, so they only take effect when no mode class is
* present (i.e. System) and pick a single logo from the OS prefers-color-scheme.
*/
public function system_mode_logo_styles() {
if ( !wp_style_is( 'adminify', 'enqueued' ) && !wp_style_is( 'adminify', 'registered' ) ) {
return;
}
$css = '.wp-adminify-settings img.adminify-settings-dark-logo{display:none}' . '.wp-adminify-settings img.adminify-settings-light-logo{display:inline-block}' . '@media (prefers-color-scheme: dark){' . '.wp-adminify-settings img.adminify-settings-light-logo{display:none}' . '.wp-adminify-settings img.adminify-settings-dark-logo{display:inline-block}' . '}';
wp_add_inline_style( 'adminify', $css );
}
/**
* Snapshot the wp-adminify-settings menu, submenu and page callback right
* before Freemius's _prepare_admin_menu (priority 999999999) can remove them.
*/
public function pxlbsadminify_capture_settings_menu() {
global $menu, $submenu, $wp_filter;
$slug = 'wp-adminify-settings';
$hook = 'toplevel_page_' . $slug;
if ( !empty( $menu ) ) {
foreach ( $menu as $item ) {
if ( isset( $item[2] ) && $item[2] === $slug ) {
$this->captured_menu_item = $item;
break;
}
}
}
if ( isset( $submenu[$slug] ) ) {
$this->captured_submenu = $submenu[$slug];
}
if ( isset( $wp_filter[$hook] ) ) {
foreach ( $wp_filter[$hook]->callbacks as $callbacks ) {
foreach ( $callbacks as $callback ) {
$this->captured_page_cb = $callback['function'];
break 2;
}
}
}
}
/**
* Restore anything Freemius removed: the top-level menu entry, its submenus
* and the page render callback. No-op when nothing was removed.
*/
public function pxlbsadminify_restore_settings_menu() {
global $menu, $submenu;
$slug = 'wp-adminify-settings';
$hook = 'toplevel_page_' . $slug;
// Re-attach the page render callback so the page is loadable again.
if ( !has_action( $hook ) && $this->captured_page_cb ) {
add_action( $hook, $this->captured_page_cb );
}
// Re-add the top-level menu entry if it was removed.
$has_top = false;
if ( !empty( $menu ) ) {
foreach ( $menu as $item ) {
if ( isset( $item[2] ) && $item[2] === $slug ) {
$has_top = true;
break;
}
}
}
if ( !$has_top && $this->captured_menu_item ) {
$menu[] = $this->captured_menu_item;
}
// Re-add submenus if they were removed (preserves their original URLs).
if ( empty( $submenu[$slug] ) && $this->captured_submenu ) {
$submenu[$slug] = $this->captured_submenu;
}
}
public function network_panel() {
add_menu_page(
$this->get_plugin_menu_label(),
$this->get_plugin_menu_label(),
'manage_options',
'wp-adminify-settings',
[$this, 'network_panel_display'],
PXLBSADMINIFY_ASSETS_IMAGE . 'logos/menu-icon.svg',
30
);
}
public function get_bloginfo( $blog_id, $fields = [] ) {
switch_to_blog( $blog_id );
$_fields = [];
foreach ( $fields as $field ) {
$_fields[$field] = get_bloginfo( $field );
}
restore_current_blog();
return $_fields;
}
public function get_sites() {
$sites = get_sites();
foreach ( $sites as $site ) {
$info = $this->get_bloginfo( $site->blog_id, ['name'] );
$site->name = $info['name'];
}
return $sites;
}
public function get_sites_option_empty() {
/* translators: 1: option value attribute, 2: option label text */
return sprintf( __( '', 'adminify' ), 0, __( 'Select', 'adminify' ) );
}
public function get_sites_option( $sites = [], $add_empty_slot = false ) {
if ( empty( $sites ) ) {
$sites = $this->get_sites();
}
$_sites = [];
if ( $add_empty_slot ) {
$_sites[] = $this->get_sites_option_empty();
}
foreach ( $sites as $site ) {
/* translators: 1: site blog ID used as option value, 2: site name shown as option label */
$_sites[] = sprintf( __( '', 'adminify' ), $site->blog_id, $site->name );
}
return implode( '', $_sites );
}
public function maybe_display_message() {
if ( empty( $this->message ) ) {
return;
}
$classes = 'adminify-status adminify-status--' . esc_attr( $this->message['type'] );
echo '
' . wp_kses_post( $this->message['message'] ) . '
';
}
public function network_panel_display() {
$multisite_settings = sprintf(
wp_kses_post( '
', 'adminify' ),
Utils::upgrade_pro_notice_class(),
esc_html__( 'Network Settings', 'adminify' ),
esc_url( 'https://wpadminify.com/pricing' ),
Utils::upgrade_pro_notice_class( 'Please Upgrade or Activate License' )
);
// Initialize the multisite_settings variable
$multisite_settings = apply_filters( 'pxlbsadminify/admin_settings/network', $multisite_settings );
// Apply the filter
echo wp_kses_post( $multisite_settings );
}
public function option_modules() {
$extra_data_merge = [];
$clonable_data = [
'pxlbsadminify_settings' => __( 'Adminify Options', 'adminify' ),
'_adminify_admin_columns_adminify_admin_page' => __( 'Admin Page Columns Data', 'adminify' ),
];
// Activity Logs Active
if ( Utils::is_plugin_active( 'adminify-activity-logs/adminify-activity-logs.php' ) ) {
$extra_data_merge['adminify_activity_logs'] = __( 'Activity Logs Data', 'adminify' );
$clonable_data = array_merge( $clonable_data, $extra_data_merge );
}
// Quick Circle Menu Active
if ( Utils::is_plugin_active( 'adminify-quick-circle-menu/adminify-quick-circle-menu.php' ) ) {
$extra_data_merge['pxlbsadminify_quick_circle_menu'] = __( 'Quick Circle Menu', 'adminify' );
$clonable_data = array_merge( $clonable_data, $extra_data_merge );
}
// Google Pagespeed Active
if ( Utils::is_plugin_active( 'adminify-google-pagespeed/adminify-google-pagespeed.php' ) ) {
$extra_data_merge['adminify_page_speed'] = __( 'Google Pagespeed', 'adminify' );
$clonable_data = array_merge( $clonable_data, $extra_data_merge );
}
// Login Customizer Active
if ( Utils::is_plugin_active( 'loginfy/loginfy.php' ) ) {
$extra_data_merge['pxlbsadminify_login'] = __( 'Loginify Data', 'adminify' );
$clonable_data = array_merge( $clonable_data, $extra_data_merge );
}
// Header Footer Scripts Active
if ( Utils::is_plugin_active( 'adminify-sidebar-generator/adminify-sidebar-generator.php' ) ) {
$extra_data_merge['pxlbsadminify_sidebar_settings'] = __( 'Sidebar Generator', 'adminify' );
$clonable_data = array_merge( $clonable_data, $extra_data_merge );
}
// Sidebar Generator Active
if ( Utils::is_plugin_active( 'adminify-header-footer-scripts/adminify-header-footer-scripts.php' ) ) {
$extra_data_merge['pxlbsadminify_custom_js_css'] = __( 'Custom JS/CSS', 'adminify' );
$clonable_data = array_merge( $clonable_data, $extra_data_merge );
}
// Admin Columns Active
if ( Utils::is_plugin_active( 'adminify-admin-columns/adminify-admin-columns.php' ) ) {
$extra_data_merge['_adminify_admin_columns_page'] = __( 'Admin Columns Page Data', 'adminify' );
$extra_data_merge['_adminify_admin_columns_post'] = __( 'Admin Columns Post Data', 'adminify' );
$clonable_data = array_merge( $clonable_data, $extra_data_merge );
}
return (array) apply_filters( 'adminify_clone_blog_option_modules', $clonable_data );
}
public function get_pagespeed_data( $copy_from ) {
switch_to_blog( $copy_from );
global $wpdb;
$table_name = $wpdb->prefix . 'adminify_page_speed';
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter -- table name derived from a sanitized internal value, no user input; direct query required for reading a custom plugin table; not cached intentionally.
$histories = $wpdb->get_results( "SELECT * FROM {$table_name}", ARRAY_A );
restore_current_blog();
return $histories;
}
public function clone_pagespeed_data( $histories, $copy_to ) {
switch_to_blog( $copy_to );
global $wpdb;
$table_name = $wpdb->prefix . 'adminify_page_speed';
foreach ( $histories as $history ) {
unset($history['id']);
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- direct query required for writing to a custom plugin table; not cached intentionally.
$wpdb->insert( "{$table_name}", $history, [
'url' => '%s',
'score_desktop' => '%d',
'score_mobile' => '%d',
'data_desktop' => '%s',
'data_mobile' => '%s',
'screenshot' => '%s',
'time' => '%s',
] );
}
restore_current_blog();
}
public function get_admin_columns_options( $copy_from ) {
$options = [];
switch_to_blog( $copy_from );
$args = [
'public' => true,
];
$types = get_post_types( $args );
unset($types['attachment']);
restore_current_blog();
foreach ( $types as $type ) {
$options[] = '_adminify_admin_columns_meta_' . esc_attr( $type );
}
return $options;
}
public static function get_instance() {
if ( !is_null( self::$instance ) ) {
return self::$instance;
}
self::$instance = new self();
return self::$instance;
}
protected function get_defaults() {
return $this->defaults;
}
public static function get_pro_label() {
$is_pro = "";
$is_pro = esc_html__( 'Adminify', 'adminify' );
return $is_pro;
}
public function get_plugin_menu_icon() {
$menu_icon = PXLBSADMINIFY_ASSETS_IMAGE . 'logos/menu-icon-light.svg';
$saved_data = get_option( $this->prefix );
if ( isset( $saved_data['white_label']['adminify']['menu_icon'] ) && !empty( $saved_data['white_label']['adminify']['menu_icon']['url'] ) ) {
$menu_icon = $saved_data['white_label']['adminify']['menu_icon']['url'];
}
return $menu_icon;
}
public function get_plugin_menu_label() {
$plugin_menu_label = self::get_pro_label();
$saved_data = get_option( $this->prefix );
if ( isset( $saved_data['white_label']['adminify']['menu_label'] ) && !empty( $saved_data['white_label']['adminify']['menu_label'] ) ) {
$plugin_menu_label = $saved_data['white_label']['adminify']['menu_label'];
}
return $plugin_menu_label;
}
public static function support_url() {
$support_url = '';
$support_url = 'https://wordpress.org/support/plugin/adminify/#new-topic-0';
return $support_url;
}
public function pxlbsadminify_options() {
if ( !class_exists( 'ADMINIFY' ) ) {
return;
}
$submenu_position = apply_filters( 'pxlbsadminify_submenu_position', 30 );
$saved_data = get_option( $this->prefix );
$global_admin_ui_mode = ( empty( $saved_data['light_dark_mode']['admin_ui_mode'] ) ? 'light' : sanitize_text_field( $saved_data['light_dark_mode']['admin_ui_mode'] ) );
$admin_ui_mode = ( empty( get_user_meta( get_current_user_id(), 'color_mode', true ) ) ? $global_admin_ui_mode : get_user_meta( get_current_user_id(), 'color_mode', true ) );
$light_logo_image_url = PXLBSADMINIFY_ASSETS_IMAGE . 'logos/logo-text-light.svg';
$dark_logo_image_url = PXLBSADMINIFY_ASSETS_IMAGE . 'logos/logo-text-dark.svg';
$plugin_author_name = PXLBSADMINIFY_AUTHOR;
// WP Adminify Options
\ADMINIFY::createOptions( $this->prefix, [
'framework_title' => '' . ' by ' . esc_html( $plugin_author_name ) . '',
'framework_class' => '',
'menu_title' => $this->get_plugin_menu_label(),
'menu_slug' => 'wp-adminify-settings',
'menu_capability' => 'manage_options',
'menu_icon' => $this->get_plugin_menu_icon(),
'menu_position' => 30,
'menu_hidden' => false,
'menu_parent' => 'admin.php?page=wp-adminify-settings',
'show_bar_menu' => true,
'show_sub_menu' => false,
'show_in_network' => false,
'show_in_customizer' => false,
'show_search' => false,
'show_reset_all' => true,
'show_reset_section' => true,
'show_footer' => true,
'show_all_options' => false,
'show_form_warning' => true,
'sticky_header' => false,
'save_defaults' => false,
'ajax_save' => true,
'admin_bar_menu_icon' => '',
'admin_bar_menu_priority' => 80,
'footer_text' => ' ',
'footer_after' => ' ',
'footer_credit' => ' ',
'database' => 'options',
'transient_time' => 0,
'contextual_help' => [],
'contextual_help_sidebar' => '',
'enqueue_webfont' => true,
'async_webfont' => false,
'output_css' => true,
'nav' => 'normal',
'has_nav' => false,
'theme' => 'dark',
'class' => 'wp-adminify-settings',
'defaults' => [],
] );
$this->defaults = array_merge( $this->defaults, ( new Customize() )->get_defaults() );
$this->defaults = array_merge( $this->defaults, ( new MenuLayout() )->get_defaults() );
$this->defaults = array_merge( $this->defaults, ( new Productivity() )->get_defaults() );
$this->defaults = array_merge( $this->defaults, ( new Security() )->get_defaults() );
$this->defaults = array_merge( $this->defaults, ( new Performance() )->get_defaults() );
$this->defaults = array_merge( $this->defaults, ( new CustomCSSJS() )->get_defaults() );
$this->defaults = array_merge( $this->defaults, ( new White_Label() )->get_defaults() );
// Fix Missing keys on save
add_filter( "adminify_{$this->prefix}_save", function ( $data ) {
$data = $this->fix_missing_keys( $this->defaults, $data );
return $data;
} );
// Backup Settings
\ADMINIFY::createSection( $this->prefix, [
'title' => __( 'Backup', 'adminify' ),
'icon' => 'fas fa-database',
'fields' => [[
'type' => 'subheading',
'content' => Utils::help_urls(
__( 'Backup Config Settings', 'adminify' ),
'https://wpadminify.com/docs/adminify/export-import/backup',
'https://www.youtube.com/playlist?list=PLqpMw0NsHXV-EKj9Xm1DMGa6FGniHHly8',
'https://www.facebook.com/groups/jeweltheme',
self::support_url()
),
], [
'type' => 'backup',
'class' => 'adminify-block',
]],
] );
}
function fix_missing_keys( $defaults, $data ) {
if ( is_array( $defaults ) ) {
foreach ( $defaults as $key => $value ) {
if ( is_array( $value ) ) {
if ( !isset( $data[$key] ) || gettype( $data[$key] ) !== 'array' ) {
$data[$key] = [];
}
$data[$key] = $this->fix_missing_keys( $value, $data[$key] );
}
}
}
return $data;
}
public function get_prefix() {
return $this->prefix;
}
/**
* Render-time hook that neutralizes Pro-locked controls in the
* free build. Bypassed when the Pro plugin is active so the Pro
* UI is unchanged.
*
* Two operating modes, both detected from the rendered HTML:
*
* 1. Field-level lock (the field's class array contains
* 'adminify-pro-locked'): strip name="..." from every input/
* select/textarea, add disabled + tabindex="-1", and wrap the
* entire field with a
* that carries a lock-icon + "Upgrade to Pro" CTA overlay.
*
* 2. Option-level lock (a checkbox/radio option label contains
* ): for every
* that contains the marker span, strip name="..." from the
* enclosed input and add disabled + tabindex="-1". Inline lock
* icon is rendered by CSS off the marker class itself.
*
* @param string $html Rendered field HTML from the framework.
* @param array $field Field config array.
* @return string Possibly transformed HTML.
*/
public function render_pro_locked_field( $html, $field ) {
// Pro plugin active: leave HTML untouched.
if ( function_exists( 'jltwp_adminify' ) && jltwp_adminify()->can_use_premium_code__premium_only() ) {
return $html;
}
$field_class = '';
if ( is_array( $field ) && isset( $field['class'] ) ) {
$field_class = (string) $field['class'];
}
// Detect field-level lock from either the new marker class
// (adminify-pro-locked) or the legacy Pro-feature classes that
// pre-date the render-disable hook. Both signal a Pro-only
// field that must not submit a value in the free build.
$has_field_lock = strpos( $field_class, 'adminify-pro-locked' ) !== false || strpos( $field_class, 'adminify-pro-fieldset' ) !== false || strpos( $field_class, 'adminify-pro-feature' ) !== false || strpos( $field_class, 'adminify-pro-notice' ) !== false;
// Per-option lock signal: the helper Utils::upgrade_pro_class()
// emits a next to a Pro-only
// checkbox label. Match that span (or the historical
// adminify-pro-locked-option marker) inside
blocks.
$has_option_lock = strpos( $html, 'adminify-pro-checkbox' ) !== false || strpos( $html, 'adminify-pro-locked-option' ) !== false;
if ( !$has_field_lock && !$has_option_lock ) {
return $html;
}
if ( $has_field_lock ) {
// Strip name attrs and disable inputs across the whole field.
// The visual treatment is the inline Pro
// rendered by the helper — no extra wrapper / overlay.
$html = $this->adminify_strip_inputs( $html );
return $html;
}
// Option-level: only strip inputs inside
blocks that
// carry the per-option marker. Match each