Changeset 3458969
- Timestamp:
- 02/11/2026 01:02:01 PM (7 weeks ago)
- Location:
- cancer-awareness-ribbon-shortcode
- Files:
-
- 4 edited
-
assets/banner-1544x500.png (modified) (previous)
-
assets/banner-772x250.png (modified) (previous)
-
trunk/cancer-awareness-ribbon.php (modified) (17 diffs)
-
trunk/readme.txt (modified) (12 diffs)
Legend:
- Unmodified
- Added
- Removed
-
cancer-awareness-ribbon-shortcode/trunk/cancer-awareness-ribbon.php
r3458865 r3458969 3 3 /** 4 4 * Plugin Name: Cancer Awareness Ribbon Shortcode 5 * Description: Adds a shortcode to display a cancerawareness ribbon whose colors change based on the current month (or by type override).6 * Version: 1. 4.05 * Description: Adds a shortcode to display an awareness ribbon whose colors change based on the current month (or by type override). 6 * Version: 1.5.0 7 7 * Author: Parallel Media 8 8 * License: GPLv2 or later … … 19 19 plugins_url('assets/css/cancer-awareness-ribbon.css', __FILE__), 20 20 [], 21 '1. 4.0'21 '1.5.0' 22 22 ); 23 23 }, 20); 24 24 25 25 /** 26 * Cancer list: type => [label, month, colors[], optional category] 26 * Default awareness types list (internal). 27 * Schema: type => [label, month, colors[], optional category] 27 28 * Categories: Cancer, Medical, Social, Global 28 29 */ 29 function car_get_ cancers(): array30 function car_get_default_awareness_types(): array 30 31 { 31 32 return [ … … 62 63 'thyroid_cancer' => ['label' => 'Thyroid Cancer', 'month' => 9, 'colors' => ['#800080', '#00B3B3', '#FF69B4']], 63 64 64 // v1.1 -additional awareness ribbons (non-cancer)65 // additional awareness ribbons (non-cancer) 65 66 'hiv_aids_awareness' => ['label' => 'HIV / AIDS Awareness', 'month' => 12, 'colors' => ['#E10600'], 'category' => 'Global'], 66 67 'autism_awareness' => ['label' => 'Autism Awareness', 'month' => 4, 'colors' => ['#1877F2'], 'category' => 'Medical'], … … 68 69 'diabetes_awareness' => ['label' => 'Diabetes Awareness', 'month' => 11, 'colors' => ['#9E9E9E'], 'category' => 'Medical'], 69 70 'heart_disease_awareness' => ['label' => 'Heart Disease Awareness', 'month' => 2, 'colors' => ['#C62828'], 'category' => 'Medical'], 70 71 // v1.2 - additional awareness ribbons (non-cancer)72 71 'domestic_violence_awareness' => ['label' => 'Domestic Violence Awareness', 'month' => 10, 'colors' => ['#800080'], 'category' => 'Social'], 73 72 'prostate_health_awareness' => ['label' => 'Prostate Health Awareness', 'month' => 9, 'colors' => ['#7EC8E3'], 'category' => 'Medical'], … … 75 74 'lung_health_awareness' => ['label' => 'Lung Health Awareness', 'month' => 11, 'colors' => ['#FFFFFF'], 'category' => 'Medical'], 76 75 'alzheimers_awareness' => ['label' => 'Alzheimer’s Awareness', 'month' => 11, 'colors' => ['#5E2D79'], 'category' => 'Medical'], 77 78 // v1.3 - additional awareness ribbons (non-cancer)79 76 'pride_awareness' => ['label' => 'Pride Awareness', 'month' => 6, 'colors' => ['#E40303', '#FF8C00', '#FFED00', '#008026', '#004DFF', '#750787'], 'category' => 'Social'], 80 77 'veterans_awareness' => ['label' => 'Veterans Awareness', 'month' => 11, 'colors' => ['#B22234', '#FFFFFF', '#3C3B6E'], 'category' => 'Social'], … … 83 80 'organ_donation_awareness' => ['label' => 'Organ Donation Awareness', 'month' => 4, 'colors' => ['#4CAF50'], 'category' => 'Medical'], 84 81 ]; 82 } 83 84 /** 85 * Basic hex color validator (#RGB or #RRGGBB). 86 */ 87 function car_is_hex_color($c): bool 88 { 89 $c = trim((string)$c); 90 if ($c === '') return false; 91 return (bool)preg_match('/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/', $c); 92 } 93 94 function car_clamp_int($v, int $min, int $max): int 95 { 96 $v = (int)$v; 97 return max($min, min($max, $v)); 98 } 99 100 function car_normalize_category($v): string 101 { 102 $v = trim((string)$v); 103 if ($v === '') return ''; 104 $v = strtolower($v); 105 106 if ($v === 'cancers') $v = 'cancer'; 107 if ($v === 'med') $v = 'medical'; 108 109 $map = [ 110 'cancer' => 'Cancer', 111 'medical' => 'Medical', 112 'social' => 'Social', 113 'global' => 'Global', 114 ]; 115 116 return $map[$v] ?? ''; 117 } 118 119 function car_sanitize_awareness_types($types): array 120 { 121 if (!is_array($types)) return []; 122 123 $out = []; 124 foreach ($types as $raw_key => $raw_item) { 125 $key = sanitize_key((string)$raw_key); 126 if ($key === '') continue; 127 if (!is_array($raw_item)) continue; 128 129 $label = isset($raw_item['label']) ? trim((string)$raw_item['label']) : ''; 130 if ($label === '') continue; 131 132 $month = isset($raw_item['month']) ? (int)$raw_item['month'] : 0; 133 if ($month !== 0) $month = car_clamp_int($month, 1, 12); 134 135 $colors_in = $raw_item['colors'] ?? []; 136 if (!is_array($colors_in)) $colors_in = [$colors_in]; 137 138 $colors = []; 139 foreach ($colors_in as $c) { 140 $c = trim((string)$c); 141 if ($c === '') continue; 142 if (!car_is_hex_color($c)) continue; 143 $colors[] = $c; 144 } 145 if (!$colors) $colors = ['#999999']; 146 147 $category = ''; 148 if (isset($raw_item['category'])) { 149 $category = car_normalize_category($raw_item['category']); 150 } 151 152 $item = [ 153 'label' => $label, 154 'month' => $month, 155 'colors' => $colors, 156 ]; 157 if ($category !== '') $item['category'] = $category; 158 159 $out[$key] = $item; 160 } 161 162 return $out; 163 } 164 165 /** 166 * Awareness Types Registry (v1.5) 167 * 168 * Developers can register/modify awareness ribbons via: 169 * add_filter('car_awareness_types', function(array $types) { ...; return $types; }); 170 */ 171 function car_get_awareness_types(): array 172 { 173 $types = car_get_default_awareness_types(); 174 $types = apply_filters('car_awareness_types', $types); 175 return car_sanitize_awareness_types($types); 176 } 177 178 /** 179 * Backwards compatibility wrapper (deprecated). 180 * 181 * @deprecated 1.5.0 Use car_get_awareness_types() 182 */ 183 function car_get_cancers(): array 184 { 185 return car_get_awareness_types(); 186 } 187 188 function car_item_category(array $item): string 189 { 190 $cat = isset($item['category']) ? car_normalize_category($item['category']) : ''; 191 return $cat !== '' ? $cat : 'Cancer'; 192 } 193 194 function car_group_items_by_category(array $items): array 195 { 196 $order = ['Cancer', 'Medical', 'Social', 'Global']; 197 $grouped = [ 198 'Cancer' => [], 199 'Medical' => [], 200 'Social' => [], 201 'Global' => [], 202 ]; 203 204 foreach ($items as $key => $item) { 205 $cat = car_item_category($item); 206 if (!isset($grouped[$cat])) $grouped[$cat] = []; 207 $grouped[$cat][$key] = $item; 208 } 209 210 $out = []; 211 foreach ($order as $cat) { 212 if (!empty($grouped[$cat])) $out[$cat] = $grouped[$cat]; 213 unset($grouped[$cat]); 214 } 215 foreach ($grouped as $cat => $bucket) { 216 if (!empty($bucket)) $out[$cat] = $bucket; 217 } 218 219 return $out; 220 } 221 222 /** 223 * Helper for builder select options (flat). 224 * Elementor SELECT does not reliably support optgroups (nested arrays). 225 */ 226 function car_get_awareness_types_select_options_flat(): array 227 { 228 $types = car_get_awareness_types(); 229 $out = []; 230 231 foreach ($types as $key => $item) { 232 $label = (string)($item['label'] ?? $key); 233 $cat = car_item_category($item); 234 $out[$key] = $cat . ' | ' . $label; 235 } 236 237 // Optional: sort by label (keeps it tidy) 238 asort($out, SORT_NATURAL | SORT_FLAG_CASE); 239 240 return $out; 85 241 } 86 242 … … 103 259 } 104 260 105 function car_clamp_int($v, int $min, int $max): int106 {107 $v = (int)$v;108 return max($min, min($max, $v));109 }110 111 function car_normalize_category($v): string112 {113 $v = trim((string)$v);114 if ($v === '') return '';115 $v = strtolower($v);116 117 // allow a few friendly aliases118 if ($v === 'cancers') $v = 'cancer';119 if ($v === 'med') $v = 'medical';120 121 $map = [122 'cancer' => 'Cancer',123 'medical' => 'Medical',124 'social' => 'Social',125 'global' => 'Global',126 ];127 128 return $map[$v] ?? '';129 }130 131 function car_item_category(array $item): string132 {133 // Default: anything without explicit category is Cancer134 $cat = isset($item['category']) ? car_normalize_category($item['category']) : '';135 return $cat !== '' ? $cat : 'Cancer';136 }137 138 function car_group_items_by_category(array $items): array139 {140 $order = ['Cancer', 'Medical', 'Social', 'Global'];141 $grouped = [142 'Cancer' => [],143 'Medical' => [],144 'Social' => [],145 'Global' => [],146 ];147 148 foreach ($items as $key => $item) {149 $cat = car_item_category($item);150 if (!isset($grouped[$cat])) $grouped[$cat] = [];151 $grouped[$cat][$key] = $item;152 }153 154 // return ordered + any extra categories (future-proof)155 $out = [];156 foreach ($order as $cat) {157 if (!empty($grouped[$cat])) $out[$cat] = $grouped[$cat];158 unset($grouped[$cat]);159 }160 foreach ($grouped as $cat => $bucket) {161 if (!empty($bucket)) $out[$cat] = $bucket;162 }163 164 return $out;165 }166 167 261 function car_render_ribbon_svg(array $colors, int $size, string $label): string 168 262 { … … 193 287 c-33.208-21.358-88.518-46.819-163.426-46.819s-130.217,25.46-163.426,46.819c-25.382,16.325-41.878,32.54-49.703,41.068 194 288 c-16.459-29.648-25.327-63.358-25.327-97.408C861.545,436.251,868.418,406.194,881.421,379.246z M826.783,1759.396 195 l-157.379-336.675l255.586-332.444l168.38,259.026L826.783,1759.396z M1373.217,1759.396l-268.557-413.123l-0.042-0.064 289 l-157.379-336.675l255.586-332.444l168.38,259.026L826.783,1759.396z M1373.217,1759.396 290 l-268.557-413.123l-0.042-0.064 196 291 c-0.007-0.01-0.013-0.02-0.02-0.03L770.167,831.709c-18.718-28.784-29.762-62.112-31.94-96.38s4.559-68.728,19.482-99.653 197 292 l94.354-195.578c-1.086,8.654-1.637,17.37-1.637,26.073c0,38.495,10.741,76.575,30.562,109.42c0.135,0.271,0.29,0.533,0.47,0.782 … … 213 308 } 214 309 310 /** 311 * Shared renderer so shortcode + builders can call the same logic. 312 */ 313 function car_render_awareness_ribbon(array $atts = []): string 314 { 315 return car_shortcode_cancer_ribbon($atts); 316 } 317 215 318 function car_shortcode_cancer_ribbon($atts): string 216 319 { … … 221 324 'label' => '0', 222 325 'class' => '', 223 'category' => '', // v1.4: filter by category (Cancer, Medical, Social, Global)224 'list' => '0', // v1.4: list all ribbons for a selected month326 'category' => '', 327 'list' => '0', 225 328 ], $atts, 'cancer_ribbon'); 226 329 227 330 wp_enqueue_style('car-ribbon-style'); 228 331 229 $ cancers = car_get_cancers();332 $types = car_get_awareness_types(); 230 333 231 334 $size = car_clamp_int($atts['size'], 16, 512); … … 244 347 $extra_class = sanitize_html_class((string)$atts['class']); 245 348 246 // v1.4: list all awareness ribbons for the selected month (optionally filtered by category)247 349 if ($list_mode) { 248 350 $matches = []; 249 351 250 foreach ($ cancers as $key => $item) {352 foreach ($types as $key => $item) { 251 353 if ((int)($item['month'] ?? 0) !== (int)$month) continue; 252 354 … … 262 364 } 263 365 264 // Group by category (Cancer, Medical, Social, Global)265 366 $grouped = car_group_items_by_category($matches); 266 367 … … 293 394 } 294 395 295 // Single ribbon mode (existing behavior) + optional category filter when type is not forced296 396 $type = sanitize_key((string)$atts['type']); 297 397 $selected = null; 298 398 299 // Type override always wins 300 if ($type && isset($cancers[$type])) { 301 $selected = $cancers[$type]; 399 if ($type && isset($types[$type])) { 400 $selected = $types[$type]; 302 401 } else { 303 // If a category is provided and it's not Cancer, skip featured_by_month and pick first matching in that category for the month304 402 if ($category !== '' && $category !== 'Cancer') { 305 foreach ($ cancers as $item) {403 foreach ($types as $item) { 306 404 if ((int)($item['month'] ?? 0) === (int)$month && strcasecmp(car_item_category($item), $category) === 0) { 307 405 $selected = $item; … … 310 408 } 311 409 } else { 312 // Original featured-by-month logic313 410 $featured = car_featured_by_month(); 314 if (isset($featured[$month]) && isset($cancers[$featured[$month]])) { 315 $candidate = $cancers[$featured[$month]]; 316 // If category is set (Cancer) ensure it matches 411 if (isset($featured[$month]) && isset($types[$featured[$month]])) { 412 $candidate = $types[$featured[$month]]; 317 413 if ($category === '' || strcasecmp(car_item_category($candidate), $category) === 0) { 318 414 $selected = $candidate; … … 321 417 } 322 418 323 // Fallback: first item matching month (+ optional category)324 419 if (!$selected) { 325 foreach ($ cancers as $item) {420 foreach ($types as $item) { 326 421 if ((int)($item['month'] ?? 0) !== (int)$month) continue; 327 422 if ($category !== '' && strcasecmp(car_item_category($item), $category) !== 0) continue; … … 338 433 339 434 $wrap_class = 'car-ribbon-wrap' . ($extra_class ? ' ' . $extra_class : ''); 340 341 435 $svg = car_render_ribbon_svg((array)$selected['colors'], $size, (string)$selected['label']); 342 436 … … 355 449 add_shortcode('cancer_ribbon', 'car_shortcode_cancer_ribbon'); 356 450 }); 451 452 /** 453 * Integrations loader 454 */ 455 function car_load_integrations(): void 456 { 457 // Admin page 458 if (is_admin()) { 459 $admin_loader = __DIR__ . '/includes/admin/admin.php'; 460 if (file_exists($admin_loader)) { 461 require_once $admin_loader; 462 } 463 } 464 465 // Elementor integration 466 $elementor_loader = __DIR__ . '/includes/integrations/elementor.php'; 467 if (file_exists($elementor_loader)) { 468 require_once $elementor_loader; 469 } 470 471 // WPBakery / Visual Composer integration 472 $wpbakery_loader = __DIR__ . '/includes/integrations/wpbakery.php'; 473 if (file_exists($wpbakery_loader)) { 474 require_once $wpbakery_loader; 475 } 476 477 // Divi integration 478 $divi_loader = __DIR__ . '/includes/integrations/divi.php'; 479 if (file_exists($divi_loader)) { 480 require_once $divi_loader; 481 } 482 483 // Beaver Builder integration 484 $beaver_loader = __DIR__ . '/includes/integrations/beaver.php'; 485 if (file_exists($beaver_loader)) { 486 require_once $beaver_loader; 487 } 488 } 489 add_action('plugins_loaded', 'car_load_integrations', 30); -
cancer-awareness-ribbon-shortcode/trunk/readme.txt
r3458889 r3458969 1 1 === Cancer Awareness Ribbon Shortcode === 2 2 Contributors: freelancedirectza 3 Tags: cancer, awareness, shortcode, accessibility, charity3 Tags: cancer, nonprofit, ribbon, shortcode, accessibility 4 4 Requires at least: 5.8 5 5 Tested up to: 6.9 6 6 Requires PHP: 7.4 7 Stable tag: 1. 4.08 Version: 1. 4.07 Stable tag: 1.5.0 8 Version: 1.5.0 9 9 License: GPLv2 or later 10 10 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 16 16 **Cancer Awareness Ribbon Shortcode** is a lightweight WordPress plugin that adds a shortcode for displaying a professionally designed awareness ribbon anywhere on your website. 17 17 18 [Live Demo](https://www.parallelmedia.co.za/cancer-awareness-ribbon-demo )18 [Live Demo](https://www.parallelmedia.co.za/cancer-awareness-ribbon-demo/) 19 19 20 20 The ribbon automatically adapts to the current awareness month and supports a wide range of awareness types including Cancer, Medical, Social, and Global causes. … … 24 24 - Supports single-color and multi-color (gradient) ribbons 25 25 - Uses a clean, scalable SVG with no background 26 - Works seamlessly with Elementor, Gutenberg, headers, footers, and widgets 26 - Works seamlessly with Elementor, Divi, WPBakery, Beaver Builder, Gutenberg, headers, footers, and widgets 27 - Includes a built-in admin shortcode builder with live preview 27 28 - Scales crisply at any size 28 29 - Does not rely on external libraries or image files … … 37 38 - Site-wide awareness displays 38 39 39 Version 1.4.0 introduces: 40 - Category grouping (Cancer, Medical, Social, Global) 41 - Category filtering via shortcode 42 - List mode to display all awareness ribbons for a selected month 43 - Structured support for expanding awareness types 40 Version 1.5.0 introduces: 41 - Admin settings page with live shortcode preview 42 - Default ribbon settings (size, type, month, category, label, list mode) 43 - Internal data structure refactor from cancer-only to awareness types 44 - Developer filter hook for registering custom awareness ribbons 45 - Improved builder integrations (Elementor, Divi, WPBakery, Beaver Builder) 46 - Foundation for future Pro features 44 47 45 48 == Features == 46 49 47 50 * Automatic ribbon selection based on the current month 48 * Supports many awareness types (Cancer, Medical, Social, Global)51 * Supports Cancer, Medical, Social, and Global awareness types 49 52 * Multi-color gradient support for applicable ribbons 50 53 * Fully responsive SVG (no images required) 51 * Elementor Shortcode widget compatible 54 * Admin shortcode builder with live preview 55 * Save default ribbon display settings 56 * Compatible with major page builders 52 57 * Lightweight and fast (no external libraries) 53 58 * Accessible SVG with ARIA labels 54 59 * Customizable size, label, type, month, category filtering, and month listing via shortcode attributes 60 * Developer hook to extend awareness ribbon library 55 61 56 62 == Usage == … … 66 72 [cancer_ribbon type="breast_cancer"] 67 73 [cancer_ribbon month="10"] 68 69 New in 1.4.0:70 74 71 75 [cancer_ribbon category="Medical"] … … 80 84 * `month` – Force a specific month (1–12) 81 85 * `category` – Filter by category: Cancer, Medical, Social, Global (optional) 82 * `list` – If set to 1/true, lists all ribbons for the selected month (optional, works great with `category`) 86 * `list` – If set to 1/true, lists all ribbons for the selected month (optional) 87 88 == Admin Shortcode Builder == 89 90 Version 1.5.0 adds a top-level **Awareness Ribbon** admin page where you can: 91 92 - Select ribbon type 93 - Choose month or auto-detect 94 - Adjust ribbon size 95 - Enable label display 96 - Filter by category 97 - Enable list mode 98 - Add custom CSS class 99 - View live preview instantly 100 - Copy generated shortcode 101 - Save global defaults 102 103 == Developer Extensibility == 104 105 Developers can extend the ribbon library using a filter hook: 106 107 108 109 add_filter( 'car_awareness_types', 'my_custom_awareness_ribbon' ); 110 function my_custom_awareness_ribbon( $types ) { 111 $types['my_custom_cause'] = array( 112 'label' => 'My Custom Cause', 113 'month' => 6, 114 'colors' => array( '#123456', '#abcdef' ), 115 'category' => 'Global', 116 ); 117 return $types; 118 } 119 120 121 This allows plugins and themes to register custom awareness ribbons without modifying core plugin files. 83 122 84 123 == Supported Awareness Types == … … 97 136 - Thyroid Cancer (September) – Purple, Teal & Pink 98 137 99 Additional awareness ribbons added in later versions include (among others): 138 Additional awareness ribbons include (among others): 139 100 140 - HIV / AIDS Awareness 101 141 - Autism Awareness … … 121 161 == Frequently Asked Questions == 122 162 123 = Does this work with Elementor? =124 Yes. Use Elementor’s **Shortcode** widget and insert `[cancer_ribbon]`.163 = Does this work with page builders? = 164 Yes. It works with Elementor, Divi, WPBakery, Beaver Builder, Gutenberg, and any builder that supports shortcodes. 125 165 126 166 = Does it add any images or external files? = … … 147 187 2. Breast cancer awareness ribbon (October) 148 188 3. Multi-color gradient ribbon example 149 4. Elementor Shortcode widget usage 150 5. Month listing view (list mode) showing multiple ribbons 189 4. Elementor module integration 190 5. Admin shortcode builder with live preview 191 6. Month listing view (list mode) showing multiple ribbons 151 192 152 193 == Changelog == 194 195 = 1.5.0 = 196 * Added admin shortcode builder with live preview 197 * Added global default ribbon settings 198 * Refactored internal data structure from cancer-only to awareness types 199 * Added developer filter hook for registering custom awareness ribbons 200 * Added full builder integrations (Elementor, Divi, WPBakery, Beaver Builder) 201 * Improved internal structure for future Pro version expansion 153 202 154 203 = 1.4.0 = … … 157 206 * Added `list` shortcode attribute to display all ribbons for a selected month 158 207 * Added grouped output by category when using list mode 159 * Added categories to non-cancer awareness entries while keeping existing data structure intact160 208 161 209 = 1.3.0 = 162 * Added Pride awareness ribbon (multi-color gradient)210 * Added Pride awareness ribbon 163 211 * Added Veterans awareness ribbon 164 212 * Added Child Protection awareness ribbon … … 180 228 * Added Heart Disease awareness ribbon 181 229 182 = 1.0.2 =183 * Fixed stylesheet loading to use proper WordPress enqueue functions184 * Updated contributor metadata for WordPress.org compliance185 * Minor internal cleanup and review-related improvements186 187 = 1.0.1 =188 * Added support for custom SVG ribbon189 * Improved Elementor compatibility190 * Fixed inline CSS loading issues191 * Removed background elements from SVG192 193 230 = 1.0.0 = 194 231 * Initial release … … 196 233 == Upgrade Notice == 197 234 198 = 1.4.0 = 199 Adds category support, category filtering, and list mode to display all ribbons for a selected month. 200 201 = 1.0.2 = 202 Fixed stylesheet loading, updated contributor metadata, and minor internal cleanup. 235 = 1.5.0 = 236 Adds admin shortcode builder, default settings support, internal awareness refactor, developer extensibility hook, and builder integrations. 203 237 204 238 == License ==
Note: See TracChangeset
for help on using the changeset viewer.