9bb2171b92
add 'no dates' logic
1515 lines
57 KiB
PHP
1515 lines
57 KiB
PHP
<?php
|
|
/**
|
|
* HSSM Frontend Class
|
|
*
|
|
* Handles front-end functionality including the slide creation dashboard
|
|
*
|
|
* @package Hi_School_Slide_Manager
|
|
* @since 1.0.0
|
|
*/
|
|
|
|
// Prevent direct access
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit( 'Direct access forbidden.' );
|
|
}
|
|
|
|
/**
|
|
* HSSM Frontend Class
|
|
*
|
|
* Frontend dashboard and slide management interface
|
|
*/
|
|
class HSSM_Frontend {
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function __construct() {
|
|
add_action( 'init', array( $this, 'init' ) );
|
|
}
|
|
|
|
/**
|
|
* Initialize frontend functionality
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function init() {
|
|
// Register page template
|
|
add_filter( 'theme_page_templates', array( $this, 'register_page_template' ) );
|
|
add_filter( 'page_template', array( $this, 'load_page_template' ) );
|
|
|
|
// Handle page routing
|
|
add_action( 'template_redirect', array( $this, 'handle_page_routing' ) );
|
|
|
|
// AJAX handlers
|
|
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_get_slides', array( $this, 'ajax_get_slides' ) );
|
|
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_schedule_slide', array( $this, 'ajax_schedule_slide' ) );
|
|
add_action( 'wp_ajax_hssm_publish_slide', array( $this, 'ajax_publish_slide' ) );
|
|
add_action( 'wp_ajax_hssm_duplicate_slide', array( $this, 'ajax_duplicate_slide' ) );
|
|
add_action( 'wp_ajax_hssm_toggle_slide_status', array( $this, 'ajax_toggle_slide_status' ) );
|
|
add_action( 'wp_ajax_hssm_approve_slide', array( $this, 'ajax_approve_slide' ) );
|
|
add_action( 'wp_ajax_hssm_preview_slides', array( $this, 'ajax_preview_slides' ) );
|
|
|
|
// Notification Settings AJAX
|
|
add_action( 'wp_ajax_hssm_get_notification_settings', array( $this, 'ajax_get_notification_settings' ) );
|
|
add_action( 'wp_ajax_hssm_save_notification_settings', array( $this, 'ajax_save_notification_settings' ) );
|
|
|
|
|
|
// Frontend assets
|
|
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_assets' ) );
|
|
|
|
// Filter slides query on preview page
|
|
add_action( 'pre_get_posts', array( $this, 'filter_preview_slides_query' ) );
|
|
}
|
|
|
|
/**
|
|
* Register the page template in the template dropdown
|
|
*
|
|
* @since 1.0.0
|
|
* @param array $templates Array of page templates
|
|
* @return array Modified templates array
|
|
*/
|
|
public function register_page_template( $templates ) {
|
|
$templates['page-slide-dashboard.php'] = __( 'Slide Dashboard', 'hi-school-slide-manager' );
|
|
$templates['page-slide-preview.php'] = __( 'Slide Preview', 'hi-school-slide-manager' );
|
|
$templates['page-slide-confirmation.php'] = __( 'Slide Confirmation', 'hi-school-slide-manager' );
|
|
return $templates;
|
|
}
|
|
|
|
/**
|
|
* Load the custom page template
|
|
*
|
|
* @since 1.0.0
|
|
* @param string $template The path to the template
|
|
* @return string The modified template path
|
|
*/
|
|
public function load_page_template( $template ) {
|
|
global $post;
|
|
|
|
// Check if this is a page and has our template assigned
|
|
if ( is_page() ) {
|
|
$slug = get_page_template_slug( $post->ID );
|
|
|
|
if ( in_array( $slug, array( 'page-slide-dashboard.php', 'page-slide-preview.php', 'page-slide-confirmation.php' ), true ) ) {
|
|
// First try the theme directory
|
|
$theme_template = trailingslashit( get_template_directory() ) . $slug;
|
|
|
|
if ( file_exists( $theme_template ) ) {
|
|
return $theme_template;
|
|
}
|
|
|
|
// Fallback to our plugin templates
|
|
$plugin_template = HSSM_PLUGIN_DIR . 'templates/' . $slug;
|
|
if ( file_exists( $plugin_template ) ) {
|
|
return $plugin_template;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $template;
|
|
}
|
|
|
|
/**
|
|
* Handle frontend page routing
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function handle_page_routing() {
|
|
global $post;
|
|
|
|
// Check if this is our slide dashboard page
|
|
if ( is_page() && get_page_template_slug( $post->ID ) === 'page-slide-dashboard.php' ) {
|
|
// Check authentication with Members plugin
|
|
if ( ! $this->check_dashboard_access() ) {
|
|
$this->redirect_to_login();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if user has access to the dashboard
|
|
*
|
|
* @since 1.0.0
|
|
* @param bool $check_upload Whether to also check upload capabilities
|
|
* @return bool Access granted
|
|
*/
|
|
private function check_dashboard_access( $check_upload = false ) {
|
|
// Check if user is logged in
|
|
if ( ! is_user_logged_in() ) {
|
|
error_log( 'Dashboard access denied: User not logged in' );
|
|
return false;
|
|
}
|
|
|
|
$user_id = get_current_user_id();
|
|
error_log( 'Checking dashboard access for user ID: ' . $user_id );
|
|
|
|
// Check Members plugin capability FIRST
|
|
if ( function_exists( 'members_user_can' ) && members_user_can( $user_id, 'hssm_manage_slides' ) ) {
|
|
error_log( 'Members plugin check: PASS (hssm_manage_slides)' );
|
|
|
|
if ( $check_upload ) {
|
|
$can_upload = current_user_can( 'upload_files' );
|
|
error_log( 'Upload files capability check: ' . ($can_upload ? 'PASS' : 'FAIL') );
|
|
return $can_upload;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Fallback to WordPress capabilities - be more permissive
|
|
$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') );
|
|
|
|
if ( $check_upload ) {
|
|
$can_upload = current_user_can( 'upload_files' );
|
|
error_log( 'Upload files capability check: ' . ($can_upload ? 'PASS' : 'FAIL') );
|
|
return $can_edit && $can_upload;
|
|
}
|
|
|
|
return $can_edit;
|
|
}
|
|
|
|
/**
|
|
* Redirect to login page
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
private function redirect_to_login() {
|
|
$login_url = wp_login_url( get_permalink() );
|
|
wp_redirect( $login_url );
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Enqueue frontend assets
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function enqueue_assets() {
|
|
global $post;
|
|
|
|
// Only load on our dashboard or preview pages
|
|
if ( ! is_page() ) {
|
|
return;
|
|
}
|
|
|
|
$template_slug = get_page_template_slug( $post->ID );
|
|
$is_dashboard = ( $template_slug === 'page-slide-dashboard.php' );
|
|
$is_preview = ( $template_slug === 'page-slide-preview.php' );
|
|
|
|
if ( ! $is_dashboard && ! $is_preview ) {
|
|
return;
|
|
}
|
|
|
|
// Check access (preview page may be public, but dashboard requires auth)
|
|
if ( $is_dashboard && ! $this->check_dashboard_access() ) {
|
|
return;
|
|
}
|
|
|
|
// Enqueue styles (both pages need dashboard CSS)
|
|
wp_enqueue_style(
|
|
'hssm-dashboard',
|
|
HSSM_PLUGIN_URL . 'assets/css/dashboard.css',
|
|
array(),
|
|
HSSM_VERSION
|
|
);
|
|
|
|
// Dashboard page needs full JS; preview page only needs styles
|
|
if ( $is_dashboard ) {
|
|
// Enqueue scripts
|
|
wp_enqueue_script( 'jquery-ui-sortable' );
|
|
wp_enqueue_media(); // For image uploads
|
|
|
|
wp_enqueue_script(
|
|
'hssm-dashboard',
|
|
HSSM_PLUGIN_URL . 'assets/js/dashboard.js',
|
|
array( 'jquery', 'jquery-ui-sortable' ),
|
|
HSSM_VERSION,
|
|
true
|
|
);
|
|
|
|
// Localize script
|
|
wp_localize_script( 'hssm-dashboard', 'hssmDashboard', array(
|
|
'ajaxurl' => admin_url( 'admin-ajax.php' ),
|
|
'nonce' => wp_create_nonce( 'hssm_dashboard_nonce' ),
|
|
'strings' => array(
|
|
'save_success' => __( 'Slide saved successfully!', 'hi-school-slide-manager' ),
|
|
'save_error' => __( 'Error saving slide. Please try again.', 'hi-school-slide-manager' ),
|
|
'delete_confirm' => __( 'Are you sure you want to delete this slide?', 'hi-school-slide-manager' ),
|
|
'delete_success' => __( 'Slide deleted successfully!', 'hi-school-slide-manager' ),
|
|
'required_fields' => __( 'Please fill in all required fields.', 'hi-school-slide-manager' ),
|
|
'max_forms' => __( 'Maximum 5 slide forms allowed at once.', 'hi-school-slide-manager' ),
|
|
),
|
|
) );
|
|
|
|
// Add sites data for JavaScript
|
|
wp_localize_script( 'hssm-dashboard', 'hssmSites', $this->get_available_sites() );
|
|
}
|
|
|
|
// Preview page specific JS
|
|
if ( $is_preview ) {
|
|
wp_enqueue_script( 'jquery-ui-datepicker' );
|
|
// Enqueue jQuery UI CSS (using a reliable CDN or local if available,
|
|
// but WP doesn't ship with a default jQuery UI theme CSS)
|
|
wp_enqueue_style(
|
|
'jquery-ui-style',
|
|
'https://code.jquery.com/ui/1.13.2/themes/smoothness/jquery-ui.css',
|
|
array(),
|
|
'1.13.2'
|
|
);
|
|
|
|
wp_enqueue_script(
|
|
'hssm-preview',
|
|
HSSM_PLUGIN_URL . 'assets/js/preview.js',
|
|
array( 'jquery', 'jquery-ui-datepicker' ),
|
|
HSSM_VERSION,
|
|
true
|
|
);
|
|
|
|
// Localize script for preview page too
|
|
wp_localize_script( 'hssm-preview', 'hssmPreview', array(
|
|
'ajaxurl' => admin_url( 'admin-ajax.php' ),
|
|
'nonce' => wp_create_nonce( 'hssm_dashboard_nonce' ),
|
|
'strings' => array(
|
|
'approve_confirm' => __( 'Are you sure you want to approve this slide?', 'hi-school-slide-manager' ),
|
|
'approve_success' => __( 'Slide approved successfully!', 'hi-school-slide-manager' ),
|
|
'approve_error' => __( 'Error approving slide. Please try again.', 'hi-school-slide-manager' ),
|
|
),
|
|
) );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* AJAX handler for image uploads
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function ajax_upload_image() {
|
|
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'hssm_dashboard_nonce' ) || ! current_user_can( 'upload_files' ) ) {
|
|
wp_send_json_error( array( 'message' => 'Unauthorized' ) );
|
|
return;
|
|
}
|
|
|
|
// This is handled by media_handle_upload in standard WP AJAX flow usually,
|
|
// but if we need custom handling it goes here.
|
|
// For now, assuming standard media uploader is used on frontend which might not need this
|
|
// if using wp.media JS library directly.
|
|
// However, if we need to process the upload specifically for this plugin:
|
|
|
|
if ( ! empty( $_FILES['file'] ) ) {
|
|
$file = $_FILES['file'];
|
|
$attachment_id = media_handle_upload( 'file', 0 );
|
|
|
|
if ( is_wp_error( $attachment_id ) ) {
|
|
wp_send_json_error( array( 'message' => 'Upload failed: ' . $attachment_id->get_error_message() ) );
|
|
} else {
|
|
wp_send_json_success( array(
|
|
'attachment_id' => $attachment_id,
|
|
'url' => wp_get_attachment_url( $attachment_id )
|
|
) );
|
|
}
|
|
} else {
|
|
wp_send_json_error( array( 'message' => 'No file provided' ) );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* AJAX handler for previewing slides
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function ajax_preview_slides() {
|
|
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'hssm_dashboard_nonce' ) || ! current_user_can( 'read' ) ) {
|
|
wp_send_json_error( array( 'message' => 'Unauthorized' ) );
|
|
return;
|
|
}
|
|
|
|
$site_slug = isset( $_POST['site'] ) ? sanitize_text_field( $_POST['site'] ) : '';
|
|
$date = isset( $_POST['date'] ) ? sanitize_text_field( $_POST['date'] ) : current_time( 'Y-m-d' );
|
|
|
|
// This logic mirrors hssm_get_preview_slides_for_date in the template
|
|
// We need to fetch slides that would be active on this date for this site
|
|
|
|
$meta_query = array(
|
|
'relation' => 'AND',
|
|
array(
|
|
'relation' => 'OR',
|
|
array(
|
|
'key' => '_hssm_start_date',
|
|
'value' => '',
|
|
'compare' => '=',
|
|
),
|
|
array(
|
|
'key' => '_hssm_start_date',
|
|
'value' => $date,
|
|
'compare' => '<=',
|
|
),
|
|
array(
|
|
'key' => '_hssm_start_date',
|
|
'compare' => 'NOT EXISTS',
|
|
),
|
|
),
|
|
array(
|
|
'relation' => 'OR',
|
|
array(
|
|
'key' => '_hssm_end_date',
|
|
'value' => $date,
|
|
'compare' => '>=',
|
|
),
|
|
array(
|
|
'key' => '_hssm_end_date',
|
|
'compare' => 'NOT EXISTS',
|
|
),
|
|
array(
|
|
'key' => '_hssm_end_date',
|
|
'value' => '',
|
|
'compare' => '=',
|
|
),
|
|
),
|
|
);
|
|
|
|
$tax_query = array();
|
|
if ( ! empty( $site_slug ) ) {
|
|
$tax_query[] = array(
|
|
'taxonomy' => 'hssm_site',
|
|
'field' => 'slug',
|
|
'terms' => $site_slug,
|
|
);
|
|
}
|
|
|
|
$args = array(
|
|
'post_type' => 'hssm_slide',
|
|
'post_status' => array( 'publish', 'future' ),
|
|
'posts_per_page' => -1,
|
|
'orderby' => 'meta_value_num',
|
|
'meta_key' => '_hssm_order',
|
|
'order' => 'ASC',
|
|
'meta_query' => $meta_query,
|
|
'tax_query' => $tax_query
|
|
);
|
|
|
|
$slides = get_posts( $args );
|
|
$formatted_slides = array();
|
|
|
|
foreach ( $slides as $slide ) {
|
|
$formatted_slides[] = $this->format_slide_for_frontend( $slide->ID );
|
|
}
|
|
|
|
wp_send_json_success( array( 'slides' => $formatted_slides ) );
|
|
}
|
|
|
|
/**
|
|
* AJAX handler for saving slides
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function ajax_save_slide() {
|
|
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'hssm_dashboard_nonce' ) || ! $this->check_dashboard_access() ) {
|
|
wp_send_json_error( array( 'message' => 'Unauthorized' ) );
|
|
return;
|
|
}
|
|
|
|
// Sanitize and validate input
|
|
$slide_data = $this->sanitize_slide_data( $_POST );
|
|
|
|
if ( ! $this->validate_slide_data( $slide_data ) ) {
|
|
wp_send_json_error( array( 'message' => 'Invalid slide data' ) );
|
|
}
|
|
|
|
// Create the slide post
|
|
$post_args = array(
|
|
'post_type' => 'hssm_slide',
|
|
'post_title' => $slide_data['title'],
|
|
'post_content' => $slide_data['content'],
|
|
'post_excerpt' => $slide_data['content'],
|
|
'post_status' => $slide_data['post_status'],
|
|
'post_author' => get_current_user_id(),
|
|
);
|
|
|
|
// If scheduling for future, set the post date
|
|
if ( $slide_data['post_status'] === 'future' && ! empty( $slide_data['start_date'] ) ) {
|
|
$post_args['post_date'] = $slide_data['start_date'] . ' 00:00:00';
|
|
$post_args['post_date_gmt'] = get_gmt_from_date( $post_args['post_date'] );
|
|
}
|
|
|
|
$slide_id = wp_insert_post( $post_args );
|
|
|
|
if ( is_wp_error( $slide_id ) ) {
|
|
wp_send_json_error( array( 'message' => 'Failed to create slide' ) );
|
|
}
|
|
|
|
// Save meta data
|
|
$this->save_slide_meta( $slide_id, $slide_data );
|
|
|
|
// Save taxonomies
|
|
$this->save_slide_taxonomies( $slide_id, $slide_data );
|
|
|
|
// Set featured image if provided
|
|
if ( ! empty( $slide_data['featured_image_id'] ) ) {
|
|
set_post_thumbnail( $slide_id, $slide_data['featured_image_id'] );
|
|
}
|
|
|
|
wp_send_json_success( array(
|
|
'message' => 'Slide saved successfully!',
|
|
'slide_id' => $slide_id,
|
|
'slide_data' => $this->format_slide_for_frontend( $slide_id )
|
|
) );
|
|
}
|
|
|
|
/**
|
|
* AJAX handler for image uploads
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
/**
|
|
* Sanitize slide data from form
|
|
*
|
|
* @since 1.0.0
|
|
* @param array $data Raw form data
|
|
* @return array Sanitized data
|
|
*/
|
|
private function sanitize_slide_data( $data ) {
|
|
error_log( 'Raw form data received: ' . print_r( $data, true ) );
|
|
|
|
// Handle target_sites - it might come as an array or need to be extracted
|
|
$target_sites = array();
|
|
if ( isset( $data['target_sites'] ) ) {
|
|
if ( is_array( $data['target_sites'] ) ) {
|
|
$target_sites = $data['target_sites'];
|
|
} else {
|
|
// If it's a single value, make it an array
|
|
$target_sites = array( $data['target_sites'] );
|
|
}
|
|
}
|
|
|
|
// Handle buttons - decode JSON if it's a string
|
|
$buttons = $data['buttons'] ?? array();
|
|
if ( is_string( $buttons ) ) {
|
|
$decoded = json_decode( stripslashes( $buttons ), true );
|
|
if ( is_array( $decoded ) ) {
|
|
$buttons = $decoded;
|
|
}
|
|
}
|
|
|
|
$sanitized = array(
|
|
'title' => sanitize_text_field( $data['title'] ?? '' ),
|
|
'subtitle' => sanitize_text_field( $data['subtitle'] ?? '' ),
|
|
'content' => wp_kses_post( $data['content'] ?? '' ),
|
|
'buttons' => $this->sanitize_buttons( $buttons ),
|
|
'target_sites' => array_map( 'sanitize_text_field', $target_sites ),
|
|
'client' => sanitize_text_field( $data['client'] ?? '' ),
|
|
'start_date' => sanitize_text_field( $data['start_date'] ?? '' ),
|
|
'end_date' => sanitize_text_field( $data['end_date'] ?? '' ),
|
|
'post_status' => in_array( $data['post_status'] ?? 'draft', array( 'draft', 'publish', 'future' ) ) ? $data['post_status'] : 'draft',
|
|
'auto_publish' => ! empty( $data['auto_publish'] ),
|
|
'auto_unpublish' => ! empty( $data['auto_unpublish'] ),
|
|
'order' => intval( $data['order'] ?? 0 ),
|
|
'featured_image_id' => intval( $data['featured_image_id'] ?? 0 ),
|
|
'hide_all_text' => ! empty( $data['hide_all_text'] ) && $data['hide_all_text'] === '1',
|
|
);
|
|
|
|
error_log( 'Sanitized slide data: ' . print_r( $sanitized, true ) );
|
|
error_log( 'Target sites count: ' . count( $sanitized['target_sites'] ) );
|
|
return $sanitized;
|
|
}
|
|
|
|
/**
|
|
* Sanitize buttons array
|
|
*
|
|
* @since 1.0.0
|
|
* @param array $buttons Raw buttons data
|
|
* @return array Sanitized buttons
|
|
*/
|
|
private function sanitize_buttons( $buttons ) {
|
|
$sanitized = array();
|
|
|
|
if ( is_array( $buttons ) ) {
|
|
foreach ( $buttons as $button ) {
|
|
if ( ! empty( $button['text'] ) || ! empty( $button['url'] ) ) {
|
|
$sanitized[] = array(
|
|
'text' => sanitize_text_field( $button['text'] ?? 'Learn More' ),
|
|
'url' => esc_url_raw( $button['url'] ?? '' ),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ensure at least one button
|
|
if ( empty( $sanitized ) ) {
|
|
$sanitized[] = array( 'text' => 'Learn More', 'url' => '' );
|
|
}
|
|
|
|
return array_slice( $sanitized, 0, 5 ); // Max 5 buttons
|
|
}
|
|
|
|
/**
|
|
* Validate slide data
|
|
*
|
|
* @since 1.0.0
|
|
* @param array $data Sanitized slide data
|
|
* @return bool Is valid
|
|
*/
|
|
private function validate_slide_data( $data ) {
|
|
error_log( 'Validating slide data: ' . print_r( $data, true ) );
|
|
|
|
// Required fields
|
|
if ( empty( $data['title'] ) ) {
|
|
error_log( 'Validation failed: Missing title' );
|
|
return false;
|
|
}
|
|
|
|
// Validate target sites
|
|
if ( ! empty( $data['target_sites'] ) && is_array( $data['target_sites'] ) ) {
|
|
// Check if each site slug exists as a taxonomy term
|
|
foreach ( $data['target_sites'] as $site_slug ) {
|
|
$term = get_term_by( 'slug', $site_slug, 'hssm_site' );
|
|
if ( ! $term || is_wp_error( $term ) ) {
|
|
error_log( 'Validation failed: Invalid site slug (not a taxonomy term): ' . $site_slug );
|
|
return false;
|
|
}
|
|
}
|
|
} else {
|
|
error_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 ) );
|
|
return false;
|
|
}
|
|
|
|
error_log( 'Validation passed' );
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Save slide meta data
|
|
*
|
|
* @since 1.0.0
|
|
* @param int $slide_id Slide ID
|
|
* @param array $data Slide data
|
|
*/
|
|
private function save_slide_meta( $slide_id, $data ) {
|
|
$meta_fields = array(
|
|
'_hssm_subtitle' => $data['subtitle'],
|
|
'_hssm_buttons' => $data['buttons'],
|
|
'_hssm_start_date' => $data['start_date'],
|
|
'_hssm_end_date' => $data['end_date'],
|
|
'_hssm_auto_publish' => $data['auto_publish'] ? '1' : '0',
|
|
'_hssm_auto_unpublish' => $data['auto_unpublish'] ? '1' : '0',
|
|
'_hssm_order' => $data['order'],
|
|
'_hssm_hide_all_text' => $data['hide_all_text'] ? '1' : '0',
|
|
);
|
|
|
|
foreach ( $meta_fields as $key => $value ) {
|
|
update_post_meta( $slide_id, $key, $value );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Save slide taxonomies
|
|
*
|
|
* @since 1.0.0
|
|
* @param int $slide_id Slide ID
|
|
* @param array $data Slide data
|
|
*/
|
|
private function save_slide_taxonomies( $slide_id, $data ) {
|
|
// Set 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 ) );
|
|
|
|
// Ensure we're using term slugs, not IDs
|
|
$term_slugs = array();
|
|
foreach ( $data['target_sites'] as $site_slug ) {
|
|
// Check if term exists, if not create it
|
|
$term = get_term_by( 'slug', $site_slug, 'hssm_site' );
|
|
if ( ! $term || is_wp_error( $term ) ) {
|
|
// Try to create the term if it doesn't exist
|
|
$term_result = wp_insert_term( $site_slug, 'hssm_site', array( 'slug' => $site_slug ) );
|
|
if ( ! is_wp_error( $term_result ) ) {
|
|
$term_slugs[] = $site_slug;
|
|
}
|
|
} else {
|
|
$term_slugs[] = $site_slug;
|
|
}
|
|
}
|
|
|
|
if ( ! empty( $term_slugs ) ) {
|
|
$result = wp_set_post_terms( $slide_id, $term_slugs, 'hssm_site' );
|
|
error_log( 'wp_set_post_terms result: ' . print_r( $result, true ) );
|
|
} else {
|
|
error_log( 'No valid term slugs to save' );
|
|
}
|
|
} else {
|
|
error_log( 'No target sites to save for slide ' . $slide_id );
|
|
}
|
|
|
|
// Set client
|
|
if ( ! empty( $data['client'] ) ) {
|
|
wp_set_post_terms( $slide_id, array( $data['client'] ), 'hssm_client' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Format slide data for frontend display
|
|
*
|
|
* @since 1.0.0
|
|
* @param int $slide_id Slide ID
|
|
* @return array Formatted slide data
|
|
*/
|
|
private function format_slide_for_frontend( $slide_id ) {
|
|
$slide = get_post( $slide_id );
|
|
|
|
return array(
|
|
'id' => $slide->ID,
|
|
'title' => $slide->post_title,
|
|
'subtitle' => get_post_meta( $slide_id, '_hssm_subtitle', true ),
|
|
'content' => $slide->post_content,
|
|
'buttons' => get_post_meta( $slide_id, '_hssm_buttons', true ),
|
|
'featured_image' => get_the_post_thumbnail_url( $slide_id, 'medium' ),
|
|
'target_sites' => wp_get_post_terms( $slide_id, 'hssm_site', array( 'fields' => 'slugs' ) ),
|
|
'client' => wp_get_post_terms( $slide_id, 'hssm_client', array( 'fields' => 'slugs' ) ),
|
|
'status' => $slide->post_status,
|
|
'created' => $slide->post_date,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* AJAX handler for getting slides
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function ajax_get_slides() {
|
|
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 view slides.' ) );
|
|
return;
|
|
}
|
|
// Get pagination parameters
|
|
$page = isset( $_POST['page'] ) ? intval( $_POST['page'] ) : 1;
|
|
$per_page = isset( $_POST['per_page'] ) ? intval( $_POST['per_page'] ) : 25;
|
|
$offset = ( $page - 1 ) * $per_page;
|
|
|
|
// Get filter parameters
|
|
$status_filter = isset( $_POST['status_filter'] ) ? sanitize_text_field( $_POST['status_filter'] ) : '';
|
|
$site_filter = isset( $_POST['site_filter'] ) ? sanitize_text_field( $_POST['site_filter'] ) : '';
|
|
$client_filter = isset( $_POST['client_filter'] ) ? sanitize_text_field( $_POST['client_filter'] ) : '';
|
|
$month_filter = isset( $_POST['month_filter'] ) ? sanitize_text_field( $_POST['month_filter'] ) : ''; // Format: YYYY-MM
|
|
$year_filter = isset( $_POST['year_filter'] ) ? intval( $_POST['year_filter'] ) : 0;
|
|
|
|
// Build query args
|
|
$args = array(
|
|
'post_type' => 'hssm_slide',
|
|
'post_status' => array( 'publish', 'draft', 'pending', 'future' ), // Include all statuses
|
|
'posts_per_page' => $per_page,
|
|
'offset' => $offset,
|
|
'orderby' => 'date',
|
|
'order' => 'DESC',
|
|
'tax_query' => array(),
|
|
'date_query' => array()
|
|
);
|
|
|
|
// Add status filter
|
|
if ( ! empty( $status_filter ) ) {
|
|
$args['post_status'] = array( $status_filter );
|
|
}
|
|
|
|
// Add site filter using taxonomy query
|
|
if ( ! empty( $site_filter ) ) {
|
|
// Get site term by slug
|
|
$site_term = get_term_by( 'slug', $site_filter, 'hssm_site' );
|
|
if ( $site_term && ! is_wp_error( $site_term ) ) {
|
|
$args['tax_query'][] = array(
|
|
'taxonomy' => 'hssm_site',
|
|
'field' => 'term_id',
|
|
'terms' => $site_term->term_id,
|
|
);
|
|
}
|
|
}
|
|
|
|
// Add client filter using taxonomy query
|
|
if ( ! empty( $client_filter ) ) {
|
|
// Get client term by slug or ID
|
|
$client_term = is_numeric( $client_filter )
|
|
? get_term( intval( $client_filter ), 'hssm_client' )
|
|
: get_term_by( 'slug', $client_filter, 'hssm_client' );
|
|
if ( $client_term && ! is_wp_error( $client_term ) ) {
|
|
$args['tax_query'][] = array(
|
|
'taxonomy' => 'hssm_client',
|
|
'field' => 'term_id',
|
|
'terms' => $client_term->term_id,
|
|
);
|
|
}
|
|
}
|
|
|
|
// Add month/year filter using date query
|
|
if ( ! empty( $month_filter ) ) {
|
|
// Format: YYYY-MM
|
|
$date_parts = explode( '-', $month_filter );
|
|
if ( count( $date_parts ) === 2 && strlen( $date_parts[0] ) === 4 && strlen( $date_parts[1] ) === 2 ) {
|
|
$year = intval( $date_parts[0] );
|
|
$month = intval( $date_parts[1] );
|
|
if ( $year > 0 && $month >= 1 && $month <= 12 ) {
|
|
$args['date_query'][] = array(
|
|
'year' => $year,
|
|
'month' => $month,
|
|
);
|
|
}
|
|
}
|
|
} elseif ( $year_filter > 0 ) {
|
|
// If only year is specified
|
|
$args['date_query'][] = array(
|
|
'year' => $year_filter,
|
|
);
|
|
}
|
|
|
|
// Set relation if we have multiple taxonomy queries
|
|
if ( count( $args['tax_query'] ) > 1 ) {
|
|
$args['tax_query']['relation'] = 'AND';
|
|
} elseif ( empty( $args['tax_query'] ) ) {
|
|
// Remove empty tax_query to avoid unnecessary query conditions
|
|
unset( $args['tax_query'] );
|
|
}
|
|
|
|
// Remove empty date_query if no date filters were applied
|
|
if ( empty( $args['date_query'] ) ) {
|
|
unset( $args['date_query'] );
|
|
}
|
|
|
|
// Get total count for pagination
|
|
$count_args = $args;
|
|
$count_args['posts_per_page'] = -1;
|
|
$count_args['fields'] = 'ids';
|
|
unset( $count_args['offset'] );
|
|
$total_slides = count( get_posts( $count_args ) );
|
|
|
|
// Get slides
|
|
$slides = get_posts( $args );
|
|
$formatted_slides = array();
|
|
|
|
foreach ( $slides as $slide ) {
|
|
$slide_meta = get_post_meta( $slide->ID );
|
|
|
|
// Get selected sites from taxonomy terms
|
|
$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,
|
|
'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(
|
|
'slides' => $formatted_slides,
|
|
'total' => $total_slides,
|
|
'page' => $page,
|
|
'per_page' => $per_page,
|
|
'total_pages' => ceil( $total_slides / $per_page ),
|
|
'has_more' => ( $page * $per_page ) < $total_slides
|
|
) );
|
|
}
|
|
|
|
/**
|
|
* AJAX handler for approving slides
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function ajax_approve_slide() {
|
|
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 ( ! isset( $_POST['slide_id'] ) || '' === trim( (string) $_POST['slide_id'] ) ) {
|
|
wp_send_json_error( array( 'message' => 'Slide ID is required' ) );
|
|
return;
|
|
}
|
|
|
|
$slide_id = intval( $_POST['slide_id'] );
|
|
$approve_action = isset( $_POST['approve_action'] ) ? sanitize_text_field( $_POST['approve_action'] ) : 'publish';
|
|
|
|
// Check if slide exists
|
|
$slide = get_post( $slide_id );
|
|
if ( ! $slide || $slide->post_type !== 'hssm_slide' ) {
|
|
wp_send_json_error( array( 'message' => 'Slide not found' ) );
|
|
return;
|
|
}
|
|
|
|
// Check permissions
|
|
if ( ! current_user_can( 'edit_posts' ) ) {
|
|
wp_send_json_error( array( 'message' => 'Permission denied' ) );
|
|
return;
|
|
}
|
|
|
|
$slide_meta = get_post_meta( $slide_id );
|
|
$start_date = isset( $slide_meta['_hssm_start_date'][0] ) ? $slide_meta['_hssm_start_date'][0] : '';
|
|
|
|
if ( $approve_action === 'schedule' && ! empty( $start_date ) ) {
|
|
// Schedule for future publication
|
|
$post_data = array(
|
|
'ID' => $slide_id,
|
|
'post_status' => 'future',
|
|
'post_date' => $start_date . ' 00:00:00'
|
|
);
|
|
} else {
|
|
// Publish immediately
|
|
$post_data = array(
|
|
'ID' => $slide_id,
|
|
'post_status' => 'publish'
|
|
);
|
|
}
|
|
|
|
$result = wp_update_post( $post_data );
|
|
|
|
if ( $result ) {
|
|
error_log( "Slide $slide_id approved with action: $approve_action" );
|
|
|
|
// Trigger 2: Notification to Creator (Author) when approved
|
|
$notifications = new HSSM_Notifications();
|
|
$notifications->notify_creator_slide_approved( $slide_id );
|
|
|
|
wp_send_json_success( array(
|
|
'message' => 'Slide approved successfully',
|
|
'new_status' => $post_data['post_status']
|
|
) );
|
|
} else {
|
|
wp_send_json_error( array( 'message' => 'Failed to approve slide' ) );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* AJAX handler for deleting slides
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function ajax_delete_slide() {
|
|
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 ( ! isset( $_POST['slide_id'] ) || '' === trim( (string) $_POST['slide_id'] ) ) {
|
|
wp_send_json_error( array( 'message' => 'Slide ID is required' ) );
|
|
return;
|
|
}
|
|
|
|
$slide_id = intval( $_POST['slide_id'] );
|
|
|
|
// Check if slide exists and user can delete it
|
|
$slide = get_post( $slide_id );
|
|
if ( ! $slide || $slide->post_type !== 'hssm_slide' ) {
|
|
wp_send_json_error( array( 'message' => 'Slide not found' ) );
|
|
}
|
|
|
|
if ( ! current_user_can( 'delete_post', $slide_id ) ) {
|
|
wp_send_json_error( array( 'message' => 'Insufficient permissions' ) );
|
|
}
|
|
|
|
// Delete the slide
|
|
$result = wp_delete_post( $slide_id, true );
|
|
|
|
if ( $result ) {
|
|
wp_send_json_success( array( 'message' => 'Slide deleted successfully!' ) );
|
|
} else {
|
|
wp_send_json_error( array( 'message' => 'Failed to delete slide' ) );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* AJAX handler for updating slides
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function ajax_update_slide() {
|
|
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 ( ! isset( $_POST['slide_id'] ) || '' === trim( (string) $_POST['slide_id'] ) ) {
|
|
wp_send_json_error( array( 'message' => 'Slide ID is required' ) );
|
|
return;
|
|
}
|
|
|
|
$slide_id = intval( $_POST['slide_id'] );
|
|
|
|
// Check if slide exists and user can edit it
|
|
$slide = get_post( $slide_id );
|
|
if ( ! $slide || $slide->post_type !== 'hssm_slide' ) {
|
|
wp_send_json_error( array( 'message' => 'Slide not found' ) );
|
|
}
|
|
|
|
if ( ! current_user_can( 'edit_post', $slide_id ) ) {
|
|
wp_send_json_error( array( 'message' => 'Insufficient permissions' ) );
|
|
}
|
|
|
|
// Sanitize and validate input
|
|
$slide_data = $this->sanitize_slide_data( $_POST );
|
|
|
|
if ( ! $this->validate_slide_data( $slide_data ) ) {
|
|
wp_send_json_error( array( 'message' => 'Invalid slide data' ) );
|
|
}
|
|
|
|
// Get post status from request (default to draft if not specified)
|
|
$post_status = isset( $_POST['post_status'] ) ? sanitize_text_field( $_POST['post_status'] ) : 'draft';
|
|
|
|
// Validate post status
|
|
$allowed_statuses = array( 'draft', 'pending', 'publish', 'future' );
|
|
if ( ! in_array( $post_status, $allowed_statuses, true ) ) {
|
|
$post_status = 'draft';
|
|
}
|
|
|
|
// Update the slide post
|
|
$post_args = array(
|
|
'ID' => $slide_id,
|
|
'post_title' => $slide_data['title'],
|
|
'post_content' => $slide_data['content'],
|
|
'post_excerpt' => $slide_data['content'],
|
|
'post_status' => $post_status,
|
|
);
|
|
|
|
// If scheduling for future and start date is set, use that as post_date
|
|
if ( $post_status === 'future' && ! empty( $slide_data['start_date'] ) ) {
|
|
$post_args['post_date'] = $slide_data['start_date'] . ' 00:00:00';
|
|
$post_args['post_date_gmt'] = get_gmt_from_date( $post_args['post_date'] );
|
|
}
|
|
|
|
$result = wp_update_post( $post_args );
|
|
|
|
if ( is_wp_error( $result ) ) {
|
|
wp_send_json_error( array( 'message' => 'Failed to update slide' ) );
|
|
}
|
|
|
|
// Update meta data
|
|
$this->save_slide_meta( $slide_id, $slide_data );
|
|
|
|
// Update taxonomies
|
|
$this->save_slide_taxonomies( $slide_id, $slide_data );
|
|
|
|
// Update featured image if provided
|
|
if ( ! empty( $slide_data['featured_image_id'] ) ) {
|
|
set_post_thumbnail( $slide_id, $slide_data['featured_image_id'] );
|
|
}
|
|
|
|
// Send approval notification if status is pending
|
|
if ( $post_status === 'pending' ) {
|
|
// Trigger 1 (variant): Notification to Editor when updated slide is scheduled for approval
|
|
$notifications = new HSSM_Notifications();
|
|
$notifications->notify_editor_slide_created( $slide_id, 'scheduled' );
|
|
}
|
|
|
|
$status_message = ( $post_status === 'pending' )
|
|
? 'Slide updated and scheduled for approval!'
|
|
: 'Slide updated successfully!';
|
|
|
|
wp_send_json_success( array(
|
|
'message' => $status_message,
|
|
'slide_data' => $this->format_slide_for_frontend( $slide_id )
|
|
) );
|
|
}
|
|
|
|
/**
|
|
* AJAX handler for scheduling a slide for approval
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function ajax_schedule_slide() {
|
|
error_log( 'Schedule slide AJAX called' );
|
|
error_log( 'POST data: ' . print_r( $_POST, true ) );
|
|
|
|
// Check nonce
|
|
if ( ! check_ajax_referer( 'hssm_dashboard_nonce', 'nonce', false ) ) {
|
|
error_log( 'Nonce verification failed' );
|
|
wp_send_json_error( array( 'message' => 'Security check failed' ) );
|
|
}
|
|
|
|
// Check user permissions
|
|
if ( ! current_user_can( 'edit_posts' ) ) {
|
|
error_log( 'User permissions check failed' );
|
|
wp_send_json_error( array( 'message' => 'Insufficient permissions' ) );
|
|
}
|
|
|
|
// Sanitize and validate input
|
|
$slide_data = $this->sanitize_slide_data( $_POST );
|
|
|
|
if ( ! $this->validate_slide_data( $slide_data ) ) {
|
|
error_log( 'Slide data validation failed' );
|
|
wp_send_json_error( array( 'message' => 'Invalid slide data' ) );
|
|
}
|
|
|
|
// Create slide with 'pending' status for approval
|
|
$post_args = array(
|
|
'post_title' => $slide_data['title'],
|
|
'post_content' => $slide_data['content'],
|
|
'post_excerpt' => $slide_data['content'],
|
|
'post_type' => 'hssm_slide',
|
|
'post_status' => 'pending',
|
|
'meta_input' => array(
|
|
'_hssm_scheduled_for_approval' => current_time( 'timestamp' ),
|
|
'_hssm_submitted_by' => get_current_user_id(),
|
|
)
|
|
);
|
|
|
|
$slide_id = wp_insert_post( $post_args );
|
|
|
|
if ( is_wp_error( $slide_id ) || ! $slide_id ) {
|
|
wp_send_json_error( array( 'message' => 'Failed to schedule slide' ) );
|
|
}
|
|
|
|
// Save meta data and taxonomies
|
|
$this->save_slide_meta( $slide_id, $slide_data );
|
|
$this->save_slide_taxonomies( $slide_id, $slide_data );
|
|
|
|
// Set featured image
|
|
if ( ! empty( $slide_data['featured_image_id'] ) ) {
|
|
set_post_thumbnail( $slide_id, $slide_data['featured_image_id'] );
|
|
}
|
|
|
|
// Send approval email notifications
|
|
// Trigger 1 (variant): Notification to Editor when slide is scheduled for approval
|
|
$notifications = new HSSM_Notifications();
|
|
$notifications->notify_editor_slide_created( $slide_id, 'scheduled' );
|
|
|
|
wp_send_json_success( array(
|
|
'message' => 'Slide scheduled for approval. Email notifications sent.',
|
|
'slide_id' => $slide_id
|
|
) );
|
|
}
|
|
|
|
/**
|
|
* AJAX handler for publishing a slide immediately
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function ajax_publish_slide() {
|
|
// Check nonce
|
|
if ( ! check_ajax_referer( 'hssm_dashboard_nonce', 'nonce', false ) ) {
|
|
wp_send_json_error( array( 'message' => 'Security check failed' ) );
|
|
}
|
|
|
|
// Check user permissions
|
|
if ( ! current_user_can( 'publish_posts' ) ) {
|
|
wp_send_json_error( array( 'message' => 'Insufficient permissions' ) );
|
|
}
|
|
|
|
// Sanitize and validate input
|
|
$slide_data = $this->sanitize_slide_data( $_POST );
|
|
|
|
if ( ! $this->validate_slide_data( $slide_data ) ) {
|
|
wp_send_json_error( array( 'message' => 'Invalid slide data' ) );
|
|
}
|
|
|
|
// Create slide with 'publish' status
|
|
$post_args = array(
|
|
'post_title' => $slide_data['title'],
|
|
'post_content' => $slide_data['content'],
|
|
'post_excerpt' => $slide_data['content'],
|
|
'post_type' => 'hssm_slide',
|
|
'post_status' => 'publish',
|
|
'meta_input' => array(
|
|
'_hssm_published_immediately' => current_time( 'timestamp' ),
|
|
'_hssm_published_by' => get_current_user_id(),
|
|
)
|
|
);
|
|
|
|
$slide_id = wp_insert_post( $post_args );
|
|
|
|
if ( is_wp_error( $slide_id ) || ! $slide_id ) {
|
|
wp_send_json_error( array( 'message' => 'Failed to publish slide' ) );
|
|
}
|
|
|
|
// Save meta data and taxonomies
|
|
$this->save_slide_meta( $slide_id, $slide_data );
|
|
$this->save_slide_taxonomies( $slide_id, $slide_data );
|
|
|
|
// Set featured image
|
|
if ( ! empty( $slide_data['featured_image_id'] ) ) {
|
|
set_post_thumbnail( $slide_id, $slide_data['featured_image_id'] );
|
|
}
|
|
|
|
// Send approval/notification emails
|
|
// Trigger 1: Notification to Editor when slide is scheduled or published
|
|
$notifications = new HSSM_Notifications();
|
|
$notifications->notify_editor_slide_created( $slide_id, 'published' );
|
|
|
|
wp_send_json_success( array(
|
|
'message' => 'Slide published successfully. Approval notifications sent.',
|
|
'slide_id' => $slide_id
|
|
) );
|
|
}
|
|
|
|
/**
|
|
* Send email notifications for slide approval workflow
|
|
*
|
|
* @since 1.0.0
|
|
* @param int $slide_id The slide ID
|
|
* @param string $action The action taken ('scheduled' or 'published')
|
|
*/
|
|
private function send_approval_notification( $slide_id, $action ) {
|
|
// Use the new Notification class
|
|
$notifications = new HSSM_Notifications();
|
|
$notifications->notify_editor_slide_created( $slide_id, $action );
|
|
}
|
|
|
|
/**
|
|
* Get formatted text of target sites for a slide
|
|
*
|
|
* @since 1.0.0
|
|
* @param int $slide_id The slide ID
|
|
* @return string Formatted target sites text
|
|
*/
|
|
private function get_slide_target_sites_text( $slide_id ) {
|
|
$target_sites = get_post_meta( $slide_id, '_hssm_target_sites', true );
|
|
|
|
if ( empty( $target_sites ) || ! is_array( $target_sites ) ) {
|
|
return 'None selected';
|
|
}
|
|
|
|
$site_names = array();
|
|
foreach ( $target_sites as $site_id ) {
|
|
// Get site name - this could be enhanced to use actual site data
|
|
$site_names[] = ucfirst( str_replace( '-', ' ', $site_id ) );
|
|
}
|
|
|
|
return implode( ', ', $site_names );
|
|
}
|
|
|
|
/**
|
|
* Get client name for a slide from taxonomy
|
|
*
|
|
* @since 1.0.0
|
|
* @param int $slide_id Slide ID
|
|
* @return string Client name or empty string
|
|
*/
|
|
private function get_slide_client_name( $slide_id ) {
|
|
$client_terms = wp_get_post_terms( $slide_id, 'hssm_client', array( 'fields' => 'all' ) );
|
|
if ( ! empty( $client_terms ) && ! is_wp_error( $client_terms ) ) {
|
|
return $client_terms[0]->name;
|
|
}
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Get available sites for targeting
|
|
*
|
|
* @since 1.0.0
|
|
* @return array Available sites data
|
|
*/
|
|
private function get_available_sites() {
|
|
// Use centralized method from HSSM_Main if available
|
|
if ( class_exists( 'HSSM_Main' ) && method_exists( 'HSSM_Main', 'get_companion_sites' ) ) {
|
|
$sites = HSSM_Main::get_companion_sites();
|
|
$formatted_sites = array();
|
|
|
|
foreach ( $sites as $site ) {
|
|
$formatted_sites[] = array(
|
|
'id' => $site['slug'],
|
|
'name' => $site['name']
|
|
);
|
|
}
|
|
|
|
return $formatted_sites;
|
|
}
|
|
|
|
// Fallback for safety
|
|
return array(
|
|
array(
|
|
'id' => 'hi-school',
|
|
'name' => 'Hi-School Pharmacy'
|
|
),
|
|
array(
|
|
'id' => 'one-stop',
|
|
'name' => 'One Stop Hardware'
|
|
),
|
|
array(
|
|
'id' => 'ace',
|
|
'name' => 'Ace Hardware'
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* AJAX handler for duplicating slides
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function ajax_duplicate_slide() {
|
|
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'hssm_dashboard_nonce' ) || ! $this->check_dashboard_access() ) {
|
|
wp_send_json_error( array( 'message' => 'Unauthorized' ) );
|
|
return;
|
|
}
|
|
|
|
if ( ! isset( $_POST['slide_id'] ) || '' === trim( (string) $_POST['slide_id'] ) ) {
|
|
wp_send_json_error( array( 'message' => 'Slide ID is required' ) );
|
|
return;
|
|
}
|
|
|
|
$original_id = intval( $_POST['slide_id'] );
|
|
$original_post = get_post( $original_id );
|
|
|
|
if ( ! $original_post || $original_post->post_type !== 'hssm_slide' ) {
|
|
wp_send_json_error( array( 'message' => 'Slide not found' ) );
|
|
}
|
|
|
|
// Create new post
|
|
$new_post_data = array(
|
|
'post_title' => $original_post->post_title . ' (Copy)',
|
|
'post_content' => $original_post->post_content,
|
|
'post_status' => 'draft',
|
|
'post_type' => 'hssm_slide',
|
|
'post_author' => get_current_user_id(),
|
|
);
|
|
|
|
$new_id = wp_insert_post( $new_post_data );
|
|
|
|
if ( is_wp_error( $new_id ) ) {
|
|
wp_send_json_error( array( 'message' => 'Failed to duplicate slide' ) );
|
|
}
|
|
|
|
// Copy all meta fields
|
|
$meta_fields = get_post_meta( $original_id );
|
|
foreach ( $meta_fields as $key => $values ) {
|
|
foreach ( $values as $value ) {
|
|
add_post_meta( $new_id, $key, maybe_unserialize( $value ) );
|
|
}
|
|
}
|
|
|
|
wp_send_json_success( array( 'message' => 'Slide duplicated successfully', 'new_id' => $new_id ) );
|
|
}
|
|
|
|
/**
|
|
* AJAX handler for toggling slide status
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function ajax_toggle_slide_status() {
|
|
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'hssm_dashboard_nonce' ) || ! $this->check_dashboard_access() ) {
|
|
wp_send_json_error( array( 'message' => 'Unauthorized' ) );
|
|
return;
|
|
}
|
|
|
|
if ( ! isset( $_POST['slide_id'] ) || '' === trim( (string) $_POST['slide_id'] ) ) {
|
|
wp_send_json_error( array( 'message' => 'Slide ID is required' ) );
|
|
return;
|
|
}
|
|
|
|
$slide_id = intval( $_POST['slide_id'] );
|
|
$post = get_post( $slide_id );
|
|
|
|
if ( ! $post || $post->post_type !== 'hssm_slide' ) {
|
|
wp_send_json_error( array( 'message' => 'Slide not found' ) );
|
|
}
|
|
|
|
// Toggle status
|
|
$new_status = ( $post->post_status === 'publish' ) ? 'draft' : 'publish';
|
|
|
|
$updated = wp_update_post( array(
|
|
'ID' => $slide_id,
|
|
'post_status' => $new_status
|
|
) );
|
|
|
|
if ( is_wp_error( $updated ) ) {
|
|
wp_send_json_error( array( 'message' => 'Failed to update slide status' ) );
|
|
}
|
|
|
|
// Trigger notification if published via toggle?
|
|
// Logic check: If toggled to publish, it means it's Live.
|
|
if ( $new_status === 'publish' ) {
|
|
// Trigger 3: Notification to ITCGuys when slide goes Live (via manual toggle)
|
|
$notifications = new HSSM_Notifications();
|
|
$notifications->notify_itc_slide_live( $slide_id );
|
|
}
|
|
|
|
wp_send_json_success( array(
|
|
'message' => 'Slide status updated successfully',
|
|
'new_status' => $new_status
|
|
) );
|
|
}
|
|
|
|
/**
|
|
* AJAX handler to get notification settings
|
|
*/
|
|
public function ajax_get_notification_settings() {
|
|
if ( ! check_ajax_referer( 'hssm_dashboard_nonce', 'nonce', false ) || ! $this->check_dashboard_access() ) {
|
|
wp_send_json_error( array( 'message' => 'Unauthorized' ) );
|
|
}
|
|
|
|
$settings = HSSM_Notifications::get_settings();
|
|
wp_send_json_success( $settings );
|
|
}
|
|
|
|
/**
|
|
* AJAX handler to save notification settings
|
|
*/
|
|
public function ajax_save_notification_settings() {
|
|
if ( ! check_ajax_referer( 'hssm_dashboard_nonce', 'nonce', false ) || ! $this->check_dashboard_access() ) {
|
|
wp_send_json_error( array( 'message' => 'Unauthorized' ) );
|
|
}
|
|
|
|
// Pass raw values to the class method which handles sanitization
|
|
$settings = array(
|
|
'editor_emails' => isset($_POST['editor_emails']) ? wp_unslash( $_POST['editor_emails'] ) : '',
|
|
'itc_emails' => isset($_POST['itc_emails']) ? wp_unslash( $_POST['itc_emails'] ) : ''
|
|
);
|
|
|
|
if ( HSSM_Notifications::save_settings( $settings ) ) {
|
|
wp_send_json_success( array( 'message' => 'Settings saved' ) );
|
|
} else {
|
|
// It might fail if no changes were made, which is fine, but we'll return success anyway or handle accordingly
|
|
wp_send_json_success( array( 'message' => 'Settings saved (or no changes)' ) );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Filter Slides Query on Preview Page
|
|
* We use pre_get_posts because it's more reliable at catching all queries.
|
|
*
|
|
* @since 1.0.0
|
|
* @param WP_Query $query The query object.
|
|
*/
|
|
public function filter_preview_slides_query( $query ) {
|
|
if ( is_admin() ) {
|
|
return;
|
|
}
|
|
|
|
// --- DEBUG ---
|
|
// error_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
|
|
$obj_id = get_queried_object_id();
|
|
if ( ! $obj_id ) {
|
|
global $post;
|
|
$obj_id = $post->ID ?? 0;
|
|
}
|
|
|
|
$template = get_page_template_slug( $obj_id );
|
|
if ( $template !== 'page-slide-preview.php' ) {
|
|
return;
|
|
}
|
|
|
|
// Don't filter the main query (the page itself)
|
|
if ( $query->is_main_query() ) {
|
|
return;
|
|
}
|
|
|
|
// Check if this query is intended for our slides.
|
|
// We look for queries that either already target hssm_slide
|
|
// OR queries from Divi loops that might need redirection.
|
|
$post_type = $query->get( 'post_type' );
|
|
|
|
// If it's a menu or something else we recognize, bail
|
|
if ( $query->get( 'post_type' ) === 'nav_menu_item' ) {
|
|
return;
|
|
}
|
|
|
|
// Force the query to slides for the preview
|
|
$query->set( 'post_type', 'hssm_slide' );
|
|
$query->set( 'posts_per_page', -1 );
|
|
$query->set( 'post_status', array( 'publish', 'future', 'pending' ) );
|
|
|
|
// Filter parameters from URL
|
|
$date_param = isset( $_GET['hssm_date'] ) ? sanitize_text_field( $_GET['hssm_date'] ) : current_time( 'Y-m-d' );
|
|
$site_param = isset( $_GET['hssm_site'] ) ? sanitize_text_field( $_GET['hssm_site'] ) : '';
|
|
|
|
// Apply Meta Query for Date (evergreen: no start/end = always show)
|
|
$meta_query = array(
|
|
'relation' => 'AND',
|
|
array(
|
|
'relation' => 'OR',
|
|
array(
|
|
'key' => '_hssm_start_date',
|
|
'value' => '',
|
|
'compare' => '=',
|
|
),
|
|
array(
|
|
'key' => '_hssm_start_date',
|
|
'value' => $date_param,
|
|
'compare' => '<=',
|
|
),
|
|
array(
|
|
'key' => '_hssm_start_date',
|
|
'compare' => 'NOT EXISTS',
|
|
),
|
|
),
|
|
array(
|
|
'relation' => 'OR',
|
|
array(
|
|
'key' => '_hssm_end_date',
|
|
'value' => $date_param,
|
|
'compare' => '>=',
|
|
),
|
|
array(
|
|
'key' => '_hssm_end_date',
|
|
'compare' => 'NOT EXISTS',
|
|
),
|
|
array(
|
|
'key' => '_hssm_end_date',
|
|
'value' => '',
|
|
'compare' => '=',
|
|
),
|
|
),
|
|
);
|
|
$query->set( 'meta_query', $meta_query );
|
|
|
|
// Apply Tax Query for Site
|
|
if ( ! empty( $site_param ) ) {
|
|
$tax_query = array(
|
|
array(
|
|
'taxonomy' => 'hssm_site',
|
|
'field' => 'slug',
|
|
'terms' => $site_param,
|
|
)
|
|
);
|
|
$query->set( 'tax_query', $tax_query );
|
|
}
|
|
|
|
// Ensure ordering matches
|
|
$query->set( 'orderby', 'meta_value_num' );
|
|
$query->set( 'meta_key', '_hssm_order' );
|
|
$query->set( 'order', 'ASC' );
|
|
$query->set( 'ignore_sticky_posts', true );
|
|
}
|
|
|
|
} |