Home / Admin / NS CALENDAR SHORTCODE
Duplicate Snippet

Embed Snippet on Your Site

NS CALENDAR SHORTCODE

ismail daugherty PRO
<10
Code Preview
php
<?php
/**
 * Compliance Calendar - Dashboard Shortcodes v1.3
 * 
 * Shortcodes for displaying compliance data on frontend
 * Uses group_id (BuddyBoss) as primary identifier
 * 
 * WPCODE SETTINGS:
 * - Code Type: PHP Snippet
 * - Location: Run Everywhere  
 * - Auto Insert: Site Wide Header
 * - Priority: 10
 * 
 * AVAILABLE SHORTCODES:
 * [compliance_dashboard]                    - Full dashboard with all tables
 * [compliance_dashboard group_id="123"]     - Dashboard for specific group
 * [compliance_dashboard group_id="123" year="2025"]
 * [compliance_month_cards]                  - 12 month cards view (NEW v1.3)
 * [compliance_month_cards detail_page="123"] - With drill-down link
 * [compliance_month_detail]                 - Single month detail view (NEW v1.3)
 * [compliance_month_detail month="jan"]     - Specific month
 * [compliance_progress_bar]                 - Progress bar only
 * [compliance_progress_bar group_id="123"]
 * [compliance_status_badge]                 - Simple status badge
 * [compliance_status_badge group_id="123"]
 * 
 * NOTE: Calendar shortcode removed due to inline script WAF conflicts.
 * Use dashboard view instead, or add calendar separately.
 * 
 * COLOR PALETTE (Next Step Consulting):
 * Primary Brown:  #8B5A2B
 * Coral Accent:   #F5844C
 * Teal:           #2A9D8F
 * Dark Teal:      #264653
 * 
 * CHANGELOG:
 * v1.3 - Added month cards view and month detail shortcodes
 * v1.2 - Removed inline scripts (Cloudflare WAF fix), removed sanitize_hex_color
 * v1.1 - Added input sanitization, year range validation
 * v1.0 - Initial release
 */
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}
/**
 * =============================================================================
 * HELPER FUNCTIONS
 * =============================================================================
 */
/**
 * Get the current user's primary BuddyBoss group ID
 * 
 * @return int|false Group ID or false if not found
 */
function bha_compliance_get_user_group_id() {
    
    if ( ! is_user_logged_in() ) {
        return false;
    }
    
    $user_id = get_current_user_id();
    
    // First check user meta for explicit group_id
    $group_id = get_user_meta( $user_id, 'group_id', true );
    if ( $group_id ) {
        return absint( $group_id );
    }
    
    // Fallback: Get first BuddyBoss group membership
    if ( function_exists( 'groups_get_user_groups' ) ) {
        $user_groups = groups_get_user_groups( $user_id );
        if ( ! empty( $user_groups['groups'] ) ) {
            return absint( $user_groups['groups'][0] );
        }
    }
    
    return false;
}
/**
 * Get compliance tracker post for a group and year
 * 
 * @param int $group_id BuddyBoss group ID
 * @param int|null $year Tracking year (defaults to current)
 * @return WP_Post|null Tracker post or null
 */
function bha_compliance_get_tracker( $group_id, $year = null ) {
    
    $group_id = absint( $group_id );
    if ( $group_id < 1 ) {
        return null;
    }
    
    if ( ! $year ) {
        $year = (int) wp_date( 'Y' );
    } else {
        $year = absint( $year );
        if ( $year < 2020 || $year > 2050 ) {
            $year = (int) wp_date( 'Y' );
        }
    }
    
    $trackers = get_posts( array(
        'post_type'      => 'compliance_tracker',
        'post_status'    => 'publish',
        'posts_per_page' => 1,
        'meta_query'     => array(
            'relation' => 'AND',
            array(
                'key'     => 'group_id',
                'value'   => $group_id,
                'compare' => '=',
                'type'    => 'NUMERIC',
            ),
            array(
                'key'     => 'tracking_year',
                'value'   => $year,
                'compare' => '=',
                'type'    => 'NUMERIC',
            ),
        ),
    ) );
    
    return ! empty( $trackers ) ? $trackers[0] : null;
}
/**
 * Get all compliance data for a tracker
 * 
 * @param int $post_id Tracker post ID
 * @return array Compliance data
 */
