Update dashboard JS and frontend class

This commit is contained in:
stack_admn committed 2026-10-31 18:17:55 -07:00
1 parent 48c7d23261
commit 2b1424d127
8 files changed
+242 -95

No files matched your search

+1 -1
View File
@@ -1082,7 +1082,7 @@
<div class="hssm-image-controls"> <div class="hssm-image-controls">
<button type="button" class="hssm-btn hssm-btn-sm hssm-upload-btn" data-target="${this.formCounter}">Upload</button> <button type="button" class="hssm-btn hssm-btn-sm hssm-upload-btn" data-target="${this.formCounter}">Upload</button>
<button type="button" class="hssm-btn hssm-btn-danger hssm-btn-sm hssm-remove-image" data-target="${this.formCounter}" style="${slideData.featured_image_url ? '' : 'display: none;'}">Remove</button> <button type="button" class="hssm-btn hssm-btn-danger hssm-btn-sm hssm-remove-image" data-target="${this.formCounter}" style="${slideData.featured_image_url ? '' : 'display: none;'}">Remove</button>
<input type="hidden" name="slides[${this.formCounter}][featured_image]" id="image_id_${this.formCounter}" class="hssm-image-id" value=""> <input type="hidden" name="slides[${this.formCounter}][featured_image]" id="image_id_${this.formCounter}" class="hssm-image-id" value="${slideData.featured_image || ''}">
</div> </div>
</div> </div>
</div> </div>
+20 -2
View File
@@ -3,7 +3,7 @@
* Plugin Name: Hi-School Slide Manager * Plugin Name: Hi-School Slide Manager
* Plugin URI: https://hi-school.com/slide-manager * Plugin URI: https://hi-school.com/slide-manager
* Description: Multi-site slide management system for Hi-School websites. Allows staff to create and schedule slides on the main site, display them as headers on companion sites via REST API, with advanced preview and editing capabilities. * Description: Multi-site slide management system for Hi-School websites. Allows staff to create and schedule slides on the main site, display them as headers on companion sites via REST API, with advanced preview and editing capabilities.
* Version: 1.1.1 * Version: 1.1.2
* Author: Hi-School Development Team * Author: Hi-School Development Team
* Author URI: https://hi-school.com * Author URI: https://hi-school.com
* License: GPL v2 or later * License: GPL v2 or later
@@ -22,7 +22,7 @@ if ( ! defined( 'ABSPATH' ) ) {
} }
// Plugin constants // Plugin constants
define( 'HSSM_VERSION', '1.1.1' ); define( 'HSSM_VERSION', '1.1.2' );
define( 'HSSM_PLUGIN_FILE', __FILE__ ); define( 'HSSM_PLUGIN_FILE', __FILE__ );
define( 'HSSM_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); define( 'HSSM_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'HSSM_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); define( 'HSSM_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
@@ -32,6 +32,24 @@ define( 'HSSM_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
// define( 'HSSM_SLIDES_TABLE', 'hssm_slides' ); // define( 'HSSM_SLIDES_TABLE', 'hssm_slides' );
// define( 'HSSM_SITES_TABLE', 'hssm_companion_sites' ); // define( 'HSSM_SITES_TABLE', 'hssm_companion_sites' );
/**
* Write a debug log line only when WP_DEBUG and WP_DEBUG_LOG are enabled.
*
* @since 1.1.2
* @param mixed $message Message or data to log.
*/
function hssm_debug_log( $message ) {
if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG || ! defined( 'WP_DEBUG_LOG' ) || ! WP_DEBUG_LOG ) {
return;
}
if ( ! is_string( $message ) ) {
$message = print_r( $message, true );
}
error_log( 'HSSM: ' . $message );
}
// Include core files // Include core files
require_once HSSM_PLUGIN_DIR . 'includes/class-hssm-autoloader.php'; require_once HSSM_PLUGIN_DIR . 'includes/class-hssm-autoloader.php';
require_once HSSM_PLUGIN_DIR . 'includes/class-hssm-main.php'; require_once HSSM_PLUGIN_DIR . 'includes/class-hssm-main.php';
+40 -5
View File
@@ -45,7 +45,22 @@ class HSSM_Admin {
* @since 1.0.0 * @since 1.0.0
*/ */
public function add_menus() { public function add_menus() {
// Add settings page under the Slides menu $plugin_mode = get_option( 'hssm_plugin_mode', 'manager' );
// Client mode does not register the slides CPT, so Settings cannot hang off that menu.
if ( 'client' === $plugin_mode ) {
add_menu_page(
__( 'Slide Manager', 'hi-school-slide-manager' ),
__( 'Slide Manager', 'hi-school-slide-manager' ),
'manage_options',
'hssm-settings',
array( $this, 'settings_page' ),
'dashicons-images-alt2',
58
);
return;
}
add_submenu_page( add_submenu_page(
'edit.php?post_type=hssm_slide', 'edit.php?post_type=hssm_slide',
__( 'Slide Manager Settings', 'hi-school-slide-manager' ), __( 'Slide Manager Settings', 'hi-school-slide-manager' ),
@@ -55,7 +70,6 @@ class HSSM_Admin {
array( $this, 'settings_page' ) array( $this, 'settings_page' )
); );
// Add API documentation page
add_submenu_page( add_submenu_page(
'edit.php?post_type=hssm_slide', 'edit.php?post_type=hssm_slide',
__( 'API Documentation', 'hi-school-slide-manager' ), __( 'API Documentation', 'hi-school-slide-manager' ),
@@ -79,6 +93,7 @@ class HSSM_Admin {
register_setting( 'hssm_settings', 'hssm_notification_emails' ); register_setting( 'hssm_settings', 'hssm_notification_emails' );
register_setting( 'hssm_settings', 'hssm_cache_duration' ); register_setting( 'hssm_settings', 'hssm_cache_duration' );
register_setting( 'hssm_settings', 'hssm_api_keys' ); register_setting( 'hssm_settings', 'hssm_api_keys' );
register_setting( 'hssm_settings', 'hssm_client_api_key' );
// Add settings sections // Add settings sections
add_settings_section( add_settings_section(
@@ -127,6 +142,14 @@ class HSSM_Admin {
'hssm_general' 'hssm_general'
); );
add_settings_field(
'hssm_client_api_key',
__( 'Client API Key', 'hi-school-slide-manager' ),
array( $this, 'client_api_key_field' ),
'hssm-settings',
'hssm_general'
);
add_settings_field( add_settings_field(
'hssm_cache_duration', 'hssm_cache_duration',
__( 'Cache Duration', 'hi-school-slide-manager' ), __( 'Cache Duration', 'hi-school-slide-manager' ),
@@ -192,7 +215,7 @@ class HSSM_Admin {
<li><code><?php echo esc_html( rest_url( 'hssm/v1/slide/{id}' ) ); ?></code> - Get single slide</li> <li><code><?php echo esc_html( rest_url( 'hssm/v1/slide/{id}' ) ); ?></code> - Get single slide</li>
<li><code><?php echo esc_html( rest_url( 'hssm/v1/health' ) ); ?></code> - Health check (no auth required)</li> <li><code><?php echo esc_html( rest_url( 'hssm/v1/health' ) ); ?></code> - Health check (no auth required)</li>
</ul> </ul>
<p><strong><?php _e( 'Authentication:', 'hi-school-slide-manager' ); ?></strong> <?php _e( 'Include API key in X-HSSM-API-Key header or api_key parameter', 'hi-school-slide-manager' ); ?></p> <p><strong><?php _e( 'Authentication:', 'hi-school-slide-manager' ); ?></strong> <?php _e( 'Include an API key from the list below in the X-HSSM-API-Key header or api_key parameter. On each companion site, paste that same key into Settings → Client API Key.', 'hi-school-slide-manager' ); ?></p>
</div> </div>
</div> </div>
<?php <?php
@@ -386,6 +409,9 @@ Headers: X-HSSM-API-Key: your-api-key</code></pre>
if ( isset( $_POST['hssm_client_site_slug'] ) ) { if ( isset( $_POST['hssm_client_site_slug'] ) ) {
update_option( 'hssm_client_site_slug', sanitize_text_field( $_POST['hssm_client_site_slug'] ) ); update_option( 'hssm_client_site_slug', sanitize_text_field( $_POST['hssm_client_site_slug'] ) );
} }
if ( isset( $_POST['hssm_client_api_key'] ) ) {
update_option( 'hssm_client_api_key', sanitize_text_field( wp_unslash( $_POST['hssm_client_api_key'] ) ) );
}
if ( isset( $_POST['hssm_cache_duration'] ) ) { if ( isset( $_POST['hssm_cache_duration'] ) ) {
update_option( 'hssm_cache_duration', absint( $_POST['hssm_cache_duration'] ) ); update_option( 'hssm_cache_duration', absint( $_POST['hssm_cache_duration'] ) );
} }
@@ -437,7 +463,7 @@ Headers: X-HSSM-API-Key: your-api-key</code></pre>
* API section callback * API section callback
*/ */
public function api_section_callback() { public function api_section_callback() {
echo '<p>' . __( 'Manage API keys for companion sites.', 'hi-school-slide-manager' ) . '</p>'; echo '<p>' . __( 'Generate keys on the Manager site, then paste one into each companion site under Client API Key.', 'hi-school-slide-manager' ) . '</p>';
} }
/** /**
@@ -482,6 +508,15 @@ Headers: X-HSSM-API-Key: your-api-key</code></pre>
<?php <?php
} }
/**
* Client API key field
*/
public function client_api_key_field() {
$value = get_option( 'hssm_client_api_key', '' );
echo '<input type="text" name="hssm_client_api_key" value="' . esc_attr( $value ) . '" class="regular-text" autocomplete="off" />';
echo '<p class="description">' . esc_html__( 'Used only in Client mode. Copy a key from the Manager site (Settings → API Keys) and paste it here. Requests fail with 403 until this matches a manager key.', 'hi-school-slide-manager' ) . '</p>';
}
/** /**
* Cache duration field * Cache duration field
*/ */
@@ -531,7 +566,7 @@ Headers: X-HSSM-API-Key: your-api-key</code></pre>
} }
echo '<p><button type="submit" name="generate_api_key" value="1" class="button button-secondary">' . __( 'Generate New API Key', 'hi-school-slide-manager' ) . '</button></p>'; echo '<p><button type="submit" name="generate_api_key" value="1" class="button button-secondary">' . __( 'Generate New API Key', 'hi-school-slide-manager' ) . '</button></p>';
echo '<p class="description">' . __( 'API keys are used by companion sites to authenticate and fetch slides.', 'hi-school-slide-manager' ) . '</p>'; echo '<p class="description">' . __( 'Generate a key on this Manager site, then paste it into each companion site under Settings → Client API Key.', 'hi-school-slide-manager' ) . '</p>';
echo '</div>'; echo '</div>';
+3 -3
View File
@@ -24,11 +24,11 @@ class HSSM_API_Client {
public function get_slides() { public function get_slides() {
$api_url = get_option( 'hssm_api_url' ); $api_url = get_option( 'hssm_api_url' );
$site_slug = get_option( 'hssm_client_site_slug' ); $site_slug = get_option( 'hssm_client_site_slug' );
$api_key = 'HI_SCHOOL_FIXED_API_KEY'; // Hardcoded fixed API key $api_key = get_option( 'hssm_client_api_key', '' );
$cache_duration = get_option( 'hssm_cache_duration', 3600 ); $cache_duration = get_option( 'hssm_cache_duration', 3600 );
if ( empty( $api_url ) || empty( $site_slug ) || empty( $api_key ) ) { // Added $api_key check here if ( empty( $api_url ) || empty( $site_slug ) || empty( $api_key ) ) {
return new WP_Error( 'missing_config', __( 'API URL, Site Slug, or API Key not configured.', 'hi-school-slide-manager' ) ); // Updated error message return new WP_Error( 'missing_config', __( 'API URL, site slug, or client API key is not configured.', 'hi-school-slide-manager' ) );
} }
// Check cache first // Check cache first
+158 -73
View File
@@ -46,6 +46,7 @@ class HSSM_Frontend {
add_action( 'wp_ajax_hssm_save_slide', array( $this, 'ajax_save_slide' ) ); add_action( 'wp_ajax_hssm_save_slide', array( $this, 'ajax_save_slide' ) );
add_action( 'wp_ajax_hssm_upload_image', array( $this, 'ajax_upload_image' ) ); add_action( 'wp_ajax_hssm_upload_image', array( $this, 'ajax_upload_image' ) );
add_action( 'wp_ajax_hssm_get_slides', array( $this, 'ajax_get_slides' ) ); add_action( 'wp_ajax_hssm_get_slides', array( $this, 'ajax_get_slides' ) );
add_action( 'wp_ajax_hssm_get_slide_for_edit', array( $this, 'ajax_get_slide_for_edit' ) );
add_action( 'wp_ajax_hssm_delete_slide', array( $this, 'ajax_delete_slide' ) ); add_action( 'wp_ajax_hssm_delete_slide', array( $this, 'ajax_delete_slide' ) );
add_action( 'wp_ajax_hssm_update_slide', array( $this, 'ajax_update_slide' ) ); add_action( 'wp_ajax_hssm_update_slide', array( $this, 'ajax_update_slide' ) );
add_action( 'wp_ajax_hssm_schedule_slide', array( $this, 'ajax_schedule_slide' ) ); add_action( 'wp_ajax_hssm_schedule_slide', array( $this, 'ajax_schedule_slide' ) );
@@ -142,20 +143,20 @@ class HSSM_Frontend {
private function check_dashboard_access( $check_upload = false ) { private function check_dashboard_access( $check_upload = false ) {
// Check if user is logged in // Check if user is logged in
if ( ! is_user_logged_in() ) { if ( ! is_user_logged_in() ) {
error_log( 'Dashboard access denied: User not logged in' ); hssm_debug_log( 'Dashboard access denied: User not logged in' );
return false; return false;
} }
$user_id = get_current_user_id(); $user_id = get_current_user_id();
error_log( 'Checking dashboard access for user ID: ' . $user_id ); hssm_debug_log( 'Checking dashboard access for user ID: ' . $user_id );
// Check Members plugin capability FIRST // Check Members plugin capability FIRST
if ( function_exists( 'members_user_can' ) && members_user_can( $user_id, 'hssm_manage_slides' ) ) { if ( function_exists( 'members_user_can' ) && members_user_can( $user_id, 'hssm_manage_slides' ) ) {
error_log( 'Members plugin check: PASS (hssm_manage_slides)' ); hssm_debug_log( 'Members plugin check: PASS (hssm_manage_slides)' );
if ( $check_upload ) { if ( $check_upload ) {
$can_upload = current_user_can( 'upload_files' ); $can_upload = current_user_can( 'upload_files' );
error_log( 'Upload files capability check: ' . ($can_upload ? 'PASS' : 'FAIL') ); hssm_debug_log( 'Upload files capability check: ' . ($can_upload ? 'PASS' : 'FAIL') );
return $can_upload; return $can_upload;
} }
@@ -164,11 +165,11 @@ class HSSM_Frontend {
// Fallback to WordPress capabilities - be more permissive // Fallback to WordPress capabilities - be more permissive
$can_edit = current_user_can( 'edit_posts' ) || current_user_can( 'publish_posts' ) || current_user_can( 'manage_options' ); $can_edit = current_user_can( 'edit_posts' ) || current_user_can( 'publish_posts' ) || current_user_can( 'manage_options' );
error_log( 'WordPress capability check (edit_posts/publish_posts/manage_options): ' . ($can_edit ? 'PASS' : 'FAIL') ); hssm_debug_log( 'WordPress capability check (edit_posts/publish_posts/manage_options): ' . ($can_edit ? 'PASS' : 'FAIL') );
if ( $check_upload ) { if ( $check_upload ) {
$can_upload = current_user_can( 'upload_files' ); $can_upload = current_user_can( 'upload_files' );
error_log( 'Upload files capability check: ' . ($can_upload ? 'PASS' : 'FAIL') ); hssm_debug_log( 'Upload files capability check: ' . ($can_upload ? 'PASS' : 'FAIL') );
return $can_edit && $can_upload; return $can_edit && $can_upload;
} }
@@ -475,7 +476,7 @@ class HSSM_Frontend {
* @return array Sanitized data * @return array Sanitized data
*/ */
private function sanitize_slide_data( $data ) { private function sanitize_slide_data( $data ) {
error_log( 'Raw form data received: ' . print_r( $data, true ) ); hssm_debug_log( 'Raw form data received: ' . print_r( $data, true ) );
// Handle target_sites - it might come as an array or need to be extracted // Handle target_sites - it might come as an array or need to be extracted
$target_sites = array(); $target_sites = array();
@@ -514,8 +515,8 @@ class HSSM_Frontend {
'hide_all_text' => ! empty( $data['hide_all_text'] ) && $data['hide_all_text'] === '1', 'hide_all_text' => ! empty( $data['hide_all_text'] ) && $data['hide_all_text'] === '1',
); );
error_log( 'Sanitized slide data: ' . print_r( $sanitized, true ) ); hssm_debug_log( 'Sanitized slide data: ' . print_r( $sanitized, true ) );
error_log( 'Target sites count: ' . count( $sanitized['target_sites'] ) ); hssm_debug_log( 'Target sites count: ' . count( $sanitized['target_sites'] ) );
return $sanitized; return $sanitized;
} }
@@ -556,11 +557,11 @@ class HSSM_Frontend {
* @return bool Is valid * @return bool Is valid
*/ */
private function validate_slide_data( $data ) { private function validate_slide_data( $data ) {
error_log( 'Validating slide data: ' . print_r( $data, true ) ); hssm_debug_log( 'Validating slide data: ' . print_r( $data, true ) );
// Required fields // Required fields
if ( empty( $data['title'] ) ) { if ( empty( $data['title'] ) ) {
error_log( 'Validation failed: Missing title' ); hssm_debug_log( 'Validation failed: Missing title' );
return false; return false;
} }
@@ -570,17 +571,17 @@ class HSSM_Frontend {
foreach ( $data['target_sites'] as $site_slug ) { foreach ( $data['target_sites'] as $site_slug ) {
$term = get_term_by( 'slug', $site_slug, 'hssm_site' ); $term = get_term_by( 'slug', $site_slug, 'hssm_site' );
if ( ! $term || is_wp_error( $term ) ) { if ( ! $term || is_wp_error( $term ) ) {
error_log( 'Validation failed: Invalid site slug (not a taxonomy term): ' . $site_slug ); hssm_debug_log( 'Validation failed: Invalid site slug (not a taxonomy term): ' . $site_slug );
return false; return false;
} }
} }
} else { } else {
error_log( 'Validation failed: No target sites selected or target_sites is not an array' ); hssm_debug_log( 'Validation failed: No target sites selected or target_sites is not an array' );
error_log( 'target_sites value: ' . print_r( $data['target_sites'] ?? 'NOT SET', true ) ); hssm_debug_log( 'target_sites value: ' . print_r( $data['target_sites'] ?? 'NOT SET', true ) );
return false; return false;
} }
error_log( 'Validation passed' ); hssm_debug_log( 'Validation passed' );
return true; return true;
} }
@@ -618,7 +619,7 @@ class HSSM_Frontend {
private function save_slide_taxonomies( $slide_id, $data ) { private function save_slide_taxonomies( $slide_id, $data ) {
// Set target sites // Set target sites
if ( ! empty( $data['target_sites'] ) && is_array( $data['target_sites'] ) ) { if ( ! empty( $data['target_sites'] ) && is_array( $data['target_sites'] ) ) {
error_log( 'Saving target sites for slide ' . $slide_id . ': ' . print_r( $data['target_sites'], true ) ); hssm_debug_log( 'Saving target sites for slide ' . $slide_id . ': ' . print_r( $data['target_sites'], true ) );
// Ensure we're using term slugs, not IDs // Ensure we're using term slugs, not IDs
$term_slugs = array(); $term_slugs = array();
@@ -638,12 +639,12 @@ class HSSM_Frontend {
if ( ! empty( $term_slugs ) ) { if ( ! empty( $term_slugs ) ) {
$result = wp_set_post_terms( $slide_id, $term_slugs, 'hssm_site' ); $result = wp_set_post_terms( $slide_id, $term_slugs, 'hssm_site' );
error_log( 'wp_set_post_terms result: ' . print_r( $result, true ) ); hssm_debug_log( 'wp_set_post_terms result: ' . print_r( $result, true ) );
} else { } else {
error_log( 'No valid term slugs to save' ); hssm_debug_log( 'No valid term slugs to save' );
} }
} else { } else {
error_log( 'No target sites to save for slide ' . $slide_id ); hssm_debug_log( 'No target sites to save for slide ' . $slide_id );
} }
// Set client // Set client
@@ -794,56 +795,12 @@ class HSSM_Frontend {
$formatted_slides = array(); $formatted_slides = array();
foreach ( $slides as $slide ) { foreach ( $slides as $slide ) {
$slide_meta = get_post_meta( $slide->ID ); $formatted = $this->format_slide_for_dashboard( $slide );
if ( $formatted ) {
// Get selected sites from taxonomy terms $formatted_slides[] = $formatted;
$site_terms = wp_get_post_terms( $slide->ID, 'hssm_site', array( 'fields' => 'all' ) );
$site_names = array();
if ( ! empty( $site_terms ) && ! is_wp_error( $site_terms ) ) {
foreach ( $site_terms as $site_term ) {
$site_names[] = $site_term->name;
} }
} }
// Get featured image
$featured_image_url = get_the_post_thumbnail_url( $slide->ID, 'thumbnail' );
// Get schedule info
$start_date = isset( $slide_meta['_hssm_start_date'][0] ) ? $slide_meta['_hssm_start_date'][0] : '';
$end_date = isset( $slide_meta['_hssm_end_date'][0] ) ? $slide_meta['_hssm_end_date'][0] : '';
$auto_publish = isset( $slide_meta['_hssm_auto_publish'][0] ) ? $slide_meta['_hssm_auto_publish'][0] : '';
$auto_unpublish = isset( $slide_meta['_hssm_auto_unpublish'][0] ) ? $slide_meta['_hssm_auto_unpublish'][0] : '';
// Format status for display
$status_display = ucfirst( $slide->post_status );
if ( $slide->post_status === 'pending' ) {
$status_display = 'Pending Approval';
} elseif ( $slide->post_status === 'future' ) {
$status_display = 'Scheduled';
}
$formatted_slides[] = array(
'id' => $slide->ID,
'title' => $slide->post_title,
'subtitle' => isset( $slide_meta['_hssm_subtitle'][0] ) ? $slide_meta['_hssm_subtitle'][0] : '',
'content' => $slide->post_content,
'status' => $slide->post_status,
'status_display' => $status_display,
'sites' => $site_names,
'target_sites' => $site_names,
'client' => $this->get_slide_client_name( $slide->ID ),
'start_date' => $start_date,
'end_date' => $end_date,
'auto_publish' => $auto_publish,
'auto_unpublish' => $auto_unpublish,
'featured_image_url' => $featured_image_url,
'created' => $slide->post_date,
'modified' => $slide->post_modified,
'buttons' => isset( $slide_meta['_hssm_buttons'][0] ) ? maybe_unserialize( $slide_meta['_hssm_buttons'][0] ) : array(),
'hide_all_text' => isset( $slide_meta['_hssm_hide_all_text'][0] ) && $slide_meta['_hssm_hide_all_text'][0] === '1'
);
}
wp_send_json_success( array( wp_send_json_success( array(
'slides' => $formatted_slides, 'slides' => $formatted_slides,
'total' => $total_slides, 'total' => $total_slides,
@@ -854,6 +811,134 @@ class HSSM_Frontend {
) ); ) );
} }
/**
* AJAX handler for loading a single slide into the dashboard edit form.
*
* Used when the slide is not already in the in-memory list (pagination, filters, deep link).
*
* @since 1.1.2
*/
public function ajax_get_slide_for_edit() {
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'hssm_dashboard_nonce' ) ) {
wp_send_json_error( array( 'message' => 'Nonce verification failed' ) );
return;
}
if ( ! current_user_can( 'edit_posts' ) ) {
wp_send_json_error( array( 'message' => 'You do not have permission to edit slides.' ) );
return;
}
if ( ! isset( $_POST['slide_id'] ) || '' === trim( (string) $_POST['slide_id'] ) ) {
wp_send_json_error( array( 'message' => 'Slide ID is required' ) );
return;
}
$slide_id = absint( $_POST['slide_id'] );
$slide = get_post( $slide_id );
if ( ! $slide || 'hssm_slide' !== $slide->post_type ) {
wp_send_json_error( array( 'message' => 'Slide not found' ) );
return;
}
if ( ! current_user_can( 'edit_post', $slide_id ) ) {
wp_send_json_error( array( 'message' => 'Insufficient permissions' ) );
return;
}
$formatted = $this->format_slide_for_dashboard( $slide );
if ( ! $formatted ) {
wp_send_json_error( array( 'message' => 'Slide not found' ) );
return;
}
wp_send_json_success( array( 'slide' => $formatted ) );
}
/**
* Format a slide for the dashboard list and edit form.
*
* @since 1.1.2
* @param int|WP_Post $slide Slide ID or post object.
* @return array|null Formatted slide data.
*/
private function format_slide_for_dashboard( $slide ) {
if ( is_numeric( $slide ) ) {
$slide = get_post( $slide );
}
if ( ! $slide instanceof WP_Post || 'hssm_slide' !== $slide->post_type ) {
return null;
}
$slide_meta = get_post_meta( $slide->ID );
$site_terms = wp_get_post_terms( $slide->ID, 'hssm_site', array( 'fields' => 'all' ) );
$site_names = array();
if ( ! empty( $site_terms ) && ! is_wp_error( $site_terms ) ) {
foreach ( $site_terms as $site_term ) {
$site_names[] = $site_term->name;
}
}
$status_display = ucfirst( $slide->post_status );
if ( 'pending' === $slide->post_status ) {
$status_display = 'Pending Approval';
} elseif ( 'future' === $slide->post_status ) {
$status_display = 'Scheduled';
}
$start_date = isset( $slide_meta['_hssm_start_date'][0] ) ? $slide_meta['_hssm_start_date'][0] : '';
$end_date = isset( $slide_meta['_hssm_end_date'][0] ) ? $slide_meta['_hssm_end_date'][0] : '';
return array(
'id' => $slide->ID,
'title' => $slide->post_title,
'subtitle' => isset( $slide_meta['_hssm_subtitle'][0] ) ? $slide_meta['_hssm_subtitle'][0] : '',
'content' => $slide->post_content,
'status' => $slide->post_status,
'status_display' => $status_display,
'sites' => $site_names,
'target_sites' => $site_names,
'client' => $this->get_slide_client_name( $slide->ID ),
'start_date' => $this->format_dashboard_date( $start_date ),
'end_date' => $this->format_dashboard_date( $end_date ),
'auto_publish' => isset( $slide_meta['_hssm_auto_publish'][0] ) ? $slide_meta['_hssm_auto_publish'][0] : '',
'auto_unpublish' => isset( $slide_meta['_hssm_auto_unpublish'][0] ) ? $slide_meta['_hssm_auto_unpublish'][0] : '',
'featured_image' => (int) get_post_thumbnail_id( $slide->ID ),
'featured_image_url' => get_the_post_thumbnail_url( $slide->ID, 'thumbnail' ),
'created' => $slide->post_date,
'modified' => $slide->post_modified,
'buttons' => isset( $slide_meta['_hssm_buttons'][0] ) ? maybe_unserialize( $slide_meta['_hssm_buttons'][0] ) : array(),
'hide_all_text' => isset( $slide_meta['_hssm_hide_all_text'][0] ) && '1' === $slide_meta['_hssm_hide_all_text'][0],
);
}
/**
* Normalize stored dates for HTML date inputs (YYYY-MM-DD).
*
* @since 1.1.2
* @param string $value Stored date or datetime.
* @return string
*/
private function format_dashboard_date( $value ) {
if ( empty( $value ) ) {
return '';
}
if ( preg_match( '/^(\d{4}-\d{2}-\d{2})/', $value, $matches ) ) {
return $matches[1];
}
$timestamp = strtotime( $value );
if ( ! $timestamp ) {
return '';
}
return wp_date( 'Y-m-d', $timestamp );
}
/** /**
* AJAX handler for approving slides * AJAX handler for approving slides
* *
@@ -907,7 +992,7 @@ class HSSM_Frontend {
$result = wp_update_post( $post_data ); $result = wp_update_post( $post_data );
if ( $result ) { if ( $result ) {
error_log( "Slide $slide_id approved with action: $approve_action" ); hssm_debug_log( "Slide $slide_id approved with action: $approve_action" );
// Trigger 2: Notification to Creator (Author) when approved // Trigger 2: Notification to Creator (Author) when approved
$notifications = new HSSM_Notifications(); $notifications = new HSSM_Notifications();
@@ -1057,18 +1142,18 @@ class HSSM_Frontend {
* @since 1.0.0 * @since 1.0.0
*/ */
public function ajax_schedule_slide() { public function ajax_schedule_slide() {
error_log( 'Schedule slide AJAX called' ); hssm_debug_log( 'Schedule slide AJAX called' );
error_log( 'POST data: ' . print_r( $_POST, true ) ); hssm_debug_log( 'POST data: ' . print_r( $_POST, true ) );
// Check nonce // Check nonce
if ( ! check_ajax_referer( 'hssm_dashboard_nonce', 'nonce', false ) ) { if ( ! check_ajax_referer( 'hssm_dashboard_nonce', 'nonce', false ) ) {
error_log( 'Nonce verification failed' ); hssm_debug_log( 'Nonce verification failed' );
wp_send_json_error( array( 'message' => 'Security check failed' ) ); wp_send_json_error( array( 'message' => 'Security check failed' ) );
} }
// Check user permissions // Check user permissions
if ( ! current_user_can( 'edit_posts' ) ) { if ( ! current_user_can( 'edit_posts' ) ) {
error_log( 'User permissions check failed' ); hssm_debug_log( 'User permissions check failed' );
wp_send_json_error( array( 'message' => 'Insufficient permissions' ) ); wp_send_json_error( array( 'message' => 'Insufficient permissions' ) );
} }
@@ -1076,7 +1161,7 @@ class HSSM_Frontend {
$slide_data = $this->sanitize_slide_data( $_POST ); $slide_data = $this->sanitize_slide_data( $_POST );
if ( ! $this->validate_slide_data( $slide_data ) ) { if ( ! $this->validate_slide_data( $slide_data ) ) {
error_log( 'Slide data validation failed' ); hssm_debug_log( 'Slide data validation failed' );
wp_send_json_error( array( 'message' => 'Invalid slide data' ) ); wp_send_json_error( array( 'message' => 'Invalid slide data' ) );
} }
@@ -1416,7 +1501,7 @@ class HSSM_Frontend {
} }
// --- DEBUG --- // --- DEBUG ---
// error_log('HSSM Query Filter Check: is_main=' . ($query->is_main_query()?'Y':'N') . ' post_type=' . print_r($query->get('post_type'), true)); // hssm_debug_log('HSSM Query Filter Check: is_main=' . ($query->is_main_query()?'Y':'N') . ' post_type=' . print_r($query->get('post_type'), true));
// Only on preview page // Only on preview page
$obj_id = get_queried_object_id(); $obj_id = get_queried_object_id();
+3 -3
View File
@@ -173,9 +173,7 @@ class HSSM_Main {
add_action( 'admin_menu', array( $this, 'add_admin_menus' ) ); add_action( 'admin_menu', array( $this, 'add_admin_menus' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) );
// AJAX hooks for authenticated users // AJAX hooks live on HSSM_Frontend. Preview email is still a coming-soon UI stub.
// Note: Main AJAX handlers are in HSSM_Frontend class
add_action( 'wp_ajax_hssm_send_preview_email', array( $this, 'ajax_send_preview_email' ) );
// Cron hooks for scheduled slides // Cron hooks for scheduled slides
add_action( 'hssm_check_scheduled_slides', array( $this, 'check_scheduled_slides' ) ); add_action( 'hssm_check_scheduled_slides', array( $this, 'check_scheduled_slides' ) );
@@ -456,6 +454,7 @@ class HSSM_Main {
'hssm_preview_page_slug' => 'slide-preview', 'hssm_preview_page_slug' => 'slide-preview',
'hssm_manager_page_slug' => 'slide-manager', 'hssm_manager_page_slug' => 'slide-manager',
'hssm_api_keys' => array( wp_generate_password( 32, false ) ), // Generate initial API key 'hssm_api_keys' => array( wp_generate_password( 32, false ) ), // Generate initial API key
'hssm_client_api_key' => '',
); );
foreach ( $default_options as $option_name => $option_value ) { foreach ( $default_options as $option_name => $option_value ) {
@@ -482,6 +481,7 @@ class HSSM_Main {
'hssm_preview_page_slug', 'hssm_preview_page_slug',
'hssm_manager_page_slug', 'hssm_manager_page_slug',
'hssm_api_keys', 'hssm_api_keys',
'hssm_client_api_key',
'hssm_notification_settings', 'hssm_notification_settings',
); );
+1 -1
View File
@@ -100,7 +100,7 @@ class HSSM_Notifications {
$emails = $this->get_emails_array( $settings['editor_emails'] ); $emails = $this->get_emails_array( $settings['editor_emails'] );
if ( empty( $emails ) ) { if ( empty( $emails ) ) {
error_log( 'HSSM: No Editor emails configured for notification.' ); hssm_debug_log( 'No Editor emails configured for notification.' );
return; return;
} }
+16 -7
View File
@@ -145,9 +145,10 @@ class HSSM_REST_API {
); );
// Add date filtering if specified // Add date filtering if specified
$date_meta_query = null;
if ( $date ) { if ( $date ) {
$target_date = $date . ' 23:59:59'; $target_date = $date . ' 23:59:59';
$query_args['meta_query'] = array( $date_meta_query = array(
'relation' => 'AND', 'relation' => 'AND',
array( array(
'relation' => 'OR', 'relation' => 'OR',
@@ -184,18 +185,26 @@ class HSSM_REST_API {
) )
) )
); );
$query_args['meta_query'] = $date_meta_query;
} }
// Handle status filtering // Handle status filtering without dropping an existing date window
if ( $status === 'scheduled' ) { if ( $status === 'scheduled' ) {
$current_time = current_time( 'mysql' ); $scheduled_clause = array(
$query_args['meta_query'] = array(
array(
'key' => '_hssm_start_date', 'key' => '_hssm_start_date',
'value' => $current_time, 'value' => current_time( 'mysql' ),
'compare' => '>' 'compare' => '>'
)
); );
if ( $date_meta_query ) {
$query_args['meta_query'] = array(
'relation' => 'AND',
$date_meta_query,
$scheduled_clause,
);
} else {
$query_args['meta_query'] = array( $scheduled_clause );
}
} elseif ( $status === 'all' ) { } elseif ( $status === 'all' ) {
$query_args['post_status'] = array( 'publish', 'future', 'draft' ); $query_args['post_status'] = array( 'publish', 'future', 'draft' );
} }