/* version: v0.3.1 | date: 2026-04-23 15:45 UTC+03:00 | Support modal: Fetch and display HubSpot company contract info on selection */ /* version: v0.3.0 | date: 2026-04-03 12:00 UTC+07:00 | Admin inbox: image upload via paste/attach button */ /* version: v0.2.2 | date: 2026-02-28 12:36 UTC+07:00 | WP-Admin: floating ticket button + tenant mode (booking admin) */ /* Plugin Name: SH Support Inbox Description: WP-Admin Support Inbox (2-pane) for replying as shared Support identity. Version: 0.2.2 Author: SportsHunter Team */ if (!defined('ABSPATH')) { exit; } final class SH_Support_Inbox_Plugin { const NONCE_ACTION = 'sh_support_inbox'; const MENU_SLUG = 'sh-support-inbox'; const TENANT_TARGET_PAGE_SLUG = 'sportshunter'; // Keep this list centralized for easy future updates (e.g. add booknetic_staff). private static array $TENANT_ALLOWED_ROLES = [ 'booknetic_saas_tenant', 'booknetic_staff', ]; private static function current_user_can_use_admin_support_ui(): bool { if (!is_user_logged_in() || !is_admin()) { return false; } $u = wp_get_current_user(); $roles = is_object($u) && isset($u->roles) && is_array($u->roles) ? $u->roles : []; // Exclude tenants (even if they can hit some wp-admin endpoints). if (in_array('sh_tenant', $roles, true) || in_array('booknetic_saas_tenant', $roles, true)) { return false; } // Allow anyone who can access wp-admin for content/admin work. if (current_user_can('manage_options')) { return true; } return current_user_can('edit_posts') || current_user_can('edit_pages') || current_user_can('moderate_comments'); } private static function is_tenant_target_page(): bool { if (!is_admin()) { return false; } $pagenow = isset($GLOBALS['pagenow']) ? (string) $GLOBALS['pagenow'] : ''; if ($pagenow !== 'admin.php') { return false; } $page = isset($_GET['page']) ? sanitize_text_field((string) $_GET['page']) : ''; return $page === self::TENANT_TARGET_PAGE_SLUG; } private static function current_user_is_allowed_tenant(): bool { if (!is_user_logged_in() || !is_admin()) { return false; } $u = wp_get_current_user(); $roles = is_object($u) && isset($u->roles) && is_array($u->roles) ? $u->roles : []; foreach (self::$TENANT_ALLOWED_ROLES as $r) { if (in_array($r, $roles, true)) { return true; } } return false; } public static function init(): void { add_action('admin_menu', [self::class, 'register_menu']); add_action('admin_enqueue_scripts', [self::class, 'enqueue_assets']); } public static function register_menu(): void { add_menu_page( 'Support Inbox', 'Support Inbox', 'manage_options', self::MENU_SLUG, [self::class, 'render_page'], 'dashicons-format-chat', 0.1 ); } public static function enqueue_assets(string $hook_suffix): void { $is_admin_mode = self::current_user_can_use_admin_support_ui(); // Tenant button is enabled only on the booking admin page. $is_target_booking_page = self::is_tenant_target_page(); $should_enqueue_global = $is_admin_mode || $is_target_booking_page; // Tenant mode: booking admin page for non-admin users. $tenant_mode = $is_target_booking_page && !$is_admin_mode; if ($should_enqueue_global) { $base_url = plugin_dir_url(__FILE__); $global_css_path = plugin_dir_path(__FILE__) . 'assets/global.css'; $global_js_path = plugin_dir_path(__FILE__) . 'assets/global.js'; $global_css_ver = file_exists($global_css_path) ? (string) filemtime($global_css_path) : '0.2.2'; $global_js_ver = file_exists($global_js_path) ? (string) filemtime($global_js_path) : '0.2.2'; wp_enqueue_style( 'sh-support-inbox-global', $base_url . 'assets/global.css', [], $global_css_ver ); wp_enqueue_script( 'sh-support-inbox-global', $base_url . 'assets/global.js', [], $global_js_ver, true ); wp_localize_script('sh-support-inbox-global', 'shSupportInboxGlobal', [ 'apiUrl' => home_url('/app-api/support-messaging.php'), 'nonce' => wp_create_nonce(self::NONCE_ACTION), 'menuSlug' => self::MENU_SLUG, 'assetsUrl' => $base_url . 'assets/', 'tenantPageSlug' => self::TENANT_TARGET_PAGE_SLUG, 'tenantAllowedRoles' => array_values(self::$TENANT_ALLOWED_ROLES), 'tenantMode' => $tenant_mode, ]); } if ($hook_suffix !== 'toplevel_page_' . self::MENU_SLUG) { return; } $base_url = plugin_dir_url(__FILE__); $admin_css_path = plugin_dir_path(__FILE__) . 'assets/admin.css'; $admin_js_path = plugin_dir_path(__FILE__) . 'assets/admin.js'; $admin_css_ver = file_exists($admin_css_path) ? (string) filemtime($admin_css_path) : '0.2.2'; $admin_js_ver = file_exists($admin_js_path) ? (string) filemtime($admin_js_path) : '0.2.2'; wp_enqueue_style( 'sh-support-inbox-admin', $base_url . 'assets/admin.css', [], $admin_css_ver ); wp_enqueue_script( 'sh-support-inbox-admin', $base_url . 'assets/admin.js', [], $admin_js_ver, true ); $logo_url = 'https://www.sportshunter.gr/wp-content/plugins/sh-reviews/assets/img/sh_3d_logo.png'; // Fallback logic (kept for future) // $custom_logo_id = (int) get_theme_mod('custom_logo'); // if ($custom_logo_id > 0) { // $custom_logo_url = wp_get_attachment_image_url($custom_logo_id, 'full'); // if (is_string($custom_logo_url) && $custom_logo_url !== '') { // $logo_url = $custom_logo_url; // } // } // if ($logo_url === '') { // $site_icon_url = get_site_icon_url(128); // if (is_string($site_icon_url) && $site_icon_url !== '') { // $logo_url = $site_icon_url; // } // } wp_localize_script('sh-support-inbox-admin', 'shSupportInbox', [ 'apiUrl' => home_url('/app-api/support-messaging.php'), 'nonce' => wp_create_nonce(self::NONCE_ACTION), 'backUrl' => admin_url('index.php'), 'logoUrl' => $logo_url, ]); } public static function render_page(): void { if (!current_user_can('manage_options')) { wp_die('Unauthorized'); } $nonce = wp_create_nonce(self::NONCE_ACTION); echo '
'; } } SH_Support_Inbox_Plugin::init();