function bha_compliance_get_data( $post_id ) {
    
    $post_id = absint( $post_id );
    if ( $post_id < 1 ) {
        return array( 'error' => true, 'message' => 'Invalid post ID' );
    }
    
    $post = get_post( $post_id );
    if ( ! $post || $post->post_type !== 'compliance_tracker' ) {
        return array( 'error' => true, 'message' => 'Invalid compliance tracker' );
    }
    
    $data = array(
        'error'             => false,
        'organization_name' => sanitize_text_field( get_field( 'organization_name', $post_id ) ) ?: 'Unknown',
        'tracking_year'     => absint( get_field( 'tracking_year', $post_id ) ) ?: (int) wp_date( 'Y' ),
        'monthly_due_day'   => absint( get_field( 'monthly_due_day', $post_id ) ) ?: 15,
        'monthly_items'     => array(),
        'quarterly_items'   => array(),
        'annual_items'      => array(),
        'totals'            => array(
            'total'     => 0,
            'completed' => 0,
            'pending'   => 0,
            'overdue'   => 0,
        ),
    );
    
    $today = wp_date( 'Y-m-d' );
    $tracking_year = $data['tracking_year'];
    $monthly_due_day = min( max( $data['monthly_due_day'], 1 ), 28 );
    
    // Monthly items configuration
    $monthly_config = array(
        'emergency_drill'        => 'Emergency Drill',
        'budget_projected'       => 'Budget Projected',
        'budget_actual'          => 'Budget Actual',
        'vehicle_inspection'     => 'Vehicle Inspection',
        'transportation_mileage' => 'Transportation Mileage',
        'staff_meeting'          => 'Staff Meeting',
        'hs_inspection'          => 'H&S Inspection',
        'clinical_supervision'   => 'Clinical Supervision',
        'grievances'             => 'Grievances',
        'incident_reports'       => 'Incident Reports',
        'client_accommodation'   => 'Client Accommodation',
        'staff_accommodation'    => 'Staff Accommodation',
    );
    
    $months = array(
        1 => 'jan', 2 => 'feb', 3 => 'mar', 4 => 'apr',
        5 => 'may', 6 => 'jun', 7 => 'jul', 8 => 'aug',
        9 => 'sep', 10 => 'oct', 11 => 'nov', 12 => 'dec',
    );
    
    $month_names = array(
        1 => 'January', 2 => 'February', 3 => 'March', 4 => 'April',
        5 => 'May', 6 => 'June', 7 => 'July', 8 => 'August',
        9 => 'September', 10 => 'October', 11 => 'November', 12 => 'December',
    );
    
    // Process monthly items
    foreach ( $monthly_config as $item_key => $item_label ) {
        $item_data = array(
            'key'    => $item_key,
            'label'  => $item_label,
            'months' => array(),
        );
        
        foreach ( $months as $month_num => $month_abbr ) {
            $due_date = sprintf( '%d-%02d-%02d', $tracking_year, $month_num, $monthly_due_day );
            $field_key_complete = $item_key . '_' . $month_abbr . '_complete';
            $field_key_date = $item_key . '_' . $month_abbr . '_date';
            
            $is_complete = (bool) get_field( $field_key_complete, $post_id );
            $completed_date = get_field( $field_key_date, $post_id );
            
            if ( $completed_date ) {
                $completed_date = sanitize_text_field( $completed_date );
            }
            
            $status = 'future';
            if ( $is_complete ) {
                $status = 'complete';
                $data['totals']['completed']++;
            } elseif ( $due_date <= $today ) {
                $status = 'overdue';
                $data['totals']['overdue']++;
            } else {
                $status = 'pending';
                $data['totals']['pending']++;
            }
            
            $data['totals']['total']++;
            
            $item_data['months'][ $month_abbr ] = array(
                'month_num'      => $month_num,
                'month_name'     => $month_names[ $month_num ],
                'due_date'       => $due_date,
                'is_complete'    => $is_complete,
                'completed_date' => $completed_date,
                'status'         => $status,
            );
        }
        
        $data['monthly_items'][ $item_key ] = $item_data;
    }
    
    // Quarterly items
    $quarterly_config = array(
        'billing_audit'          => 'Billing Audit',
        'clinical_record_review' => 'Clinical Record Review',
    );
    
    $quarter_due_dates = array(
        1 => sanitize_text_field( get_field( 'q1_due_date', $post_id ) ) ?: sprintf( '%d-03-31', $tracking_year ),
        2 => sanitize_text_field( get_field( 'q2_due_date', $post_id ) ) ?: sprintf( '%d-06-30', $tracking_year ),
        3 => sanitize_text_field( get_field( 'q3_due_date', $post_id ) ) ?: sprintf( '%d-09-30', $tracking_year ),
        4 => sanitize_text_field( get_field( 'q4_due_date', $post_id ) ) ?: sprintf( '%d-12-31', $tracking_year ),
    );
    
    foreach ( $quarterly_config as $item_key => $item_label ) {
        $item_data = array(
            'key'      => $item_key,
            'label'    => $item_label,
            'quarters' => array(),
        );
        
        for ( $q = 1; $q <= 4; $q++ ) {
            $due_date = $quarter_due_dates[ $q ];
            $field_key_complete = $item_key . '_q' . $q . '_complete';
            $field_key_date = $item_key . '_q' . $q . '_date';
            
            $is_complete = (bool) get_field( $field_key_complete, $post_id );
            $completed_date = get_field( $field_key_date, $post_id );
            
            if ( $completed_date ) {
                $completed_date = sanitize_text_field( $completed_date );
            }
            
            $status = 'future';
            if ( $is_complete ) {
                $status = 'complete';
                $data['totals']['completed']++;
            } elseif ( $due_date <= $today ) {
                $status = 'overdue';
                $data['totals']['overdue']++;
            } else {
                $status = 'pending';
                $data['totals']['pending']++;
            }
            
            $data['totals']['total']++;
            
            $item_data['quarters'][ $q ] = array(
                'quarter'        => 'Q' . $q,
                'due_date'       => $due_date,
                'is_complete'    => $is_complete,
                'completed_date' => $completed_date,
                'status'         => $status,
            );
        }
        
        $data['quarterly_items'][ $item_key ] = $item_data;
    }
    
    // Annual items
    $annual_config = array(
        'strategic_meeting'    => 'Strategic Meeting',
        'satisfaction_surveys' => 'Satisfaction Surveys',
    );
    
    $annual_due_date = sanitize_text_field( get_field( 'annual_due_date', $post_id ) ) ?: sprintf( '%d-12-15', $tracking_year );
    
    foreach ( $annual_config as $item_key => $item_label ) {
        $field_key_complete = $item_key . '_complete';
        $field_key_date = $item_key . '_date';
        
        $is_complete = (bool) get_field( $field_key_complete, $post_id );
        $completed_date = get_field( $field_key_date, $post_id );
        
        if ( $completed_date ) {
            $completed_date = sanitize_text_field( $completed_date );
        }
        
        $status = 'future';
        if ( $is_complete ) {
            $status = 'complete';
            $data['totals']['completed']++;
        } elseif ( $annual_due_date <= $today ) {
            $status = 'overdue';
            $data['totals']['overdue']++;
        } else {
            $status = 'pending';
            $data['totals']['pending']++;
        }
        
        $data['totals']['total']++;
        
        $data['annual_items'][ $item_key ] = array(
            'key'            => $item_key,
            'label'          => $item_label,
            'due_date'       => $annual_due_date,
            'is_complete'    => $is_complete,
            'completed_date' => $completed_date,
            'status'         => $status,
        );
    }
    
    // Calculate percentage
    $data['totals']['percentage'] = $data['totals']['total'] > 0 
        ? round( ( $data['totals']['completed'] / $data['totals']['total'] ) * 100, 1 ) 
        : 0;
    
    return $data;
}
/**
 * Get compliance data for a specific month (NEW v1.3)
 * 
 * @param int    $post_id   Compliance tracker post ID
 * @param string $month     Month abbreviation (jan, feb, etc.)
 * @param int    $month_num Month number (1-12)
 * @return array Month compliance data
 */
function bha_compliance_get_month_data( $post_id, $month, $month_num ) {
    
    $post_id = absint( $post_id );
    $tracking_year = absint( get_field( 'tracking_year', $post_id ) ) ?: (int) wp_date( 'Y' );
    $monthly_due_day = absint( get_field( 'monthly_due_day', $post_id ) ) ?: 15;
    
    $today = wp_date( 'Y-m-d' );
    $due_date = sprintf( '%d-%02d-%02d', $tracking_year, $month_num, $monthly_due_day );
    
    $monthly_items = array(
        'emergency_drill'        => 'Emergency Drill',
        'budget_projected'       => 'Budget Projected',
        'budget_actual'          => 'Budget Actual',
        'vehicle_inspection'     => 'Vehicle Inspection',
        'transportation_mileage' => 'Transportation Mileage',
        'staff_meeting'          => 'Staff Meeting',
        'hs_inspection'          => 'H&S Inspection',
        'clinical_supervision'   => 'Clinical Supervision',
        'grievances'             => 'Grievances',
        'incident_reports'       => 'Incident Reports',
        'client_accommodation'   => 'Client Accommodation',
        'staff_accommodation'    => 'Staff Accommodation',
    );
    
    $total = 0;
    $completed = 0;
    $overdue = 0;
    $items = array();
    
    foreach ( $monthly_items as $item_key => $item_label ) {
        $field_complete = $item_key . '_' . $month . '_complete';
        $field_date = $item_key . '_' . $month . '_date';
        $field_entry = $item_key . '_' . $month . '_entry_id';
        
        $is_complete = (bool) get_field( $field_complete, $post_id );
        $completed_date = get_field( $field_date, $post_id );
        $entry_id = get_field( $field_entry, $post_id );
        
        $total++;
        
        $status = 'future';
        if ( $is_complete ) {
            $status = 'complete';
            $completed++;
        } elseif ( $due_date < $today ) {
            $status = 'overdue';
            $overdue++;
        } elseif ( $due_date <= $today ) {
            $status = 'pending';
        }
        
        $items[] = array(
            'key'            => $item_key,
            'label'          => $item_label,
            'status'         => $status,
            'is_complete'    => $is_complete,
            'completed_date' => $completed_date,
            'entry_id'       => $entry_id,
            'frequency'      => 'monthly',
        );
    }
    
    // Add quarterly items for months 3, 6, 9, 12
    $is_quarterly_month = in_array( $month_num, array( 3, 6, 9, 12 ), true );
    $quarter = (int) ceil( $month_num / 3 );
    
    if ( $is_quarterly_month ) {
        $quarterly_items = array(
            'billing_audit'          => 'Billing Audit',
            'clinical_record_review' => 'Clinical Record Review',
        );
        
        $quarter_due_dates = array(
            1 => sprintf( '%d-03-31', $tracking_year ),
            2 => sprintf( '%d-06-30', $tracking_year ),
            3 => sprintf( '%d-09-30', $tracking_year ),
            4 => sprintf( '%d-12-31', $tracking_year ),
        );
        
        $q_due = $quarter_due_dates[ $quarter ];
        
        foreach ( $quarterly_items as $item_key => $item_label ) {
            $field_complete = $item_key . '_q' . $quarter . '_complete';
            $field_date = $item_key . '_q' . $quarter . '_date';
            $field_entry = $item_key . '_q' . $quarter . '_entry_id';
            
            $is_complete = (bool) get_field( $field_complete, $post_id );
            $completed_date = get_field( $field_date, $post_id );
            $entry_id = get_field( $field_entry, $post_id );
            
            $total++;
            
            $status = 'future';
            if ( $is_complete ) {
                $status = 'complete';
                $completed++;
            } elseif ( $q_due < $today ) {
                $status = 'overdue';
                $overdue++;
            } elseif ( $q_due <= $today ) {
                $status = 'pending';
            }
            
            $items[] = array(
                'key'            => $item_key,
                'label'          => $item_label . ' (Q' . $quarter . ')',
                'status'         => $status,
                'is_complete'    => $is_complete,
                'completed_date' => $completed_date,
                'entry_id'       => $entry_id,
                'frequency'      => 'quarterly',
                'quarter'        => $quarter,
            );
        }
    }
    
    // Add annual items for December
    $is_annual_month = ( $month_num === 12 );
    
    if ( $is_annual_month ) {
        $annual_items = array(
            'strategic_meeting'    => 'Strategic Meeting',
            'satisfaction_surveys' => 'Satisfaction Surveys',
        );
        
        $annual_due = sprintf( '%d-12-15', $tracking_year );
        
        foreach ( $annual_items as $item_key => $item_label ) {
            $field_complete = $item_key . '_complete';
            $field_date = $item_key . '_date';
            $field_entry = $item_key . '_entry_id';
            
            $is_complete = (bool) get_field( $field_complete, $post_id );
            $completed_date = get_field( $field_date, $post_id );
            $entry_id = get_field( $field_entry, $post_id );
            
            $total++;
            
            $status = 'future';
            if ( $is_complete ) {
                $status = 'complete';
                $completed++;
            } elseif ( $annual_due < $today ) {
                $status = 'overdue';
                $overdue++;
            } elseif ( $annual_due <= $today ) {
                $status = 'pending';
            }
            
            $items[] = array(
                'key'            => $item_key,
                'label'          => $item_label . ' (Annual)',
                'status'         => $status,
                'is_complete'    => $is_complete,
                'completed_date' => $completed_date,
                'entry_id'       => $entry_id,
                'frequency'      => 'annual',
            );
        }
    }
    
    $percentage = $total > 0 ? round( ( $completed / $total ) * 100 ) : 0;
    
    return array(
        'month'              => $month,
        'month_num'          => $month_num,
        'total'              => $total,
        'completed'          => $completed,
        'overdue'            => $overdue,
        'pending'            => $total - $completed - $overdue,
        'percentage'         => $percentage,
        'due_date'           => $due_date,
        'is_quarterly_month' => $is_quarterly_month,
        'is_annual_month'    => $is_annual_month,
        'quarter'            => $is_quarterly_month ? $quarter : null,
        'items'              => $items,
    );
}
/**
 * Render progress bar HTML
 * 
 * @param array $totals Totals array with percentage
 * @return string HTML
 */
