'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 the feature‐loader class (with sorting & fallback)
// -----------------------------------------------------------------------------
$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 '
Admin Hero error: feature‐loader file is missing.
';
} );
// stop here to avoid fatal
return;
}
class Admin_Hero {
private $feature_loader;
public function __construct() {
$this->feature_loader = new Admin_Hero_Feature_Loader();
$this->setup_hooks();
}
private function setup_hooks() {
// load features for both admin & AJAX
add_action( 'plugins_loaded', [ $this, 'load_features' ] );
// only enqueue & render modal in wp-admin
if ( is_admin() ) {
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
add_action( 'admin_footer', [ $this, 'render_modal' ] );
}
// AJAX saves still work anywhere
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' ] );
}
public function load_features() {
$this->feature_loader->load_features( ADMIN_HERO_DIR . 'features/' );
}
public function enqueue_assets() {
// only in Dashboard and for users who can edit posts
if ( ! is_admin() || ! current_user_can( 'edit_posts' ) ) {
return;
}
// CSS: latest
$css_files = glob( ADMIN_HERO_DIR . 'assets/css/admin-hero*.css' );
$css_file = ! empty( $css_files ) ? basename( $css_files[0] ) : 'admin-hero.css';
wp_enqueue_style( 'admin-hero-css', ADMIN_HERO_URL . 'assets/css/' . $css_file, [], ADMIN_HERO_VERSION );
// JS: latest
$js_files = glob( ADMIN_HERO_DIR . 'assets/js/admin-hero*.js' );
$js_file = ! empty( $js_files ) ? basename( $js_files[0] ) : 'admin-hero.js';
wp_enqueue_script( 'admin-hero-js', ADMIN_HERO_URL . 'assets/js/' . $js_file, [ 'jquery' ], ADMIN_HERO_VERSION, true );
// Font Awesome
wp_enqueue_style( 'font-awesome', ADMIN_HERO_URL . 'assets/fontawesome/css/all.min.css', [], '6.7.2' );
// Quill Editor (local)
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 );
// Pass data to JS
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' => true,
'features' => $this->feature_loader->get_features(),
] );
}
public function render_modal() {
// only in Dashboard and for users who can edit posts
if ( ! is_admin() || ! current_user_can( 'edit_posts' ) ) {
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'
);
$nonce = wp_create_nonce( 'admin_hero_action' );
// Before hook
do_action( 'admin_hero_render_modal_before', $user, $note, $timestamp, $nonce );
// pick template (Free or Pro override)
$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;
}
// After hook
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' ] );
}
$raw_settings = filter_input( INPUT_POST, 'settings', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
$raw_settings = is_array( $raw_settings ) ? wp_unslash( $raw_settings ) : [];
$settings = [];
foreach ( $raw_settings as $feature_id => $value ) {
$feature_id = sanitize_key( $feature_id );
$value = is_array( $value ) ? array_map( 'sanitize_text_field', $value ) : sanitize_text_field( $value );
$settings[ $feature_id ] = $value;
}
$user_id = get_current_user_id();
foreach ( $settings as $feature_id => $value ) {
$feature = $this->feature_loader->get_feature( $feature_id );
if ( $feature && isset( $feature['sanitize_callback'] ) ) {
$value = call_user_func( $feature['sanitize_callback'], $value );
}
update_user_meta( $user_id, "admin_hero_feature_{$feature_id}", $value );
}
wp_send_json_success( [ 'message' => 'Settings saved' ] );
}
}
new Admin_Hero();