'default',
'calendar' => 'gregorian',
'time_format' => '24',
'use_site_tz' => 1,
'custom_timezone' => 'UTC',
'minimal_mode' => 0,
'time_color' => '#2ECC71',
'date_color' => '#E74C3C',
'clickable_clock' => 1,
'floating_clock' => 0, // Default OFF to keep classic toolbar behaviour.
'display_mode' => 'digital',
'analog_theme' => 'tomanify',
'analog_show_date' => 1,
'analog_size' => 'small',
];
}
/**
* Retrieve a single option (with defaults).
*
* @param string $key Option key.
* @return mixed|null
*/
function atlc_get_option( $key ) {
$all = wp_parse_args( get_option( ATLC_OPTION_NAME, [] ), atlc_default_options() );
return $all[ $key ] ?? null;
}
/**
* Determine whether the floating clock should be used.
*
* Floating is required for Analog mode (the admin bar is too small).
*
* @return bool
*/
function atlc_should_use_floating_clock() {
if ( 'analog' === atlc_get_option( 'display_mode' ) ) {
return true;
}
return ( (int) atlc_get_option( 'floating_clock' ) === 1 );
}
/**
* Return the site’s timezone (IANA or UTC±offset).
*
* @return string
*/
function atlc_get_site_timezone() {
$tz_string = get_option( 'timezone_string' );
if ( $tz_string ) {
return $tz_string;
}
$offset = get_option( 'gmt_offset' );
if ( ! $offset ) {
return 'UTC';
}
$hours = floor( $offset );
$minutes = abs( ( $offset - $hours ) * 60 );
return sprintf( 'UTC%+03d:%02d', $hours, $minutes );
}
/**
* Return the selected timezone based on settings.
*
* @return string
*/
function atlc_get_selected_timezone() {
return atlc_get_option( 'use_site_tz' )
? atlc_get_site_timezone()
: ( atlc_get_option( 'custom_timezone' ) ?: 'UTC' );
}
/**
* Settings URL.
*
* @return string
*/
function atlc_get_settings_url() {
return admin_url( 'options-general.php?page=' . ATLC_MENU_SLUG );
}
/* -------------------------------------------------------------------------- */
/* Internationalisation */
/* -------------------------------------------------------------------------- */
/**
* Scan /languages for available locales.
*
* @return array code => label
*/
function atlc_available_languages() {
static $cache = null;
if ( null !== $cache ) {
return $cache;
}
$cache = [ 'default' => __( 'Default (Dashboard)', 'admin-toolbar-live-clock' ) ];
foreach ( glob( plugin_dir_path( __FILE__ ) . 'languages/' . ATLC_DOMAIN . '-*.mo' ) as $file ) {
$code = str_replace( [ ATLC_DOMAIN . '-', '.mo' ], '', basename( $file ) );
$label = '';
if ( function_exists( 'locale_get_display_language' ) ) {
$label = locale_get_display_language( $code, $code );
}
if ( ! $label ) {
$map = [
'hi_IN' => 'हिन्दी',
'th_TH' => 'ไทย',
];
$label = $map[ $code ] ?? $code;
}
if ( preg_match( '/^[a-z]/i', $label ) ) {
$label = ucwords( $label );
}
$cache[ $code ] = sprintf( '%s (%s)', $label, $code );
}
$cache['en_US'] = $cache['en_US'] ?? 'English (en_US)';
return $cache;
}
add_filter(
'plugin_locale',
static function ( $locale, $domain ) {
if ( ATLC_DOMAIN !== $domain ) {
return $locale;
}
$sel = atlc_get_option( 'language' );
return ( $sel && 'default' !== $sel ) ? $sel : $locale;
},
10,
2
);
add_action(
'plugins_loaded',
static function () {
$sel = atlc_get_option( 'language' );
if ( $sel && 'default' !== $sel ) {
unload_textdomain( ATLC_DOMAIN );
if ( 'en_US' === $sel ) {
return;
}
$mofiles = [
plugin_dir_path( __FILE__ ) . 'languages/' . ATLC_DOMAIN . "-$sel.mo",
WP_LANG_DIR . '/plugins/' . ATLC_DOMAIN . "-$sel.mo",
];
foreach ( $mofiles as $mofile ) {
if ( is_readable( $mofile ) && load_textdomain( ATLC_DOMAIN, $mofile ) ) {
return;
}
}
}
},
0
);
/* -------------------------------------------------------------------------- */
/* Sanitisation */
/* -------------------------------------------------------------------------- */
/**
* Validate & sanitise settings.
*
* @param array $raw Raw options.
* @return array
*/
function atlc_sanitize_options( $raw ) {
$clean = atlc_default_options();
$raw = (array) $raw;
$langs = array_keys( atlc_available_languages() );
$calendars = [ 'gregorian', 'persian', 'islamic', 'hebrew', 'buddhist', 'japanese' ];
$display_modes = [ 'digital', 'analog' ];
$themes = [ 'modern', 'material', 'tomanify' ];
$analog_sizes = [ 'large', 'small' ];
$clean['minimal_mode'] = empty( $raw['minimal_mode'] ) ? 0 : 1;
if ( isset( $raw['display_mode'] ) && in_array( $raw['display_mode'], $display_modes, true ) ) {
$clean['display_mode'] = $raw['display_mode'];
}
if ( isset( $raw['analog_theme'] ) && in_array( $raw['analog_theme'], $themes, true ) ) {
$clean['analog_theme'] = $raw['analog_theme'];
}
$clean['analog_show_date'] = empty( $raw['analog_show_date'] ) ? 0 : 1;
if ( isset( $raw['analog_size'] ) && in_array( $raw['analog_size'], $analog_sizes, true ) ) {
$clean['analog_size'] = $raw['analog_size'];
}
if ( isset( $raw['language'] ) && in_array( $raw['language'], $langs, true ) ) {
$clean['language'] = $raw['language'];
}
if ( isset( $raw['calendar'] ) && in_array( $raw['calendar'], $calendars, true ) ) {
$clean['calendar'] = $raw['calendar'];
}
$clean['time_format'] = ( isset( $raw['time_format'] ) && '12' === $raw['time_format'] ) ? '12' : '24';
$clean['use_site_tz'] = empty( $raw['use_site_tz'] ) ? 0 : 1;
$clean['clickable_clock'] = empty( $raw['clickable_clock'] ) ? 0 : 1;
$clean['floating_clock'] = empty( $raw['floating_clock'] ) ? 0 : 1;
if ( isset( $raw['custom_timezone'] ) && in_array( $raw['custom_timezone'], timezone_identifiers_list(), true ) ) {
$clean['custom_timezone'] = $raw['custom_timezone'];
}
foreach ( [ 'time_color', 'date_color' ] as $c ) {
$hex = sanitize_hex_color( $raw[ $c ] ?? '' );
if ( $hex ) {
$clean[ $c ] = strtoupper( $hex );
}
}
if ( 1 === (int) $clean['minimal_mode'] ) {
// Minimal (v1-like) mode: hide advanced features and revert to defaults.
$clean['display_mode'] = 'digital';
$clean['floating_clock'] = 0;
$clean['clickable_clock'] = 0;
// Default colours.
$clean['time_color'] = '#2ECC71';
$clean['date_color'] = '#E74C3C';
// Keep analog-related options in safe defaults (not used while digital).
$clean['analog_theme'] = 'modern';
$clean['analog_show_date'] = 1;
$clean['analog_size'] = 'large';
}
if ( 'analog' === $clean['display_mode'] ) {
$clean['floating_clock'] = 1;
}
return $clean;
}
/* -------------------------------------------------------------------------- */
/* Settings page */
/* -------------------------------------------------------------------------- */
add_action(
'admin_menu',
static function () {
add_options_page(
__( 'Admin Toolbar Live Clock', 'admin-toolbar-live-clock' ),
__( 'Toolbar Clock', 'admin-toolbar-live-clock' ),
'manage_options',
ATLC_MENU_SLUG,
'atlc_render_settings_page'
);
}
);
add_action(
'admin_init',
static function () {
register_setting( ATLC_OPTION_GROUP, ATLC_OPTION_NAME, 'atlc_sanitize_options' );
// Tabs (sections) for a cleaner settings UI.
add_settings_section( 'atlc_general', '', '__return_false', ATLC_MENU_SLUG );
add_settings_section( 'atlc_style', '', '__return_false', ATLC_MENU_SLUG );
add_settings_section( 'atlc_about', '', '__return_false', ATLC_MENU_SLUG );
$general_fields = [
'minimal_mode' => __( 'Minimal mode', 'admin-toolbar-live-clock' ),
'calendar' => __( 'Calendar system', 'admin-toolbar-live-clock' ),
'time_format' => __( 'Clock format', 'admin-toolbar-live-clock' ),
'use_site_tz' => __( 'Use site timezone', 'admin-toolbar-live-clock' ),
'custom_timezone' => __( 'Custom timezone', 'admin-toolbar-live-clock' ),
'language' => __( 'Plugin language', 'admin-toolbar-live-clock' ),
'clickable_clock' => __( 'Make clock clickable', 'admin-toolbar-live-clock' ),
];
$style_fields = [
'display_mode' => __( 'Clock style', 'admin-toolbar-live-clock' ),
'analog_theme' => __( 'Analog theme', 'admin-toolbar-live-clock' ),
'analog_size' => __( 'Analog size', 'admin-toolbar-live-clock' ),
'analog_show_date' => __( 'Show date', 'admin-toolbar-live-clock' ),
'time_color' => __( 'Clock colour', 'admin-toolbar-live-clock' ),
'date_color' => __( 'Date colour', 'admin-toolbar-live-clock' ),
'floating_clock' => __( 'Enable floating (draggable) clock', 'admin-toolbar-live-clock' ),
];
foreach ( $general_fields as $id => $label ) {
add_settings_field( $id, $label, "atlc_field_{$id}", ATLC_MENU_SLUG, 'atlc_general' );
}
foreach ( $style_fields as $id => $label ) {
add_settings_field( $id, $label, "atlc_field_{$id}", ATLC_MENU_SLUG, 'atlc_style' );
}
}
);
/* ---------- field callbacks ----------- */
function atlc_field_language() {
$val = atlc_get_option( 'language' );
?>
__( 'Gregorian', 'admin-toolbar-live-clock' ),
'persian' => __( 'Jalali (Persian)', 'admin-toolbar-live-clock' ),
'islamic' => __( 'Hijri (Islamic)', 'admin-toolbar-live-clock' ),
'hebrew' => __( 'Hebrew', 'admin-toolbar-live-clock' ),
'buddhist' => __( 'Buddhist (Thai)', 'admin-toolbar-live-clock' ),
'japanese' => __( 'Japanese', 'admin-toolbar-live-clock' ),
];
?>
__( '24-hour', 'admin-toolbar-live-clock' ),
'12' => __( '12-hour AM/PM', 'admin-toolbar-live-clock' ),
];
?>
/> /> ', esc_attr( ATLC_OPTION_NAME ), esc_attr( $key ), esc_attr( (string) atlc_get_option( $key ) ) ); } function atlc_field_time_color() { atlc_color_picker_input( 'time_color' ); } function atlc_field_date_color() { atlc_color_picker_input( 'date_color' ); } /** * Render settings page. */ function atlc_render_settings_page() { $active_tab = 'general'; // Tab selection is a UI-only query var (no state changes). Nonce is not required. // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( isset( $_GET['atlc_tab'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $maybe = sanitize_key( wp_unslash( $_GET['atlc_tab'] ) ); if ( in_array( $maybe, [ 'general', 'style', 'about' ], true ) ) { $active_tab = $maybe; } } ?>