fix: resolve dashboard fatal errors and event edit security check failures

Fixes three critical production issues discovered on upskillhvac.com:

 Dashboard Fatal Errors (class-hvac-dashboard-data.php):
- Added class_exists('Tribe__Events__Main') checks before accessing TEC constants
- Prevents fatal errors when TEC plugin loads after our code
- Applied to get_total_events_count(), get_upcoming_events_count(), and get_past_events_count()
- Gracefully returns 0 when TEC is not available

 Event Edit Security Check Failure (page-edit-event-custom.php):
- Fixed nonce action mismatch: changed 'hvac_edit_event' to 'hvac_event_action'
- Aligns with HVAC_Event_Manager::NONCE_ACTION constant
- Resolves "Security check failed" error on event update forms

 Google Drive Folder Update:
- Updated embedded folder ID from 16uDRkFcaEqKUxfBek9VbfbAIeFV77nZG to 1-SDHGR9Ix6BmUVTHa3wI99K0rwfWL-vs
- Applied to templates/page-trainer-resources.php (trainer resources page)
- Applied to includes/class-hvac-announcements-display.php (shortcode default)
- Updated tests/unit/test-announcements-display.php (test references)

All changes tested and verified on production.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
ben 2025-10-29 16:37:59 -03:00
parent 5ab180b5d0
commit 80f11e71dd
5 changed files with 44 additions and 29 deletions

View file

@ -251,7 +251,7 @@ class HVAC_Announcements_Display {
}
$atts = shortcode_atts(array(
'url' => 'https://drive.google.com/drive/folders/16uDRkFcaEqKUxfBek9VbfbAIeFV77nZG?usp=drive_link',
'url' => 'https://drive.google.com/drive/folders/1-SDHGR9Ix6BmUVTHa3wI99K0rwfWL-vs?usp=drive_link',
'height' => '600',
'width' => '100%',
), $atts);

View file

