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 = '
';
+ } 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!');
}
}