function bha_compliance_render_progress_bar( $totals ) {
    
    $percentage = isset( $totals['percentage'] ) ? floatval( $totals['percentage'] ) : 0;
    $completed = isset( $totals['completed'] ) ? absint( $totals['completed'] ) : 0;
    $total = isset( $totals['total'] ) ? absint( $totals['total'] ) : 0;
    
    $percentage = max( 0, min( 100, $percentage ) );
    
    $bar_class = 'progress-critical';
    if ( $percentage >= 80 ) {
        $bar_class = 'progress-good';
    } elseif ( $percentage >= 50 ) {
        $bar_class = 'progress-warning';
    }
    
    ob_start();
    ?>
    <div class="compliance-progress">
        <div class="progress-header">
            <span class="progress-label">Overall Compliance</span>
            <span class="progress-percentage"><?php echo esc_html( $percentage ); ?>%</span>
        </div>
        <div class="progress-bar-container">
            <div class="progress-bar <?php echo esc_attr( $bar_class ); ?>" style="width: <?php echo esc_attr( $percentage ); ?>%;"></div>
        </div>
        <div class="progress-footer">
            <?php echo esc_html( $completed ); ?> of <?php echo esc_html( $total ); ?> items completed
        </div>
    </div>
    <?php
    return ob_get_clean();
}
/**
 * =============================================================================
 * SHORTCODE 1: Full Dashboard (Table View)
 * [compliance_dashboard group_id="123" year="2025"]
 * =============================================================================
 */
