From 75a097a018a0090f5902758353c578fce4aa2a25 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Sat, 23 May 2026 18:43:42 +0000
Subject: [PATCH] =CustomBlocks.php overhaul relatively complete. Also refactored the gallery in gallery.min.js and the jvbRenderGallery.

---
 inc/managers/ErrorHandler.php |  331 ++++++++++++++++++++++++++-----------------------------
 1 files changed, 156 insertions(+), 175 deletions(-)

diff --git a/inc/managers/ErrorHandler.php b/inc/managers/ErrorHandler.php
index 166229e..9aefef1 100644
--- a/inc/managers/ErrorHandler.php
+++ b/inc/managers/ErrorHandler.php
@@ -12,8 +12,6 @@
 
 class ErrorHandler
 {
-    protected object $wpdb;
-	protected string $tableName;
     protected int $notification_threshold = 5; // Critical errors within 1 hour
 
     protected array $error_levels = [
@@ -24,11 +22,14 @@
         'critical' => 4
     ];
 
+	protected CustomTable $table;
+
     public function __construct()
     {
-        global $wpdb;
-        $this->wpdb = $wpdb;
-		$this->tableName = $wpdb->prefix . BASE . 'error_log';
+		$this->defineTables();
+//        global $wpdb;
+//        $this->wpdb = $wpdb;
+//		$this->tableName = $wpdb->prefix . BASE . 'error_log';
 
         add_filter(BASE.'handle_bulk_operation', [$this, 'processOperation'], 10, 3);
 
@@ -39,6 +40,35 @@
 //        add_filter(BASE.'admin_action_filter', [$this, 'adminActionFilter'], 10, 3);
     }
 
+	public function defineTables():void
+	{
+		$table = CustomTable::for('error_log');
+		$table->setColumns([
+			'id'			=> 'bigint(20) unsigned NOT NULL AUTO_INCREMENT',
+			'error_type'	=> 'varchar(50) NOT NULL',
+			'component'		=> 'varchar(100) NOT NULL',
+			'method'		=> 'varchar(100) DEFAULT NULL',
+			'page_url'		=> 'varchar(255) DEFAULT NULL',
+			'message'		=> 'text NOT NULL',
+			'context'		=> 'JSON',
+			'severity'		=> 'ENUM(\'high\',\'normal\',\'low\') DEFAULT \'normal\'',
+			'user_id'		=> $table->getUserIDType().' DEFAULT NULL',
+			'user_was_logged_in'	=> 'tinyint(1) NOT NULL',
+			'source'		=> 'ENUM(\'frontend\', \'backend\') NOT NULL',
+			'created_at'	=> 'timestamp DEFAULT CURRENT_TIMESTAMP',
+		]);
+
+		$table->setKeys([
+			['key' => 'PRIMARY', 'value' => 'id'],
+			'`created_at` (`created_at`)',
+			'`component_severity_date` (`component`, `severity`, `created_at`)',
+			'`error_type_date` (`error_type`, `created_at`)',
+			'`severity_date` (`severity`, `created_at`)'
+		]);
+
+		$table->defineTable();
+		$this->table = $table;
+	}
     public function registerAdminAction():void
     {
         $admin = JVB()->admin();
@@ -68,7 +98,7 @@
         }
 
         try {
-            $table = $this->tableName;
+
             // Extract error data
             $component = sanitize_text_field($data['component'] ?? '');
             $message = sanitize_textarea_field($data['message'] ?? '');
@@ -94,8 +124,7 @@
             }
 
             // Insert into database
-            $result = $this->wpdb->insert(
-                $table,
+            $result = $this->table->insert(
                 [
                     'error_type' => $error_type,
                     'component' => $component,
@@ -104,24 +133,15 @@
                     'severity' => $severity,
                     'user_id' => get_current_user_id(),
                     'created_at' => current_time('mysql')
-                ],
-                [
-                    '%s', // error_type
-                    '%s', // component
-                    '%s', // message
-                    '%s', // context (JSON)
-                    '%s', // severity
-                    '%d', // user_id
-                    '%s'  // created_at
                 ]
             );
 
-            if ($result === false) {
+            if (!$result) {
                 // If insert fails, log to PHP error log as fallback
-                error_log("[ErrorHandler] Database insert failed: " . $this->wpdb->last_error);
+                error_log("[ErrorHandler] Database insert failed: " . $$this->table->getLastError());
                 return [
 					'success'	=> false,
-					'message'	=> "[ErrorHandler] Database insert failed: " . $this->wpdb->last_error
+					'message'	=> "[ErrorHandler] Database insert failed: " . $$this->table->getLastError()
 				];
             }
 
@@ -155,19 +175,15 @@
     protected function checkErrorThreshold(string $error_type, string $component)
     {
         // Get count of similar critical errors in the last hour
-        $count = $this->wpdb->get_var($this->wpdb->prepare(
-            "SELECT COUNT(*)
-         FROM {$this->tableName}
-         WHERE error_type = %s
-         AND component = %s
-         AND severity = 'critical'
-         AND created_at > DATE_SUB(NOW(), INTERVAL 1 HOUR)",
-            $error_type,
-            $component
-        ));
+		$count = $this->table->count([
+			'error_type' => $error_type,
+			'component' => $component,
+			'severity' => $this->error_levels[$error_type],
+			'created_at' => ['>','DATE_SUB(NOW(), INTERVAL 1 HOUR)']
+		]);
 
         // If threshold reached, take additional actions (e.g., notify developers)
-        if ((int)$count >= $this->notification_threshold) {
+        if ($count >= $this->notification_threshold) {
             // You could send an urgent notification, Slack message, etc.
             $admin_email = get_option('admin_email');
             $subject = "[URGENT] Error Threshold Exceeded for {$component}";
@@ -189,8 +205,6 @@
 	public function log(string $component, string $message, array $context = [], string $severity = 'error'): array
 	{
 		try {
-			$table = $this->wpdb->prefix . BASE . 'error_log';
-
 			// Validate severity
 			if (!array_key_exists($severity, $this->error_levels)) {
 				$severity = 'error';
@@ -207,8 +221,7 @@
 			$source = isset($context['source']) ? $context['source'] :
 				(isset($context['url']) ? 'frontend' : 'backend');
 
-			$result = $this->wpdb->insert(
-				$table,
+			$result = $this->table->insert(
 				[
 					'error_type' => $error_type,
 					'component' => $component,
@@ -221,20 +234,18 @@
 					'user_was_logged_in' => $user_was_logged_in ? 1 : 0,
 					'source' => $source,
 					'created_at' => current_time('mysql')
-				],
-				['%s', '%s', '%s', '%s', '%s', '%s', '%s', '%d', '%d', '%s', '%s']
-			);
+				]);
 
-			if ($result === false) {
-				error_log("[ErrorHandler] Database insert failed: " . $this->wpdb->last_error);
-				return ['success' => false, 'message' => $this->wpdb->last_error];
+			if (!$result) {
+				error_log("[ErrorHandler] Database insert failed: " . $this->table->getLastError());
+				return ['success' => false, 'message' => $this->table->getLastError()];
 			}
 
 			if ($severity === 'critical') {
 				$this->checkErrorThreshold($error_type, $component);
 			}
 
-			return ['success' => true, 'id' => $this->wpdb->insert_id];
+			return ['success' => true, 'id' => $result];
 
 		} catch (Exception $e) {
 			error_log("[ErrorHandler Exception] " . $e->getMessage());
@@ -249,14 +260,31 @@
      *
      * @return bool Whether the notification is sent successfully
      */
-    protected function notifyAdmin(string $component, string $message, array $context):bool
-    {
-        $admin_email = get_option('admin_email');
-        $subject = "[edmonton.ink Critical Error] {$component}";
-        $body = "Error: {$message}\n\nContext: " . print_r($context, true);
+	protected function notifyAdmin(string $component, string $message, array $context):bool
+	{
+		$admin_email = get_option('admin_email');
+		$subject = "[" . get_bloginfo('name') . " Critical Error] {$component}";
 
-        return JVB()->email()->sendEmail($admin_email, $subject, $body);
-    }
+		$body = JVB()->email()->alert(
+			'A critical error has occurred and requires immediate attention',
+			'error'
+		);
+
+		$body .= JVB()->email()->h2('Error Details');
+		$body .= JVB()->email()->card(
+			'<p><strong>Component:</strong> ' . esc_html($component) . '</p>' .
+			'<p><strong>Message:</strong></p>' .
+			JVB()->email()->codeBlock($message),
+			'Error Information'
+		);
+
+		if (!empty($context)) {
+			$body .= JVB()->email()->h3('Additional Context');
+			$body .= JVB()->email()->codeBlock(json_encode($context, JSON_PRETTY_PRINT));
+		}
+
+		return JVB()->email()->sendEmail($admin_email, $subject, $body, 'CRITICAL ERROR');
+	}
 
     /**
      * Gather summary of the most important errors
@@ -266,8 +294,6 @@
      */
 	public function gatherErrorSummary(?string $start_date = null, ?string $end_date = null): array
 	{
-		$table = $this->wpdb->prefix . BASE . 'error_log';
-
 		if (!$start_date) {
 			$start_date = gmdate('Y-m-d 00:00:00', strtotime('-1 day'));
 		}
@@ -276,72 +302,14 @@
 		}
 
 		// Most frequent error patterns (deduplicated by component/method/message)
-		$frequent = $this->wpdb->get_results($this->wpdb->prepare(
-			"SELECT
-            component,
-            method,
-            error_type,
-            message,
-            severity,
-            source,
-            COUNT(*) as count,
-            SUM(CASE WHEN user_was_logged_in = 1 THEN 1 ELSE 0 END) as logged_in_count,
-            SUM(CASE WHEN user_was_logged_in = 0 THEN 1 ELSE 0 END) as logged_out_count,
-            MIN(created_at) as first_seen,
-            MAX(created_at) as last_seen
-         FROM {$table}
-         WHERE created_at BETWEEN %s AND %s
-         GROUP BY component, method, error_type, message, severity, source
-         ORDER BY count DESC, severity DESC
-         LIMIT 10",
-			$start_date,
-			$end_date
-		));
-
-		// Critical errors
-		$critical = $this->wpdb->get_results($this->wpdb->prepare(
-			"SELECT
-            component,
-            method,
-            error_type,
-            message,
-            source,
-            COUNT(*) as count,
-            SUM(CASE WHEN user_was_logged_in = 1 THEN 1 ELSE 0 END) as logged_in_count,
-            SUM(CASE WHEN user_was_logged_in = 0 THEN 1 ELSE 0 END) as logged_out_count,
-            MIN(created_at) as first_seen,
-            MAX(created_at) as last_seen
-         FROM {$table}
-         WHERE created_at BETWEEN %s AND %s AND severity = 'critical'
-         GROUP BY component, method, error_type, message, source
-         ORDER BY count DESC
-         LIMIT 5",
-			$start_date,
-			$end_date
-		));
-
-		// Overall stats
-		$stats = $this->wpdb->get_row($this->wpdb->prepare(
-			"SELECT
-            COUNT(*) as total_errors,
-            COUNT(DISTINCT CONCAT(component, '-', COALESCE(method, ''), '-', error_type)) as unique_error_types,
-            SUM(CASE WHEN user_was_logged_in = 1 THEN 1 ELSE 0 END) as logged_in_errors,
-            SUM(CASE WHEN user_was_logged_in = 0 THEN 1 ELSE 0 END) as logged_out_errors,
-            SUM(CASE WHEN source = 'frontend' THEN 1 ELSE 0 END) as frontend_errors,
-            SUM(CASE WHEN source = 'backend' THEN 1 ELSE 0 END) as backend_errors,
-            SUM(CASE WHEN severity = 'critical' THEN 1 ELSE 0 END) as critical_count,
-            SUM(CASE WHEN severity = 'error' THEN 1 ELSE 0 END) as error_count,
-            SUM(CASE WHEN severity = 'warning' THEN 1 ELSE 0 END) as warning_count
-         FROM {$table}
-         WHERE created_at BETWEEN %s AND %s",
-			$start_date,
-			$end_date
-		));
+		$frequent = $this->table->getMany([
+			'where' => [
+				'created_at'	=> ['BETWEEN', "{$start_date} AND {$end_date}"]
+			]
+		]);
 
 		return [
-			'frequent' => $frequent,
-			'critical' => $critical,
-			'stats' => $stats,
+			'errors'	=> $frequent,
 			'date_range' => ['start' => $start_date, 'end' => $end_date]
 		];
 	}
@@ -350,79 +318,92 @@
      * Send daily error summary email to administrator
      * @return bool Whether email is sent
      */
-    public function sendErrorSummary():bool
-    {
-        // Get summary data
-        $summary = $this->gatherErrorSummary();
+	public function sendErrorSummary():bool
+	{
+		$summary = $this->gatherErrorSummary();
 
-        // Only send if there are errors
-        if (empty($summary['frequent']) && empty($summary['critical'])) {
-            return false;
-        }
+		if (empty($summary['frequent']) && empty($summary['critical'])) {
+			return false;
+		}
 
-        $admin_email = get_option('admin_email');
-        $site_name = get_bloginfo('name');
-        $today = date('Y-m-d');
-        $yesterday = date('Y-m-d', strtotime('-1 day'));
+		$admin_email = get_option('admin_email');
+		$site_name = get_bloginfo('name');
+		$yesterday = date('Y-m-d', strtotime('-1 day'));
+		$subject = "[{$site_name}] Daily Error Summary - " . date('Y-m-d');
 
-        $subject = "[{$site_name}] Daily Error Summary - {$today}";
+		// Header with alert
+		$body = JVB()->email()->h1('Daily Error Summary');
+		$body .= sprintf('<p>Error summary for <strong>%s</strong></p>', $yesterday);
 
-        // Build email body
-        $body = "= Error Summary for {$yesterday} =\n\n";
+		// Summary stats in a grid
+		if (!empty($summary['stats'])) {
+			$stats = [
+				JVB()->email()->stat($summary['stats']->total_errors, 'Total Errors'),
+				JVB()->email()->stat($summary['stats']->critical_count, 'Critical', 'Requires attention'),
+				JVB()->email()->stat($summary['stats']->error_count, 'Errors'),
+				JVB()->email()->stat($summary['stats']->warning_count, 'Warnings')
+			];
+			$body .= JVB()->email()->grid($stats, 4);
+		}
 
-        // Add frequent errors section
-        if (!empty($summary['frequent'])) {
-            $body .= "== Most Frequent Errors ==\n\n";
+		// Alert if critical errors exist
+		if (!empty($summary['critical'])) {
+			$body .= JVB()->email()->alert(
+				sprintf('Found %d critical errors that need immediate attention', count($summary['critical'])),
+				'error'
+			);
+		}
 
-            foreach ($summary['frequent'] as $index => $error) {
-                $body .= ($index + 1) . ". [{$error->component}] {$error->error_type}\n";
-                $body .= "   Message: " . wp_trim_words($error->message, 20, '...') . "\n";
-                $body .= "   Count: {$error->count}\n\n";
-            }
-        }
+		$body .= JVB()->email()->spacer(20);
 
-        // Add critical errors section
-        if (!empty($summary['critical'])) {
-            $body .= "== Recent Critical Errors ==\n\n";
+		// Frequent errors section
+		if (!empty($summary['frequent'])) {
+			$body .= JVB()->email()->h2('Most Frequent Errors');
 
-            foreach ($summary['critical'] as $index => $error) {
-                $body .= ($index + 1) . ". [{$error->component}] {$error->error_type}\n";
-                $body .= "   Time: {$error->created_at}\n";
-                $body .= "   Message: " . $error->message . "\n\n";
+			foreach ($summary['frequent'] as $error) {
+				$cardContent = JVB()->email()->badge($error->count . 'x', 'warning') . ' ';
+				$cardContent .= '<strong>' . esc_html($error->error_type) . '</strong>';
+				$cardContent .= '<p style="margin:10px 0 5px 0;font-size:13px;">' . esc_html(wp_trim_words($error->message, 15)) . '</p>';
+				$cardContent .= '<p style="margin:0;font-size:12px;color:' . JVB()->email()->colours['dark-200'] . ';">
+                Source: ' . esc_html($error->source) . ' |
+                Logged in: ' . $error->logged_in_count . ' |
+                Logged out: ' . $error->logged_out_count . '
+            </p>';
 
-                // Include context for critical errors if available
-                if (!empty($error->context)) {
-                    $context = json_decode($error->context, true);
-                    if (is_array($context)) {
-                        $body .= "   Context:\n";
-                        foreach ($context as $key => $value) {
-                            if (is_array($value) || is_object($value)) {
-                                $value = json_encode($value);
-                            }
-                            $body .= "     - {$key}: {$value}\n";
-                        }
-                    }
-                    $body .= "\n";
-                }
-            }
-        }
+				$body .= JVB()->email()->card($cardContent, $error->component);
+			}
+		}
 
-        // Add dashboard link if available
-        $admin_url = admin_url('admin.php?page=jvb-error-logs');
-        $body .= "View detailed error logs in the dashboard: {$admin_url}\n\n";
+		// Critical errors section
+		if (!empty($summary['critical'])) {
+			$body .= JVB()->email()->spacer(30);
+			$body .= JVB()->email()->h2('Recent Critical Errors');
 
-        // Send the email
-        $sent = JVB()->email()->sendEmail($admin_email, $subject, $body, 'ERROR SUMMARY');
+			foreach ($summary['critical'] as $error) {
+				$cardContent = '<p><strong>Time:</strong> ' . esc_html($error->created_at) . '</p>';
+				$cardContent .= '<p><strong>Message:</strong></p>';
+				$cardContent .= JVB()->email()->codeBlock($error->message);
 
-        // Log that summary was sent
-        if ($sent) {
-            error_log("[ErrorHandler] Daily error summary sent to {$admin_email}");
-        } else {
-            error_log("[ErrorHandler] Daily error summary was not sent.");
-        }
+				// Include context if available
+				if (!empty($error->context)) {
+					$context = json_decode($error->context, true);
+					if (is_array($context)) {
+						$cardContent .= '<p><strong>Context:</strong></p>';
+						$cardContent .= JVB()->email()->codeBlock(json_encode($context, JSON_PRETTY_PRINT));
+					}
+				}
 
-        return $sent;
-    }
+				$body .= JVB()->email()->card($cardContent, $error->component . ': ' . $error->error_type);
+			}
+		}
+
+		// Dashboard link
+		$admin_url = admin_url('admin.php?page=jvb-error-logs');
+		$body .= JVB()->email()->spacer(30);
+		$body .= JVB()->email()->button($admin_url, 'View Detailed Logs');
+
+		return JVB()->email()->sendEmail($admin_email, $subject, $body, 'ERROR SUMMARY');
+	}
 
     /**
      * Get HTML version of the error summary for nicer emails

--
Gitblit v1.10.0