diff --git a/assets/css/hvac-announcements-admin.css b/assets/css/hvac-announcements-admin.css index b8fb378c..2af15796 100644 --- a/assets/css/hvac-announcements-admin.css +++ b/assets/css/hvac-announcements-admin.css @@ -171,7 +171,7 @@ width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); - z-index: 999999; + z-index: 100000; /* Below WordPress media modal (160000) to allow media library to stack on top */ display: flex; justify-content: center; align-items: center; diff --git a/assets/js/hvac-announcements-admin.js b/assets/js/hvac-announcements-admin.js index 78faeb61..32566aac 100644 --- a/assets/js/hvac-announcements-admin.js +++ b/assets/js/hvac-announcements-admin.js @@ -16,7 +16,7 @@ jQuery(document).ready(function($) { // Initialize init(); - + /** * Initialize the announcements interface */ @@ -24,27 +24,8 @@ jQuery(document).ready(function($) { loadAnnouncements(); loadCategories(); initializeEventHandlers(); - initializeEditor(); - } - - /** - * Initialize TinyMCE editor - */ - function initializeEditor() { - if (typeof wp !== 'undefined' && wp.editor) { - // Initialize WordPress editor - wp.editor.initialize('announcement-content', { - tinymce: { - wpautop: true, - plugins: 'lists link image media paste', - toolbar1: 'formatselect | bold italic | alignleft aligncenter alignright | bullist numlist | link unlink | wp_adv', - toolbar2: 'strikethrough hr forecolor pastetext removeformat charmap outdent indent undo redo wp_help', - height: 300 - }, - quicktags: true, - mediaButtons: true - }); - } + // NOTE: Editor initialization removed - wp_editor() PHP function handles this + // The duplicate JavaScript initialization was causing the media modal to auto-open } /** @@ -255,6 +236,10 @@ jQuery(document).ready(function($) { $modal.addClass('active'); $('body').addClass('modal-open'); + // Add custom "Add Media" button to TinyMCE editor toolbar + // This is needed because media_buttons => false in wp_editor() to prevent auto-open + addMediaButtonToEditor(); + if (announcementId) { $('#modal-title').text('Edit Announcement'); loadAnnouncementForEdit(announcementId); @@ -263,6 +248,72 @@ jQuery(document).ready(function($) { resetForm(); } } + + /** + * Add custom "Add Media" button to TinyMCE editor + * Required because wp_editor has media_buttons => false to prevent auto-open in hidden modal + */ + function addMediaButtonToEditor() { + // Check if button already exists + if ($('#wp-announcement-content-media-buttons').length > 0) { + return; + } + + // Create media button container + const $mediaButton = $('
'); + const $addMediaBtn = $(''); + $addMediaBtn.html(' Add Media'); + + // Add click handler + $addMediaBtn.on('click', function(e) { + e.preventDefault(); + openEditorMediaUploader(); + }); + + $mediaButton.append($addMediaBtn); + + // Insert button before editor wrapper + $('#wp-announcement-content-wrap').before($mediaButton); + } + + /** + * Open media uploader for the announcement content editor + */ + function openEditorMediaUploader() { + if (typeof wp.media === 'undefined') { + return; + } + + const editorMediaUploader = wp.media({ + title: 'Insert Media', + button: { + text: 'Insert into post' + }, + multiple: true + }); + + editorMediaUploader.on('select', function() { + const selection = editorMediaUploader.state().get('selection'); + const editor = tinymce.get('announcement-content'); + + selection.forEach(function(attachment) { + attachment = attachment.toJSON(); + let html = ''; + + if (attachment.type === 'image') { + html = '' + (attachment.alt || '') + ''; + } else { + html = '' + attachment.title + ''; + } + + if (editor) { + editor.insertContent(html); + } + }); + }); + + editorMediaUploader.open(); + } /** * Close the modal @@ -280,15 +331,18 @@ jQuery(document).ready(function($) { function resetForm() { $('#announcement-form')[0].reset(); $('#announcement-id').val(''); - - // Reset editor - if (wp.editor) { - wp.editor.setContent('announcement-content', ''); + + // Reset editor using TinyMCE native API + if (typeof tinymce !== 'undefined') { + const editor = tinymce.get('announcement-content'); + if (editor) { + editor.setContent(''); + } } - + // Reset featured image removeFeaturedImage(); - + // Uncheck all categories $('#categories-container input[type="checkbox"]').prop('checked', false); } @@ -320,26 +374,29 @@ jQuery(document).ready(function($) { $('#announcement-excerpt').val(announcement.excerpt); $('#announcement-status').val(announcement.status); $('#announcement-tags').val(announcement.tags); - - // Set content in editor - if (wp.editor) { - wp.editor.setContent('announcement-content', announcement.content); + + // Set content in editor using TinyMCE native API + if (typeof tinymce !== 'undefined') { + const editor = tinymce.get('announcement-content'); + if (editor) { + editor.setContent(announcement.content || ''); + } } - + // Set publish date if (announcement.date) { const date = new Date(announcement.date); const localDate = date.toISOString().slice(0, 16); $('#announcement-date').val(localDate); } - + // Set categories if (announcement.categories && announcement.categories.length > 0) { announcement.categories.forEach(function(catId) { $('#categories-container input[value="' + catId + '"]').prop('checked', true); }); } - + // Set featured image if (announcement.featured_image_id) { $('#featured-image-id').val(announcement.featured_image_id); @@ -354,12 +411,19 @@ jQuery(document).ready(function($) { * Save announcement (create or update) */ function saveAnnouncement() { - // Get editor content + // Get editor content using WordPress editor API or TinyMCE native API let content = ''; - if (wp.editor) { + if (typeof wp !== 'undefined' && wp.editor && wp.editor.getContent) { + // Use WordPress API if available (WordPress 4.8+) content = wp.editor.getContent('announcement-content'); + } else if (typeof tinymce !== 'undefined') { + // Fallback to TinyMCE native API + const editor = tinymce.get('announcement-content'); + if (editor) { + content = editor.getContent(); + } } - + // Gather form data const formData = { action: $('#announcement-id').val() ? 'hvac_update_announcement' : 'hvac_create_announcement', @@ -374,12 +438,12 @@ jQuery(document).ready(function($) { categories: [], featured_image_id: $('#featured-image-id').val() }; - + // Get selected categories $('#categories-container input:checked').each(function() { formData.categories.push($(this).val()); }); - + // Send AJAX request $.post(hvac_announcements.ajax_url, formData, function(response) { if (response.success) { diff --git a/includes/class-hvac-announcements-admin.php b/includes/class-hvac-announcements-admin.php index cfedeaad..626c84e7 100644 --- a/includes/class-hvac-announcements-admin.php +++ b/includes/class-hvac-announcements-admin.php @@ -40,35 +40,65 @@ class HVAC_Announcements_Admin { * Constructor */ private function __construct() { + error_log('HVAC_Announcements_Admin: Constructor called - initializing hooks'); $this->init_hooks(); + error_log('HVAC_Announcements_Admin: Hooks initialized successfully'); } /** * Initialize hooks */ private function init_hooks() { - add_action('wp_enqueue_scripts', array($this, 'enqueue_admin_assets')); + error_log('HVAC_Announcements_Admin: Registering wp_enqueue_scripts hook with priority 20'); + // Use priority 20 to ensure post object is available + add_action('wp_enqueue_scripts', array($this, 'enqueue_admin_assets'), 20); + error_log('HVAC_Announcements_Admin: Hook registered successfully'); + + // Also try init hook to verify hooks are working at all + add_action('init', array($this, 'test_hook')); + } + + /** + * Test hook to verify hooks are working + */ + public function test_hook() { + error_log('HVAC_Announcements_Admin: TEST HOOK FIRED - hooks are working!'); } /** * Enqueue admin assets on master trainer pages */ public function enqueue_admin_assets() { + // Debug logging + error_log('HVAC Announcements Admin: enqueue_admin_assets called'); + error_log('HVAC Announcements Admin: is_master_trainer = ' . (HVAC_Announcements_Permissions::is_master_trainer() ? 'YES' : 'NO')); + error_log('HVAC Announcements Admin: is_page_template check = ' . (is_page_template('page-master-announcements.php') ? 'YES' : 'NO')); + + $queried = get_queried_object(); + if ($queried) { + error_log('HVAC Announcements Admin: queried_object type = ' . get_class($queried)); + if (is_a($queried, 'WP_Post')) { + error_log('HVAC Announcements Admin: post_name = ' . $queried->post_name); + error_log('HVAC Announcements Admin: post_type = ' . $queried->post_type); + $template = get_post_meta($queried->ID, '_wp_page_template', true); + error_log('HVAC Announcements Admin: page_template meta = ' . $template); + } + } + // Only enqueue on master trainer announcement pages if ($this->is_master_trainer_announcement_page()) { - // Ensure jQuery and editor dependencies are loaded in head - // CRITICAL: Load in head (false) because wp_editor() outputs inline scripts in body - wp_enqueue_script('jquery'); - wp_enqueue_script('editor'); + error_log('HVAC Announcements Admin: ENQUEUING SCRIPTS'); + + // Enqueue editor - dependencies handled automatically wp_enqueue_editor(); - // Enqueue admin JavaScript - MUST load in head to be available for wp_editor inline scripts + // Enqueue admin JavaScript - Load in footer after wp_editor inline scripts wp_enqueue_script( 'hvac-announcements-admin', plugin_dir_url(dirname(__FILE__)) . 'assets/js/hvac-announcements-admin.js', array('jquery', 'editor'), defined('HVAC_VERSION') ? HVAC_VERSION : '1.0.0', - false // Load in head, not footer, for wp_editor compatibility + true // Load in footer after wp_editor inline scripts ); // Localize script with AJAX data @@ -99,29 +129,56 @@ class HVAC_Announcements_Admin { /** * Check if current page is master trainer announcement page * + * Uses multi-layered detection approach for reliability during wp_enqueue_scripts + * @see class-hvac-scripts-styles.php for pattern reference + * * @return bool */ private function is_master_trainer_announcement_page() { - global $post; - - if (!is_a($post, 'WP_Post')) { - return false; - } - - // Check if user is master trainer + // Check if user is master trainer first if (!HVAC_Announcements_Permissions::is_master_trainer()) { return false; } - - // Check for announcement pages - $announcement_slugs = array( - 'announcements', // Primary announcement page - 'master-announcements', - 'master-manage-announcements', - 'manage-announcements' + + // PRIMARY: Check URL path (most reliable during wp_enqueue_scripts) + $current_path = isset($_SERVER['REQUEST_URI']) ? trim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/') : ''; + + $announcement_paths = array( + 'master-trainer/announcements', + 'master-trainer/master-announcements', + 'master-trainer/manage-announcements' ); - - return in_array($post->post_name, $announcement_slugs); + + foreach ($announcement_paths as $path) { + if (strpos($current_path, $path) !== false) { + return true; + } + } + + // SECONDARY: Check page template (may not work during wp_enqueue_scripts) + if (is_page_template('page-master-announcements.php')) { + return true; + } + + // TERTIARY: Check by page slug + if (is_page('announcements') || is_page('master-announcements') || is_page('manage-announcements')) { + return true; + } + + // FALLBACK: Check queried object for announcement slugs + $queried_object = get_queried_object(); + if (is_a($queried_object, 'WP_Post')) { + $announcement_slugs = array( + 'announcements', + 'master-announcements', + 'master-manage-announcements', + 'manage-announcements' + ); + + return in_array($queried_object->post_name, $announcement_slugs); + } + + return false; } /** @@ -214,9 +271,11 @@ class HVAC_Announcements_Admin {
false to prevent auto-open in hidden modal + // Media button will be added manually via JavaScript when modal opens wp_editor('', 'announcement-content', array( 'textarea_name' => 'announcement_content', - 'media_buttons' => true, + 'media_buttons' => false, // FIXED: Prevents media modal auto-open in hidden div 'textarea_rows' => 10, 'teeny' => false, 'dfw' => false, diff --git a/includes/class-hvac-plugin.php b/includes/class-hvac-plugin.php index 0f8c5daf..23e99a18 100644 --- a/includes/class-hvac-plugin.php +++ b/includes/class-hvac-plugin.php @@ -115,7 +115,7 @@ final class HVAC_Plugin { define('HVAC_PLUGIN_VERSION', '2.0.0'); } if (!defined('HVAC_VERSION')) { - define('HVAC_VERSION', '2.0.1'); + define('HVAC_VERSION', '2.1.5'); } if (!defined('HVAC_PLUGIN_FILE')) { define('HVAC_PLUGIN_FILE', dirname(__DIR__) . '/hvac-community-events.php'); @@ -238,6 +238,7 @@ final class HVAC_Plugin { 'class-hvac-master-events-overview.php', 'class-hvac-master-trainers-overview.php', 'class-hvac-announcements-manager.php', + 'class-hvac-announcements-admin.php', 'class-hvac-announcements-display.php', 'class-hvac-master-pages-fixer.php', 'class-hvac-master-layout-standardizer.php', @@ -545,7 +546,8 @@ final class HVAC_Plugin { } // Schedule non-critical components for lazy loading - add_action('wp_loaded', [$this, 'initializeSecondaryComponents'], 5); + // Use 'init' instead of 'wp_loaded' so components can register wp_enqueue_scripts hooks + add_action('init', [$this, 'initializeSecondaryComponents'], 5); add_action('admin_init', [$this, 'initializeAdminComponents'], 5); } @@ -712,8 +714,13 @@ final class HVAC_Plugin { if (class_exists('HVAC_Announcements_Display')) { HVAC_Announcements_Display::get_instance(); } + error_log('HVAC Plugin: Checking if HVAC_Announcements_Admin class exists: ' . (class_exists('HVAC_Announcements_Admin') ? 'YES' : 'NO')); if (class_exists('HVAC_Announcements_Admin')) { + error_log('HVAC Plugin: Instantiating HVAC_Announcements_Admin...'); HVAC_Announcements_Admin::get_instance(); + error_log('HVAC Plugin: HVAC_Announcements_Admin instantiated successfully'); + } else { + error_log('HVAC Plugin: ERROR - HVAC_Announcements_Admin class does not exist!'); } }