@ -43,18 +43,23 @@ class HVAC_Dashboard_Data {
*/
public function get_total_events_count() {
global $wpdb;
try {
// Check if TEC is available
if ( ! class_exists( 'Tribe__Events__Main' ) ) {
return 0;
}
// Cache key based on user ID
$cache_key = 'hvac_dashboard_total_events_' . $this->user_id;
$count = wp_cache_get( $cache_key, 'hvac_dashboard' );
if ( false === $count ) {
// Use direct database query to avoid TEC query hijacking
$count = $wpdb->get_var( $wpdb->prepare(
"SELECT COUNT(*) FROM {$wpdb->posts}
WHERE post_type = %s
AND post_author = %d
"SELECT COUNT(*) FROM {$wpdb->posts}
WHERE post_type = %s
AND post_author = %d
AND post_status IN ('publish', 'future', 'draft', 'pending', 'private')",
Tribe__Events__Main::POSTTYPE,
$this->user_id
@ -84,20 +89,25 @@ class HVAC_Dashboard_Data {
*/
public function get_upcoming_events_count() {
global $wpdb;
// Check if TEC is available
if ( ! class_exists( 'Tribe__Events__Main' ) ) {
return 0;
}
// Cache key based on user ID
$cache_key = 'hvac_dashboard_upcoming_events_' . $this->user_id;
$count = wp_cache_get( $cache_key, 'hvac_dashboard' );
if ( false === $count ) {
$today = date( 'Y-m-d H:i:s' );
// Use direct database query to avoid TEC query hijacking
$count = $wpdb->get_var( $wpdb->prepare(
"SELECT COUNT(*) FROM {$wpdb->posts} p
LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND pm.meta_key = '_EventStartDate'
WHERE p.post_type = %s
AND p.post_author = %d
WHERE p.post_type = %s
AND p.post_author = %d
AND p.post_status IN ('publish', 'future')
AND (pm.meta_value >= %s OR pm.meta_value IS NULL)",
Tribe__Events__Main::POSTTYPE,
@ -119,20 +129,25 @@ class HVAC_Dashboard_Data {
*/
public function get_past_events_count() {
global $wpdb;
// Check if TEC is available
if ( ! class_exists( 'Tribe__Events__Main' ) ) {
return 0;
}
// Cache key based on user ID
$cache_key = 'hvac_dashboard_past_events_' . $this->user_id;
$count = wp_cache_get( $cache_key, 'hvac_dashboard' );
if ( false === $count ) {
$today = date( 'Y-m-d H:i:s' );
// Use direct database query to avoid TEC query hijacking
$count = $wpdb->get_var( $wpdb->prepare(
"SELECT COUNT(*) FROM {$wpdb->posts} p
LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND pm.meta_key = '_EventEndDate'
WHERE p.post_type = %s
AND p.post_author = %d
WHERE p.post_type = %s
AND p.post_author = %d
AND p.post_status IN ('publish', 'private')
AND pm.meta_value < %s",
Tribe__Events__Main::POSTTYPE,

View file

@ -113,7 +113,7 @@ get_header();
<?php endif; ?>
<form method="post" action="" class="hvac-event-form" novalidate>
<?php wp_nonce_field('hvac_edit_event', 'hvac_event_nonce'); ?>
<?php wp_nonce_field('hvac_event_action', 'hvac_event_nonce'); ?>
<input type="hidden" name="event_id" value="<?php echo esc_attr($event_id); ?>">
<!-- Basic Information -->

View file

@ -172,8 +172,8 @@ $menu_system = HVAC_Menu_System::get_instance();
<div class="google-drive-container">
<?php
// Google Drive embed with proper URL format
$drive_url = 'https://drive.google.com/drive/folders/16uDRkFcaEqKUxfBek9VbfbAIeFV77nZG?usp=drive_link';
$folder_id = '16uDRkFcaEqKUxfBek9VbfbAIeFV77nZG';
$drive_url = 'https://drive.google.com/drive/folders/1-SDHGR9Ix6BmUVTHa3wI99K0rwfWL-vs?usp=drive_link';
$folder_id = '1-SDHGR9Ix6BmUVTHa3wI99K0rwfWL-vs';
// Use the modern embed format that works better
$embed_url = 'https://drive.google.com/embeddedfolderview?id=' . $folder_id;

View file

@ -160,13 +160,13 @@ class Test_HVAC_Announcements_Display extends WP_UnitTestCase {
*/
public function test_google_drive_shortcode() {
wp_set_current_user( $this->regular_trainer );
$output = do_shortcode( '[hvac_google_drive_embed url="https://drive.google.com/drive/folders/16uDRkFcaEqKUxfBek9VbfbAIeFV77nZG" height="500"]' );
$output = do_shortcode( '[hvac_google_drive_embed url="https://drive.google.com/drive/folders/1-SDHGR9Ix6BmUVTHa3wI99K0rwfWL-vs" height="500"]' );
// Should contain iframe
$this->assertStringContainsString( '<iframe', $output );
$this->assertStringContainsString( 'height="500"', $output );
// Should contain embed URL
$this->assertStringContainsString( 'embeddedfolderview', $output );
}
@ -178,17 +178,17 @@ class Test_HVAC_Announcements_Display extends WP_UnitTestCase {
$reflection = new ReflectionClass( $this->display_handler );
$method = $reflection->getMethod( 'convert_drive_url_to_embed' );
$method->setAccessible( true );
// Test folder URL conversion
$sharing_url = 'https://drive.google.com/drive/folders/16uDRkFcaEqKUxfBek9VbfbAIeFV77nZG?usp=drive_link';
$sharing_url = 'https://drive.google.com/drive/folders/1-SDHGR9Ix6BmUVTHa3wI99K0rwfWL-vs?usp=drive_link';
$embed_url = $method->invoke( $this->display_handler, $sharing_url );
$this->assertEquals( 'https://drive.google.com/embeddedfolderview?id=16uDRkFcaEqKUxfBek9VbfbAIeFV77nZG#list', $embed_url );
$this->assertEquals( 'https://drive.google.com/embeddedfolderview?id=1-SDHGR9Ix6BmUVTHa3wI99K0rwfWL-vs#list', $embed_url );
// Test invalid URL returns original
$invalid_url = 'https://example.com/not-a-drive-url';
$result = $method->invoke( $this->display_handler, $invalid_url );
$this->assertEquals( $invalid_url, $result );
}