'Version' ] );
define( 'ADMIN_HERO_VERSION', $plugin_data['Version'] );
define( 'ADMIN_HERO_DIR', plugin_dir_path( __FILE__ ) );
define( 'ADMIN_HERO_URL', plugin_dir_url( __FILE__ ) );
// -----------------------------------------------------------------------------
// LOAD FEATURE LOADER (dynamic versioned file)
// -----------------------------------------------------------------------------
$loader_files = glob( ADMIN_HERO_DIR . 'includes/class-feature-loader*.php' );
if ( ! empty( $loader_files ) ) {
rsort( $loader_files );
require_once $loader_files[0];
} elseif ( file_exists( ADMIN_HERO_DIR . 'includes/class-feature-loader.php' ) ) {
require_once ADMIN_HERO_DIR . 'includes/class-feature-loader.php';
} else {
add_action( 'admin_notices', function() {
echo '
AdminHero error: feature-loader file is missing.
';
} );
return;
}
class Admin_Hero {
/** @var Admin_Hero_Feature_Loader */
private $feature_loader;
public function __construct() {
$this->feature_loader = new Admin_Hero_Feature_Loader();
$this->setup_hooks();
}
private function setup_hooks() {
// 1) Load all panel- and feature-bootstrappers
add_action( 'plugins_loaded', [ $this, 'load_features' ] );
// 2) Enqueue & render modal in Dashboard and front-end
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_assets' ] );
add_action( 'admin_footer', [ $this, 'render_modal' ] );
add_action( 'wp_footer', [ $this, 'render_modal' ] );
// 3) AJAX handlers
add_action( 'wp_ajax_admin_hero_save_note', [ $this, 'save_note' ] );
add_action( 'wp_ajax_admin_hero_refresh_nonce', [ $this, 'refresh_nonce' ] );
add_action( 'wp_ajax_admin_hero_save_settings', [ $this, 'save_settings' ] );
add_action( 'wp_ajax_admin_hero_mark_onboarding_seen', [ $this, 'mark_onboarding_seen' ] );
add_action( 'wp_ajax_admin_hero_reset_onboarding', [ $this, 'reset_onboarding' ] );
}
public function load_features() {
// panel bootstrappers
$info_boot = glob( ADMIN_HERO_DIR . 'panels/info/info*.php' );
if ( ! empty( $info_boot ) ) {
require_once $info_boot[0];
}
$tasks_boot = glob( ADMIN_HERO_DIR . 'panels/tasks/tasks*.php' );
if ( ! empty( $tasks_boot ) ) {
require_once $tasks_boot[0];
}
// real features
$this->feature_loader->load_features( ADMIN_HERO_DIR . 'features/' );
}
public function enqueue_assets() {
if ( ! current_user_can( 'edit_posts' ) ) {
return;
}
$is_admin = is_admin();
$frontend_feat = $this->feature_loader->get_feature( 'frontend' );
$is_frontend = ! $is_admin && $frontend_feat && ! empty( $frontend_feat['enabled'] );
if ( ! ( $is_admin || $is_frontend ) ) {
return;
}
// core CSS
$css_files = glob( ADMIN_HERO_DIR . 'assets/css/admin-hero*.css' );
if ( ! empty( $css_files ) ) {
rsort( $css_files );
$css_file = basename( $css_files[0] );
} else {
$css_file = 'admin-hero.css';
}
wp_enqueue_style( 'admin-hero-css', ADMIN_HERO_URL . 'assets/css/' . $css_file, [], ADMIN_HERO_VERSION );
// core JS
$js_files = glob( ADMIN_HERO_DIR . 'assets/js/admin-hero*.js' );
if ( ! empty( $js_files ) ) {
rsort( $js_files );
$js_file = basename( $js_files[0] );
} else {
$js_file = 'admin-hero.js';
}
wp_enqueue_script( 'admin-hero-js', ADMIN_HERO_URL . 'assets/js/' . $js_file, [ 'jquery' ], ADMIN_HERO_VERSION, true );
// third-party assets
wp_enqueue_style( 'font-awesome', ADMIN_HERO_URL . 'assets/fontawesome/css/all.min.css', [], '6.7.2' );
wp_enqueue_style( 'quill-css', ADMIN_HERO_URL . 'assets/quilleditor/quill.snow.css', [], '2.0.3' );
wp_enqueue_script( 'quill-js', ADMIN_HERO_URL . 'assets/quilleditor/quill.min.js', [], '2.0.3', true );
// get default panel setting
$all_settings = get_option( 'admin_hero_settings', [] );
$default_panel = isset( $all_settings['default_panel'] ) ? $all_settings['default_panel'] : 'settings';
// localize
wp_localize_script( 'admin-hero-js', 'AdminHero', [
'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'admin_hero_action' ),
'version' => ADMIN_HERO_VERSION,
'is_admin' => $is_admin,
'is_pro' => defined( 'ADMIN_HERO_PRO_VERSION' ) && ADMIN_HERO_PRO_VERSION,
'logo_url' => ADMIN_HERO_URL . 'assets/img/ah-logo.png',
'logo_pro_url' => ADMIN_HERO_URL . 'assets/img/ah-logo-pro.webp',
'features' => array_values( $this->feature_loader->get_features() ),
'defaultOpenPanel' => $default_panel,
'onboardingSeen' => get_user_meta( get_current_user_id(), 'admin_hero_onboarding_seen', true ) ? true : false,
] );
// per-feature enqueue callbacks
foreach ( $this->feature_loader->get_features() as $feature ) {
if ( ! empty( $feature['enabled'] )
&& ! empty( $feature['enqueue_callback'] )
&& is_callable( $feature['enqueue_callback'] )
) {
call_user_func( $feature['enqueue_callback'] );
}
}
}
public function render_modal() {
if ( ! current_user_can( 'edit_posts' ) ) {
return;
}
$is_admin = is_admin();
$frontend_feat = $this->feature_loader->get_feature( 'frontend' );
$is_frontend = ! $is_admin && $frontend_feat && ! empty( $frontend_feat['enabled'] );
if ( ! ( $is_admin || $is_frontend ) ) {
return;
}
$user = wp_get_current_user();
$note = get_user_meta( $user->ID, 'admin_hero_text', true );
$last_saved = get_user_meta( $user->ID, 'admin_hero_last_saved', true );
$timestamp = 'Last saved: ' . (
$last_saved
? date_i18n( ADMIN_HERO_TIMESTAMP_FORMAT, strtotime( $last_saved ) )
: 'Never saved'
);
$all_settings = get_option( 'admin_hero_settings', [] );
$default = isset( $all_settings['default_panel'] ) ? $all_settings['default_panel'] : 'settings';
$nonce = wp_create_nonce( 'admin_hero_action' );
$onboarding_flag = ! get_user_meta( $user->ID, 'admin_hero_onboarding_seen', true );
do_action( 'admin_hero_render_modal_before', $user, $note, $timestamp, $nonce );
// dynamic modal template
$modal_files = glob( ADMIN_HERO_DIR . 'templates/modal*.php' );
$modal_file = ! empty( $modal_files ) ? $modal_files[0] : ADMIN_HERO_DIR . 'templates/modal.php';
$modal_file = apply_filters( 'admin_hero_modal_template', $modal_file );
if ( file_exists( $modal_file ) ) {
include $modal_file;
}
do_action( 'admin_hero_render_modal_after' );
}
public function save_note() {
check_ajax_referer( 'admin_hero_action', 'nonce' );
if ( ! current_user_can( 'edit_posts' ) ) {
wp_send_json_error( [ 'message' => 'Unauthorized' ] );
}
$user_id = get_current_user_id();
$note = wp_kses_post( wp_unslash( $_POST['note'] ?? '' ) );
update_user_meta( $user_id, 'admin_hero_text', $note );
update_user_meta( $user_id, 'admin_hero_last_saved', current_time( 'mysql' ) );
wp_send_json_success([
'message' => 'Note saved',
'timestamp' => date_i18n( ADMIN_HERO_TIMESTAMP_FORMAT, current_time( 'timestamp' ) ),
]);
}
public function refresh_nonce() {
if ( ! current_user_can( 'edit_posts' ) ) {
wp_send_json_error( [ 'message' => 'Unauthorized' ] );
}
wp_send_json_success( [ 'nonce' => wp_create_nonce( 'admin_hero_action' ) ] );
}
public function save_settings() {
check_ajax_referer( 'admin_hero_action', 'nonce' );
if ( ! current_user_can( 'edit_posts' ) ) {
wp_send_json_error( [ 'message' => 'Unauthorized' ] );
}
// Grab entire settings array
$raw_settings = filter_input( INPUT_POST, 'settings', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
$settings = is_array( $raw_settings ) ? wp_unslash( $raw_settings ) : [];
// Sanitize default_panel
if ( isset( $settings['default_panel'] ) ) {
$valid_panels = [ 'notes', 'tasks', 'info', 'settings' ];
$settings['default_panel'] = in_array( $settings['default_panel'], $valid_panels ) ? $settings['default_panel'] : 'settings';
}
// Persist full settings array to options
update_option( 'admin_hero_settings', $settings );
// Save individual feature flags to usermeta
foreach ( $settings as $feature_id => $value ) {
if ( 'default_panel' === $feature_id ) {
continue;
}
$feature = $this->feature_loader->get_feature( $feature_id );
if ( $feature && ! empty( $feature['sanitize_callback'] ) ) {
$value = call_user_func( $feature['sanitize_callback'], $value );
}
update_user_meta( get_current_user_id(), "admin_hero_feature_{$feature_id}", sanitize_text_field( $value ) );
}
wp_send_json_success( [ 'message' => 'Settings saved' ] );
}
public function mark_onboarding_seen() {
check_ajax_referer( 'admin_hero_action', 'nonce' );
if ( ! current_user_can( 'edit_posts' ) ) {
wp_send_json_error( [ 'message' => 'Unauthorized' ] );
}
update_user_meta( get_current_user_id(), 'admin_hero_onboarding_seen', true );
wp_send_json_success();
}
public function reset_onboarding() {
check_ajax_referer( 'admin_hero_action', 'nonce' );
if ( ! current_user_can( 'edit_posts' ) ) {
wp_send_json_error( [ 'message' => 'Unauthorized' ] );
}
delete_user_meta( get_current_user_id(), 'admin_hero_onboarding_seen' );
wp_send_json_success();
}
}
new Admin_Hero();