diff --git a/admin/generate_card.php b/admin/generate_card.php
new file mode 100644
index 0000000..e8553ea
--- /dev/null
+++ b/admin/generate_card.php
@@ -0,0 +1,86 @@
+utf8Glyphs($text);
+}
+
+// --- Image Generation ---
+header('Content-Type: image/jpeg');
+$image = imagecreatefrompng($template_image);
+
+// Colors
+$text_color = imagecolorallocate($image, 0, 0, 0); // Black
+
+// --- Text Wrapping and Positioning ---
+$lines = [];
+if ($lang === 'ar') {
+ // Simple reverse for RTL line wrapping (basic)
+ $words = explode(' ', $text);
+ $line = '';
+ foreach ($words as $word) {
+ $new_line = $line . ' ' . $word;
+ $bbox = imagettfbbox($font_size, 0, $font_file, $new_line);
+ $line_width = abs($bbox[2] - $bbox[0]);
+ if ($line_width > ($width - 80)) { // 40px margin
+ $lines[] = $line;
+ $line = $word;
+ } else {
+ $line = $new_line;
+ }
+ }
+ $lines[] = $line;
+} else {
+ $words = explode(' ', $text);
+ $line = '';
+ foreach ($words as $word) {
+ $new_line = $line . ($line ? ' ' : '') . $word;
+ $bbox = imagettfbbox($font_size, 0, $font_file, $new_line);
+ $line_width = abs($bbox[2] - $bbox[0]);
+ if ($line_width > ($width - 80)) { // 40px margin
+ $lines[] = $line;
+ $line = $word;
+ } else {
+ $line = $new_line;
+ }
+ }
+ $lines[] = $line;
+}
+
+
+// Calculate total text height
+$total_text_height = count($lines) * ($font_size * 1.5);
+$y_start = ($height - $total_text_height) / 2;
+
+// Draw text line by line
+foreach ($lines as $i => $line) {
+ $line = trim($line);
+ $bbox = imagettfbbox($font_size, 0, $font_file, $line);
+ $line_width = abs($bbox[2] - $bbox[0]);
+ $x = ($width - $line_width) / 2;
+ $y = $y_start + ($i * $font_size * 1.5);
+ imagettftext($image, $font_size, 0, $x, $y, $text_color, $font_file, $line);
+}
+
+
+// --- Output ---
+imagejpeg($image);
+imagedestroy($image);
diff --git a/admin/settings.php b/admin/settings.php
index 8f51d3b..2ed8880 100644
--- a/admin/settings.php
+++ b/admin/settings.php
@@ -11,10 +11,16 @@ if (!is_super_admin()) {
$pdo = db();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ // Handle checkbox separately
+ if (!isset($_POST['settings']['whatsapp_send_cards'])) {
+ $_POST['settings']['whatsapp_send_cards'] = '0';
+ }
+
foreach ($_POST['settings'] as $key => $value) {
$stmt = $pdo->prepare("INSERT INTO settings (setting_key, setting_value) VALUES (?, ?) ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)");
$stmt->execute([$key, $value]);
}
+
header('Location: settings.php?success=1');
exit;
}
@@ -194,16 +200,25 @@ $is_rtl = (get_current_lang() === 'ar');
-
-
-
-
-
+
+
diff --git a/assets/images/card_templates/default.png b/assets/images/card_templates/default.png
new file mode 100644
index 0000000..1e0f8d5
Binary files /dev/null and b/assets/images/card_templates/default.png differ
diff --git a/db/migrations/20260215_add_whatsapp_send_cards_setting.sql b/db/migrations/20260215_add_whatsapp_send_cards_setting.sql
new file mode 100644
index 0000000..89772a9
--- /dev/null
+++ b/db/migrations/20260215_add_whatsapp_send_cards_setting.sql
@@ -0,0 +1 @@
+INSERT INTO settings (setting_key, setting_value) VALUES ('whatsapp_send_cards', '0');
\ No newline at end of file
diff --git a/mail/WablasService.php b/mail/WablasService.php
index 9d98fb2..6612bc6 100644
--- a/mail/WablasService.php
+++ b/mail/WablasService.php
@@ -8,7 +8,6 @@ class WablasService {
$token = $settings['wablas_api_token'] ?? '';
$serverUrl = $settings['wablas_server_url'] ?? '';
- $securityKey = $settings['wablas_security_key'] ?? '';
if (empty($token) || empty($serverUrl)) {
error_log("Wablas settings missing.");
@@ -18,10 +17,6 @@ class WablasService {
$to = prefix_phone($to);
$data = ['phone' => $to, 'message' => $message];
- if (!empty($securityKey)) {
- $data['security_key'] = $securityKey;
- $data['secret_key'] = $securityKey;
- }
$curl = curl_init();
curl_setopt($curl, CURLOPT_HTTPHEADER, ["Authorization: $token"]);
@@ -50,13 +45,60 @@ class WablasService {
return ['success' => false, 'error' => $result];
}
+ public static function sendImageAndCaption($to, $imageUrl, $caption) {
+ $pdo = db();
+ $settings = $pdo->query("SELECT setting_key, setting_value FROM settings WHERE setting_key LIKE 'wablas_%'")->fetchAll(PDO::FETCH_KEY_PAIR);
+
+ $token = $settings['wablas_api_token'] ?? '';
+ $serverUrl = $settings['wablas_server_url'] ?? '';
+
+ if (empty($token) || empty($serverUrl)) {
+ error_log("Wablas settings missing.");
+ return ['success' => false, 'error' => 'Settings missing'];
+ }
+
+ $to = prefix_phone($to);
+
+ $data = [
+ 'phone' => $to,
+ 'image' => $imageUrl,
+ 'caption' => $caption
+ ];
+
+ $curl = curl_init();
+ curl_setopt($curl, CURLOPT_HTTPHEADER, ["Authorization: $token"]);
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data));
+ curl_setopt($curl, CURLOPT_URL, rtrim($serverUrl, '/') . "/api/send-image");
+ curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
+
+ $result = curl_exec($curl);
+ $error = curl_error($curl);
+ curl_close($curl);
+
+ if ($error) {
+ error_log("Wablas CURL error: " . $error);
+ return ['success' => false, 'error' => $error];
+ }
+
+ $response = json_decode($result, true);
+ if (isset($response['status']) && $response['status'] == true) {
+ return ['success' => true, 'data' => $response];
+ }
+
+ error_log("Wablas API error: " . $result);
+ return ['success' => false, 'error' => $result];
+ }
+
public static function getOrgName($lang = 'en') {
$pdo = db();
$org = $pdo->query("SELECT name_en, name_ar FROM org_profile LIMIT 1")->fetch();
return ($lang === 'ar') ? ($org['name_ar'] ?? 'المنظمة') : ($org['name_en'] ?? 'Organization');
}
- private static function sendTemplatedMessage($to, $templateName, $vars, $lang = 'en') {
+ private static function sendTemplatedMessage($to, $templateName, $vars, $lang = 'en', $useImage = true) {
if (empty($to)) {
return ['success' => false, 'error' => 'Recipient phone number is missing.'];
}
@@ -77,7 +119,18 @@ class WablasService {
$messageBody = str_replace('{'.$key.'}', $value, $messageBody);
}
- return self::sendMessage($to, $messageBody);
+ if ($useImage) {
+ // ToDo: Find a way to get the base URL
+ $siteUrl = 'http://' . $_SERVER['HTTP_HOST'];
+ $imageUrl = $siteUrl . '/admin/generate_card.php?' . http_build_query([
+ 'text' => $messageBody,
+ 'lang' => $lang,
+ 'template' => $templateName
+ ]);
+ return self::sendImageAndCaption($to, $imageUrl, $messageBody);
+ } else {
+ return self::sendMessage($to, $messageBody);
+ }
}
public static function sendThankYou($donation, $lang = 'en') {