function bha_compliance_dashboard_shortcode( $atts ) {
    
    $atts = shortcode_atts( array(
        'group_id' => '',
        'year'     => '',
    ), $atts, 'compliance_dashboard' );
    
    // Get group_id
    $group_id = ! empty( $atts['group_id'] ) ? absint( $atts['group_id'] ) : bha_compliance_get_user_group_id();
    
    if ( ! $group_id ) {
        return '<div class="compliance-error" style="padding:15px;background:#f8d7da;border:1px solid #f5c6cb;border-radius:4px;color:#721c24;">No organization found. Please contact support.</div>';
    }
    
    // Get year
    $year = ! empty( $atts['year'] ) ? absint( $atts['year'] ) : (int) wp_date( 'Y' );
    if ( $year < 2020 || $year > 2050 ) {
        $year = (int) wp_date( 'Y' );
    }
    
    // Get tracker
    $tracker = bha_compliance_get_tracker( $group_id, $year );
    
    if ( ! $tracker ) {
        return '<div class="compliance-error" style="padding:15px;background:#f8d7da;border:1px solid #f5c6cb;border-radius:4px;color:#721c24;">No compliance tracker found for this organization and year.</div>';
    }
    
    // Get data
    $data = bha_compliance_get_data( $tracker->ID );
    
    if ( isset( $data['error'] ) && $data['error'] ) {
        return '<div class="compliance-error" style="padding:15px;background:#f8d7da;border:1px solid #f5c6cb;border-radius:4px;color:#721c24;">' . esc_html( $data['message'] ) . '</div>';
    }
    
    ob_start();
    ?>
    <div class="compliance-dashboard" data-group-id="<?php echo esc_attr( $group_id ); ?>" data-year="<?php echo esc_attr( $year ); ?>">
        
        <div class="compliance-header">
            <h2 style="margin:0 0 20px 0;font-size:24px;color:#333;"><?php echo esc_html( $data['organization_name'] ); ?> - <?php echo esc_html( $data['tracking_year'] ); ?> Compliance</h2>
        </div>
        
        <?php echo bha_compliance_render_progress_bar( $data['totals'] ); ?>
        
        <div class="compliance-stats" style="display:grid;grid-template-columns:repeat(4,1fr);gap:15px;margin-bottom:30px;">
            <div class="stat-box" style="padding:20px;border-radius:8px;text-align:center;color:#fff;background:#6c757d;">
                <span class="stat-number" style="display:block;font-size:32px;font-weight:700;"><?php echo esc_html( $data['totals']['total'] ); ?></span>
                <span class="stat-label" style="display:block;font-size:14px;opacity:0.9;">Total Items</span>
            </div>
            <div class="stat-box" style="padding:20px;border-radius:8px;text-align:center;color:#fff;background:#28a745;">
                <span class="stat-number" style="display:block;font-size:32px;font-weight:700;"><?php echo esc_html( $data['totals']['completed'] ); ?></span>
                <span class="stat-label" style="display:block;font-size:14px;opacity:0.9;">Completed</span>
            </div>
            <div class="stat-box" style="padding:20px;border-radius:8px;text-align:center;color:#333;background:#ffc107;">
                <span class="stat-number" style="display:block;font-size:32px;font-weight:700;"><?php echo esc_html( $data['totals']['pending'] ); ?></span>
                <span class="stat-label" style="display:block;font-size:14px;opacity:0.9;">Pending</span>
            </div>
            <div class="stat-box" style="padding:20px;border-radius:8px;text-align:center;color:#fff;background:#dc3545;">
                <span class="stat-number" style="display:block;font-size:32px;font-weight:700;"><?php echo esc_html( $data['totals']['overdue'] ); ?></span>
                <span class="stat-label" style="display:block;font-size:14px;opacity:0.9;">Overdue</span>
            </div>
        </div>
        
        <div class="compliance-section" style="margin-bottom:30px;">
            <h3 style="margin:0 0 15px 0;font-size:18px;color:#333;border-bottom:2px solid #007bff;padding-bottom:8px;">Monthly Compliance Items</h3>
            <div style="overflow-x:auto;">
                <table class="compliance-table" style="width:100%;border-collapse:collapse;font-size:14px;">
                    <thead>
                        <tr>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:left;">Item</th>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:center;">Jan</th>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:center;">Feb</th>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:center;">Mar</th>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:center;">Apr</th>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:center;">May</th>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:center;">Jun</th>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:center;">Jul</th>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:center;">Aug</th>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:center;">Sep</th>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:center;">Oct</th>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:center;">Nov</th>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:center;">Dec</th>
                        </tr>
                    </thead>
                    <tbody>
                        <?php foreach ( $data['monthly_items'] as $item ) : ?>
                        <tr>
                            <td style="padding:10px 8px;border:1px solid #dee2e6;text-align:left;font-weight:500;white-space:nowrap;"><?php echo esc_html( $item['label'] ); ?></td>
                            <?php foreach ( $item['months'] as $month ) : 
                                $bg_color = '#f8f9fa';
                                $text_color = '#6c757d';
                                if ( $month['status'] === 'complete' ) {
                                    $bg_color = '#d4edda';
                                    $text_color = '#155724';
                                } elseif ( $month['status'] === 'overdue' ) {
                                    $bg_color = '#f8d7da';
                                    $text_color = '#721c24';
                                } elseif ( $month['status'] === 'pending' ) {
                                    $bg_color = '#fff3cd';
                                    $text_color = '#856404';
                                }
                            ?>
                            <td style="padding:10px 8px;border:1px solid #dee2e6;text-align:center;font-weight:600;background:<?php echo esc_attr( $bg_color ); ?>;color:<?php echo esc_attr( $text_color ); ?>;" title="<?php echo esc_attr( $month['month_name'] . ' - ' . ucfirst( $month['status'] ) ); ?>">
                                <?php echo $month['is_complete'] ? '&#10003;' : '&ndash;'; ?>
                            </td>
                            <?php endforeach; ?>
                        </tr>
                        <?php endforeach; ?>
                    </tbody>
                </table>
            </div>
        </div>
        
        <div class="compliance-section" style="margin-bottom:30px;">
            <h3 style="margin:0 0 15px 0;font-size:18px;color:#333;border-bottom:2px solid #007bff;padding-bottom:8px;">Quarterly Compliance Items</h3>
            <div style="overflow-x:auto;">
                <table class="compliance-table" style="width:100%;border-collapse:collapse;font-size:14px;">
                    <thead>
                        <tr>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:left;">Item</th>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:center;">Q1 (Mar 31)</th>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:center;">Q2 (Jun 30)</th>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:center;">Q3 (Sep 30)</th>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:center;">Q4 (Dec 31)</th>
                        </tr>
                    </thead>
                    <tbody>
                        <?php foreach ( $data['quarterly_items'] as $item ) : ?>
                        <tr>
                            <td style="padding:10px 8px;border:1px solid #dee2e6;text-align:left;font-weight:500;white-space:nowrap;"><?php echo esc_html( $item['label'] ); ?></td>
                            <?php foreach ( $item['quarters'] as $quarter ) : 
                                $bg_color = '#f8f9fa';
                                $text_color = '#6c757d';
                                if ( $quarter['status'] === 'complete' ) {
                                    $bg_color = '#d4edda';
                                    $text_color = '#155724';
                                } elseif ( $quarter['status'] === 'overdue' ) {
                                    $bg_color = '#f8d7da';
                                    $text_color = '#721c24';
                                } elseif ( $quarter['status'] === 'pending' ) {
                                    $bg_color = '#fff3cd';
                                    $text_color = '#856404';
                                }
                            ?>
                            <td style="padding:10px 8px;border:1px solid #dee2e6;text-align:center;font-weight:600;background:<?php echo esc_attr( $bg_color ); ?>;color:<?php echo esc_attr( $text_color ); ?>;" title="<?php echo esc_attr( $quarter['quarter'] . ' - ' . ucfirst( $quarter['status'] ) ); ?>">
                                <?php echo $quarter['is_complete'] ? '&#10003;' : '&ndash;'; ?>
                            </td>
                            <?php endforeach; ?>
                        </tr>
                        <?php endforeach; ?>
                    </tbody>
                </table>
            </div>
        </div>
        
        <div class="compliance-section" style="margin-bottom:30px;">
            <h3 style="margin:0 0 15px 0;font-size:18px;color:#333;border-bottom:2px solid #007bff;padding-bottom:8px;">Annual Compliance Items</h3>
            <div style="overflow-x:auto;">
                <table class="compliance-table" style="width:100%;border-collapse:collapse;font-size:14px;">
                    <thead>
                        <tr>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:left;">Item</th>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:center;">Due Date</th>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:center;">Status</th>
                            <th style="padding:10px 8px;border:1px solid #dee2e6;background:#f8f9fa;font-weight:600;text-align:center;">Completed</th>
                        </tr>
                    </thead>
                    <tbody>
                        <?php foreach ( $data['annual_items'] as $item ) : 
                            $bg_color = '#f8f9fa';
                            $text_color = '#6c757d';
                            if ( $item['status'] === 'complete' ) {
                                $bg_color = '#d4edda';
                                $text_color = '#155724';
                            } elseif ( $item['status'] === 'overdue' ) {
                                $bg_color = '#f8d7da';
                                $text_color = '#721c24';
                            } elseif ( $item['status'] === 'pending' ) {
                                $bg_color = '#fff3cd';
                                $text_color = '#856404';
                            }
                        ?>
                        <tr>
                            <td style="padding:10px 8px;border:1px solid #dee2e6;text-align:left;font-weight:500;"><?php echo esc_html( $item['label'] ); ?></td>
                            <td style="padding:10px 8px;border:1px solid #dee2e6;text-align:center;"><?php echo esc_html( date( 'M j, Y', strtotime( $item['due_date'] ) ) ); ?></td>
                            <td style="padding:10px 8px;border:1px solid #dee2e6;text-align:center;font-weight:600;background:<?php echo esc_attr( $bg_color ); ?>;color:<?php echo esc_attr( $text_color ); ?>;">
                                <?php echo esc_html( ucfirst( $item['status'] ) ); ?>
                            </td>
                            <td style="padding:10px 8px;border:1px solid #dee2e6;text-align:center;">
                                <?php echo $item['completed_date'] ? esc_html( date( 'M j, Y', strtotime( $item['completed_date'] ) ) ) : '&ndash;'; ?>
                            </td>
                        </tr>
                        <?php endforeach; ?>
                    </tbody>
                </table>
            </div>
        </div>
        
    </div>
    
    <style>
    .compliance-dashboard { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; max-width: 100%; margin: 0 auto; }
    .compliance-progress { margin-bottom: 25px; }
    .progress-header { display: flex; justify-content: space-between; margin-bottom: 8px; }
    .progress-label { font-weight: 600; color: #333; }
    .progress-percentage { font-weight: 700; font-size: 18px; }
    .progress-bar-container { height: 24px; background: #e9ecef; border-radius: 12px; overflow: hidden; }
    .progress-bar { height: 100%; border-radius: 12px; transition: width 0.5s ease; }
    .progress-good { background: linear-gradient(90deg, #28a745, #20c997); }
    .progress-warning { background: linear-gradient(90deg, #ffc107, #fd7e14); }
    .progress-critical { background: linear-gradient(90deg, #dc3545, #c82333); }
    .progress-footer { margin-top: 8px; font-size: 14px; color: #666; }
    @media (max-width: 768px) {
        .compliance-stats { grid-template-columns: repeat(2, 1fr) !important; }
        .stat-number { font-size: 24px !important; }
        .compliance-table { font-size: 12px !important; }
    }
    @media (max-width: 480px) {
        .compliance-stats { grid-template-columns: 1fr !important; }
    }
    </style>
    <?php
    return ob_get_clean();
}
add_shortcode( 'compliance_dashboard', 'bha_compliance_dashboard_shortcode' );
/**
 * =============================================================================
 * SHORTCODE 2: Month Cards Dashboard (NEW v1.3)
 * [compliance_month_cards]
 * [compliance_month_cards detail_page="123" group_id="456" year="2025"]
 * =============================================================================
 */
function bha_compliance_month_cards_shortcode( $atts ) {
    
    $atts = shortcode_atts( array(
        'group_id'    => '',
        'year'        => '',
        'detail_page' => '',
    ), $atts, 'compliance_month_cards' );
    
    $group_id = ! empty( $atts['group_id'] ) ? absint( $atts['group_id'] ) : bha_compliance_get_user_group_id();
    
    if ( ! $group_id ) {
        return '<div class="cc-error">Please log in to view your compliance dashboard.</div>';
    }
    
    $year = ! empty( $atts['year'] ) ? absint( $atts['year'] ) : (int) wp_date( 'Y' );
    if ( $year < 2020 || $year > 2050 ) {
        $year = (int) wp_date( 'Y' );
    }
    
    $tracker = bha_compliance_get_tracker( $group_id, $year );
    
    if ( ! $tracker ) {
        return '<div class="cc-error">No compliance tracker found for your organization. Please contact support.</div>';
    }
    
    $org_name = sanitize_text_field( get_field( 'organization_name', $tracker->ID ) ) ?: 'Your Organization';
    $detail_page = ! empty( $atts['detail_page'] ) ? absint( $atts['detail_page'] ) : 0;
    
    $months = array(
        1  => array( 'abbr' => 'jan', 'name' => 'January',   'short' => 'JAN' ),
        2  => array( 'abbr' => 'feb', 'name' => 'February',  'short' => 'FEB' ),
        3  => array( 'abbr' => 'mar', 'name' => 'March',     'short' => 'MAR' ),
        4  => array( 'abbr' => 'apr', 'name' => 'April',     'short' => 'APR' ),
        5  => array( 'abbr' => 'may', 'name' => 'May',       'short' => 'MAY' ),
        6  => array( 'abbr' => 'jun', 'name' => 'June',      'short' => 'JUN' ),
        7  => array( 'abbr' => 'jul', 'name' => 'July',      'short' => 'JUL' ),
        8  => array( 'abbr' => 'aug', 'name' => 'August',    'short' => 'AUG' ),
        9  => array( 'abbr' => 'sep', 'name' => 'September', 'short' => 'SEP' ),
        10 => array( 'abbr' => 'oct', 'name' => 'October',   'short' => 'OCT' ),
        11 => array( 'abbr' => 'nov', 'name' => 'November',  'short' => 'NOV' ),
        12 => array( 'abbr' => 'dec', 'name' => 'December',  'short' => 'DEC' ),
    );
    
    $current_month = (int) wp_date( 'n' );
    
    // Calculate overall progress
    $overall_total = 0;
    $overall_completed = 0;
    foreach ( $months as $m_num => $m_info ) {
        $m_data = bha_compliance_get_month_data( $tracker->ID, $m_info['abbr'], $m_num );
        $overall_total += $m_data['total'];
        $overall_completed += $m_data['completed'];
    }
    $overall_pct = $overall_total > 0 ? round( ( $overall_completed / $overall_total ) * 100 ) : 0;
    
    ob_start();
    ?>
    <div class="cc-month-dashboard">
        
        <div class="cc-dashboard-header">
            <div class="cc-header-content">
                <h2 class="cc-org-title"><?php echo esc_html( $org_name ); ?></h2>
                <p class="cc-year-subtitle"><?php echo esc_html( $year ); ?> CARF Compliance Calendar</p>
            </div>
            <div class="cc-header-badge">
                <div class="cc-overall-progress">
                    <span class="cc-overall-pct"><?php echo esc_html( $overall_pct ); ?>%</span>
                    <span class="cc-overall-label">Overall</span>
                </div>
            </div>
        </div>
        
        <div class="cc-month-grid">
            <?php foreach ( $months as $month_num => $month_info ) :
                $month_data = bha_compliance_get_month_data( $tracker->ID, $month_info['abbr'], $month_num );
                $pct = $month_data['percentage'];
                
                $status_class = 'future';
                if ( $month_num < $current_month ) {
                    $status_class = $pct >= 80 ? 'good' : ( $pct >= 50 ? 'warning' : 'critical' );
                } elseif ( $month_num === $current_month ) {
                    $status_class = 'current';
                }
                
                $detail_link = '';
                if ( $detail_page > 0 ) {
                    $detail_link = add_query_arg( array(
                        'month' => $month_info['abbr'],
                        'year'  => $year,
                    ), get_permalink( $detail_page ) );
                }
                ?>
                <div class="cc-month-card cc-status-<?php echo esc_attr( $status_class ); ?><?php echo $month_data['is_quarterly_month'] ? ' cc-quarterly' : ''; ?><?php echo $month_data['is_annual_month'] ? ' cc-annual' : ''; ?>">
                    
                    <div class="cc-card-badges">
                        <?php if ( $month_data['is_quarterly_month'] ) : ?>
                            <span class="cc-badge cc-badge-quarterly">Q<?php echo esc_html( $month_data['quarter'] ); ?></span>
                        <?php endif; ?>
                        <?php if ( $month_data['is_annual_month'] ) : ?>
                            <span class="cc-badge cc-badge-annual">Annual</span>
                        <?php endif; ?>
                    </div>
                    
                    <div class="cc-month-name"><?php echo esc_html( $month_info['short'] ); ?></div>
                    
                    <div class="cc-progress-ring" data-percentage="<?php echo esc_attr( $pct ); ?>">
                        <svg viewBox="0 0 100 100">
                            <circle class="cc-ring-bg" cx="50" cy="50" r="42"/>
                            <circle class="cc-ring-progress" cx="50" cy="50" r="42" 
                                    style="stroke-dasharray: <?php echo esc_attr( ( $pct / 100 ) * 264 ); ?> 264;"/>
                        </svg>
                        <div class="cc-ring-text"><?php echo esc_html( $pct ); ?>%</div>
                    </div>
                    
                    <div class="cc-month-stats">
                        <span class="cc-stat cc-stat-complete" title="Completed">&#10003; <?php echo esc_html( $month_data['completed'] ); ?></span>
                        <?php if ( $month_data['overdue'] > 0 ) : ?>
                            <span class="cc-stat cc-stat-overdue" title="Overdue">&#9888; <?php echo esc_html( $month_data['overdue'] ); ?></span>
                        <?php endif; ?>
                        <span class="cc-stat cc-stat-total" title="Total Items"><?php echo esc_html( $month_data['total'] ); ?> items</span>
                    </div>
                    
                    <?php if ( $detail_link ) : ?>
                        <a href="<?php echo esc_url( $detail_link ); ?>" class="cc-view-btn">View Details</a>
                    <?php endif; ?>
                    
                </div>
            <?php endforeach; ?>
        </div>
        
        <div class="cc-legend">
            <span class="cc-legend-item"><span class="cc-dot cc-dot-good"></span> On Track (&ge;80%)</span>
            <span class="cc-legend-item"><span class="cc-dot cc-dot-warning"></span> Needs Attention (50-79%)</span>
            <span class="cc-legend-item"><span class="cc-dot cc-dot-critical"></span> Critical (<50%)</span>
            <span class="cc-legend-item"><span class="cc-dot cc-dot-current"></span> Current Month</span>
        </div>
        
    </div>
    <?php
    echo bha_compliance_month_cards_css();
    return ob_get_clean();
}
add_shortcode( 'compliance_month_cards', 'bha_compliance_month_cards_shortcode' );
/**
 * =============================================================================
 * SHORTCODE 3: Month Detail View (NEW v1.3)
 * [compliance_month_detail month="jan"]
 * [compliance_month_detail month="current" group_id="123" year="2025"]
 * =============================================================================
 */
function bha_compliance_month_detail_shortcode( $atts ) {
    
    $atts = shortcode_atts( array(
        'month'     => 'current',
        'group_id'  => '',
        'year'      => '',
        'back_page' => '',
    ), $atts, 'compliance_month_detail' );
    
    $group_id = ! empty( $atts['group_id'] ) ? absint( $atts['group_id'] ) : bha_compliance_get_user_group_id();
    
    if ( ! $group_id ) {
        return '<div class="cc-error">Please log in to view compliance details.</div>';
    }
    
    $year = ! empty( $atts['year'] ) ? absint( $atts['year'] ) : 0;
    if ( ! $year && isset( $_GET['year'] ) ) {
        $year = absint( $_GET['year'] );
    }
    if ( ! $year || $year < 2020 || $year > 2050 ) {
        $year = (int) wp_date( 'Y' );
    }
    
    $month_input = ! empty( $atts['month'] ) ? sanitize_key( $atts['month'] ) : 'current';
    if ( isset( $_GET['month'] ) ) {
        $month_input = sanitize_key( $_GET['month'] );
    }
    
    $month_map = array(
        'jan' => 1, 'feb' => 2, 'mar' => 3, 'apr' => 4,
        'may' => 5, 'jun' => 6, 'jul' => 7, 'aug' => 8,
        'sep' => 9, 'oct' => 10, 'nov' => 11, 'dec' => 12,
    );
    
    $month_names = array(
        1 => 'January', 2 => 'February', 3 => 'March', 4 => 'April',
        5 => 'May', 6 => 'June', 7 => 'July', 8 => 'August',
        9 => 'September', 10 => 'October', 11 => 'November', 12 => 'December',
    );
    
    if ( $month_input === 'current' ) {
        $month_num = (int) wp_date( 'n' );
        $month_abbr = array_search( $month_num, $month_map );
    } elseif ( isset( $month_map[ $month_input ] ) ) {
        $month_abbr = $month_input;
        $month_num = $month_map[ $month_input ];
    } else {
        return '<div class="cc-error">Invalid month specified.</div>';
    }
    
    $tracker = bha_compliance_get_tracker( $group_id, $year );
    
    if ( ! $tracker ) {
        return '<div class="cc-error">No compliance tracker found.</div>';
    }
    
    $org_name = sanitize_text_field( get_field( 'organization_name', $tracker->ID ) ) ?: 'Your Organization';
    $month_data = bha_compliance_get_month_data( $tracker->ID, $month_abbr, $month_num );
    $back_page = ! empty( $atts['back_page'] ) ? absint( $atts['back_page'] ) : 0;
    
    ob_start();
    ?>
    <div class="cc-month-detail">
        
        <div class="cc-detail-header">
            <div class="cc-detail-title">
                <h2><?php echo esc_html( $month_names[ $month_num ] ); ?> <?php echo esc_html( $year ); ?></h2>
                <p class="cc-org-subtitle"><?php echo esc_html( $org_name ); ?></p>
            </div>
            <div class="cc-detail-progress">
                <div class="cc-progress-circle" data-pct="<?php echo esc_attr( $month_data['percentage'] ); ?>">
                    <span class="cc-pct-value"><?php echo esc_html( $month_data['percentage'] ); ?>%</span>
                    <span class="cc-pct-label">Complete</span>
                </div>
            </div>
        </div>
        
        <div class="cc-stats-bar">
            <div class="cc-stat-box cc-stat-completed">
                <span class="cc-stat-num"><?php echo esc_html( $month_data['completed'] ); ?></span>
                <span class="cc-stat-lbl">Completed</span>
            </div>
            <div class="cc-stat-box cc-stat-pending">
                <span class="cc-stat-num"><?php echo esc_html( $month_data['pending'] ); ?></span>
                <span class="cc-stat-lbl">Pending</span>
            </div>
            <div class="cc-stat-box cc-stat-overdue">
                <span class="cc-stat-num"><?php echo esc_html( $month_data['overdue'] ); ?></span>
                <span class="cc-stat-lbl">Overdue</span>
            </div>
            <div class="cc-stat-box cc-stat-total">
                <span class="cc-stat-num"><?php echo esc_html( $month_data['total'] ); ?></span>
                <span class="cc-stat-lbl">Total</span>
            </div>
        </div>
        
        <?php if ( $month_data['is_quarterly_month'] || $month_data['is_annual_month'] ) : ?>
            <div class="cc-special-badges">
                <?php if ( $month_data['is_quarterly_month'] ) : ?>
                    <span class="cc-special-badge cc-special-quarterly">
                        &#11088; Quarterly Items Due (Q<?php echo esc_html( $month_data['quarter'] ); ?>)
                    </span>
                <?php endif; ?>
                <?php if ( $month_data['is_annual_month'] ) : ?>
                    <span class="cc-special-badge cc-special-annual">
                        &#11088; Annual Items Due
                    </span>
                <?php endif; ?>
            </div>
        <?php endif; ?>
        
        <div class="cc-items-grid">
            <?php foreach ( $month_data['items'] as $item ) :
                $status_class = $item['status'];
                $status_icon = '&#9675;';
                $status_text = 'Pending';
                
                if ( $item['status'] === 'complete' ) {
                    $status_icon = '&#10003;';
                    $status_text = 'Complete';
                } elseif ( $item['status'] === 'overdue' ) {
                    $status_icon = '&#9888;';
                    $status_text = 'Overdue';
                } elseif ( $item['status'] === 'future' ) {
                    $status_icon = '&#9675;';
                    $status_text = 'Upcoming';
                }
                ?>
                <div class="cc-item-card cc-item-<?php echo esc_attr( $status_class ); ?>">
                    <div class="cc-item-status">
                        <span class="cc-status-icon"><?php echo $status_icon; ?></span>
                    </div>
                    <div class="cc-item-content">
                        <span class="cc-item-label"><?php echo esc_html( $item['label'] ); ?></span>
                        <?php if ( $item['is_complete'] && $item['completed_date'] ) : ?>
                            <span class="cc-item-date">Completed: <?php echo esc_html( date( 'M j, Y', strtotime( $item['completed_date'] ) ) ); ?></span>
                        <?php elseif ( $item['status'] === 'overdue' ) : ?>
                            <span class="cc-item-date cc-date-overdue">Due date passed</span>
                        <?php endif; ?>
                    </div>
                    <div class="cc-item-actions">
                        <?php if ( $item['is_complete'] && $item['entry_id'] ) : ?>
                            <span class="cc-action-badge cc-badge-done">Done</span>
                        <?php else : ?>
                            <span class="cc-action-badge cc-badge-pending"><?php echo esc_html( $status_text ); ?></span>
                        <?php endif; ?>
                    </div>
                </div>
            <?php endforeach; ?>
        </div>
        
        <?php if ( $back_page > 0 ) : ?>
            <div class="cc-back-section">
                <a href="<?php echo esc_url( get_permalink( $back_page ) ); ?>" class="cc-back-btn">&larr; Back to Calendar</a>
            </div>
        <?php endif; ?>
        
    </div>
    <?php
    echo bha_compliance_month_cards_css();
    return ob_get_clean();
}
add_shortcode( 'compliance_month_detail', 'bha_compliance_month_detail_shortcode' );
/**
 * =============================================================================
 * SHORTCODE 4: Progress Bar Only
 * [compliance_progress_bar group_id="123" year="2025"]
 * =============================================================================
 */
function bha_compliance_progress_bar_shortcode( $atts ) {
    
    $atts = shortcode_atts( array(
        'group_id' => '',
        'year'     => '',
    ), $atts, 'compliance_progress_bar' );
    
    $group_id = ! empty( $atts['group_id'] ) ? absint( $atts['group_id'] ) : bha_compliance_get_user_group_id();
    
    if ( ! $group_id ) {
        return '';
    }
    
    $year = ! empty( $atts['year'] ) ? absint( $atts['year'] ) : (int) wp_date( 'Y' );
    if ( $year < 2020 || $year > 2050 ) {
        $year = (int) wp_date( 'Y' );
    }
    
    $tracker = bha_compliance_get_tracker( $group_id, $year );
    
    if ( ! $tracker ) {
        return '';
    }
    
    $data = bha_compliance_get_data( $tracker->ID );
    
    if ( isset( $data['error'] ) && $data['error'] ) {
        return '';
    }
    
    ob_start();
    echo bha_compliance_render_progress_bar( $data['totals'] );
    ?>
    <style>
    .compliance-progress { margin-bottom: 25px; }
    .progress-header { display: flex; justify-content: space-between; margin-bottom: 8px; }
    .progress-label { font-weight: 600; color: #333; }
    .progress-percentage { font-weight: 700; font-size: 18px; }
    .progress-bar-container { height: 24px; background: #e9ecef; border-radius: 12px; overflow: hidden; }
    .progress-bar { height: 100%; border-radius: 12px; transition: width 0.5s ease; }
    .progress-good { background: linear-gradient(90deg, #28a745, #20c997); }
    .progress-warning { background: linear-gradient(90deg, #ffc107, #fd7e14); }
    .progress-critical { background: linear-gradient(90deg, #dc3545, #c82333); }
    .progress-footer { margin-top: 8px; font-size: 14px; color: #666; }
    </style>
    <?php
    return ob_get_clean();
}
add_shortcode( 'compliance_progress_bar', 'bha_compliance_progress_bar_shortcode' );
/**
 * =============================================================================
 * SHORTCODE 5: Status Badge
 * [compliance_status_badge group_id="123" year="2025"]
 * =============================================================================
 */
function bha_compliance_status_badge_shortcode( $atts ) {
    
    $atts = shortcode_atts( array(
        'group_id' => '',
        'year'     => '',
    ), $atts, 'compliance_status_badge' );
    
    $group_id = ! empty( $atts['group_id'] ) ? absint( $atts['group_id'] ) : bha_compliance_get_user_group_id();
    
    if ( ! $group_id ) {
        return '';
    }
    
    $year = ! empty( $atts['year'] ) ? absint( $atts['year'] ) : (int) wp_date( 'Y' );
    if ( $year < 2020 || $year > 2050 ) {
        $year = (int) wp_date( 'Y' );
    }
    
    $tracker = bha_compliance_get_tracker( $group_id, $year );
    
    if ( ! $tracker ) {
        return '';
    }
    
    $data = bha_compliance_get_data( $tracker->ID );
    
    if ( isset( $data['error'] ) && $data['error'] ) {
        return '';
    }
    
    $percentage = $data['totals']['percentage'];
    
    $bg_color = '#f8d7da';
    $text_color = '#721c24';
    $status_text = 'Critical';
    
    if ( $percentage >= 80 ) {
        $bg_color = '#d4edda';
        $text_color = '#155724';
        $status_text = 'Good';
    } elseif ( $percentage >= 50 ) {
        $bg_color = '#fff3cd';
        $text_color = '#856404';
        $status_text = 'Warning';
    }
    
    return '<span style="display:inline-block;padding:6px 12px;border-radius:20px;font-size:14px;font-weight:600;background:' . esc_attr( $bg_color ) . ';color:' . esc_attr( $text_color ) . ';">' . esc_html( $percentage ) . '% - ' . esc_html( $status_text ) . '</span>';
}
add_shortcode( 'compliance_status_badge', 'bha_compliance_status_badge_shortcode' );
/**
 * =============================================================================
 * SHORTCODE 6: Debug - List all trackers
 * [compliance_debug]
 * =============================================================================
 */
function bha_compliance_debug_shortcode() {
    
    if ( ! current_user_can( 'manage_options' ) ) {
        return '<div style="padding:15px;background:#f8d7da;border:1px solid #f5c6cb;border-radius:4px;color:#721c24;">Admin access required.</div>';
    }
    
    $trackers = get_posts( array(
        'post_type'      => 'compliance_tracker',
        'posts_per_page' => -1,
        'post_status'    => 'any',
    ) );
    
    ob_start();
    ?>
    <div style="background:#e7f3ff;padding:20px;margin:20px 0;border:3px solid #2196F3;border-radius:8px;">
        <h3 style="margin:0 0 15px;color:#1976D2;">Compliance Trackers Debug</h3>
        <p><strong>Total trackers found:</strong> <?php echo count( $trackers ); ?></p>
        
        <?php if ( ! empty( $trackers ) ) : ?>
            <?php foreach ( $trackers as $tracker ) : ?>
                <?php
                $group_id = get_field( 'group_id', $tracker->ID );
                $org_name = get_field( 'organization_name', $tracker->ID );
                $year = get_field( 'tracking_year', $tracker->ID );
                ?>
                <div style="background:#fff;padding:15px;margin:10px 0;border-left:4px solid #4CAF50;border-radius:4px;">
                    <strong style="font-size:16px;color:#2196F3;">Post ID: <?php echo (int) $tracker->ID; ?></strong><br>
                    <strong>Title:</strong> <?php echo esc_html( $tracker->post_title ); ?><br>
                    <strong>Group ID:</strong> <?php echo $group_id ? esc_html( $group_id ) : 'Not set'; ?><br>
                    <strong>Organization:</strong> <?php echo $org_name ? esc_html( $org_name ) : 'Not set'; ?><br>
                    <strong>Year:</strong> <?php echo $year ? esc_html( $year ) : 'Not set'; ?><br>
                    <div style="background:#fff3cd;padding:10px;margin-top:10px;">
                        <strong>Test shortcodes:</strong><br>
                        <code style="background:white;padding:2px 5px;display:block;margin:5px 0;">[compliance_dashboard group_id="<?php echo esc_attr( $group_id ); ?>" year="<?php echo esc_attr( $year ); ?>"]</code>
                        <code style="background:white;padding:2px 5px;display:block;margin:5px 0;">[compliance_month_cards group_id="<?php echo esc_attr( $group_id ); ?>" year="<?php echo esc_attr( $year ); ?>"]</code>
                    </div>
                </div>
            <?php endforeach; ?>
        <?php else : ?>
            <div style="background:#ffebee;padding:15px;border-left:4px solid #f44336;color:#c62828;">
                <strong>No compliance trackers found!</strong>
            </div>
        <?php endif; ?>
    </div>
    <?php
    return ob_get_clean();
}
add_shortcode( 'compliance_debug', 'bha_compliance_debug_shortcode' );
/**
 * =============================================================================
 * CSS FOR MONTH CARDS (NEW v1.3)
 * Next Step Consulting Color Palette
 * =============================================================================
 */
function bha_compliance_month_cards_css() {
    static $css_output = false;
    if ( $css_output ) {
        return '';
    }
    $css_output = true;
    
    ob_start();
    ?>
    <style>
    :root {
        --cc-primary: #8B5A2B;
        --cc-accent: #F5844C;
        --cc-teal: #2A9D8F;
        --cc-dark: #264653;
        --cc-good: #2A9D8F;
        --cc-warning: #F4A261;
        --cc-critical: #E76F51;
        --cc-future: #94A3B8;
        --cc-current: #3B82F6;
        --cc-white: #FFFFFF;
        --cc-bg: #F8FAFC;
        --cc-border: #E2E8F0;
        --cc-text: #1E293B;
        --cc-text-muted: #64748B;
    }
    
    .cc-month-dashboard, .cc-month-detail { font-family: 'Poppins', 'Segoe UI', -apple-system, sans-serif; max-width: 1400px; margin: 0 auto; padding: 20px; }
    .cc-error { background: #FEF2F2; border: 1px solid #FECACA; color: #991B1B; padding: 20px; border-radius: 12px; text-align: center; }
    
    /* Dashboard Header */
    .cc-dashboard-header, .cc-detail-header { background: linear-gradient(135deg, var(--cc-primary) 0%, var(--cc-dark) 100%); border-radius: 20px; padding: 40px; margin-bottom: 40px; display: flex; justify-content: space-between; align-items: center; color: var(--cc-white); }
    .cc-org-title { font-size: 32px; font-weight: 700; margin: 0 0 8px 0; }
    .cc-year-subtitle, .cc-org-subtitle { font-size: 18px; opacity: 0.9; margin: 0; }
    .cc-overall-progress, .cc-progress-circle { background: rgba(255,255,255,0.15); border-radius: 16px; padding: 20px 30px; text-align: center; border: 1px solid rgba(255,255,255,0.2); }
    .cc-overall-pct, .cc-pct-value { display: block; font-size: 42px; font-weight: 700; line-height: 1; }
    .cc-overall-label, .cc-pct-label { font-size: 14px; opacity: 0.8; text-transform: uppercase; }
    
    /* Month Grid */
    .cc-month-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 24px; margin-bottom: 40px; }
    .cc-month-card { background: var(--cc-white); border-radius: 16px; padding: 24px; text-align: center; box-shadow: 0 4px 15px rgba(0,0,0,0.08); transition: all 0.3s ease; position: relative; overflow: hidden; border: 2px solid transparent; }
    .cc-month-card::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 5px; background: var(--cc-border); }
    .cc-month-card:hover { transform: translateY(-8px); box-shadow: 0 10px 40px rgba(0,0,0,0.12); }
    
    .cc-month-card.cc-status-good::before { background: linear-gradient(90deg, var(--cc-good), #52C7B8); }
    .cc-month-card.cc-status-warning::before { background: linear-gradient(90deg, var(--cc-warning), #FCD34D); }
    .cc-month-card.cc-status-critical::before { background: linear-gradient(90deg, var(--cc-critical), #F87171); }
    .cc-month-card.cc-status-current::before { background: linear-gradient(90deg, var(--cc-current), #60A5FA); }
    .cc-month-card.cc-status-current { border-color: var(--cc-current); }
    .cc-month-card.cc-quarterly, .cc-month-card.cc-annual { background: linear-gradient(180deg, var(--cc-white) 0%, #FFFBEB 100%); }
    
    .cc-card-badges { position: absolute; top: 12px; right: 12px; display: flex; gap: 6px; }
    .cc-badge { font-size: 10px; font-weight: 700; padding: 4px 8px; border-radius: 6px; text-transform: uppercase; }
    .cc-badge-quarterly { background: linear-gradient(135deg, var(--cc-accent), var(--cc-warning)); color: var(--cc-white); }
    .cc-badge-annual { background: linear-gradient(135deg, var(--cc-primary), var(--cc-dark)); color: var(--cc-white); }
    
    .cc-month-name { font-size: 20px; font-weight: 700; color: var(--cc-dark); margin-bottom: 16px; }
    
    .cc-progress-ring { width: 100px; height: 100px; margin: 0 auto 16px; position: relative; }
    .cc-progress-ring svg { transform: rotate(-90deg); width: 100%; height: 100%; }
    .cc-ring-bg { fill: none; stroke: var(--cc-border); stroke-width: 8; }
    .cc-ring-progress { fill: none; stroke: var(--cc-teal); stroke-width: 8; stroke-linecap: round; transition: stroke-dasharray 0.6s ease; }
    .cc-status-warning .cc-ring-progress { stroke: var(--cc-warning); }
    .cc-status-critical .cc-ring-progress { stroke: var(--cc-critical); }
    .cc-status-current .cc-ring-progress { stroke: var(--cc-current); }
    .cc-status-future .cc-ring-progress { stroke: var(--cc-future); }
    .cc-ring-text { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 22px; font-weight: 700; color: var(--cc-dark); }
    
    .cc-month-stats { display: flex; justify-content: center; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; }
    .cc-stat { font-size: 12px; color: var(--cc-text-muted); }
    .cc-stat-complete { color: var(--cc-good); }
    .cc-stat-overdue { color: var(--cc-critical); font-weight: 600; }
    
    .cc-view-btn { display: inline-block; padding: 10px 24px; background: linear-gradient(135deg, var(--cc-accent), #F9A66C); color: var(--cc-white) !important; text-decoration: none !important; border-radius: 10px; font-weight: 600; font-size: 14px; transition: all 0.3s ease; }
    .cc-view-btn:hover { transform: scale(1.05); box-shadow: 0 6px 20px rgba(245,132,76,0.4); }
    
    .cc-legend { display: flex; justify-content: center; gap: 24px; flex-wrap: wrap; padding: 20px; background: var(--cc-bg); border-radius: 12px; }
    .cc-legend-item { display: flex; align-items: center; gap: 8px; font-size: 14px; color: var(--cc-text-muted); }
    .cc-dot { width: 12px; height: 12px; border-radius: 50%; }
    .cc-dot-good { background: var(--cc-good); }
    .cc-dot-warning { background: var(--cc-warning); }
    .cc-dot-critical { background: var(--cc-critical); }
    .cc-dot-current { background: var(--cc-current); }
    
    /* Month Detail */
    .cc-detail-header { margin-bottom: 30px; }
    .cc-detail-title h2 { font-size: 36px; font-weight: 700; margin: 0 0 8px 0; }
    .cc-progress-circle { width: 120px; height: 120px; border-radius: 50%; display: flex; flex-direction: column; justify-content: center; align-items: center; border: 4px solid rgba(255,255,255,0.3); }
    
    .cc-stats-bar { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; margin-bottom: 30px; }
    .cc-stat-box { background: var(--cc-white); border-radius: 12px; padding: 24px; text-align: center; box-shadow: 0 1px 2px rgba(0,0,0,0.05); border-left: 4px solid var(--cc-border); }
    .cc-stat-box.cc-stat-completed { border-color: var(--cc-good); }
    .cc-stat-box.cc-stat-pending { border-color: var(--cc-warning); }
    .cc-stat-box.cc-stat-overdue { border-color: var(--cc-critical); }
    .cc-stat-box.cc-stat-total { border-color: var(--cc-dark); }
    .cc-stat-num { display: block; font-size: 32px; font-weight: 700; color: var(--cc-dark); line-height: 1; margin-bottom: 4px; }
    .cc-stat-completed .cc-stat-num { color: var(--cc-good); }
    .cc-stat-overdue .cc-stat-num { color: var(--cc-critical); }
    .cc-stat-lbl { font-size: 13px; color: var(--cc-text-muted); text-transform: uppercase; }
    
    .cc-special-badges { display: flex; gap: 16px; margin-bottom: 30px; flex-wrap: wrap; }
    .cc-special-badge { display: inline-flex; align-items: center; gap: 8px; padding: 12px 20px; border-radius: 10px; font-weight: 600; font-size: 14px; }
    .cc-special-quarterly { background: linear-gradient(135deg, #FEF3C7, #FDE68A); color: #92400E; border: 1px solid #FCD34D; }
    .cc-special-annual { background: linear-gradient(135deg, #F3E8FF, #E9D5FF); color: #6B21A8; border: 1px solid #C4B5FD; }
    
    .cc-items-grid { display: flex; flex-direction: column; gap: 12px; margin-bottom: 40px; }
    .cc-item-card { background: var(--cc-white); border-radius: 12px; padding: 20px 24px; display: flex; align-items: center; gap: 20px; box-shadow: 0 1px 2px rgba(0,0,0,0.05); border-left: 4px solid var(--cc-border); transition: all 0.3s ease; }
    .cc-item-card:hover { box-shadow: 0 4px 15px rgba(0,0,0,0.08); transform: translateX(4px); }
    .cc-item-complete { border-color: var(--cc-good); background: linear-gradient(90deg, #F0FDF4 0%, var(--cc-white) 20%); }
    .cc-item-pending { border-color: var(--cc-warning); }
    .cc-item-overdue { border-color: var(--cc-critical); background: linear-gradient(90deg, #FEF2F2 0%, var(--cc-white) 20%); }
    .cc-item-future { border-color: var(--cc-future); opacity: 0.7; }
    
    .cc-item-status { width: 40px; height: 40px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 20px; flex-shrink: 0; }
    .cc-item-complete .cc-item-status { background: var(--cc-good); color: var(--cc-white); }
    .cc-item-pending .cc-item-status { background: #FEF3C7; color: var(--cc-warning); }
    .cc-item-overdue .cc-item-status { background: #FEE2E2; color: var(--cc-critical); }
    .cc-item-future .cc-item-status { background: var(--cc-bg); color: var(--cc-future); }
    
    .cc-item-content { flex: 1; min-width: 0; }
    .cc-item-label { display: block; font-weight: 600; color: var(--cc-dark); font-size: 15px; }
    .cc-item-date { font-size: 13px; color: var(--cc-text-muted); }
    .cc-date-overdue { color: var(--cc-critical); font-weight: 500; }
    
    .cc-item-actions { flex-shrink: 0; }
    .cc-action-badge { display: inline-block; padding: 8px 16px; border-radius: 8px; font-size: 12px; font-weight: 600; text-transform: uppercase; }
    .cc-badge-done { background: #D1FAE5; color: #065F46; }
    .cc-badge-pending { background: #FEF3C7; color: #92400E; }
    
    .cc-back-section { text-align: center; padding-top: 20px; border-top: 1px solid var(--cc-border); }
    .cc-back-btn { display: inline-flex; align-items: center; gap: 8px; padding: 14px 28px; background: var(--cc-dark); color: var(--cc-white) !important; text-decoration: none !important; border-radius: 10px; font-weight: 600; transition: all 0.3s ease; }
    .cc-back-btn:hover { background: var(--cc-primary); transform: translateX(-4px); }
    
    @media (max-width: 768px) {
        .cc-dashboard-header, .cc-detail-header { flex-direction: column; text-align: center; gap: 24px; padding: 30px 20px; }
        .cc-org-title { font-size: 26px; }
        .cc-month-grid { grid-template-columns: repeat(3, 1fr); gap: 16px; }
        .cc-month-card { padding: 16px; }
        .cc-progress-ring { width: 80px; height: 80px; }
        .cc-ring-text { font-size: 18px; }
        .cc-stats-bar { grid-template-columns: repeat(2, 1fr); }
        .cc-item-card { flex-wrap: wrap; }
    }
    @media (max-width: 480px) {
        .cc-month-grid { grid-template-columns: repeat(2, 1fr); }
        .cc-stats-bar { grid-template-columns: 1fr; }
    }
    </style>
    <?php
    return ob_get_clean();
}

Comments

Add a Comment